wrc: Change the format of the output of "wrc --verify-translation".
[wine/wine64.git] / tools / wrc / translation.c
blob217aa6645913da95e6d93eb8de9edea9b04d60f8
1 /*
2 * Copyright 2003 Vincent BĂ©ron
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <assert.h>
23 #include "dumpres.h"
24 #include "utils.h"
25 #include "wrc.h"
27 #define MASTER_LANGUAGE LANG_ENGLISH
28 #define MASTER_SUBLANGUAGE SUBLANG_ENGLISH_US
29 #define NB_LANG 0x94
31 enum lang_type_e {
32 lang_type_master = 0,
33 lang_type_neutral,
34 lang_type_normal
37 static language_t get_language(resource_t *resource) {
38 switch(resource->type) {
39 case res_acc:
40 return *resource->res.acc->lvc.language;
41 case res_bmp:
42 return *resource->res.bmp->data->lvc.language;
43 case res_cur:
44 return *resource->res.cur->lvc.language;
45 case res_curg:
46 return *resource->res.curg->lvc.language;
47 case res_dlg:
48 return *resource->res.dlg->lvc.language;
49 case res_dlgex:
50 return *resource->res.dlgex->lvc.language;
51 case res_fnt:
52 return *resource->res.fnt->data->lvc.language;
53 case res_fntdir:
54 return *resource->res.fnd->data->lvc.language;
55 case res_ico:
56 return *resource->res.ico->lvc.language;
57 case res_icog:
58 return *resource->res.icog->lvc.language;
59 case res_men:
60 return *resource->res.men->lvc.language;
61 case res_menex:
62 return *resource->res.menex->lvc.language;
63 case res_rdt:
64 return *resource->res.rdt->data->lvc.language;
65 case res_stt:
66 return *resource->res.stt->lvc.language;
67 case res_usr:
68 return *resource->res.usr->data->lvc.language;
69 case res_msg:
70 return *resource->res.msg->data->lvc.language;
71 case res_ver:
72 return *resource->res.ver->lvc.language;
73 case res_dlginit:
74 return *resource->res.dlgi->data->lvc.language;
75 case res_toolbar:
76 return *resource->res.tbt->lvc.language;
77 case res_anicur:
78 case res_aniico:
79 return *resource->res.ani->data->lvc.language;
80 case res_html:
81 return *resource->res.html->data->lvc.language;
82 default:
83 /* Not supposed to reach here */
84 fprintf(stderr, "Not supposed to reach here (get_language_id())\n");
85 abort();
89 static int get_language_id(resource_t *resource) {
90 return get_language(resource).id;
93 static int compare_lang(language_t lang1, language_t lang2)
95 return memcmp(&lang1, &lang2, sizeof(language_t));
98 #if 0
100 #define PRETTYPRINTLANG(langid) \
101 if(LANG_##langid == lid) { \
102 return #langid; \
105 static const char *get_language_name(int lid) {
106 PRETTYPRINTLANG(NEUTRAL)
107 PRETTYPRINTLANG(AFRIKAANS)
108 PRETTYPRINTLANG(ALBANIAN)
109 PRETTYPRINTLANG(ARABIC)
110 PRETTYPRINTLANG(ARMENIAN)
111 PRETTYPRINTLANG(ASSAMESE)
112 PRETTYPRINTLANG(AZERI)
113 PRETTYPRINTLANG(BASQUE)
114 PRETTYPRINTLANG(BELARUSIAN)
115 PRETTYPRINTLANG(BENGALI)
116 PRETTYPRINTLANG(BULGARIAN)
117 PRETTYPRINTLANG(CATALAN)
118 PRETTYPRINTLANG(CHINESE)
119 PRETTYPRINTLANG(CROATIAN)
120 PRETTYPRINTLANG(CZECH)
121 PRETTYPRINTLANG(DANISH)
122 PRETTYPRINTLANG(DIVEHI)
123 PRETTYPRINTLANG(DUTCH)
124 PRETTYPRINTLANG(ENGLISH)
125 PRETTYPRINTLANG(ESTONIAN)
126 PRETTYPRINTLANG(FAEROESE)
127 PRETTYPRINTLANG(FARSI)
128 PRETTYPRINTLANG(FINNISH)
129 PRETTYPRINTLANG(FRENCH)
130 PRETTYPRINTLANG(GALICIAN)
131 PRETTYPRINTLANG(GEORGIAN)
132 PRETTYPRINTLANG(GERMAN)
133 PRETTYPRINTLANG(GREEK)
134 PRETTYPRINTLANG(GUJARATI)
135 PRETTYPRINTLANG(HEBREW)
136 PRETTYPRINTLANG(HINDI)
137 PRETTYPRINTLANG(HUNGARIAN)
138 PRETTYPRINTLANG(ICELANDIC)
139 PRETTYPRINTLANG(INDONESIAN)
140 PRETTYPRINTLANG(ITALIAN)
141 PRETTYPRINTLANG(JAPANESE)
142 PRETTYPRINTLANG(KANNADA)
143 PRETTYPRINTLANG(KASHMIRI)
144 PRETTYPRINTLANG(KAZAK)
145 PRETTYPRINTLANG(KONKANI)
146 PRETTYPRINTLANG(KOREAN)
147 PRETTYPRINTLANG(KYRGYZ)
148 PRETTYPRINTLANG(LATVIAN)
149 PRETTYPRINTLANG(LITHUANIAN)
150 PRETTYPRINTLANG(MACEDONIAN)
151 PRETTYPRINTLANG(MALAY)
152 PRETTYPRINTLANG(MALAYALAM)
153 PRETTYPRINTLANG(MANIPURI)
154 PRETTYPRINTLANG(MARATHI)
155 PRETTYPRINTLANG(MONGOLIAN)
156 PRETTYPRINTLANG(NEPALI)
157 PRETTYPRINTLANG(NORWEGIAN)
158 PRETTYPRINTLANG(ORIYA)
159 PRETTYPRINTLANG(POLISH)
160 PRETTYPRINTLANG(PORTUGUESE)
161 PRETTYPRINTLANG(PUNJABI)
162 PRETTYPRINTLANG(ROMANIAN)
163 PRETTYPRINTLANG(RUSSIAN)
164 PRETTYPRINTLANG(SANSKRIT)
165 PRETTYPRINTLANG(SERBIAN)
166 PRETTYPRINTLANG(SINDHI)
167 PRETTYPRINTLANG(SLOVAK)
168 PRETTYPRINTLANG(SLOVENIAN)
169 PRETTYPRINTLANG(SPANISH)
170 PRETTYPRINTLANG(SWAHILI)
171 PRETTYPRINTLANG(SWEDISH)
172 PRETTYPRINTLANG(SYRIAC)
173 PRETTYPRINTLANG(TAMIL)
174 PRETTYPRINTLANG(TATAR)
175 PRETTYPRINTLANG(TELUGU)
176 PRETTYPRINTLANG(THAI)
177 PRETTYPRINTLANG(TURKISH)
178 PRETTYPRINTLANG(UKRAINIAN)
179 PRETTYPRINTLANG(URDU)
180 PRETTYPRINTLANG(UZBEK)
181 PRETTYPRINTLANG(VIETNAMESE)
182 PRETTYPRINTLANG(GAELIC)
183 PRETTYPRINTLANG(MALTESE)
184 PRETTYPRINTLANG(MAORI)
185 PRETTYPRINTLANG(RHAETO_ROMANCE)
186 PRETTYPRINTLANG(SAAMI)
187 PRETTYPRINTLANG(SORBIAN)
188 PRETTYPRINTLANG(SUTU)
189 PRETTYPRINTLANG(TSONGA)
190 PRETTYPRINTLANG(TSWANA)
191 PRETTYPRINTLANG(VENDA)
192 PRETTYPRINTLANG(XHOSA)
193 PRETTYPRINTLANG(ZULU)
194 PRETTYPRINTLANG(ESPERANTO)
195 PRETTYPRINTLANG(WALON)
196 PRETTYPRINTLANG(CORNISH)
197 PRETTYPRINTLANG(WELSH)
198 PRETTYPRINTLANG(BRETON)
199 return "Unknown language";
201 #endif
203 static int compare_accelerator(accelerator_t *accelerator1, accelerator_t *accelerator2) {
204 int different = 0;
205 event_t *ev1 = NULL, *ev2 = NULL;
206 if(!different &&
207 ((accelerator1->memopt != accelerator2->memopt) ||
208 (accelerator1->lvc.version != accelerator2->lvc.version) ||
209 (accelerator1->lvc.characts != accelerator2->lvc.characts)))
210 different = 1;
211 ev1 = accelerator1->events;
212 ev2 = accelerator2->events;
213 while(!different && ev1 && ev2) {
214 if(!different &&
215 ((ev1->id != ev2->id) ||
216 (ev1->flags != ev2->flags)))
217 different = 1;
218 ev1 = ev1->next;
219 ev2 = ev2->next;
221 if(!different &&
222 ((ev1 && !ev2) || (!ev1 && ev2)))
223 different = 1;
224 return different;
227 static int compare_bitmap(bitmap_t *bitmap1, bitmap_t *bitmap2) {
228 int different = 0;
229 if(!different &&
230 ((bitmap1->memopt != bitmap2->memopt) ||
231 (bitmap1->data->lvc.version != bitmap2->data->lvc.version) ||
232 (bitmap1->data->lvc.characts != bitmap2->data->lvc.characts)))
233 different = 1;
234 return different;
237 static int compare_cursor(cursor_t *cursor1, cursor_t *cursor2) {
238 int different = 0;
239 if(!different &&
240 ((cursor1->id != cursor2->id) ||
241 (cursor1->width != cursor2->width) ||
242 (cursor1->height != cursor2->height) ||
243 (cursor1->xhot != cursor2->xhot) ||
244 (cursor1->yhot != cursor2->yhot)))
245 different = 1;
246 if(!different &&
247 ((cursor1->lvc.version != cursor2->lvc.version) ||
248 (cursor1->lvc.characts != cursor2->lvc.characts)))
249 different = 1;
250 return different;
253 static int compare_cursor_group(cursor_group_t *cursor_group1, cursor_group_t *cursor_group2) {
254 int different = 0;
255 cursor_t *cursor1 = NULL, *cursor2 = NULL;
256 if(!different &&
257 ((cursor_group1->memopt != cursor_group2->memopt) ||
258 (cursor_group1->lvc.version != cursor_group2->lvc.version) ||
259 (cursor_group1->lvc.characts != cursor_group2->lvc.characts)))
260 different = 1;
261 if(!different &&
262 (cursor_group1->ncursor != cursor_group2->ncursor))
263 different = 1;
264 if(!different) {
265 cursor1 = cursor_group1->cursorlist;
266 cursor2 = cursor_group2->cursorlist;
267 while(!different && cursor1 && cursor2) {
268 different = compare_cursor(cursor1, cursor2);
269 cursor1 = cursor1->next;
270 cursor2 = cursor2->next;
272 if(!different &&
273 ((cursor1 && !cursor2) ||
274 (!cursor1 && cursor2)))
275 different = 1;
277 return different;
280 static int compare_control(control_t *control1, control_t *control2) {
281 int different = 0;
282 char *nameid = NULL;
283 if(!different &&
284 ((control1 && !control2) ||
285 (!control1 && control2)))
286 different = 1;
287 if(different || !control1 || !control2)
288 return different;
289 nameid = strdup(get_nameid_str(control1->ctlclass));
290 if(!different && strcmp(nameid, get_nameid_str(control2->ctlclass)))
291 different = 1;
292 free(nameid);
293 if(!different &&
294 (control1->id != control2->id))
295 different = 1;
296 if(!different && control1->gotstyle && control2->gotstyle) {
297 if((!control1->style || !control2->style) ||
298 (control1->style->and_mask || control2->style->and_mask) ||
299 (control1->style->or_mask != control2->style->or_mask))
300 different = 1;
301 } else if(!different &&
302 ((control1->gotstyle && !control2->gotstyle) ||
303 (!control1->gotstyle && control2->gotstyle)))
304 different = 1;
305 if(!different && control1->gotexstyle && control2->gotexstyle) {
306 if((!control1->exstyle || !control2->exstyle) ||
307 (control1->exstyle->and_mask || control2->exstyle->and_mask) ||
308 (control1->exstyle->or_mask != control2->exstyle->or_mask))
309 different = 1;
310 } else if(!different &&
311 ((control1->gotexstyle && !control2->gotexstyle) ||
312 (!control1->gotexstyle && control2->gotexstyle)))
313 different = 1;
314 if(!different && control1->gothelpid && control2->gothelpid) {
315 if(control1->helpid != control2->helpid)
316 different = 1;
317 } else if(!different &&
318 ((control1->gothelpid && !control2->gothelpid) ||
319 (!control1->gothelpid && control2->gothelpid)))
320 different = 1;
321 return different;
324 static int compare_dialog(dialog_t *dialog1, dialog_t *dialog2) {
325 int different = 0;
326 char *nameid = NULL;
327 if(!different &&
328 ((dialog1->memopt != dialog2->memopt) ||
329 (dialog1->lvc.version != dialog2->lvc.version) ||
330 (dialog1->lvc.characts != dialog2->lvc.characts)))
331 different = 1;
332 if(!different && dialog1->gotstyle && dialog2->gotstyle) {
333 if((!dialog1->style || !dialog2->style) ||
334 (dialog1->style->and_mask || dialog2->style->and_mask) ||
335 (dialog1->style->or_mask != dialog2->style->or_mask))
336 different = 1;
337 } else if(!different &&
338 ((dialog1->gotstyle && !dialog2->gotstyle) ||
339 (!dialog1->gotstyle && dialog2->gotstyle)))
340 different = 1;
341 if(!different && dialog1->gotexstyle && dialog2->gotexstyle) {
342 if((!dialog1->exstyle || !dialog2->exstyle) ||
343 (dialog1->exstyle->and_mask || dialog2->exstyle->and_mask) ||
344 (dialog1->exstyle->or_mask != dialog2->exstyle->or_mask))
345 different = 1;
346 } else if(!different &&
347 ((dialog1->gotexstyle && !dialog2->gotexstyle) ||
348 (!dialog1->gotexstyle && dialog2->gotexstyle)))
349 different = 1;
350 nameid = strdup(get_nameid_str(dialog1->menu));
351 if(!different && strcmp(nameid, get_nameid_str(dialog2->menu)))
352 different = 1;
353 free(nameid);
354 nameid = strdup(get_nameid_str(dialog1->dlgclass));
355 if(!different && strcmp(nameid, get_nameid_str(dialog2->dlgclass)))
356 different = 1;
357 free(nameid);
358 if(!different)
359 different = compare_control(dialog1->controls, dialog2->controls);
360 return different;
363 static int compare_dialogex(dialogex_t *dialogex1, dialogex_t *dialogex2) {
364 int different = 0;
365 char *nameid = NULL;
366 if(!different &&
367 ((dialogex1->memopt != dialogex2->memopt) ||
368 (dialogex1->lvc.version != dialogex2->lvc.version) ||
369 (dialogex1->lvc.characts != dialogex2->lvc.characts)))
370 different = 1;
371 if(!different && dialogex1->gotstyle && dialogex2->gotstyle) {
372 if((!dialogex1->style || !dialogex2->style) ||
373 (dialogex1->style->and_mask || dialogex2->style->and_mask) ||
374 (dialogex1->style->or_mask != dialogex2->style->or_mask))
375 different = 1;
376 } else if(!different &&
377 ((dialogex1->gotstyle && !dialogex2->gotstyle) ||
378 (!dialogex1->gotstyle && dialogex2->gotstyle)))
379 different = 1;
380 if(!different && dialogex1->gotexstyle && dialogex2->gotexstyle) {
381 if((!dialogex1->exstyle || !dialogex2->exstyle) ||
382 (dialogex1->exstyle->and_mask || dialogex2->exstyle->and_mask) ||
383 (dialogex1->exstyle->or_mask != dialogex2->exstyle->or_mask))
384 different = 1;
385 } else if(!different &&
386 ((dialogex1->gotexstyle && !dialogex2->gotexstyle) ||
387 (!dialogex1->gotexstyle && dialogex2->gotexstyle)))
388 different = 1;
389 if(!different && dialogex1->gothelpid && dialogex2->gothelpid) {
390 if(dialogex1->helpid != dialogex2->helpid)
391 different = 1;
392 } else if(!different &&
393 ((dialogex1->gothelpid && !dialogex2->gothelpid) ||
394 (!dialogex1->gothelpid && dialogex2->gothelpid)))
395 different = 1;
396 nameid = strdup(get_nameid_str(dialogex1->menu));
397 if(!different && strcmp(nameid, get_nameid_str(dialogex2->menu)))
398 different = 1;
399 free(nameid);
400 nameid = strdup(get_nameid_str(dialogex1->dlgclass));
401 if(!different && strcmp(nameid, get_nameid_str(dialogex2->dlgclass)))
402 different = 1;
403 free(nameid);
404 if(!different)
405 different = compare_control(dialogex1->controls, dialogex2->controls);
406 return different;
409 static int compare_font(font_t *font1, font_t *font2) {
410 int different = 0;
411 if(!different &&
412 ((font1->memopt != font2->memopt) ||
413 (font1->data->lvc.version != font2->data->lvc.version) ||
414 (font1->data->lvc.characts != font2->data->lvc.characts)))
415 different = 1;
416 return different;
419 static int compare_fontdir(fontdir_t *fontdir1, fontdir_t *fontdir2) {
420 int different = 0;
421 if(!different &&
422 ((fontdir1->memopt != fontdir2->memopt) ||
423 (fontdir1->data->lvc.version != fontdir2->data->lvc.version) ||
424 (fontdir1->data->lvc.characts != fontdir2->data->lvc.characts)))
425 different = 1;
426 return different;
429 static int compare_icon(icon_t *icon1, icon_t *icon2) {
430 int different = 0;
431 if(!different &&
432 ((icon1->id != icon2->id) ||
433 (icon1->width != icon2->width) ||
434 (icon1->height != icon2->height)))
435 different = 1;
436 if(!different &&
437 ((icon1->lvc.version != icon2->lvc.version) ||
438 (icon1->lvc.characts != icon2->lvc.characts)))
439 different = 1;
440 return different;
443 static int compare_icon_group(icon_group_t *icon_group1, icon_group_t *icon_group2) {
444 int different = 0;
445 icon_t *icon1 = NULL, *icon2 = NULL;
446 if(!different &&
447 ((icon_group1->memopt != icon_group2->memopt) ||
448 (icon_group1->lvc.version != icon_group2->lvc.version) ||
449 (icon_group1->lvc.characts != icon_group2->lvc.characts)))
450 different = 1;
451 if(!different &&
452 (icon_group1->nicon != icon_group2->nicon))
453 different = 1;
454 if(!different) {
455 icon1 = icon_group1->iconlist;
456 icon2 = icon_group2->iconlist;
457 while(!different && icon1 && icon2) {
458 different = compare_icon(icon1, icon2);
459 icon1 = icon1->next;
460 icon2 = icon2->next;
462 if(!different &&
463 ((icon1 && !icon2) ||
464 (!icon1 && icon2)))
465 different = 1;
467 return different;
470 static int compare_menu_item(menu_item_t *menu_item1, menu_item_t *menu_item2) {
471 int different = 0;
472 while(!different && menu_item1 && menu_item2) {
473 if(menu_item1->popup && menu_item2->popup)
474 different = compare_menu_item(menu_item1->popup, menu_item2->popup);
475 else if(!menu_item1->popup && !menu_item2->popup) {
476 if(menu_item1->name && menu_item2->name) {
477 if((menu_item1->id != menu_item2->id) ||
478 (menu_item1->state != menu_item2->state))
479 different = 1;
480 } else if((menu_item1->name && !menu_item2->name) ||
481 (!menu_item1->name && menu_item2->name))
482 different = 1;
483 } else
484 different = 1;
485 menu_item1 = menu_item1->next;
486 menu_item2 = menu_item2->next;
488 if(!different &&
489 ((menu_item1 && !menu_item2) ||
490 (!menu_item1 && menu_item2)))
491 different = 1;
492 return different;
495 static int compare_menu(menu_t *menu1, menu_t *menu2) {
496 int different = 0;
497 if(!different &&
498 ((menu1->memopt != menu2->memopt) ||
499 (menu1->lvc.version != menu2->lvc.version) ||
500 (menu1->lvc.characts != menu2->lvc.characts)))
501 different = 1;
502 if(!different)
503 different = compare_menu_item(menu1->items, menu2->items);
504 return different;
507 static int compare_menuex_item(menuex_item_t *menuex_item1, menuex_item_t *menuex_item2) {
508 int different = 0;
509 while(!different && menuex_item1 && menuex_item2) {
510 if(menuex_item1->popup && menuex_item2->popup) {
511 if(!different && menuex_item1->gotid && menuex_item2->gotid) {
512 if(menuex_item1->id != menuex_item2->id)
513 different = 1;
514 } else if(!different &&
515 ((menuex_item1->gotid && !menuex_item2->gotid) ||
516 (!menuex_item2->gotid && menuex_item2->gotid)))
517 different = 1;
518 if(!different && menuex_item1->gottype && menuex_item2->gottype) {
519 if(menuex_item1->type != menuex_item2->type)
520 different = 1;
521 } else if(!different &&
522 ((menuex_item1->gottype && !menuex_item2->gottype) ||
523 (!menuex_item2->gottype && menuex_item2->gottype)))
524 different = 1;
525 if(!different && menuex_item1->gotstate && menuex_item2->gotstate) {
526 if(menuex_item1->state != menuex_item2->state)
527 different = 1;
528 } else if(!different &&
529 ((menuex_item1->gotstate && !menuex_item2->gotstate) ||
530 (!menuex_item2->gotstate && menuex_item2->gotstate)))
531 different = 1;
532 if(!different && menuex_item1->gothelpid && menuex_item2->gothelpid) {
533 if(menuex_item1->helpid != menuex_item2->helpid)
534 different = 1;
535 } else if(!different &&
536 ((menuex_item1->gothelpid && !menuex_item2->gothelpid) ||
537 (!menuex_item2->gothelpid && menuex_item2->gothelpid)))
538 different = 1;
539 if(!different)
540 different = compare_menuex_item(menuex_item1->popup, menuex_item2->popup);
541 } else if(!menuex_item1->popup && !menuex_item2->popup) {
542 if(menuex_item1->name && menuex_item2->name) {
543 if(!different && menuex_item1->gotid && menuex_item2->gotid) {
544 if(menuex_item1->id != menuex_item2->id)
545 different = 1;
546 } else if(!different &&
547 ((menuex_item1->gotid && !menuex_item2->gotid) ||
548 (!menuex_item2->gotid && menuex_item2->gotid)))
549 different = 1;
550 if(!different && menuex_item1->gottype && menuex_item2->gottype) {
551 if(menuex_item1->type != menuex_item2->type)
552 different = 1;
553 } else if(!different &&
554 ((menuex_item1->gottype && !menuex_item2->gottype) ||
555 (!menuex_item2->gottype && menuex_item2->gottype)))
556 different = 1;
557 if(!different && menuex_item1->gotstate && menuex_item2->gotstate) {
558 if(menuex_item1->state != menuex_item2->state)
559 different = 1;
560 } else if(!different &&
561 ((menuex_item1->gotstate && !menuex_item2->gotstate) ||
562 (!menuex_item2->gotstate && menuex_item2->gotstate)))
563 different = 1;
564 if(!different && menuex_item1->gothelpid && menuex_item2->gothelpid) {
565 if(menuex_item1->helpid != menuex_item2->helpid)
566 different = 1;
567 } else if(!different &&
568 ((menuex_item1->gothelpid && !menuex_item2->gothelpid) ||
569 (!menuex_item2->gothelpid && menuex_item2->gothelpid)))
570 different = 1;
571 } else if((menuex_item1->name && !menuex_item2->name) ||
572 (!menuex_item1->name && menuex_item2->name))
573 different = 1;
574 } else
575 different = 1;
576 menuex_item1 = menuex_item1->next;
577 menuex_item2 = menuex_item2->next;
579 if(!different &&
580 ((menuex_item1 && !menuex_item2) ||
581 (!menuex_item1 && menuex_item2)))
582 different = 1;
583 return different;
586 static int compare_menuex(menuex_t *menuex1, menuex_t *menuex2) {
587 int different = 0;
588 if(!different &&
589 ((menuex1->memopt != menuex2->memopt) ||
590 (menuex1->lvc.version != menuex2->lvc.version) ||
591 (menuex1->lvc.characts != menuex2->lvc.characts)))
592 different = 1;
593 if(!different)
594 different = compare_menuex_item(menuex1->items, menuex2->items);
595 return different;
598 static int compare_rcdata(rcdata_t *rcdata1, rcdata_t *rcdata2) {
599 int different = 0;
600 if(!different &&
601 ((rcdata1->memopt != rcdata2->memopt) ||
602 (rcdata1->data->lvc.version != rcdata2->data->lvc.version) ||
603 (rcdata1->data->lvc.characts != rcdata2->data->lvc.characts)))
604 different = 1;
605 return different;
608 static int compare_html(html_t *rcdata1, html_t *rcdata2) {
609 int different = 0;
610 if(!different &&
611 ((rcdata1->memopt != rcdata2->memopt) ||
612 (rcdata1->data->lvc.version != rcdata2->data->lvc.version) ||
613 (rcdata1->data->lvc.characts != rcdata2->data->lvc.characts)))
614 different = 1;
615 return different;
618 static int compare_stringtable(stringtable_t *stringtable1, stringtable_t *stringtable2) {
619 int different = 0;
620 int i;
621 while(!different && stringtable1 && stringtable2) {
622 if((stringtable1->memopt != stringtable2->memopt) ||
623 (stringtable1->lvc.version != stringtable2->lvc.version) ||
624 (stringtable1->lvc.characts != stringtable2->lvc.characts))
625 different = 1;
626 if(!different) {
627 if((stringtable1->nentries != stringtable2->nentries) ||
628 (stringtable1->idbase != stringtable2->idbase))
629 different = 1;
630 else
631 for(i = 0 ; i < stringtable1->nentries; i++)
632 if((stringtable1->entries[i].id != stringtable2->entries[i].id) ||
633 (stringtable1->entries[i].memopt != stringtable2->entries[i].memopt) ||
634 (stringtable1->entries[i].str && !stringtable2->entries[i].str) ||
635 (!stringtable1->entries[i].str && stringtable2->entries[i].str)) {
636 different = 1;
637 break;
640 stringtable1 = stringtable1->next;
641 stringtable2 = stringtable2->next;
643 return different;
646 static int compare_user(user_t *user1, user_t *user2) {
647 int different = 0;
648 char *nameid = NULL;
649 if(!different &&
650 ((user1->memopt != user2->memopt) ||
651 (user1->data->lvc.version != user2->data->lvc.version) ||
652 (user1->data->lvc.characts != user2->data->lvc.characts)))
653 different = 1;
654 nameid = strdup(get_nameid_str(user1->type));
655 if(!different && strcmp(nameid, get_nameid_str(user2->type)))
656 different = 1;
657 free(nameid);
658 return different;
661 static int compare_messagetable(messagetable_t *messagetable1, messagetable_t *messagetable2) {
662 int different = 0;
663 if(!different &&
664 ((messagetable1->memopt != messagetable2->memopt) ||
665 (messagetable1->data->lvc.version != messagetable2->data->lvc.version) ||
666 (messagetable1->data->lvc.characts != messagetable2->data->lvc.characts)))
667 different = 1;
668 return different;
671 static int compare_string(string_t *string1, string_t *string2) {
672 int different = 0;
673 if(!different &&
674 ((string1->size != string2->size) ||
675 (string1->type != string2->type)))
676 different = 1;
677 if(!different) {
678 if(string1->type == str_char)
679 different = memcmp(string1->str.cstr, string2->str.cstr, string1->size);
680 else if(string1->type == str_unicode)
681 different = memcmp(string1->str.wstr, string2->str.wstr, string1->size*sizeof(WCHAR));
682 else
683 different = 1;
685 return different;
688 static int compare_ver_block(ver_block_t *ver_block1, ver_block_t *ver_block2);
690 static int compare_ver_value(ver_value_t *ver_value1, ver_value_t *ver_value2) {
691 int different = 0;
692 int i = 0;
693 if(!different &&
694 (ver_value1->type == ver_value2->type)) {
695 switch(ver_value1->type) {
696 case val_str:
697 if(!different && ver_value1->key && ver_value2->key)
698 different = compare_string(ver_value1->key, ver_value2->key);
699 else if(!different &&
700 ((ver_value1->key && !ver_value2->key) ||
701 (!ver_value1->key && ver_value2->key)))
702 different = 1;
703 break;
704 case val_words:
705 if(!different && ver_value1->key && ver_value2->key)
706 different = compare_string(ver_value1->key, ver_value2->key);
707 else if(!different &&
708 ((ver_value1->key && !ver_value2->key) ||
709 (!ver_value1->key && ver_value2->key)))
710 different = 1;
711 if(!different && ver_value1->value.words && ver_value2->value.words) {
712 if(!different &&
713 (ver_value1->value.words->nwords != ver_value2->value.words->nwords))
714 different = 1;
715 if(!different)
716 for(i = 0; i < ver_value1->value.words->nwords; i++) {
717 if(ver_value1->value.words->words[i] != ver_value2->value.words->words[i]) {
718 different = 1;
719 break;
722 } else if(!different &&
723 ((ver_value1->value.words && !ver_value2->value.words) ||
724 (!ver_value1->value.words && ver_value2->value.words)))
725 different = 1;
726 break;
727 case val_block:
728 if(!different && ver_value1->value.block && ver_value2->value.block)
729 different = compare_ver_block(ver_value1->value.block, ver_value2->value.block);
730 else if(!different &&
731 ((ver_value1->value.block && !ver_value2->value.block) ||
732 (!ver_value1->value.block && ver_value2->value.block)))
733 different = 1;
734 break;
735 default:
736 different = 1;
738 } else
739 different = 1;
740 return different;
743 static int compare_ver_block(ver_block_t *ver_block1, ver_block_t *ver_block2) {
744 int different = 0;
745 ver_value_t *ver_value1 = NULL, *ver_value2 = NULL;
746 if(!different) {
747 ver_value1 = ver_block1->values;
748 ver_value2 = ver_block2->values;
749 while(!different && ver_value1 && ver_value2) {
750 different = compare_ver_value(ver_value1, ver_value2);
751 ver_value1 = ver_value1->next;
752 ver_value2 = ver_value2->next;
754 if(!different &&
755 ((ver_value1 && !ver_value2) ||
756 (!ver_value1 && ver_value2)))
757 different = 1;
759 return different;
762 static int compare_versioninfo(versioninfo_t *versioninfo1, versioninfo_t *versioninfo2) {
763 int different = 0;
764 ver_block_t *ver_block1 = NULL, *ver_block2 = NULL;
765 if(!different &&
766 ((versioninfo1->memopt != versioninfo2->memopt) ||
767 (versioninfo1->lvc.version != versioninfo2->lvc.version) ||
768 (versioninfo1->lvc.characts != versioninfo2->lvc.characts)))
769 different = 1;
770 if(!different && versioninfo1->gotit.fv && versioninfo2->gotit.fv) {
771 if((versioninfo1->filever_maj1 != versioninfo2->filever_maj1) ||
772 (versioninfo1->filever_maj2 != versioninfo2->filever_maj2) ||
773 (versioninfo1->filever_min1 != versioninfo2->filever_min1) ||
774 (versioninfo1->filever_min2 != versioninfo2->filever_min2))
775 different = 1;
776 } else if(!different &&
777 ((versioninfo1->gotit.fv && !versioninfo2->gotit.fv) ||
778 (!versioninfo1->gotit.fv && versioninfo2->gotit.fv)))
779 different = 1;
780 if(!different && versioninfo1->gotit.pv && versioninfo2->gotit.pv) {
781 if((versioninfo1->prodver_maj1 != versioninfo2->prodver_maj1) ||
782 (versioninfo1->prodver_maj2 != versioninfo2->prodver_maj2) ||
783 (versioninfo1->prodver_min1 != versioninfo2->prodver_min1) ||
784 (versioninfo1->prodver_min2 != versioninfo2->prodver_min2))
785 different = 1;
786 } else if(!different &&
787 ((versioninfo1->gotit.pv && !versioninfo2->gotit.pv) ||
788 (!versioninfo1->gotit.pv && versioninfo2->gotit.pv)))
789 different = 1;
790 if(!different && versioninfo1->gotit.fo && versioninfo2->gotit.fo) {
791 if(versioninfo1->fileos != versioninfo2->fileos)
792 different = 1;
793 } else if(!different &&
794 ((versioninfo1->gotit.fo && !versioninfo2->gotit.fo) ||
795 (!versioninfo1->gotit.fo && versioninfo2->gotit.fo)))
796 different = 1;
797 if(!different && versioninfo1->gotit.ff && versioninfo2->gotit.ff) {
798 if(versioninfo1->fileflags != versioninfo2->fileflags)
799 different = 1;
800 } else if(!different &&
801 ((versioninfo1->gotit.ff && !versioninfo2->gotit.ff) ||
802 (!versioninfo1->gotit.ff && versioninfo2->gotit.ff)))
803 different = 1;
804 if(!different && versioninfo1->gotit.ffm && versioninfo2->gotit.ffm) {
805 if(versioninfo1->fileflagsmask != versioninfo2->fileflagsmask)
806 different = 1;
807 } else if(!different &&
808 ((versioninfo1->gotit.ffm && !versioninfo2->gotit.ffm) ||
809 (!versioninfo1->gotit.ffm && versioninfo2->gotit.ffm)))
810 different = 1;
811 if(!different && versioninfo1->gotit.ft && versioninfo2->gotit.ft) {
812 if(versioninfo1->filetype != versioninfo2->filetype)
813 different = 1;
814 } else if(!different &&
815 ((versioninfo1->gotit.ft && !versioninfo2->gotit.ft) ||
816 (!versioninfo1->gotit.ft && versioninfo2->gotit.ft)))
817 different = 1;
818 if(!different && versioninfo1->gotit.fst && versioninfo2->gotit.fst) {
819 if(versioninfo1->filesubtype != versioninfo2->filesubtype)
820 different = 1;
821 } else if(!different &&
822 ((versioninfo1->gotit.fst && !versioninfo2->gotit.fst) ||
823 (!versioninfo1->gotit.fst && versioninfo2->gotit.fst)))
824 different = 1;
825 if(!different) {
826 ver_block1 = versioninfo1->blocks;
827 ver_block2 = versioninfo2->blocks;
828 while(!different && ver_block1 && ver_block2) {
829 different = compare_ver_block(ver_block1, ver_block2);
830 ver_block1 = ver_block1->next;
831 ver_block2 = ver_block2->next;
833 if(!different &&
834 ((ver_block1 && !ver_block2) ||
835 (!ver_block1 && ver_block2)))
836 different = 1;
838 return different;
841 static int compare_dlginit(dlginit_t *dlginit1, dlginit_t *dlginit2) {
842 int different = 0;
843 if(!different &&
844 ((dlginit1->memopt != dlginit2->memopt) ||
845 (dlginit1->data->lvc.version != dlginit2->data->lvc.version) ||
846 (dlginit1->data->lvc.characts != dlginit2->data->lvc.characts)))
847 different = 1;
848 return different;
851 static int compare_toolbar_item(toolbar_item_t *toolbar_item1, toolbar_item_t *toolbar_item2) {
852 int different = 0;
853 while(!different && toolbar_item1 && toolbar_item2) {
854 if((toolbar_item1->id && !toolbar_item2->id) ||
855 (!toolbar_item1->id && toolbar_item2->id))
856 different = 1;
857 toolbar_item1 = toolbar_item1->next;
858 toolbar_item2 = toolbar_item2->next;
860 if(!different &&
861 ((toolbar_item1 && !toolbar_item2) ||
862 (!toolbar_item1 && toolbar_item2)))
863 different = 1;
864 return different;
867 static int compare_toolbar(toolbar_t *toolbar1, toolbar_t *toolbar2) {
868 int different = 0;
869 if(!different &&
870 ((toolbar1->memopt != toolbar2->memopt) ||
871 (toolbar1->lvc.version != toolbar2->lvc.version) ||
872 (toolbar1->lvc.characts != toolbar2->lvc.characts)))
873 different = 1;
874 if(!different)
875 different = compare_toolbar_item(toolbar1->items, toolbar2->items);
876 return different;
879 static int compare_ani_curico(ani_curico_t *ani_curico1, ani_curico_t *ani_curico2) {
880 int different = 0;
881 if(!different &&
882 ((ani_curico1->memopt != ani_curico2->memopt) ||
883 (ani_curico1->data->lvc.version != ani_curico2->data->lvc.version) ||
884 (ani_curico1->data->lvc.characts != ani_curico2->data->lvc.characts)))
885 different = 1;
886 return different;
889 static int compare(resource_t *resource1, resource_t *resource2) {
890 switch(resource1->type) {
891 case res_acc:
892 return compare_accelerator(resource1->res.acc, resource2->res.acc);
893 case res_bmp:
894 return compare_bitmap(resource1->res.bmp, resource2->res.bmp);
895 case res_cur:
896 return compare_cursor(resource1->res.cur, resource2->res.cur);
897 case res_curg:
898 return compare_cursor_group(resource1->res.curg, resource2->res.curg);
899 case res_dlg:
900 return compare_dialog(resource1->res.dlg, resource2->res.dlg);
901 case res_dlgex:
902 return compare_dialogex(resource1->res.dlgex, resource2->res.dlgex);
903 case res_fnt:
904 return compare_font(resource1->res.fnt, resource2->res.fnt);
905 case res_fntdir:
906 return compare_fontdir(resource1->res.fnd, resource2->res.fnd);
907 case res_ico:
908 return compare_icon(resource1->res.ico, resource2->res.ico);
909 case res_icog:
910 return compare_icon_group(resource1->res.icog, resource2->res.icog);
911 case res_men:
912 return compare_menu(resource1->res.men, resource2->res.men);
913 case res_menex:
914 return compare_menuex(resource1->res.menex, resource2->res.menex);
915 case res_rdt:
916 return compare_rcdata(resource1->res.rdt, resource2->res.rdt);
917 case res_stt:
918 return compare_stringtable(resource1->res.stt, resource2->res.stt);
919 case res_usr:
920 return compare_user(resource1->res.usr, resource2->res.usr);
921 case res_html:
922 return compare_html(resource1->res.html, resource2->res.html);
923 case res_msg:
924 return compare_messagetable(resource1->res.msg, resource2->res.msg);
925 case res_ver:
926 return compare_versioninfo(resource1->res.ver, resource2->res.ver);
927 case res_dlginit:
928 return compare_dlginit(resource1->res.dlgi, resource2->res.dlgi);
929 case res_toolbar:
930 return compare_toolbar(resource1->res.tbt, resource2->res.tbt);
931 case res_anicur:
932 case res_aniico:
933 return compare_ani_curico(resource1->res.ani, resource2->res.ani);
934 default:
935 /* Not supposed to reach here */
936 fprintf(stderr, "Not supposed to reach here (compare())\n");
937 abort();
938 return -1;
942 static void dump_stringtable(resource_t *res)
944 stringtable_t *stt = res->res.stt;
945 int j;
947 printf("DUMP ");
948 assert((stt->idbase%16) == 0);
949 assert(stt->nentries == 16);
950 for (j = 0; j < stt->nentries; j++)
952 stt_entry_t *entry = &stt->entries[j];
953 language_t *lang = stt->lvc.language;
954 string_t *newstr;
955 WCHAR *wstr;
956 int k;
958 if (entry->str)
960 newstr = convert_string(entry->str, str_unicode, get_language_codepage(lang->id, lang->sub));
961 printf("%02x%02x", newstr->size & 0xff, (newstr->size >> 8) & 0xff);
962 wstr = newstr->str.wstr;
963 for (k = 0; k < newstr->size; k++)
964 printf("%02x%02x", wstr[k] & 0xff, wstr[k] >> 8);
965 free_string(newstr);
967 else
968 printf("0000");
970 putchar('\n');
973 static void dump(resource_t *res)
975 switch (res->type)
977 case res_stt:
978 dump_stringtable(res);
979 return;
980 default:
981 break;
985 typedef struct resource_lang_node
987 language_t lang;
988 resource_t *res;
989 struct resource_lang_node *next;
990 } resource_lang_node_t;
992 typedef struct resource_id_node
994 name_id_t *id;
995 resource_lang_node_t *langs;
996 struct resource_id_node *next;
997 } resource_id_node_t;
999 struct
1001 int enabled;
1002 struct resource_id_node *ids;
1003 } verify_tab[res_usr+1];
1005 static void add_resource(resource_t *res)
1007 resource_id_node_t *idnode;
1008 resource_lang_node_t *langnode;
1009 if (!verify_tab[res->type].enabled)
1011 fprintf(stderr, "ERR: Report this: unknown resource type parsed %08x\n", res->type);
1012 return;
1015 for (idnode = verify_tab[res->type].ids; idnode; idnode = idnode->next)
1016 if (compare_name_id(idnode->id, res->name) == 0)
1017 break;
1019 if (idnode == NULL)
1021 idnode = xmalloc(sizeof(resource_id_node_t));
1022 idnode->id = res->name;
1023 idnode->langs = NULL;
1024 idnode->next = verify_tab[res->type].ids;
1025 verify_tab[res->type].ids = idnode;
1028 for (langnode = idnode->langs; langnode; langnode = langnode->next)
1029 if (compare_lang(langnode->lang, get_language(res)) == 0)
1031 fprintf(stderr, "ERR: resource %s [type %x] language %03x:%02x duplicated!\n",
1032 get_nameid_str(res->name), res->type, langnode->lang.id, langnode->lang.sub);
1033 return;
1036 langnode = xmalloc(sizeof(resource_lang_node_t));
1037 langnode->res = res;
1038 langnode->lang = get_language(res);
1039 langnode->next = idnode->langs;
1040 idnode->langs = langnode;
1043 static void setup_tabs()
1045 int i;
1047 for (i = 0; i <= res_usr; i++)
1048 switch(i) {
1049 case res_acc:
1050 case res_bmp:
1051 case res_cur:
1052 case res_curg:
1053 case res_dlg:
1054 case res_dlgex:
1055 case res_fnt:
1056 case res_fntdir:
1057 case res_ico:
1058 case res_icog:
1059 case res_men:
1060 case res_menex:
1061 case res_rdt:
1062 case res_stt:
1063 case res_usr:
1064 case res_msg:
1065 case res_ver:
1066 case res_dlginit:
1067 case res_toolbar:
1068 case res_anicur:
1069 case res_aniico:
1070 case res_html:
1071 verify_tab[i].enabled = 1;
1072 break;
1076 static const char *get_typename_for_int(int type) {
1077 resource_t res;
1078 res.type = type;
1079 return get_typename(&res);
1082 static resource_t *find_main(int type, name_id_t *id, resource_lang_node_t *langnode)
1084 resource_t *neutral = NULL, *en = NULL, *en_US = NULL;
1085 for (; langnode; langnode = langnode->next)
1087 if (langnode->lang.id == LANG_NEUTRAL && langnode->lang.sub == SUBLANG_NEUTRAL)
1088 neutral = langnode->res;
1089 if (langnode->lang.id == MASTER_LANGUAGE && langnode->lang.sub == SUBLANG_NEUTRAL)
1090 en = langnode->res;
1091 if (langnode->lang.id == MASTER_LANGUAGE && langnode->lang.sub == MASTER_SUBLANGUAGE)
1092 en_US = langnode->res;
1095 if (neutral != NULL && (en != NULL || en_US != NULL))
1097 fprintf(stderr, "INFO: Resource %04x/%s has both NEUTRAL and MASTER language translarion\n",
1098 type, get_nameid_str(id));
1101 if (en_US != NULL) return en_US;
1102 if (en != NULL) return en;
1103 return neutral;
1106 void verify_translations(resource_t *top) {
1107 resource_t *curr = top;
1108 resource_id_node_t *idnode;
1109 resource_lang_node_t *langnode;
1110 int type;
1112 setup_tabs();
1113 while (curr)
1115 add_resource(curr);
1116 curr = curr->next;
1119 for (type = 0; type <= res_usr; type++)
1121 printf("TYPE NEXT [%s]\n", get_typename_for_int(type));
1122 for (idnode = verify_tab[type].ids; idnode; idnode = idnode->next)
1124 resource_t *mainres;
1125 printf("RESOURCE [%s]\n", get_nameid_str(idnode->id));
1127 mainres = find_main(type, idnode->id, idnode->langs);
1128 if (!mainres)
1130 fprintf(stderr, "ERR: resource %04x/%s has translation(s) but not available in NEUTRAL or MASTER language\n",
1131 type, get_nameid_str(idnode->id));
1132 for (langnode = idnode->langs; langnode; langnode = langnode->next)
1133 printf("EXTRA %03x:%02x\n", langnode->lang.id, langnode->lang.sub);
1134 continue;
1137 if (get_language_id(mainres) == LANG_NEUTRAL && idnode->langs->next == NULL) {
1138 printf("NOTRANSL\n");
1139 continue;
1142 for (langnode = idnode->langs; langnode; langnode = langnode->next)
1144 printf("EXIST %03x:%02x\n", langnode->lang.id, langnode->lang.sub);
1145 dump(langnode->res);
1146 if (compare(langnode->res, mainres))
1148 printf("DIFF %03x:%02x\n", langnode->lang.id, langnode->lang.sub);