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