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