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