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