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