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