ddraw/tests: Don't use 0xaa to avoid any confusion when running with +heap.
[wine] / tools / wrc / translation.c
1 /*
2  * Copyright 2003 Vincent BĂ©ron
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <assert.h>
22
23 #include "dumpres.h"
24 #include "utils.h"
25 #include "wrc.h"
26
27 #define MASTER_LANGUAGE LANG_ENGLISH
28 #define MASTER_SUBLANGUAGE SUBLANG_ENGLISH_US
29 #define NB_LANG 0x94
30
31 enum lang_type_e {
32         lang_type_master = 0,
33         lang_type_neutral,
34         lang_type_normal
35 };
36
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();
86         }
87 }
88
89 static int get_language_id(resource_t *resource) {
90     return get_language(resource).id;
91 }
92
93 static int compare_lang(language_t lang1, language_t lang2)
94 {
95     return memcmp(&lang1, &lang2, sizeof(language_t));
96 }
97
98 #if 0
99
100 #define PRETTYPRINTLANG(langid) \
101         if(LANG_##langid == lid) { \
102                 return #langid; \
103         }
104
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";
200 }
201 #endif
202
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;
220         }
221         if(!different &&
222            ((ev1 && !ev2) || (!ev1 && ev2)))
223                 different = 1;
224         return different;
225 }
226
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;
235 }
236
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;
251 }
252
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;
271                 }
272                 if(!different &&
273                    ((cursor1 && !cursor2) ||
274                    (!cursor1 && cursor2)))
275                         different = 1;
276         }
277         return different;
278 }
279
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;
322 }
323
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;
361 }
362
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;
407 }
408
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;
417 }
418
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;
427 }
428
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;
441 }
442
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;
461                 }
462                 if(!different &&
463                    ((icon1 && !icon2) ||
464                    (!icon1 && icon2)))
465                         different = 1;
466         }
467         return different;
468 }
469
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;
487         }
488         if(!different &&
489            ((menu_item1 && !menu_item2) ||
490            (!menu_item1 && menu_item2)))
491                 different = 1;
492         return different;
493 }
494
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;
505 }
506
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;
578         }
579         if(!different &&
580            ((menuex_item1 && !menuex_item2) ||
581            (!menuex_item1 && menuex_item2)))
582                 different = 1;
583         return different;
584 }
585
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;
596 }
597
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;
606 }
607
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;
616 }
617
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;
638                                         }
639                 }
640                 stringtable1 = stringtable1->next;
641                 stringtable2 = stringtable2->next;
642         }
643         return different;
644 }
645
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;
659 }
660
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;
669 }
670
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;
684         }
685         return different;
686 }
687
688 static int compare_ver_block(ver_block_t *ver_block1, ver_block_t *ver_block2);
689
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;
720                                                         }
721                                                 }
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;
737                 }
738         } else
739                 different = 1;
740         return different;
741 }
742
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;
753                 }
754                 if(!different &&
755                    ((ver_value1 && !ver_value2) ||
756                    (!ver_value1 && ver_value2)))
757                         different = 1;
758         }
759         return different;
760 }
761
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;
832                 }
833                 if(!different &&
834                    ((ver_block1 && !ver_block2) ||
835                    (!ver_block1 && ver_block2)))
836                         different = 1;
837         }
838         return different;
839 }
840
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;
849 }
850
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;
859         }
860         if(!different &&
861            ((toolbar_item1 && !toolbar_item2) ||
862            (!toolbar_item1 && toolbar_item2)))
863                 different = 1;
864         return different;
865 }
866
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;
877 }
878
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;
887 }
888
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;
939         }
940 }
941
942 static void dump_stringtable(resource_t *res)
943 {
944     stringtable_t *stt = res->res.stt;
945     int j;
946
947     printf("DUMP ");
948     assert((stt->idbase%16) == 0);
949     assert(stt->nentries == 16);
950     for (j = 0; j < stt->nentries; j++)
951     {
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;
957
958         if (entry->str)
959         {
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);
966         }
967         else
968             printf("0000");
969     }
970     putchar('\n');
971 }
972
973 static void dump(resource_t *res)
974 {
975     switch (res->type)
976     {
977         case res_stt:
978             dump_stringtable(res);
979             return;
980         default:
981             break;
982     }
983 }
984
985 typedef struct resource_lang_node
986 {
987     language_t lang;
988     resource_t *res;
989     struct resource_lang_node *next;
990 } resource_lang_node_t;
991
992 typedef struct resource_id_node
993 {
994     name_id_t *id;
995     resource_lang_node_t *langs;
996     struct resource_id_node *next;
997 } resource_id_node_t;
998
999 struct
1000 {
1001     int enabled;
1002     struct resource_id_node *ids;
1003 } verify_tab[res_usr+1];
1004
1005 static void add_resource(resource_t *res)
1006 {
1007     resource_id_node_t *idnode;
1008     resource_lang_node_t *langnode;
1009     if (!verify_tab[res->type].enabled)
1010     {
1011         fprintf(stderr, "ERR: Report this: unknown resource type parsed %08x\n", res->type);
1012         return;
1013     }
1014
1015     for (idnode = verify_tab[res->type].ids; idnode; idnode = idnode->next)
1016         if (compare_name_id(idnode->id, res->name) == 0)
1017             break;
1018
1019     if (idnode == NULL)
1020     {
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;
1026     }
1027
1028     for (langnode = idnode->langs; langnode; langnode = langnode->next)
1029         if (compare_lang(langnode->lang, get_language(res)) == 0)
1030         {
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;
1034         }
1035
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;
1041 }
1042
1043 static void setup_tabs(void)
1044 {
1045     int i;
1046
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;
1073         }
1074 }
1075
1076 static const char *get_typename_for_int(int type) {
1077     resource_t res;
1078     res.type = type;
1079     return get_typename(&res);
1080 }
1081
1082 static resource_t *find_main(int type, name_id_t *id, resource_lang_node_t *langnode)
1083 {
1084     resource_t *neutral = NULL, *en = NULL, *en_US = NULL;
1085     for (; langnode; langnode = langnode->next)
1086     {
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;
1093     }
1094
1095     if (neutral != NULL && (en != NULL || en_US != NULL))
1096     {
1097         fprintf(stderr, "INFO: Resource %04x/%s has both NEUTRAL and MASTER language translarion\n",
1098             type, get_nameid_str(id));
1099     }
1100
1101     if (en_US != NULL) return en_US;
1102     if (en != NULL) return en;
1103     return neutral;
1104 }
1105
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;
1111
1112     setup_tabs();
1113     while (curr)
1114     {
1115         add_resource(curr);
1116         curr = curr->next;
1117     }
1118
1119     for (type = 0; type <= res_usr; type++)
1120     {
1121         printf("TYPE NEXT [%s]\n", get_typename_for_int(type));
1122         for (idnode = verify_tab[type].ids; idnode; idnode = idnode->next)
1123         {
1124             resource_t *mainres;
1125             printf("RESOURCE [%s]\n", get_nameid_str(idnode->id));
1126
1127             mainres = find_main(type, idnode->id, idnode->langs);
1128             if (!mainres)
1129             {
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;
1135             }
1136
1137             if (get_language_id(mainres) == LANG_NEUTRAL && idnode->langs->next == NULL) {
1138                 printf("NOTRANSL\n");
1139                 continue;
1140             }
1141
1142             for (langnode = idnode->langs; langnode; langnode = langnode->next)
1143             {
1144                 printf("EXIST %03x:%02x\n", langnode->lang.id, langnode->lang.sub);
1145                 dump(langnode->res);
1146                 if (compare(langnode->res, mainres))
1147                 {
1148                     printf("DIFF %03x:%02x\n", langnode->lang.id, langnode->lang.sub);
1149                 }
1150             }
1151         }
1152     }
1153 }