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

Last change on this file since 906 was 906, checked in by bird, 26 years ago

A quick and dirty fix to make wrc produce alp compatible assembly code.

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