Recovery of release 990110 after disk crash.
[wine/multimedia.git] / tools / wrc / writeres.c
blob2e1714328a4e02ab35dc421ffbc39ed1a696143f
1 /*
2 * Write .res, .s and .h file(s) from a resource-tree
4 * Copyright 1998 Bertho A. Stultiens
6 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <assert.h>
12 #include <time.h>
14 #include <config.h>
15 #include "wrc.h"
16 #include "writeres.h"
17 #include "genres.h"
18 #include "newstruc.h"
19 #include "utils.h"
21 #ifdef NEED_UNDERSCORE_PREFIX
22 char Underscore[] = "_";
23 #else
24 char Underscore[] = "";
25 #endif
27 char s_file_head_str[] =
28 "#\n"
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"
33 "#\n\n"
34 "\t.data\n\n"
37 char s_file_tail_str[] =
38 "# <eof>\n\n"
41 char s_file_autoreg_str[] =
42 "\t.text\n"
43 ".LAuto_Register:\n"
44 "\tpushl\t$%s%s\n"
45 #ifdef NEED_UNDERSCORE_PREFIX
46 "\tcall\t_LIBRES_RegisterResources\n"
47 #else
48 "\tcall\tLIBRES_RegisterResources\n"
49 #endif
50 "\taddl\t$4,%%esp\n"
51 "\tret\n\n"
52 #ifdef __NetBSD__
53 ".stabs \"___CTOR_LIST__\",22,0,0,.LAuto_Register\n\n"
54 #else
55 "\t.section .ctors,\"aw\"\n"
56 "\t.long\t.LAuto_Register\n\n"
57 #endif
60 char h_file_head_str[] =
61 "/*\n"
62 " * This file is generated with wrc version " WRC_FULLVERSION ". Do not edit!\n"
63 " * Source : %s\n"
64 " * Cmdline: %s\n"
65 " * Date : %s"
66 " */\n\n"
67 "#ifndef __%08x_H\n" /* This becomes the data of compile */
68 "#define __%08x_H\n\n"
69 "#ifndef __WRC_RSC_H\n"
70 "#include <wrc_rsc.h>\n"
71 "#endif\n\n"
74 char h_file_tail_str[] =
75 "#endif\n"
76 "/* <eof> */\n\n"
79 char _NEResTab[] = "_NEResTab";
80 char _PEResTab[] = "_PEResTab";
81 char _ResTable[] = "_ResTable";
83 res_count_t *rcarray = NULL;
84 int rccount = 0;
85 int n_id_entries = 0;
86 int n_name_entries = 0;
88 time_t now;
91 *****************************************************************************
92 * Function : write_resfile
93 * Syntax : void write_resfile(char *outname, resource_t *top)
94 * Input :
95 * outname - Filename to write to
96 * top - The resource-tree to convert
97 * Output :
98 * Description :
99 * Remarks :
100 *****************************************************************************
102 void write_resfile(char *outname, resource_t *top)
104 FILE *fo;
105 int ret;
106 char zeros[3] = {0, 0, 0};
108 fo = fopen(outname, "wb");
109 if(!fo)
111 error("Could not open %s\n", outname);
114 if(win32)
116 /* Put an empty resource first to signal win32 format */
117 res_t *res = new_res();
118 put_dword(res, 0); /* ResSize */
119 put_dword(res, 0x00000020); /* HeaderSize */
120 put_word(res, 0xffff); /* ResType */
121 put_word(res, 0);
122 put_word(res, 0xffff); /* ResName */
123 put_word(res, 0);
124 put_dword(res, 0); /* DataVersion */
125 put_word(res, 0); /* Memory options */
126 put_word(res, 0); /* Language */
127 put_dword(res, 0); /* Version */
128 put_dword(res, 0); /* Charateristics */
129 ret = fwrite(res->data, 1, res->size, fo);
130 if(ret != res->size)
132 fclose(fo);
133 error("Error writing %s", outname);
135 free(res);
138 for(; top; top = top->next)
140 if(!top->binres)
141 continue;
143 ret = fwrite(top->binres->data, 1, top->binres->size, fo);
144 if(ret != top->binres->size)
146 fclose(fo);
147 error("Error writing %s", outname);
149 if(win32 && (top->binres->size & 0x03))
151 /* Write padding */
152 ret = fwrite(zeros, 1, 4 - (top->binres->size & 0x03), fo);
153 if(ret != 4 - (top->binres->size & 0x03))
155 fclose(fo);
156 error("Error writing %s", outname);
160 fclose(fo);
164 *****************************************************************************
165 * Function : write_s_res
166 * Syntax : void write_s_res(FILE *fp, res_t *res)
167 * Input :
168 * Output :
169 * Description :
170 * Remarks :
171 *****************************************************************************
173 #define BYTESPERLINE 8
174 void write_s_res(FILE *fp, res_t *res)
176 int idx = res->dataidx;
177 int end = res->size;
178 int rest = (end - idx) % BYTESPERLINE;
179 int lines = (end - idx) / BYTESPERLINE;
180 int i, j;
182 for(i = 0 ; i < lines; i++)
184 fprintf(fp, "\t.byte\t");
185 for(j = 0; j < BYTESPERLINE; j++, idx++)
187 fprintf(fp, "0x%02x%s", res->data[idx] & 0xff,
188 j == BYTESPERLINE-1 ? "" : ", ");
190 fprintf(fp, "\n");
192 if(rest)
194 fprintf(fp, "\t.byte\t");
195 for(j = 0; j < rest; j++, idx++)
197 fprintf(fp, "0x%02x%s", res->data[idx] & 0xff,
198 j == rest-1 ? "" : ", ");
200 fprintf(fp, "\n");
205 *****************************************************************************
206 * Function : write_name_str
207 * Syntax : void write_name_str(FILE *fp, name_id_t *nid)
208 * Input :
209 * Output :
210 * Description :
211 * Remarks : One level self recursive for string type conversion
212 *****************************************************************************
214 void write_name_str(FILE *fp, name_id_t *nid)
216 res_t res;
217 assert(nid->type == name_str);
219 if(!win32 && nid->name.s_name->type == str_char)
221 res.size = strlen(nid->name.s_name->str.cstr);
222 if(res.size > 254)
223 error("Can't write strings larger than 254 bytes");
224 if(res.size == 0)
225 internal_error(__FILE__, __LINE__, "Attempt to write empty string");
226 res.dataidx = 0;
227 res.data = (char *)xmalloc(res.size + 1);
228 res.data[0] = (char)res.size;
229 res.size++; /* We need to write the lenth byte as well */
230 strcpy(res.data+1, nid->name.s_name->str.cstr);
231 write_s_res(fp, &res);
232 free(res.data);
234 else if(!win32 && nid->name.s_name->type == str_unicode)
236 name_id_t lnid;
237 string_t str;
239 lnid.type = name_str;
240 lnid.name.s_name = &str;
241 str.type = str_char;
242 str.str.cstr = dupwstr2cstr(nid->name.s_name->str.wstr);
243 write_name_str(fp, &lnid);
244 free(str.str.cstr);
246 else if(win32 && nid->name.s_name->type == str_char)
248 name_id_t lnid;
249 string_t str;
251 lnid.type = name_str;
252 lnid.name.s_name = &str;
253 str.type = str_unicode;
254 str.str.wstr = dupcstr2wstr(nid->name.s_name->str.cstr);
255 write_name_str(fp, &lnid);
256 free(str.str.wstr);
258 else if(win32 && nid->name.s_name->type == str_unicode)
260 res.size = wstrlen(nid->name.s_name->str.wstr);
261 if(res.size > 65534)
262 error("Can't write strings larger than 65534 bytes");
263 if(res.size == 0)
264 internal_error(__FILE__, __LINE__, "Attempt to write empty string");
265 res.dataidx = 0;
266 res.data = (char *)xmalloc((res.size + 1) * 2);
267 ((short *)res.data)[0] = (short)res.size;
268 wstrcpy((short *)(res.data+2), nid->name.s_name->str.wstr);
269 res.size *= 2; /* Function writes bytes, not shorts... */
270 res.size += 2; /* We need to write the length word as well */
271 write_s_res(fp, &res);
272 free(res.data);
274 else
276 internal_error(__FILE__, __LINE__, "Hmm, requested to write a string of unknown type %d",
277 nid->name.s_name->type);
282 *****************************************************************************
283 * Function : compare_name_id
284 * Syntax : int compare_name_id(name_id_t *n1, name_id_t *n2)
285 * Input :
286 * Output :
287 * Description :
288 * Remarks :
289 *****************************************************************************
291 int compare_name_id(name_id_t *n1, name_id_t *n2)
293 if(n1->type == name_ord && n2->type == name_ord)
295 return n1->name.i_name - n2->name.i_name;
297 else if(n1->type == name_str && n2->type == name_str)
299 if(n1->name.s_name->type == str_char
300 && n2->name.s_name->type == str_char)
302 return strcasecmp(n1->name.s_name->str.cstr, n2->name.s_name->str.cstr);
304 else if(n1->name.s_name->type == str_unicode
305 && n2->name.s_name->type == str_unicode)
307 return wstricmp(n1->name.s_name->str.wstr, n2->name.s_name->str.wstr);
309 else
311 internal_error(__FILE__, __LINE__, "Can't yet compare strings of mixed type");
314 else if(n1->type == name_ord && n2->type == name_str)
315 return -1;
316 else if(n1->type == name_str && n2->type == name_ord)
317 return 1;
318 else
319 internal_error(__FILE__, __LINE__, "Comparing name-ids with unknown types (%d, %d)",
320 n1->type, n2->type);
322 return 0; /* Keep the compiler happy */
326 *****************************************************************************
327 * Function : find_counter
328 * Syntax : res_count_t *find_counter(name_id_t *type)
329 * Input :
330 * Output :
331 * Description :
332 * Remarks :
333 *****************************************************************************
335 res_count_t *find_counter(name_id_t *type)
337 int i;
338 for(i = 0; i < rccount; i++)
340 if(!compare_name_id(type, &(rcarray[i].type)))
341 return &rcarray[i];
343 return NULL;
347 *****************************************************************************
348 * Function : count_resources
349 * Syntax : res_count_t *count_resources(resource_t *top)
350 * Input :
351 * Output :
352 * Description :
353 * Remarks : The whole lot is converted into arrays because they are
354 * easy sortable. Makes the lot almost unreadable, but it
355 * works (I hope). Basically you have to keep in mind that
356 * the lot is a three-dimensional structure for win32 and a
357 * two-dimensional structure for win16.
358 *****************************************************************************
360 #define RCT(v) (*((resource_t **)(v)))
361 /* qsort sorting function */
362 int sort_name_id(const void *e1, const void *e2)
364 return compare_name_id(RCT(e1)->name, RCT(e2)->name);
367 int sort_language(const void *e1, const void *e2)
369 assert((RCT(e1)->lan) != NULL);
370 assert((RCT(e2)->lan) != NULL);
372 return MAKELANGID(RCT(e1)->lan->id, RCT(e1)->lan->sub)
373 - MAKELANGID(RCT(e2)->lan->id, RCT(e2)->lan->sub);
375 #undef RCT
376 #define RCT(v) ((res_count_t *)(v))
377 int sort_type(const void *e1, const void *e2)
379 return compare_name_id(&(RCT(e1)->type), &(RCT(e2)->type));
381 #undef RCT
383 void count_resources(resource_t *top)
385 resource_t *rsc;
386 res_count_t *rcp;
387 name_id_t nid;
388 int i, j;
390 for(rsc = top; rsc; rsc = rsc->next)
392 if(!rsc->binres)
393 continue;
394 switch(rsc->type)
396 case res_dlgex:
397 nid.name.i_name = WRC_RT_DIALOG;
398 nid.type = name_ord;
399 break;
400 case res_menex:
401 nid.name.i_name = WRC_RT_MENU;
402 nid.type = name_ord;
403 break;
404 case res_usr:
405 nid = *(rsc->res.usr->type);
406 break;
407 default:
408 nid.name.i_name = rsc->type;
409 nid.type = name_ord;
412 if((rcp = find_counter(&nid)) == NULL)
414 /* Count the number of uniq ids and names */
416 if(nid.type == name_ord)
417 n_id_entries++;
418 else
419 n_name_entries++;
421 if(!rcarray)
423 rcarray = (res_count_t *)xmalloc(sizeof(res_count_t));
424 rccount = 1;
425 rcarray[0].count = 1;
426 rcarray[0].type = nid;
427 rcarray[0].rscarray = (resource_t **)xmalloc(sizeof(resource_t *));
428 rcarray[0].rscarray[0] = rsc;
430 else
432 rccount++;
433 rcarray = (res_count_t *)xrealloc(rcarray, rccount * sizeof(res_count_t));
434 rcarray[rccount-1].count = 1;
435 rcarray[rccount-1].type = nid;
436 rcarray[rccount-1].rscarray = (resource_t **)xmalloc(sizeof(resource_t *));
437 rcarray[rccount-1].rscarray[0] = rsc;
440 else
442 rcp->count++;
443 rcp->rscarray = (resource_t **)xrealloc(rcp->rscarray, rcp->count * sizeof(resource_t *));
444 rcp->rscarray[rcp->count-1] = rsc;
448 if(!win32)
450 /* We're done, win16 requires no special sorting */
451 return;
454 /* We now have a unsorted list of types with an array of res_count_t
455 * in rcarray[0..rccount-1]. And we have names of one type in the
456 * rcarray[x].rsc[0..rcarray[x].count-1] arrays.
457 * The list needs to be sorted for win32's top level tree structure.
460 /* Sort the types */
461 if(rccount > 1)
462 qsort(rcarray, rccount, sizeof(rcarray[0]), sort_type);
464 /* Now sort the name-id arrays */
465 for(i = 0; i < rccount; i++)
467 if(rcarray[i].count > 1)
468 qsort(rcarray[i].rscarray, rcarray[i].count, sizeof(rcarray[0].rscarray[0]), sort_name_id);
471 /* Now split the name-id arrays into name/language
472 * subs. Don't look at the awfull expressions...
473 * We do this by taking the array elements out of rscarray and putting
474 * together a new array in rsc32array.
476 for(i = 0; i < rccount; i++)
478 res_count_t *rcap;
480 assert(rcarray[i].count >= 1);
482 /* rcap points to the current type we are dealing with */
483 rcap = &(rcarray[i]);
485 /* Insert the first name-id */
486 rcap->rsc32array = (res32_count_t *)xmalloc(sizeof(res32_count_t));
487 rcap->count32 = 1;
488 rcap->rsc32array[0].rsc = (resource_t **)xmalloc(sizeof(resource_t *));
489 rcap->rsc32array[0].count = 1;
490 rcap->rsc32array[0].rsc[0] = rcap->rscarray[0];
491 if(rcap->rscarray[0]->name->type == name_ord)
493 rcap->n_id_entries = 1;
494 rcap->n_name_entries = 0;
496 else
498 rcap->n_id_entries = 0;
499 rcap->n_name_entries = 1;
502 /* Now loop over the resting resources of the current type
503 * to find duplicate names (which should have different
504 * languages).
506 for(j = 1; j < rcap->count; j++)
508 res32_count_t *r32cp;
510 /* r32cp points to the current res32_count structure
511 * that holds the resource name we are processing.
513 r32cp = &(rcap->rsc32array[rcap->count32-1]);
515 if(!compare_name_id(r32cp->rsc[0]->name, rcarray[i].rscarray[j]->name))
517 /* Names are the same, add to list */
518 r32cp->count++;
519 r32cp->rsc = (resource_t **)xrealloc(r32cp->rsc, r32cp->count * sizeof(resource_t *));
520 r32cp->rsc[r32cp->count-1] = rcap->rscarray[j];
522 if(rcap->rscarray[j]->name->type == name_ord)
524 rcap->n_id_entries = 1;
525 rcap->n_name_entries = 0;
527 else
529 rcap->n_id_entries = 0;
530 rcap->n_name_entries = 1;
533 else
535 /* New name-id, sort the old one by
536 * language and create new list
538 if(r32cp->count > 1)
539 qsort(r32cp->rsc, r32cp->count, sizeof(r32cp->rsc[0]), sort_language);
540 rcap->count32++;
541 rcap->rsc32array = (res32_count_t*)xrealloc(rcap->rsc32array, rcap->count32 * sizeof(res32_count_t));
542 rcap->rsc32array[rcap->count32-1].rsc = (resource_t **)xmalloc(sizeof(resource_t *));
543 rcap->rsc32array[rcap->count32-1].count = 1;
544 rcap->rsc32array[rcap->count32-1].rsc[0] = rcap->rscarray[j];
546 if(rcap->rscarray[j]->name->type == name_ord)
547 rcap->n_id_entries++;
548 else
549 rcap->n_name_entries++;
552 /* Also sort the languages of the last name group */
553 if(rcap->rsc32array[rcap->count32-1].count > 1)
554 qsort(rcap->rsc32array[rcap->count32-1].rsc,
555 rcap->rsc32array[rcap->count32-1].count,
556 sizeof(rcap->rsc32array[rcap->count32-1].rsc[0]),
557 sort_language);
562 *****************************************************************************
563 * Function : write_pe_segment
564 * Syntax : void write_pe_segment(FILE *fp, resource_t *top)
565 * Input :
566 * Output :
567 * Description :
568 * Remarks :
569 *****************************************************************************
571 void write_pe_segment(FILE *fp, resource_t *top)
573 int i;
574 int direntries;
576 fprintf(fp, "\t.align\t4\n");
577 fprintf(fp, "%s%s:\n", prefix, _PEResTab);
578 fprintf(fp, "\t.globl\t%s%s\n", prefix, _PEResTab);
579 /* Flags */
580 fprintf(fp, "\t.long\t0\n");
581 /* Time/Date stamp */
582 fprintf(fp, "\t.long\t0x%08lx\n", now);
583 /* Version */
584 fprintf(fp, "\t.long\t0\n"); /* FIXME: must version be filled out? */
585 /* # of id entries, # of name entries */
586 fprintf(fp, "\t.short\t%d, %d\n", n_name_entries, n_id_entries);
588 /* Write the type level of the tree */
589 for(i = 0; i < rccount; i++)
591 res_count_t *rcp;
592 char *label;
594 rcp = &rcarray[i];
596 /* TypeId */
597 if(rcp->type.type == name_ord)
598 fprintf(fp, "\t.long\t%d\n", rcp->type.name.i_name);
599 else
601 char *name = prep_nid_for_label(&(rcp->type));
602 fprintf(fp, "\t.long\t(%s_%s_typename - %s%s) | 0x80000000\n",
603 prefix,
604 name,
605 prefix,
606 _PEResTab);
608 /* Offset */
609 label = prep_nid_for_label(&(rcp->type));
610 fprintf(fp, "\t.long\t(.L%s - %s%s) | 0x80000000\n",
611 label,
612 prefix,
613 _PEResTab);
616 /* Write the name level of the tree */
618 for(i = 0; i < rccount; i++)
620 res_count_t *rcp;
621 char *typelabel;
622 char *namelabel;
623 int j;
625 rcp = &rcarray[i];
627 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
628 fprintf(fp, ".L%s:\n", typelabel);
630 fprintf(fp, "\t.long\t0\n"); /* Flags */
631 fprintf(fp, "\t.long\t0x%08lx\n", now); /* TimeDate */
632 fprintf(fp, "\t.long\t0\n"); /* FIXME: must version be filled out? */
633 fprintf(fp, "\t.short\t%d, %d\n", rcp->n_name_entries, rcp->n_id_entries);
634 for(j = 0; j < rcp->count32; j++)
636 resource_t *rsc = rcp->rsc32array[j].rsc[0];
637 /* NameId */
638 if(rsc->name->type == name_ord)
639 fprintf(fp, "\t.long\t%d\n", rsc->name->name.i_name);
640 else
642 fprintf(fp, "\t.long\t(%s%s_name - %s%s) | 0x80000000\n",
643 prefix,
644 rsc->c_name,
645 prefix,
646 _PEResTab);
648 /* Maybe FIXME: Unescape the tree (ommit 0x80000000) and
649 * put the offset to the resource data entry.
650 * ?? Is unescaping worth while ??
652 /* Offset */
653 namelabel = prep_nid_for_label(rsc->name);
654 fprintf(fp, "\t.long\t(.L%s_%s - %s%s) | 0x80000000\n",
655 typelabel,
656 namelabel,
657 prefix,
658 _PEResTab);
660 free(typelabel);
663 /* Write the language level of the tree */
665 for(i = 0; i < rccount; i++)
667 res_count_t *rcp;
668 char *namelabel;
669 char *typelabel;
670 int j;
672 rcp = &rcarray[i];
673 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
675 for(j = 0; j < rcp->count32; j++)
677 res32_count_t *r32cp = &(rcp->rsc32array[j]);
678 int k;
680 namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
681 fprintf(fp, ".L%s_%s:\n", typelabel, namelabel);
683 fprintf(fp, "\t.long\t0\n"); /* Flags */
684 fprintf(fp, "\t.long\t0x%08lx\n", now); /* TimeDate */
685 fprintf(fp, "\t.long\t0\n"); /* FIXME: must version be filled out? */
686 fprintf(fp, "\t.short\t0, %d\n", r32cp->count);
688 for(k = 0; k < r32cp->count; k++)
690 resource_t *rsc = r32cp->rsc[k];
691 assert(rsc->lan != NULL);
692 /* LanguageId */
693 fprintf(fp, "\t.long\t0x%08x\n", rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
694 /* Offset */
695 fprintf(fp, "\t.long\t.L%s_%s_%d - %s%s\n",
696 typelabel,
697 namelabel,
698 rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0,
699 prefix,
700 _PEResTab);
702 free(namelabel);
704 free(typelabel);
707 /* Write the resource table itself */
708 fprintf(fp, "%s_ResourceDirectory:\n", prefix);
709 fprintf(fp, "\t.globl\t%s_ResourceDirectory\n", prefix);
710 direntries = 0;
712 for(i = 0; i < rccount; i++)
714 res_count_t *rcp;
715 char *namelabel;
716 char *typelabel;
717 int j;
719 rcp = &rcarray[i];
720 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
722 for(j = 0; j < rcp->count32; j++)
724 res32_count_t *r32cp = &(rcp->rsc32array[j]);
725 int k;
727 namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
729 for(k = 0; k < r32cp->count; k++)
731 resource_t *rsc = r32cp->rsc[k];
733 assert(rsc->lan != NULL);
735 fprintf(fp, ".L%s_%s_%d:\n",
736 typelabel,
737 namelabel,
738 rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
740 /* Data RVA */
741 fprintf(fp, "\t.long\t%s%s_data - %s%s\n",
742 prefix,
743 rsc->c_name,
744 prefix,
745 _PEResTab);
746 /* Size */
747 fprintf(fp, "\t.long\t%d\n",
748 rsc->binres->size - rsc->binres->dataidx);
749 /* CodePage */
750 fprintf(fp, "\t.long\t%ld\n", codepage);
751 /* Reserved */
752 fprintf(fp, "\t.long\t0\n");
754 direntries++;
756 free(namelabel);
758 free(typelabel);
761 fprintf(fp, "\t.align\t4\n");
762 fprintf(fp, "%s_NumberOfResources:\n", prefix);
763 fprintf(fp, "\t.globl\t%s_NumberOfResources\n", prefix);
764 fprintf(fp, "\t.long\t%d\n", direntries);
768 *****************************************************************************
769 * Function : write_ne_segment
770 * Syntax : void write_ne_segment(FILE *fp, resource_t *top)
771 * Input :
772 * Output :
773 * Description :
774 * Remarks :
775 *****************************************************************************
777 void write_ne_segment(FILE *fp, resource_t *top)
779 int i, j;
781 fprintf(fp, "\t.align\t4\n");
782 fprintf(fp, "%s%s:\n", prefix, _NEResTab);
783 fprintf(fp, "\t.globl\t%s%s\n", prefix, _NEResTab);
785 /* AlignmentShift */
786 fprintf(fp, "\t.short\t%d\n", alignment_pwr);
788 /* TypeInfo */
789 for(i = 0; i < rccount; i++)
791 res_count_t *rcp = &rcarray[i];
793 /* TypeId */
794 if(rcp->type.type == name_ord)
795 fprintf(fp, "\t.short\t0x%04x\n", rcp->type.name.i_name | 0x8000);
796 else
797 fprintf(fp, "\t.short\t%s_%s_typename - %s%s\n",
798 prefix,
799 rcp->type.name.s_name->str.cstr,
800 prefix,
801 _NEResTab);
802 /* ResourceCount */
803 fprintf(fp, "\t.short\t%d\n", rcp->count);
804 /* Reserved */
805 fprintf(fp, "\t.long\t0\n");
806 /* NameInfo */
807 for(j = 0; j < rcp->count; j++)
809 /* FIXME: dividing by `alignment` doesn't seem to
810 * work with as (GAS). Shifting results in the
811 * correct behaviour. Maybe an as bug or just my
812 * lack of knowing as expression-syntax.
814 /* Offset */
816 * VERY IMPORTANT:
817 * The offset is relative to the beginning of the NE resource segment
818 * and _NOT_ to the file-beginning. This is because we do not have a
819 * file based resource, but a simulated NE segment. The offset _is_
820 * scaled by the AlignShift field.
821 * All other things are as the MS doc describes (alignment etc.)
823 fprintf(fp, "\t.short\t(%s%s_data - %s%s) >> %d\n",
824 prefix,
825 rcp->rscarray[j]->c_name,
826 prefix,
827 _NEResTab,
828 alignment_pwr);
829 /* Length */
830 fprintf(fp, "\t.short\t%d\n",
831 rcp->rscarray[j]->binres->size - rcp->rscarray[j]->binres->dataidx);
832 /* Flags */
833 fprintf(fp, "\t.short\t0x%04x\n", (WORD)rcp->rscarray[j]->memopt);
834 /* Id */
835 if(rcp->rscarray[j]->name->type == name_ord)
836 fprintf(fp, "\t.short\t0x%04x\n", rcp->rscarray[j]->name->name.i_name | 0x8000);
837 else
838 fprintf(fp, "\t.short\t%s%s_name - %s%s\n",
839 prefix,
840 rcp->rscarray[j]->c_name,
841 prefix,
842 _NEResTab);
843 /* Handle and Usage */
844 fprintf(fp, "\t.short\t0, 0\n");
847 /* EndTypes */
848 fprintf(fp, "\t.short\t0\n");
852 *****************************************************************************
853 * Function : write_rsc_names
854 * Syntax : void write_rsc_names(FILE *fp, resource_t *top)
855 * Input :
856 * Output :
857 * Description :
858 * Remarks :
859 *****************************************************************************
861 void write_rsc_names(FILE *fp, resource_t *top)
863 int i, j;
865 if(win32)
867 /* Write the names */
869 for(i = 0; i < rccount; i++)
871 res_count_t *rcp;
873 rcp = &rcarray[i];
875 if(rcp->type.type == name_str)
877 char *name = prep_nid_for_label(&(rcp->type));
878 fprintf(fp, "%s_%s_typename:\n",
879 prefix,
880 name);
881 write_name_str(fp, &(rcp->type));
884 for(j = 0; j < rcp->count32; j++)
886 resource_t *rsc = rcp->rsc32array[j].rsc[0];
888 if(rsc->name->type == name_str)
890 fprintf(fp, "%s%s_name:\n",
891 prefix,
892 rsc->c_name);
893 write_name_str(fp, rsc->name);
898 else
900 /* ResourceNames */
901 for(i = 0; i < rccount; i++)
903 res_count_t *rcp = &rcarray[i];
905 for(j = 0; j < rcp->count; j++)
907 if(rcp->type.type == name_str)
909 fprintf(fp, "%s_%s_typename:\n",
910 prefix,
911 rcp->type.name.s_name->str.cstr);
912 write_name_str(fp, &(rcp->type));
914 if(rcp->rscarray[j]->name->type == name_str)
916 fprintf(fp, "%s%s_name:\n",
917 prefix,
918 rcp->rscarray[j]->c_name);
919 write_name_str(fp, rcp->rscarray[j]->name);
923 /* EndNames */
925 /* This is to end the NE resource table */
926 if(create_dir)
927 fprintf(fp, "\t.byte\t0\n");
930 fprintf(fp, "\n");
934 *****************************************************************************
935 * Function : write_s_file
936 * Syntax : void write_s_file(char *outname, resource_t *top)
937 * Input :
938 * outname - Filename to write to
939 * top - The resource-tree to convert
940 * Output :
941 * Description :
942 * Remarks :
943 *****************************************************************************
945 void write_s_file(char *outname, resource_t *top)
947 FILE *fo;
948 resource_t *rsc;
950 fo = fopen(outname, "wt");
951 if(!fo)
953 error("Could not open %s\n", outname);
956 now = time(NULL);
957 fprintf(fo, s_file_head_str, input_name ? input_name : "stdin",
958 cmdline, ctime(&now));
960 /* Get an idea how many we have and restructure the tables */
961 count_resources(top);
963 /* First write the segment tables */
964 if(create_dir)
966 if(win32)
967 write_pe_segment(fo, top);
968 else
969 write_ne_segment(fo, top);
972 /* Dump the names */
973 write_rsc_names(fo, top);
975 if(!indirect_only)
977 /* Write the resource data */
978 fprintf(fo, "#\n# Resource binary data\n#\n");
979 for(rsc = top; rsc; rsc = rsc->next)
981 if(!rsc->binres)
982 continue;
984 fprintf(fo, "\t.align\t%d\n", win32 ? 4 : alignment);
985 fprintf(fo, "%s%s_data:\n", prefix, rsc->c_name);
986 if(global)
987 fprintf(fo, "\t.globl\t%s%s_data\n", prefix, rsc->c_name);
989 write_s_res(fo, rsc->binres);
991 fprintf(fo, "\n");
994 if(create_dir)
996 /* Add the size of the entire resource section for elf-dlls */
997 fprintf(fo, "%s_ResourceSectionSize:\n", prefix);
998 fprintf(fo, "\t.globl\t%s_ResourceSectionSize\n", prefix);
999 fprintf(fo, "\t.long\t. - %s%s\n", prefix, _PEResTab);
1003 if(indirect)
1005 /* Write the indirection structures */
1006 fprintf(fo, "\n#\n# Resource indirection structures\n#\n");
1007 fprintf(fo, "\t.align\t4\n");
1008 for(rsc = top; rsc; rsc = rsc->next)
1010 int type;
1011 char *type_name = NULL;
1013 if(!rsc->binres)
1014 continue;
1016 switch(rsc->type)
1018 case res_menex:
1019 type = WRC_RT_MENU;
1020 break;
1021 case res_dlgex:
1022 type = WRC_RT_DIALOG;
1023 break;
1024 case res_usr:
1025 assert(rsc->res.usr->type != NULL);
1026 type_name = prep_nid_for_label(rsc->res.usr->type);
1027 type = 0;
1028 break;
1029 default:
1030 type = rsc->type;
1034 * This follows a structure like:
1035 * struct wrc_resource {
1036 * INT32 id;
1037 * RSCNAME *resname;
1038 * INT32 restype;
1039 * RSCNAME *typename;
1040 * void *data;
1041 * UINT32 datasize;
1042 * };
1043 * The 'RSCNAME' is a pascal-style string where the
1044 * first byte/word denotes the size and the rest the string
1045 * itself.
1047 fprintf(fo, "%s%s:\n", prefix, rsc->c_name);
1048 if(global)
1049 fprintf(fo, "\t.globl\t%s%s\n", prefix, rsc->c_name);
1050 fprintf(fo, "\t.long\t%d, %s%s%s, %d, %s%s%s%s, %s%s_data, %d\n",
1051 rsc->name->type == name_ord ? rsc->name->name.i_name : 0,
1052 rsc->name->type == name_ord ? "0" : prefix,
1053 rsc->name->type == name_ord ? "" : rsc->c_name,
1054 rsc->name->type == name_ord ? "" : "_name",
1055 type,
1056 type ? "0" : prefix,
1057 type ? "" : "_",
1058 type ? "" : type_name,
1059 type ? "" : "_typename",
1060 prefix,
1061 rsc->c_name,
1062 rsc->binres->size - rsc->binres->dataidx);
1063 fprintf(fo, "\n");
1065 fprintf(fo, "\n");
1067 /* Write the indirection table */
1068 fprintf(fo, "#\n# Resource indirection table\n#\n");
1069 fprintf(fo, "\t.align\t4\n");
1070 fprintf(fo, "%s%s:\n", prefix, _ResTable);
1071 fprintf(fo, "\t.globl\t%s%s\n", prefix, _ResTable);
1072 for(rsc = top; rsc; rsc = rsc->next)
1074 fprintf(fo, "\t.long\t%s%s\n", prefix, rsc->c_name);
1076 fprintf(fo, "\t.long\t0\n");
1077 fprintf(fo, "\n");
1080 if(auto_register)
1081 fprintf(fo, s_file_autoreg_str, prefix, _ResTable);
1083 fprintf(fo, s_file_tail_str);
1084 fclose(fo);
1088 *****************************************************************************
1089 * Function : write_h_file
1090 * Syntax : void write_h_file(char *outname, resource_t *top)
1091 * Input :
1092 * outname - Filename to write to
1093 * top - The resource-tree to convert
1094 * Output :
1095 * Description :
1096 * Remarks :
1097 *****************************************************************************
1099 void write_h_file(char *outname, resource_t *top)
1101 FILE *fo;
1102 resource_t *rsc;
1103 char *h_prefix;
1105 #ifdef NEED_UNDERSCORE_PREFIX
1106 h_prefix = prefix + 1;
1107 #else
1108 h_prefix = prefix;
1109 #endif
1111 fo = fopen(outname, "wt");
1112 if(!fo)
1114 error("Could not open %s\n", outname);
1117 time(&now);
1118 fprintf(fo, h_file_head_str, input_name ? input_name : "stdin",
1119 cmdline, ctime(&now), now, now);
1121 /* First write the segment tables reference */
1122 if(create_dir)
1124 fprintf(fo, "extern %schar %s%s[];\n\n",
1125 constant ? "const " : "",
1126 h_prefix,
1127 win32 ? _PEResTab : _NEResTab);
1130 /* Write the resource data */
1131 for(rsc = top; global && rsc; rsc = rsc->next)
1133 if(!rsc->binres)
1134 continue;
1136 fprintf(fo, "extern %schar %s%s_data[];\n",
1137 constant ? "const " : "",
1138 h_prefix,
1139 rsc->c_name);
1142 if(indirect)
1144 if(global)
1145 fprintf(fo, "\n");
1147 /* Write the indirection structures */
1148 for(rsc = top; global && rsc; rsc = rsc->next)
1150 fprintf(fo, "extern %swrc_resource%d_t %s%s;\n",
1151 constant ? "const " : "",
1152 win32 ? 32 : 16,
1153 h_prefix,
1154 rsc->c_name);
1157 if(global)
1158 fprintf(fo, "\n");
1160 /* Write the indirection table */
1161 fprintf(fo, "extern %swrc_resource%d_t %s%s[];\n\n",
1162 constant ? "const " : "",
1163 win32 ? 32 : 16,
1164 h_prefix,
1165 _ResTable);
1168 fprintf(fo, h_file_tail_str);
1169 fclose(fo);