Added first version of the Perl regression testing framework.
[wine/multimedia.git] / tools / wrc / writeres.c
blob7f535fbed7693f749d31dddc67317dac71b56626
1 /*
2 * Write .res, .s and .h file(s) from a resource-tree
4 * Copyright 1998 Bertho A. Stultiens
6 */
8 #include "config.h"
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <assert.h>
15 #include "wine/unicode.h"
16 #include "wrc.h"
17 #include "writeres.h"
18 #include "genres.h"
19 #include "newstruc.h"
20 #include "utils.h"
22 #ifdef NEED_UNDERSCORE_PREFIX
23 char Underscore[] = "_";
24 #else
25 char Underscore[] = "";
26 #endif
28 static char 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"
38 static char s_file_tail_str[] =
39 "/* <eof> */\n"
40 "\n"
43 static char 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
62 static char 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"
77 static char h_file_tail_str[] =
78 "#endif\n"
79 "/* <eof> */\n\n"
82 char _NEResTab[] = "_NEResTab";
83 char _PEResTab[] = "_PEResTab";
84 char _ResTable[] = "_ResTable";
86 /* Variables used for resource sorting */
87 res_count_t *rcarray = NULL; /* Type-level count array */
88 int rccount = 0; /* Nr of entries in the type-level array */
89 int n_id_entries = 0; /* win32 only: Nr of unique ids in the type-level array */
90 int n_name_entries = 0; /* win32 only: Nr of unique namess in the type-level array */
92 static int direntries; /* win32 only: Total number of unique resources */
95 *****************************************************************************
96 * Function : write_resfile
97 * Syntax : void write_resfile(char *outname, resource_t *top)
98 * Input :
99 * outname - Filename to write to
100 * top - The resource-tree to convert
101 * Output :
102 * Description :
103 * Remarks :
104 *****************************************************************************
106 void write_resfile(char *outname, resource_t *top)
108 FILE *fo;
109 int ret;
110 char zeros[3] = {0, 0, 0};
112 fo = fopen(outname, "wb");
113 if(!fo)
115 error("Could not open %s\n", outname);
118 if(win32)
120 /* Put an empty resource first to signal win32 format */
121 res_t *res = new_res();
122 put_dword(res, 0); /* ResSize */
123 put_dword(res, 0x00000020); /* HeaderSize */
124 put_word(res, 0xffff); /* ResType */
125 put_word(res, 0);
126 put_word(res, 0xffff); /* ResName */
127 put_word(res, 0);
128 put_dword(res, 0); /* DataVersion */
129 put_word(res, 0); /* Memory options */
130 put_word(res, 0); /* Language */
131 put_dword(res, 0); /* Version */
132 put_dword(res, 0); /* Charateristics */
133 ret = fwrite(res->data, 1, res->size, fo);
134 if(ret != res->size)
136 fclose(fo);
137 error("Error writing %s", outname);
139 free(res);
142 for(; top; top = top->next)
144 if(!top->binres)
145 continue;
147 ret = fwrite(top->binres->data, 1, top->binres->size, fo);
148 if(ret != top->binres->size)
150 fclose(fo);
151 error("Error writing %s", outname);
153 if(win32 && (top->binres->size & 0x03))
155 /* Write padding */
156 ret = fwrite(zeros, 1, 4 - (top->binres->size & 0x03), fo);
157 if(ret != 4 - (top->binres->size & 0x03))
159 fclose(fo);
160 error("Error writing %s", outname);
164 fclose(fo);
168 *****************************************************************************
169 * Function : write_s_res
170 * Syntax : void write_s_res(FILE *fp, res_t *res)
171 * Input :
172 * Output :
173 * Description :
174 * Remarks :
175 *****************************************************************************
177 #define BYTESPERLINE 8
178 static void write_s_res(FILE *fp, res_t *res)
180 int idx = res->dataidx;
181 int end = res->size;
182 int rest = (end - idx) % BYTESPERLINE;
183 int lines = (end - idx) / BYTESPERLINE;
184 int i, j;
186 for(i = 0 ; i < lines; i++)
188 fprintf(fp, "\t.byte\t");
189 for(j = 0; j < BYTESPERLINE; j++, idx++)
191 fprintf(fp, "0x%02x%s", res->data[idx] & 0xff,
192 j == BYTESPERLINE-1 ? "" : ", ");
194 fprintf(fp, "\n");
196 if(rest)
198 fprintf(fp, "\t.byte\t");
199 for(j = 0; j < rest; j++, idx++)
201 fprintf(fp, "0x%02x%s", res->data[idx] & 0xff,
202 j == rest-1 ? "" : ", ");
204 fprintf(fp, "\n");
207 #undef BYTESPERLINE
210 *****************************************************************************
211 * Function : write_name_str
212 * Syntax : void write_name_str(FILE *fp, name_id_t *nid)
213 * Input :
214 * Output :
215 * Description :
216 * Remarks : One level self recursive for string type conversion
217 *****************************************************************************
219 static void write_name_str(FILE *fp, name_id_t *nid)
221 res_t res;
222 assert(nid->type == name_str);
224 if(!win32 && nid->name.s_name->type == str_char)
226 res.size = strlen(nid->name.s_name->str.cstr);
227 if(res.size > 254)
228 error("Can't write strings larger than 254 bytes");
229 if(res.size == 0)
230 internal_error(__FILE__, __LINE__, "Attempt to write empty string");
231 res.dataidx = 0;
232 res.data = (char *)xmalloc(res.size + 1);
233 res.data[0] = (char)res.size;
234 res.size++; /* We need to write the length byte as well */
235 strcpy(res.data+1, nid->name.s_name->str.cstr);
236 write_s_res(fp, &res);
237 free(res.data);
239 else if(!win32 && nid->name.s_name->type == str_unicode)
241 name_id_t lnid;
242 string_t str;
244 lnid.type = name_str;
245 lnid.name.s_name = &str;
246 str.type = str_char;
247 str.str.cstr = dupwstr2cstr(nid->name.s_name->str.wstr);
248 write_name_str(fp, &lnid);
249 free(str.str.cstr);
251 else if(win32 && nid->name.s_name->type == str_char)
253 name_id_t lnid;
254 string_t str;
256 lnid.type = name_str;
257 lnid.name.s_name = &str;
258 str.type = str_unicode;
259 str.str.wstr = dupcstr2wstr(nid->name.s_name->str.cstr);
260 write_name_str(fp, &lnid);
261 free(str.str.wstr);
263 else if(win32 && nid->name.s_name->type == str_unicode)
265 res.size = strlenW(nid->name.s_name->str.wstr);
266 if(res.size > 65534)
267 error("Can't write strings larger than 65534 bytes");
268 if(res.size == 0)
269 internal_error(__FILE__, __LINE__, "Attempt to write empty string");
270 res.dataidx = 0;
271 res.data = (char *)xmalloc((res.size + 1) * 2);
272 ((short *)res.data)[0] = (short)res.size;
273 strcpyW((WCHAR *)(res.data+2), nid->name.s_name->str.wstr);
274 res.size *= 2; /* Function writes bytes, not shorts... */
275 res.size += 2; /* We need to write the length word as well */
276 write_s_res(fp, &res);
277 free(res.data);
279 else
281 internal_error(__FILE__, __LINE__, "Hmm, requested to write a string of unknown type %d",
282 nid->name.s_name->type);
287 *****************************************************************************
288 * Function : find_counter
289 * Syntax : res_count_t *find_counter(name_id_t *type)
290 * Input :
291 * Output :
292 * Description :
293 * Remarks :
294 *****************************************************************************
296 static res_count_t *find_counter(name_id_t *type)
298 int i;
299 for(i = 0; i < rccount; i++)
301 if(!compare_name_id(type, &(rcarray[i].type)))
302 return &rcarray[i];
304 return NULL;
308 *****************************************************************************
309 * Function : count_resources
310 * Syntax : res_count_t *count_resources(resource_t *top)
311 * Input :
312 * Output :
313 * Description :
314 * Remarks : The whole lot is converted into arrays because they are
315 * easy sortable. Makes the lot almost unreadable, but it
316 * works (I hope). Basically you have to keep in mind that
317 * the lot is a three-dimensional structure for win32 and a
318 * two-dimensional structure for win16.
319 *****************************************************************************
321 #define RCT(v) (*((resource_t **)(v)))
322 /* qsort sorting function */
323 static int sort_name_id(const void *e1, const void *e2)
325 return compare_name_id(RCT(e1)->name, RCT(e2)->name);
328 static int sort_language(const void *e1, const void *e2)
330 assert((RCT(e1)->lan) != NULL);
331 assert((RCT(e2)->lan) != NULL);
333 return MAKELANGID(RCT(e1)->lan->id, RCT(e1)->lan->sub)
334 - MAKELANGID(RCT(e2)->lan->id, RCT(e2)->lan->sub);
336 #undef RCT
337 #define RCT(v) ((res_count_t *)(v))
338 static int sort_type(const void *e1, const void *e2)
340 return compare_name_id(&(RCT(e1)->type), &(RCT(e2)->type));
342 #undef RCT
344 static void count_resources(resource_t *top)
346 resource_t *rsc;
347 res_count_t *rcp;
348 name_id_t nid;
349 int i, j;
351 for(rsc = top; rsc; rsc = rsc->next)
353 if(!rsc->binres)
354 continue;
355 switch(rsc->type)
357 case res_dlgex:
358 nid.name.i_name = WRC_RT_DIALOG;
359 nid.type = name_ord;
360 break;
361 case res_menex:
362 nid.name.i_name = WRC_RT_MENU;
363 nid.type = name_ord;
364 break;
365 case res_usr:
366 nid = *(rsc->res.usr->type);
367 break;
368 default:
369 nid.name.i_name = rsc->type;
370 nid.type = name_ord;
373 if((rcp = find_counter(&nid)) == NULL)
375 /* Count the number of uniq ids and names */
377 if(nid.type == name_ord)
378 n_id_entries++;
379 else
380 n_name_entries++;
382 if(!rcarray)
384 rcarray = (res_count_t *)xmalloc(sizeof(res_count_t));
385 rccount = 1;
386 rcarray[0].count = 1;
387 rcarray[0].type = nid;
388 rcarray[0].rscarray = (resource_t **)xmalloc(sizeof(resource_t *));
389 rcarray[0].rscarray[0] = rsc;
391 else
393 rccount++;
394 rcarray = (res_count_t *)xrealloc(rcarray, rccount * sizeof(res_count_t));
395 rcarray[rccount-1].count = 1;
396 rcarray[rccount-1].type = nid;
397 rcarray[rccount-1].rscarray = (resource_t **)xmalloc(sizeof(resource_t *));
398 rcarray[rccount-1].rscarray[0] = rsc;
401 else
403 rcp->count++;
404 rcp->rscarray = (resource_t **)xrealloc(rcp->rscarray, rcp->count * sizeof(resource_t *));
405 rcp->rscarray[rcp->count-1] = rsc;
409 if(!win32)
411 /* We're done, win16 requires no special sorting */
412 return;
415 /* We now have a unsorted list of types with an array of res_count_t
416 * in rcarray[0..rccount-1]. And we have names of one type in the
417 * rcarray[x].rsc[0..rcarray[x].count-1] arrays.
418 * The list needs to be sorted for win32's top level tree structure.
421 /* Sort the types */
422 if(rccount > 1)
423 qsort(rcarray, rccount, sizeof(rcarray[0]), sort_type);
425 /* Now sort the name-id arrays */
426 for(i = 0; i < rccount; i++)
428 if(rcarray[i].count > 1)
429 qsort(rcarray[i].rscarray, rcarray[i].count, sizeof(rcarray[0].rscarray[0]), sort_name_id);
432 /* Now split the name-id arrays into name/language
433 * subs. Don't look at the awfull expressions...
434 * We do this by taking the array elements out of rscarray and putting
435 * together a new array in rsc32array.
437 for(i = 0; i < rccount; i++)
439 res_count_t *rcap;
441 assert(rcarray[i].count >= 1);
443 /* rcap points to the current type we are dealing with */
444 rcap = &(rcarray[i]);
446 /* Insert the first name-id */
447 rcap->rsc32array = (res32_count_t *)xmalloc(sizeof(res32_count_t));
448 rcap->count32 = 1;
449 rcap->rsc32array[0].rsc = (resource_t **)xmalloc(sizeof(resource_t *));
450 rcap->rsc32array[0].count = 1;
451 rcap->rsc32array[0].rsc[0] = rcap->rscarray[0];
452 if(rcap->rscarray[0]->name->type == name_ord)
454 rcap->n_id_entries = 1;
455 rcap->n_name_entries = 0;
457 else
459 rcap->n_id_entries = 0;
460 rcap->n_name_entries = 1;
463 /* Now loop over the resting resources of the current type
464 * to find duplicate names (which should have different
465 * languages).
467 for(j = 1; j < rcap->count; j++)
469 res32_count_t *r32cp;
471 /* r32cp points to the current res32_count structure
472 * that holds the resource name we are processing.
474 r32cp = &(rcap->rsc32array[rcap->count32-1]);
476 if(!compare_name_id(r32cp->rsc[0]->name, rcarray[i].rscarray[j]->name))
478 /* Names are the same, add to list */
479 r32cp->count++;
480 r32cp->rsc = (resource_t **)xrealloc(r32cp->rsc, r32cp->count * sizeof(resource_t *));
481 r32cp->rsc[r32cp->count-1] = rcap->rscarray[j];
483 else
485 /* New name-id, sort the old one by
486 * language and create new list
488 if(r32cp->count > 1)
489 qsort(r32cp->rsc, r32cp->count, sizeof(r32cp->rsc[0]), sort_language);
490 rcap->count32++;
491 rcap->rsc32array = (res32_count_t*)xrealloc(rcap->rsc32array, rcap->count32 * sizeof(res32_count_t));
492 rcap->rsc32array[rcap->count32-1].rsc = (resource_t **)xmalloc(sizeof(resource_t *));
493 rcap->rsc32array[rcap->count32-1].count = 1;
494 rcap->rsc32array[rcap->count32-1].rsc[0] = rcap->rscarray[j];
496 if(rcap->rscarray[j]->name->type == name_ord)
497 rcap->n_id_entries++;
498 else
499 rcap->n_name_entries++;
502 /* Also sort the languages of the last name group */
503 if(rcap->rsc32array[rcap->count32-1].count > 1)
504 qsort(rcap->rsc32array[rcap->count32-1].rsc,
505 rcap->rsc32array[rcap->count32-1].count,
506 sizeof(rcap->rsc32array[rcap->count32-1].rsc[0]),
507 sort_language);
512 *****************************************************************************
513 * Function : write_pe_segment
514 * Syntax : void write_pe_segment(FILE *fp)
515 * Input :
516 * Output :
517 * Description :
518 * Remarks :
519 *****************************************************************************
521 static void write_pe_segment(FILE *fp)
523 int i;
525 fprintf(fp, "\t.align\t4\n");
526 fprintf(fp, "%s%s:\n", prefix, _PEResTab);
527 fprintf(fp, "\t.globl\t%s%s\n", prefix, _PEResTab);
528 /* Flags */
529 fprintf(fp, "\t.long\t0\n");
530 /* Time/Date stamp */
531 fprintf(fp, "\t.long\t0x%08lx\n", (long)now);
532 /* Version */
533 fprintf(fp, "\t.long\t0\n"); /* FIXME: must version be filled out? */
534 /* # of id entries, # of name entries */
535 fprintf(fp, "\t.short\t%d, %d\n", n_name_entries, n_id_entries);
537 /* Write the type level of the tree */
538 for(i = 0; i < rccount; i++)
540 res_count_t *rcp;
541 char *label;
543 rcp = &rcarray[i];
545 /* TypeId */
546 if(rcp->type.type == name_ord)
547 fprintf(fp, "\t.long\t%d\n", rcp->type.name.i_name);
548 else
550 char *name = prep_nid_for_label(&(rcp->type));
551 fprintf(fp, "\t.long\t(%s_%s_typename - %s%s) | 0x80000000\n",
552 prefix,
553 name,
554 prefix,
555 _PEResTab);
557 /* Offset */
558 label = prep_nid_for_label(&(rcp->type));
559 fprintf(fp, "\t.long\t(.L%s - %s%s) | 0x80000000\n",
560 label,
561 prefix,
562 _PEResTab);
565 /* Write the name level of the tree */
567 for(i = 0; i < rccount; i++)
569 res_count_t *rcp;
570 char *typelabel;
571 char *namelabel;
572 int j;
574 rcp = &rcarray[i];
576 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
577 fprintf(fp, ".L%s:\n", typelabel);
579 fprintf(fp, "\t.long\t0\n"); /* Flags */
580 fprintf(fp, "\t.long\t0x%08lx\n", (long)now); /* TimeDate */
581 fprintf(fp, "\t.long\t0\n"); /* FIXME: must version be filled out? */
582 fprintf(fp, "\t.short\t%d, %d\n", rcp->n_name_entries, rcp->n_id_entries);
583 for(j = 0; j < rcp->count32; j++)
585 resource_t *rsc = rcp->rsc32array[j].rsc[0];
586 /* NameId */
587 if(rsc->name->type == name_ord)
588 fprintf(fp, "\t.long\t%d\n", rsc->name->name.i_name);
589 else
591 fprintf(fp, "\t.long\t(%s%s_name - %s%s) | 0x80000000\n",
592 prefix,
593 rsc->c_name,
594 prefix,
595 _PEResTab);
597 /* Maybe FIXME: Unescape the tree (ommit 0x80000000) and
598 * put the offset to the resource data entry.
599 * ?? Is unescaping worth while ??
601 /* Offset */
602 namelabel = prep_nid_for_label(rsc->name);
603 fprintf(fp, "\t.long\t(.L%s_%s - %s%s) | 0x80000000\n",
604 typelabel,
605 namelabel,
606 prefix,
607 _PEResTab);
609 free(typelabel);
612 /* Write the language level of the tree */
614 for(i = 0; i < rccount; i++)
616 res_count_t *rcp;
617 char *namelabel;
618 char *typelabel;
619 int j;
621 rcp = &rcarray[i];
622 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
624 for(j = 0; j < rcp->count32; j++)
626 res32_count_t *r32cp = &(rcp->rsc32array[j]);
627 int k;
629 namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
630 fprintf(fp, ".L%s_%s:\n", typelabel, namelabel);
632 fprintf(fp, "\t.long\t0\n"); /* Flags */
633 fprintf(fp, "\t.long\t0x%08lx\n", (long)now); /* TimeDate */
634 fprintf(fp, "\t.long\t0\n"); /* FIXME: must version be filled out? */
635 fprintf(fp, "\t.short\t0, %d\n", r32cp->count);
637 for(k = 0; k < r32cp->count; k++)
639 resource_t *rsc = r32cp->rsc[k];
640 assert(rsc->lan != NULL);
641 /* LanguageId */
642 fprintf(fp, "\t.long\t0x%08x\n", rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
643 /* Offset */
644 fprintf(fp, "\t.long\t.L%s_%s_%d - %s%s\n",
645 typelabel,
646 namelabel,
647 rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0,
648 prefix,
649 _PEResTab);
651 free(namelabel);
653 free(typelabel);
656 /* Write the resource table itself */
657 fprintf(fp, "%s_ResourceDirectory:\n", prefix);
658 fprintf(fp, "\t.globl\t%s_ResourceDirectory\n", prefix);
659 direntries = 0;
661 for(i = 0; i < rccount; i++)
663 res_count_t *rcp;
664 char *namelabel;
665 char *typelabel;
666 int j;
668 rcp = &rcarray[i];
669 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
671 for(j = 0; j < rcp->count32; j++)
673 res32_count_t *r32cp = &(rcp->rsc32array[j]);
674 int k;
676 namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
678 for(k = 0; k < r32cp->count; k++)
680 resource_t *rsc = r32cp->rsc[k];
682 assert(rsc->lan != NULL);
684 fprintf(fp, ".L%s_%s_%d:\n",
685 typelabel,
686 namelabel,
687 rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
689 /* Data RVA */
690 fprintf(fp, "\t.long\t%s%s_data - %s%s\n",
691 prefix,
692 rsc->c_name,
693 prefix,
694 _PEResTab);
695 /* Size */
696 fprintf(fp, "\t.long\t%d\n",
697 rsc->binres->size - rsc->binres->dataidx);
698 /* CodePage */
699 fprintf(fp, "\t.long\t%ld\n", codepage);
700 /* Reserved */
701 fprintf(fp, "\t.long\t0\n");
703 direntries++;
705 free(namelabel);
707 free(typelabel);
712 *****************************************************************************
713 * Function : write_ne_segment
714 * Syntax : void write_ne_segment(FILE *fp)
715 * Input :
716 * Output :
717 * Description :
718 * Remarks :
719 *****************************************************************************
721 static void write_ne_segment(FILE *fp)
723 int i, j;
725 fprintf(fp, "\t.align\t4\n");
726 fprintf(fp, "%s%s:\n", prefix, _NEResTab);
727 fprintf(fp, "\t.globl\t%s%s\n", prefix, _NEResTab);
729 /* AlignmentShift */
730 fprintf(fp, "\t.short\t%d\n", alignment_pwr);
732 /* TypeInfo */
733 for(i = 0; i < rccount; i++)
735 res_count_t *rcp = &rcarray[i];
737 /* TypeId */
738 if(rcp->type.type == name_ord)
739 fprintf(fp, "\t.short\t0x%04x\n", rcp->type.name.i_name | 0x8000);
740 else
741 fprintf(fp, "\t.short\t%s_%s_typename - %s%s\n",
742 prefix,
743 rcp->type.name.s_name->str.cstr,
744 prefix,
745 _NEResTab);
746 /* ResourceCount */
747 fprintf(fp, "\t.short\t%d\n", rcp->count);
748 /* Reserved */
749 fprintf(fp, "\t.long\t0\n");
750 /* NameInfo */
751 for(j = 0; j < rcp->count; j++)
754 * VERY IMPORTANT:
755 * The offset is relative to the beginning of the NE resource segment
756 * and _NOT_ to the file-beginning. This is because we do not have a
757 * file based resource, but a simulated NE segment. The offset _is_
758 * scaled by the AlignShift field.
759 * All other things are as the MS doc describes (alignment etc.)
761 /* Offset */
762 fprintf(fp, "\t.short\t(%s%s_data - %s%s) >> %d\n",
763 prefix,
764 rcp->rscarray[j]->c_name,
765 prefix,
766 _NEResTab,
767 alignment_pwr);
768 /* Length */
769 fprintf(fp, "\t.short\t%d\n",
770 (rcp->rscarray[j]->binres->size - rcp->rscarray[j]->binres->dataidx + alignment - 1) >> alignment_pwr);
771 /* Flags */
772 fprintf(fp, "\t.short\t0x%04x\n", (WORD)rcp->rscarray[j]->memopt);
773 /* Id */
774 if(rcp->rscarray[j]->name->type == name_ord)
775 fprintf(fp, "\t.short\t0x%04x\n", rcp->rscarray[j]->name->name.i_name | 0x8000);
776 else
777 fprintf(fp, "\t.short\t%s%s_name - %s%s\n",
778 prefix,
779 rcp->rscarray[j]->c_name,
780 prefix,
781 _NEResTab);
782 /* Handle and Usage */
783 fprintf(fp, "\t.short\t0, 0\n");
786 /* EndTypes */
787 fprintf(fp, "\t.short\t0\n");
791 *****************************************************************************
792 * Function : write_rsc_names
793 * Syntax : void write_rsc_names(FILE *fp)
794 * Input :
795 * Output :
796 * Description :
797 * Remarks :
798 *****************************************************************************
800 static void write_rsc_names(FILE *fp)
802 int i, j;
804 if(win32)
806 /* Write the names */
808 for(i = 0; i < rccount; i++)
810 res_count_t *rcp;
812 rcp = &rcarray[i];
814 if(rcp->type.type == name_str)
816 char *name = prep_nid_for_label(&(rcp->type));
817 fprintf(fp, "%s_%s_typename:\n",
818 prefix,
819 name);
820 write_name_str(fp, &(rcp->type));
823 for(j = 0; j < rcp->count32; j++)
825 resource_t *rsc = rcp->rsc32array[j].rsc[0];
827 if(rsc->name->type == name_str)
829 fprintf(fp, "%s%s_name:\n",
830 prefix,
831 rsc->c_name);
832 write_name_str(fp, rsc->name);
837 else
839 /* ResourceNames */
840 for(i = 0; i < rccount; i++)
842 res_count_t *rcp = &rcarray[i];
844 if(rcp->type.type == name_str)
846 fprintf(fp, "%s_%s_typename:\n",
847 prefix,
848 rcp->type.name.s_name->str.cstr);
849 write_name_str(fp, &(rcp->type));
851 for(j = 0; j < rcp->count; j++)
853 if(rcp->rscarray[j]->name->type == name_str)
855 fprintf(fp, "%s%s_name:\n",
856 prefix,
857 rcp->rscarray[j]->c_name);
858 write_name_str(fp, rcp->rscarray[j]->name);
862 /* EndNames */
864 /* This is to end the NE resource table */
865 if(create_dir)
866 fprintf(fp, "\t.byte\t0\n");
869 fprintf(fp, "\n");
873 *****************************************************************************
874 * Function : write_s_file
875 * Syntax : void write_s_file(char *outname, resource_t *top)
876 * Input :
877 * outname - Filename to write to
878 * top - The resource-tree to convert
879 * Output :
880 * Description :
881 * Remarks :
882 *****************************************************************************
884 void write_s_file(char *outname, resource_t *top)
886 FILE *fo;
887 resource_t *rsc;
889 fo = fopen(outname, "wt");
890 if(!fo)
892 error("Could not open %s\n", outname);
893 return;
897 char *s, *p;
898 s = ctime(&now);
899 p = strchr(s, '\n');
900 if(p) *p = '\0';
901 fprintf(fo, s_file_head_str, input_name ? input_name : "stdin",
902 cmdline, s);
905 /* Get an idea how many we have and restructure the tables */
906 count_resources(top);
908 /* First write the segment tables */
909 if(create_dir)
911 if(win32)
912 write_pe_segment(fo);
913 else
914 write_ne_segment(fo);
917 /* Dump the names */
918 write_rsc_names(fo);
920 if(create_dir)
921 fprintf(fo, ".LResTabEnd:\n");
923 if(!indirect_only)
925 /* Write the resource data */
926 fprintf(fo, "\n/* Resource binary data */\n\n");
927 for(rsc = top; rsc; rsc = rsc->next)
929 if(!rsc->binres)
930 continue;
932 fprintf(fo, "\t.align\t%d\n", win32 ? 4 : alignment);
933 fprintf(fo, "%s%s_data:\n", prefix, rsc->c_name);
934 if(global)
935 fprintf(fo, "\t.globl\t%s%s_data\n", prefix, rsc->c_name);
937 write_s_res(fo, rsc->binres);
939 fprintf(fo, "\n");
942 if(create_dir)
944 /* Add a resource descriptor for built-in and elf-dlls */
945 fprintf(fo, "\t.align\t4\n");
946 fprintf(fo, "%s_ResourceDescriptor:\n", prefix);
947 fprintf(fo, "\t.globl\t%s_ResourceDescriptor\n", prefix);
948 fprintf(fo, "%s_ResourceTable:\n", prefix);
949 if(global)
950 fprintf(fo, "\t.globl\t%s_ResourceTable\n", prefix);
951 fprintf(fo, "\t.long\t%s%s\n", prefix, win32 ? _PEResTab : _NEResTab);
952 fprintf(fo, "%s_NumberOfResources:\n", prefix);
953 if(global)
954 fprintf(fo, "\t.globl\t%s_NumberOfResources\n", prefix);
955 fprintf(fo, "\t.long\t%d\n", direntries);
956 fprintf(fo, "%s_ResourceSectionSize:\n", prefix);
957 if(global)
958 fprintf(fo, "\t.globl\t%s_ResourceSectionSize\n", prefix);
959 fprintf(fo, "\t.long\t.LResTabEnd - %s%s\n", prefix, win32 ? _PEResTab : _NEResTab);
960 if(win32)
962 fprintf(fo, "%s_ResourcesEntries:\n", prefix);
963 if(global)
964 fprintf(fo, "\t.globl\t%s_ResourcesEntries\n", prefix);
965 fprintf(fo, "\t.long\t%s_ResourceDirectory\n", prefix);
970 if(indirect)
972 /* Write the indirection structures */
973 fprintf(fo, "\n/* Resource indirection structures */\n\n");
974 fprintf(fo, "\t.align\t4\n");
975 for(rsc = top; rsc; rsc = rsc->next)
977 int type;
978 char *type_name = NULL;
980 if(!rsc->binres)
981 continue;
983 switch(rsc->type)
985 case res_menex:
986 type = WRC_RT_MENU;
987 break;
988 case res_dlgex:
989 type = WRC_RT_DIALOG;
990 break;
991 case res_usr:
992 assert(rsc->res.usr->type != NULL);
993 type_name = prep_nid_for_label(rsc->res.usr->type);
994 type = 0;
995 break;
996 default:
997 type = rsc->type;
1001 * This follows a structure like:
1002 * struct wrc_resource {
1003 * INT32 id;
1004 * RSCNAME *resname;
1005 * INT32 restype;
1006 * RSCNAME *typename;
1007 * void *data;
1008 * UINT32 datasize;
1009 * };
1010 * The 'RSCNAME' is a pascal-style string where the
1011 * first byte/word denotes the size and the rest the string
1012 * itself.
1014 fprintf(fo, "%s%s:\n", prefix, rsc->c_name);
1015 if(global)
1016 fprintf(fo, "\t.globl\t%s%s\n", prefix, rsc->c_name);
1017 fprintf(fo, "\t.long\t%d, %s%s%s, %d, %s%s%s%s, %s%s_data, %d\n",
1018 rsc->name->type == name_ord ? rsc->name->name.i_name : 0,
1019 rsc->name->type == name_ord ? "0" : prefix,
1020 rsc->name->type == name_ord ? "" : rsc->c_name,
1021 rsc->name->type == name_ord ? "" : "_name",
1022 type,
1023 type ? "0" : prefix,
1024 type ? "" : "_",
1025 type ? "" : type_name,
1026 type ? "" : "_typename",
1027 prefix,
1028 rsc->c_name,
1029 rsc->binres->size - rsc->binres->dataidx);
1030 fprintf(fo, "\n");
1032 fprintf(fo, "\n");
1034 /* Write the indirection table */
1035 fprintf(fo, "/* Resource indirection table */\n\n");
1036 fprintf(fo, "\t.align\t4\n");
1037 fprintf(fo, "%s%s:\n", prefix, _ResTable);
1038 fprintf(fo, "\t.globl\t%s%s\n", prefix, _ResTable);
1039 for(rsc = top; rsc; rsc = rsc->next)
1041 fprintf(fo, "\t.long\t%s%s\n", prefix, rsc->c_name);
1043 fprintf(fo, "\t.long\t0\n");
1044 fprintf(fo, "\n");
1047 if(auto_register)
1048 fprintf(fo, s_file_autoreg_str, prefix, _ResTable);
1050 fprintf(fo, s_file_tail_str);
1051 fclose(fo);
1055 *****************************************************************************
1056 * Function : write_h_file
1057 * Syntax : void write_h_file(char *outname, resource_t *top)
1058 * Input :
1059 * outname - Filename to write to
1060 * top - The resource-tree to convert
1061 * Output :
1062 * Description :
1063 * Remarks :
1064 *****************************************************************************
1066 void write_h_file(char *outname, resource_t *top)
1068 FILE *fo;
1069 resource_t *rsc;
1070 char *h_prefix;
1072 #ifdef NEED_UNDERSCORE_PREFIX
1073 h_prefix = prefix + 1;
1074 #else
1075 h_prefix = prefix;
1076 #endif
1078 fo = fopen(outname, "wt");
1079 if(!fo)
1081 error("Could not open %s\n", outname);
1084 fprintf(fo, h_file_head_str, input_name ? input_name : "stdin",
1085 cmdline, ctime(&now), (long)now, (long)now);
1087 /* First write the segment tables reference */
1088 if(create_dir)
1090 fprintf(fo, "extern %schar %s%s[];\n\n",
1091 constant ? "const " : "",
1092 h_prefix,
1093 win32 ? _PEResTab : _NEResTab);
1096 /* Write the resource data */
1097 for(rsc = top; global && rsc; rsc = rsc->next)
1099 if(!rsc->binres)
1100 continue;
1102 fprintf(fo, "extern %schar %s%s_data[];\n",
1103 constant ? "const " : "",
1104 h_prefix,
1105 rsc->c_name);
1108 if(indirect)
1110 if(global)
1111 fprintf(fo, "\n");
1113 /* Write the indirection structures */
1114 for(rsc = top; global && rsc; rsc = rsc->next)
1116 fprintf(fo, "extern %swrc_resource%d_t %s%s;\n",
1117 constant ? "const " : "",
1118 win32 ? 32 : 16,
1119 h_prefix,
1120 rsc->c_name);
1123 if(global)
1124 fprintf(fo, "\n");
1126 /* Write the indirection table */
1127 fprintf(fo, "extern %swrc_resource%d_t %s%s[];\n\n",
1128 constant ? "const " : "",
1129 win32 ? 32 : 16,
1130 h_prefix,
1131 _ResTable);
1134 fprintf(fo, h_file_tail_str);
1135 fclose(fo);