msi/tests: Add test for merging tables with string primary keys.
[wine] / tools / wrc / genres.c
1 /*
2  * Generate .res format from a resource-tree
3  *
4  * Copyright 1998 Bertho A. Stultiens
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * History:
21  * 05-May-2000 BS       - Added code to support endian conversions. The
22  *                        extra functions also aid unaligned access, but
23  *                        this is not yet implemented.
24  * 25-May-1998 BS       - Added simple unicode -> char conversion for resource
25  *                        names in .s and .h files.
26  */
27
28 #include "config.h"
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdarg.h>
34 #include <assert.h>
35 #include <ctype.h>
36
37 #include "wrc.h"
38 #include "genres.h"
39 #include "utils.h"
40 #include "windef.h"
41 #include "winbase.h"
42 #include "wingdi.h"
43 #include "winuser.h"
44 #include "wine/unicode.h"
45
46 #define SetResSize(res, tag)    set_dword((res), (tag), (res)->size - get_dword((res), (tag)))
47
48 res_t *new_res(void)
49 {
50         res_t *r;
51         r = xmalloc(sizeof(res_t));
52         r->allocsize = RES_BLOCKSIZE;
53         r->size = 0;
54         r->dataidx = 0;
55         r->data = xmalloc(RES_BLOCKSIZE);
56         return r;
57 }
58
59 res_t *grow_res(res_t *r, unsigned int add)
60 {
61         r->allocsize += add;
62         r->data = xrealloc(r->data, r->allocsize);
63         return r;
64 }
65
66 /*
67  *****************************************************************************
68  * Function     : put_byte
69  *                put_word
70  *                put_dword
71  * Syntax       : void put_byte(res_t *res, unsigned c)
72  *                void put_word(res_t *res, unsigned w)
73  *                void put_dword(res_t *res, unsigned d)
74  * Input        :
75  *      res     - Binary resource to put the data in
76  *      c, w, d - Data to put
77  * Output       : nop
78  * Description  : Put primitives that put an item in the binary resource.
79  *                The data array grows automatically.
80  * Remarks      :
81  *****************************************************************************
82 */
83 void put_byte(res_t *res, unsigned c)
84 {
85         if(res->allocsize - res->size < sizeof(char))
86                 grow_res(res, RES_BLOCKSIZE);
87         res->data[res->size] = (char)c;
88         res->size += sizeof(char);
89 }
90
91 void put_word(res_t *res, unsigned w)
92 {
93         if(res->allocsize - res->size < sizeof(WORD))
94                 grow_res(res, RES_BLOCKSIZE);
95         switch(byteorder)
96         {
97 #ifdef WORDS_BIGENDIAN
98         default:
99 #endif
100         case WRC_BO_BIG:
101                 res->data[res->size+0] = HIBYTE(w);
102                 res->data[res->size+1] = LOBYTE(w);
103                 break;
104
105 #ifndef WORDS_BIGENDIAN
106         default:
107 #endif
108         case WRC_BO_LITTLE:
109                 res->data[res->size+1] = HIBYTE(w);
110                 res->data[res->size+0] = LOBYTE(w);
111                 break;
112         }
113         res->size += sizeof(WORD);
114 }
115
116 void put_dword(res_t *res, unsigned d)
117 {
118         if(res->allocsize - res->size < sizeof(DWORD))
119                 grow_res(res, RES_BLOCKSIZE);
120         switch(byteorder)
121         {
122 #ifdef WORDS_BIGENDIAN
123         default:
124 #endif
125         case WRC_BO_BIG:
126                 res->data[res->size+0] = HIBYTE(HIWORD(d));
127                 res->data[res->size+1] = LOBYTE(HIWORD(d));
128                 res->data[res->size+2] = HIBYTE(LOWORD(d));
129                 res->data[res->size+3] = LOBYTE(LOWORD(d));
130                 break;
131
132 #ifndef WORDS_BIGENDIAN
133         default:
134 #endif
135         case WRC_BO_LITTLE:
136                 res->data[res->size+3] = HIBYTE(HIWORD(d));
137                 res->data[res->size+2] = LOBYTE(HIWORD(d));
138                 res->data[res->size+1] = HIBYTE(LOWORD(d));
139                 res->data[res->size+0] = LOBYTE(LOWORD(d));
140                 break;
141         }
142         res->size += sizeof(DWORD);
143 }
144
145 static void put_pad(res_t *res)
146 {
147         while(res->size & 0x3)
148                 put_byte(res, 0);
149 }
150
151 /*
152  *****************************************************************************
153  * Function     : set_word
154  *                set_dword
155  * Syntax       : void set_word(res_t *res, int ofs, unsigned w)
156  *                void set_dword(res_t *res, int ofs, unsigned d)
157  * Input        :
158  *      res     - Binary resource to put the data in
159  *      ofs     - Byte offset in data-array
160  *      w, d    - Data to put
161  * Output       : nop
162  * Description  : Set the value of a binary resource data array to a
163  *                specific value.
164  * Remarks      :
165  *****************************************************************************
166 */
167 static void set_word(res_t *res, int ofs, unsigned w)
168 {
169         switch(byteorder)
170         {
171 #ifdef WORDS_BIGENDIAN
172         default:
173 #endif
174         case WRC_BO_BIG:
175                 res->data[ofs+0] = HIBYTE(w);
176                 res->data[ofs+1] = LOBYTE(w);
177                 break;
178
179 #ifndef WORDS_BIGENDIAN
180         default:
181 #endif
182         case WRC_BO_LITTLE:
183                 res->data[ofs+1] = HIBYTE(w);
184                 res->data[ofs+0] = LOBYTE(w);
185                 break;
186         }
187 }
188
189 static void set_dword(res_t *res, int ofs, unsigned d)
190 {
191         switch(byteorder)
192         {
193 #ifdef WORDS_BIGENDIAN
194         default:
195 #endif
196         case WRC_BO_BIG:
197                 res->data[ofs+0] = HIBYTE(HIWORD(d));
198                 res->data[ofs+1] = LOBYTE(HIWORD(d));
199                 res->data[ofs+2] = HIBYTE(LOWORD(d));
200                 res->data[ofs+3] = LOBYTE(LOWORD(d));
201                 break;
202
203 #ifndef WORDS_BIGENDIAN
204         default:
205 #endif
206         case WRC_BO_LITTLE:
207                 res->data[ofs+3] = HIBYTE(HIWORD(d));
208                 res->data[ofs+2] = LOBYTE(HIWORD(d));
209                 res->data[ofs+1] = HIBYTE(LOWORD(d));
210                 res->data[ofs+0] = LOBYTE(LOWORD(d));
211                 break;
212         }
213 }
214
215 /*
216  *****************************************************************************
217  * Function     : get_dword
218  * Input        :
219  *      res     - Binary resource to put the data in
220  *      ofs     - Byte offset in data-array
221  * Output       : The data in native endian
222  * Description  : Get the value of a binary resource data array in native
223  *                endian.
224  * Remarks      :
225  *****************************************************************************
226 */
227 static DWORD get_dword(res_t *res, int ofs)
228 {
229         switch(byteorder)
230         {
231 #ifdef WORDS_BIGENDIAN
232         default:
233 #endif
234         case WRC_BO_BIG:
235                 return   (res->data[ofs+0] << 24)
236                        | (res->data[ofs+1] << 16)
237                        | (res->data[ofs+2] <<  8)
238                        |  res->data[ofs+3];
239
240 #ifndef WORDS_BIGENDIAN
241         default:
242 #endif
243         case WRC_BO_LITTLE:
244                 return   (res->data[ofs+3] << 24)
245                        | (res->data[ofs+2] << 16)
246                        | (res->data[ofs+1] <<  8)
247                        |  res->data[ofs+0];
248         }
249 }
250
251 /*
252  *****************************************************************************
253  * Function     : string_to_upper
254  * Syntax       : void string_to_upper(string_t *str)
255  * Input        :
256  * Output       :
257  * Description  :
258  * Remarks      : FIXME: codepages...
259  *****************************************************************************
260 */
261 static void string_to_upper(string_t *str)
262 {
263     int i;
264
265     if(str->type == str_char)
266     {
267         for (i = 0; i < str->size; i++) str->str.cstr[i] = toupper((unsigned char)str->str.cstr[i]);
268     }
269     else if(str->type == str_unicode)
270     {
271         for (i = 0; i < str->size; i++) str->str.wstr[i] = toupperW(str->str.wstr[i]);
272     }
273     else
274     {
275         internal_error(__FILE__, __LINE__, "Invalid string type %d\n", str->type);
276     }
277 }
278
279 /*
280  *****************************************************************************
281  * Function     : put_string
282  * Syntax       : void put_string(res_t *res, string_t *str, enum str_e type,
283  *                                int isterm, const language_t *lang)
284  * Input        :
285  *      res     - Binary resource to put the data in
286  *      str     - String to put
287  *      type    - Data has to be written in either str_char or str_unicode
288  *      isterm  - The string is '\0' terminated (disregard the string's
289  *                size member)
290  * Output       : nop
291  * Description  :
292  * Remarks      :
293  *****************************************************************************
294 */
295 static void put_string(res_t *res, const string_t *str, enum str_e type, int isterm,
296                        const language_t *lang)
297 {
298     int cnt, codepage;
299     string_t *newstr;
300
301     assert(res != NULL);
302     assert(str != NULL);
303
304     if (lang) codepage = get_language_codepage( lang->id, lang->sub );
305     else codepage = get_language_codepage( 0, 0 );
306
307     assert( codepage != -1 );
308
309     newstr = convert_string(str, type, codepage);
310     if (type == str_unicode)
311     {
312         if (str->type == str_char)
313         {
314             if (!check_unicode_conversion( str, newstr, codepage ))
315                 error( "String %s does not convert identically to Unicode and back in codepage %d. "
316                        "Try using a Unicode string instead\n", str->str.cstr, codepage );
317         }
318         if (!isterm) put_word(res, newstr->size);
319         for(cnt = 0; cnt < newstr->size; cnt++)
320         {
321             WCHAR c = newstr->str.wstr[cnt];
322             if (isterm && !c) break;
323             put_word(res, c);
324         }
325         if (isterm) put_word(res, 0);
326     }
327     else  /* str_char */
328     {
329         if (!isterm) put_byte(res, newstr->size);
330         for(cnt = 0; cnt < newstr->size; cnt++)
331         {
332             char c = newstr->str.cstr[cnt];
333             if (isterm && !c) break;
334             put_byte(res, c);
335         }
336         if (isterm) put_byte(res, 0);
337     }
338     free_string(newstr);
339 }
340
341 /*
342  *****************************************************************************
343  * Function     : put_name_id
344  * Syntax       : void put_name_id(res_t *res, name_id_t *nid, int upcase, const language_t *lang)
345  * Input        :
346  * Output       :
347  * Description  :
348  * Remarks      :
349  *****************************************************************************
350 */
351 static void put_name_id(res_t *res, name_id_t *nid, int upcase, const language_t *lang)
352 {
353         if(nid->type == name_ord)
354         {
355                 if(win32)
356                         put_word(res, 0xffff);
357                 else
358                         put_byte(res, 0xff);
359                 put_word(res, (WORD)nid->name.i_name);
360         }
361         else if(nid->type == name_str)
362         {
363                 if(upcase)
364                         string_to_upper(nid->name.s_name);
365                 put_string(res, nid->name.s_name, win32 ? str_unicode : str_char, TRUE, lang);
366         }
367         else
368         {
369                 internal_error(__FILE__, __LINE__, "Invalid name_id type %d\n", nid->type);
370         }
371 }
372
373 /*
374  *****************************************************************************
375  * Function     : put_lvc
376  * Syntax       : void put_lvc(res_t *res, lvc_t *lvc)
377  * Input        :
378  * Output       :
379  * Description  :
380  * Remarks      :
381  *****************************************************************************
382 */
383 static void put_lvc(res_t *res, lvc_t *lvc)
384 {
385         if(lvc && lvc->language)
386                 put_word(res, MAKELANGID(lvc->language->id, lvc->language->sub));
387         else
388                 put_word(res, 0);       /* Neutral */
389         if(lvc && lvc->version)
390                 put_dword(res, *(lvc->version));
391         else
392                 put_dword(res, 0);
393         if(lvc && lvc->characts)
394                 put_dword(res, *(lvc->characts));
395         else
396                 put_dword(res, 0);
397 }
398
399 /*
400  *****************************************************************************
401  * Function     : put_raw_data
402  * Syntax       : void put_raw_data(res_t *res, raw_data_t *raw, int offset)
403  * Input        :
404  * Output       :
405  * Description  :
406  * Remarks      :
407  *****************************************************************************
408 */
409 static void put_raw_data(res_t *res, raw_data_t *raw, int offset)
410 {
411         unsigned int wsize = raw->size - offset;
412         if(res->allocsize - res->size < wsize)
413                 grow_res(res, wsize);
414         memcpy(&(res->data[res->size]), raw->data + offset, wsize);
415         res->size += wsize;
416 }
417
418 /*
419  *****************************************************************************
420  * Function     : put_res_header
421  * Syntax       : input_res_header(res_t *res, int type, name_id_t *ntype,
422  *                                  name_id_t *name, DWORD memopt, lvc_t *lvc)
423  *
424  * Input        :
425  *      res     - Binary resource descriptor to write to
426  *      type    - Resource identifier (if ntype == NULL)
427  *      ntype   - Name id of type
428  *      name    - Resource's name
429  *      memopt  - Resource's memory options to write
430  *      lvc     - Language, version and characteristics (win32 only)
431  * Output       : An index to the resource size field. The resource size field
432  *                contains the header size upon exit.
433  * Description  :
434  * Remarks      :
435  *****************************************************************************
436 */
437 static int put_res_header(res_t *res, int type, name_id_t *ntype, name_id_t *name,
438                           DWORD memopt, lvc_t *lvc)
439 {
440         if(win32)
441         {
442                 put_dword(res, 0);              /* We will overwrite these later */
443                 put_dword(res, 0);
444                 if(!ntype)
445                 {
446                         put_word(res, 0xffff);          /* ResType */
447                         put_word(res, type);
448                 }
449                 else
450                         put_name_id(res, ntype, TRUE, lvc->language);
451                 put_name_id(res, name, TRUE, lvc->language); /* ResName */
452                 put_pad(res);
453                 put_dword(res, 0);              /* DataVersion */
454                 put_word(res, memopt);          /* Memory options */
455                 put_lvc(res, lvc);              /* Language, version and characts */
456                 set_dword(res, 0*sizeof(DWORD), res->size);     /* Set preliminary resource */
457                 set_dword(res, 1*sizeof(DWORD), res->size);     /* Set HeaderSize */
458                 res->dataidx = res->size;
459                 return 0;
460         }
461         else /* win16 */
462         {
463                 int tag;
464                 if(!ntype)
465                 {
466                         put_byte(res, 0xff);            /* ResType */
467                         put_word(res, type);
468                 }
469                 else
470                         put_name_id(res, ntype, TRUE, NULL);
471                 put_name_id(res, name, TRUE, NULL); /* ResName */
472                 put_word(res, memopt);          /* Memory options */
473                 tag = res->size;
474                 put_dword(res, 0);              /* ResSize overwritten later*/
475                 set_dword(res, tag, res->size);
476                 res->dataidx = res->size;
477                 return tag;
478         }
479 }
480
481 /*
482  *****************************************************************************
483  * Function     : accelerator2res
484  * Syntax       : res_t *accelerator2res(name_id_t *name, accelerator_t *acc)
485  * Input        :
486  *      name    - Name/ordinal of the resource
487  *      acc     - The accelerator descriptor
488  * Output       : New .res format structure
489  * Description  :
490  * Remarks      :
491  *****************************************************************************
492 */
493 static res_t *accelerator2res(name_id_t *name, accelerator_t *acc)
494 {
495         int restag;
496         res_t *res;
497         event_t *ev;
498         assert(name != NULL);
499         assert(acc != NULL);
500
501         ev = acc->events;
502         res = new_res();
503         if(win32)
504         {
505                 restag = put_res_header(res, WRC_RT_ACCELERATOR, NULL, name, acc->memopt, &(acc->lvc));
506                 while(ev)
507                 {
508                         put_word(res, ev->flags | (ev->next ? 0 : 0x80));
509                         put_word(res, ev->key);
510                         put_word(res, ev->id);
511                         put_word(res, 0);       /* Padding */
512                         ev = ev->next;
513                 }
514                 put_pad(res);
515         }
516         else /* win16 */
517         {
518                 restag = put_res_header(res, WRC_RT_ACCELERATOR, NULL, name, acc->memopt, NULL);
519                 while(ev)
520                 {
521                         put_byte(res, ev->flags | (ev->next ? 0 : 0x80));
522                         put_word(res, ev->key);
523                         put_word(res, ev->id);
524                         ev = ev->next;
525                 }
526         }
527         /* Set ResourceSize */
528         SetResSize(res, restag);
529         return res;
530 }
531
532 /*
533  *****************************************************************************
534  * Function     : dialog2res
535  * Syntax       : res_t *dialog2res(name_id_t *name, dialog_t *dlg)
536  * Input        :
537  *      name    - Name/ordinal of the resource
538  *      dlg     - The dialog descriptor
539  * Output       : New .res format structure
540  * Description  :
541  * Remarks      :
542  *****************************************************************************
543 */
544 static res_t *dialog2res(name_id_t *name, dialog_t *dlg)
545 {
546         int restag;
547         res_t *res;
548         control_t *ctrl;
549         int tag_nctrl;
550         int nctrl = 0;
551         assert(name != NULL);
552         assert(dlg != NULL);
553
554         ctrl = dlg->controls;
555         res = new_res();
556         if(win32)
557         {
558                 restag = put_res_header(res, WRC_RT_DIALOG, NULL, name, dlg->memopt, &(dlg->lvc));
559
560                 put_dword(res, dlg->style->or_mask);
561                 put_dword(res, dlg->gotexstyle ? dlg->exstyle->or_mask : 0);
562                 tag_nctrl = res->size;
563                 put_word(res, 0);               /* Number of controls */
564                 put_word(res, dlg->x);
565                 put_word(res, dlg->y);
566                 put_word(res, dlg->width);
567                 put_word(res, dlg->height);
568                 if(dlg->menu)
569                         put_name_id(res, dlg->menu, TRUE, dlg->lvc.language);
570                 else
571                         put_word(res, 0);
572                 if(dlg->dlgclass)
573                         put_name_id(res, dlg->dlgclass, TRUE, dlg->lvc.language);
574                 else
575                         put_word(res, 0);
576                 if(dlg->title)
577                         put_string(res, dlg->title, str_unicode, TRUE, dlg->lvc.language);
578                 else
579                         put_word(res, 0);
580                 if(dlg->font)
581                 {
582                         put_word(res, dlg->font->size);
583                         put_string(res, dlg->font->name, str_unicode, TRUE, dlg->lvc.language);
584                 }
585
586                 put_pad(res);
587                 while(ctrl)
588                 {
589                         /* FIXME: what is default control style? */
590                         put_dword(res, ctrl->gotstyle ? ctrl->style->or_mask: WS_CHILD);
591                         put_dword(res, ctrl->gotexstyle ? ctrl->exstyle->or_mask : 0);
592                         put_word(res, ctrl->x);
593                         put_word(res, ctrl->y);
594                         put_word(res, ctrl->width);
595                         put_word(res, ctrl->height);
596                         put_word(res, ctrl->id);
597                         if(ctrl->ctlclass)
598                                 put_name_id(res, ctrl->ctlclass, TRUE, dlg->lvc.language);
599                         else
600                                 internal_error(__FILE__, __LINE__, "Control has no control-class\n");
601                         if(ctrl->title)
602                                 put_name_id(res, ctrl->title, FALSE, dlg->lvc.language);
603                         else
604                                 put_word(res, 0);
605                         if(ctrl->extra)
606                         {
607                                 put_word(res, ctrl->extra->size+2);
608                                 put_pad(res);
609                                 put_raw_data(res, ctrl->extra, 0);
610                         }
611                         else
612                                 put_word(res, 0);
613
614                         if(ctrl->next)
615                                 put_pad(res);
616                         nctrl++;
617                         ctrl = ctrl->next;
618                 }
619                 /* Set number of controls */
620                 set_word(res, tag_nctrl, (WORD)nctrl);
621         }
622         else /* win16 */
623         {
624                 restag = put_res_header(res, WRC_RT_DIALOG, NULL, name, dlg->memopt, NULL);
625
626                 put_dword(res, dlg->gotstyle ? dlg->style->or_mask : WS_POPUPWINDOW);
627                 tag_nctrl = res->size;
628                 put_byte(res, 0);               /* Number of controls */
629                 put_word(res, dlg->x);
630                 put_word(res, dlg->y);
631                 put_word(res, dlg->width);
632                 put_word(res, dlg->height);
633                 if(dlg->menu)
634                         put_name_id(res, dlg->menu, TRUE, NULL);
635                 else
636                         put_byte(res, 0);
637                 if(dlg->dlgclass)
638                         put_name_id(res, dlg->dlgclass, TRUE, NULL);
639                 else
640                         put_byte(res, 0);
641                 if(dlg->title)
642                         put_string(res, dlg->title, str_char, TRUE, NULL);
643                 else
644                         put_byte(res, 0);
645                 if(dlg->font)
646                 {
647                         put_word(res, dlg->font->size);
648                         put_string(res, dlg->font->name, str_char, TRUE, NULL);
649                 }
650
651                 while(ctrl)
652                 {
653                         put_word(res, ctrl->x);
654                         put_word(res, ctrl->y);
655                         put_word(res, ctrl->width);
656                         put_word(res, ctrl->height);
657                         put_word(res, ctrl->id);
658                         put_dword(res, ctrl->gotstyle ? ctrl->style->or_mask: WS_CHILD);
659                         if(ctrl->ctlclass)
660                         {
661                                 if(ctrl->ctlclass->type == name_ord
662                                 && ctrl->ctlclass->name.i_name >= 0x80
663                                 && ctrl->ctlclass->name.i_name <= 0x85)
664                                         put_byte(res, ctrl->ctlclass->name.i_name);
665                                 else if(ctrl->ctlclass->type == name_str)
666                                         put_name_id(res, ctrl->ctlclass, FALSE, NULL);
667                                 else
668                                         error("Unknown control-class %04x\n", ctrl->ctlclass->name.i_name);
669                         }
670                         else
671                                 internal_error(__FILE__, __LINE__, "Control has no control-class\n");
672                         if(ctrl->title)
673                                 put_name_id(res, ctrl->title, FALSE, NULL);
674                         else
675                                 put_byte(res, 0);
676
677                         /* FIXME: What is this extra byte doing here? */
678                         put_byte(res, 0);
679
680                         nctrl++;
681                         ctrl = ctrl->next;
682                 }
683                 /* Set number of controls */
684                 ((char *)res->data)[tag_nctrl] = (char)nctrl;
685         }
686         /* Set ResourceSize */
687         SetResSize(res, restag);
688         return res;
689 }
690
691 /*
692  *****************************************************************************
693  * Function     : dialogex2res
694  * Syntax       : res_t *dialogex2res(name_id_t *name, dialogex_t *dlgex)
695  * Input        :
696  *      name    - Name/ordinal of the resource
697  *      dlgex   - The dialogex descriptor
698  * Output       : New .res format structure
699  * Description  :
700  * Remarks      :
701  *****************************************************************************
702 */
703 static res_t *dialogex2res(name_id_t *name, dialogex_t *dlgex)
704 {
705         int restag;
706         res_t *res;
707         control_t *ctrl;
708         int tag_nctrl;
709         int nctrl = 0;
710         assert(name != NULL);
711         assert(dlgex != NULL);
712
713         ctrl = dlgex->controls;
714         res = new_res();
715         if(win32)
716         {
717                 restag = put_res_header(res, WRC_RT_DIALOG, NULL, name, dlgex->memopt, &(dlgex->lvc));
718
719                 /* FIXME: MS doc says that the first word must contain 0xffff
720                  * and the second 0x0001 to signal a DLGTEMPLATEEX. Borland's
721                  * compiler reverses the two words.
722                  * I don't know which one to choose, but I write it as Mr. B
723                  * writes it.
724                  */
725                 put_word(res, 1);               /* Signature */
726                 put_word(res, 0xffff);          /* DlgVer */
727                 put_dword(res, dlgex->gothelpid ? dlgex->helpid : 0);
728                 put_dword(res, dlgex->gotexstyle ? dlgex->exstyle->or_mask : 0);
729                 put_dword(res, dlgex->gotstyle ? dlgex->style->or_mask : WS_POPUPWINDOW);
730                 tag_nctrl = res->size;
731                 put_word(res, 0);               /* Number of controls */
732                 put_word(res, dlgex->x);
733                 put_word(res, dlgex->y);
734                 put_word(res, dlgex->width);
735                 put_word(res, dlgex->height);
736                 if(dlgex->menu)
737                         put_name_id(res, dlgex->menu, TRUE, dlgex->lvc.language);
738                 else
739                         put_word(res, 0);
740                 if(dlgex->dlgclass)
741                         put_name_id(res, dlgex->dlgclass, TRUE, dlgex->lvc.language);
742                 else
743                         put_word(res, 0);
744                 if(dlgex->title)
745                         put_string(res, dlgex->title, str_unicode, TRUE, dlgex->lvc.language);
746                 else
747                         put_word(res, 0);
748                 if(dlgex->font)
749                 {
750                         put_word(res, dlgex->font->size);
751                         put_word(res, dlgex->font->weight);
752                         /* FIXME: ? TRUE should be sufficient to say that it's
753                          * italic, but Borland's compiler says it's 0x0101.
754                          * I just copy it here, and hope for the best.
755                          */
756                         put_word(res, dlgex->font->italic ? 0x0101 : 0);
757                         put_string(res, dlgex->font->name, str_unicode, TRUE, dlgex->lvc.language);
758                 }
759
760                 put_pad(res);
761                 while(ctrl)
762                 {
763                         put_dword(res, ctrl->gothelpid ? ctrl->helpid : 0);
764                         put_dword(res, ctrl->gotexstyle ? ctrl->exstyle->or_mask : 0);
765                         /* FIXME: what is default control style? */
766                         put_dword(res, ctrl->gotstyle ? ctrl->style->or_mask : WS_CHILD | WS_VISIBLE);
767                         put_word(res, ctrl->x);
768                         put_word(res, ctrl->y);
769                         put_word(res, ctrl->width);
770                         put_word(res, ctrl->height);
771                         put_dword(res, ctrl->id);
772                         if(ctrl->ctlclass)
773                                 put_name_id(res, ctrl->ctlclass, TRUE, dlgex->lvc.language);
774                         else
775                                 internal_error(__FILE__, __LINE__, "Control has no control-class\n");
776                         if(ctrl->title)
777                                 put_name_id(res, ctrl->title, FALSE, dlgex->lvc.language);
778                         else
779                                 put_word(res, 0);
780                         if(ctrl->extra)
781                         {
782                                 put_pad(res);
783                                 put_word(res, ctrl->extra->size);
784                                 put_raw_data(res, ctrl->extra, 0);
785                         }
786                         else
787                                 put_word(res, 0);
788
789                         put_pad(res);
790                         nctrl++;
791                         ctrl = ctrl->next;
792                 }
793                 /* Set number of controls */
794                 set_word(res, tag_nctrl, (WORD)nctrl);
795                 /* Set ResourceSize */
796                 SetResSize(res, restag);
797                 put_pad(res);
798         }
799         else /* win16 */
800         {
801                 /* Do not generate anything in 16-bit mode */
802                 free(res->data);
803                 free(res);
804                 return NULL;
805         }
806         return res;
807 }
808
809 /*
810  *****************************************************************************
811  * Function     : menuitem2res
812  * Syntax       : void menuitem2res(res_t *res, menu_item_t *item)
813  * Input        :
814  * Output       :
815  * Description  :
816  * Remarks      : Self recursive
817  *****************************************************************************
818 */
819 static void menuitem2res(res_t *res, menu_item_t *menitem, const language_t *lang)
820 {
821         menu_item_t *itm = menitem;
822         if(win32)
823         {
824                 while(itm)
825                 {
826                         put_word(res, itm->state | (itm->popup ? MF_POPUP : 0) | (!itm->next ? MF_END : 0));
827                         if(!itm->popup)
828                                 put_word(res, itm->id);
829                         if(itm->name)
830                                 put_string(res, itm->name, str_unicode, TRUE, lang);
831                         else
832                                 put_word(res, 0);
833                         if(itm->popup)
834                                 menuitem2res(res, itm->popup, lang);
835                         itm = itm->next;
836                 }
837         }
838         else /* win16 */
839         {
840                 while(itm)
841                 {
842                         put_word(res, itm->state | (itm->popup ? MF_POPUP : 0) | (!itm->next ? MF_END : 0));
843                         if(!itm->popup)
844                                 put_word(res, itm->id);
845                         if(itm->name)
846                                 put_string(res, itm->name, str_char, TRUE, lang);
847                         else
848                                 put_byte(res, 0);
849                         if(itm->popup)
850                                 menuitem2res(res, itm->popup, lang);
851                         itm = itm->next;
852                 }
853         }
854
855 }
856
857 /*
858  *****************************************************************************
859  * Function     : menu2res
860  * Syntax       : res_t *menu2res(name_id_t *name, menu_t *men)
861  * Input        :
862  *      name    - Name/ordinal of the resource
863  *      men     - The menu descriptor
864  * Output       : New .res format structure
865  * Description  :
866  * Remarks      :
867  *****************************************************************************
868 */
869 static res_t *menu2res(name_id_t *name, menu_t *men)
870 {
871         int restag;
872         res_t *res;
873         assert(name != NULL);
874         assert(men != NULL);
875
876         res = new_res();
877         restag = put_res_header(res, WRC_RT_MENU, NULL, name, men->memopt, win32 ? &(men->lvc) : NULL);
878
879         put_dword(res, 0);              /* Menuheader: Version and HeaderSize */
880         menuitem2res(res, men->items, win32 ? men->lvc.language : NULL);
881         /* Set ResourceSize */
882         SetResSize(res, restag);
883         if(win32)
884                 put_pad(res);
885         return res;
886 }
887
888 /*
889  *****************************************************************************
890  * Function     : menuexitem2res
891  * Syntax       : void menuexitem2res(res_t *res, menuex_item_t *item)
892  * Input        :
893  * Output       : nop
894  * Description  :
895  * Remarks      : Self recursive
896  *****************************************************************************
897 */
898 static void menuexitem2res(res_t *res, menuex_item_t *menitem, const language_t *lang)
899 {
900         menuex_item_t *itm = menitem;
901         assert(win32 != 0);
902         while(itm)
903         {
904                 put_dword(res, itm->gottype ? itm->type : 0);
905                 put_dword(res, itm->gotstate ? itm->state : 0);
906                 put_dword(res, itm->gotid ? itm->id : 0);       /* FIXME: Docu. says word */
907                 put_word(res, (itm->popup ? 0x01 : 0) | (!itm->next ? MF_END : 0));
908                 if(itm->name)
909                         put_string(res, itm->name, str_unicode, TRUE, lang);
910                 else
911                         put_word(res, 0);
912                 put_pad(res);
913                 if(itm->popup)
914                 {
915                         put_dword(res, itm->gothelpid ? itm->helpid : 0);
916                         menuexitem2res(res, itm->popup, lang);
917                 }
918                 itm = itm->next;
919         }
920
921 }
922
923 /*
924  *****************************************************************************
925  * Function     : menuex2res
926  * Syntax       : res_t *menuex2res(name_id_t *name, menuex_t *menex)
927  * Input        :
928  *      name    - Name/ordinal of the resource
929  *      menex   - The menuex descriptor
930  * Output       : New .res format structure
931  * Description  :
932  * Remarks      :
933  *****************************************************************************
934 */
935 static res_t *menuex2res(name_id_t *name, menuex_t *menex)
936 {
937         int restag;
938         res_t *res;
939         assert(name != NULL);
940         assert(menex != NULL);
941
942         res = new_res();
943         if(win32)
944         {
945                 restag = put_res_header(res, WRC_RT_MENU, NULL, name, menex->memopt, &(menex->lvc));
946
947                 put_word(res, 1);               /* Menuheader: Version */
948                 put_word(res, 4);               /* Offset */
949                 put_dword(res, 0);              /* HelpId */
950                 put_pad(res);
951                 menuexitem2res(res, menex->items, menex->lvc.language);
952                 /* Set ResourceSize */
953                 SetResSize(res, restag);
954                 put_pad(res);
955         }
956         else /* win16 */
957         {
958                 /* Do not generate anything in 16-bit mode */
959                 free(res->data);
960                 free(res);
961                 return NULL;
962         }
963         return res;
964 }
965
966 /*
967  *****************************************************************************
968  * Function     : cursorgroup2res
969  * Syntax       : res_t *cursorgroup2res(name_id_t *name, cursor_group_t *curg)
970  * Input        :
971  *      name    - Name/ordinal of the resource
972  *      curg    - The cursor descriptor
973  * Output       : New .res format structure
974  * Description  :
975  * Remarks      :
976  *****************************************************************************
977 */
978 static res_t *cursorgroup2res(name_id_t *name, cursor_group_t *curg)
979 {
980         int restag;
981         res_t *res;
982         cursor_t *cur;
983         assert(name != NULL);
984         assert(curg != NULL);
985
986         res = new_res();
987         restag = put_res_header(res, WRC_RT_GROUP_CURSOR, NULL, name, curg->memopt, &(curg->lvc));
988         if(win32)
989         {
990                 put_word(res, 0);       /* Reserved */
991                 /* FIXME: The ResType in the NEWHEADER structure should
992                  * contain 14 according to the MS win32 doc. This is
993                  * not the case with the BRC compiler and I really doubt
994                  * the latter. Putting one here is compliant to win16 spec,
995                  * but who knows the true value?
996                  */
997                 put_word(res, 2);       /* ResType */
998                 put_word(res, curg->ncursor);
999 #if 0
1000                 for(cur = curg->cursorlist; cur; cur = cur->next)
1001 #else
1002                 cur = curg->cursorlist;
1003                 while(cur->next)
1004                         cur = cur->next;
1005                 for(; cur; cur = cur->prev)
1006 #endif
1007                 {
1008                         put_word(res, cur->width);
1009                         /* FIXME: The height of a cursor is half the size of
1010                          * the bitmap's height. BRC puts the height from the
1011                          * BITMAPINFOHEADER here instead of the cursorfile's
1012                          * height. MS doesn't seem to care...
1013                          */
1014                         put_word(res, cur->height);
1015                         /* FIXME: The next two are reversed in BRC and I don't
1016                          * know why. Probably a bug. But, we can safely ignore
1017                          * it because win16 does not support color cursors.
1018                          * A warning should have been generated by the parser.
1019                          */
1020                         put_word(res, cur->planes);
1021                         put_word(res, cur->bits);
1022                         /* FIXME: The +4 is the hotspot in the cursor resource.
1023                          * However, I could not find this in the documentation.
1024                          * The hotspot bytes must either be included or MS
1025                          * doesn't care.
1026                          */
1027                         put_dword(res, cur->data->size +4);
1028                         put_word(res, cur->id);
1029                 }
1030         }
1031         else /* win16 */
1032         {
1033                 put_word(res, 0);       /* Reserved */
1034                 put_word(res, 2);       /* ResType */
1035                 put_word(res, curg->ncursor);
1036 #if 0
1037                 for(cur = curg->cursorlist; cur; cur = cur->next)
1038 #else
1039                 cur = curg->cursorlist;
1040                 while(cur->next)
1041                         cur = cur->next;
1042                 for(; cur; cur = cur->prev)
1043 #endif
1044                 {
1045                         put_word(res, cur->width);
1046                         /* FIXME: The height of a cursor is half the size of
1047                          * the bitmap's height. BRC puts the height from the
1048                          * BITMAPINFOHEADER here instead of the cursorfile's
1049                          * height. MS doesn't seem to care...
1050                          */
1051                         put_word(res, cur->height);
1052                         /* FIXME: The next two are reversed in BRC and I don't
1053                          * know why. Probably a bug. But, we can safely ignore
1054                          * it because win16 does not support color cursors.
1055                          * A warning should have been generated by the parser.
1056                          */
1057                         put_word(res, cur->planes);
1058                         put_word(res, cur->bits);
1059                         /* FIXME: The +4 is the hotspot in the cursor resource.
1060                          * However, I could not find this in the documentation.
1061                          * The hotspot bytes must either be included or MS
1062                          * doesn't care.
1063                          */
1064                         put_dword(res, cur->data->size +4);
1065                         put_word(res, cur->id);
1066                 }
1067         }
1068         SetResSize(res, restag);        /* Set ResourceSize */
1069         if(win32)
1070                 put_pad(res);
1071
1072         return res;
1073 }
1074
1075 /*
1076  *****************************************************************************
1077  * Function     : cursor2res
1078  * Syntax       : res_t *cursor2res(cursor_t *cur)
1079  * Input        :
1080  *      cur     - The cursor descriptor
1081  * Output       : New .res format structure
1082  * Description  :
1083  * Remarks      :
1084  *****************************************************************************
1085 */
1086 static res_t *cursor2res(cursor_t *cur)
1087 {
1088         int restag;
1089         res_t *res;
1090         name_id_t name;
1091
1092         assert(cur != NULL);
1093
1094         res = new_res();
1095         name.type = name_ord;
1096         name.name.i_name = cur->id;
1097         restag = put_res_header(res, WRC_RT_CURSOR, NULL, &name, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE, &(cur->lvc));
1098         put_word(res, cur->xhot);
1099         put_word(res, cur->yhot);
1100         put_raw_data(res, cur->data, 0);
1101
1102         SetResSize(res, restag);        /* Set ResourceSize */
1103         if(win32)
1104                 put_pad(res);
1105
1106         return res;
1107 }
1108
1109 /*
1110  *****************************************************************************
1111  * Function     : icongroup2res
1112  * Syntax       : res_t *icongroup2res(name_id_t *name, icon_group_t *icog)
1113  * Input        :
1114  *      name    - Name/ordinal of the resource
1115  *      icog    - The icon group descriptor
1116  * Output       : New .res format structure
1117  * Description  :
1118  * Remarks      :
1119  *****************************************************************************
1120 */
1121 static res_t *icongroup2res(name_id_t *name, icon_group_t *icog)
1122 {
1123         int restag;
1124         res_t *res;
1125         icon_t *ico;
1126         assert(name != NULL);
1127         assert(icog != NULL);
1128
1129         res = new_res();
1130         restag = put_res_header(res, WRC_RT_GROUP_ICON, NULL, name, icog->memopt, &(icog->lvc));
1131         if(win32)
1132         {
1133                 put_word(res, 0);       /* Reserved */
1134                 /* FIXME: The ResType in the NEWHEADER structure should
1135                  * contain 14 according to the MS win32 doc. This is
1136                  * not the case with the BRC compiler and I really doubt
1137                  * the latter. Putting one here is compliant to win16 spec,
1138                  * but who knows the true value?
1139                  */
1140                 put_word(res, 1);       /* ResType */
1141                 put_word(res, icog->nicon);
1142                 for(ico = icog->iconlist; ico; ico = ico->next)
1143                 {
1144                         put_byte(res, ico->width);
1145                         put_byte(res, ico->height);
1146                         put_byte(res, ico->nclr);
1147                         put_byte(res, 0);       /* Reserved */
1148                         put_word(res, ico->planes);
1149                         put_word(res, ico->bits);
1150                         put_dword(res, ico->data->size);
1151                         put_word(res, ico->id);
1152                 }
1153         }
1154         else /* win16 */
1155         {
1156                 put_word(res, 0);       /* Reserved */
1157                 put_word(res, 1);       /* ResType */
1158                 put_word(res, icog->nicon);
1159                 for(ico = icog->iconlist; ico; ico = ico->next)
1160                 {
1161                         put_byte(res, ico->width);
1162                         put_byte(res, ico->height);
1163                         put_byte(res, ico->nclr);
1164                         put_byte(res, 0);       /* Reserved */
1165                         put_word(res, ico->planes);
1166                         put_word(res, ico->bits);
1167                         put_dword(res, ico->data->size);
1168                         put_word(res, ico->id);
1169                 }
1170         }
1171         SetResSize(res, restag);        /* Set ResourceSize */
1172         if(win32)
1173                 put_pad(res);
1174
1175         return res;
1176 }
1177
1178 /*
1179  *****************************************************************************
1180  * Function     : icon2res
1181  * Syntax       : res_t *icon2res(icon_t *ico)
1182  * Input        :
1183  *      ico     - The icon descriptor
1184  * Output       : New .res format structure
1185  * Description  :
1186  * Remarks      :
1187  *****************************************************************************
1188 */
1189 static res_t *icon2res(icon_t *ico)
1190 {
1191         int restag;
1192         res_t *res;
1193         name_id_t name;
1194
1195         assert(ico != NULL);
1196
1197         res = new_res();
1198         name.type = name_ord;
1199         name.name.i_name = ico->id;
1200         restag = put_res_header(res, WRC_RT_ICON, NULL, &name, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE, &(ico->lvc));
1201         put_raw_data(res, ico->data, 0);
1202
1203         SetResSize(res, restag);        /* Set ResourceSize */
1204         if(win32)
1205                 put_pad(res);
1206
1207         return res;
1208 }
1209
1210 /*
1211  *****************************************************************************
1212  * Function     : anicurico2res
1213  * Syntax       : res_t *anicurico2res(name_id_t *name, ani_curico_t *ani)
1214  * Input        :
1215  *      name    - Name/ordinal of the resource
1216  *      ani     - The animated object descriptor
1217  * Output       : New .res format structure
1218  * Description  :
1219  * Remarks      : The endian of the object's structures have been converted
1220  *                by the loader.
1221  *                There are rumors that win311 could handle animated stuff.
1222  *                That is why they are generated for both win16 and win32
1223  *                compile.
1224  *****************************************************************************
1225 */
1226 static res_t *anicurico2res(name_id_t *name, ani_curico_t *ani, enum res_e type)
1227 {
1228         int restag;
1229         res_t *res;
1230         assert(name != NULL);
1231         assert(ani != NULL);
1232
1233         res = new_res();
1234         restag = put_res_header(res, type == res_anicur ? WRC_RT_ANICURSOR : WRC_RT_ANIICON,
1235                                 NULL, name, ani->memopt, NULL);
1236         put_raw_data(res, ani->data, 0);
1237         /* Set ResourceSize */
1238         SetResSize(res, restag);
1239         if(win32)
1240                 put_pad(res);
1241         return res;
1242 }
1243
1244 /*
1245  *****************************************************************************
1246  * Function     : bitmap2res
1247  * Syntax       : res_t *bitmap2res(name_id_t *name, bitmap_t *bmp)
1248  * Input        :
1249  *      name    - Name/ordinal of the resource
1250  *      bmp     - The bitmap descriptor
1251  * Output       : New .res format structure
1252  * Description  :
1253  * Remarks      : The endian of the bitmap structures have been converted
1254  *                by the loader.
1255  *****************************************************************************
1256 */
1257 static res_t *bitmap2res(name_id_t *name, bitmap_t *bmp)
1258 {
1259         int restag;
1260         res_t *res;
1261         assert(name != NULL);
1262         assert(bmp != NULL);
1263
1264         res = new_res();
1265         restag = put_res_header(res, WRC_RT_BITMAP, NULL, name, bmp->memopt, &(bmp->data->lvc));
1266         if(bmp->data->data[0] == 'B'
1267         && bmp->data->data[1] == 'M'
1268         && ((BITMAPFILEHEADER *)bmp->data->data)->bfSize == bmp->data->size
1269         && bmp->data->size >= sizeof(BITMAPFILEHEADER))
1270         {
1271                 /* The File header is still attached, don't write it */
1272                 put_raw_data(res, bmp->data, sizeof(BITMAPFILEHEADER));
1273         }
1274         else
1275         {
1276                 put_raw_data(res, bmp->data, 0);
1277         }
1278         /* Set ResourceSize */
1279         SetResSize(res, restag);
1280         if(win32)
1281                 put_pad(res);
1282         return res;
1283 }
1284
1285 /*
1286  *****************************************************************************
1287  * Function     : font2res
1288  * Syntax       : res_t *font2res(name_id_t *name, font_t *fnt)
1289  * Input        :
1290  *      name    - Name/ordinal of the resource
1291  *      fnt     - The font descriptor
1292  * Output       : New .res format structure
1293  * Description  :
1294  * Remarks      : The data has been prepared just after parsing.
1295  *****************************************************************************
1296 */
1297 static res_t *font2res(name_id_t *name, font_t *fnt)
1298 {
1299         int restag;
1300         res_t *res;
1301         assert(name != NULL);
1302         assert(fnt != NULL);
1303
1304         res = new_res();
1305         restag = put_res_header(res, WRC_RT_FONT, NULL, name, fnt->memopt, &(fnt->data->lvc));
1306         put_raw_data(res, fnt->data, 0);
1307         /* Set ResourceSize */
1308         SetResSize(res, restag);
1309         if(win32)
1310                 put_pad(res);
1311         return res;
1312 }
1313
1314 /*
1315  *****************************************************************************
1316  * Function     : fontdir2res
1317  * Syntax       : res_t *fontdir2res(name_id_t *name, fontdir_t *fnd)
1318  * Input        :
1319  *      name    - Name/ordinal of the resource
1320  *      fntdir  - The fontdir descriptor
1321  * Output       : New .res format structure
1322  * Description  :
1323  * Remarks      : The data has been prepared just after parsing.
1324  *****************************************************************************
1325 */
1326 static res_t *fontdir2res(name_id_t *name, fontdir_t *fnd)
1327 {
1328         int restag;
1329         res_t *res;
1330         assert(name != NULL);
1331         assert(fnd != NULL);
1332
1333         res = new_res();
1334         restag = put_res_header(res, WRC_RT_FONTDIR, NULL, name, fnd->memopt, &(fnd->data->lvc));
1335         put_raw_data(res, fnd->data, 0);
1336         /* Set ResourceSize */
1337         SetResSize(res, restag);
1338         if(win32)
1339                 put_pad(res);
1340         return res;
1341 }
1342
1343 /*
1344  *****************************************************************************
1345  * Function     : html2res
1346  * Syntax       : res_t *html2res(name_id_t *name, html_t *html)
1347  * Input        :
1348  *      name    - Name/ordinal of the resource
1349  *      rdt     - The html descriptor
1350  * Output       : New .res format structure
1351  * Description  :
1352  * Remarks      :
1353  *****************************************************************************
1354 */
1355 static res_t *html2res(name_id_t *name, html_t *html)
1356 {
1357         int restag;
1358         res_t *res;
1359         assert(name != NULL);
1360         assert(html != NULL);
1361
1362         res = new_res();
1363         restag = put_res_header(res, WRC_RT_HTML, NULL, name, html->memopt, &(html->data->lvc));
1364         put_raw_data(res, html->data, 0);
1365         /* Set ResourceSize */
1366         SetResSize(res, restag);
1367         if(win32)
1368                 put_pad(res);
1369         return res;
1370 }
1371
1372 /*
1373  *****************************************************************************
1374  * Function     : rcdata2res
1375  * Syntax       : res_t *rcdata2res(name_id_t *name, rcdata_t *rdt)
1376  * Input        :
1377  *      name    - Name/ordinal of the resource
1378  *      rdt     - The rcdata descriptor
1379  * Output       : New .res format structure
1380  * Description  :
1381  * Remarks      :
1382  *****************************************************************************
1383 */
1384 static res_t *rcdata2res(name_id_t *name, rcdata_t *rdt)
1385 {
1386         int restag;
1387         res_t *res;
1388         assert(name != NULL);
1389         assert(rdt != NULL);
1390
1391         res = new_res();
1392         restag = put_res_header(res, WRC_RT_RCDATA, NULL, name, rdt->memopt, &(rdt->data->lvc));
1393         put_raw_data(res, rdt->data, 0);
1394         /* Set ResourceSize */
1395         SetResSize(res, restag);
1396         if(win32)
1397                 put_pad(res);
1398         return res;
1399 }
1400
1401 /*
1402  *****************************************************************************
1403  * Function     : messagetable2res
1404  * Syntax       : res_t *messagetable2res(name_id_t *name, messagetable_t *msg)
1405  * Input        :
1406  *      name    - Name/ordinal of the resource
1407  *      msg     - The messagetable descriptor
1408  * Output       : New .res format structure
1409  * Description  :
1410  * Remarks      : The data has been converted to the appropriate endian
1411  *                after it was parsed.
1412  *****************************************************************************
1413 */
1414 static res_t *messagetable2res(name_id_t *name, messagetable_t *msg)
1415 {
1416         int restag;
1417         res_t *res;
1418         assert(name != NULL);
1419         assert(msg != NULL);
1420
1421         res = new_res();
1422         restag = put_res_header(res, WRC_RT_MESSAGETABLE, NULL, name, msg->memopt, &(msg->data->lvc));
1423         put_raw_data(res, msg->data, 0);
1424         /* Set ResourceSize */
1425         SetResSize(res, restag);
1426         if(win32)
1427                 put_pad(res);
1428         return res;
1429 }
1430
1431 /*
1432  *****************************************************************************
1433  * Function     : stringtable2res
1434  * Syntax       : res_t *stringtable2res(stringtable_t *stt)
1435  * Input        :
1436  *      stt     - The stringtable descriptor
1437  * Output       : New .res format structure
1438  * Description  :
1439  * Remarks      :
1440  *****************************************************************************
1441 */
1442 static res_t *stringtable2res(stringtable_t *stt)
1443 {
1444         res_t *res;
1445         name_id_t name;
1446         int i;
1447         int restag;
1448         DWORD lastsize = 0;
1449
1450         assert(stt != NULL);
1451         res = new_res();
1452
1453         for(; stt; stt = stt->next)
1454         {
1455                 if(!stt->nentries)
1456                 {
1457                         warning("Empty internal stringtable\n");
1458                         continue;
1459                 }
1460                 name.type = name_ord;
1461                 name.name.i_name = (stt->idbase >> 4) + 1;
1462                 restag = put_res_header(res, WRC_RT_STRING, NULL, &name, stt->memopt, win32 ? &(stt->lvc) : NULL);
1463                 for(i = 0; i < stt->nentries; i++)
1464                 {
1465                         if(stt->entries[i].str && stt->entries[i].str->size)
1466                         {
1467                                 put_string(res, stt->entries[i].str, win32 ? str_unicode : str_char,
1468                                            FALSE, win32 ? stt->lvc.language : NULL);
1469                         }
1470                         else
1471                         {
1472                                 if (win32)
1473                                         put_word(res, 0);
1474                                 else
1475                                         put_byte(res, 0);
1476                         }
1477                 }
1478                 /* Set ResourceSize */
1479                 SetResSize(res, restag - lastsize);
1480                 if(win32)
1481                         put_pad(res);
1482                 lastsize = res->size;
1483         }
1484         return res;
1485 }
1486
1487 /*
1488  *****************************************************************************
1489  * Function     : user2res
1490  * Syntax       : res_t *user2res(name_id_t *name, user_t *usr)
1491  * Input        :
1492  *      name    - Name/ordinal of the resource
1493  *      usr     - The userresource descriptor
1494  * Output       : New .res format structure
1495  * Description  :
1496  * Remarks      :
1497  *****************************************************************************
1498 */
1499 static res_t *user2res(name_id_t *name, user_t *usr)
1500 {
1501         int restag;
1502         res_t *res;
1503         assert(name != NULL);
1504         assert(usr != NULL);
1505
1506         res = new_res();
1507         restag = put_res_header(res, 0, usr->type, name, usr->memopt, &(usr->data->lvc));
1508         put_raw_data(res, usr->data, 0);
1509         /* Set ResourceSize */
1510         SetResSize(res, restag);
1511         if(win32)
1512                 put_pad(res);
1513         return res;
1514 }
1515
1516 /*
1517  *****************************************************************************
1518  * Function     : versionblock2res
1519  * Syntax       : void versionblock2res(res_t *res, ver_block_t *blk)
1520  * Input        :
1521  *      res     - Binary resource to write to
1522  *      blk     - The version block to be written
1523  * Output       :
1524  * Description  :
1525  * Remarks      : Self recursive
1526  *****************************************************************************
1527 */
1528 static void versionblock2res(res_t *res, ver_block_t *blk, int level, const language_t *lang)
1529 {
1530         ver_value_t *val;
1531         int blksizetag;
1532         int valblksizetag;
1533         int valvalsizetag;
1534         int tag;
1535         int i;
1536
1537         blksizetag = res->size;
1538         put_word(res, 0);       /* Will be overwritten later */
1539         put_word(res, 0);
1540         if(win32)
1541                 put_word(res, 0);       /* level ? */
1542         put_string(res, blk->name, win32 ? str_unicode : str_char, TRUE, lang);
1543         put_pad(res);
1544         for(val = blk->values; val; val = val->next)
1545         {
1546                 if(val->type == val_str)
1547                 {
1548                         valblksizetag = res->size;
1549                         put_word(res, 0);       /* Will be overwritten later */
1550                         valvalsizetag = res->size;
1551                         put_word(res, 0);       /* Will be overwritten later */
1552                         if(win32)
1553                         {
1554                                 put_word(res, level);
1555                         }
1556                         put_string(res, val->key, win32 ? str_unicode : str_char, TRUE, lang);
1557                         put_pad(res);
1558                         tag = res->size;
1559                         put_string(res, val->value.str, win32 ? str_unicode : str_char, TRUE, lang);
1560                         if(win32)
1561                                 set_word(res, valvalsizetag, (WORD)((res->size - tag) >> 1));
1562                         else
1563                                 set_word(res, valvalsizetag, (WORD)(res->size - tag));
1564                         set_word(res, valblksizetag, (WORD)(res->size - valblksizetag));
1565                         put_pad(res);
1566                 }
1567                 else if(val->type == val_words)
1568                 {
1569                         valblksizetag = res->size;
1570                         put_word(res, 0);       /* Will be overwritten later */
1571                         valvalsizetag = res->size;
1572                         put_word(res, 0);       /* Will be overwritten later */
1573                         if(win32)
1574                         {
1575                                 put_word(res, level);
1576                         }
1577                         put_string(res, val->key, win32 ? str_unicode : str_char, TRUE, lang);
1578                         put_pad(res);
1579                         tag = res->size;
1580                         for(i = 0; i < val->value.words->nwords; i++)
1581                         {
1582                                 put_word(res, val->value.words->words[i]);
1583                         }
1584                         set_word(res, valvalsizetag, (WORD)(res->size - tag));
1585                         set_word(res, valblksizetag, (WORD)(res->size - valblksizetag));
1586                         put_pad(res);
1587                 }
1588                 else if(val->type == val_block)
1589                 {
1590                         versionblock2res(res, val->value.block, level+1, lang);
1591                 }
1592                 else
1593                 {
1594                         internal_error(__FILE__, __LINE__, "Invalid value indicator %d in VERSIONINFO\n", val->type);
1595                 }
1596         }
1597
1598         /* Set blocksize */
1599         set_word(res, blksizetag, (WORD)(res->size - blksizetag));
1600 }
1601
1602 /*
1603  *****************************************************************************
1604  * Function     : versioninfo2res
1605  * Syntax       : res_t *versioninfo2res(name_id_t *name, versioninfo_t *ver)
1606  * Input        :
1607  *      name    - Name/ordinal of the resource
1608  *      ver     - The versioninfo descriptor
1609  * Output       : New .res format structure
1610  * Description  :
1611  * Remarks      :
1612  *****************************************************************************
1613 */
1614 static res_t *versioninfo2res(name_id_t *name, versioninfo_t *ver)
1615 {
1616         int restag;
1617         int rootblocksizetag;
1618         int valsizetag;
1619         int tag;
1620         res_t *res;
1621         string_t vsvi;
1622         ver_block_t *blk;
1623
1624         assert(name != NULL);
1625         assert(ver != NULL);
1626
1627         vsvi.type = str_char;
1628         vsvi.str.cstr = xstrdup("VS_VERSION_INFO");
1629         vsvi.size = 15; /* Excl. termination */
1630
1631         res = new_res();
1632         restag = put_res_header(res, WRC_RT_VERSION, NULL, name, ver->memopt, &(ver->lvc));
1633         rootblocksizetag = res->size;
1634         put_word(res, 0);       /* BlockSize filled in later */
1635         valsizetag = res->size;
1636         put_word(res, 0);       /* ValueSize filled in later*/
1637         if(win32)
1638                 put_word(res, 0);       /* Tree-level ? */
1639         put_string(res, &vsvi, win32 ? str_unicode : str_char,
1640                    TRUE, win32 ? ver->lvc.language : NULL);
1641         if(win32)
1642                 put_pad(res);
1643         tag = res->size;
1644         put_dword(res, VS_FFI_SIGNATURE);
1645         put_dword(res, VS_FFI_STRUCVERSION);
1646         put_dword(res, (ver->filever_maj1 << 16) + (ver->filever_maj2 & 0xffff));
1647         put_dword(res, (ver->filever_min1 << 16) + (ver->filever_min2 & 0xffff));
1648         put_dword(res, (ver->prodver_maj1 << 16) + (ver->prodver_maj2 & 0xffff));
1649         put_dword(res, (ver->prodver_min1 << 16) + (ver->prodver_min2 & 0xffff));
1650         put_dword(res, ver->fileflagsmask);
1651         put_dword(res, ver->fileflags);
1652         put_dword(res, ver->fileos);
1653         put_dword(res, ver->filetype);
1654         put_dword(res, ver->filesubtype);
1655         put_dword(res, 0);              /* FileDateMS */
1656         put_dword(res, 0);              /* FileDateLS */
1657         /* Set ValueSize */
1658         set_word(res, valsizetag, (WORD)(res->size - tag));
1659         /* Descend into the blocks */
1660         for(blk = ver->blocks; blk; blk = blk->next)
1661                 versionblock2res(res, blk, 0, win32 ? ver->lvc.language : NULL);
1662         /* Set root block's size */
1663         set_word(res, rootblocksizetag, (WORD)(res->size - rootblocksizetag));
1664
1665         SetResSize(res, restag);
1666         if(win32)
1667                 put_pad(res);
1668
1669         free(vsvi.str.cstr);
1670         return res;
1671 }
1672
1673 /*
1674  *****************************************************************************
1675  * Function     : toolbaritem2res
1676  * Syntax       : void toolbaritem2res(res_t *res, toolbar_item_t *tbitem)
1677  * Input        :
1678  * Output       : nop
1679  * Description  :
1680  * Remarks      : Self recursive
1681  *****************************************************************************
1682 */
1683 static void toolbaritem2res(res_t *res, toolbar_item_t *tbitem)
1684 {
1685         toolbar_item_t *itm = tbitem;
1686         assert(win32 != 0);
1687         while(itm)
1688         {
1689                 put_word(res, itm->id);
1690                 itm = itm->next;
1691         }
1692
1693 }
1694
1695 /*
1696  *****************************************************************************
1697  * Function     : toolbar2res
1698  * Syntax       : res_t *toolbar2res(name_id_t *name, toolbar_t *toolbar)
1699  * Input        :
1700  *      name    - Name/ordinal of the resource
1701  *      toolbar - The toolbar descriptor
1702  * Output       : New .res format structure
1703  * Description  :
1704  * Remarks      :
1705  *****************************************************************************
1706 */
1707 static res_t *toolbar2res(name_id_t *name, toolbar_t *toolbar)
1708 {
1709         int restag;
1710         res_t *res;
1711         assert(name != NULL);
1712         assert(toolbar != NULL);
1713
1714         res = new_res();
1715         if(win32)
1716         {
1717                 restag = put_res_header(res, WRC_RT_TOOLBAR, NULL, name, toolbar->memopt, &(toolbar->lvc));
1718
1719                 put_word(res, 1);               /* Menuheader: Version */
1720                 put_word(res, toolbar->button_width); /* (in pixels?) */
1721                 put_word(res, toolbar->button_height); /* (in pixels?) */
1722                 put_word(res, toolbar->nitems);
1723                 put_pad(res);
1724                 toolbaritem2res(res, toolbar->items);
1725                 /* Set ResourceSize */
1726                 SetResSize(res, restag);
1727                 put_pad(res);
1728         }
1729         else /* win16 */
1730         {
1731                 /* Do not generate anything in 16-bit mode */
1732                 free(res->data);
1733                 free(res);
1734                 return NULL;
1735         }
1736         return res;
1737 }
1738
1739 /*
1740  *****************************************************************************
1741  * Function     : dlginit2res
1742  * Syntax       : res_t *dlginit2res(name_id_t *name, dlginit_t *dit)
1743  * Input        :
1744  *      name    - Name/ordinal of the resource
1745  *      rdt     - The dlginit descriptor
1746  * Output       : New .res format structure
1747  * Description  :
1748  * Remarks      :
1749  *****************************************************************************
1750 */
1751 static res_t *dlginit2res(name_id_t *name, dlginit_t *dit)
1752 {
1753         int restag;
1754         res_t *res;
1755         assert(name != NULL);
1756         assert(dit != NULL);
1757
1758         res = new_res();
1759         restag = put_res_header(res, WRC_RT_DLGINIT, NULL, name, dit->memopt, &(dit->data->lvc));
1760         put_raw_data(res, dit->data, 0);
1761         /* Set ResourceSize */
1762         SetResSize(res, restag);
1763         if(win32)
1764                 put_pad(res);
1765         return res;
1766 }
1767
1768 /*
1769  *****************************************************************************
1770  * Function     : prep_nid_for_label
1771  * Syntax       : char *prep_nid_for_label(const name_id_t *nid)
1772  * Input        :
1773  * Output       :
1774  * Description  : Converts a resource name into the first 32 (or less)
1775  *                characters of the name with conversions.
1776  * Remarks      :
1777  *****************************************************************************
1778 */
1779 #define MAXNAMELEN      32
1780 char *prep_nid_for_label(const name_id_t *nid)
1781 {
1782         static char buf[MAXNAMELEN+1];
1783
1784         assert(nid != NULL);
1785
1786         if(nid->type == name_str && nid->name.s_name->type == str_unicode)
1787         {
1788                 WCHAR *sptr;
1789                 int i;
1790                 sptr = nid->name.s_name->str.wstr;
1791                 buf[0] = '\0';
1792                 for(i = 0; *sptr && i < MAXNAMELEN; i++)
1793                 {
1794                         if((unsigned)*sptr < 0x80 && isprint(*sptr & 0xff))
1795                                 buf[i] = *sptr++;
1796                         else
1797                                 warning("Resourcename (str_unicode) contain unprintable characters or invalid translation, ignored\n");
1798                 }
1799                 buf[i] = '\0';
1800         }
1801         else if(nid->type == name_str && nid->name.s_name->type == str_char)
1802         {
1803                 char *cptr;
1804                 int i;
1805                 cptr = nid->name.s_name->str.cstr;
1806                 buf[0] = '\0';
1807                 for(i = 0; *cptr && i < MAXNAMELEN; i++)
1808                 {
1809                         if((unsigned)*cptr < 0x80 && isprint(*cptr & 0xff))
1810                                 buf[i] = *cptr++;
1811                         else
1812                                 warning("Resourcename (str_char) contain unprintable characters, ignored\n");
1813                 }
1814                 buf[i] = '\0';
1815         }
1816         else if(nid->type == name_ord)
1817         {
1818                 sprintf(buf, "%u", nid->name.i_name);
1819         }
1820         else
1821         {
1822                 internal_error(__FILE__, __LINE__, "Resource name_id with invalid type %d\n", nid->type);
1823         }
1824         return buf;
1825 }
1826 #undef MAXNAMELEN
1827
1828 /*
1829  *****************************************************************************
1830  * Function     : make_c_name
1831  * Syntax       : char *make_c_name(const char *base, const name_id_t *nid, const language_t *lan)
1832  * Input        :
1833  * Output       :
1834  * Description  : Converts a resource name into a valid c-identifier in the
1835  *                form "_base_nid".
1836  * Remarks      :
1837  *****************************************************************************
1838 */
1839 char *make_c_name(const char *base, const name_id_t *nid, const language_t *lan)
1840 {
1841         int nlen;
1842         char *buf;
1843         char *ret;
1844         char lanbuf[6];
1845
1846         sprintf(lanbuf, "%d", lan ? MAKELANGID(lan->id, lan->sub) : 0);
1847         buf = prep_nid_for_label(nid);
1848         nlen = strlen(buf) + strlen(lanbuf);
1849         nlen += strlen(base) + 4; /* three time '_' and '\0' */
1850         ret = xmalloc(nlen);
1851         strcpy(ret, "_");
1852         strcat(ret, base);
1853         strcat(ret, "_");
1854         strcat(ret, buf);
1855         strcat(ret, "_");
1856         strcat(ret, lanbuf);
1857         return ret;
1858 }
1859
1860 /*
1861  *****************************************************************************
1862  * Function     : get_c_typename
1863  * Syntax       : const char *get_c_typename(enum res_e type)
1864  * Input        :
1865  * Output       :
1866  * Description  : Convert resource enum to char string to be used in c-name
1867  *                creation.
1868  * Remarks      :
1869  *****************************************************************************
1870 */
1871 const char *get_c_typename(enum res_e type)
1872 {
1873         switch(type)
1874         {
1875         case res_acc:   return "Acc";
1876         case res_anicur:return "AniCur";
1877         case res_aniico:return "AniIco";
1878         case res_bmp:   return "Bmp";
1879         case res_cur:   return "Cur";
1880         case res_curg:  return "CurGrp";
1881         case res_dlg:
1882         case res_dlgex: return "Dlg";
1883         case res_fnt:   return "Fnt";
1884         case res_fntdir:return "FntDir";
1885         case res_ico:   return "Ico";
1886         case res_icog:  return "IcoGrp";
1887         case res_men:
1888         case res_menex: return "Men";
1889         case res_rdt:   return "RCDat";
1890         case res_stt:   return "StrTab";
1891         case res_usr:   return "Usr";
1892         case res_msg:   return "MsgTab";
1893         case res_ver:   return "VerInf";
1894         case res_toolbar:       return "TlBr";
1895         case res_dlginit: return "DlgInit";
1896         default:        return "Oops";
1897         }
1898 }
1899
1900 /*
1901  *****************************************************************************
1902  * Function     : resources2res
1903  * Syntax       : void resources2res(resource_t *top)
1904  * Input        :
1905  *      top     - The resource-tree to convert
1906  * Output       :
1907  * Description  : Convert logical resource descriptors into binary data
1908  * Remarks      :
1909  *****************************************************************************
1910 */
1911 void resources2res(resource_t *top)
1912 {
1913         while(top)
1914         {
1915                 switch(top->type)
1916                 {
1917                 case res_acc:
1918                         if(!top->binres)
1919                                 top->binres = accelerator2res(top->name, top->res.acc);
1920                         break;
1921                 case res_bmp:
1922                         if(!top->binres)
1923                                 top->binres = bitmap2res(top->name, top->res.bmp);
1924                         break;
1925                 case res_cur:
1926                         if(!top->binres)
1927                                 top->binres = cursor2res(top->res.cur);
1928                         break;
1929                 case res_curg:
1930                         if(!top->binres)
1931                                 top->binres = cursorgroup2res(top->name, top->res.curg);
1932                         break;
1933                 case res_dlg:
1934                         if(!top->binres)
1935                                 top->binres = dialog2res(top->name, top->res.dlg);
1936                         break;
1937                 case res_dlgex:
1938                         if(!top->binres)
1939                                 top->binres = dialogex2res(top->name, top->res.dlgex);
1940                         break;
1941                 case res_fnt:
1942                         if(!top->binres)
1943                                 top->binres = font2res(top->name, top->res.fnt);
1944                         break;
1945                 case res_fntdir:
1946                         if(!top->binres)
1947                                 top->binres = fontdir2res(top->name, top->res.fnd);
1948                         break;
1949                 case res_ico:
1950                         if(!top->binres)
1951                                 top->binres = icon2res(top->res.ico);
1952                         break;
1953                 case res_icog:
1954                         if(!top->binres)
1955                                 top->binres = icongroup2res(top->name, top->res.icog);
1956                         break;
1957                 case res_men:
1958                         if(!top->binres)
1959                                 top->binres = menu2res(top->name, top->res.men);
1960                         break;
1961                 case res_menex:
1962                         if(!top->binres)
1963                                 top->binres = menuex2res(top->name, top->res.menex);
1964                         break;
1965                 case res_html:
1966                         if(!top->binres)
1967                                 top->binres = html2res(top->name, top->res.html);
1968                         break;
1969                 case res_rdt:
1970                         if(!top->binres)
1971                                 top->binres = rcdata2res(top->name, top->res.rdt);
1972                         break;
1973                 case res_stt:
1974                         if(!top->binres)
1975                                 top->binres = stringtable2res(top->res.stt);
1976                         break;
1977                 case res_usr:
1978                         if(!top->binres)
1979                                 top->binres = user2res(top->name, top->res.usr);
1980                         break;
1981                 case res_msg:
1982                         if(!top->binres)
1983                                 top->binres = messagetable2res(top->name, top->res.msg);
1984                         break;
1985                 case res_ver:
1986                         if(!top->binres)
1987                                 top->binres = versioninfo2res(top->name, top->res.ver);
1988                         break;
1989                 case res_toolbar:
1990                         if(!top->binres)
1991                                 top->binres = toolbar2res(top->name, top->res.tbt);
1992                         break;
1993                 case res_dlginit:
1994                         if(!top->binres)
1995                             top->binres = dlginit2res(top->name, top->res.dlgi);
1996                         break;
1997                 case res_anicur:
1998                 case res_aniico:
1999                         if(!top->binres)
2000                             top->binres = anicurico2res(top->name, top->res.ani, top->type);
2001                         break;
2002                 default:
2003                         internal_error(__FILE__, __LINE__, "Unknown resource type encountered %d in binary res generation\n", top->type);
2004                 }
2005                 top->c_name = make_c_name(get_c_typename(top->type), top->name, top->lan);
2006                 top = top->next;
2007         }
2008 }