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