mshtml: Don't share nstable reference with nsnode.
[wine.git] / tools / wrc / translation.c
blob74f2017895337018f1126e775055cf33569b187f
1 /*
2 * Copyright 2003 Vincent BĂ©ron
3 * Copyright 2007, 2008 Mikolaj Zalewski
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <assert.h>
24 #include "dumpres.h"
25 #include "utils.h"
26 #include "wrc.h"
28 #define MASTER_LANGUAGE LANG_ENGLISH
29 #define MASTER_SUBLANGUAGE SUBLANG_ENGLISH_US
30 #define NB_LANG 0x94
32 enum lang_type_e {
33 lang_type_master = 0,
34 lang_type_neutral,
35 lang_type_normal
38 static language_t get_language(resource_t *resource) {
39 switch(resource->type) {
40 case res_acc:
41 return *resource->res.acc->lvc.language;
42 case res_bmp:
43 return *resource->res.bmp->data->lvc.language;
44 case res_cur:
45 return *resource->res.cur->lvc.language;
46 case res_curg:
47 return *resource->res.curg->lvc.language;
48 case res_dlg:
49 return *resource->res.dlg->lvc.language;
50 case res_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();
86 static int get_language_id(resource_t *resource) {
87 return get_language(resource).id;
90 static int compare_lang(language_t lang1, language_t lang2)
92 return memcmp(&lang1, &lang2, sizeof(language_t));
95 #if 0
97 #define PRETTYPRINTLANG(langid) \
98 if(LANG_##langid == lid) { \
99 return #langid; \
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(IRISH)
138 PRETTYPRINTLANG(ITALIAN)
139 PRETTYPRINTLANG(JAPANESE)
140 PRETTYPRINTLANG(KANNADA)
141 PRETTYPRINTLANG(KASHMIRI)
142 PRETTYPRINTLANG(KAZAK)
143 PRETTYPRINTLANG(KONKANI)
144 PRETTYPRINTLANG(KOREAN)
145 PRETTYPRINTLANG(KYRGYZ)
146 PRETTYPRINTLANG(LATVIAN)
147 PRETTYPRINTLANG(LITHUANIAN)
148 PRETTYPRINTLANG(MACEDONIAN)
149 PRETTYPRINTLANG(MALAY)
150 PRETTYPRINTLANG(MALAYALAM)
151 PRETTYPRINTLANG(MANIPURI)
152 PRETTYPRINTLANG(MARATHI)
153 PRETTYPRINTLANG(MONGOLIAN)
154 PRETTYPRINTLANG(NEPALI)
155 PRETTYPRINTLANG(NORWEGIAN)
156 PRETTYPRINTLANG(ORIYA)
157 PRETTYPRINTLANG(POLISH)
158 PRETTYPRINTLANG(PORTUGUESE)
159 PRETTYPRINTLANG(PUNJABI)
160 PRETTYPRINTLANG(ROMANIAN)
161 PRETTYPRINTLANG(RUSSIAN)
162 PRETTYPRINTLANG(SANSKRIT)
163 PRETTYPRINTLANG(SERBIAN)
164 PRETTYPRINTLANG(SINDHI)
165 PRETTYPRINTLANG(SLOVAK)
166 PRETTYPRINTLANG(SLOVENIAN)
167 PRETTYPRINTLANG(SPANISH)
168 PRETTYPRINTLANG(SWAHILI)
169 PRETTYPRINTLANG(SWEDISH)
170 PRETTYPRINTLANG(SYRIAC)
171 PRETTYPRINTLANG(TAMIL)
172 PRETTYPRINTLANG(TATAR)
173 PRETTYPRINTLANG(TELUGU)
174 PRETTYPRINTLANG(THAI)
175 PRETTYPRINTLANG(TURKISH)
176 PRETTYPRINTLANG(UKRAINIAN)
177 PRETTYPRINTLANG(URDU)
178 PRETTYPRINTLANG(UZBEK)
179 PRETTYPRINTLANG(VIETNAMESE)
180 PRETTYPRINTLANG(SCOTTISH_GAELIC)
181 PRETTYPRINTLANG(MALTESE)
182 PRETTYPRINTLANG(MAORI)
183 PRETTYPRINTLANG(RHAETO_ROMANCE)
184 PRETTYPRINTLANG(SAAMI)
185 PRETTYPRINTLANG(SORBIAN)
186 PRETTYPRINTLANG(SUTU)
187 PRETTYPRINTLANG(TSONGA)
188 PRETTYPRINTLANG(TSWANA)
189 PRETTYPRINTLANG(VENDA)
190 PRETTYPRINTLANG(XHOSA)
191 PRETTYPRINTLANG(ZULU)
192 PRETTYPRINTLANG(ESPERANTO)
193 PRETTYPRINTLANG(WALON)
194 PRETTYPRINTLANG(CORNISH)
195 PRETTYPRINTLANG(WELSH)
196 PRETTYPRINTLANG(BRETON)
197 return "Unknown language";
199 #endif
201 static int compare_accelerator(accelerator_t *accelerator1, accelerator_t *accelerator2) {
202 int different = 0;
203 event_t *ev1 = NULL, *ev2 = NULL;
204 if(((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;
218 if(!different &&
219 ((ev1 && !ev2) || (!ev1 && ev2)))
220 different = 1;
221 return different;
224 static int compare_bitmap(bitmap_t *bitmap1, bitmap_t *bitmap2) {
225 int different = 0;
226 if(((bitmap1->memopt != bitmap2->memopt) ||
227 (bitmap1->data->lvc.version != bitmap2->data->lvc.version) ||
228 (bitmap1->data->lvc.characts != bitmap2->data->lvc.characts)))
229 different = 1;
230 return different;
233 static int compare_cursor(cursor_t *cursor1, cursor_t *cursor2) {
234 int different = 0;
235 if(((cursor1->id != cursor2->id) ||
236 (cursor1->width != cursor2->width) ||
237 (cursor1->height != cursor2->height) ||
238 (cursor1->xhot != cursor2->xhot) ||
239 (cursor1->yhot != cursor2->yhot)))
240 different = 1;
241 if(!different &&
242 ((cursor1->lvc.version != cursor2->lvc.version) ||
243 (cursor1->lvc.characts != cursor2->lvc.characts)))
244 different = 1;
245 return different;
248 static int compare_cursor_group(cursor_group_t *cursor_group1, cursor_group_t *cursor_group2) {
249 int different = 0;
250 cursor_t *cursor1 = NULL, *cursor2 = NULL;
251 if(((cursor_group1->memopt != cursor_group2->memopt) ||
252 (cursor_group1->lvc.version != cursor_group2->lvc.version) ||
253 (cursor_group1->lvc.characts != cursor_group2->lvc.characts)))
254 different = 1;
255 if(!different &&
256 (cursor_group1->ncursor != cursor_group2->ncursor))
257 different = 1;
258 if(!different) {
259 cursor1 = cursor_group1->cursorlist;
260 cursor2 = cursor_group2->cursorlist;
261 while(!different && cursor1 && cursor2) {
262 different = compare_cursor(cursor1, cursor2);
263 cursor1 = cursor1->next;
264 cursor2 = cursor2->next;
266 if(!different &&
267 ((cursor1 && !cursor2) ||
268 (!cursor1 && cursor2)))
269 different = 1;
271 return different;
274 static int compare_control(control_t *control1, control_t *control2) {
275 int different = 0;
276 char *nameid = NULL;
277 int ignore_style;
278 if(((control1 && !control2) || (!control1 && control2)))
279 different = 1;
280 if(different || !control1 || !control2)
281 return different;
282 nameid = strdup(get_nameid_str(control1->ctlclass));
283 if(strcmp(nameid, get_nameid_str(control2->ctlclass)))
284 different = 1;
285 free(nameid);
286 if (different)
287 return different;
289 /* allow the translators to set some styles */
290 ignore_style = 0;
291 if (control1->ctlclass->type == name_ord && control1->ctlclass->name.i_name == CT_BUTTON)
292 ignore_style = 0x2000; /* BS_MULTILINE*/
294 if((control1->id != control2->id))
295 different = 1;
296 if(!different && control1->gotstyle && control2->gotstyle) {
297 if((!control1->style || !control2->style) ||
298 (control1->style->and_mask || control2->style->and_mask) ||
299 ((control1->style->or_mask & ~ignore_style) != (control2->style->or_mask & ~ignore_style)))
300 different = 1;
301 } else if(!different &&
302 ((control1->gotstyle && !control2->gotstyle) ||
303 (!control1->gotstyle && control2->gotstyle)))
304 different = 1;
305 if(!different && control1->gotexstyle && control2->gotexstyle) {
306 if((!control1->exstyle || !control2->exstyle) ||
307 (control1->exstyle->and_mask || control2->exstyle->and_mask) ||
308 (control1->exstyle->or_mask != control2->exstyle->or_mask))
309 different = 1;
310 } else if(!different &&
311 ((control1->gotexstyle && !control2->gotexstyle) ||
312 (!control1->gotexstyle && control2->gotexstyle)))
313 different = 1;
314 if(!different && control1->gothelpid && control2->gothelpid) {
315 if(control1->helpid != control2->helpid)
316 different = 1;
317 } else if(!different &&
318 ((control1->gothelpid && !control2->gothelpid) ||
319 (!control1->gothelpid && control2->gothelpid)))
320 different = 1;
321 return different;
324 static int compare_dialog(dialog_t *dialog1, dialog_t *dialog2) {
325 int different = 0;
326 char *nameid = NULL;
327 control_t *ctrl1, *ctrl2;
328 if(((dialog1->memopt != dialog2->memopt) ||
329 (dialog1->lvc.version != dialog2->lvc.version) ||
330 (dialog1->lvc.characts != dialog2->lvc.characts)))
331 different = 1;
332 if(!different && dialog1->gotstyle && dialog2->gotstyle) {
333 if((!dialog1->style || !dialog2->style) ||
334 (dialog1->style->and_mask || dialog2->style->and_mask) ||
335 (dialog1->style->or_mask != dialog2->style->or_mask))
336 different = 1;
337 } else if(!different &&
338 ((dialog1->gotstyle && !dialog2->gotstyle) ||
339 (!dialog1->gotstyle && dialog2->gotstyle)))
340 different = 1;
341 if(!different && dialog1->gotexstyle && dialog2->gotexstyle) {
342 if((!dialog1->exstyle || !dialog2->exstyle) ||
343 (dialog1->exstyle->and_mask || dialog2->exstyle->and_mask) ||
344 (dialog1->exstyle->or_mask != dialog2->exstyle->or_mask))
345 different = 1;
346 } else if(!different &&
347 ((dialog1->gotexstyle && !dialog2->gotexstyle) ||
348 (!dialog1->gotexstyle && dialog2->gotexstyle)))
349 different = 1;
350 if(!different && dialog1->gothelpid && dialog2->gothelpid) {
351 if(dialog1->helpid != dialog2->helpid)
352 different = 1;
353 } else if(!different &&
354 ((dialog1->gothelpid && !dialog2->gothelpid) ||
355 (!dialog1->gothelpid && dialog2->gothelpid)))
356 different = 1;
357 nameid = strdup(get_nameid_str(dialog1->menu));
358 if(!different && strcmp(nameid, get_nameid_str(dialog2->menu)))
359 different = 1;
360 free(nameid);
361 nameid = strdup(get_nameid_str(dialog1->dlgclass));
362 if(!different && strcmp(nameid, get_nameid_str(dialog2->dlgclass)))
363 different = 1;
364 free(nameid);
366 ctrl1 = dialog1->controls;
367 ctrl2 = dialog2->controls;
368 while(!different && (ctrl1 || ctrl2))
370 different = compare_control(ctrl1, ctrl2);
371 if (ctrl1) ctrl1 = ctrl1->next;
372 if (ctrl2) ctrl2 = ctrl2->next;
374 return different;
377 static int compare_font(font_t *font1, font_t *font2) {
378 int different = 0;
379 if(((font1->memopt != font2->memopt) ||
380 (font1->data->lvc.version != font2->data->lvc.version) ||
381 (font1->data->lvc.characts != font2->data->lvc.characts)))
382 different = 1;
383 return different;
386 static int compare_fontdir(fontdir_t *fontdir1, fontdir_t *fontdir2) {
387 int different = 0;
388 if(((fontdir1->memopt != fontdir2->memopt) ||
389 (fontdir1->data->lvc.version != fontdir2->data->lvc.version) ||
390 (fontdir1->data->lvc.characts != fontdir2->data->lvc.characts)))
391 different = 1;
392 return different;
395 static int compare_icon(icon_t *icon1, icon_t *icon2) {
396 int different = 0;
397 if(((icon1->id != icon2->id) ||
398 (icon1->width != icon2->width) ||
399 (icon1->height != icon2->height)))
400 different = 1;
401 if(!different &&
402 ((icon1->lvc.version != icon2->lvc.version) ||
403 (icon1->lvc.characts != icon2->lvc.characts)))
404 different = 1;
405 return different;
408 static int compare_icon_group(icon_group_t *icon_group1, icon_group_t *icon_group2) {
409 int different = 0;
410 icon_t *icon1 = NULL, *icon2 = NULL;
411 if(((icon_group1->memopt != icon_group2->memopt) ||
412 (icon_group1->lvc.version != icon_group2->lvc.version) ||
413 (icon_group1->lvc.characts != icon_group2->lvc.characts)))
414 different = 1;
415 if(!different &&
416 (icon_group1->nicon != icon_group2->nicon))
417 different = 1;
418 if(!different) {
419 icon1 = icon_group1->iconlist;
420 icon2 = icon_group2->iconlist;
421 while(!different && icon1 && icon2) {
422 different = compare_icon(icon1, icon2);
423 icon1 = icon1->next;
424 icon2 = icon2->next;
426 if(!different &&
427 ((icon1 && !icon2) ||
428 (!icon1 && icon2)))
429 different = 1;
431 return different;
434 static int compare_menu_item(menu_item_t *menu_item1, menu_item_t *menu_item2) {
435 int different = 0;
436 while(!different && menu_item1 && menu_item2) {
437 if(menu_item1->popup && menu_item2->popup) {
438 if(!different && menu_item1->gotid && menu_item2->gotid) {
439 if(menu_item1->id != menu_item2->id)
440 different = 1;
441 } else if(!different &&
442 ((menu_item1->gotid && !menu_item2->gotid) ||
443 (!menu_item1->gotid && menu_item2->gotid)))
444 different = 1;
445 if(!different && menu_item1->gottype && menu_item2->gottype) {
446 if(menu_item1->type != menu_item2->type)
447 different = 1;
448 } else if(!different &&
449 ((menu_item1->gottype && !menu_item2->gottype) ||
450 (!menu_item1->gottype && menu_item2->gottype)))
451 different = 1;
452 if(!different && menu_item1->gotstate && menu_item2->gotstate) {
453 if(menu_item1->state != menu_item2->state)
454 different = 1;
455 } else if(!different &&
456 ((menu_item1->gotstate && !menu_item2->gotstate) ||
457 (!menu_item1->gotstate && menu_item2->gotstate)))
458 different = 1;
459 if(!different && menu_item1->gothelpid && menu_item2->gothelpid) {
460 if(menu_item1->helpid != menu_item2->helpid)
461 different = 1;
462 } else if(!different &&
463 ((menu_item1->gothelpid && !menu_item2->gothelpid) ||
464 (!menu_item1->gothelpid && menu_item2->gothelpid)))
465 different = 1;
466 if(!different)
467 different = compare_menu_item(menu_item1->popup, menu_item2->popup);
468 } else if(!menu_item1->popup && !menu_item2->popup) {
469 if(menu_item1->name && menu_item2->name) {
470 if(!different && menu_item1->gotid && menu_item2->gotid) {
471 if(menu_item1->id != menu_item2->id)
472 different = 1;
473 } else if(!different &&
474 ((menu_item1->gotid && !menu_item2->gotid) ||
475 (!menu_item1->gotid && menu_item2->gotid)))
476 different = 1;
477 if(!different && menu_item1->gottype && menu_item2->gottype) {
478 if(menu_item1->type != menu_item2->type)
479 different = 1;
480 } else if(!different &&
481 ((menu_item1->gottype && !menu_item2->gottype) ||
482 (!menu_item1->gottype && menu_item2->gottype)))
483 different = 1;
484 if(!different && menu_item1->gotstate && menu_item2->gotstate) {
485 if(menu_item1->state != menu_item2->state)
486 different = 1;
487 } else if(!different &&
488 ((menu_item1->gotstate && !menu_item2->gotstate) ||
489 (!menu_item1->gotstate && menu_item2->gotstate)))
490 different = 1;
491 if(!different && menu_item1->gothelpid && menu_item2->gothelpid) {
492 if(menu_item1->helpid != menu_item2->helpid)
493 different = 1;
494 } else if(!different &&
495 ((menu_item1->gothelpid && !menu_item2->gothelpid) ||
496 (!menu_item1->gothelpid && menu_item2->gothelpid)))
497 different = 1;
498 } else if((menu_item1->name && !menu_item2->name) ||
499 (!menu_item1->name && menu_item2->name))
500 different = 1;
501 } else
502 different = 1;
503 menu_item1 = menu_item1->next;
504 menu_item2 = menu_item2->next;
506 if(!different &&
507 ((menu_item1 && !menu_item2) ||
508 (!menu_item1 && menu_item2)))
509 different = 1;
510 return different;
513 static int compare_menu(menu_t *menu1, menu_t *menu2) {
514 int different = 0;
515 if(((menu1->memopt != menu2->memopt) ||
516 (menu1->lvc.version != menu2->lvc.version) ||
517 (menu1->lvc.characts != menu2->lvc.characts)))
518 different = 1;
519 if(!different)
520 different = compare_menu_item(menu1->items, menu2->items);
521 return different;
524 static int compare_rcdata(rcdata_t *rcdata1, rcdata_t *rcdata2) {
525 int different = 0;
526 if(((rcdata1->memopt != rcdata2->memopt) ||
527 (rcdata1->data->lvc.version != rcdata2->data->lvc.version) ||
528 (rcdata1->data->lvc.characts != rcdata2->data->lvc.characts)))
529 different = 1;
530 return different;
533 static int compare_html(html_t *rcdata1, html_t *rcdata2) {
534 int different = 0;
535 if(((rcdata1->memopt != rcdata2->memopt) ||
536 (rcdata1->data->lvc.version != rcdata2->data->lvc.version) ||
537 (rcdata1->data->lvc.characts != rcdata2->data->lvc.characts)))
538 different = 1;
539 return different;
542 static int compare_stringtable(stringtable_t *stringtable1, stringtable_t *stringtable2) {
543 int different = 0;
544 int i;
545 while(!different && stringtable1 && stringtable2) {
546 if((stringtable1->memopt != stringtable2->memopt) ||
547 (stringtable1->lvc.version != stringtable2->lvc.version) ||
548 (stringtable1->lvc.characts != stringtable2->lvc.characts))
549 different = 1;
550 if(!different) {
551 if((stringtable1->nentries != stringtable2->nentries) ||
552 (stringtable1->idbase != stringtable2->idbase))
553 different = 1;
554 else
555 for(i = 0 ; i < stringtable1->nentries; i++)
556 if((stringtable1->entries[i].id != stringtable2->entries[i].id) ||
557 (stringtable1->entries[i].memopt != stringtable2->entries[i].memopt) ||
558 (stringtable1->entries[i].str && !stringtable2->entries[i].str) ||
559 (!stringtable1->entries[i].str && stringtable2->entries[i].str)) {
560 different = 1;
561 break;
564 stringtable1 = stringtable1->next;
565 stringtable2 = stringtable2->next;
567 return different;
570 static int compare_user(user_t *user1, user_t *user2) {
571 int different = 0;
572 char *nameid = NULL;
573 if(((user1->memopt != user2->memopt) ||
574 (user1->data->lvc.version != user2->data->lvc.version) ||
575 (user1->data->lvc.characts != user2->data->lvc.characts)))
576 different = 1;
577 nameid = strdup(get_nameid_str(user1->type));
578 if(!different && strcmp(nameid, get_nameid_str(user2->type)))
579 different = 1;
580 free(nameid);
581 return different;
584 static int compare_messagetable(messagetable_t *messagetable1, messagetable_t *messagetable2) {
585 int different = 0;
586 if(((messagetable1->memopt != messagetable2->memopt) ||
587 (messagetable1->data->lvc.version != messagetable2->data->lvc.version) ||
588 (messagetable1->data->lvc.characts != messagetable2->data->lvc.characts)))
589 different = 1;
590 return different;
593 static int compare_string(string_t *string1, string_t *string2) {
594 int different = 0;
595 if(((string1->size != string2->size) ||
596 (string1->type != string2->type)))
597 different = 1;
598 if(!different) {
599 if(string1->type == str_char)
600 different = memcmp(string1->str.cstr, string2->str.cstr, string1->size);
601 else if(string1->type == str_unicode)
602 different = memcmp(string1->str.wstr, string2->str.wstr, string1->size*sizeof(WCHAR));
603 else
604 different = 1;
606 return different;
609 static int compare_ver_block(ver_block_t *ver_block1, ver_block_t *ver_block2);
611 static int compare_ver_value(ver_value_t *ver_value1, ver_value_t *ver_value2) {
612 int different = 0;
613 int i = 0;
614 if((ver_value1->type == ver_value2->type)) {
615 switch(ver_value1->type) {
616 case val_str:
617 if(!different && ver_value1->key && ver_value2->key)
618 different = compare_string(ver_value1->key, ver_value2->key);
619 else if(!different &&
620 ((ver_value1->key && !ver_value2->key) ||
621 (!ver_value1->key && ver_value2->key)))
622 different = 1;
623 break;
624 case val_words:
625 if(!different && ver_value1->key && ver_value2->key)
626 different = compare_string(ver_value1->key, ver_value2->key);
627 else if(!different &&
628 ((ver_value1->key && !ver_value2->key) ||
629 (!ver_value1->key && ver_value2->key)))
630 different = 1;
631 if(!different && ver_value1->value.words && ver_value2->value.words) {
632 if(ver_value1->value.words->nwords != ver_value2->value.words->nwords)
633 different = 1;
634 if(!different)
635 for(i = 0; i < ver_value1->value.words->nwords; i++) {
636 if(ver_value1->value.words->words[i] != ver_value2->value.words->words[i]) {
637 different = 1;
638 break;
641 } else if(!different &&
642 ((ver_value1->value.words && !ver_value2->value.words) ||
643 (!ver_value1->value.words && ver_value2->value.words)))
644 different = 1;
645 break;
646 case val_block:
647 if(!different && ver_value1->value.block && ver_value2->value.block)
648 different = compare_ver_block(ver_value1->value.block, ver_value2->value.block);
649 else if(!different &&
650 ((ver_value1->value.block && !ver_value2->value.block) ||
651 (!ver_value1->value.block && ver_value2->value.block)))
652 different = 1;
653 break;
654 default:
655 different = 1;
657 } else
658 different = 1;
659 return different;
662 static int compare_ver_block(ver_block_t *ver_block1, ver_block_t *ver_block2) {
663 int different = 0;
664 ver_value_t *ver_value1 = ver_block1->values, *ver_value2 = ver_block2->values;
666 while(!different && ver_value1 && ver_value2) {
667 different = compare_ver_value(ver_value1, ver_value2);
668 ver_value1 = ver_value1->next;
669 ver_value2 = ver_value2->next;
671 if(!different &&
672 ((ver_value1 && !ver_value2) ||
673 (!ver_value1 && ver_value2)))
674 different = 1;
676 return different;
679 static int compare_versioninfo(versioninfo_t *versioninfo1, versioninfo_t *versioninfo2) {
680 int different = 0;
681 ver_block_t *ver_block1 = NULL, *ver_block2 = NULL;
682 if(((versioninfo1->memopt != versioninfo2->memopt) ||
683 (versioninfo1->lvc.version != versioninfo2->lvc.version) ||
684 (versioninfo1->lvc.characts != versioninfo2->lvc.characts)))
685 different = 1;
686 if(!different && versioninfo1->gotit.fv && versioninfo2->gotit.fv) {
687 if((versioninfo1->filever_maj1 != versioninfo2->filever_maj1) ||
688 (versioninfo1->filever_maj2 != versioninfo2->filever_maj2) ||
689 (versioninfo1->filever_min1 != versioninfo2->filever_min1) ||
690 (versioninfo1->filever_min2 != versioninfo2->filever_min2))
691 different = 1;
692 } else if(!different &&
693 ((versioninfo1->gotit.fv && !versioninfo2->gotit.fv) ||
694 (!versioninfo1->gotit.fv && versioninfo2->gotit.fv)))
695 different = 1;
696 if(!different && versioninfo1->gotit.pv && versioninfo2->gotit.pv) {
697 if((versioninfo1->prodver_maj1 != versioninfo2->prodver_maj1) ||
698 (versioninfo1->prodver_maj2 != versioninfo2->prodver_maj2) ||
699 (versioninfo1->prodver_min1 != versioninfo2->prodver_min1) ||
700 (versioninfo1->prodver_min2 != versioninfo2->prodver_min2))
701 different = 1;
702 } else if(!different &&
703 ((versioninfo1->gotit.pv && !versioninfo2->gotit.pv) ||
704 (!versioninfo1->gotit.pv && versioninfo2->gotit.pv)))
705 different = 1;
706 if(!different && versioninfo1->gotit.fo && versioninfo2->gotit.fo) {
707 if(versioninfo1->fileos != versioninfo2->fileos)
708 different = 1;
709 } else if(!different &&
710 ((versioninfo1->gotit.fo && !versioninfo2->gotit.fo) ||
711 (!versioninfo1->gotit.fo && versioninfo2->gotit.fo)))
712 different = 1;
713 if(!different && versioninfo1->gotit.ff && versioninfo2->gotit.ff) {
714 if(versioninfo1->fileflags != versioninfo2->fileflags)
715 different = 1;
716 } else if(!different &&
717 ((versioninfo1->gotit.ff && !versioninfo2->gotit.ff) ||
718 (!versioninfo1->gotit.ff && versioninfo2->gotit.ff)))
719 different = 1;
720 if(!different && versioninfo1->gotit.ffm && versioninfo2->gotit.ffm) {
721 if(versioninfo1->fileflagsmask != versioninfo2->fileflagsmask)
722 different = 1;
723 } else if(!different &&
724 ((versioninfo1->gotit.ffm && !versioninfo2->gotit.ffm) ||
725 (!versioninfo1->gotit.ffm && versioninfo2->gotit.ffm)))
726 different = 1;
727 if(!different && versioninfo1->gotit.ft && versioninfo2->gotit.ft) {
728 if(versioninfo1->filetype != versioninfo2->filetype)
729 different = 1;
730 } else if(!different &&
731 ((versioninfo1->gotit.ft && !versioninfo2->gotit.ft) ||
732 (!versioninfo1->gotit.ft && versioninfo2->gotit.ft)))
733 different = 1;
734 if(!different && versioninfo1->gotit.fst && versioninfo2->gotit.fst) {
735 if(versioninfo1->filesubtype != versioninfo2->filesubtype)
736 different = 1;
737 } else if(!different &&
738 ((versioninfo1->gotit.fst && !versioninfo2->gotit.fst) ||
739 (!versioninfo1->gotit.fst && versioninfo2->gotit.fst)))
740 different = 1;
741 if(!different) {
742 ver_block1 = versioninfo1->blocks;
743 ver_block2 = versioninfo2->blocks;
744 while(!different && ver_block1 && ver_block2) {
745 different = compare_ver_block(ver_block1, ver_block2);
746 ver_block1 = ver_block1->next;
747 ver_block2 = ver_block2->next;
749 if(!different &&
750 ((ver_block1 && !ver_block2) ||
751 (!ver_block1 && ver_block2)))
752 different = 1;
754 return different;
757 static int compare_dlginit(dlginit_t *dlginit1, dlginit_t *dlginit2) {
758 int different = 0;
759 if(((dlginit1->memopt != dlginit2->memopt) ||
760 (dlginit1->data->lvc.version != dlginit2->data->lvc.version) ||
761 (dlginit1->data->lvc.characts != dlginit2->data->lvc.characts)))
762 different = 1;
763 return different;
766 static int compare_toolbar_item(toolbar_item_t *toolbar_item1, toolbar_item_t *toolbar_item2) {
767 int different = 0;
768 while(!different && toolbar_item1 && toolbar_item2) {
769 if((toolbar_item1->id && !toolbar_item2->id) ||
770 (!toolbar_item1->id && toolbar_item2->id))
771 different = 1;
772 toolbar_item1 = toolbar_item1->next;
773 toolbar_item2 = toolbar_item2->next;
775 if(!different &&
776 ((toolbar_item1 && !toolbar_item2) ||
777 (!toolbar_item1 && toolbar_item2)))
778 different = 1;
779 return different;
782 static int compare_toolbar(toolbar_t *toolbar1, toolbar_t *toolbar2) {
783 int different = 0;
784 if(((toolbar1->memopt != toolbar2->memopt) ||
785 (toolbar1->lvc.version != toolbar2->lvc.version) ||
786 (toolbar1->lvc.characts != toolbar2->lvc.characts)))
787 different = 1;
788 if(!different)
789 different = compare_toolbar_item(toolbar1->items, toolbar2->items);
790 return different;
793 static int compare_ani_curico(ani_curico_t *ani_curico1, ani_curico_t *ani_curico2) {
794 int different = 0;
795 if(((ani_curico1->memopt != ani_curico2->memopt) ||
796 (ani_curico1->data->lvc.version != ani_curico2->data->lvc.version) ||
797 (ani_curico1->data->lvc.characts != ani_curico2->data->lvc.characts)))
798 different = 1;
799 return different;
802 static int compare(resource_t *resource1, resource_t *resource2) {
803 switch(resource1->type) {
804 case res_acc:
805 return compare_accelerator(resource1->res.acc, resource2->res.acc);
806 case res_bmp:
807 return compare_bitmap(resource1->res.bmp, resource2->res.bmp);
808 case res_cur:
809 return compare_cursor(resource1->res.cur, resource2->res.cur);
810 case res_curg:
811 return compare_cursor_group(resource1->res.curg, resource2->res.curg);
812 case res_dlg:
813 return compare_dialog(resource1->res.dlg, resource2->res.dlg);
814 case res_fnt:
815 return compare_font(resource1->res.fnt, resource2->res.fnt);
816 case res_fntdir:
817 return compare_fontdir(resource1->res.fnd, resource2->res.fnd);
818 case res_ico:
819 return compare_icon(resource1->res.ico, resource2->res.ico);
820 case res_icog:
821 return compare_icon_group(resource1->res.icog, resource2->res.icog);
822 case res_men:
823 return compare_menu(resource1->res.men, resource2->res.men);
824 case res_rdt:
825 return compare_rcdata(resource1->res.rdt, resource2->res.rdt);
826 case res_stt:
827 return compare_stringtable(resource1->res.stt, resource2->res.stt);
828 case res_usr:
829 return compare_user(resource1->res.usr, resource2->res.usr);
830 case res_html:
831 return compare_html(resource1->res.html, resource2->res.html);
832 case res_msg:
833 return compare_messagetable(resource1->res.msg, resource2->res.msg);
834 case res_ver:
835 return compare_versioninfo(resource1->res.ver, resource2->res.ver);
836 case res_dlginit:
837 return compare_dlginit(resource1->res.dlgi, resource2->res.dlgi);
838 case res_toolbar:
839 return compare_toolbar(resource1->res.tbt, resource2->res.tbt);
840 case res_anicur:
841 case res_aniico:
842 return compare_ani_curico(resource1->res.ani, resource2->res.ani);
843 default:
844 /* Not supposed to reach here */
845 fprintf(stderr, "Not supposed to reach here (compare())\n");
846 abort();
847 return -1;
851 typedef struct resource_lang_node
853 language_t lang;
854 resource_t *res;
855 struct resource_lang_node *next;
856 } resource_lang_node_t;
858 typedef struct resource_id_node
860 name_id_t *id;
861 resource_lang_node_t *langs;
862 struct resource_id_node *next;
863 } resource_id_node_t;
865 static struct
867 int enabled;
868 struct resource_id_node *ids;
869 } verify_tab[res_usr+1];
871 static void add_resource(resource_t *res)
873 resource_id_node_t *idnode;
874 resource_lang_node_t *langnode;
875 if (!verify_tab[res->type].enabled)
877 fprintf(stderr, "ERR: Report this: unknown resource type parsed %08x\n", res->type);
878 return;
881 for (idnode = verify_tab[res->type].ids; idnode; idnode = idnode->next)
882 if (compare_name_id(idnode->id, res->name) == 0)
883 break;
885 if (idnode == NULL)
887 idnode = xmalloc(sizeof(resource_id_node_t));
888 idnode->id = res->name;
889 idnode->langs = NULL;
890 idnode->next = verify_tab[res->type].ids;
891 verify_tab[res->type].ids = idnode;
894 for (langnode = idnode->langs; langnode; langnode = langnode->next)
895 if (compare_lang(langnode->lang, get_language(res)) == 0)
897 fprintf(stderr, "ERR: resource %s [type %x] language %03x:%02x duplicated!\n",
898 get_nameid_str(res->name), res->type, langnode->lang.id, langnode->lang.sub);
899 return;
902 langnode = xmalloc(sizeof(resource_lang_node_t));
903 langnode->res = res;
904 langnode->lang = get_language(res);
905 langnode->next = idnode->langs;
906 idnode->langs = langnode;
909 static void setup_tabs(void)
911 int i;
913 for (i = 0; i <= res_usr; i++)
914 switch(i) {
915 case res_acc:
916 case res_bmp:
917 case res_cur:
918 case res_curg:
919 case res_dlg:
920 case res_fnt:
921 case res_fntdir:
922 case res_ico:
923 case res_icog:
924 case res_men:
925 case res_rdt:
926 case res_stt:
927 case res_usr:
928 case res_msg:
929 case res_ver:
930 case res_dlginit:
931 case res_toolbar:
932 case res_anicur:
933 case res_aniico:
934 case res_html:
935 verify_tab[i].enabled = 1;
936 break;
940 static const char *get_typename_for_int(int type) {
941 resource_t res;
942 res.type = type;
943 return get_typename(&res);
946 static resource_t *find_main(int type, name_id_t *id, resource_lang_node_t *langnode)
948 resource_t *neutral = NULL, *en = NULL, *en_US = NULL;
949 for (; langnode; langnode = langnode->next)
951 if (langnode->lang.id == LANG_NEUTRAL && langnode->lang.sub == SUBLANG_NEUTRAL)
952 neutral = langnode->res;
953 if (langnode->lang.id == MASTER_LANGUAGE && langnode->lang.sub == SUBLANG_NEUTRAL)
954 en = langnode->res;
955 if (langnode->lang.id == MASTER_LANGUAGE && langnode->lang.sub == MASTER_SUBLANGUAGE)
956 en_US = langnode->res;
959 if (neutral != NULL && (en != NULL || en_US != NULL))
961 fprintf(stderr, "INFO: Resource %04x/%s has both NEUTRAL and MASTER language translation\n",
962 type, get_nameid_str(id));
965 if (en_US != NULL) return en_US;
966 if (en != NULL) return en;
967 return neutral;
970 void verify_translations(resource_t *top) {
971 resource_t *curr = top;
972 resource_id_node_t *idnode;
973 resource_lang_node_t *langnode;
974 int type;
976 setup_tabs();
977 while (curr)
979 add_resource(curr);
980 curr = curr->next;
983 for (type = 0; type <= res_usr; type++)
985 printf("TYPE NEXT [%s]\n", get_typename_for_int(type));
986 for (idnode = verify_tab[type].ids; idnode; idnode = idnode->next)
988 resource_t *mainres;
989 printf("RESOURCE [%s]\n", get_nameid_str(idnode->id));
991 mainres = find_main(type, idnode->id, idnode->langs);
992 if (!mainres)
994 fprintf(stderr, "ERR: resource %04x/%s has translation(s) but not available in NEUTRAL or MASTER language\n",
995 type, get_nameid_str(idnode->id));
996 for (langnode = idnode->langs; langnode; langnode = langnode->next)
997 printf("EXTRA %03x:%02x\n", langnode->lang.id, langnode->lang.sub);
998 continue;
1001 if (get_language_id(mainres) == LANG_NEUTRAL && idnode->langs->next == NULL) {
1002 printf("NOTRANSL\n");
1003 continue;
1006 for (langnode = idnode->langs; langnode; langnode = langnode->next)
1008 printf("EXIST %03x:%02x\n", langnode->lang.id, langnode->lang.sub);
1009 if (compare(langnode->res, mainres))
1011 printf("DIFF %03x:%02x\n", langnode->lang.id, langnode->lang.sub);