source: trunk/tools/wrc/writeres.c

Last change on this file was 21589, checked in by dmik, 14 years ago

tools/wrc: Restored generating GAS output by default. MASM output is now generated by specifying the -M option.

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