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