appwiz.cpl: Remove an unused function.
[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_fnt:
51                         return *resource->res.fnt->data->lvc.language;
52                 case res_fntdir:
53                         return *resource->res.fnd->data->lvc.language;
54                 case res_ico:
55                         return *resource->res.ico->lvc.language;
56                 case res_icog:
57                         return *resource->res.icog->lvc.language;
58                 case res_men:
59                         return *resource->res.men->lvc.language;
60                 case res_rdt:
61                         return *resource->res.rdt->data->lvc.language;
62                 case res_stt:
63                         return *resource->res.stt->lvc.language;
64                 case res_usr:
65                         return *resource->res.usr->data->lvc.language;
66                 case res_msg:
67                         return *resource->res.msg->data->lvc.language;
68                 case res_ver:
69                         return *resource->res.ver->lvc.language;
70                 case res_dlginit:
71                         return *resource->res.dlgi->data->lvc.language;
72                 case res_toolbar:
73                         return *resource->res.tbt->lvc.language;
74                 case res_anicur:
75                 case res_aniico:
76                         return *resource->res.ani->data->lvc.language;
77                 case res_html:
78                         return *resource->res.html->data->lvc.language;
79                 default:
80                         /* Not supposed to reach here */
81                         fprintf(stderr, "Not supposed to reach here (get_language_id())\n");
82                         abort();
83         }
84 }
85
86 static int get_language_id(resource_t *resource) {
87     return get_language(resource).id;
88 }
89
90 static int compare_lang(language_t lang1, language_t lang2)
91 {
92     return memcmp(&lang1, &lang2, sizeof(language_t));
93 }
94
95 #if 0
96
97 #define PRETTYPRINTLANG(langid) \
98         if(LANG_##langid == lid) { \
99                 return #langid; \
100         }
101
102 static const char *get_language_name(int lid) {
103         PRETTYPRINTLANG(NEUTRAL)
104         PRETTYPRINTLANG(AFRIKAANS)
105         PRETTYPRINTLANG(ALBANIAN)
106         PRETTYPRINTLANG(ARABIC)
107         PRETTYPRINTLANG(ARMENIAN)
108         PRETTYPRINTLANG(ASSAMESE)
109         PRETTYPRINTLANG(AZERI)
110         PRETTYPRINTLANG(BASQUE)
111         PRETTYPRINTLANG(BELARUSIAN)
112         PRETTYPRINTLANG(BENGALI)
113         PRETTYPRINTLANG(BULGARIAN)
114         PRETTYPRINTLANG(CATALAN)
115         PRETTYPRINTLANG(CHINESE)
116         PRETTYPRINTLANG(CROATIAN)
117         PRETTYPRINTLANG(CZECH)
118         PRETTYPRINTLANG(DANISH)
119         PRETTYPRINTLANG(DIVEHI)
120         PRETTYPRINTLANG(DUTCH)
121         PRETTYPRINTLANG(ENGLISH)
122         PRETTYPRINTLANG(ESTONIAN)
123         PRETTYPRINTLANG(FAEROESE)
124         PRETTYPRINTLANG(FARSI)
125         PRETTYPRINTLANG(FINNISH)
126         PRETTYPRINTLANG(FRENCH)
127         PRETTYPRINTLANG(GALICIAN)
128         PRETTYPRINTLANG(GEORGIAN)
129         PRETTYPRINTLANG(GERMAN)
130         PRETTYPRINTLANG(GREEK)
131         PRETTYPRINTLANG(GUJARATI)
132         PRETTYPRINTLANG(HEBREW)
133         PRETTYPRINTLANG(HINDI)
134         PRETTYPRINTLANG(HUNGARIAN)
135         PRETTYPRINTLANG(ICELANDIC)
136         PRETTYPRINTLANG(INDONESIAN)
137         PRETTYPRINTLANG(ITALIAN)
138         PRETTYPRINTLANG(JAPANESE)
139         PRETTYPRINTLANG(KANNADA)
140         PRETTYPRINTLANG(KASHMIRI)
141         PRETTYPRINTLANG(KAZAK)
142         PRETTYPRINTLANG(KONKANI)
143         PRETTYPRINTLANG(KOREAN)
144         PRETTYPRINTLANG(KYRGYZ)
145         PRETTYPRINTLANG(LATVIAN)
146         PRETTYPRINTLANG(LITHUANIAN)
147         PRETTYPRINTLANG(MACEDONIAN)
148         PRETTYPRINTLANG(MALAY)
149         PRETTYPRINTLANG(MALAYALAM)
150         PRETTYPRINTLANG(MANIPURI)
151         PRETTYPRINTLANG(MARATHI)
152         PRETTYPRINTLANG(MONGOLIAN)
153         PRETTYPRINTLANG(NEPALI)
154         PRETTYPRINTLANG(NORWEGIAN)
155         PRETTYPRINTLANG(ORIYA)
156         PRETTYPRINTLANG(POLISH)
157         PRETTYPRINTLANG(PORTUGUESE)
158         PRETTYPRINTLANG(PUNJABI)
159         PRETTYPRINTLANG(ROMANIAN)
160         PRETTYPRINTLANG(RUSSIAN)
161         PRETTYPRINTLANG(SANSKRIT)
162         PRETTYPRINTLANG(SERBIAN)
163         PRETTYPRINTLANG(SINDHI)
164         PRETTYPRINTLANG(SLOVAK)
165         PRETTYPRINTLANG(SLOVENIAN)
166         PRETTYPRINTLANG(SPANISH)
167         PRETTYPRINTLANG(SWAHILI)
168         PRETTYPRINTLANG(SWEDISH)
169         PRETTYPRINTLANG(SYRIAC)
170         PRETTYPRINTLANG(TAMIL)
171         PRETTYPRINTLANG(TATAR)
172         PRETTYPRINTLANG(TELUGU)
173         PRETTYPRINTLANG(THAI)
174         PRETTYPRINTLANG(TURKISH)
175         PRETTYPRINTLANG(UKRAINIAN)
176         PRETTYPRINTLANG(URDU)
177         PRETTYPRINTLANG(UZBEK)
178         PRETTYPRINTLANG(VIETNAMESE)
179         PRETTYPRINTLANG(GAELIC)
180         PRETTYPRINTLANG(MALTESE)
181         PRETTYPRINTLANG(MAORI)
182         PRETTYPRINTLANG(RHAETO_ROMANCE)
183         PRETTYPRINTLANG(SAAMI)
184         PRETTYPRINTLANG(SORBIAN)
185         PRETTYPRINTLANG(SUTU)
186         PRETTYPRINTLANG(TSONGA)
187         PRETTYPRINTLANG(TSWANA)
188         PRETTYPRINTLANG(VENDA)
189         PRETTYPRINTLANG(XHOSA)
190         PRETTYPRINTLANG(ZULU)
191         PRETTYPRINTLANG(ESPERANTO)
192         PRETTYPRINTLANG(WALON)
193         PRETTYPRINTLANG(CORNISH)
194         PRETTYPRINTLANG(WELSH)
195         PRETTYPRINTLANG(BRETON)
196         return "Unknown language";
197 }
198 #endif
199
200 static int compare_accelerator(accelerator_t *accelerator1, accelerator_t *accelerator2) {
201         int different = 0;
202         event_t *ev1 = NULL, *ev2 = NULL;
203         if(!different &&
204            ((accelerator1->memopt != accelerator2->memopt) ||
205            (accelerator1->lvc.version != accelerator2->lvc.version) ||
206            (accelerator1->lvc.characts != accelerator2->lvc.characts)))
207                 different = 1;
208         ev1 = accelerator1->events;
209         ev2 = accelerator2->events;
210         while(!different && ev1 && ev2) {
211                 if(!different &&
212                    ((ev1->id != ev2->id) ||
213                    (ev1->flags != ev2->flags)))
214                         different = 1;
215                 ev1 = ev1->next;
216                 ev2 = ev2->next;
217         }
218         if(!different &&
219            ((ev1 && !ev2) || (!ev1 && ev2)))
220                 different = 1;
221         return different;
222 }
223
224 static int compare_bitmap(bitmap_t *bitmap1, bitmap_t *bitmap2) {
225         int different = 0;
226         if(!different &&
227            ((bitmap1->memopt != bitmap2->memopt) ||
228            (bitmap1->data->lvc.version != bitmap2->data->lvc.version) ||
229            (bitmap1->data->lvc.characts != bitmap2->data->lvc.characts)))
230                 different = 1;
231         return different;
232 }
233
234 static int compare_cursor(cursor_t *cursor1, cursor_t *cursor2) {
235         int different = 0;
236         if(!different &&
237            ((cursor1->id != cursor2->id) ||
238            (cursor1->width != cursor2->width) ||
239            (cursor1->height != cursor2->height) ||
240            (cursor1->xhot != cursor2->xhot) ||
241            (cursor1->yhot != cursor2->yhot)))
242                 different = 1;
243         if(!different &&
244            ((cursor1->lvc.version != cursor2->lvc.version) ||
245            (cursor1->lvc.characts != cursor2->lvc.characts)))
246                 different = 1;
247         return different;
248 }
249
250 static int compare_cursor_group(cursor_group_t *cursor_group1, cursor_group_t *cursor_group2) {
251         int different = 0;
252         cursor_t *cursor1 = NULL, *cursor2 = NULL;
253         if(!different &&
254            ((cursor_group1->memopt != cursor_group2->memopt) ||
255            (cursor_group1->lvc.version != cursor_group2->lvc.version) ||
256            (cursor_group1->lvc.characts != cursor_group2->lvc.characts)))
257                 different = 1;
258         if(!different &&
259            (cursor_group1->ncursor != cursor_group2->ncursor))
260                 different = 1;
261         if(!different) {
262                 cursor1 = cursor_group1->cursorlist;
263                 cursor2 = cursor_group2->cursorlist;
264                 while(!different && cursor1 && cursor2) {
265                         different = compare_cursor(cursor1, cursor2);
266                         cursor1 = cursor1->next;
267                         cursor2 = cursor2->next;
268                 }
269                 if(!different &&
270                    ((cursor1 && !cursor2) ||
271                    (!cursor1 && cursor2)))
272                         different = 1;
273         }
274         return different;
275 }
276
277 static int compare_control(control_t *control1, control_t *control2) {
278         int different = 0;
279         char *nameid = NULL;
280         int ignore_style;
281         if(!different &&
282                 ((control1 && !control2) ||
283                 (!control1 && control2)))
284                         different = 1;
285         if(different || !control1 || !control2)
286                 return different;
287         nameid = strdup(get_nameid_str(control1->ctlclass));
288         if(!different && strcmp(nameid, get_nameid_str(control2->ctlclass)))
289                 different = 1;
290         free(nameid);
291         if (different)
292             return different;
293
294         /* allow the translators to set some styles */
295         ignore_style = 0;
296         if (control1->ctlclass->type == name_ord && control1->ctlclass->name.i_name == CT_BUTTON)
297             ignore_style = 0x2000;          /* BS_MULTILINE*/
298
299         if(!different && 
300            (control1->id != control2->id))
301                 different = 1;
302         if(!different && control1->gotstyle && control2->gotstyle) {
303                 if((!control1->style || !control2->style) ||
304                    (control1->style->and_mask || control2->style->and_mask) ||
305                    ((control1->style->or_mask & ~ignore_style) != (control2->style->or_mask & ~ignore_style)))
306                         different = 1;
307         } else if(!different &&
308                   ((control1->gotstyle && !control2->gotstyle) ||
309                   (!control1->gotstyle && control2->gotstyle)))
310                         different = 1;
311         if(!different && control1->gotexstyle && control2->gotexstyle) {
312                 if((!control1->exstyle || !control2->exstyle) ||
313                    (control1->exstyle->and_mask || control2->exstyle->and_mask) ||
314                    (control1->exstyle->or_mask != control2->exstyle->or_mask))
315                         different = 1;
316         } else if(!different &&
317                   ((control1->gotexstyle && !control2->gotexstyle) ||
318                   (!control1->gotexstyle && control2->gotexstyle)))
319                         different = 1;
320         if(!different && control1->gothelpid && control2->gothelpid) {
321                 if(control1->helpid != control2->helpid)
322                         different = 1;
323         } else if(!different &&
324                   ((control1->gothelpid && !control2->gothelpid) ||
325                   (!control1->gothelpid && control2->gothelpid)))
326                         different = 1;
327         return different;
328 }
329
330 static int compare_dialog(dialog_t *dialog1, dialog_t *dialog2) {
331         int different = 0;
332         char *nameid = NULL;
333         control_t *ctrl1, *ctrl2;
334         if(!different &&
335            ((dialog1->memopt != dialog2->memopt) ||
336            (dialog1->lvc.version != dialog2->lvc.version) ||
337            (dialog1->lvc.characts != dialog2->lvc.characts)))
338                 different = 1;
339         if(!different && dialog1->gotstyle && dialog2->gotstyle) {
340                 if((!dialog1->style || !dialog2->style) ||
341                    (dialog1->style->and_mask || dialog2->style->and_mask) ||
342                    (dialog1->style->or_mask != dialog2->style->or_mask))
343                         different = 1;
344         } else if(!different &&
345                   ((dialog1->gotstyle && !dialog2->gotstyle) ||
346                   (!dialog1->gotstyle && dialog2->gotstyle)))
347                         different = 1;
348         if(!different && dialog1->gotexstyle && dialog2->gotexstyle) {
349                 if((!dialog1->exstyle || !dialog2->exstyle) ||
350                    (dialog1->exstyle->and_mask || dialog2->exstyle->and_mask) ||
351                    (dialog1->exstyle->or_mask != dialog2->exstyle->or_mask))
352                         different = 1;
353         } else if(!different &&
354                   ((dialog1->gotexstyle && !dialog2->gotexstyle) ||
355                   (!dialog1->gotexstyle && dialog2->gotexstyle)))
356                         different = 1;
357         if(!different && dialog1->gothelpid && dialog2->gothelpid) {
358                 if(dialog1->helpid != dialog2->helpid)
359                         different = 1;
360         } else if(!different &&
361                   ((dialog1->gothelpid && !dialog2->gothelpid) ||
362                   (!dialog1->gothelpid && dialog2->gothelpid)))
363                         different = 1;
364         nameid = strdup(get_nameid_str(dialog1->menu));
365         if(!different && strcmp(nameid, get_nameid_str(dialog2->menu)))
366                 different = 1;
367         free(nameid);
368         nameid = strdup(get_nameid_str(dialog1->dlgclass));
369         if(!different && strcmp(nameid, get_nameid_str(dialog2->dlgclass)))
370                 different = 1;
371         free(nameid);
372
373         ctrl1 = dialog1->controls;
374         ctrl2 = dialog2->controls;
375         while(!different && (ctrl1 || ctrl2))
376         {
377             different = compare_control(ctrl1, ctrl2);
378             if (ctrl1) ctrl1 = ctrl1->next;
379             if (ctrl2) ctrl2 = ctrl2->next;
380         }
381         return different;
382 }
383
384 static int compare_font(font_t *font1, font_t *font2) {
385         int different = 0;
386         if(!different &&
387            ((font1->memopt != font2->memopt) ||
388            (font1->data->lvc.version != font2->data->lvc.version) ||
389            (font1->data->lvc.characts != font2->data->lvc.characts)))
390                 different = 1;
391         return different;
392 }
393
394 static int compare_fontdir(fontdir_t *fontdir1, fontdir_t *fontdir2) {
395         int different = 0;
396         if(!different &&
397            ((fontdir1->memopt != fontdir2->memopt) ||
398            (fontdir1->data->lvc.version != fontdir2->data->lvc.version) ||
399            (fontdir1->data->lvc.characts != fontdir2->data->lvc.characts)))
400                 different = 1;
401         return different;
402 }
403
404 static int compare_icon(icon_t *icon1, icon_t *icon2) {
405         int different = 0;
406         if(!different &&
407            ((icon1->id != icon2->id) ||
408            (icon1->width != icon2->width) ||
409            (icon1->height != icon2->height)))
410                 different = 1;
411         if(!different &&
412            ((icon1->lvc.version != icon2->lvc.version) ||
413            (icon1->lvc.characts != icon2->lvc.characts)))
414                 different = 1;
415         return different;
416 }
417
418 static int compare_icon_group(icon_group_t *icon_group1, icon_group_t *icon_group2) {
419         int different = 0;
420         icon_t *icon1 = NULL, *icon2 = NULL;
421         if(!different &&
422            ((icon_group1->memopt != icon_group2->memopt) ||
423            (icon_group1->lvc.version != icon_group2->lvc.version) ||
424            (icon_group1->lvc.characts != icon_group2->lvc.characts)))
425                 different = 1;
426         if(!different &&
427            (icon_group1->nicon != icon_group2->nicon))
428                 different = 1;
429         if(!different) {
430                 icon1 = icon_group1->iconlist;
431                 icon2 = icon_group2->iconlist;
432                 while(!different && icon1 && icon2) {
433                         different = compare_icon(icon1, icon2);
434                         icon1 = icon1->next;
435                         icon2 = icon2->next;
436                 }
437                 if(!different &&
438                    ((icon1 && !icon2) ||
439                    (!icon1 && icon2)))
440                         different = 1;
441         }
442         return different;
443 }
444
445 static int compare_menu_item(menu_item_t *menu_item1, menu_item_t *menu_item2) {
446         int different = 0;
447         while(!different && menu_item1 && menu_item2) {
448                 if(menu_item1->popup && menu_item2->popup) {
449                         if(!different && menu_item1->gotid && menu_item2->gotid) {
450                                 if(menu_item1->id != menu_item2->id)
451                                         different = 1;
452                         } else if(!different &&
453                                   ((menu_item1->gotid && !menu_item2->gotid) ||
454                                   (!menu_item1->gotid && menu_item2->gotid)))
455                                         different = 1;
456                         if(!different && menu_item1->gottype && menu_item2->gottype) {
457                                 if(menu_item1->type != menu_item2->type)
458                                         different = 1;
459                         } else if(!different &&
460                                   ((menu_item1->gottype && !menu_item2->gottype) ||
461                                   (!menu_item1->gottype && menu_item2->gottype)))
462                                         different = 1;
463                         if(!different && menu_item1->gotstate && menu_item2->gotstate) {
464                                 if(menu_item1->state != menu_item2->state)
465                                         different = 1;
466                         } else if(!different &&
467                                   ((menu_item1->gotstate && !menu_item2->gotstate) ||
468                                   (!menu_item1->gotstate && menu_item2->gotstate)))
469                                         different = 1;
470                         if(!different && menu_item1->gothelpid && menu_item2->gothelpid) {
471                                 if(menu_item1->helpid != menu_item2->helpid)
472                                         different = 1;
473                         } else if(!different &&
474                                   ((menu_item1->gothelpid && !menu_item2->gothelpid) ||
475                                   (!menu_item1->gothelpid && menu_item2->gothelpid)))
476                                         different = 1;
477                         if(!different)
478                                 different = compare_menu_item(menu_item1->popup, menu_item2->popup);
479                 } else if(!menu_item1->popup && !menu_item2->popup) {
480                         if(menu_item1->name && menu_item2->name) {
481                                 if(!different && menu_item1->gotid && menu_item2->gotid) {
482                                         if(menu_item1->id != menu_item2->id)
483                                                 different = 1;
484                                 } else if(!different &&
485                                           ((menu_item1->gotid && !menu_item2->gotid) ||
486                                           (!menu_item1->gotid && menu_item2->gotid)))
487                                                 different = 1;
488                                 if(!different && menu_item1->gottype && menu_item2->gottype) {
489                                         if(menu_item1->type != menu_item2->type)
490                                                 different = 1;
491                                 } else if(!different &&
492                                           ((menu_item1->gottype && !menu_item2->gottype) ||
493                                           (!menu_item1->gottype && menu_item2->gottype)))
494                                                 different = 1;
495                                 if(!different && menu_item1->gotstate && menu_item2->gotstate) {
496                                         if(menu_item1->state != menu_item2->state)
497                                                 different = 1;
498                                 } else if(!different &&
499                                           ((menu_item1->gotstate && !menu_item2->gotstate) ||
500                                           (!menu_item1->gotstate && menu_item2->gotstate)))
501                                                 different = 1;
502                                 if(!different && menu_item1->gothelpid && menu_item2->gothelpid) {
503                                         if(menu_item1->helpid != menu_item2->helpid)
504                                                 different = 1;
505                                 } else if(!different &&
506                                           ((menu_item1->gothelpid && !menu_item2->gothelpid) ||
507                                           (!menu_item1->gothelpid && menu_item2->gothelpid)))
508                                                 different = 1;
509                         } else if((menu_item1->name && !menu_item2->name) ||
510                                   (!menu_item1->name && menu_item2->name))
511                                         different = 1;
512                 } else
513                         different = 1;
514                 menu_item1 = menu_item1->next;
515                 menu_item2 = menu_item2->next;
516         }
517         if(!different &&
518            ((menu_item1 && !menu_item2) ||
519            (!menu_item1 && menu_item2)))
520                 different = 1;
521         return different;
522 }
523
524 static int compare_menu(menu_t *menu1, menu_t *menu2) {
525         int different = 0;
526         if(!different &&
527            ((menu1->memopt != menu2->memopt) ||
528            (menu1->lvc.version != menu2->lvc.version) ||
529            (menu1->lvc.characts != menu2->lvc.characts)))
530                 different = 1;
531         if(!different)
532                 different = compare_menu_item(menu1->items, menu2->items);
533         return different;
534 }
535
536 static int compare_rcdata(rcdata_t *rcdata1, rcdata_t *rcdata2) {
537         int different = 0;
538         if(!different &&
539            ((rcdata1->memopt != rcdata2->memopt) ||
540            (rcdata1->data->lvc.version != rcdata2->data->lvc.version) ||
541            (rcdata1->data->lvc.characts != rcdata2->data->lvc.characts)))
542                 different = 1;
543         return different;
544 }
545
546 static int compare_html(html_t *rcdata1, html_t *rcdata2) {
547         int different = 0;
548         if(!different &&
549            ((rcdata1->memopt != rcdata2->memopt) ||
550            (rcdata1->data->lvc.version != rcdata2->data->lvc.version) ||
551            (rcdata1->data->lvc.characts != rcdata2->data->lvc.characts)))
552                 different = 1;
553         return different;
554 }
555
556 static int compare_stringtable(stringtable_t *stringtable1, stringtable_t *stringtable2) {
557         int different = 0;
558         int i;
559         while(!different && stringtable1 && stringtable2) {
560                 if((stringtable1->memopt != stringtable2->memopt) ||
561                    (stringtable1->lvc.version != stringtable2->lvc.version) ||
562                    (stringtable1->lvc.characts != stringtable2->lvc.characts))
563                         different = 1;
564                 if(!different) {
565                         if((stringtable1->nentries != stringtable2->nentries) ||
566                            (stringtable1->idbase != stringtable2->idbase))
567                                 different = 1;
568                         else
569                                 for(i = 0 ; i < stringtable1->nentries; i++)
570                                         if((stringtable1->entries[i].id != stringtable2->entries[i].id) ||
571                                            (stringtable1->entries[i].memopt != stringtable2->entries[i].memopt) ||
572                                            (stringtable1->entries[i].str && !stringtable2->entries[i].str) ||
573                                            (!stringtable1->entries[i].str && stringtable2->entries[i].str)) {
574                                                 different = 1;
575                                                 break;
576                                         }
577                 }
578                 stringtable1 = stringtable1->next;
579                 stringtable2 = stringtable2->next;
580         }
581         return different;
582 }
583
584 static int compare_user(user_t *user1, user_t *user2) {
585         int different = 0;
586         char *nameid = NULL;
587         if(!different &&
588            ((user1->memopt != user2->memopt) ||
589            (user1->data->lvc.version != user2->data->lvc.version) ||
590            (user1->data->lvc.characts != user2->data->lvc.characts)))
591                 different = 1;
592         nameid = strdup(get_nameid_str(user1->type));
593         if(!different && strcmp(nameid, get_nameid_str(user2->type)))
594                 different = 1;
595         free(nameid);
596         return different;
597 }
598
599 static int compare_messagetable(messagetable_t *messagetable1, messagetable_t *messagetable2) {
600         int different = 0;
601         if(!different &&
602            ((messagetable1->memopt != messagetable2->memopt) ||
603            (messagetable1->data->lvc.version != messagetable2->data->lvc.version) ||
604            (messagetable1->data->lvc.characts != messagetable2->data->lvc.characts)))
605                 different = 1;
606         return different;
607 }
608
609 static int compare_string(string_t *string1, string_t *string2) {
610         int different = 0;
611         if(!different &&
612            ((string1->size != string2->size) ||
613            (string1->type != string2->type)))
614                 different = 1;
615         if(!different) {
616                 if(string1->type == str_char)
617                         different = memcmp(string1->str.cstr, string2->str.cstr, string1->size);
618                 else if(string1->type == str_unicode)
619                         different = memcmp(string1->str.wstr, string2->str.wstr, string1->size*sizeof(WCHAR));
620                 else
621                         different = 1;
622         }
623         return different;
624 }
625
626 static int compare_ver_block(ver_block_t *ver_block1, ver_block_t *ver_block2);
627
628 static int compare_ver_value(ver_value_t *ver_value1, ver_value_t *ver_value2) {
629         int different = 0;
630         int i = 0;
631         if(!different &&
632            (ver_value1->type == ver_value2->type)) {
633                 switch(ver_value1->type) {
634                         case val_str:
635                                 if(!different && ver_value1->key && ver_value2->key)
636                                         different = compare_string(ver_value1->key, ver_value2->key);
637                                 else if(!different &&
638                                         ((ver_value1->key && !ver_value2->key) ||
639                                         (!ver_value1->key && ver_value2->key)))
640                                                 different = 1;
641                                 break;
642                         case val_words:
643                                 if(!different && ver_value1->key && ver_value2->key)
644                                         different = compare_string(ver_value1->key, ver_value2->key);
645                                 else if(!different &&
646                                         ((ver_value1->key && !ver_value2->key) ||
647                                         (!ver_value1->key && ver_value2->key)))
648                                                 different = 1;
649                                 if(!different && ver_value1->value.words && ver_value2->value.words) {
650                                         if(!different &&
651                                            (ver_value1->value.words->nwords != ver_value2->value.words->nwords))
652                                                 different = 1;
653                                         if(!different)
654                                                 for(i = 0; i < ver_value1->value.words->nwords; i++) {
655                                                         if(ver_value1->value.words->words[i] != ver_value2->value.words->words[i]) {
656                                                                 different = 1;
657                                                                 break;
658                                                         }
659                                                 }
660                                 } else if(!different &&
661                                           ((ver_value1->value.words && !ver_value2->value.words) ||
662                                           (!ver_value1->value.words && ver_value2->value.words)))
663                                                 different = 1;
664                                 break;
665                         case val_block:
666                                 if(!different && ver_value1->value.block && ver_value2->value.block)
667                                         different = compare_ver_block(ver_value1->value.block, ver_value2->value.block);
668                                 else if(!different &&
669                                         ((ver_value1->value.block && !ver_value2->value.block) ||
670                                         (!ver_value1->value.block && ver_value2->value.block)))
671                                                 different = 1;
672                                 break;
673                         default:
674                                 different = 1;
675                 }
676         } else
677                 different = 1;
678         return different;
679 }
680
681 static int compare_ver_block(ver_block_t *ver_block1, ver_block_t *ver_block2) {
682         int different = 0;
683         ver_value_t *ver_value1 = NULL, *ver_value2 = NULL;
684         if(!different) {
685                 ver_value1 = ver_block1->values;
686                 ver_value2 = ver_block2->values;
687                 while(!different && ver_value1 && ver_value2) {
688                         different = compare_ver_value(ver_value1, ver_value2);
689                         ver_value1 = ver_value1->next;
690                         ver_value2 = ver_value2->next;
691                 }
692                 if(!different &&
693                    ((ver_value1 && !ver_value2) ||
694                    (!ver_value1 && ver_value2)))
695                         different = 1;
696         }
697         return different;
698 }
699
700 static int compare_versioninfo(versioninfo_t *versioninfo1, versioninfo_t *versioninfo2) {
701         int different = 0;
702         ver_block_t *ver_block1 = NULL, *ver_block2 = NULL;
703         if(!different &&
704            ((versioninfo1->memopt != versioninfo2->memopt) ||
705            (versioninfo1->lvc.version != versioninfo2->lvc.version) ||
706            (versioninfo1->lvc.characts != versioninfo2->lvc.characts)))
707                 different = 1;
708         if(!different && versioninfo1->gotit.fv && versioninfo2->gotit.fv) {
709                 if((versioninfo1->filever_maj1 != versioninfo2->filever_maj1) ||
710                    (versioninfo1->filever_maj2 != versioninfo2->filever_maj2) ||
711                    (versioninfo1->filever_min1 != versioninfo2->filever_min1) ||
712                    (versioninfo1->filever_min2 != versioninfo2->filever_min2))
713                         different = 1;
714         } else if(!different &&
715                   ((versioninfo1->gotit.fv && !versioninfo2->gotit.fv) ||
716                   (!versioninfo1->gotit.fv && versioninfo2->gotit.fv)))
717                         different = 1;
718         if(!different && versioninfo1->gotit.pv && versioninfo2->gotit.pv) {
719                 if((versioninfo1->prodver_maj1 != versioninfo2->prodver_maj1) ||
720                    (versioninfo1->prodver_maj2 != versioninfo2->prodver_maj2) ||
721                    (versioninfo1->prodver_min1 != versioninfo2->prodver_min1) ||
722                    (versioninfo1->prodver_min2 != versioninfo2->prodver_min2))
723                         different = 1;
724         } else if(!different &&
725                   ((versioninfo1->gotit.pv && !versioninfo2->gotit.pv) ||
726                   (!versioninfo1->gotit.pv && versioninfo2->gotit.pv)))
727                         different = 1;
728         if(!different && versioninfo1->gotit.fo && versioninfo2->gotit.fo) {
729                 if(versioninfo1->fileos != versioninfo2->fileos)
730                         different = 1;
731         } else if(!different &&
732                   ((versioninfo1->gotit.fo && !versioninfo2->gotit.fo) ||
733                   (!versioninfo1->gotit.fo && versioninfo2->gotit.fo)))
734                         different = 1;
735         if(!different && versioninfo1->gotit.ff && versioninfo2->gotit.ff) {
736                 if(versioninfo1->fileflags != versioninfo2->fileflags)
737                         different = 1;
738         } else if(!different &&
739                   ((versioninfo1->gotit.ff && !versioninfo2->gotit.ff) ||
740                   (!versioninfo1->gotit.ff && versioninfo2->gotit.ff)))
741                         different = 1;
742         if(!different && versioninfo1->gotit.ffm && versioninfo2->gotit.ffm) {
743                 if(versioninfo1->fileflagsmask != versioninfo2->fileflagsmask)
744                         different = 1;
745         } else if(!different &&
746                   ((versioninfo1->gotit.ffm && !versioninfo2->gotit.ffm) ||
747                   (!versioninfo1->gotit.ffm && versioninfo2->gotit.ffm)))
748                         different = 1;
749         if(!different && versioninfo1->gotit.ft && versioninfo2->gotit.ft) {
750                 if(versioninfo1->filetype != versioninfo2->filetype)
751                         different = 1;
752         } else if(!different &&
753                   ((versioninfo1->gotit.ft && !versioninfo2->gotit.ft) ||
754                   (!versioninfo1->gotit.ft && versioninfo2->gotit.ft)))
755                         different = 1;
756         if(!different && versioninfo1->gotit.fst && versioninfo2->gotit.fst) {
757                 if(versioninfo1->filesubtype != versioninfo2->filesubtype)
758                         different = 1;
759         } else if(!different &&
760                   ((versioninfo1->gotit.fst && !versioninfo2->gotit.fst) ||
761                   (!versioninfo1->gotit.fst && versioninfo2->gotit.fst)))
762                         different = 1;
763         if(!different) {
764                 ver_block1 = versioninfo1->blocks;
765                 ver_block2 = versioninfo2->blocks;
766                 while(!different && ver_block1 && ver_block2) {
767                         different = compare_ver_block(ver_block1, ver_block2);
768                         ver_block1 = ver_block1->next;
769                         ver_block2 = ver_block2->next;
770                 }
771                 if(!different &&
772                    ((ver_block1 && !ver_block2) ||
773                    (!ver_block1 && ver_block2)))
774                         different = 1;
775         }
776         return different;
777 }
778
779 static int compare_dlginit(dlginit_t *dlginit1, dlginit_t *dlginit2) {
780         int different = 0;
781         if(!different &&
782            ((dlginit1->memopt != dlginit2->memopt) ||
783            (dlginit1->data->lvc.version != dlginit2->data->lvc.version) ||
784            (dlginit1->data->lvc.characts != dlginit2->data->lvc.characts)))
785                 different = 1;
786         return different;
787 }
788
789 static int compare_toolbar_item(toolbar_item_t *toolbar_item1, toolbar_item_t *toolbar_item2) {
790         int different = 0;
791         while(!different && toolbar_item1 && toolbar_item2) {
792                 if((toolbar_item1->id && !toolbar_item2->id) ||
793                    (!toolbar_item1->id && toolbar_item2->id))
794                         different = 1;
795                 toolbar_item1 = toolbar_item1->next;
796                 toolbar_item2 = toolbar_item2->next;
797         }
798         if(!different &&
799            ((toolbar_item1 && !toolbar_item2) ||
800            (!toolbar_item1 && toolbar_item2)))
801                 different = 1;
802         return different;
803 }
804
805 static int compare_toolbar(toolbar_t *toolbar1, toolbar_t *toolbar2) {
806         int different = 0;
807         if(!different &&
808            ((toolbar1->memopt != toolbar2->memopt) ||
809            (toolbar1->lvc.version != toolbar2->lvc.version) ||
810            (toolbar1->lvc.characts != toolbar2->lvc.characts)))
811                 different = 1;
812         if(!different)
813                 different = compare_toolbar_item(toolbar1->items, toolbar2->items);
814         return different;
815 }
816
817 static int compare_ani_curico(ani_curico_t *ani_curico1, ani_curico_t *ani_curico2) {
818         int different = 0;
819         if(!different &&
820            ((ani_curico1->memopt != ani_curico2->memopt) ||
821            (ani_curico1->data->lvc.version != ani_curico2->data->lvc.version) ||
822            (ani_curico1->data->lvc.characts != ani_curico2->data->lvc.characts)))
823                 different = 1;
824         return different;
825 }
826
827 static int compare(resource_t *resource1, resource_t *resource2) {
828         switch(resource1->type) {
829                 case res_acc:
830                         return compare_accelerator(resource1->res.acc, resource2->res.acc);
831                 case res_bmp:
832                         return compare_bitmap(resource1->res.bmp, resource2->res.bmp);
833                 case res_cur:
834                         return compare_cursor(resource1->res.cur, resource2->res.cur);
835                 case res_curg:
836                         return compare_cursor_group(resource1->res.curg, resource2->res.curg);
837                 case res_dlg:
838                         return compare_dialog(resource1->res.dlg, resource2->res.dlg);
839                 case res_fnt:
840                         return compare_font(resource1->res.fnt, resource2->res.fnt);
841                 case res_fntdir:
842                         return compare_fontdir(resource1->res.fnd, resource2->res.fnd);
843                 case res_ico:
844                         return compare_icon(resource1->res.ico, resource2->res.ico);
845                 case res_icog:
846                         return compare_icon_group(resource1->res.icog, resource2->res.icog);
847                 case res_men:
848                         return compare_menu(resource1->res.men, resource2->res.men);
849                 case res_rdt:
850                         return compare_rcdata(resource1->res.rdt, resource2->res.rdt);
851                 case res_stt:
852                         return compare_stringtable(resource1->res.stt, resource2->res.stt);
853                 case res_usr:
854                         return compare_user(resource1->res.usr, resource2->res.usr);
855                 case res_html:
856                         return compare_html(resource1->res.html, resource2->res.html);
857                 case res_msg:
858                         return compare_messagetable(resource1->res.msg, resource2->res.msg);
859                 case res_ver:
860                         return compare_versioninfo(resource1->res.ver, resource2->res.ver);
861                 case res_dlginit:
862                         return compare_dlginit(resource1->res.dlgi, resource2->res.dlgi);
863                 case res_toolbar:
864                         return compare_toolbar(resource1->res.tbt, resource2->res.tbt);
865                 case res_anicur:
866                 case res_aniico:
867                         return compare_ani_curico(resource1->res.ani, resource2->res.ani);
868                 default:
869                         /* Not supposed to reach here */
870                         fprintf(stderr, "Not supposed to reach here (compare())\n");
871                         abort();
872                         return -1;
873         }
874 }
875
876 typedef struct resource_lang_node
877 {
878     language_t lang;
879     resource_t *res;
880     struct resource_lang_node *next;
881 } resource_lang_node_t;
882
883 typedef struct resource_id_node
884 {
885     name_id_t *id;
886     resource_lang_node_t *langs;
887     struct resource_id_node *next;
888 } resource_id_node_t;
889
890 static struct
891 {
892     int enabled;
893     struct resource_id_node *ids;
894 } verify_tab[res_usr+1];
895
896 static void add_resource(resource_t *res)
897 {
898     resource_id_node_t *idnode;
899     resource_lang_node_t *langnode;
900     if (!verify_tab[res->type].enabled)
901     {
902         fprintf(stderr, "ERR: Report this: unknown resource type parsed %08x\n", res->type);
903         return;
904     }
905
906     for (idnode = verify_tab[res->type].ids; idnode; idnode = idnode->next)
907         if (compare_name_id(idnode->id, res->name) == 0)
908             break;
909
910     if (idnode == NULL)
911     {
912         idnode = xmalloc(sizeof(resource_id_node_t));
913         idnode->id = res->name;
914         idnode->langs = NULL;
915         idnode->next = verify_tab[res->type].ids;
916         verify_tab[res->type].ids = idnode;
917     }
918
919     for (langnode = idnode->langs; langnode; langnode = langnode->next)
920         if (compare_lang(langnode->lang, get_language(res)) == 0)
921         {
922             fprintf(stderr, "ERR: resource %s [type %x] language %03x:%02x duplicated!\n",
923                 get_nameid_str(res->name), res->type, langnode->lang.id, langnode->lang.sub);
924             return;
925         }
926
927     langnode = xmalloc(sizeof(resource_lang_node_t));
928     langnode->res = res;
929     langnode->lang = get_language(res);
930     langnode->next = idnode->langs;
931     idnode->langs = langnode;
932 }
933
934 static void setup_tabs(void)
935 {
936     int i;
937
938     for (i = 0; i <= res_usr; i++)
939         switch(i) {
940                 case res_acc:
941                 case res_bmp:
942                 case res_cur:
943                 case res_curg:
944                 case res_dlg:
945                 case res_fnt:
946                 case res_fntdir:
947                 case res_ico:
948                 case res_icog:
949                 case res_men:
950                 case res_rdt:
951                 case res_stt:
952                 case res_usr:
953                 case res_msg:
954                 case res_ver:
955                 case res_dlginit:
956                 case res_toolbar:
957                 case res_anicur:
958                 case res_aniico:
959                 case res_html:
960                     verify_tab[i].enabled = 1;
961                     break;
962         }
963 }
964
965 static const char *get_typename_for_int(int type) {
966     resource_t res;
967     res.type = type;
968     return get_typename(&res);
969 }
970
971 static resource_t *find_main(int type, name_id_t *id, resource_lang_node_t *langnode)
972 {
973     resource_t *neutral = NULL, *en = NULL, *en_US = NULL;
974     for (; langnode; langnode = langnode->next)
975     {
976         if (langnode->lang.id == LANG_NEUTRAL && langnode->lang.sub == SUBLANG_NEUTRAL)
977             neutral = langnode->res;
978         if (langnode->lang.id == MASTER_LANGUAGE && langnode->lang.sub == SUBLANG_NEUTRAL)
979             en = langnode->res;
980         if (langnode->lang.id == MASTER_LANGUAGE && langnode->lang.sub == MASTER_SUBLANGUAGE)
981             en_US = langnode->res;
982     }
983
984     if (neutral != NULL && (en != NULL || en_US != NULL))
985     {
986         fprintf(stderr, "INFO: Resource %04x/%s has both NEUTRAL and MASTER language translation\n",
987             type, get_nameid_str(id));
988     }
989
990     if (en_US != NULL) return en_US;
991     if (en != NULL) return en;
992     return neutral;
993 }
994
995 void verify_translations(resource_t *top) {
996     resource_t *curr = top;
997     resource_id_node_t *idnode;
998     resource_lang_node_t *langnode;
999     int type;
1000
1001     setup_tabs();
1002     while (curr)
1003     {
1004         add_resource(curr);
1005         curr = curr->next;
1006     }
1007
1008     for (type = 0; type <= res_usr; type++)
1009     {
1010         printf("TYPE NEXT [%s]\n", get_typename_for_int(type));
1011         for (idnode = verify_tab[type].ids; idnode; idnode = idnode->next)
1012         {
1013             resource_t *mainres;
1014             printf("RESOURCE [%s]\n", get_nameid_str(idnode->id));
1015
1016             mainres = find_main(type, idnode->id, idnode->langs);
1017             if (!mainres)
1018             {
1019                 fprintf(stderr, "ERR: resource %04x/%s has translation(s) but not available in NEUTRAL or MASTER language\n",
1020                     type, get_nameid_str(idnode->id));
1021                 for (langnode = idnode->langs; langnode; langnode = langnode->next)
1022                     printf("EXTRA %03x:%02x\n", langnode->lang.id, langnode->lang.sub);
1023                 continue;
1024             }
1025
1026             if (get_language_id(mainres) == LANG_NEUTRAL && idnode->langs->next == NULL) {
1027                 printf("NOTRANSL\n");
1028                 continue;
1029             }
1030
1031             for (langnode = idnode->langs; langnode; langnode = langnode->next)
1032             {
1033                 printf("EXIST %03x:%02x\n", langnode->lang.id, langnode->lang.sub);
1034                 if (compare(langnode->res, mainres))
1035                 {
1036                     printf("DIFF %03x:%02x\n", langnode->lang.id, langnode->lang.sub);
1037                 }
1038             }
1039         }
1040     }
1041 }