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