server: Define an lparam_t type for message parameters that can hold all sorts of...
[wine] / tools / wrc / translation.c
1 /*
2  * Copyright 2003 Vincent BĂ©ron
3  * Copyright 2007, 2008 Mikolaj Zalewski
4  *
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.
9  *
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.
14  *
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
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <assert.h>
23
24 #include "dumpres.h"
25 #include "utils.h"
26 #include "wrc.h"
27
28 #define MASTER_LANGUAGE LANG_ENGLISH
29 #define MASTER_SUBLANGUAGE SUBLANG_ENGLISH_US
30 #define NB_LANG 0x94
31
32 enum lang_type_e {
33         lang_type_master = 0,
34         lang_type_neutral,
35         lang_type_normal
36 };
37
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();
87         }
88 }
89
90 static int get_language_id(resource_t *resource) {
91     return get_language(resource).id;
92 }
93
94 static int compare_lang(language_t lang1, language_t lang2)
95 {
96     return memcmp(&lang1, &lang2, sizeof(language_t));
97 }
98
99 #if 0
100
101 #define PRETTYPRINTLANG(langid) \
102         if(LANG_##langid == lid) { \
103                 return #langid; \
104         }
105
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";
201 }
202 #endif
203
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;
221         }
222         if(!different &&
223            ((ev1 && !ev2) || (!ev1 && ev2)))
224                 different = 1;
225         return different;
226 }
227
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;
236 }
237
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;
252 }
253
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;
272                 }
273                 if(!different &&
274                    ((cursor1 && !cursor2) ||
275                    (!cursor1 && cursor2)))
276                         different = 1;
277         }
278         return different;
279 }
280
281 static int compare_control(control_t *control1, control_t *control2) {
282         int different = 0;
283         char *nameid = NULL;
284         int ignore_style;
285         if(!different &&
286                 ((control1 && !control2) ||
287                 (!control1 && control2)))
288                         different = 1;
289         if(different || !control1 || !control2)
290                 return different;
291         nameid = strdup(get_nameid_str(control1->ctlclass));
292         if(!different && strcmp(nameid, get_nameid_str(control2->ctlclass)))
293                 different = 1;
294         free(nameid);
295         if (different)
296             return different;
297
298         /* allow the translators to set some styles */
299         ignore_style = 0;
300         if (control1->ctlclass->type == name_ord && control1->ctlclass->name.i_name == CT_BUTTON)
301             ignore_style = 0x2000;          /* BS_MULTILINE*/
302
303         if(!different && 
304            (control1->id != control2->id))
305                 different = 1;
306         if(!different && control1->gotstyle && control2->gotstyle) {
307                 if((!control1->style || !control2->style) ||
308                    (control1->style->and_mask || control2->style->and_mask) ||
309                    ((control1->style->or_mask & ~ignore_style) != (control2->style->or_mask & ~ignore_style)))
310                         different = 1;
311         } else if(!different &&
312                   ((control1->gotstyle && !control2->gotstyle) ||
313                   (!control1->gotstyle && control2->gotstyle)))
314                         different = 1;
315         if(!different && control1->gotexstyle && control2->gotexstyle) {
316                 if((!control1->exstyle || !control2->exstyle) ||
317                    (control1->exstyle->and_mask || control2->exstyle->and_mask) ||
318                    (control1->exstyle->or_mask != control2->exstyle->or_mask))
319                         different = 1;
320         } else if(!different &&
321                   ((control1->gotexstyle && !control2->gotexstyle) ||
322                   (!control1->gotexstyle && control2->gotexstyle)))
323                         different = 1;
324         if(!different && control1->gothelpid && control2->gothelpid) {
325                 if(control1->helpid != control2->helpid)
326                         different = 1;
327         } else if(!different &&
328                   ((control1->gothelpid && !control2->gothelpid) ||
329                   (!control1->gothelpid && control2->gothelpid)))
330                         different = 1;
331         return different;
332 }
333
334 static int compare_dialog(dialog_t *dialog1, dialog_t *dialog2) {
335         int different = 0;
336         char *nameid = NULL;
337         control_t *ctrl1, *ctrl2;
338         if(!different &&
339            ((dialog1->memopt != dialog2->memopt) ||
340            (dialog1->lvc.version != dialog2->lvc.version) ||
341            (dialog1->lvc.characts != dialog2->lvc.characts)))
342                 different = 1;
343         if(!different && dialog1->gotstyle && dialog2->gotstyle) {
344                 if((!dialog1->style || !dialog2->style) ||
345                    (dialog1->style->and_mask || dialog2->style->and_mask) ||
346                    (dialog1->style->or_mask != dialog2->style->or_mask))
347                         different = 1;
348         } else if(!different &&
349                   ((dialog1->gotstyle && !dialog2->gotstyle) ||
350                   (!dialog1->gotstyle && dialog2->gotstyle)))
351                         different = 1;
352         if(!different && dialog1->gotexstyle && dialog2->gotexstyle) {
353                 if((!dialog1->exstyle || !dialog2->exstyle) ||
354                    (dialog1->exstyle->and_mask || dialog2->exstyle->and_mask) ||
355                    (dialog1->exstyle->or_mask != dialog2->exstyle->or_mask))
356                         different = 1;
357         } else if(!different &&
358                   ((dialog1->gotexstyle && !dialog2->gotexstyle) ||
359                   (!dialog1->gotexstyle && dialog2->gotexstyle)))
360                         different = 1;
361         nameid = strdup(get_nameid_str(dialog1->menu));
362         if(!different && strcmp(nameid, get_nameid_str(dialog2->menu)))
363                 different = 1;
364         free(nameid);
365         nameid = strdup(get_nameid_str(dialog1->dlgclass));
366         if(!different && strcmp(nameid, get_nameid_str(dialog2->dlgclass)))
367                 different = 1;
368         free(nameid);
369
370         ctrl1 = dialog1->controls;
371         ctrl2 = dialog2->controls;
372         while(!different && (ctrl1 || ctrl2))
373         {
374             different = compare_control(ctrl1, ctrl2);
375             if (ctrl1) ctrl1 = ctrl1->next;
376             if (ctrl2) ctrl2 = ctrl2->next;
377         }
378         return different;
379 }
380
381 static int compare_dialogex(dialogex_t *dialogex1, dialogex_t *dialogex2) {
382         int different = 0;
383         char *nameid = NULL;
384         control_t *ctrl1, *ctrl2;
385         if(!different &&
386            ((dialogex1->memopt != dialogex2->memopt) ||
387            (dialogex1->lvc.version != dialogex2->lvc.version) ||
388            (dialogex1->lvc.characts != dialogex2->lvc.characts)))
389                 different = 1;
390         if(!different && dialogex1->gotstyle && dialogex2->gotstyle) {
391                 if((!dialogex1->style || !dialogex2->style) ||
392                    (dialogex1->style->and_mask || dialogex2->style->and_mask) ||
393                    (dialogex1->style->or_mask != dialogex2->style->or_mask))
394                         different = 1;
395         } else if(!different &&
396                   ((dialogex1->gotstyle && !dialogex2->gotstyle) ||
397                   (!dialogex1->gotstyle && dialogex2->gotstyle)))
398                         different = 1;
399         if(!different && dialogex1->gotexstyle && dialogex2->gotexstyle) {
400                 if((!dialogex1->exstyle || !dialogex2->exstyle) ||
401                    (dialogex1->exstyle->and_mask || dialogex2->exstyle->and_mask) ||
402                    (dialogex1->exstyle->or_mask != dialogex2->exstyle->or_mask))
403                         different = 1;
404         } else if(!different &&
405                   ((dialogex1->gotexstyle && !dialogex2->gotexstyle) ||
406                   (!dialogex1->gotexstyle && dialogex2->gotexstyle)))
407                         different = 1;
408         if(!different && dialogex1->gothelpid && dialogex2->gothelpid) {
409                 if(dialogex1->helpid != dialogex2->helpid)
410                         different = 1;
411         } else if(!different &&
412                   ((dialogex1->gothelpid && !dialogex2->gothelpid) ||
413                   (!dialogex1->gothelpid && dialogex2->gothelpid)))
414                         different = 1;
415         nameid = strdup(get_nameid_str(dialogex1->menu));
416         if(!different && strcmp(nameid, get_nameid_str(dialogex2->menu)))
417                 different = 1;
418         free(nameid);
419         nameid = strdup(get_nameid_str(dialogex1->dlgclass));
420         if(!different && strcmp(nameid, get_nameid_str(dialogex2->dlgclass)))
421                 different = 1;
422         free(nameid);
423
424         ctrl1 = dialogex1->controls;
425         ctrl2 = dialogex2->controls;
426         while(!different && (ctrl1 || ctrl2))
427         {
428             different = compare_control(ctrl1, ctrl2);
429             if (ctrl1) ctrl1 = ctrl1->next;
430             if (ctrl2) ctrl2 = ctrl2->next;
431         }
432         return different;
433 }
434
435 static int compare_font(font_t *font1, font_t *font2) {
436         int different = 0;
437         if(!different &&
438            ((font1->memopt != font2->memopt) ||
439            (font1->data->lvc.version != font2->data->lvc.version) ||
440            (font1->data->lvc.characts != font2->data->lvc.characts)))
441                 different = 1;
442         return different;
443 }
444
445 static int compare_fontdir(fontdir_t *fontdir1, fontdir_t *fontdir2) {
446         int different = 0;
447         if(!different &&
448            ((fontdir1->memopt != fontdir2->memopt) ||
449            (fontdir1->data->lvc.version != fontdir2->data->lvc.version) ||
450            (fontdir1->data->lvc.characts != fontdir2->data->lvc.characts)))
451                 different = 1;
452         return different;
453 }
454
455 static int compare_icon(icon_t *icon1, icon_t *icon2) {
456         int different = 0;
457         if(!different &&
458            ((icon1->id != icon2->id) ||
459            (icon1->width != icon2->width) ||
460            (icon1->height != icon2->height)))
461                 different = 1;
462         if(!different &&
463            ((icon1->lvc.version != icon2->lvc.version) ||
464            (icon1->lvc.characts != icon2->lvc.characts)))
465                 different = 1;
466         return different;
467 }
468
469 static int compare_icon_group(icon_group_t *icon_group1, icon_group_t *icon_group2) {
470         int different = 0;
471         icon_t *icon1 = NULL, *icon2 = NULL;
472         if(!different &&
473            ((icon_group1->memopt != icon_group2->memopt) ||
474            (icon_group1->lvc.version != icon_group2->lvc.version) ||
475            (icon_group1->lvc.characts != icon_group2->lvc.characts)))
476                 different = 1;
477         if(!different &&
478            (icon_group1->nicon != icon_group2->nicon))
479                 different = 1;
480         if(!different) {
481                 icon1 = icon_group1->iconlist;
482                 icon2 = icon_group2->iconlist;
483                 while(!different && icon1 && icon2) {
484                         different = compare_icon(icon1, icon2);
485                         icon1 = icon1->next;
486                         icon2 = icon2->next;
487                 }
488                 if(!different &&
489                    ((icon1 && !icon2) ||
490                    (!icon1 && icon2)))
491                         different = 1;
492         }
493         return different;
494 }
495
496 static int compare_menu_item(menu_item_t *menu_item1, menu_item_t *menu_item2) {
497         int different = 0;
498         while(!different && menu_item1 && menu_item2) {
499                 if(menu_item1->popup && menu_item2->popup)
500                         different = compare_menu_item(menu_item1->popup, menu_item2->popup);
501                 else if(!menu_item1->popup && !menu_item2->popup) {
502                         if(menu_item1->name && menu_item2->name) {
503                                 if((menu_item1->id != menu_item2->id) ||
504                                    (menu_item1->state != menu_item2->state))
505                                         different = 1;
506                         } else if((menu_item1->name && !menu_item2->name) ||
507                                   (!menu_item1->name && menu_item2->name))
508                                         different = 1;
509                 } else
510                         different = 1;
511                 menu_item1 = menu_item1->next;
512                 menu_item2 = menu_item2->next;
513         }
514         if(!different &&
515            ((menu_item1 && !menu_item2) ||
516            (!menu_item1 && menu_item2)))
517                 different = 1;
518         return different;
519 }
520
521 static int compare_menu(menu_t *menu1, menu_t *menu2) {
522         int different = 0;
523         if(!different &&
524            ((menu1->memopt != menu2->memopt) ||
525            (menu1->lvc.version != menu2->lvc.version) ||
526            (menu1->lvc.characts != menu2->lvc.characts)))
527                 different = 1;
528         if(!different)
529                 different = compare_menu_item(menu1->items, menu2->items);
530         return different;
531 }
532
533 static int compare_menuex_item(menuex_item_t *menuex_item1, menuex_item_t *menuex_item2) {
534         int different = 0;
535         while(!different && menuex_item1 && menuex_item2) {
536                 if(menuex_item1->popup && menuex_item2->popup) {
537                         if(!different && menuex_item1->gotid && menuex_item2->gotid) {
538                                 if(menuex_item1->id != menuex_item2->id)
539                                         different = 1;
540                         } else if(!different &&
541                                   ((menuex_item1->gotid && !menuex_item2->gotid) ||
542                                   (!menuex_item2->gotid && menuex_item2->gotid)))
543                                         different = 1;
544                         if(!different && menuex_item1->gottype && menuex_item2->gottype) {
545                                 if(menuex_item1->type != menuex_item2->type)
546                                         different = 1;
547                         } else if(!different &&
548                                   ((menuex_item1->gottype && !menuex_item2->gottype) ||
549                                   (!menuex_item2->gottype && menuex_item2->gottype)))
550                                         different = 1;
551                         if(!different && menuex_item1->gotstate && menuex_item2->gotstate) {
552                                 if(menuex_item1->state != menuex_item2->state)
553                                         different = 1;
554                         } else if(!different &&
555                                   ((menuex_item1->gotstate && !menuex_item2->gotstate) ||
556                                   (!menuex_item2->gotstate && menuex_item2->gotstate)))
557                                         different = 1;
558                         if(!different && menuex_item1->gothelpid && menuex_item2->gothelpid) {
559                                 if(menuex_item1->helpid != menuex_item2->helpid)
560                                         different = 1;
561                         } else if(!different &&
562                                   ((menuex_item1->gothelpid && !menuex_item2->gothelpid) ||
563                                   (!menuex_item2->gothelpid && menuex_item2->gothelpid)))
564                                         different = 1;
565                         if(!different)
566                                 different = compare_menuex_item(menuex_item1->popup, menuex_item2->popup);
567                 } else if(!menuex_item1->popup && !menuex_item2->popup) {
568                         if(menuex_item1->name && menuex_item2->name) {
569                                 if(!different && menuex_item1->gotid && menuex_item2->gotid) {
570                                         if(menuex_item1->id != menuex_item2->id)
571                                                 different = 1;
572                                 } else if(!different &&
573                                           ((menuex_item1->gotid && !menuex_item2->gotid) ||
574                                           (!menuex_item2->gotid && menuex_item2->gotid)))
575                                                 different = 1;
576                                 if(!different && menuex_item1->gottype && menuex_item2->gottype) {
577                                         if(menuex_item1->type != menuex_item2->type)
578                                                 different = 1;
579                                 } else if(!different &&
580                                           ((menuex_item1->gottype && !menuex_item2->gottype) ||
581                                           (!menuex_item2->gottype && menuex_item2->gottype)))
582                                                 different = 1;
583                                 if(!different && menuex_item1->gotstate && menuex_item2->gotstate) {
584                                         if(menuex_item1->state != menuex_item2->state)
585                                                 different = 1;
586                                 } else if(!different &&
587                                           ((menuex_item1->gotstate && !menuex_item2->gotstate) ||
588                                           (!menuex_item2->gotstate && menuex_item2->gotstate)))
589                                                 different = 1;
590                                 if(!different && menuex_item1->gothelpid && menuex_item2->gothelpid) {
591                                         if(menuex_item1->helpid != menuex_item2->helpid)
592                                                 different = 1;
593                                 } else if(!different &&
594                                           ((menuex_item1->gothelpid && !menuex_item2->gothelpid) ||
595                                           (!menuex_item2->gothelpid && menuex_item2->gothelpid)))
596                                                 different = 1;
597                         } else if((menuex_item1->name && !menuex_item2->name) ||
598                                   (!menuex_item1->name && menuex_item2->name))
599                                         different = 1;
600                 } else
601                         different = 1;
602                 menuex_item1 = menuex_item1->next;
603                 menuex_item2 = menuex_item2->next;
604         }
605         if(!different &&
606            ((menuex_item1 && !menuex_item2) ||
607            (!menuex_item1 && menuex_item2)))
608                 different = 1;
609         return different;
610 }
611
612 static int compare_menuex(menuex_t *menuex1, menuex_t *menuex2) {
613         int different = 0;
614         if(!different &&
615            ((menuex1->memopt != menuex2->memopt) ||
616            (menuex1->lvc.version != menuex2->lvc.version) ||
617            (menuex1->lvc.characts != menuex2->lvc.characts)))
618                 different = 1;
619         if(!different)
620                 different = compare_menuex_item(menuex1->items, menuex2->items);
621         return different;
622 }
623
624 static int compare_rcdata(rcdata_t *rcdata1, rcdata_t *rcdata2) {
625         int different = 0;
626         if(!different &&
627            ((rcdata1->memopt != rcdata2->memopt) ||
628            (rcdata1->data->lvc.version != rcdata2->data->lvc.version) ||
629            (rcdata1->data->lvc.characts != rcdata2->data->lvc.characts)))
630                 different = 1;
631         return different;
632 }
633
634 static int compare_html(html_t *rcdata1, html_t *rcdata2) {
635         int different = 0;
636         if(!different &&
637            ((rcdata1->memopt != rcdata2->memopt) ||
638            (rcdata1->data->lvc.version != rcdata2->data->lvc.version) ||
639            (rcdata1->data->lvc.characts != rcdata2->data->lvc.characts)))
640                 different = 1;
641         return different;
642 }
643
644 static int compare_stringtable(stringtable_t *stringtable1, stringtable_t *stringtable2) {
645         int different = 0;
646         int i;
647         while(!different && stringtable1 && stringtable2) {
648                 if((stringtable1->memopt != stringtable2->memopt) ||
649                    (stringtable1->lvc.version != stringtable2->lvc.version) ||
650                    (stringtable1->lvc.characts != stringtable2->lvc.characts))
651                         different = 1;
652                 if(!different) {
653                         if((stringtable1->nentries != stringtable2->nentries) ||
654                            (stringtable1->idbase != stringtable2->idbase))
655                                 different = 1;
656                         else
657                                 for(i = 0 ; i < stringtable1->nentries; i++)
658                                         if((stringtable1->entries[i].id != stringtable2->entries[i].id) ||
659                                            (stringtable1->entries[i].memopt != stringtable2->entries[i].memopt) ||
660                                            (stringtable1->entries[i].str && !stringtable2->entries[i].str) ||
661                                            (!stringtable1->entries[i].str && stringtable2->entries[i].str)) {
662                                                 different = 1;
663                                                 break;
664                                         }
665                 }
666                 stringtable1 = stringtable1->next;
667                 stringtable2 = stringtable2->next;
668         }
669         return different;
670 }
671
672 static int compare_user(user_t *user1, user_t *user2) {
673         int different = 0;
674         char *nameid = NULL;
675         if(!different &&
676            ((user1->memopt != user2->memopt) ||
677            (user1->data->lvc.version != user2->data->lvc.version) ||
678            (user1->data->lvc.characts != user2->data->lvc.characts)))
679                 different = 1;
680         nameid = strdup(get_nameid_str(user1->type));
681         if(!different && strcmp(nameid, get_nameid_str(user2->type)))
682                 different = 1;
683         free(nameid);
684         return different;
685 }
686
687 static int compare_messagetable(messagetable_t *messagetable1, messagetable_t *messagetable2) {
688         int different = 0;
689         if(!different &&
690            ((messagetable1->memopt != messagetable2->memopt) ||
691            (messagetable1->data->lvc.version != messagetable2->data->lvc.version) ||
692            (messagetable1->data->lvc.characts != messagetable2->data->lvc.characts)))
693                 different = 1;
694         return different;
695 }
696
697 static int compare_string(string_t *string1, string_t *string2) {
698         int different = 0;
699         if(!different &&
700            ((string1->size != string2->size) ||
701            (string1->type != string2->type)))
702                 different = 1;
703         if(!different) {
704                 if(string1->type == str_char)
705                         different = memcmp(string1->str.cstr, string2->str.cstr, string1->size);
706                 else if(string1->type == str_unicode)
707                         different = memcmp(string1->str.wstr, string2->str.wstr, string1->size*sizeof(WCHAR));
708                 else
709                         different = 1;
710         }
711         return different;
712 }
713
714 static int compare_ver_block(ver_block_t *ver_block1, ver_block_t *ver_block2);
715
716 static int compare_ver_value(ver_value_t *ver_value1, ver_value_t *ver_value2) {
717         int different = 0;
718         int i = 0;
719         if(!different &&
720            (ver_value1->type == ver_value2->type)) {
721                 switch(ver_value1->type) {
722                         case val_str:
723                                 if(!different && ver_value1->key && ver_value2->key)
724                                         different = compare_string(ver_value1->key, ver_value2->key);
725                                 else if(!different &&
726                                         ((ver_value1->key && !ver_value2->key) ||
727                                         (!ver_value1->key && ver_value2->key)))
728                                                 different = 1;
729                                 break;
730                         case val_words:
731                                 if(!different && ver_value1->key && ver_value2->key)
732                                         different = compare_string(ver_value1->key, ver_value2->key);
733                                 else if(!different &&
734                                         ((ver_value1->key && !ver_value2->key) ||
735                                         (!ver_value1->key && ver_value2->key)))
736                                                 different = 1;
737                                 if(!different && ver_value1->value.words && ver_value2->value.words) {
738                                         if(!different &&
739                                            (ver_value1->value.words->nwords != ver_value2->value.words->nwords))
740                                                 different = 1;
741                                         if(!different)
742                                                 for(i = 0; i < ver_value1->value.words->nwords; i++) {
743                                                         if(ver_value1->value.words->words[i] != ver_value2->value.words->words[i]) {
744                                                                 different = 1;
745                                                                 break;
746                                                         }
747                                                 }
748                                 } else if(!different &&
749                                           ((ver_value1->value.words && !ver_value2->value.words) ||
750                                           (!ver_value1->value.words && ver_value2->value.words)))
751                                                 different = 1;
752                                 break;
753                         case val_block:
754                                 if(!different && ver_value1->value.block && ver_value2->value.block)
755                                         different = compare_ver_block(ver_value1->value.block, ver_value2->value.block);
756                                 else if(!different &&
757                                         ((ver_value1->value.block && !ver_value2->value.block) ||
758                                         (!ver_value1->value.block && ver_value2->value.block)))
759                                                 different = 1;
760                                 break;
761                         default:
762                                 different = 1;
763                 }
764         } else
765                 different = 1;
766         return different;
767 }
768
769 static int compare_ver_block(ver_block_t *ver_block1, ver_block_t *ver_block2) {
770         int different = 0;
771         ver_value_t *ver_value1 = NULL, *ver_value2 = NULL;
772         if(!different) {
773                 ver_value1 = ver_block1->values;
774                 ver_value2 = ver_block2->values;
775                 while(!different && ver_value1 && ver_value2) {
776                         different = compare_ver_value(ver_value1, ver_value2);
777                         ver_value1 = ver_value1->next;
778                         ver_value2 = ver_value2->next;
779                 }
780                 if(!different &&
781                    ((ver_value1 && !ver_value2) ||
782                    (!ver_value1 && ver_value2)))
783                         different = 1;
784         }
785         return different;
786 }
787
788 static int compare_versioninfo(versioninfo_t *versioninfo1, versioninfo_t *versioninfo2) {
789         int different = 0;
790         ver_block_t *ver_block1 = NULL, *ver_block2 = NULL;
791         if(!different &&
792            ((versioninfo1->memopt != versioninfo2->memopt) ||
793            (versioninfo1->lvc.version != versioninfo2->lvc.version) ||
794            (versioninfo1->lvc.characts != versioninfo2->lvc.characts)))
795                 different = 1;
796         if(!different && versioninfo1->gotit.fv && versioninfo2->gotit.fv) {
797                 if((versioninfo1->filever_maj1 != versioninfo2->filever_maj1) ||
798                    (versioninfo1->filever_maj2 != versioninfo2->filever_maj2) ||
799                    (versioninfo1->filever_min1 != versioninfo2->filever_min1) ||
800                    (versioninfo1->filever_min2 != versioninfo2->filever_min2))
801                         different = 1;
802         } else if(!different &&
803                   ((versioninfo1->gotit.fv && !versioninfo2->gotit.fv) ||
804                   (!versioninfo1->gotit.fv && versioninfo2->gotit.fv)))
805                         different = 1;
806         if(!different && versioninfo1->gotit.pv && versioninfo2->gotit.pv) {
807                 if((versioninfo1->prodver_maj1 != versioninfo2->prodver_maj1) ||
808                    (versioninfo1->prodver_maj2 != versioninfo2->prodver_maj2) ||
809                    (versioninfo1->prodver_min1 != versioninfo2->prodver_min1) ||
810                    (versioninfo1->prodver_min2 != versioninfo2->prodver_min2))
811                         different = 1;
812         } else if(!different &&
813                   ((versioninfo1->gotit.pv && !versioninfo2->gotit.pv) ||
814                   (!versioninfo1->gotit.pv && versioninfo2->gotit.pv)))
815                         different = 1;
816         if(!different && versioninfo1->gotit.fo && versioninfo2->gotit.fo) {
817                 if(versioninfo1->fileos != versioninfo2->fileos)
818                         different = 1;
819         } else if(!different &&
820                   ((versioninfo1->gotit.fo && !versioninfo2->gotit.fo) ||
821                   (!versioninfo1->gotit.fo && versioninfo2->gotit.fo)))
822                         different = 1;
823         if(!different && versioninfo1->gotit.ff && versioninfo2->gotit.ff) {
824                 if(versioninfo1->fileflags != versioninfo2->fileflags)
825                         different = 1;
826         } else if(!different &&
827                   ((versioninfo1->gotit.ff && !versioninfo2->gotit.ff) ||
828                   (!versioninfo1->gotit.ff && versioninfo2->gotit.ff)))
829                         different = 1;
830         if(!different && versioninfo1->gotit.ffm && versioninfo2->gotit.ffm) {
831                 if(versioninfo1->fileflagsmask != versioninfo2->fileflagsmask)
832                         different = 1;
833         } else if(!different &&
834                   ((versioninfo1->gotit.ffm && !versioninfo2->gotit.ffm) ||
835                   (!versioninfo1->gotit.ffm && versioninfo2->gotit.ffm)))
836                         different = 1;
837         if(!different && versioninfo1->gotit.ft && versioninfo2->gotit.ft) {
838                 if(versioninfo1->filetype != versioninfo2->filetype)
839                         different = 1;
840         } else if(!different &&
841                   ((versioninfo1->gotit.ft && !versioninfo2->gotit.ft) ||
842                   (!versioninfo1->gotit.ft && versioninfo2->gotit.ft)))
843                         different = 1;
844         if(!different && versioninfo1->gotit.fst && versioninfo2->gotit.fst) {
845                 if(versioninfo1->filesubtype != versioninfo2->filesubtype)
846                         different = 1;
847         } else if(!different &&
848                   ((versioninfo1->gotit.fst && !versioninfo2->gotit.fst) ||
849                   (!versioninfo1->gotit.fst && versioninfo2->gotit.fst)))
850                         different = 1;
851         if(!different) {
852                 ver_block1 = versioninfo1->blocks;
853                 ver_block2 = versioninfo2->blocks;
854                 while(!different && ver_block1 && ver_block2) {
855                         different = compare_ver_block(ver_block1, ver_block2);
856                         ver_block1 = ver_block1->next;
857                         ver_block2 = ver_block2->next;
858                 }
859                 if(!different &&
860                    ((ver_block1 && !ver_block2) ||
861                    (!ver_block1 && ver_block2)))
862                         different = 1;
863         }
864         return different;
865 }
866
867 static int compare_dlginit(dlginit_t *dlginit1, dlginit_t *dlginit2) {
868         int different = 0;
869         if(!different &&
870            ((dlginit1->memopt != dlginit2->memopt) ||
871            (dlginit1->data->lvc.version != dlginit2->data->lvc.version) ||
872            (dlginit1->data->lvc.characts != dlginit2->data->lvc.characts)))
873                 different = 1;
874         return different;
875 }
876
877 static int compare_toolbar_item(toolbar_item_t *toolbar_item1, toolbar_item_t *toolbar_item2) {
878         int different = 0;
879         while(!different && toolbar_item1 && toolbar_item2) {
880                 if((toolbar_item1->id && !toolbar_item2->id) ||
881                    (!toolbar_item1->id && toolbar_item2->id))
882                         different = 1;
883                 toolbar_item1 = toolbar_item1->next;
884                 toolbar_item2 = toolbar_item2->next;
885         }
886         if(!different &&
887            ((toolbar_item1 && !toolbar_item2) ||
888            (!toolbar_item1 && toolbar_item2)))
889                 different = 1;
890         return different;
891 }
892
893 static int compare_toolbar(toolbar_t *toolbar1, toolbar_t *toolbar2) {
894         int different = 0;
895         if(!different &&
896            ((toolbar1->memopt != toolbar2->memopt) ||
897            (toolbar1->lvc.version != toolbar2->lvc.version) ||
898            (toolbar1->lvc.characts != toolbar2->lvc.characts)))
899                 different = 1;
900         if(!different)
901                 different = compare_toolbar_item(toolbar1->items, toolbar2->items);
902         return different;
903 }
904
905 static int compare_ani_curico(ani_curico_t *ani_curico1, ani_curico_t *ani_curico2) {
906         int different = 0;
907         if(!different &&
908            ((ani_curico1->memopt != ani_curico2->memopt) ||
909            (ani_curico1->data->lvc.version != ani_curico2->data->lvc.version) ||
910            (ani_curico1->data->lvc.characts != ani_curico2->data->lvc.characts)))
911                 different = 1;
912         return different;
913 }
914
915 static int compare(resource_t *resource1, resource_t *resource2) {
916         switch(resource1->type) {
917                 case res_acc:
918                         return compare_accelerator(resource1->res.acc, resource2->res.acc);
919                 case res_bmp:
920                         return compare_bitmap(resource1->res.bmp, resource2->res.bmp);
921                 case res_cur:
922                         return compare_cursor(resource1->res.cur, resource2->res.cur);
923                 case res_curg:
924                         return compare_cursor_group(resource1->res.curg, resource2->res.curg);
925                 case res_dlg:
926                         return compare_dialog(resource1->res.dlg, resource2->res.dlg);
927                 case res_dlgex:
928                         return compare_dialogex(resource1->res.dlgex, resource2->res.dlgex);
929                 case res_fnt:
930                         return compare_font(resource1->res.fnt, resource2->res.fnt);
931                 case res_fntdir:
932                         return compare_fontdir(resource1->res.fnd, resource2->res.fnd);
933                 case res_ico:
934                         return compare_icon(resource1->res.ico, resource2->res.ico);
935                 case res_icog:
936                         return compare_icon_group(resource1->res.icog, resource2->res.icog);
937                 case res_men:
938                         return compare_menu(resource1->res.men, resource2->res.men);
939                 case res_menex:
940                         return compare_menuex(resource1->res.menex, resource2->res.menex);
941                 case res_rdt:
942                         return compare_rcdata(resource1->res.rdt, resource2->res.rdt);
943                 case res_stt:
944                         return compare_stringtable(resource1->res.stt, resource2->res.stt);
945                 case res_usr:
946                         return compare_user(resource1->res.usr, resource2->res.usr);
947                 case res_html:
948                         return compare_html(resource1->res.html, resource2->res.html);
949                 case res_msg:
950                         return compare_messagetable(resource1->res.msg, resource2->res.msg);
951                 case res_ver:
952                         return compare_versioninfo(resource1->res.ver, resource2->res.ver);
953                 case res_dlginit:
954                         return compare_dlginit(resource1->res.dlgi, resource2->res.dlgi);
955                 case res_toolbar:
956                         return compare_toolbar(resource1->res.tbt, resource2->res.tbt);
957                 case res_anicur:
958                 case res_aniico:
959                         return compare_ani_curico(resource1->res.ani, resource2->res.ani);
960                 default:
961                         /* Not supposed to reach here */
962                         fprintf(stderr, "Not supposed to reach here (compare())\n");
963                         abort();
964                         return -1;
965         }
966 }
967
968 typedef struct resource_lang_node
969 {
970     language_t lang;
971     resource_t *res;
972     struct resource_lang_node *next;
973 } resource_lang_node_t;
974
975 typedef struct resource_id_node
976 {
977     name_id_t *id;
978     resource_lang_node_t *langs;
979     struct resource_id_node *next;
980 } resource_id_node_t;
981
982 struct
983 {
984     int enabled;
985     struct resource_id_node *ids;
986 } verify_tab[res_usr+1];
987
988 static void add_resource(resource_t *res)
989 {
990     resource_id_node_t *idnode;
991     resource_lang_node_t *langnode;
992     if (!verify_tab[res->type].enabled)
993     {
994         fprintf(stderr, "ERR: Report this: unknown resource type parsed %08x\n", res->type);
995         return;
996     }
997
998     for (idnode = verify_tab[res->type].ids; idnode; idnode = idnode->next)
999         if (compare_name_id(idnode->id, res->name) == 0)
1000             break;
1001
1002     if (idnode == NULL)
1003     {
1004         idnode = xmalloc(sizeof(resource_id_node_t));
1005         idnode->id = res->name;
1006         idnode->langs = NULL;
1007         idnode->next = verify_tab[res->type].ids;
1008         verify_tab[res->type].ids = idnode;
1009     }
1010
1011     for (langnode = idnode->langs; langnode; langnode = langnode->next)
1012         if (compare_lang(langnode->lang, get_language(res)) == 0)
1013         {
1014             fprintf(stderr, "ERR: resource %s [type %x] language %03x:%02x duplicated!\n",
1015                 get_nameid_str(res->name), res->type, langnode->lang.id, langnode->lang.sub);
1016             return;
1017         }
1018
1019     langnode = xmalloc(sizeof(resource_lang_node_t));
1020     langnode->res = res;
1021     langnode->lang = get_language(res);
1022     langnode->next = idnode->langs;
1023     idnode->langs = langnode;
1024 }
1025
1026 static void setup_tabs(void)
1027 {
1028     int i;
1029
1030     for (i = 0; i <= res_usr; i++)
1031         switch(i) {
1032                 case res_acc:
1033                 case res_bmp:
1034                 case res_cur:
1035                 case res_curg:
1036                 case res_dlg:
1037                 case res_dlgex:
1038                 case res_fnt:
1039                 case res_fntdir:
1040                 case res_ico:
1041                 case res_icog:
1042                 case res_men:
1043                 case res_menex:
1044                 case res_rdt:
1045                 case res_stt:
1046                 case res_usr:
1047                 case res_msg:
1048                 case res_ver:
1049                 case res_dlginit:
1050                 case res_toolbar:
1051                 case res_anicur:
1052                 case res_aniico:
1053                 case res_html:
1054                     verify_tab[i].enabled = 1;
1055                     break;
1056         }
1057 }
1058
1059 static const char *get_typename_for_int(int type) {
1060     resource_t res;
1061     res.type = type;
1062     return get_typename(&res);
1063 }
1064
1065 static resource_t *find_main(int type, name_id_t *id, resource_lang_node_t *langnode)
1066 {
1067     resource_t *neutral = NULL, *en = NULL, *en_US = NULL;
1068     for (; langnode; langnode = langnode->next)
1069     {
1070         if (langnode->lang.id == LANG_NEUTRAL && langnode->lang.sub == SUBLANG_NEUTRAL)
1071             neutral = langnode->res;
1072         if (langnode->lang.id == MASTER_LANGUAGE && langnode->lang.sub == SUBLANG_NEUTRAL)
1073             en = langnode->res;
1074         if (langnode->lang.id == MASTER_LANGUAGE && langnode->lang.sub == MASTER_SUBLANGUAGE)
1075             en_US = langnode->res;
1076     }
1077
1078     if (neutral != NULL && (en != NULL || en_US != NULL))
1079     {
1080         fprintf(stderr, "INFO: Resource %04x/%s has both NEUTRAL and MASTER language translarion\n",
1081             type, get_nameid_str(id));
1082     }
1083
1084     if (en_US != NULL) return en_US;
1085     if (en != NULL) return en;
1086     return neutral;
1087 }
1088
1089 void verify_translations(resource_t *top) {
1090     resource_t *curr = top;
1091     resource_id_node_t *idnode;
1092     resource_lang_node_t *langnode;
1093     int type;
1094
1095     setup_tabs();
1096     while (curr)
1097     {
1098         add_resource(curr);
1099         curr = curr->next;
1100     }
1101
1102     for (type = 0; type <= res_usr; type++)
1103     {
1104         printf("TYPE NEXT [%s]\n", get_typename_for_int(type));
1105         for (idnode = verify_tab[type].ids; idnode; idnode = idnode->next)
1106         {
1107             resource_t *mainres;
1108             printf("RESOURCE [%s]\n", get_nameid_str(idnode->id));
1109
1110             mainres = find_main(type, idnode->id, idnode->langs);
1111             if (!mainres)
1112             {
1113                 fprintf(stderr, "ERR: resource %04x/%s has translation(s) but not available in NEUTRAL or MASTER language\n",
1114                     type, get_nameid_str(idnode->id));
1115                 for (langnode = idnode->langs; langnode; langnode = langnode->next)
1116                     printf("EXTRA %03x:%02x\n", langnode->lang.id, langnode->lang.sub);
1117                 continue;
1118             }
1119
1120             if (get_language_id(mainres) == LANG_NEUTRAL && idnode->langs->next == NULL) {
1121                 printf("NOTRANSL\n");
1122                 continue;
1123             }
1124
1125             for (langnode = idnode->langs; langnode; langnode = langnode->next)
1126             {
1127                 printf("EXIST %03x:%02x\n", langnode->lang.id, langnode->lang.sub);
1128                 if (compare(langnode->res, mainres))
1129                 {
1130                     printf("DIFF %03x:%02x\n", langnode->lang.id, langnode->lang.sub);
1131                 }
1132             }
1133         }
1134     }
1135 }