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

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

Created Wine port of wrc (using EMX/GCC)

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