Release 20021031.
[wine/multimedia.git] / tools / wrc / writeres.c
blobc068d41f6c92d22a6d70eb4b1ebd1d5433b1de4e
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"
22 #include "wine/port.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
29 #include "wine/unicode.h"
30 #include "wrc.h"
31 #include "writeres.h"
32 #include "genres.h"
33 #include "newstruc.h"
34 #include "utils.h"
36 static char s_file_head_str[] =
37 "/* This file is generated with wrc version " WRC_FULLVERSION ". Do not edit! */\n"
38 "/* Source : %s */\n"
39 "/* Cmdline: %s */\n"
40 "/* Date : %s */\n"
41 "\n"
42 "\t.data\n"
43 "\n"
46 static char s_file_tail_str[] =
47 "/* <eof> */\n"
48 "\n"
51 static char s_file_autoreg_str[] =
52 "\t.text\n"
53 ".LAuto_Register:\n"
54 "\tpushl\t$" __ASM_NAME("%s%s") "\n"
55 "\tcall\t" __ASM_NAME("LIBRES_RegisterResources") "\n"
56 "\taddl\t$4,%%esp\n"
57 "\tret\n\n"
58 #ifdef __NetBSD__
59 ".stabs \"___CTOR_LIST__\",22,0,0,.LAuto_Register\n\n"
60 #else
61 "\t.section .ctors,\"aw\"\n"
62 "\t.long\t.LAuto_Register\n\n"
63 #endif
66 static char h_file_head_str[] =
67 "/*\n"
68 " * This file is generated with wrc version " WRC_FULLVERSION ". Do not edit!\n"
69 " * Source : %s\n"
70 " * Cmdline: %s\n"
71 " * Date : %s"
72 " */\n"
73 "\n"
74 "#ifndef __%08lx_H\n" /* This becomes the date of compile */
75 "#define __%08lx_H\n"
76 "\n"
77 "#include <wrc_rsc.h>\n"
78 "\n"
81 static char h_file_tail_str[] =
82 "#endif\n"
83 "/* <eof> */\n\n"
86 char _NEResTab[] = "_NEResTab";
87 char _PEResTab[] = "_PEResTab";
88 char _ResTable[] = "_ResTable";
90 /* Variables used for resource sorting */
91 res_count_t *rcarray = NULL; /* Type-level count array */
92 int rccount = 0; /* Nr of entries in the type-level array */
93 int n_id_entries = 0; /* win32 only: Nr of unique ids in the type-level array */
94 int n_name_entries = 0; /* win32 only: Nr of unique namess in the type-level array */
96 static int direntries; /* win32 only: Total number of unique resources */
99 *****************************************************************************
100 * Function : write_resfile
101 * Syntax : void write_resfile(char *outname, resource_t *top)
102 * Input :
103 * outname - Filename to write to
104 * top - The resource-tree to convert
105 * Output :
106 * Description :
107 * Remarks :
108 *****************************************************************************
110 void write_resfile(char *outname, resource_t *top)
112 FILE *fo;
113 int ret;
114 char zeros[3] = {0, 0, 0};
116 fo = fopen(outname, "wb");
117 if(!fo)
119 error("Could not open %s\n", outname);
122 if(win32)
124 /* Put an empty resource first to signal win32 format */
125 res_t *res = new_res();
126 put_dword(res, 0); /* ResSize */
127 put_dword(res, 0x00000020); /* HeaderSize */
128 put_word(res, 0xffff); /* ResType */
129 put_word(res, 0);
130 put_word(res, 0xffff); /* ResName */
131 put_word(res, 0);
132 put_dword(res, 0); /* DataVersion */
133 put_word(res, 0); /* Memory options */
134 put_word(res, 0); /* Language */
135 put_dword(res, 0); /* Version */
136 put_dword(res, 0); /* Charateristics */
137 ret = fwrite(res->data, 1, res->size, fo);
138 if(ret != res->size)
140 fclose(fo);
141 error("Error writing %s", outname);
143 free(res);
146 for(; top; top = top->next)
148 if(!top->binres)
149 continue;
151 ret = fwrite(top->binres->data, 1, top->binres->size, fo);
152 if(ret != top->binres->size)
154 fclose(fo);
155 error("Error writing %s", outname);
157 if(win32 && (top->binres->size & 0x03))
159 /* Write padding */
160 ret = fwrite(zeros, 1, 4 - (top->binres->size & 0x03), fo);
161 if(ret != 4 - (top->binres->size & 0x03))
163 fclose(fo);
164 error("Error writing %s", outname);
168 fclose(fo);
172 *****************************************************************************
173 * Function : write_s_res
174 * Syntax : void write_s_res(FILE *fp, res_t *res)
175 * Input :
176 * Output :
177 * Description :
178 * Remarks :
179 *****************************************************************************
181 #define BYTESPERLINE 8
182 static void write_s_res(FILE *fp, res_t *res)
184 int idx = res->dataidx;
185 int end = res->size;
186 int rest = (end - idx) % BYTESPERLINE;
187 int lines = (end - idx) / BYTESPERLINE;
188 int i, j;
190 for(i = 0 ; i < lines; i++)
192 fprintf(fp, "\t.byte\t");
193 for(j = 0; j < BYTESPERLINE; j++, idx++)
195 fprintf(fp, "0x%02x%s", res->data[idx] & 0xff,
196 j == BYTESPERLINE-1 ? "" : ", ");
198 fprintf(fp, "\n");
200 if(rest)
202 fprintf(fp, "\t.byte\t");
203 for(j = 0; j < rest; j++, idx++)
205 fprintf(fp, "0x%02x%s", res->data[idx] & 0xff,
206 j == rest-1 ? "" : ", ");
208 fprintf(fp, "\n");
211 #undef BYTESPERLINE
214 *****************************************************************************
215 * Function : write_name_str
216 * Syntax : void write_name_str(FILE *fp, name_id_t *nid)
217 * Input :
218 * Output :
219 * Description :
220 * Remarks : One level self recursive for string type conversion
221 *****************************************************************************
223 static void write_name_str(FILE *fp, name_id_t *nid)
225 res_t res;
226 assert(nid->type == name_str);
228 if(!win32 && nid->name.s_name->type == str_char)
230 res.size = strlen(nid->name.s_name->str.cstr);
231 if(res.size > 254)
232 error("Can't write strings larger than 254 bytes");
233 if(res.size == 0)
234 internal_error(__FILE__, __LINE__, "Attempt to write empty string");
235 res.dataidx = 0;
236 res.data = (char *)xmalloc(1 + res.size + 1);
237 res.data[0] = (char)res.size;
238 res.size++; /* We need to write the length byte as well */
239 strcpy(res.data+1, nid->name.s_name->str.cstr);
240 write_s_res(fp, &res);
241 free(res.data);
243 else if(!win32 && nid->name.s_name->type == str_unicode)
245 name_id_t lnid;
247 lnid.type = name_str;
248 lnid.name.s_name = convert_string( nid->name.s_name, str_char,
249 get_language_codepage(0,0) );
250 write_name_str(fp, &lnid);
251 free_string( lnid.name.s_name );
253 else if(win32 && nid->name.s_name->type == str_char)
255 name_id_t lnid;
257 lnid.type = name_str;
258 lnid.name.s_name = convert_string( nid->name.s_name, str_unicode,
259 get_language_codepage(0,0) );
260 write_name_str(fp, &lnid);
261 free_string( lnid.name.s_name );
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 characters");
268 if(res.size == 0)
269 internal_error(__FILE__, __LINE__, "Attempt to write empty string");
270 res.dataidx = 0;
271 res.data = (char *)xmalloc(2 + (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, __ASM_NAME("%s%s") ":\n", prefix, _PEResTab);
527 fprintf(fp, "\t.globl\t" __ASM_NAME("%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(" __ASM_NAME("%s_%s_typename") " - " __ASM_NAME("%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 - " __ASM_NAME("%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(" __ASM_NAME("%s%s_name") " - " __ASM_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 - " __ASM_NAME("%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 - " __ASM_NAME("%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, __ASM_NAME("%s_ResourceDirectory") ":\n", prefix);
658 fprintf(fp, "\t.globl\t" __ASM_NAME("%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" __ASM_NAME("%s%s_data") " - " __ASM_NAME("%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, __ASM_NAME("%s%s") ":\n", prefix, _NEResTab);
727 fprintf(fp, "\t.globl\t" __ASM_NAME("%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" __ASM_NAME("%s_%s_typename") " - " __ASM_NAME("%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(" __ASM_NAME("%s%s_data") " - " __ASM_NAME("%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" __ASM_NAME("%s%s_name") " - " __ASM_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, __ASM_NAME("%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, __ASM_NAME("%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, __ASM_NAME("%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, __ASM_NAME("%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, __ASM_NAME("%s%s_data") ":\n", prefix, rsc->c_name);
934 if(global)
935 fprintf(fo, "\t.globl\t" __ASM_NAME("%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, __ASM_NAME("%s_ResourceDescriptor") ":\n", prefix);
947 fprintf(fo, "\t.globl\t" __ASM_NAME("%s_ResourceDescriptor") "\n", prefix);
948 fprintf(fo, __ASM_NAME("%s_ResourceTable") ":\n", prefix);
949 if(global)
950 fprintf(fo, "\t.globl\t" __ASM_NAME("%s_ResourceTable") "\n", prefix);
951 fprintf(fo, "\t.long\t" __ASM_NAME("%s%s") "\n", prefix, win32 ? _PEResTab : _NEResTab);
952 fprintf(fo, __ASM_NAME("%s_NumberOfResources") ":\n", prefix);
953 if(global)
954 fprintf(fo, "\t.globl\t" __ASM_NAME("%s_NumberOfResources") "\n", prefix);
955 fprintf(fo, "\t.long\t%d\n", direntries);
956 fprintf(fo, __ASM_NAME("%s_ResourceSectionSize") ":\n", prefix);
957 if(global)
958 fprintf(fo, "\t.globl\t" __ASM_NAME("%s_ResourceSectionSize") "\n", prefix);
959 fprintf(fo, "\t.long\t.LResTabEnd - " __ASM_NAME("%s%s") "\n", prefix, win32 ? _PEResTab : _NEResTab);
960 if(win32)
962 fprintf(fo, __ASM_NAME("%s_ResourcesEntries") ":\n", prefix);
963 if(global)
964 fprintf(fo, "\t.globl\t" __ASM_NAME("%s_ResourcesEntries") "\n", prefix);
965 fprintf(fo, "\t.long\t" __ASM_NAME("%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, __ASM_NAME("%s%s") ":\n", prefix, rsc->c_name);
1015 if(global)
1016 fprintf(fo, "\t.globl\t" __ASM_NAME("%s%s") "\n", prefix, rsc->c_name);
1017 if (rsc->name->type == name_ord)
1018 fprintf(fo, "\t.long\t%d, 0, ", rsc->name->name.i_name );
1019 else
1020 fprintf(fo, "\t.long\t0, " __ASM_NAME("%s%s_name") ", ",
1021 prefix, rsc->c_name );
1022 if (type)
1023 fprintf(fo, "%d, 0, ", type);
1024 else
1025 fprintf(fo, "0, " __ASM_NAME("%s_%s_typename") ", ",
1026 prefix, type_name );
1028 fprintf(fo, __ASM_NAME("%s%s_data") ", %d\n",
1029 prefix,
1030 rsc->c_name,
1031 rsc->binres->size - rsc->binres->dataidx);
1032 fprintf(fo, "\n");
1034 fprintf(fo, "\n");
1036 /* Write the indirection table */
1037 fprintf(fo, "/* Resource indirection table */\n\n");
1038 fprintf(fo, "\t.align\t4\n");
1039 fprintf(fo, __ASM_NAME("%s%s") ":\n", prefix, _ResTable);
1040 fprintf(fo, "\t.globl\t" __ASM_NAME("%s%s") "\n", prefix, _ResTable);
1041 for(rsc = top; rsc; rsc = rsc->next)
1043 fprintf(fo, "\t.long\t" __ASM_NAME("%s%s") "\n", prefix, rsc->c_name);
1045 fprintf(fo, "\t.long\t0\n");
1046 fprintf(fo, "\n");
1049 if(auto_register)
1050 fprintf(fo, s_file_autoreg_str, prefix, _ResTable);
1052 fprintf(fo, s_file_tail_str);
1053 fclose(fo);
1057 *****************************************************************************
1058 * Function : write_h_file
1059 * Syntax : void write_h_file(char *outname, resource_t *top)
1060 * Input :
1061 * outname - Filename to write to
1062 * top - The resource-tree to convert
1063 * Output :
1064 * Description :
1065 * Remarks :
1066 *****************************************************************************
1068 void write_h_file(char *outname, resource_t *top)
1070 FILE *fo;
1071 resource_t *rsc;
1073 fo = fopen(outname, "wt");
1074 if(!fo)
1076 error("Could not open %s\n", outname);
1079 fprintf(fo, h_file_head_str, input_name ? input_name : "stdin",
1080 cmdline, ctime(&now), (long)now, (long)now);
1082 /* First write the segment tables reference */
1083 if(create_dir)
1085 fprintf(fo, "extern %schar %s%s[];\n\n",
1086 constant ? "const " : "",
1087 prefix,
1088 win32 ? _PEResTab : _NEResTab);
1091 /* Write the resource data */
1092 for(rsc = top; global && rsc; rsc = rsc->next)
1094 if(!rsc->binres)
1095 continue;
1097 fprintf(fo, "extern %schar %s%s_data[];\n",
1098 constant ? "const " : "",
1099 prefix,
1100 rsc->c_name);
1103 if(indirect)
1105 if(global)
1106 fprintf(fo, "\n");
1108 /* Write the indirection structures */
1109 for(rsc = top; global && rsc; rsc = rsc->next)
1111 fprintf(fo, "extern %swrc_resource%d_t %s%s;\n",
1112 constant ? "const " : "",
1113 win32 ? 32 : 16,
1114 prefix,
1115 rsc->c_name);
1118 if(global)
1119 fprintf(fo, "\n");
1121 /* Write the indirection table */
1122 fprintf(fo, "extern %swrc_resource%d_t %s%s[];\n\n",
1123 constant ? "const " : "",
1124 win32 ? 32 : 16,
1125 prefix,
1126 _ResTable);
1129 fprintf(fo, h_file_tail_str);
1130 fclose(fo);