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

Last change on this file since 979 was 979, checked in by sandervl, 26 years ago

Resource name bugfix

File size: 37.5 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_%d_%s_name - %s%s) "OR" "HEXBIT31"\n",
685 prefix,
686 rsc->type,
687 label,
688 prefix,
689 _PEResTab);
690 }
691 /* Maybe FIXME: Unescape the tree (ommit 0x80000000) and
692 * put the offset to the resource data entry.
693 * ?? Is unescaping worth while ??
694 */
695 /* Offset */
696 namelabel = prep_nid_for_label(rsc->name);
697 fprintf(fp, "\t"DIRECTIVE_LONG"\t("LOCAL_PREFIX"L%s_%s - %s%s) "OR" "HEXBIT31"\n",
698 typelabel,
699 namelabel,
700 prefix,
701 _PEResTab);
702 }
703 free(typelabel);
704 }
705
706 /* Write the language level of the tree */
707
708 for(i = 0; i < rccount; i++)
709 {
710 res_count_t *rcp;
711 char *namelabel;
712 char *typelabel;
713 int j;
714
715 rcp = &rcarray[i];
716 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
717
718 for(j = 0; j < rcp->count32; j++)
719 {
720 res32_count_t *r32cp = &(rcp->rsc32array[j]);
721 int k;
722
723 namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
724 fprintf(fp, LOCAL_PREFIX"L%s_%s:\n", typelabel, namelabel);
725
726 fprintf(fp, "\t"DIRECTIVE_LONG"\t0\n"); /* Flags */
727 fprintf(fp, "\t"DIRECTIVE_LONG"\t"LONGFRMT"\n", (long)now); /* TimeDate */
728 fprintf(fp, "\t"DIRECTIVE_LONG"\t0\n"); /* FIXME: must version be filled out? */
729 fprintf(fp, "\t"DIRECTIVE_WORD"\t0, %d\n", r32cp->count);
730
731 for(k = 0; k < r32cp->count; k++)
732 {
733 resource_t *rsc = r32cp->rsc[k];
734 assert(rsc->lan != NULL);
735 /* LanguageId */
736 fprintf(fp, "\t"DIRECTIVE_LONG"\t"LONGFRMT"\n", rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
737 /* Offset */
738 fprintf(fp, "\t"DIRECTIVE_LONG"\t"LOCAL_PREFIX"L%s_%s_%d - %s%s\n",
739 typelabel,
740 namelabel,
741 rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0,
742 prefix,
743 _PEResTab);
744 }
745 free(namelabel);
746 }
747 free(typelabel);
748 }
749
750 /* Write the resource table itself */
751 fprintf(fp, "%s_ResourceDirectory:\n", prefix);
752 fprintf(fp, "\t"DIRECTIVE_GLOBAL"\t%s_ResourceDirectory\n", prefix);
753 direntries = 0;
754
755 for(i = 0; i < rccount; i++)
756 {
757 res_count_t *rcp;
758 char *namelabel;
759 char *typelabel;
760 int j;
761
762 rcp = &rcarray[i];
763 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
764
765 for(j = 0; j < rcp->count32; j++)
766 {
767 res32_count_t *r32cp = &(rcp->rsc32array[j]);
768 int k;
769
770 namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
771
772 for(k = 0; k < r32cp->count; k++)
773 {
774 resource_t *rsc = r32cp->rsc[k];
775
776 assert(rsc->lan != NULL);
777
778 fprintf(fp, LOCAL_PREFIX"L%s_%s_%d:\n",
779 typelabel,
780 namelabel,
781 rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
782
783 /* Data RVA */
784 fprintf(fp, "\t"DIRECTIVE_LONG"\t%s%s_data - %s%s\n",
785 prefix,
786 rsc->c_name,
787 prefix,
788 _PEResTab);
789 /* Size */
790 fprintf(fp, "\t"DIRECTIVE_LONG"\t%d\n",
791 rsc->binres->size - rsc->binres->dataidx);
792 /* CodePage */
793 fprintf(fp, "\t"DIRECTIVE_LONG"\t%ld\n", codepage);
794 /* Reserved */
795 fprintf(fp, "\t"DIRECTIVE_LONG"\t0\n");
796
797 direntries++;
798 }
799 free(namelabel);
800 }
801 free(typelabel);
802 }
803}
804
805/*
806 *****************************************************************************
807 * Function : write_ne_segment
808 * Syntax : void write_ne_segment(FILE *fp, resource_t *top)
809 * Input :
810 * Output :
811 * Description :
812 * Remarks :
813 *****************************************************************************
814*/
815void write_ne_segment(FILE *fp, resource_t *top)
816{
817 int i, j;
818
819 fprintf(fp, "\t"DIRECTIVE_ALIGN"\t4\n");
820 fprintf(fp, "%s%s:\n", prefix, _NEResTab);
821 fprintf(fp, "\t"DIRECTIVE_GLOBAL"\t%s%s\n", prefix, _NEResTab);
822
823 /* AlignmentShift */
824 fprintf(fp, "\t"DIRECTIVE_WORD"\t%d\n", alignment_pwr);
825
826 /* TypeInfo */
827 for(i = 0; i < rccount; i++)
828 {
829 res_count_t *rcp = &rcarray[i];
830
831 /* TypeId */
832 if(rcp->type.type == name_ord)
833 fprintf(fp, "\t"DIRECTIVE_WORD"\t"SHORTFRMT"\n", rcp->type.name.i_name | 0x8000);
834 else
835 fprintf(fp, "\t"DIRECTIVE_WORD"\t%s_%s_typename - %s%s\n",
836 prefix,
837 rcp->type.name.s_name->str.cstr,
838 prefix,
839 _NEResTab);
840 /* ResourceCount */
841 fprintf(fp, "\t"DIRECTIVE_WORD"\t%d\n", rcp->count);
842 /* Reserved */
843 fprintf(fp, "\t"DIRECTIVE_LONG"\t0\n");
844 /* NameInfo */
845 for(j = 0; j < rcp->count; j++)
846 {
847/*
848 * VERY IMPORTANT:
849 * The offset is relative to the beginning of the NE resource segment
850 * and _NOT_ to the file-beginning. This is because we do not have a
851 * file based resource, but a simulated NE segment. The offset _is_
852 * scaled by the AlignShift field.
853 * All other things are as the MS doc describes (alignment etc.)
854 */
855 /* Offset */
856 fprintf(fp, "\t"DIRECTIVE_WORD"\t(%s%s_data - %s%s) >> %d\n",
857 prefix,
858 rcp->rscarray[j]->c_name,
859 prefix,
860 _NEResTab,
861 alignment_pwr);
862 /* Length */
863 fprintf(fp, "\t"DIRECTIVE_WORD"\t%d\n",
864 rcp->rscarray[j]->binres->size - rcp->rscarray[j]->binres->dataidx);
865 /* Flags */
866 fprintf(fp, "\t"DIRECTIVE_WORD"\t"SHORTFRMT"\n", (WORD)rcp->rscarray[j]->memopt);
867 /* Id */
868 if(rcp->rscarray[j]->name->type == name_ord)
869 fprintf(fp, "\t"DIRECTIVE_WORD"\t"SHORTFRMT"\n", rcp->rscarray[j]->name->name.i_name | 0x8000);
870 else
871 fprintf(fp, "\t"DIRECTIVE_WORD"\t%s%s_name - %s%s\n",
872 prefix,
873 rcp->rscarray[j]->c_name,
874 prefix,
875 _NEResTab);
876 /* Handle and Usage */
877 fprintf(fp, "\t"DIRECTIVE_WORD"\t0, 0\n");
878 }
879 }
880 /* EndTypes */
881 fprintf(fp, "\t"DIRECTIVE_WORD"\t0\n");
882}
883
884/*
885 *****************************************************************************
886 * Function : write_rsc_names
887 * Syntax : void write_rsc_names(FILE *fp, resource_t *top)
888 * Input :
889 * Output :
890 * Description :
891 * Remarks :
892 *****************************************************************************
893*/
894void write_rsc_names(FILE *fp, resource_t *top)
895{
896 int i, j;
897
898 if(win32)
899 {
900 /* Write the names */
901
902 for(i = 0; i < rccount; i++)
903 {
904 res_count_t *rcp;
905
906 rcp = &rcarray[i];
907
908 if(rcp->type.type == name_str)
909 {
910 char *name = prep_nid_for_label(&(rcp->type));
911 fprintf(fp, "%s_%s_typename:\n",
912 prefix,
913 name);
914 write_name_str(fp, &(rcp->type));
915 }
916
917 for(j = 0; j < rcp->count32; j++)
918 {
919 resource_t *rsc = rcp->rsc32array[j].rsc[0];
920
921 if(rsc->name->type == name_str)
922 {
923 char *name = prep_nid_for_label(rsc->name);
924
925 fprintf(fp, "%s_%d_%s_name:\n",
926 prefix, rsc->type,
927 name);
928 write_name_str(fp, rsc->name);
929 }
930 }
931 }
932 }
933 else
934 {
935 /* ResourceNames */
936 for(i = 0; i < rccount; i++)
937 {
938 res_count_t *rcp = &rcarray[i];
939
940 for(j = 0; j < rcp->count; j++)
941 {
942 if(rcp->type.type == name_str)
943 {
944 fprintf(fp, "%s_%s_typename:\n",
945 prefix,
946 rcp->type.name.s_name->str.cstr);
947 write_name_str(fp, &(rcp->type));
948 }
949 if(rcp->rscarray[j]->name->type == name_str)
950 {
951 fprintf(fp, "%s%s_name:\n",
952 prefix,
953 rcp->rscarray[j]->c_name);
954 write_name_str(fp, rcp->rscarray[j]->name);
955 }
956 }
957 }
958 /* EndNames */
959
960 /* This is to end the NE resource table */
961 if(create_dir)
962 fprintf(fp, "\t"DIRECTIVE_BYTE"\t0\n");
963 }
964
965 fprintf(fp, "\n");
966}
967
968/*
969 *****************************************************************************
970 * Function : write_s_file
971 * Syntax : void write_s_file(char *outname, resource_t *top)
972 * Input :
973 * outname - Filename to write to
974 * top - The resource-tree to convert
975 * Output :
976 * Description :
977 * Remarks :
978 *****************************************************************************
979*/
980void write_s_file(char *outname, resource_t *top)
981{
982 FILE *fo;
983 resource_t *rsc;
984
985 fo = fopen(outname, "wt");
986 if(!fo)
987 {
988 error("Could not open %s\n", outname);
989 return;
990 }
991
992 {
993 char *s, *p;
994 now = time(NULL);
995 s = ctime(&now);
996 p = strchr(s, '\n');
997 if(p) *p = '\0';
998 fprintf(fo, s_file_head_str, input_name ? input_name : "stdin",
999 cmdline, s);
1000 }
1001
1002 /* Get an idea how many we have and restructure the tables */
1003 count_resources(top);
1004
1005 /* First write the segment tables */
1006 if(create_dir)
1007 {
1008 if(win32)
1009 write_pe_segment(fo, top);
1010 else
1011 write_ne_segment(fo, top);
1012 }
1013
1014 /* Dump the names */
1015 write_rsc_names(fo, top);
1016
1017 if(create_dir)
1018 fprintf(fo, LOCAL_PREFIX"LResTabEnd:\n");
1019
1020 if(!indirect_only)
1021 {
1022 /* Write the resource data */
1023 fprintf(fo, "\n"COMMENT_LINE"/* Resource binary data */\n\n");
1024 for(rsc = top; rsc; rsc = rsc->next)
1025 {
1026 if(!rsc->binres)
1027 continue;
1028
1029 fprintf(fo, "\t"DIRECTIVE_ALIGN"\t%d\n", win32 ? 4 : alignment);
1030 fprintf(fo, "%s%s_data:\n", prefix, rsc->c_name);
1031 if(global)
1032 fprintf(fo, "\t"DIRECTIVE_GLOBAL"\t%s%s_data\n", prefix, rsc->c_name);
1033
1034 write_s_res(fo, rsc->binres);
1035
1036 fprintf(fo, "\n");
1037 }
1038
1039 if(create_dir)
1040 {
1041 /* Add a resource descriptor for built-in and elf-dlls */
1042 fprintf(fo, "\t"DIRECTIVE_ALIGN"\t4\n");
1043 fprintf(fo, "%s_ResourceDescriptor:\n", prefix);
1044 fprintf(fo, "\t"DIRECTIVE_GLOBAL"\t%s_ResourceDescriptor\n", prefix);
1045 fprintf(fo, "%s_ResourceTable:\n", prefix);
1046 if(global)
1047 fprintf(fo, "\t"DIRECTIVE_GLOBAL"\t%s_ResourceTable\n", prefix);
1048 fprintf(fo, "\t"DIRECTIVE_LONG"\t%s%s\n", prefix, win32 ? _PEResTab : _NEResTab);
1049 fprintf(fo, "%s_NumberOfResources:\n", prefix);
1050 if(global)
1051 fprintf(fo, "\t"DIRECTIVE_GLOBAL"\t%s_NumberOfResources\n", prefix);
1052 fprintf(fo, "\t"DIRECTIVE_LONG"\t%d\n", direntries);
1053 fprintf(fo, "%s_ResourceSectionSize:\n", prefix);
1054 if(global)
1055 fprintf(fo, "\t"DIRECTIVE_GLOBAL"\t%s_ResourceSectionSize\n", prefix);
1056 fprintf(fo, "\t"DIRECTIVE_LONG"\t"LOCAL_PREFIX"LResTabEnd - %s%s\n", prefix, win32 ? _PEResTab : _NEResTab);
1057 if(win32)
1058 {
1059 fprintf(fo, "%s_ResourcesEntries:\n", prefix);
1060 if(global)
1061 fprintf(fo, "\t"DIRECTIVE_GLOBAL"\t%s_ResourcesEntries\n", prefix);
1062 fprintf(fo, "\t"DIRECTIVE_LONG"\t%s_ResourceDirectory\n", prefix);
1063 }
1064 }
1065 }
1066
1067 if(indirect)
1068 {
1069 /* Write the indirection structures */
1070 fprintf(fo, "\n"COMMENT_LINE"/* Resource indirection structures */\n\n");
1071 fprintf(fo, "\t"DIRECTIVE_ALIGN"\t4\n");
1072 for(rsc = top; rsc; rsc = rsc->next)
1073 {
1074 int type;
1075 char *type_name = NULL;
1076 char *label;
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"DIRECTIVE_GLOBAL"\t%s%s\n", prefix, rsc->c_name);
1115 label = prep_nid_for_label(rsc->name);
1116 fprintf(fo, "\t"DIRECTIVE_LONG"\t%d, %s%s%s%s, %d, %s%s%s%s, %s%s_data, %d\n",
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 ? "" : "_",
1120 rsc->name->type == name_ord ? "" : label,
1121 rsc->name->type == name_ord ? "" : "_name",
1122 type,
1123 type ? "0" : prefix,
1124 type ? "" : "_",
1125 type ? "" : type_name,
1126 type ? "" : "_typename",
1127 prefix,
1128 rsc->c_name,
1129 rsc->binres->size - rsc->binres->dataidx);
1130 fprintf(fo, "\n");
1131 }
1132 fprintf(fo, "\n");
1133
1134 /* Write the indirection table */
1135 fprintf(fo, COMMENT_LINE"/* Resource indirection table */\n\n");
1136 fprintf(fo, "\t"DIRECTIVE_ALIGN"\t4\n");
1137 fprintf(fo, "%s%s:\n", prefix, _ResTable);
1138 fprintf(fo, "\t"DIRECTIVE_GLOBAL"\t%s%s\n", prefix, _ResTable);
1139 for(rsc = top; rsc; rsc = rsc->next)
1140 {
1141 fprintf(fo, "\t"DIRECTIVE_LONG"\t%s%s\n", prefix, rsc->c_name);
1142 }
1143 fprintf(fo, "\t"DIRECTIVE_LONG"\t0\n");
1144 fprintf(fo, "\n");
1145 }
1146
1147 if(auto_register)
1148 fprintf(fo, s_file_autoreg_str, prefix, _ResTable);
1149
1150 fprintf(fo, s_file_tail_str);
1151 fclose(fo);
1152}
1153
1154/*
1155 *****************************************************************************
1156 * Function : write_h_file
1157 * Syntax : void write_h_file(char *outname, resource_t *top)
1158 * Input :
1159 * outname - Filename to write to
1160 * top - The resource-tree to convert
1161 * Output :
1162 * Description :
1163 * Remarks :
1164 *****************************************************************************
1165*/
1166void write_h_file(char *outname, resource_t *top)
1167{
1168 FILE *fo;
1169 resource_t *rsc;
1170 char *h_prefix;
1171
1172#ifdef NEED_UNDERSCORE_PREFIX
1173 h_prefix = prefix + 1;
1174#else
1175 h_prefix = prefix;
1176#endif
1177
1178 fo = fopen(outname, "wt");
1179 if(!fo)
1180 {
1181 error("Could not open %s\n", outname);
1182 }
1183
1184 time(&now);
1185 fprintf(fo, h_file_head_str, input_name ? input_name : "stdin",
1186 cmdline, ctime(&now), (long)now, (long)now);
1187
1188 /* First write the segment tables reference */
1189 if(create_dir)
1190 {
1191 fprintf(fo, "extern %schar %s%s[];\n\n",
1192 constant ? "const " : "",
1193 h_prefix,
1194 win32 ? _PEResTab : _NEResTab);
1195 }
1196
1197 /* Write the resource data */
1198 for(rsc = top; global && rsc; rsc = rsc->next)
1199 {
1200 if(!rsc->binres)
1201 continue;
1202
1203 fprintf(fo, "extern %schar %s%s_data[];\n",
1204 constant ? "const " : "",
1205 h_prefix,
1206 rsc->c_name);
1207 }
1208
1209 if(indirect)
1210 {
1211 if(global)
1212 fprintf(fo, "\n");
1213
1214 /* Write the indirection structures */
1215 for(rsc = top; global && rsc; rsc = rsc->next)
1216 {
1217 fprintf(fo, "extern %swrc_resource%d_t %s%s;\n",
1218 constant ? "const " : "",
1219 win32 ? 32 : 16,
1220 h_prefix,
1221 rsc->c_name);
1222 }
1223
1224 if(global)
1225 fprintf(fo, "\n");
1226
1227 /* Write the indirection table */
1228 fprintf(fo, "extern %swrc_resource%d_t %s%s[];\n\n",
1229 constant ? "const " : "",
1230 win32 ? 32 : 16,
1231 h_prefix,
1232 _ResTable);
1233 }
1234
1235 fprintf(fo, h_file_tail_str);
1236 fclose(fo);
1237}
1238
1239
Note: See TracBrowser for help on using the repository browser.