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