source: trunk/tools/wrc/writeres.c@ 3426

Last change on this file since 3426 was 3426, checked in by sandervl, 25 years ago

update with latest wine code

File size: 31.0 KB
Line 
1/*
2 * Write .res, .s and .h file(s) from a resource-tree
3 *
4 * Copyright 1998 Bertho A. Stultiens
5 *
6 */
7
8#include "config.h"
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <assert.h>
14#include <time.h>
15
16#include "wrc.h"
17#include "writeres.h"
18#include "genres.h"
19#include "newstruc.h"
20#include "utils.h"
21
22#ifdef NEED_UNDERSCORE_PREFIX
23char Underscore[] = "_";
24#else
25char Underscore[] = "";
26#endif
27
28#define MASM 1
29#ifdef MASM
30 #define DIRECTIVE_BYTE "db"
31 #define DIRECTIVE_WORD "dw"
32 #define DIRECTIVE_LONG "dd"
33 #define DIRECTIVE_ALIGN "align"
34 #define DIRECTIVE_GLOBAL "public"
35 #define LOCAL_PREFIX ""
36 #define LONGFRMT "0%08lxh"
37 #define SHORTFRMT "0%04xh"
38 #define BYTEFRMT "0%02xh"
39 #define HEXBIT31 "80000000h"
40 #define COMMENT_LINE ";"
41 #define OR "or"
42char s_file_head_str[] =
43 ";/* This file is generated with wrc version " WRC_FULLVERSION ". Do not edit! */\n"
44 ";/* Source : %s */\n"
45 ";/* Cmdline: %s */\n"
46 ";/* Date : %s */\n"
47 "\n"
48 "\t.386p\n"
49 "\t.model flat\n"
50 "\t.data\n"
51 "\n"
52 ;
53
54char s_file_tail_str[] =
55 "\tend\n"
56 ";/* <eof> */\n"
57 "\n"
58 ;
59
60#else
61 #define DIRECTIVE_BYTE ".byte"
62 #define DIRECTIVE_WORD ".word"
63 #define DIRECTIVE_LONG ".long"
64 #define DIRECTIVE_ALIGN ".align"
65 #define DIRECTIVE_GLOBAL ".globl"
66 #define LOCAL_PREFIX "."
67 #define LONGFRMT "0x%08lx"
68 #define SHORTFRMT "0x%04x"
69 #define BYTEFRMT "0x%02x"
70 #define HEXBIT31 "0x80000000"
71 #define COMMENT_LINE
72 #define OR "|"
73
74char s_file_head_str[] =
75 "/* This file is generated with wrc version " WRC_FULLVERSION ". Do not edit! */\n"
76 "/* Source : %s */\n"
77 "/* Cmdline: %s */\n"
78 "/* Date : %s */\n"
79 "\n"
80 "\t.data\n"
81 "\n"
82 ;
83
84char s_file_tail_str[] =
85 "/* <eof> */\n"
86 "\n"
87 ;
88
89#endif
90
91char s_file_autoreg_str[] =
92 "\t.text\n"
93 ".LAuto_Register:\n"
94 "\tpushl\t$%s%s\n"
95#ifdef NEED_UNDERSCORE_PREFIX
96 "\tcall\t_LIBRES_RegisterResources\n"
97#else
98 "\tcall\tLIBRES_RegisterResources\n"
99#endif
100 "\taddl\t$4,%%esp\n"
101 "\tret\n\n"
102#ifdef __NetBSD__
103 ".stabs \"___CTOR_LIST__\",22,0,0,.LAuto_Register\n\n"
104#else
105 "\t.section .ctors,\"aw\"\n"
106 "\t.long\t.LAuto_Register\n\n"
107#endif
108 ;
109
110char h_file_head_str[] =
111 "/*\n"
112 " * This file is generated with wrc version " WRC_FULLVERSION ". Do not edit!\n"
113 " * Source : %s\n"
114 " * Cmdline: %s\n"
115 " * Date : %s"
116 " */\n"
117 "\n"
118 "#ifndef __%08lx_H\n" /* This becomes the date of compile */
119 "#define __%08lx_H\n"
120 "\n"
121 "#include <wrc_rsc.h>\n"
122 "\n"
123 ;
124
125char h_file_tail_str[] =
126 "#endif\n"
127 "/* <eof> */\n\n"
128 ;
129
130char _NEResTab[] = "_NEResTab";
131char _PEResTab[] = "_PEResTab";
132char _ResTable[] = "_ResTable";
133
134/* Variables used for resource sorting */
135res_count_t *rcarray = NULL; /* Type-level count array */
136int rccount = 0; /* Nr of entries in the type-level array */
137int n_id_entries = 0; /* win32 only: Nr of unique ids in the type-level array */
138int n_name_entries = 0; /* win32 only: Nr of unique namess in the type-level array */
139
140static int direntries; /* win32 only: Total number of unique resources */
141
142time_t now;
143
144/*
145 *****************************************************************************
146 * Function : write_resfile
147 * Syntax : void write_resfile(char *outname, resource_t *top)
148 * Input :
149 * outname - Filename to write to
150 * top - The resource-tree to convert
151 * Output :
152 * Description :
153 * Remarks :
154 *****************************************************************************
155*/
156void write_resfile(char *outname, resource_t *top)
157{
158 FILE *fo;
159 int ret;
160 char zeros[3] = {0, 0, 0};
161
162 fo = fopen(outname, "wb");
163 if(!fo)
164 {
165 error("Could not open %s\n", outname);
166 }
167
168 if(win32)
169 {
170 /* Put an empty resource first to signal win32 format */
171 res_t *res = new_res();
172 put_dword(res, 0); /* ResSize */
173 put_dword(res, 0x00000020); /* HeaderSize */
174 put_word(res, 0xffff); /* ResType */
175 put_word(res, 0);
176 put_word(res, 0xffff); /* ResName */
177 put_word(res, 0);
178 put_dword(res, 0); /* DataVersion */
179 put_word(res, 0); /* Memory options */
180 put_word(res, 0); /* Language */
181 put_dword(res, 0); /* Version */
182 put_dword(res, 0); /* Charateristics */
183 ret = fwrite(res->data, 1, res->size, fo);
184 if(ret != res->size)
185 {
186 fclose(fo);
187 error("Error writing %s", outname);
188 }
189 free(res);
190 }
191
192 for(; top; top = top->next)
193 {
194 if(!top->binres)
195 continue;
196
197 ret = fwrite(top->binres->data, 1, top->binres->size, fo);
198 if(ret != top->binres->size)
199 {
200 fclose(fo);
201 error("Error writing %s", outname);
202 }
203 if(win32 && (top->binres->size & 0x03))
204 {
205 /* Write padding */
206 ret = fwrite(zeros, 1, 4 - (top->binres->size & 0x03), fo);
207 if(ret != 4 - (top->binres->size & 0x03))
208 {
209 fclose(fo);
210 error("Error writing %s", outname);
211 }
212 }
213 }
214 fclose(fo);
215}
216
217/*
218 *****************************************************************************
219 * Function : write_s_res
220 * Syntax : void write_s_res(FILE *fp, res_t *res)
221 * Input :
222 * Output :
223 * Description :
224 * Remarks :
225 *****************************************************************************
226*/
227#define BYTESPERLINE 8
228void write_s_res(FILE *fp, res_t *res)
229{
230 int idx = res->dataidx;
231 int end = res->size;
232 int rest = (end - idx) % BYTESPERLINE;
233 int lines = (end - idx) / BYTESPERLINE;
234 int i, j;
235
236 for(i = 0 ; i < lines; i++)
237 {
238 fprintf(fp, "\t%s\t", DIRECTIVE_BYTE);
239 for(j = 0; j < BYTESPERLINE; j++, idx++)
240 {
241 fprintf(fp, BYTEFRMT"%s", res->data[idx] & 0xff,
242 j == BYTESPERLINE-1 ? "" : ", ");
243 }
244 fprintf(fp, "\n");
245 }
246 if(rest)
247 {
248 fprintf(fp, "\t%s\t", DIRECTIVE_BYTE);
249 for(j = 0; j < rest; j++, idx++)
250 {
251 fprintf(fp, BYTEFRMT"%s", res->data[idx] & 0xff,
252 j == rest-1 ? "" : ", ");
253 }
254 fprintf(fp, "\n");
255 }
256}
257
258/*
259 *****************************************************************************
260 * Function : write_name_str
261 * Syntax : void write_name_str(FILE *fp, name_id_t *nid)
262 * Input :
263 * Output :
264 * Description :
265 * Remarks : One level self recursive for string type conversion
266 *****************************************************************************
267*/
268void write_name_str(FILE *fp, name_id_t *nid)
269{
270 res_t res;
271 assert(nid->type == name_str);
272
273 if(!win32 && nid->name.s_name->type == str_char)
274 {
275 res.size = strlen(nid->name.s_name->str.cstr);
276 if(res.size > 254)
277 error("Can't write strings larger than 254 bytes");
278 if(res.size == 0)
279 internal_error(__FILE__, __LINE__, "Attempt to write empty string");
280 res.dataidx = 0;
281 res.data = (char *)xmalloc(res.size + 1);
282 res.data[0] = (char)res.size;
283 res.size++; /* We need to write the lenth byte as well */
284 strcpy(res.data+1, nid->name.s_name->str.cstr);
285 write_s_res(fp, &res);
286 free(res.data);
287 }
288 else if(!win32 && nid->name.s_name->type == str_unicode)
289 {
290 name_id_t lnid;
291 string_t str;
292
293 lnid.type = name_str;
294 lnid.name.s_name = &str;
295 str.type = str_char;
296 str.str.cstr = dupwstr2cstr(nid->name.s_name->str.wstr);
297 write_name_str(fp, &lnid);
298 free(str.str.cstr);
299 }
300 else if(win32 && nid->name.s_name->type == str_char)
301 {
302 name_id_t lnid;
303 string_t str;
304
305 lnid.type = name_str;
306 lnid.name.s_name = &str;
307 str.type = str_unicode;
308 str.str.wstr = dupcstr2wstr(nid->name.s_name->str.cstr);
309 write_name_str(fp, &lnid);
310 free(str.str.wstr);
311 }
312 else if(win32 && nid->name.s_name->type == str_unicode)
313 {
314 res.size = wstrlen(nid->name.s_name->str.wstr);
315 if(res.size > 65534)
316 error("Can't write strings larger than 65534 bytes");
317 if(res.size == 0)
318 internal_error(__FILE__, __LINE__, "Attempt to write empty string");
319 res.dataidx = 0;
320 res.data = (char *)xmalloc((res.size + 1) * 2);
321 ((short *)res.data)[0] = (short)res.size;
322 wstrcpy((short *)(res.data+2), nid->name.s_name->str.wstr);
323 res.size *= 2; /* Function writes bytes, not shorts... */
324 res.size += 2; /* We need to write the length word as well */
325 write_s_res(fp, &res);
326 free(res.data);
327 }
328 else
329 {
330 internal_error(__FILE__, __LINE__, "Hmm, requested to write a string of unknown type %d",
331 nid->name.s_name->type);
332 }
333}
334
335/*
336 *****************************************************************************
337 * Function : compare_name_id
338 * Syntax : int compare_name_id(name_id_t *n1, name_id_t *n2)
339 * Input :
340 * Output :
341 * Description :
342 * Remarks :
343 *****************************************************************************
344*/
345int compare_name_id(name_id_t *n1, name_id_t *n2)
346{
347 if(n1->type == name_ord && n2->type == name_ord)
348 {
349 return n1->name.i_name - n2->name.i_name;
350 }
351 else if(n1->type == name_str && n2->type == name_str)
352 {
353 if(n1->name.s_name->type == str_char
354 && n2->name.s_name->type == str_char)
355 {
356 return strcasecmp(n1->name.s_name->str.cstr, n2->name.s_name->str.cstr);
357 }
358 else if(n1->name.s_name->type == str_unicode
359 && n2->name.s_name->type == str_unicode)
360 {
361 return wstricmp(n1->name.s_name->str.wstr, n2->name.s_name->str.wstr);
362 }
363 else
364 {
365 internal_error(__FILE__, __LINE__, "Can't yet compare strings of mixed type");
366 }
367 }
368 else if(n1->type == name_ord && n2->type == name_str)
369 return 1;
370 else if(n1->type == name_str && n2->type == name_ord)
371 return -1;
372 else
373 internal_error(__FILE__, __LINE__, "Comparing name-ids with unknown types (%d, %d)",
374 n1->type, n2->type);
375
376 return 0; /* Keep the compiler happy */
377}
378
379/*
380 *****************************************************************************
381 * Function : find_counter
382 * Syntax : res_count_t *find_counter(name_id_t *type)
383 * Input :
384 * Output :
385 * Description :
386 * Remarks :
387 *****************************************************************************
388*/
389res_count_t *find_counter(name_id_t *type)
390{
391 int i;
392 for(i = 0; i < rccount; i++)
393 {
394 if(!compare_name_id(type, &(rcarray[i].type)))
395 return &rcarray[i];
396 }
397 return NULL;
398}
399
400/*
401 *****************************************************************************
402 * Function : count_resources
403 * Syntax : res_count_t *count_resources(resource_t *top)
404 * Input :
405 * Output :
406 * Description :
407 * Remarks : The whole lot is converted into arrays because they are
408 * easy sortable. Makes the lot almost unreadable, but it
409 * works (I hope). Basically you have to keep in mind that
410 * the lot is a three-dimensional structure for win32 and a
411 * two-dimensional structure for win16.
412 *****************************************************************************
413*/
414#define RCT(v) (*((resource_t **)(v)))
415/* qsort sorting function */
416int sort_name_id(const void *e1, const void *e2)
417{
418 return compare_name_id(RCT(e1)->name, RCT(e2)->name);
419}
420
421int sort_language(const void *e1, const void *e2)
422{
423 assert((RCT(e1)->lan) != NULL);
424 assert((RCT(e2)->lan) != NULL);
425
426 return MAKELANGID(RCT(e1)->lan->id, RCT(e1)->lan->sub)
427 - MAKELANGID(RCT(e2)->lan->id, RCT(e2)->lan->sub);
428}
429#undef RCT
430#define RCT(v) ((res_count_t *)(v))
431int sort_type(const void *e1, const void *e2)
432{
433 return compare_name_id(&(RCT(e1)->type), &(RCT(e2)->type));
434}
435#undef RCT
436
437void count_resources(resource_t *top)
438{
439 resource_t *rsc;
440 res_count_t *rcp;
441 name_id_t nid;
442 int i, j;
443
444 for(rsc = top; rsc; rsc = rsc->next)
445 {
446 if(!rsc->binres)
447 continue;
448 switch(rsc->type)
449 {
450 case res_dlgex:
451 nid.name.i_name = WRC_RT_DIALOG;
452 nid.type = name_ord;
453 break;
454 case res_menex:
455 nid.name.i_name = WRC_RT_MENU;
456 nid.type = name_ord;
457 break;
458 case res_usr:
459 nid = *(rsc->res.usr->type);
460 break;
461 default:
462 nid.name.i_name = rsc->type;
463 nid.type = name_ord;
464 }
465
466 if((rcp = find_counter(&nid)) == NULL)
467 {
468 /* Count the number of uniq ids and names */
469
470 if(nid.type == name_ord)
471 n_id_entries++;
472 else
473 n_name_entries++;
474
475 if(!rcarray)
476 {
477 rcarray = (res_count_t *)xmalloc(sizeof(res_count_t));
478 rccount = 1;
479 rcarray[0].count = 1;
480 rcarray[0].type = nid;
481 rcarray[0].rscarray = (resource_t **)xmalloc(sizeof(resource_t *));
482 rcarray[0].rscarray[0] = rsc;
483 }
484 else
485 {
486 rccount++;
487 rcarray = (res_count_t *)xrealloc(rcarray, rccount * sizeof(res_count_t));
488 rcarray[rccount-1].count = 1;
489 rcarray[rccount-1].type = nid;
490 rcarray[rccount-1].rscarray = (resource_t **)xmalloc(sizeof(resource_t *));
491 rcarray[rccount-1].rscarray[0] = rsc;
492 }
493 }
494 else
495 {
496 rcp->count++;
497 rcp->rscarray = (resource_t **)xrealloc(rcp->rscarray, rcp->count * sizeof(resource_t *));
498 rcp->rscarray[rcp->count-1] = rsc;
499 }
500 }
501
502 if(!win32)
503 {
504 /* We're done, win16 requires no special sorting */
505 return;
506 }
507
508 /* We now have a unsorted list of types with an array of res_count_t
509 * in rcarray[0..rccount-1]. And we have names of one type in the
510 * rcarray[x].rsc[0..rcarray[x].count-1] arrays.
511 * The list needs to be sorted for win32's top level tree structure.
512 */
513
514 /* Sort the types */
515 if(rccount > 1)
516 qsort(rcarray, rccount, sizeof(rcarray[0]), sort_type);
517
518 /* Now sort the name-id arrays */
519 for(i = 0; i < rccount; i++)
520 {
521 if(rcarray[i].count > 1)
522 qsort(rcarray[i].rscarray, rcarray[i].count, sizeof(rcarray[0].rscarray[0]), sort_name_id);
523 }
524
525 /* Now split the name-id arrays into name/language
526 * subs. Don't look at the awfull expressions...
527 * We do this by taking the array elements out of rscarray and putting
528 * together a new array in rsc32array.
529 */
530 for(i = 0; i < rccount; i++)
531 {
532 res_count_t *rcap;
533
534 assert(rcarray[i].count >= 1);
535
536 /* rcap points to the current type we are dealing with */
537 rcap = &(rcarray[i]);
538
539 /* Insert the first name-id */
540 rcap->rsc32array = (res32_count_t *)xmalloc(sizeof(res32_count_t));
541 rcap->count32 = 1;
542 rcap->rsc32array[0].rsc = (resource_t **)xmalloc(sizeof(resource_t *));
543 rcap->rsc32array[0].count = 1;
544 rcap->rsc32array[0].rsc[0] = rcap->rscarray[0];
545 if(rcap->rscarray[0]->name->type == name_ord)
546 {
547 rcap->n_id_entries = 1;
548 rcap->n_name_entries = 0;
549 }
550 else
551 {
552 rcap->n_id_entries = 0;
553 rcap->n_name_entries = 1;
554 }
555
556 /* Now loop over the resting resources of the current type
557 * to find duplicate names (which should have different
558 * languages).
559 */
560 for(j = 1; j < rcap->count; j++)
561 {
562 res32_count_t *r32cp;
563
564 /* r32cp points to the current res32_count structure
565 * that holds the resource name we are processing.
566 */
567 r32cp = &(rcap->rsc32array[rcap->count32-1]);
568
569 if(!compare_name_id(r32cp->rsc[0]->name, rcarray[i].rscarray[j]->name))
570 {
571 /* Names are the same, add to list */
572 r32cp->count++;
573 r32cp->rsc = (resource_t **)xrealloc(r32cp->rsc, r32cp->count * sizeof(resource_t *));
574 r32cp->rsc[r32cp->count-1] = rcap->rscarray[j];
575 }
576 else
577 {
578 /* New name-id, sort the old one by
579 * language and create new list
580 */
581 if(r32cp->count > 1)
582 qsort(r32cp->rsc, r32cp->count, sizeof(r32cp->rsc[0]), sort_language);
583 rcap->count32++;
584 rcap->rsc32array = (res32_count_t*)xrealloc(rcap->rsc32array, rcap->count32 * sizeof(res32_count_t));
585 rcap->rsc32array[rcap->count32-1].rsc = (resource_t **)xmalloc(sizeof(resource_t *));
586 rcap->rsc32array[rcap->count32-1].count = 1;
587 rcap->rsc32array[rcap->count32-1].rsc[0] = rcap->rscarray[j];
588
589 if(rcap->rscarray[j]->name->type == name_ord)
590 rcap->n_id_entries++;
591 else
592 rcap->n_name_entries++;
593 }
594 }
595 /* Also sort the languages of the last name group */
596 if(rcap->rsc32array[rcap->count32-1].count > 1)
597 qsort(rcap->rsc32array[rcap->count32-1].rsc,
598 rcap->rsc32array[rcap->count32-1].count,
599 sizeof(rcap->rsc32array[rcap->count32-1].rsc[0]),
600 sort_language);
601 }
602}
603
604/*
605 *****************************************************************************
606 * Function : write_pe_segment
607 * Syntax : void write_pe_segment(FILE *fp, resource_t *top)
608 * Input :
609 * Output :
610 * Description :
611 * Remarks :
612 *****************************************************************************
613*/
614void write_pe_segment(FILE *fp, resource_t *top)
615{
616 int i;
617
618 fprintf(fp, "\t%s\t4\n", DIRECTIVE_ALIGN);
619 fprintf(fp, "%s%s:\n", prefix, _PEResTab);
620 fprintf(fp, "\t%s\t%s%s\n", DIRECTIVE_GLOBAL, prefix, _PEResTab);
621 /* Flags */
622 fprintf(fp, "\t%s\t0\n", DIRECTIVE_LONG);
623 /* Time/Date stamp */
624 fprintf(fp, "\t%s\t"LONGFRMT"\n", DIRECTIVE_LONG, (long)now);
625 /* Version */
626 fprintf(fp, "\t%s\t0\n", DIRECTIVE_LONG); /* FIXME: must version be filled out? */
627 /* # of id entries, # of name entries */
628 fprintf(fp, "\t%s\t%d, %d\n", DIRECTIVE_WORD, n_name_entries, n_id_entries);
629
630 /* Write the type level of the tree */
631 for(i = 0; i < rccount; i++)
632 {
633 res_count_t *rcp;
634 char *label;
635
636 rcp = &rcarray[i];
637
638 /* TypeId */
639 if(rcp->type.type == name_ord)
640 fprintf(fp, "\t%s\t%d\n", DIRECTIVE_LONG, rcp->type.name.i_name);
641 else
642 {
643 char *name = prep_nid_for_label(&(rcp->type));
644 fprintf(fp, "\t%s\t(%s_%s_typename - %s%s) %s %s\n",
645 DIRECTIVE_LONG, prefix,
646 name,
647 prefix,
648 _PEResTab, OR, HEXBIT31);
649 }
650 /* Offset */
651 label = prep_nid_for_label(&(rcp->type));
652 fprintf(fp, "\t%s\t(%sL%s - %s%s) %s %s\n",
653 DIRECTIVE_LONG, LOCAL_PREFIX, label,
654 prefix,
655 _PEResTab, OR, HEXBIT31);
656 }
657
658 /* Write the name level of the tree */
659
660 for(i = 0; i < rccount; i++)
661 {
662 res_count_t *rcp;
663 char *typelabel;
664 char *namelabel;
665 int j;
666
667 rcp = &rcarray[i];
668
669 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
670 fprintf(fp, "%sL%s:\n", LOCAL_PREFIX, typelabel);
671
672 fprintf(fp, "\t%s\t0\n", DIRECTIVE_LONG); /* Flags */
673 fprintf(fp, "\t%s\t"LONGFRMT"\n", DIRECTIVE_LONG, (long)now); /* TimeDate */
674 fprintf(fp, "\t%s\t0\n", DIRECTIVE_LONG); /* FIXME: must version be filled out? */
675 fprintf(fp, "\t%s\t%d, %d\n", DIRECTIVE_WORD, rcp->n_name_entries, rcp->n_id_entries);
676 for(j = 0; j < rcp->count32; j++)
677 {
678 resource_t *rsc = rcp->rsc32array[j].rsc[0];
679 /* NameId */
680 if(rsc->name->type == name_ord)
681 fprintf(fp, "\t%s\t%d\n", DIRECTIVE_LONG, rsc->name->name.i_name);
682 else
683 {
684 fprintf(fp, "\t%s\t(%s%s_name - %s%s) %s %s\n",
685 DIRECTIVE_LONG, prefix,
686 rsc->c_name,
687 prefix,
688 _PEResTab, OR, HEXBIT31);
689 }
690 /* Maybe FIXME: Unescape the tree (ommit 0x80000000) and
691 * put the offset to the resource data entry.
692 * ?? Is unescaping worth while ??
693 */
694 /* Offset */
695 namelabel = prep_nid_for_label(rsc->name);
696 fprintf(fp, "\t%s\t(%sL%s_%s - %s%s) %s %s\n",
697 DIRECTIVE_LONG, LOCAL_PREFIX, typelabel,
698 namelabel,
699 prefix,
700 _PEResTab, OR, HEXBIT31);
701 }
702 free(typelabel);
703 }
704
705 /* Write the language level of the tree */
706
707 for(i = 0; i < rccount; i++)
708 {
709 res_count_t *rcp;
710 char *namelabel;
711 char *typelabel;
712 int j;
713
714 rcp = &rcarray[i];
715 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
716
717 for(j = 0; j < rcp->count32; j++)
718 {
719 res32_count_t *r32cp = &(rcp->rsc32array[j]);
720 int k;
721
722 namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
723 fprintf(fp, "%sL%s_%s:\n", LOCAL_PREFIX, typelabel, namelabel);
724
725 fprintf(fp, "\t%s\t0\n", DIRECTIVE_LONG); /* Flags */
726 fprintf(fp, "\t%s\t"LONGFRMT"\n", DIRECTIVE_LONG, (long)now); /* TimeDate */
727 fprintf(fp, "\t%s\t0\n", DIRECTIVE_LONG); /* FIXME: must version be filled out? */
728 fprintf(fp, "\t%s\t0, %d\n", DIRECTIVE_WORD, r32cp->count);
729
730 for(k = 0; k < r32cp->count; k++)
731 {
732 resource_t *rsc = r32cp->rsc[k];
733 assert(rsc->lan != NULL);
734 /* LanguageId */
735 fprintf(fp, "\t%s\t"LONGFRMT"\n", DIRECTIVE_LONG, rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
736 /* Offset */
737 fprintf(fp, "\t%s\t%sL%s_%s_%d - %s%s\n",
738 DIRECTIVE_LONG, LOCAL_PREFIX, typelabel,
739 namelabel,
740 rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0,
741 prefix,
742 _PEResTab);
743 }
744 free(namelabel);
745 }
746 free(typelabel);
747 }
748
749 /* Write the resource table itself */
750 fprintf(fp, "%s_ResourceDirectory:\n", prefix);
751 fprintf(fp, "\t%s\t%s_ResourceDirectory\n", DIRECTIVE_GLOBAL, prefix);
752 direntries = 0;
753
754 for(i = 0; i < rccount; i++)
755 {
756 res_count_t *rcp;
757 char *namelabel;
758 char *typelabel;
759 int j;
760
761 rcp = &rcarray[i];
762 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
763
764 for(j = 0; j < rcp->count32; j++)
765 {
766 res32_count_t *r32cp = &(rcp->rsc32array[j]);
767 int k;
768
769 namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
770
771 for(k = 0; k < r32cp->count; k++)
772 {
773 resource_t *rsc = r32cp->rsc[k];
774
775 assert(rsc->lan != NULL);
776
777 fprintf(fp, "%sL%s_%s_%d:\n",
778 LOCAL_PREFIX, typelabel,
779 namelabel,
780 rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
781
782 /* Data RVA */
783 fprintf(fp, "\t%s\t%s%s_data - %s%s\n",
784 DIRECTIVE_LONG, prefix,
785 rsc->c_name,
786 prefix,
787 _PEResTab);
788 /* Size */
789 fprintf(fp, "\t%s\t%d\n",
790 DIRECTIVE_LONG, rsc->binres->size - rsc->binres->dataidx);
791 /* CodePage */
792 fprintf(fp, "\t%s\t%ld\n", DIRECTIVE_LONG, codepage);
793 /* Reserved */
794 fprintf(fp, "\t%s\t0\n", DIRECTIVE_LONG);
795
796 direntries++;
797 }
798 free(namelabel);
799 }
800 free(typelabel);
801 }
802}
803
804/*
805 *****************************************************************************
806 * Function : write_ne_segment
807 * Syntax : void write_ne_segment(FILE *fp, resource_t *top)
808 * Input :
809 * Output :
810 * Description :
811 * Remarks :
812 *****************************************************************************
813*/
814void write_ne_segment(FILE *fp, resource_t *top)
815{
816 int i, j;
817
818 fprintf(fp, "\t%s\t4\n", DIRECTIVE_ALIGN);
819 fprintf(fp, "%s%s:\n", prefix, _NEResTab);
820 fprintf(fp, "\t%s\t%s%s\n", DIRECTIVE_GLOBAL, prefix, _NEResTab);
821
822 /* AlignmentShift */
823 fprintf(fp, "\t%s\t%d\n", DIRECTIVE_WORD, alignment_pwr);
824
825 /* TypeInfo */
826 for(i = 0; i < rccount; i++)
827 {
828 res_count_t *rcp = &rcarray[i];
829
830 /* TypeId */
831 if(rcp->type.type == name_ord)
832 fprintf(fp, "\t%s\t"SHORTFRMT"\n", DIRECTIVE_WORD, rcp->type.name.i_name | 0x8000);
833 else
834 fprintf(fp, "\t%s\t%s_%s_typename - %s%s\n",
835 DIRECTIVE_WORD, prefix,
836 rcp->type.name.s_name->str.cstr,
837 prefix,
838 _NEResTab);
839 /* ResourceCount */
840 fprintf(fp, "\t%s\t%d\n", DIRECTIVE_WORD, rcp->count);
841 /* Reserved */
842 fprintf(fp, "\t%s\t0\n", DIRECTIVE_LONG);
843 /* NameInfo */
844 for(j = 0; j < rcp->count; j++)
845 {
846/*
847 * VERY IMPORTANT:
848 * The offset is relative to the beginning of the NE resource segment
849 * and _NOT_ to the file-beginning. This is because we do not have a
850 * file based resource, but a simulated NE segment. The offset _is_
851 * scaled by the AlignShift field.
852 * All other things are as the MS doc describes (alignment etc.)
853 */
854 /* Offset */
855 fprintf(fp, "\t%s\t(%s%s_data - %s%s) >> %d\n",
856 DIRECTIVE_WORD, prefix,
857 rcp->rscarray[j]->c_name,
858 prefix,
859 _NEResTab,
860 alignment_pwr);
861 /* Length */
862 fprintf(fp, "\t%s\t%d\n",
863 DIRECTIVE_WORD, rcp->rscarray[j]->binres->size - rcp->rscarray[j]->binres->dataidx);
864 /* Flags */
865 fprintf(fp, "\t%s\t"SHORTFRMT"\n", DIRECTIVE_WORD, (WORD)rcp->rscarray[j]->memopt);
866 /* Id */
867 if(rcp->rscarray[j]->name->type == name_ord)
868 fprintf(fp, "\t%s\t"SHORTFRMT"\n", DIRECTIVE_WORD, rcp->rscarray[j]->name->name.i_name | 0x8000);
869 else
870 fprintf(fp, "\t%s\t%s%s_name - %s%s\n",
871 DIRECTIVE_WORD, prefix,
872 rcp->rscarray[j]->c_name,
873 prefix,
874 _NEResTab);
875 /* Handle and Usage */
876 fprintf(fp, "\t%s\t0, 0\n", DIRECTIVE_WORD);
877 }
878 }
879 /* EndTypes */
880 fprintf(fp, "\t%s\t0\n", DIRECTIVE_WORD);
881}
882
883/*
884 *****************************************************************************
885 * Function : write_rsc_names
886 * Syntax : void write_rsc_names(FILE *fp, resource_t *top)
887 * Input :
888 * Output :
889 * Description :
890 * Remarks :
891 *****************************************************************************
892*/
893void write_rsc_names(FILE *fp, resource_t *top)
894{
895 int i, j;
896
897 if(win32)
898 {
899 /* Write the names */
900
901 for(i = 0; i < rccount; i++)
902 {
903 res_count_t *rcp;
904
905 rcp = &rcarray[i];
906
907 if(rcp->type.type == name_str)
908 {
909 char *name = prep_nid_for_label(&(rcp->type));
910 fprintf(fp, "%s_%s_typename:\n",
911 prefix,
912 name);
913 write_name_str(fp, &(rcp->type));
914 }
915
916 for(j = 0; j < rcp->count32; j++)
917 {
918 resource_t *rsc = rcp->rsc32array[j].rsc[0];
919
920 if(rsc->name->type == name_str)
921 {
922 fprintf(fp, "%s%s_name:\n",
923 prefix,
924 rsc->c_name);
925 write_name_str(fp, rsc->name);
926 }
927 }
928 }
929 }
930 else
931 {
932 /* ResourceNames */
933 for(i = 0; i < rccount; i++)
934 {
935 res_count_t *rcp = &rcarray[i];
936
937 for(j = 0; j < rcp->count; j++)
938 {
939 if(rcp->type.type == name_str)
940 {
941 fprintf(fp, "%s_%s_typename:\n",
942 prefix,
943 rcp->type.name.s_name->str.cstr);
944 write_name_str(fp, &(rcp->type));
945 }
946 if(rcp->rscarray[j]->name->type == name_str)
947 {
948 fprintf(fp, "%s%s_name:\n",
949 prefix,
950 rcp->rscarray[j]->c_name);
951 write_name_str(fp, rcp->rscarray[j]->name);
952 }
953 }
954 }
955 /* EndNames */
956
957 /* This is to end the NE resource table */
958 if(create_dir)
959 fprintf(fp, "\t%s\t0\n", DIRECTIVE_BYTE);
960 }
961
962 fprintf(fp, "\n");
963}
964
965/*
966 *****************************************************************************
967 * Function : write_s_file
968 * Syntax : void write_s_file(char *outname, resource_t *top)
969 * Input :
970 * outname - Filename to write to
971 * top - The resource-tree to convert
972 * Output :
973 * Description :
974 * Remarks :
975 *****************************************************************************
976*/
977void write_s_file(char *outname, resource_t *top)
978{
979 FILE *fo;
980 resource_t *rsc;
981
982 fo = fopen(outname, "wt");
983 if(!fo)
984 {
985 error("Could not open %s\n", outname);
986 return;
987 }
988
989 {
990 char *s, *p;
991 now = time(NULL);
992 s = ctime(&now);
993 p = strchr(s, '\n');
994 if(p) *p = '\0';
995 fprintf(fo, s_file_head_str, input_name ? input_name : "stdin",
996 cmdline, s);
997 }
998
999 /* Get an idea how many we have and restructure the tables */
1000 count_resources(top);
1001
1002 /* First write the segment tables */
1003 if(create_dir)
1004 {
1005 if(win32)
1006 write_pe_segment(fo, top);
1007 else
1008 write_ne_segment(fo, top);
1009 }
1010
1011 /* Dump the names */
1012 write_rsc_names(fo, top);
1013
1014 if(create_dir)
1015 fprintf(fo, "%sLResTabEnd:\n", LOCAL_PREFIX);
1016
1017 if(!indirect_only)
1018 {
1019 /* Write the resource data */
1020#ifdef MASM
1021 fprintf(fo, "\n;/* Resource binary data */\n\n");
1022#else
1023 fprintf(fo, "\n/* Resource binary data */\n\n");
1024#endif
1025 for(rsc = top; rsc; rsc = rsc->next)
1026 {
1027 if(!rsc->binres)
1028 continue;
1029
1030 fprintf(fo, "\t%s\t%d\n", DIRECTIVE_ALIGN, win32 ? 4 : alignment);
1031 fprintf(fo, "%s%s_data:\n", prefix, rsc->c_name);
1032 if(global)
1033 fprintf(fo, "\t%s\t%s%s_data\n", DIRECTIVE_GLOBAL, prefix, rsc->c_name);
1034
1035 write_s_res(fo, rsc->binres);
1036
1037 fprintf(fo, "\n");
1038 }
1039
1040 if(create_dir)
1041 {
1042 /* Add a resource descriptor for built-in and elf-dlls */
1043 fprintf(fo, "\t%s\t4\n", DIRECTIVE_ALIGN);
1044 fprintf(fo, "%s_ResourceDescriptor:\n", prefix);
1045 fprintf(fo, "\t%s\t%s_ResourceDescriptor\n", DIRECTIVE_GLOBAL, prefix);
1046 fprintf(fo, "%s_ResourceTable:\n", prefix);
1047 if(global)
1048 fprintf(fo, "\t%s\t%s_ResourceTable\n", DIRECTIVE_GLOBAL, prefix);
1049 fprintf(fo, "\t%s\t%s%s\n", DIRECTIVE_LONG, prefix, win32 ? _PEResTab : _NEResTab);
1050 fprintf(fo, "%s_NumberOfResources:\n", prefix);
1051 if(global)
1052 fprintf(fo, "\t%s\t%s_NumberOfResources\n", DIRECTIVE_GLOBAL, prefix);
1053 fprintf(fo, "\t%s\t%d\n", DIRECTIVE_LONG, direntries);
1054 fprintf(fo, "%s_ResourceSectionSize:\n", prefix);
1055 if(global)
1056 fprintf(fo, "\t%s\t%s_ResourceSectionSize\n", DIRECTIVE_GLOBAL, prefix);
1057 fprintf(fo, "\t%s\t%sLResTabEnd - %s%s\n", DIRECTIVE_LONG, LOCAL_PREFIX, prefix, win32 ? _PEResTab : _NEResTab);
1058 if(win32)
1059 {
1060 fprintf(fo, "%s_ResourcesEntries:\n", prefix);
1061 if(global)
1062 fprintf(fo, "\t%s\t%s_ResourcesEntries\n", DIRECTIVE_GLOBAL, prefix);
1063 fprintf(fo, "\t%s\t%s_ResourceDirectory\n", DIRECTIVE_LONG, prefix);
1064 }
1065 }
1066 }
1067
1068 if(indirect)
1069 {
1070 /* Write the indirection structures */
1071 fprintf(fo, "\n/* Resource indirection structures */\n\n");
1072 fprintf(fo, "\t%s\t4\n", DIRECTIVE_ALIGN);
1073 for(rsc = top; rsc; rsc = rsc->next)
1074 {
1075 int type;
1076 char *type_name = NULL;
1077
1078 if(!rsc->binres)
1079 continue;
1080
1081 switch(rsc->type)
1082 {
1083 case res_menex:
1084 type = WRC_RT_MENU;
1085 break;
1086 case res_dlgex:
1087 type = WRC_RT_DIALOG;
1088 break;
1089 case res_usr:
1090 assert(rsc->res.usr->type != NULL);
1091 type_name = prep_nid_for_label(rsc->res.usr->type);
1092 type = 0;
1093 break;
1094 default:
1095 type = rsc->type;
1096 }
1097
1098 /*
1099 * This follows a structure like:
1100 * struct wrc_resource {
1101 * INT32 id;
1102 * RSCNAME *resname;
1103 * INT32 restype;
1104 * RSCNAME *typename;
1105 * void *data;
1106 * UINT32 datasize;
1107 * };
1108 * The 'RSCNAME' is a pascal-style string where the
1109 * first byte/word denotes the size and the rest the string
1110 * itself.
1111 */
1112 fprintf(fo, "%s%s:\n", prefix, rsc->c_name);
1113 if(global)
1114 fprintf(fo, "\t%s\t%s%s\n", DIRECTIVE_GLOBAL, prefix, rsc->c_name);
1115 fprintf(fo, "\t%s\t%d, %s%s%s, %d, %s%s%s%s, %s%s_data, %d\n",
1116 DIRECTIVE_LONG,
1117 rsc->name->type == name_ord ? rsc->name->name.i_name : 0,
1118 rsc->name->type == name_ord ? "0" : prefix,
1119 rsc->name->type == name_ord ? "" : rsc->c_name,
1120 rsc->name->type == name_ord ? "" : "_name",
1121 type,
1122 type ? "0" : prefix,
1123 type ? "" : "_",
1124 type ? "" : type_name,
1125 type ? "" : "_typename",
1126 prefix,
1127 rsc->c_name,
1128 rsc->binres->size - rsc->binres->dataidx);
1129 fprintf(fo, "\n");
1130 }
1131 fprintf(fo, "\n");
1132
1133 /* Write the indirection table */
1134 fprintf(fo, "/* Resource indirection table */\n\n");
1135 fprintf(fo, "\t%s\t4\n", DIRECTIVE_ALIGN);
1136 fprintf(fo, "%s%s:\n", prefix, _ResTable);
1137 fprintf(fo, "\t%s\t%s%s\n", DIRECTIVE_GLOBAL, prefix, _ResTable);
1138 for(rsc = top; rsc; rsc = rsc->next)
1139 {
1140 fprintf(fo, "\t%s\t%s%s\n", DIRECTIVE_LONG, prefix, rsc->c_name);
1141 }
1142 fprintf(fo, "\t%s\t0\n", DIRECTIVE_LONG);
1143 fprintf(fo, "\n");
1144 }
1145
1146 if(auto_register)
1147 fprintf(fo, s_file_autoreg_str, prefix, _ResTable);
1148
1149 fprintf(fo, s_file_tail_str);
1150 fclose(fo);
1151}
1152
1153/*
1154 *****************************************************************************
1155 * Function : write_h_file
1156 * Syntax : void write_h_file(char *outname, resource_t *top)
1157 * Input :
1158 * outname - Filename to write to
1159 * top - The resource-tree to convert
1160 * Output :
1161 * Description :
1162 * Remarks :
1163 *****************************************************************************
1164*/
1165void write_h_file(char *outname, resource_t *top)
1166{
1167 FILE *fo;
1168 resource_t *rsc;
1169 char *h_prefix;
1170
1171#ifdef NEED_UNDERSCORE_PREFIX
1172 h_prefix = prefix + 1;
1173#else
1174 h_prefix = prefix;
1175#endif
1176
1177 fo = fopen(outname, "wt");
1178 if(!fo)
1179 {
1180 error("Could not open %s\n", outname);
1181 }
1182
1183 time(&now);
1184 fprintf(fo, h_file_head_str, input_name ? input_name : "stdin",
1185 cmdline, ctime(&now), (long)now, (long)now);
1186
1187 /* First write the segment tables reference */
1188 if(create_dir)
1189 {
1190 fprintf(fo, "extern %schar %s%s[];\n\n",
1191 constant ? "const " : "",
1192 h_prefix,
1193 win32 ? _PEResTab : _NEResTab);
1194 }
1195
1196 /* Write the resource data */
1197 for(rsc = top; global && rsc; rsc = rsc->next)
1198 {
1199 if(!rsc->binres)
1200 continue;
1201
1202 fprintf(fo, "extern %schar %s%s_data[];\n",
1203 constant ? "const " : "",
1204 h_prefix,
1205 rsc->c_name);
1206 }
1207
1208 if(indirect)
1209 {
1210 if(global)
1211 fprintf(fo, "\n");
1212
1213 /* Write the indirection structures */
1214 for(rsc = top; global && rsc; rsc = rsc->next)
1215 {
1216 fprintf(fo, "extern %swrc_resource%d_t %s%s;\n",
1217 constant ? "const " : "",
1218 win32 ? 32 : 16,
1219 h_prefix,
1220 rsc->c_name);
1221 }
1222
1223 if(global)
1224 fprintf(fo, "\n");
1225
1226 /* Write the indirection table */
1227 fprintf(fo, "extern %swrc_resource%d_t %s%s[];\n\n",
1228 constant ? "const " : "",
1229 win32 ? 32 : 16,
1230 h_prefix,
1231 _ResTable);
1232 }
1233
1234 fprintf(fo, h_file_tail_str);
1235 fclose(fo);
1236}
1237
1238
Note: See TracBrowser for help on using the repository browser.