Fixed another regression in PlaySound.
[wine.git] / tools / wrc / writeres.c
blob0c7ed0a4f1f19d1a444b737f52b2ecaf803f05e0
1 /*
2 * Write .res, .s and .h file(s) from a resource-tree
4 * Copyright 1998 Bertho A. Stultiens
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
28 #include "wine/unicode.h"
29 #include "wrc.h"
30 #include "writeres.h"
31 #include "genres.h"
32 #include "newstruc.h"
33 #include "utils.h"
35 #ifdef NEED_UNDERSCORE_PREFIX
36 char Underscore[] = "_";
37 #else
38 char Underscore[] = "";
39 #endif
41 static char s_file_head_str[] =
42 "/* This file is generated with wrc version " WRC_FULLVERSION ". Do not edit! */\n"
43 "/* Source : %s */\n"
44 "/* Cmdline: %s */\n"
45 "/* Date : %s */\n"
46 "\n"
47 "\t.data\n"
48 "\n"
51 static char s_file_tail_str[] =
52 "/* <eof> */\n"
53 "\n"
56 static char s_file_autoreg_str[] =
57 "\t.text\n"
58 ".LAuto_Register:\n"
59 "\tpushl\t$%s%s\n"
60 #ifdef NEED_UNDERSCORE_PREFIX
61 "\tcall\t_LIBRES_RegisterResources\n"
62 #else
63 "\tcall\tLIBRES_RegisterResources\n"
64 #endif
65 "\taddl\t$4,%%esp\n"
66 "\tret\n\n"
67 #ifdef __NetBSD__
68 ".stabs \"___CTOR_LIST__\",22,0,0,.LAuto_Register\n\n"
69 #else
70 "\t.section .ctors,\"aw\"\n"
71 "\t.long\t.LAuto_Register\n\n"
72 #endif
75 static char h_file_head_str[] =
76 "/*\n"
77 " * This file is generated with wrc version " WRC_FULLVERSION ". Do not edit!\n"
78 " * Source : %s\n"
79 " * Cmdline: %s\n"
80 " * Date : %s"
81 " */\n"
82 "\n"
83 "#ifndef __%08lx_H\n" /* This becomes the date of compile */
84 "#define __%08lx_H\n"
85 "\n"
86 "#include <wrc_rsc.h>\n"
87 "\n"
90 static char h_file_tail_str[] =
91 "#endif\n"
92 "/* <eof> */\n\n"
95 char _NEResTab[] = "_NEResTab";
96 char _PEResTab[] = "_PEResTab";
97 char _ResTable[] = "_ResTable";
99 /* Variables used for resource sorting */
100 res_count_t *rcarray = NULL; /* Type-level count array */
101 int rccount = 0; /* Nr of entries in the type-level array */
102 int n_id_entries = 0; /* win32 only: Nr of unique ids in the type-level array */
103 int n_name_entries = 0; /* win32 only: Nr of unique namess in the type-level array */
105 static int direntries; /* win32 only: Total number of unique resources */
108 *****************************************************************************
109 * Function : write_resfile
110 * Syntax : void write_resfile(char *outname, resource_t *top)
111 * Input :
112 * outname - Filename to write to
113 * top - The resource-tree to convert
114 * Output :
115 * Description :
116 * Remarks :
117 *****************************************************************************
119 void write_resfile(char *outname, resource_t *top)
121 FILE *fo;
122 int ret;
123 char zeros[3] = {0, 0, 0};
125 fo = fopen(outname, "wb");
126 if(!fo)
128 error("Could not open %s\n", outname);
131 if(win32)
133 /* Put an empty resource first to signal win32 format */
134 res_t *res = new_res();
135 put_dword(res, 0); /* ResSize */
136 put_dword(res, 0x00000020); /* HeaderSize */
137 put_word(res, 0xffff); /* ResType */
138 put_word(res, 0);
139 put_word(res, 0xffff); /* ResName */
140 put_word(res, 0);
141 put_dword(res, 0); /* DataVersion */
142 put_word(res, 0); /* Memory options */
143 put_word(res, 0); /* Language */
144 put_dword(res, 0); /* Version */
145 put_dword(res, 0); /* Charateristics */
146 ret = fwrite(res->data, 1, res->size, fo);
147 if(ret != res->size)
149 fclose(fo);
150 error("Error writing %s", outname);
152 free(res);
155 for(; top; top = top->next)
157 if(!top->binres)
158 continue;
160 ret = fwrite(top->binres->data, 1, top->binres->size, fo);
161 if(ret != top->binres->size)
163 fclose(fo);
164 error("Error writing %s", outname);
166 if(win32 && (top->binres->size & 0x03))
168 /* Write padding */
169 ret = fwrite(zeros, 1, 4 - (top->binres->size & 0x03), fo);
170 if(ret != 4 - (top->binres->size & 0x03))
172 fclose(fo);
173 error("Error writing %s", outname);
177 fclose(fo);
181 *****************************************************************************
182 * Function : write_s_res
183 * Syntax : void write_s_res(FILE *fp, res_t *res)
184 * Input :
185 * Output :
186 * Description :
187 * Remarks :
188 *****************************************************************************
190 #define BYTESPERLINE 8
191 static void write_s_res(FILE *fp, res_t *res)
193 int idx = res->dataidx;
194 int end = res->size;
195 int rest = (end - idx) % BYTESPERLINE;
196 int lines = (end - idx) / BYTESPERLINE;
197 int i, j;
199 for(i = 0 ; i < lines; i++)
201 fprintf(fp, "\t.byte\t");
202 for(j = 0; j < BYTESPERLINE; j++, idx++)
204 fprintf(fp, "0x%02x%s", res->data[idx] & 0xff,
205 j == BYTESPERLINE-1 ? "" : ", ");
207 fprintf(fp, "\n");
209 if(rest)
211 fprintf(fp, "\t.byte\t");
212 for(j = 0; j < rest; j++, idx++)
214 fprintf(fp, "0x%02x%s", res->data[idx] & 0xff,
215 j == rest-1 ? "" : ", ");
217 fprintf(fp, "\n");
220 #undef BYTESPERLINE
223 *****************************************************************************
224 * Function : write_name_str
225 * Syntax : void write_name_str(FILE *fp, name_id_t *nid)
226 * Input :
227 * Output :
228 * Description :
229 * Remarks : One level self recursive for string type conversion
230 *****************************************************************************
232 static void write_name_str(FILE *fp, name_id_t *nid)
234 res_t res;
235 assert(nid->type == name_str);
237 if(!win32 && nid->name.s_name->type == str_char)
239 res.size = strlen(nid->name.s_name->str.cstr);
240 if(res.size > 254)
241 error("Can't write strings larger than 254 bytes");
242 if(res.size == 0)
243 internal_error(__FILE__, __LINE__, "Attempt to write empty string");
244 res.dataidx = 0;
245 res.data = (char *)xmalloc(1 + res.size + 1);
246 res.data[0] = (char)res.size;
247 res.size++; /* We need to write the length byte as well */
248 strcpy(res.data+1, nid->name.s_name->str.cstr);
249 write_s_res(fp, &res);
250 free(res.data);
252 else if(!win32 && nid->name.s_name->type == str_unicode)
254 name_id_t lnid;
255 string_t str;
257 lnid.type = name_str;
258 lnid.name.s_name = &str;
259 str.type = str_char;
260 str.str.cstr = dupwstr2cstr(nid->name.s_name->str.wstr);
261 write_name_str(fp, &lnid);
262 free(str.str.cstr);
264 else if(win32 && nid->name.s_name->type == str_char)
266 name_id_t lnid;
267 string_t str;
269 lnid.type = name_str;
270 lnid.name.s_name = &str;
271 str.type = str_unicode;
272 str.str.wstr = dupcstr2wstr(nid->name.s_name->str.cstr);
273 write_name_str(fp, &lnid);
274 free(str.str.wstr);
276 else if(win32 && nid->name.s_name->type == str_unicode)
278 res.size = strlenW(nid->name.s_name->str.wstr);
279 if(res.size > 65534)
280 error("Can't write strings larger than 65534 characters");
281 if(res.size == 0)
282 internal_error(__FILE__, __LINE__, "Attempt to write empty string");
283 res.dataidx = 0;
284 res.data = (char *)xmalloc(2 + (res.size + 1) * 2);
285 ((short *)res.data)[0] = (short)res.size;
286 strcpyW((WCHAR *)(res.data+2), nid->name.s_name->str.wstr);
287 res.size *= 2; /* Function writes bytes, not shorts... */
288 res.size += 2; /* We need to write the length word as well */
289 write_s_res(fp, &res);
290 free(res.data);
292 else
294 internal_error(__FILE__, __LINE__, "Hmm, requested to write a string of unknown type %d",
295 nid->name.s_name->type);
300 *****************************************************************************
301 * Function : find_counter
302 * Syntax : res_count_t *find_counter(name_id_t *type)
303 * Input :
304 * Output :
305 * Description :
306 * Remarks :
307 *****************************************************************************
309 static res_count_t *find_counter(name_id_t *type)
311 int i;
312 for(i = 0; i < rccount; i++)
314 if(!compare_name_id(type, &(rcarray[i].type)))
315 return &rcarray[i];
317 return NULL;
321 *****************************************************************************
322 * Function : count_resources
323 * Syntax : res_count_t *count_resources(resource_t *top)
324 * Input :
325 * Output :
326 * Description :
327 * Remarks : The whole lot is converted into arrays because they are
328 * easy sortable. Makes the lot almost unreadable, but it
329 * works (I hope). Basically you have to keep in mind that
330 * the lot is a three-dimensional structure for win32 and a
331 * two-dimensional structure for win16.
332 *****************************************************************************
334 #define RCT(v) (*((resource_t **)(v)))
335 /* qsort sorting function */
336 static int sort_name_id(const void *e1, const void *e2)
338 return compare_name_id(RCT(e1)->name, RCT(e2)->name);
341 static int sort_language(const void *e1, const void *e2)
343 assert((RCT(e1)->lan) != NULL);
344 assert((RCT(e2)->lan) != NULL);
346 return MAKELANGID(RCT(e1)->lan->id, RCT(e1)->lan->sub)
347 - MAKELANGID(RCT(e2)->lan->id, RCT(e2)->lan->sub);
349 #undef RCT
350 #define RCT(v) ((res_count_t *)(v))
351 static int sort_type(const void *e1, const void *e2)
353 return compare_name_id(&(RCT(e1)->type), &(RCT(e2)->type));
355 #undef RCT
357 static void count_resources(resource_t *top)
359 resource_t *rsc;
360 res_count_t *rcp;
361 name_id_t nid;
362 int i, j;
364 for(rsc = top; rsc; rsc = rsc->next)
366 if(!rsc->binres)
367 continue;
368 switch(rsc->type)
370 case res_dlgex:
371 nid.name.i_name = WRC_RT_DIALOG;
372 nid.type = name_ord;
373 break;
374 case res_menex:
375 nid.name.i_name = WRC_RT_MENU;
376 nid.type = name_ord;
377 break;
378 case res_usr:
379 nid = *(rsc->res.usr->type);
380 break;
381 default:
382 nid.name.i_name = rsc->type;
383 nid.type = name_ord;
386 if((rcp = find_counter(&nid)) == NULL)
388 /* Count the number of uniq ids and names */
390 if(nid.type == name_ord)
391 n_id_entries++;
392 else
393 n_name_entries++;
395 if(!rcarray)
397 rcarray = (res_count_t *)xmalloc(sizeof(res_count_t));
398 rccount = 1;
399 rcarray[0].count = 1;
400 rcarray[0].type = nid;
401 rcarray[0].rscarray = (resource_t **)xmalloc(sizeof(resource_t *));
402 rcarray[0].rscarray[0] = rsc;
404 else
406 rccount++;
407 rcarray = (res_count_t *)xrealloc(rcarray, rccount * sizeof(res_count_t));
408 rcarray[rccount-1].count = 1;
409 rcarray[rccount-1].type = nid;
410 rcarray[rccount-1].rscarray = (resource_t **)xmalloc(sizeof(resource_t *));
411 rcarray[rccount-1].rscarray[0] = rsc;
414 else
416 rcp->count++;
417 rcp->rscarray = (resource_t **)xrealloc(rcp->rscarray, rcp->count * sizeof(resource_t *));
418 rcp->rscarray[rcp->count-1] = rsc;
422 if(!win32)
424 /* We're done, win16 requires no special sorting */
425 return;
428 /* We now have a unsorted list of types with an array of res_count_t
429 * in rcarray[0..rccount-1]. And we have names of one type in the
430 * rcarray[x].rsc[0..rcarray[x].count-1] arrays.
431 * The list needs to be sorted for win32's top level tree structure.
434 /* Sort the types */
435 if(rccount > 1)
436 qsort(rcarray, rccount, sizeof(rcarray[0]), sort_type);
438 /* Now sort the name-id arrays */
439 for(i = 0; i < rccount; i++)
441 if(rcarray[i].count > 1)
442 qsort(rcarray[i].rscarray, rcarray[i].count, sizeof(rcarray[0].rscarray[0]), sort_name_id);
445 /* Now split the name-id arrays into name/language
446 * subs. Don't look at the awfull expressions...
447 * We do this by taking the array elements out of rscarray and putting
448 * together a new array in rsc32array.
450 for(i = 0; i < rccount; i++)
452 res_count_t *rcap;
454 assert(rcarray[i].count >= 1);
456 /* rcap points to the current type we are dealing with */
457 rcap = &(rcarray[i]);
459 /* Insert the first name-id */
460 rcap->rsc32array = (res32_count_t *)xmalloc(sizeof(res32_count_t));
461 rcap->count32 = 1;
462 rcap->rsc32array[0].rsc = (resource_t **)xmalloc(sizeof(resource_t *));
463 rcap->rsc32array[0].count = 1;
464 rcap->rsc32array[0].rsc[0] = rcap->rscarray[0];
465 if(rcap->rscarray[0]->name->type == name_ord)
467 rcap->n_id_entries = 1;
468 rcap->n_name_entries = 0;
470 else
472 rcap->n_id_entries = 0;
473 rcap->n_name_entries = 1;
476 /* Now loop over the resting resources of the current type
477 * to find duplicate names (which should have different
478 * languages).
480 for(j = 1; j < rcap->count; j++)
482 res32_count_t *r32cp;
484 /* r32cp points to the current res32_count structure
485 * that holds the resource name we are processing.
487 r32cp = &(rcap->rsc32array[rcap->count32-1]);
489 if(!compare_name_id(r32cp->rsc[0]->name, rcarray[i].rscarray[j]->name))
491 /* Names are the same, add to list */
492 r32cp->count++;
493 r32cp->rsc = (resource_t **)xrealloc(r32cp->rsc, r32cp->count * sizeof(resource_t *));
494 r32cp->rsc[r32cp->count-1] = rcap->rscarray[j];
496 else
498 /* New name-id, sort the old one by
499 * language and create new list
501 if(r32cp->count > 1)
502 qsort(r32cp->rsc, r32cp->count, sizeof(r32cp->rsc[0]), sort_language);
503 rcap->count32++;
504 rcap->rsc32array = (res32_count_t*)xrealloc(rcap->rsc32array, rcap->count32 * sizeof(res32_count_t));
505 rcap->rsc32array[rcap->count32-1].rsc = (resource_t **)xmalloc(sizeof(resource_t *));
506 rcap->rsc32array[rcap->count32-1].count = 1;
507 rcap->rsc32array[rcap->count32-1].rsc[0] = rcap->rscarray[j];
509 if(rcap->rscarray[j]->name->type == name_ord)
510 rcap->n_id_entries++;
511 else
512 rcap->n_name_entries++;
515 /* Also sort the languages of the last name group */
516 if(rcap->rsc32array[rcap->count32-1].count > 1)
517 qsort(rcap->rsc32array[rcap->count32-1].rsc,
518 rcap->rsc32array[rcap->count32-1].count,
519 sizeof(rcap->rsc32array[rcap->count32-1].rsc[0]),
520 sort_language);
525 *****************************************************************************
526 * Function : write_pe_segment
527 * Syntax : void write_pe_segment(FILE *fp)
528 * Input :
529 * Output :
530 * Description :
531 * Remarks :
532 *****************************************************************************
534 static void write_pe_segment(FILE *fp)
536 int i;
538 fprintf(fp, "\t.align\t4\n");
539 fprintf(fp, "%s%s:\n", prefix, _PEResTab);
540 fprintf(fp, "\t.globl\t%s%s\n", prefix, _PEResTab);
541 /* Flags */
542 fprintf(fp, "\t.long\t0\n");
543 /* Time/Date stamp */
544 fprintf(fp, "\t.long\t0x%08lx\n", (long)now);
545 /* Version */
546 fprintf(fp, "\t.long\t0\n"); /* FIXME: must version be filled out? */
547 /* # of id entries, # of name entries */
548 fprintf(fp, "\t.short\t%d, %d\n", n_name_entries, n_id_entries);
550 /* Write the type level of the tree */
551 for(i = 0; i < rccount; i++)
553 res_count_t *rcp;
554 char *label;
556 rcp = &rcarray[i];
558 /* TypeId */
559 if(rcp->type.type == name_ord)
560 fprintf(fp, "\t.long\t%d\n", rcp->type.name.i_name);
561 else
563 char *name = prep_nid_for_label(&(rcp->type));
564 fprintf(fp, "\t.long\t(%s_%s_typename - %s%s) | 0x80000000\n",
565 prefix,
566 name,
567 prefix,
568 _PEResTab);
570 /* Offset */
571 label = prep_nid_for_label(&(rcp->type));
572 fprintf(fp, "\t.long\t(.L%s - %s%s) | 0x80000000\n",
573 label,
574 prefix,
575 _PEResTab);
578 /* Write the name level of the tree */
580 for(i = 0; i < rccount; i++)
582 res_count_t *rcp;
583 char *typelabel;
584 char *namelabel;
585 int j;
587 rcp = &rcarray[i];
589 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
590 fprintf(fp, ".L%s:\n", typelabel);
592 fprintf(fp, "\t.long\t0\n"); /* Flags */
593 fprintf(fp, "\t.long\t0x%08lx\n", (long)now); /* TimeDate */
594 fprintf(fp, "\t.long\t0\n"); /* FIXME: must version be filled out? */
595 fprintf(fp, "\t.short\t%d, %d\n", rcp->n_name_entries, rcp->n_id_entries);
596 for(j = 0; j < rcp->count32; j++)
598 resource_t *rsc = rcp->rsc32array[j].rsc[0];
599 /* NameId */
600 if(rsc->name->type == name_ord)
601 fprintf(fp, "\t.long\t%d\n", rsc->name->name.i_name);
602 else
604 fprintf(fp, "\t.long\t(%s%s_name - %s%s) | 0x80000000\n",
605 prefix,
606 rsc->c_name,
607 prefix,
608 _PEResTab);
610 /* Maybe FIXME: Unescape the tree (ommit 0x80000000) and
611 * put the offset to the resource data entry.
612 * ?? Is unescaping worth while ??
614 /* Offset */
615 namelabel = prep_nid_for_label(rsc->name);
616 fprintf(fp, "\t.long\t(.L%s_%s - %s%s) | 0x80000000\n",
617 typelabel,
618 namelabel,
619 prefix,
620 _PEResTab);
622 free(typelabel);
625 /* Write the language level of the tree */
627 for(i = 0; i < rccount; i++)
629 res_count_t *rcp;
630 char *namelabel;
631 char *typelabel;
632 int j;
634 rcp = &rcarray[i];
635 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
637 for(j = 0; j < rcp->count32; j++)
639 res32_count_t *r32cp = &(rcp->rsc32array[j]);
640 int k;
642 namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
643 fprintf(fp, ".L%s_%s:\n", typelabel, namelabel);
645 fprintf(fp, "\t.long\t0\n"); /* Flags */
646 fprintf(fp, "\t.long\t0x%08lx\n", (long)now); /* TimeDate */
647 fprintf(fp, "\t.long\t0\n"); /* FIXME: must version be filled out? */
648 fprintf(fp, "\t.short\t0, %d\n", r32cp->count);
650 for(k = 0; k < r32cp->count; k++)
652 resource_t *rsc = r32cp->rsc[k];
653 assert(rsc->lan != NULL);
654 /* LanguageId */
655 fprintf(fp, "\t.long\t0x%08x\n", rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
656 /* Offset */
657 fprintf(fp, "\t.long\t.L%s_%s_%d - %s%s\n",
658 typelabel,
659 namelabel,
660 rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0,
661 prefix,
662 _PEResTab);
664 free(namelabel);
666 free(typelabel);
669 /* Write the resource table itself */
670 fprintf(fp, "%s_ResourceDirectory:\n", prefix);
671 fprintf(fp, "\t.globl\t%s_ResourceDirectory\n", prefix);
672 direntries = 0;
674 for(i = 0; i < rccount; i++)
676 res_count_t *rcp;
677 char *namelabel;
678 char *typelabel;
679 int j;
681 rcp = &rcarray[i];
682 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
684 for(j = 0; j < rcp->count32; j++)
686 res32_count_t *r32cp = &(rcp->rsc32array[j]);
687 int k;
689 namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
691 for(k = 0; k < r32cp->count; k++)
693 resource_t *rsc = r32cp->rsc[k];
695 assert(rsc->lan != NULL);
697 fprintf(fp, ".L%s_%s_%d:\n",
698 typelabel,
699 namelabel,
700 rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
702 /* Data RVA */
703 fprintf(fp, "\t.long\t%s%s_data - %s%s\n",
704 prefix,
705 rsc->c_name,
706 prefix,
707 _PEResTab);
708 /* Size */
709 fprintf(fp, "\t.long\t%d\n",
710 rsc->binres->size - rsc->binres->dataidx);
711 /* CodePage */
712 fprintf(fp, "\t.long\t%ld\n", codepage);
713 /* Reserved */
714 fprintf(fp, "\t.long\t0\n");
716 direntries++;
718 free(namelabel);
720 free(typelabel);
725 *****************************************************************************
726 * Function : write_ne_segment
727 * Syntax : void write_ne_segment(FILE *fp)
728 * Input :
729 * Output :
730 * Description :
731 * Remarks :
732 *****************************************************************************
734 static void write_ne_segment(FILE *fp)
736 int i, j;
738 fprintf(fp, "\t.align\t4\n");
739 fprintf(fp, "%s%s:\n", prefix, _NEResTab);
740 fprintf(fp, "\t.globl\t%s%s\n", prefix, _NEResTab);
742 /* AlignmentShift */
743 fprintf(fp, "\t.short\t%d\n", alignment_pwr);
745 /* TypeInfo */
746 for(i = 0; i < rccount; i++)
748 res_count_t *rcp = &rcarray[i];
750 /* TypeId */
751 if(rcp->type.type == name_ord)
752 fprintf(fp, "\t.short\t0x%04x\n", rcp->type.name.i_name | 0x8000);
753 else
754 fprintf(fp, "\t.short\t%s_%s_typename - %s%s\n",
755 prefix,
756 rcp->type.name.s_name->str.cstr,
757 prefix,
758 _NEResTab);
759 /* ResourceCount */
760 fprintf(fp, "\t.short\t%d\n", rcp->count);
761 /* Reserved */
762 fprintf(fp, "\t.long\t0\n");
763 /* NameInfo */
764 for(j = 0; j < rcp->count; j++)
767 * VERY IMPORTANT:
768 * The offset is relative to the beginning of the NE resource segment
769 * and _NOT_ to the file-beginning. This is because we do not have a
770 * file based resource, but a simulated NE segment. The offset _is_
771 * scaled by the AlignShift field.
772 * All other things are as the MS doc describes (alignment etc.)
774 /* Offset */
775 fprintf(fp, "\t.short\t(%s%s_data - %s%s) >> %d\n",
776 prefix,
777 rcp->rscarray[j]->c_name,
778 prefix,
779 _NEResTab,
780 alignment_pwr);
781 /* Length */
782 fprintf(fp, "\t.short\t%d\n",
783 (rcp->rscarray[j]->binres->size - rcp->rscarray[j]->binres->dataidx + alignment - 1) >> alignment_pwr);
784 /* Flags */
785 fprintf(fp, "\t.short\t0x%04x\n", (WORD)rcp->rscarray[j]->memopt);
786 /* Id */
787 if(rcp->rscarray[j]->name->type == name_ord)
788 fprintf(fp, "\t.short\t0x%04x\n", rcp->rscarray[j]->name->name.i_name | 0x8000);
789 else
790 fprintf(fp, "\t.short\t%s%s_name - %s%s\n",
791 prefix,
792 rcp->rscarray[j]->c_name,
793 prefix,
794 _NEResTab);
795 /* Handle and Usage */
796 fprintf(fp, "\t.short\t0, 0\n");
799 /* EndTypes */
800 fprintf(fp, "\t.short\t0\n");
804 *****************************************************************************
805 * Function : write_rsc_names
806 * Syntax : void write_rsc_names(FILE *fp)
807 * Input :
808 * Output :
809 * Description :
810 * Remarks :
811 *****************************************************************************
813 static void write_rsc_names(FILE *fp)
815 int i, j;
817 if(win32)
819 /* Write the names */
821 for(i = 0; i < rccount; i++)
823 res_count_t *rcp;
825 rcp = &rcarray[i];
827 if(rcp->type.type == name_str)
829 char *name = prep_nid_for_label(&(rcp->type));
830 fprintf(fp, "%s_%s_typename:\n",
831 prefix,
832 name);
833 write_name_str(fp, &(rcp->type));
836 for(j = 0; j < rcp->count32; j++)
838 resource_t *rsc = rcp->rsc32array[j].rsc[0];
840 if(rsc->name->type == name_str)
842 fprintf(fp, "%s%s_name:\n",
843 prefix,
844 rsc->c_name);
845 write_name_str(fp, rsc->name);
850 else
852 /* ResourceNames */
853 for(i = 0; i < rccount; i++)
855 res_count_t *rcp = &rcarray[i];
857 if(rcp->type.type == name_str)
859 fprintf(fp, "%s_%s_typename:\n",
860 prefix,
861 rcp->type.name.s_name->str.cstr);
862 write_name_str(fp, &(rcp->type));
864 for(j = 0; j < rcp->count; j++)
866 if(rcp->rscarray[j]->name->type == name_str)
868 fprintf(fp, "%s%s_name:\n",
869 prefix,
870 rcp->rscarray[j]->c_name);
871 write_name_str(fp, rcp->rscarray[j]->name);
875 /* EndNames */
877 /* This is to end the NE resource table */
878 if(create_dir)
879 fprintf(fp, "\t.byte\t0\n");
882 fprintf(fp, "\n");
886 *****************************************************************************
887 * Function : write_s_file
888 * Syntax : void write_s_file(char *outname, resource_t *top)
889 * Input :
890 * outname - Filename to write to
891 * top - The resource-tree to convert
892 * Output :
893 * Description :
894 * Remarks :
895 *****************************************************************************
897 void write_s_file(char *outname, resource_t *top)
899 FILE *fo;
900 resource_t *rsc;
902 fo = fopen(outname, "wt");
903 if(!fo)
905 error("Could not open %s\n", outname);
906 return;
910 char *s, *p;
911 s = ctime(&now);
912 p = strchr(s, '\n');
913 if(p) *p = '\0';
914 fprintf(fo, s_file_head_str, input_name ? input_name : "stdin",
915 cmdline, s);
918 /* Get an idea how many we have and restructure the tables */
919 count_resources(top);
921 /* First write the segment tables */
922 if(create_dir)
924 if(win32)
925 write_pe_segment(fo);
926 else
927 write_ne_segment(fo);
930 /* Dump the names */
931 write_rsc_names(fo);
933 if(create_dir)
934 fprintf(fo, ".LResTabEnd:\n");
936 if(!indirect_only)
938 /* Write the resource data */
939 fprintf(fo, "\n/* Resource binary data */\n\n");
940 for(rsc = top; rsc; rsc = rsc->next)
942 if(!rsc->binres)
943 continue;
945 fprintf(fo, "\t.align\t%d\n", win32 ? 4 : alignment);
946 fprintf(fo, "%s%s_data:\n", prefix, rsc->c_name);
947 if(global)
948 fprintf(fo, "\t.globl\t%s%s_data\n", prefix, rsc->c_name);
950 write_s_res(fo, rsc->binres);
952 fprintf(fo, "\n");
955 if(create_dir)
957 /* Add a resource descriptor for built-in and elf-dlls */
958 fprintf(fo, "\t.align\t4\n");
959 fprintf(fo, "%s_ResourceDescriptor:\n", prefix);
960 fprintf(fo, "\t.globl\t%s_ResourceDescriptor\n", prefix);
961 fprintf(fo, "%s_ResourceTable:\n", prefix);
962 if(global)
963 fprintf(fo, "\t.globl\t%s_ResourceTable\n", prefix);
964 fprintf(fo, "\t.long\t%s%s\n", prefix, win32 ? _PEResTab : _NEResTab);
965 fprintf(fo, "%s_NumberOfResources:\n", prefix);
966 if(global)
967 fprintf(fo, "\t.globl\t%s_NumberOfResources\n", prefix);
968 fprintf(fo, "\t.long\t%d\n", direntries);
969 fprintf(fo, "%s_ResourceSectionSize:\n", prefix);
970 if(global)
971 fprintf(fo, "\t.globl\t%s_ResourceSectionSize\n", prefix);
972 fprintf(fo, "\t.long\t.LResTabEnd - %s%s\n", prefix, win32 ? _PEResTab : _NEResTab);
973 if(win32)
975 fprintf(fo, "%s_ResourcesEntries:\n", prefix);
976 if(global)
977 fprintf(fo, "\t.globl\t%s_ResourcesEntries\n", prefix);
978 fprintf(fo, "\t.long\t%s_ResourceDirectory\n", prefix);
983 if(indirect)
985 /* Write the indirection structures */
986 fprintf(fo, "\n/* Resource indirection structures */\n\n");
987 fprintf(fo, "\t.align\t4\n");
988 for(rsc = top; rsc; rsc = rsc->next)
990 int type;
991 char *type_name = NULL;
993 if(!rsc->binres)
994 continue;
996 switch(rsc->type)
998 case res_menex:
999 type = WRC_RT_MENU;
1000 break;
1001 case res_dlgex:
1002 type = WRC_RT_DIALOG;
1003 break;
1004 case res_usr:
1005 assert(rsc->res.usr->type != NULL);
1006 type_name = prep_nid_for_label(rsc->res.usr->type);
1007 type = 0;
1008 break;
1009 default:
1010 type = rsc->type;
1014 * This follows a structure like:
1015 * struct wrc_resource {
1016 * INT32 id;
1017 * RSCNAME *resname;
1018 * INT32 restype;
1019 * RSCNAME *typename;
1020 * void *data;
1021 * UINT32 datasize;
1022 * };
1023 * The 'RSCNAME' is a pascal-style string where the
1024 * first byte/word denotes the size and the rest the string
1025 * itself.
1027 fprintf(fo, "%s%s:\n", prefix, rsc->c_name);
1028 if(global)
1029 fprintf(fo, "\t.globl\t%s%s\n", prefix, rsc->c_name);
1030 fprintf(fo, "\t.long\t%d, %s%s%s, %d, %s%s%s%s, %s%s_data, %d\n",
1031 rsc->name->type == name_ord ? rsc->name->name.i_name : 0,
1032 rsc->name->type == name_ord ? "0" : prefix,
1033 rsc->name->type == name_ord ? "" : rsc->c_name,
1034 rsc->name->type == name_ord ? "" : "_name",
1035 type,
1036 type ? "0" : prefix,
1037 type ? "" : "_",
1038 type ? "" : type_name,
1039 type ? "" : "_typename",
1040 prefix,
1041 rsc->c_name,
1042 rsc->binres->size - rsc->binres->dataidx);
1043 fprintf(fo, "\n");
1045 fprintf(fo, "\n");
1047 /* Write the indirection table */
1048 fprintf(fo, "/* Resource indirection table */\n\n");
1049 fprintf(fo, "\t.align\t4\n");
1050 fprintf(fo, "%s%s:\n", prefix, _ResTable);
1051 fprintf(fo, "\t.globl\t%s%s\n", prefix, _ResTable);
1052 for(rsc = top; rsc; rsc = rsc->next)
1054 fprintf(fo, "\t.long\t%s%s\n", prefix, rsc->c_name);
1056 fprintf(fo, "\t.long\t0\n");
1057 fprintf(fo, "\n");
1060 if(auto_register)
1061 fprintf(fo, s_file_autoreg_str, prefix, _ResTable);
1063 fprintf(fo, s_file_tail_str);
1064 fclose(fo);
1068 *****************************************************************************
1069 * Function : write_h_file
1070 * Syntax : void write_h_file(char *outname, resource_t *top)
1071 * Input :
1072 * outname - Filename to write to
1073 * top - The resource-tree to convert
1074 * Output :
1075 * Description :
1076 * Remarks :
1077 *****************************************************************************
1079 void write_h_file(char *outname, resource_t *top)
1081 FILE *fo;
1082 resource_t *rsc;
1083 char *h_prefix;
1085 #ifdef NEED_UNDERSCORE_PREFIX
1086 h_prefix = prefix + 1;
1087 #else
1088 h_prefix = prefix;
1089 #endif
1091 fo = fopen(outname, "wt");
1092 if(!fo)
1094 error("Could not open %s\n", outname);
1097 fprintf(fo, h_file_head_str, input_name ? input_name : "stdin",
1098 cmdline, ctime(&now), (long)now, (long)now);
1100 /* First write the segment tables reference */
1101 if(create_dir)
1103 fprintf(fo, "extern %schar %s%s[];\n\n",
1104 constant ? "const " : "",
1105 h_prefix,
1106 win32 ? _PEResTab : _NEResTab);
1109 /* Write the resource data */
1110 for(rsc = top; global && rsc; rsc = rsc->next)
1112 if(!rsc->binres)
1113 continue;
1115 fprintf(fo, "extern %schar %s%s_data[];\n",
1116 constant ? "const " : "",
1117 h_prefix,
1118 rsc->c_name);
1121 if(indirect)
1123 if(global)
1124 fprintf(fo, "\n");
1126 /* Write the indirection structures */
1127 for(rsc = top; global && rsc; rsc = rsc->next)
1129 fprintf(fo, "extern %swrc_resource%d_t %s%s;\n",
1130 constant ? "const " : "",
1131 win32 ? 32 : 16,
1132 h_prefix,
1133 rsc->c_name);
1136 if(global)
1137 fprintf(fo, "\n");
1139 /* Write the indirection table */
1140 fprintf(fo, "extern %swrc_resource%d_t %s%s[];\n\n",
1141 constant ? "const " : "",
1142 win32 ? 32 : 16,
1143 h_prefix,
1144 _ResTable);
1147 fprintf(fo, h_file_tail_str);
1148 fclose(fo);