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