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