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