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