Added support for WINEPREFIX environment variable.
[wine/multimedia.git] / tools / wrc / writeres.c
blobaebc54bb80aea8e1ceb37e41f7b1e5cd2058817a
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>
14 #include <time.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 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 char s_file_tail_str[] =
39 "/* <eof> */\n"
40 "\n"
43 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 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 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 */
94 time_t now;
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 *****************************************************************************
108 void write_resfile(char *outname, resource_t *top)
110 FILE *fo;
111 int ret;
112 char zeros[3] = {0, 0, 0};
114 fo = fopen(outname, "wb");
115 if(!fo)
117 error("Could not open %s\n", outname);
120 if(win32)
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)
138 fclose(fo);
139 error("Error writing %s", outname);
141 free(res);
144 for(; top; top = top->next)
146 if(!top->binres)
147 continue;
149 ret = fwrite(top->binres->data, 1, top->binres->size, fo);
150 if(ret != top->binres->size)
152 fclose(fo);
153 error("Error writing %s", outname);
155 if(win32 && (top->binres->size & 0x03))
157 /* Write padding */
158 ret = fwrite(zeros, 1, 4 - (top->binres->size & 0x03), fo);
159 if(ret != 4 - (top->binres->size & 0x03))
161 fclose(fo);
162 error("Error writing %s", outname);
166 fclose(fo);
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 *****************************************************************************
179 #define BYTESPERLINE 8
180 void write_s_res(FILE *fp, res_t *res)
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;
188 for(i = 0 ; i < lines; i++)
190 fprintf(fp, "\t.byte\t");
191 for(j = 0; j < BYTESPERLINE; j++, idx++)
193 fprintf(fp, "0x%02x%s", res->data[idx] & 0xff,
194 j == BYTESPERLINE-1 ? "" : ", ");
196 fprintf(fp, "\n");
198 if(rest)
200 fprintf(fp, "\t.byte\t");
201 for(j = 0; j < rest; j++, idx++)
203 fprintf(fp, "0x%02x%s", res->data[idx] & 0xff,
204 j == rest-1 ? "" : ", ");
206 fprintf(fp, "\n");
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 *****************************************************************************
220 void write_name_str(FILE *fp, name_id_t *nid)
222 res_t res;
223 assert(nid->type == name_str);
225 if(!win32 && nid->name.s_name->type == str_char)
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);
240 else if(!win32 && nid->name.s_name->type == str_unicode)
242 name_id_t lnid;
243 string_t str;
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);
252 else if(win32 && nid->name.s_name->type == str_char)
254 name_id_t lnid;
255 string_t str;
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);
264 else if(win32 && nid->name.s_name->type == str_unicode)
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);
280 else
282 internal_error(__FILE__, __LINE__, "Hmm, requested to write a string of unknown type %d",
283 nid->name.s_name->type);
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 *****************************************************************************
297 int compare_name_id(name_id_t *n1, name_id_t *n2)
299 if(n1->type == name_ord && n2->type == name_ord)
301 return n1->name.i_name - n2->name.i_name;
303 else if(n1->type == name_str && n2->type == name_str)
305 if(n1->name.s_name->type == str_char
306 && n2->name.s_name->type == str_char)
308 return strcasecmp(n1->name.s_name->str.cstr, n2->name.s_name->str.cstr);
310 else if(n1->name.s_name->type == str_unicode
311 && n2->name.s_name->type == str_unicode)
313 return wstricmp(n1->name.s_name->str.wstr, n2->name.s_name->str.wstr);
315 else
317 internal_error(__FILE__, __LINE__, "Can't yet compare strings of mixed type");
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);
328 return 0; /* Keep the compiler happy */
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 *****************************************************************************
341 res_count_t *find_counter(name_id_t *type)
343 int i;
344 for(i = 0; i < rccount; i++)
346 if(!compare_name_id(type, &(rcarray[i].type)))
347 return &rcarray[i];
349 return NULL;
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 *****************************************************************************
366 #define RCT(v) (*((resource_t **)(v)))
367 /* qsort sorting function */
368 int sort_name_id(const void *e1, const void *e2)
370 return compare_name_id(RCT(e1)->name, RCT(e2)->name);
373 int sort_language(const void *e1, const void *e2)
375 assert((RCT(e1)->lan) != NULL);
376 assert((RCT(e2)->lan) != NULL);
378 return MAKELANGID(RCT(e1)->lan->id, RCT(e1)->lan->sub)
379 - MAKELANGID(RCT(e2)->lan->id, RCT(e2)->lan->sub);
381 #undef RCT
382 #define RCT(v) ((res_count_t *)(v))
383 int sort_type(const void *e1, const void *e2)
385 return compare_name_id(&(RCT(e1)->type), &(RCT(e2)->type));
387 #undef RCT
389 void count_resources(resource_t *top)
391 resource_t *rsc;
392 res_count_t *rcp;
393 name_id_t nid;
394 int i, j;
396 for(rsc = top; rsc; rsc = rsc->next)
398 if(!rsc->binres)
399 continue;
400 switch(rsc->type)
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;
418 if((rcp = find_counter(&nid)) == NULL)
420 /* Count the number of uniq ids and names */
422 if(nid.type == name_ord)
423 n_id_entries++;
424 else
425 n_name_entries++;
427 if(!rcarray)
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;
436 else
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;
446 else
448 rcp->count++;
449 rcp->rscarray = (resource_t **)xrealloc(rcp->rscarray, rcp->count * sizeof(resource_t *));
450 rcp->rscarray[rcp->count-1] = rsc;
454 if(!win32)
456 /* We're done, win16 requires no special sorting */
457 return;
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.
466 /* Sort the types */
467 if(rccount > 1)
468 qsort(rcarray, rccount, sizeof(rcarray[0]), sort_type);
470 /* Now sort the name-id arrays */
471 for(i = 0; i < rccount; i++)
473 if(rcarray[i].count > 1)
474 qsort(rcarray[i].rscarray, rcarray[i].count, sizeof(rcarray[0].rscarray[0]), sort_name_id);
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.
482 for(i = 0; i < rccount; i++)
484 res_count_t *rcap;
486 assert(rcarray[i].count >= 1);
488 /* rcap points to the current type we are dealing with */
489 rcap = &(rcarray[i]);
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)
499 rcap->n_id_entries = 1;
500 rcap->n_name_entries = 0;
502 else
504 rcap->n_id_entries = 0;
505 rcap->n_name_entries = 1;
508 /* Now loop over the resting resources of the current type
509 * to find duplicate names (which should have different
510 * languages).
512 for(j = 1; j < rcap->count; j++)
514 res32_count_t *r32cp;
516 /* r32cp points to the current res32_count structure
517 * that holds the resource name we are processing.
519 r32cp = &(rcap->rsc32array[rcap->count32-1]);
521 if(!compare_name_id(r32cp->rsc[0]->name, rcarray[i].rscarray[j]->name))
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];
528 else
530 /* New name-id, sort the old one by
531 * language and create new list
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];
541 if(rcap->rscarray[j]->name->type == name_ord)
542 rcap->n_id_entries++;
543 else
544 rcap->n_name_entries++;
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);
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 *****************************************************************************
566 void write_pe_segment(FILE *fp, resource_t *top)
568 int i;
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);
582 /* Write the type level of the tree */
583 for(i = 0; i < rccount; i++)
585 res_count_t *rcp;
586 char *label;
588 rcp = &rcarray[i];
590 /* TypeId */
591 if(rcp->type.type == name_ord)
592 fprintf(fp, "\t.long\t%d\n", rcp->type.name.i_name);
593 else
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);
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);
610 /* Write the name level of the tree */
612 for(i = 0; i < rccount; i++)
614 res_count_t *rcp;
615 char *typelabel;
616 char *namelabel;
617 int j;
619 rcp = &rcarray[i];
621 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
622 fprintf(fp, ".L%s:\n", typelabel);
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++)
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
636 fprintf(fp, "\t.long\t(%s%s_name - %s%s) | 0x80000000\n",
637 prefix,
638 rsc->c_name,
639 prefix,
640 _PEResTab);
642 /* Maybe FIXME: Unescape the tree (ommit 0x80000000) and
643 * put the offset to the resource data entry.
644 * ?? Is unescaping worth while ??
646 /* Offset */
647 namelabel = prep_nid_for_label(rsc->name);
648 fprintf(fp, "\t.long\t(.L%s_%s - %s%s) | 0x80000000\n",
649 typelabel,
650 namelabel,
651 prefix,
652 _PEResTab);
654 free(typelabel);
657 /* Write the language level of the tree */
659 for(i = 0; i < rccount; i++)
661 res_count_t *rcp;
662 char *namelabel;
663 char *typelabel;
664 int j;
666 rcp = &rcarray[i];
667 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
669 for(j = 0; j < rcp->count32; j++)
671 res32_count_t *r32cp = &(rcp->rsc32array[j]);
672 int k;
674 namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
675 fprintf(fp, ".L%s_%s:\n", typelabel, namelabel);
677 fprintf(fp, "\t.long\t0\n"); /* Flags */
678 fprintf(fp, "\t.long\t0x%08lx\n", (long)now); /* TimeDate */
679 fprintf(fp, "\t.long\t0\n"); /* FIXME: must version be filled out? */
680 fprintf(fp, "\t.word\t0, %d\n", r32cp->count);
682 for(k = 0; k < r32cp->count; k++)
684 resource_t *rsc = r32cp->rsc[k];
685 assert(rsc->lan != NULL);
686 /* LanguageId */
687 fprintf(fp, "\t.long\t0x%08x\n", rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
688 /* Offset */
689 fprintf(fp, "\t.long\t.L%s_%s_%d - %s%s\n",
690 typelabel,
691 namelabel,
692 rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0,
693 prefix,
694 _PEResTab);
696 free(namelabel);
698 free(typelabel);
701 /* Write the resource table itself */
702 fprintf(fp, "%s_ResourceDirectory:\n", prefix);
703 fprintf(fp, "\t.globl\t%s_ResourceDirectory\n", prefix);
704 direntries = 0;
706 for(i = 0; i < rccount; i++)
708 res_count_t *rcp;
709 char *namelabel;
710 char *typelabel;
711 int j;
713 rcp = &rcarray[i];
714 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
716 for(j = 0; j < rcp->count32; j++)
718 res32_count_t *r32cp = &(rcp->rsc32array[j]);
719 int k;
721 namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
723 for(k = 0; k < r32cp->count; k++)
725 resource_t *rsc = r32cp->rsc[k];
727 assert(rsc->lan != NULL);
729 fprintf(fp, ".L%s_%s_%d:\n",
730 typelabel,
731 namelabel,
732 rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
734 /* Data RVA */
735 fprintf(fp, "\t.long\t%s%s_data - %s%s\n",
736 prefix,
737 rsc->c_name,
738 prefix,
739 _PEResTab);
740 /* Size */
741 fprintf(fp, "\t.long\t%d\n",
742 rsc->binres->size - rsc->binres->dataidx);
743 /* CodePage */
744 fprintf(fp, "\t.long\t%ld\n", codepage);
745 /* Reserved */
746 fprintf(fp, "\t.long\t0\n");
748 direntries++;
750 free(namelabel);
752 free(typelabel);
757 *****************************************************************************
758 * Function : write_ne_segment
759 * Syntax : void write_ne_segment(FILE *fp, resource_t *top)
760 * Input :
761 * Output :
762 * Description :
763 * Remarks :
764 *****************************************************************************
766 void write_ne_segment(FILE *fp, resource_t *top)
768 int i, j;
770 fprintf(fp, "\t.align\t4\n");
771 fprintf(fp, "%s%s:\n", prefix, _NEResTab);
772 fprintf(fp, "\t.globl\t%s%s\n", prefix, _NEResTab);
774 /* AlignmentShift */
775 fprintf(fp, "\t.word\t%d\n", alignment_pwr);
777 /* TypeInfo */
778 for(i = 0; i < rccount; i++)
780 res_count_t *rcp = &rcarray[i];
782 /* TypeId */
783 if(rcp->type.type == name_ord)
784 fprintf(fp, "\t.word\t0x%04x\n", rcp->type.name.i_name | 0x8000);
785 else
786 fprintf(fp, "\t.word\t%s_%s_typename - %s%s\n",
787 prefix,
788 rcp->type.name.s_name->str.cstr,
789 prefix,
790 _NEResTab);
791 /* ResourceCount */
792 fprintf(fp, "\t.word\t%d\n", rcp->count);
793 /* Reserved */
794 fprintf(fp, "\t.long\t0\n");
795 /* NameInfo */
796 for(j = 0; j < rcp->count; j++)
799 * VERY IMPORTANT:
800 * The offset is relative to the beginning of the NE resource segment
801 * and _NOT_ to the file-beginning. This is because we do not have a
802 * file based resource, but a simulated NE segment. The offset _is_
803 * scaled by the AlignShift field.
804 * All other things are as the MS doc describes (alignment etc.)
806 /* Offset */
807 fprintf(fp, "\t.word\t(%s%s_data - %s%s) >> %d\n",
808 prefix,
809 rcp->rscarray[j]->c_name,
810 prefix,
811 _NEResTab,
812 alignment_pwr);
813 /* Length */
814 fprintf(fp, "\t.word\t%d\n",
815 rcp->rscarray[j]->binres->size - rcp->rscarray[j]->binres->dataidx);
816 /* Flags */
817 fprintf(fp, "\t.word\t0x%04x\n", (WORD)rcp->rscarray[j]->memopt);
818 /* Id */
819 if(rcp->rscarray[j]->name->type == name_ord)
820 fprintf(fp, "\t.word\t0x%04x\n", rcp->rscarray[j]->name->name.i_name | 0x8000);
821 else
822 fprintf(fp, "\t.word\t%s%s_name - %s%s\n",
823 prefix,
824 rcp->rscarray[j]->c_name,
825 prefix,
826 _NEResTab);
827 /* Handle and Usage */
828 fprintf(fp, "\t.word\t0, 0\n");
831 /* EndTypes */
832 fprintf(fp, "\t.word\t0\n");
836 *****************************************************************************
837 * Function : write_rsc_names
838 * Syntax : void write_rsc_names(FILE *fp, resource_t *top)
839 * Input :
840 * Output :
841 * Description :
842 * Remarks :
843 *****************************************************************************
845 void write_rsc_names(FILE *fp, resource_t *top)
847 int i, j;
849 if(win32)
851 /* Write the names */
853 for(i = 0; i < rccount; i++)
855 res_count_t *rcp;
857 rcp = &rcarray[i];
859 if(rcp->type.type == name_str)
861 char *name = prep_nid_for_label(&(rcp->type));
862 fprintf(fp, "%s_%s_typename:\n",
863 prefix,
864 name);
865 write_name_str(fp, &(rcp->type));
868 for(j = 0; j < rcp->count32; j++)
870 resource_t *rsc = rcp->rsc32array[j].rsc[0];
872 if(rsc->name->type == name_str)
874 fprintf(fp, "%s%s_name:\n",
875 prefix,
876 rsc->c_name);
877 write_name_str(fp, rsc->name);
882 else
884 /* ResourceNames */
885 for(i = 0; i < rccount; i++)
887 res_count_t *rcp = &rcarray[i];
889 for(j = 0; j < rcp->count; j++)
891 if(rcp->type.type == name_str)
893 fprintf(fp, "%s_%s_typename:\n",
894 prefix,
895 rcp->type.name.s_name->str.cstr);
896 write_name_str(fp, &(rcp->type));
898 if(rcp->rscarray[j]->name->type == name_str)
900 fprintf(fp, "%s%s_name:\n",
901 prefix,
902 rcp->rscarray[j]->c_name);
903 write_name_str(fp, rcp->rscarray[j]->name);
907 /* EndNames */
909 /* This is to end the NE resource table */
910 if(create_dir)
911 fprintf(fp, "\t.byte\t0\n");
914 fprintf(fp, "\n");
918 *****************************************************************************
919 * Function : write_s_file
920 * Syntax : void write_s_file(char *outname, resource_t *top)
921 * Input :
922 * outname - Filename to write to
923 * top - The resource-tree to convert
924 * Output :
925 * Description :
926 * Remarks :
927 *****************************************************************************
929 void write_s_file(char *outname, resource_t *top)
931 FILE *fo;
932 resource_t *rsc;
934 fo = fopen(outname, "wt");
935 if(!fo)
937 error("Could not open %s\n", outname);
938 return;
942 char *s, *p;
943 now = time(NULL);
944 s = ctime(&now);
945 p = strchr(s, '\n');
946 if(p) *p = '\0';
947 fprintf(fo, s_file_head_str, input_name ? input_name : "stdin",
948 cmdline, s);
951 /* Get an idea how many we have and restructure the tables */
952 count_resources(top);
954 /* First write the segment tables */
955 if(create_dir)
957 if(win32)
958 write_pe_segment(fo, top);
959 else
960 write_ne_segment(fo, top);
963 /* Dump the names */
964 write_rsc_names(fo, top);
966 if(create_dir)
967 fprintf(fo, ".LResTabEnd:\n");
969 if(!indirect_only)
971 /* Write the resource data */
972 fprintf(fo, "\n/* Resource binary data */\n\n");
973 for(rsc = top; rsc; rsc = rsc->next)
975 if(!rsc->binres)
976 continue;
978 fprintf(fo, "\t.align\t%d\n", win32 ? 4 : alignment);
979 fprintf(fo, "%s%s_data:\n", prefix, rsc->c_name);
980 if(global)
981 fprintf(fo, "\t.globl\t%s%s_data\n", prefix, rsc->c_name);
983 write_s_res(fo, rsc->binres);
985 fprintf(fo, "\n");
988 if(create_dir)
990 /* Add a resource descriptor for built-in and elf-dlls */
991 fprintf(fo, "\t.align\t4\n");
992 fprintf(fo, "%s_ResourceDescriptor:\n", prefix);
993 fprintf(fo, "\t.globl\t%s_ResourceDescriptor\n", prefix);
994 fprintf(fo, "%s_ResourceTable:\n", prefix);
995 if(global)
996 fprintf(fo, "\t.globl\t%s_ResourceTable\n", prefix);
997 fprintf(fo, "\t.long\t%s%s\n", prefix, win32 ? _PEResTab : _NEResTab);
998 fprintf(fo, "%s_NumberOfResources:\n", prefix);
999 if(global)
1000 fprintf(fo, "\t.globl\t%s_NumberOfResources\n", prefix);
1001 fprintf(fo, "\t.long\t%d\n", direntries);
1002 fprintf(fo, "%s_ResourceSectionSize:\n", prefix);
1003 if(global)
1004 fprintf(fo, "\t.globl\t%s_ResourceSectionSize\n", prefix);
1005 fprintf(fo, "\t.long\t.LResTabEnd - %s%s\n", prefix, win32 ? _PEResTab : _NEResTab);
1006 if(win32)
1008 fprintf(fo, "%s_ResourcesEntries:\n", prefix);
1009 if(global)
1010 fprintf(fo, "\t.globl\t%s_ResourcesEntries\n", prefix);
1011 fprintf(fo, "\t.long\t%s_ResourceDirectory\n", prefix);
1016 if(indirect)
1018 /* Write the indirection structures */
1019 fprintf(fo, "\n/* Resource indirection structures */\n\n");
1020 fprintf(fo, "\t.align\t4\n");
1021 for(rsc = top; rsc; rsc = rsc->next)
1023 int type;
1024 char *type_name = NULL;
1026 if(!rsc->binres)
1027 continue;
1029 switch(rsc->type)
1031 case res_menex:
1032 type = WRC_RT_MENU;
1033 break;
1034 case res_dlgex:
1035 type = WRC_RT_DIALOG;
1036 break;
1037 case res_usr:
1038 assert(rsc->res.usr->type != NULL);
1039 type_name = prep_nid_for_label(rsc->res.usr->type);
1040 type = 0;
1041 break;
1042 default:
1043 type = rsc->type;
1047 * This follows a structure like:
1048 * struct wrc_resource {
1049 * INT32 id;
1050 * RSCNAME *resname;
1051 * INT32 restype;
1052 * RSCNAME *typename;
1053 * void *data;
1054 * UINT32 datasize;
1055 * };
1056 * The 'RSCNAME' is a pascal-style string where the
1057 * first byte/word denotes the size and the rest the string
1058 * itself.
1060 fprintf(fo, "%s%s:\n", prefix, rsc->c_name);
1061 if(global)
1062 fprintf(fo, "\t.globl\t%s%s\n", prefix, rsc->c_name);
1063 fprintf(fo, "\t.long\t%d, %s%s%s, %d, %s%s%s%s, %s%s_data, %d\n",
1064 rsc->name->type == name_ord ? rsc->name->name.i_name : 0,
1065 rsc->name->type == name_ord ? "0" : prefix,
1066 rsc->name->type == name_ord ? "" : rsc->c_name,
1067 rsc->name->type == name_ord ? "" : "_name",
1068 type,
1069 type ? "0" : prefix,
1070 type ? "" : "_",
1071 type ? "" : type_name,
1072 type ? "" : "_typename",
1073 prefix,
1074 rsc->c_name,
1075 rsc->binres->size - rsc->binres->dataidx);
1076 fprintf(fo, "\n");
1078 fprintf(fo, "\n");
1080 /* Write the indirection table */
1081 fprintf(fo, "/* Resource indirection table */\n\n");
1082 fprintf(fo, "\t.align\t4\n");
1083 fprintf(fo, "%s%s:\n", prefix, _ResTable);
1084 fprintf(fo, "\t.globl\t%s%s\n", prefix, _ResTable);
1085 for(rsc = top; rsc; rsc = rsc->next)
1087 fprintf(fo, "\t.long\t%s%s\n", prefix, rsc->c_name);
1089 fprintf(fo, "\t.long\t0\n");
1090 fprintf(fo, "\n");
1093 if(auto_register)
1094 fprintf(fo, s_file_autoreg_str, prefix, _ResTable);
1096 fprintf(fo, s_file_tail_str);
1097 fclose(fo);
1101 *****************************************************************************
1102 * Function : write_h_file
1103 * Syntax : void write_h_file(char *outname, resource_t *top)
1104 * Input :
1105 * outname - Filename to write to
1106 * top - The resource-tree to convert
1107 * Output :
1108 * Description :
1109 * Remarks :
1110 *****************************************************************************
1112 void write_h_file(char *outname, resource_t *top)
1114 FILE *fo;
1115 resource_t *rsc;
1116 char *h_prefix;
1118 #ifdef NEED_UNDERSCORE_PREFIX
1119 h_prefix = prefix + 1;
1120 #else
1121 h_prefix = prefix;
1122 #endif
1124 fo = fopen(outname, "wt");
1125 if(!fo)
1127 error("Could not open %s\n", outname);
1130 time(&now);
1131 fprintf(fo, h_file_head_str, input_name ? input_name : "stdin",
1132 cmdline, ctime(&now), (long)now, (long)now);
1134 /* First write the segment tables reference */
1135 if(create_dir)
1137 fprintf(fo, "extern %schar %s%s[];\n\n",
1138 constant ? "const " : "",
1139 h_prefix,
1140 win32 ? _PEResTab : _NEResTab);
1143 /* Write the resource data */
1144 for(rsc = top; global && rsc; rsc = rsc->next)
1146 if(!rsc->binres)
1147 continue;
1149 fprintf(fo, "extern %schar %s%s_data[];\n",
1150 constant ? "const " : "",
1151 h_prefix,
1152 rsc->c_name);
1155 if(indirect)
1157 if(global)
1158 fprintf(fo, "\n");
1160 /* Write the indirection structures */
1161 for(rsc = top; global && rsc; rsc = rsc->next)
1163 fprintf(fo, "extern %swrc_resource%d_t %s%s;\n",
1164 constant ? "const " : "",
1165 win32 ? 32 : 16,
1166 h_prefix,
1167 rsc->c_name);
1170 if(global)
1171 fprintf(fo, "\n");
1173 /* Write the indirection table */
1174 fprintf(fo, "extern %swrc_resource%d_t %s%s[];\n\n",
1175 constant ? "const " : "",
1176 win32 ? 32 : 16,
1177 h_prefix,
1178 _ResTable);
1181 fprintf(fo, h_file_tail_str);
1182 fclose(fo);