Added paragraph about different dll versions and structure sizes.
[wine.git] / tools / wrc / writeres.c
blobef02d4ccf968ac0536e082221344ab1699d8c7f6
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 char s_file_head_str[] =
22 "#\n"
23 "# This file is generated with wrc version " WRC_FULLVERSION ". Do not edit!\n"
24 "# Source : %s\n"
25 "# Cmdline: %s\n"
26 "# Date : %s"
27 "#\n\n"
28 "\t.data\n\n"
31 char s_file_tail_str[] =
32 "# <eof>\n\n"
35 char s_file_autoreg_str[] =
36 "\t.text\n"
37 ".LAuto_Register:\n"
38 "\tpushl\t$%s%s\n"
39 #ifdef NEED_UNDERSCORE_PREFIX
40 "\tcall\t_LIBRES_RegisterResources\n"
41 #else
42 "\tcall\tLIBRES_RegisterResources\n"
43 #endif
44 "\taddl\t$4,%%esp\n"
45 "\tret\n\n"
46 "\t.section .ctors,\"aw\"\n"
47 "\t.long\t.LAuto_Register\n\n"
50 char h_file_head_str[] =
51 "/*\n"
52 " * This file is generated with wrc version " WRC_FULLVERSION ". Do not edit!\n"
53 " * Source : %s\n"
54 " * Cmdline: %s\n"
55 " * Date : %s"
56 " */\n\n"
57 "#ifndef __%08x_H\n" /* This becomes the data of compile */
58 "#define __%08x_H\n\n"
59 "#ifndef __WRC_RSC_H\n"
60 "#include <wrc_rsc.h>\n"
61 "#endif\n\n"
64 char h_file_tail_str[] =
65 "#endif\n"
66 "/* <eof> */\n\n"
69 char _NEResTab[] = "_NEResTab";
70 char _PEResTab[] = "_PEResTab";
71 char _ResTable[] = "_ResTable";
73 res_count_t *rcarray = NULL;
74 int rccount = 0;
75 int n_id_entries = 0;
76 int n_name_entries = 0;
78 time_t now;
81 *****************************************************************************
82 * Function : write_resfile
83 * Syntax : void write_resfile(char *outname, resource_t *top)
84 * Input :
85 * outname - Filename to write to
86 * top - The resource-tree to convert
87 * Output :
88 * Description :
89 * Remarks :
90 *****************************************************************************
92 void write_resfile(char *outname, resource_t *top)
94 FILE *fo;
95 int ret;
96 char zeros[3] = {0, 0, 0};
98 fo = fopen(outname, "wb");
99 if(!fo)
101 error("Could not open %s\n", outname);
104 if(win32)
106 /* Put an empty resource first to signal win32 format */
107 res_t *res = new_res();
108 put_dword(res, 0); /* ResSize */
109 put_dword(res, 0x00000020); /* HeaderSize */
110 put_word(res, 0xffff); /* ResType */
111 put_word(res, 0);
112 put_word(res, 0xffff); /* ResName */
113 put_word(res, 0);
114 put_dword(res, 0); /* DataVersion */
115 put_word(res, 0); /* Memory options */
116 put_word(res, 0); /* Language */
117 put_dword(res, 0); /* Version */
118 put_dword(res, 0); /* Charateristics */
119 ret = fwrite(res->data, 1, res->size, fo);
120 if(ret != res->size)
122 fclose(fo);
123 error("Error writing %s", outname);
125 free(res);
128 for(; top; top = top->next)
130 if(!top->binres)
131 continue;
133 ret = fwrite(top->binres->data, 1, top->binres->size, fo);
134 if(ret != top->binres->size)
136 fclose(fo);
137 error("Error writing %s", outname);
139 if(win32 && (top->binres->size & 0x03))
141 /* Write padding */
142 ret = fwrite(zeros, 1, 4 - (top->binres->size & 0x03), fo);
143 if(ret != 4 - (top->binres->size & 0x03))
145 fclose(fo);
146 error("Error writing %s", outname);
150 fclose(fo);
154 *****************************************************************************
155 * Function : write_s_res
156 * Syntax : void write_s_res(FILE *fp, res_t *res)
157 * Input :
158 * Output :
159 * Description :
160 * Remarks :
161 *****************************************************************************
163 #define BYTESPERLINE 8
164 void write_s_res(FILE *fp, res_t *res)
166 int idx = res->dataidx;
167 int end = res->size;
168 int rest = (end - idx) % BYTESPERLINE;
169 int lines = (end - idx) / BYTESPERLINE;
170 int i, j;
172 for(i = 0 ; i < lines; i++)
174 fprintf(fp, "\t.byte\t");
175 for(j = 0; j < BYTESPERLINE; j++, idx++)
177 fprintf(fp, "0x%02x%s", res->data[idx] & 0xff,
178 j == BYTESPERLINE-1 ? "" : ", ");
180 fprintf(fp, "\n");
182 if(rest)
184 fprintf(fp, "\t.byte\t");
185 for(j = 0; j < rest; j++, idx++)
187 fprintf(fp, "0x%02x%s", res->data[idx] & 0xff,
188 j == rest-1 ? "" : ", ");
190 fprintf(fp, "\n");
195 *****************************************************************************
196 * Function : write_name_str
197 * Syntax : void write_name_str(FILE *fp, name_id_t *nid)
198 * Input :
199 * Output :
200 * Description :
201 * Remarks : One level self recursive for string type conversion
202 *****************************************************************************
204 void write_name_str(FILE *fp, name_id_t *nid)
206 res_t res;
207 assert(nid->type == name_str);
209 if(!win32 && nid->name.s_name->type == str_char)
211 res.size = strlen(nid->name.s_name->str.cstr);
212 if(res.size > 254)
213 error("Can't write strings larger than 254 bytes");
214 if(res.size == 0)
215 internal_error(__FILE__, __LINE__, "Attempt to write empty string");
216 res.dataidx = 0;
217 res.data = (char *)xmalloc(res.size + 1);
218 res.data[0] = (char)res.size;
219 res.size++; /* We need to write the lenth byte as well */
220 strcpy(res.data+1, nid->name.s_name->str.cstr);
221 write_s_res(fp, &res);
222 free(res.data);
224 else if(!win32 && nid->name.s_name->type == str_unicode)
226 name_id_t lnid;
227 string_t str;
229 lnid.type = name_str;
230 lnid.name.s_name = &str;
231 str.type = str_char;
232 str.str.cstr = dupwstr2cstr(nid->name.s_name->str.wstr);
233 write_name_str(fp, &lnid);
234 free(str.str.cstr);
236 else if(win32 && nid->name.s_name->type == str_char)
238 name_id_t lnid;
239 string_t str;
241 lnid.type = name_str;
242 lnid.name.s_name = &str;
243 str.type = str_unicode;
244 str.str.wstr = dupcstr2wstr(nid->name.s_name->str.cstr);
245 write_name_str(fp, &lnid);
246 free(str.str.wstr);
248 else if(win32 && nid->name.s_name->type == str_unicode)
250 res.size = wstrlen(nid->name.s_name->str.wstr);
251 if(res.size > 65534)
252 error("Can't write strings larger than 65534 bytes");
253 if(res.size == 0)
254 internal_error(__FILE__, __LINE__, "Attempt to write empty string");
255 res.dataidx = 0;
256 res.data = (char *)xmalloc((res.size + 1) * 2);
257 ((short *)res.data)[0] = (short)res.size;
258 wstrcpy((short *)(res.data+2), nid->name.s_name->str.wstr);
259 res.size *= 2; /* Function writes bytes, not shorts... */
260 res.size += 2; /* We need to write the length word as well */
261 write_s_res(fp, &res);
262 free(res.data);
264 else
266 internal_error(__FILE__, __LINE__, "Hmm, requested to write a string of unknown type %d",
267 nid->name.s_name->type);
272 *****************************************************************************
273 * Function : compare_name_id
274 * Syntax : int compare_name_id(name_id_t *n1, name_id_t *n2)
275 * Input :
276 * Output :
277 * Description :
278 * Remarks :
279 *****************************************************************************
281 int compare_name_id(name_id_t *n1, name_id_t *n2)
283 if(n1->type == name_ord && n2->type == name_ord)
285 return n1->name.i_name - n2->name.i_name;
287 else if(n1->type == name_str && n2->type == name_str)
289 if(n1->name.s_name->type == str_char
290 && n2->name.s_name->type == str_char)
292 return stricmp(n1->name.s_name->str.cstr, n2->name.s_name->str.cstr);
294 else if(n1->name.s_name->type == str_unicode
295 && n2->name.s_name->type == str_unicode)
297 return wstricmp(n1->name.s_name->str.wstr, n2->name.s_name->str.wstr);
299 else
301 internal_error(__FILE__, __LINE__, "Can't yet compare strings of mixed type");
304 else if(n1->type == name_ord && n2->type == name_str)
305 return -1;
306 else if(n1->type == name_str && n2->type == name_ord)
307 return 1;
308 else
309 internal_error(__FILE__, __LINE__, "Comparing name-ids with unknown types (%d, %d)",
310 n1->type, n2->type);
312 return 0; /* Keep the compiler happy */
316 *****************************************************************************
317 * Function : find_counter
318 * Syntax : res_count_t *find_counter(name_id_t *type)
319 * Input :
320 * Output :
321 * Description :
322 * Remarks :
323 *****************************************************************************
325 res_count_t *find_counter(name_id_t *type)
327 int i;
328 for(i = 0; i < rccount; i++)
330 if(!compare_name_id(type, &(rcarray[i].type)))
331 return &rcarray[i];
333 return NULL;
337 *****************************************************************************
338 * Function : count_resources
339 * Syntax : res_count_t *count_resources(resource_t *top)
340 * Input :
341 * Output :
342 * Description :
343 * Remarks : The whole lot is converted into arrays because they are
344 * easy sortable. Makes the lot almost unreadable, but it
345 * works (I hope). Basically you have to keep in mind that
346 * the lot is a three-dimensional structure for win32 and a
347 * two-dimensional structure for win16.
348 *****************************************************************************
350 #define RCT(v) (*((resource_t **)(v)))
351 /* qsort sorting function */
352 int sort_name_id(const void *e1, const void *e2)
354 return compare_name_id(RCT(e1)->name, RCT(e2)->name);
357 int sort_language(const void *e1, const void *e2)
359 assert((RCT(e1)->lan) != NULL);
360 assert((RCT(e2)->lan) != NULL);
362 return MAKELANGID(RCT(e1)->lan->id, RCT(e1)->lan->sub)
363 - MAKELANGID(RCT(e2)->lan->id, RCT(e2)->lan->sub);
365 #undef RCT
366 #define RCT(v) ((res_count_t *)(v))
367 int sort_type(const void *e1, const void *e2)
369 return compare_name_id(&(RCT(e1)->type), &(RCT(e2)->type));
371 #undef RCT
373 void count_resources(resource_t *top)
375 resource_t *rsc;
376 res_count_t *rcp;
377 name_id_t nid;
378 int i, j;
380 for(rsc = top; rsc; rsc = rsc->next)
382 if(!rsc->binres)
383 continue;
384 switch(rsc->type)
386 case res_dlgex:
387 nid.name.i_name = WRC_RT_DIALOG;
388 nid.type = name_ord;
389 break;
390 case res_menex:
391 nid.name.i_name = WRC_RT_MENU;
392 nid.type = name_ord;
393 break;
394 case res_usr:
395 nid = *(rsc->res.usr->type);
396 break;
397 default:
398 nid.name.i_name = rsc->type;
399 nid.type = name_ord;
402 if((rcp = find_counter(&nid)) == NULL)
404 /* Count the number of uniq ids and names */
406 if(nid.type == name_ord)
407 n_id_entries++;
408 else
409 n_name_entries++;
411 if(!rcarray)
413 rcarray = (res_count_t *)xmalloc(sizeof(res_count_t));
414 rccount = 1;
415 rcarray[0].count = 1;
416 rcarray[0].type = nid;
417 rcarray[0].rscarray = (resource_t **)xmalloc(sizeof(resource_t *));
418 rcarray[0].rscarray[0] = rsc;
420 else
422 rccount++;
423 rcarray = (res_count_t *)xrealloc(rcarray, rccount * sizeof(res_count_t));
424 rcarray[rccount-1].count = 1;
425 rcarray[rccount-1].type = nid;
426 rcarray[rccount-1].rscarray = (resource_t **)xmalloc(sizeof(resource_t *));
427 rcarray[rccount-1].rscarray[0] = rsc;
430 else
432 rcp->count++;
433 rcp->rscarray = (resource_t **)xrealloc(rcp->rscarray, rcp->count * sizeof(resource_t *));
434 rcp->rscarray[rcp->count-1] = rsc;
438 if(!win32)
440 /* We're done, win16 requires no special sorting */
441 return;
444 /* We now have a unsorted list of types with an array of res_count_t
445 * in rcarray[0..rccount-1]. And we have names of one type in the
446 * rcarray[x].rsc[0..rcarray[x].count-1] arrays.
447 * The list needs to be sorted for win32's top level tree structure.
450 /* Sort the types */
451 if(rccount > 1)
452 qsort(rcarray, rccount, sizeof(rcarray[0]), sort_type);
454 /* Now sort the name-id arrays */
455 for(i = 0; i < rccount; i++)
457 if(rcarray[i].count > 1)
458 qsort(rcarray[i].rscarray, rcarray[i].count, sizeof(rcarray[0].rscarray[0]), sort_name_id);
461 /* Now split the name-id arrays into name/language
462 * subs. Don't look at the awfull expressions...
463 * We do this by taking the array elements out of rscarray and putting
464 * together a new array in rsc32array.
466 for(i = 0; i < rccount; i++)
468 res_count_t *rcap;
470 assert(rcarray[i].count >= 1);
472 /* rcap points to the current type we are dealing with */
473 rcap = &(rcarray[i]);
475 /* Insert the first name-id */
476 rcap->rsc32array = (res32_count_t *)xmalloc(sizeof(res32_count_t));
477 rcap->count32 = 1;
478 rcap->rsc32array[0].rsc = (resource_t **)xmalloc(sizeof(resource_t *));
479 rcap->rsc32array[0].count = 1;
480 rcap->rsc32array[0].rsc[0] = rcap->rscarray[0];
481 if(rcap->rscarray[0]->name->type == name_ord)
483 rcap->n_id_entries = 1;
484 rcap->n_name_entries = 0;
486 else
488 rcap->n_id_entries = 0;
489 rcap->n_name_entries = 1;
492 /* Now loop over the resting resources of the current type
493 * to find duplicate names (which should have different
494 * languages).
496 for(j = 1; j < rcap->count; j++)
498 res32_count_t *r32cp;
500 /* r32cp points to the current res32_count structure
501 * that holds the resource name we are processing.
503 r32cp = &(rcap->rsc32array[rcap->count32-1]);
505 if(!compare_name_id(r32cp->rsc[0]->name, rcarray[i].rscarray[j]->name))
507 /* Names are the same, add to list */
508 r32cp->count++;
509 r32cp->rsc = (resource_t **)xrealloc(r32cp->rsc, r32cp->count * sizeof(resource_t *));
510 r32cp->rsc[r32cp->count-1] = rcap->rscarray[j];
512 if(rcap->rscarray[j]->name->type == name_ord)
514 rcap->n_id_entries = 1;
515 rcap->n_name_entries = 0;
517 else
519 rcap->n_id_entries = 0;
520 rcap->n_name_entries = 1;
523 else
525 /* New name-id, sort the old one by
526 * language and create new list
528 if(r32cp->count > 1)
529 qsort(r32cp->rsc, r32cp->count, sizeof(r32cp->rsc[0]), sort_language);
530 rcap->count32++;
531 rcap->rsc32array = (res32_count_t*)xrealloc(rcap->rsc32array, rcap->count32 * sizeof(res32_count_t));
532 rcap->rsc32array[rcap->count32-1].rsc = (resource_t **)xmalloc(sizeof(resource_t *));
533 rcap->rsc32array[rcap->count32-1].count = 1;
534 rcap->rsc32array[rcap->count32-1].rsc[0] = rcap->rscarray[j];
536 if(rcap->rscarray[j]->name->type == name_ord)
537 rcap->n_id_entries++;
538 else
539 rcap->n_name_entries++;
542 /* Also sort the languages of the last name group */
543 if(rcap->rsc32array[rcap->count32-1].count > 1)
544 qsort(rcap->rsc32array[rcap->count32-1].rsc,
545 rcap->rsc32array[rcap->count32-1].count,
546 sizeof(rcap->rsc32array[rcap->count32-1].rsc[0]),
547 sort_language);
552 *****************************************************************************
553 * Function : write_pe_segment
554 * Syntax : void write_pe_segment(FILE *fp, resource_t *top)
555 * Input :
556 * Output :
557 * Description :
558 * Remarks :
559 *****************************************************************************
561 void write_pe_segment(FILE *fp, resource_t *top)
563 int i;
565 fprintf(fp, "\t.align\t4\n");
566 fprintf(fp, "%s%s:\n", prefix, _PEResTab);
567 fprintf(fp, "\t.globl\t%s%s\n", prefix, _PEResTab);
568 /* Flags */
569 fprintf(fp, "\t.long\t0\n");
570 /* Time/Date stamp */
571 fprintf(fp, "\t.long\t0x%08lx\n", now);
572 /* Version */
573 fprintf(fp, "\t.long\t0\n"); /* FIXME: must version be filled out? */
574 /* # of id entries, # of name entries */
575 fprintf(fp, "\t.short\t%d, %d\n", n_name_entries, n_id_entries);
577 /* Write the type level of the tree */
578 for(i = 0; i < rccount; i++)
580 res_count_t *rcp;
581 char *label;
583 rcp = &rcarray[i];
585 /* TypeId */
586 if(rcp->type.type == name_ord)
587 fprintf(fp, "\t.long\t%d\n", rcp->type.name.i_name);
588 else
590 char *name = prep_nid_for_label(&(rcp->type));
591 fprintf(fp, "\t.long\t(%s_%s_typename - %s%s) | 0x80000000\n",
592 prefix,
593 name,
594 prefix,
595 _PEResTab);
597 /* Offset */
598 label = prep_nid_for_label(&(rcp->type));
599 fprintf(fp, "\t.long\t(.L%s - %s%s) | 0x80000000\n",
600 label,
601 prefix,
602 _PEResTab);
605 /* Write the name level of the tree */
607 for(i = 0; i < rccount; i++)
609 res_count_t *rcp;
610 char *typelabel;
611 char *namelabel;
612 int j;
614 rcp = &rcarray[i];
616 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
617 fprintf(fp, ".L%s:\n", typelabel);
619 fprintf(fp, "\t.long\t0\n"); /* Flags */
620 fprintf(fp, "\t.long\t0x%08lx\n", now); /* TimeDate */
621 fprintf(fp, "\t.long\t0\n"); /* FIXME: must version be filled out? */
622 fprintf(fp, "\t.short\t%d, %d\n", rcp->n_name_entries, rcp->n_id_entries);
623 for(j = 0; j < rcp->count32; j++)
625 resource_t *rsc = rcp->rsc32array[j].rsc[0];
626 /* NameId */
627 if(rsc->name->type == name_ord)
628 fprintf(fp, "\t.long\t%d\n", rsc->name->name.i_name);
629 else
631 fprintf(fp, "\t.long\t(%s%s_name - %s%s) | 0x80000000\n",
632 prefix,
633 rsc->c_name,
634 prefix,
635 _PEResTab);
637 /* Maybe FIXME: Unescape the tree (ommit 0x80000000) and
638 * put the offset to the resource data entry.
639 * ?? Is unescaping worth while ??
641 /* Offset */
642 namelabel = prep_nid_for_label(rsc->name);
643 fprintf(fp, "\t.long\t(.L%s_%s - %s%s) | 0x80000000\n",
644 typelabel,
645 namelabel,
646 prefix,
647 _PEResTab);
649 free(typelabel);
652 /* Write the language level of the tree */
654 for(i = 0; i < rccount; i++)
656 res_count_t *rcp;
657 char *namelabel;
658 char *typelabel;
659 int j;
661 rcp = &rcarray[i];
662 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
664 for(j = 0; j < rcp->count32; j++)
666 res32_count_t *r32cp = &(rcp->rsc32array[j]);
667 int k;
669 namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
670 fprintf(fp, ".L%s_%s:\n", typelabel, namelabel);
672 fprintf(fp, "\t.long\t0\n"); /* Flags */
673 fprintf(fp, "\t.long\t0x%08lx\n", now); /* TimeDate */
674 fprintf(fp, "\t.long\t0\n"); /* FIXME: must version be filled out? */
675 fprintf(fp, "\t.short\t0, %d\n", r32cp->count);
677 for(k = 0; k < r32cp->count; k++)
679 resource_t *rsc = r32cp->rsc[k];
680 assert(rsc->lan != NULL);
681 /* LanguageId */
682 fprintf(fp, "\t.long\t0x%08x\n", rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
683 /* Offset */
684 fprintf(fp, "\t.long\t.L%s_%s_%d - %s%s\n",
685 typelabel,
686 namelabel,
687 rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0,
688 prefix,
689 _PEResTab);
691 free(namelabel);
693 free(typelabel);
696 /* Write the resource table itself */
698 for(i = 0; i < rccount; i++)
700 res_count_t *rcp;
701 char *namelabel;
702 char *typelabel;
703 int j;
705 rcp = &rcarray[i];
706 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
708 for(j = 0; j < rcp->count32; j++)
710 res32_count_t *r32cp = &(rcp->rsc32array[j]);
711 int k;
713 namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
715 for(k = 0; k < r32cp->count; k++)
717 resource_t *rsc = r32cp->rsc[k];
719 assert(rsc->lan != NULL);
721 fprintf(fp, ".L%s_%s_%d:\n",
722 typelabel,
723 namelabel,
724 rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
726 /* Data RVA */
727 fprintf(fp, "\t.long\t%s%s_data - %s%s\n",
728 prefix,
729 rsc->c_name,
730 prefix,
731 _PEResTab);
732 /* Size */
733 fprintf(fp, "\t.long\t%d\n",
734 rsc->binres->size - rsc->binres->dataidx);
735 /* CodePage */
736 fprintf(fp, "\t.long\t%ld\n", codepage);
737 /* Reserved */
738 fprintf(fp, "\t.long\t0\n");
740 free(namelabel);
742 free(typelabel);
748 *****************************************************************************
749 * Function : write_ne_segment
750 * Syntax : void write_ne_segment(FILE *fp, resource_t *top)
751 * Input :
752 * Output :
753 * Description :
754 * Remarks :
755 *****************************************************************************
757 void write_ne_segment(FILE *fp, resource_t *top)
759 int i, j;
761 fprintf(fp, "\t.align\t4\n");
762 fprintf(fp, "%s%s:\n", prefix, _NEResTab);
763 fprintf(fp, "\t.globl\t%s%s\n", prefix, _NEResTab);
765 /* AlignmentShift */
766 fprintf(fp, "\t.short\t%d\n", alignment_pwr);
768 /* TypeInfo */
769 for(i = 0; i < rccount; i++)
771 res_count_t *rcp = &rcarray[i];
773 /* TypeId */
774 if(rcp->type.type == name_ord)
775 fprintf(fp, "\t.short\t0x%04x\n", rcp->type.name.i_name | 0x8000);
776 else
777 fprintf(fp, "\t.short\t%s_%s_typename - %s%s\n",
778 prefix,
779 rcp->type.name.s_name->str.cstr,
780 prefix,
781 _NEResTab);
782 /* ResourceCount */
783 fprintf(fp, "\t.short\t%d\n", rcp->count);
784 /* Reserved */
785 fprintf(fp, "\t.long\t0\n");
786 /* NameInfo */
787 for(j = 0; j < rcp->count; j++)
789 /* FIXME: dividing by `alignment` doesn't seem to
790 * work with as (GAS). Shifting results in the
791 * correct behaviour. Maybe an as bug or just my
792 * lack of knowing as expression-syntax.
794 /* Offset */
796 * VERY IMPORTANT:
797 * The offset is relative to the beginning of the NE resource segment
798 * and _NOT_ to the file-beginning. This is because we do not have a
799 * file based resource, but a simulated NE segment. The offset _is_
800 * scaled by the AlignShift field.
801 * All other things are as the MS doc describes (alignment etc.)
803 fprintf(fp, "\t.short\t(%s%s_data - %s%s) >> %d\n",
804 prefix,
805 rcp->rscarray[j]->c_name,
806 prefix,
807 _NEResTab,
808 alignment_pwr);
809 /* Length */
810 fprintf(fp, "\t.short\t%d\n",
811 rcp->rscarray[j]->binres->size - rcp->rscarray[j]->binres->dataidx);
812 /* Flags */
813 fprintf(fp, "\t.short\t0x%04x\n", (WORD)rcp->rscarray[j]->memopt);
814 /* Id */
815 if(rcp->rscarray[j]->name->type == name_ord)
816 fprintf(fp, "\t.short\t0x%04x\n", rcp->rscarray[j]->name->name.i_name | 0x8000);
817 else
818 fprintf(fp, "\t.short\t%s%s_name - %s%s\n",
819 prefix,
820 rcp->rscarray[j]->c_name,
821 prefix,
822 _NEResTab);
823 /* Handle and Usage */
824 fprintf(fp, "\t.short\t0, 0\n");
827 /* EndTypes */
828 fprintf(fp, "\t.short\t0\n");
832 *****************************************************************************
833 * Function : write_rsc_names
834 * Syntax : void write_rsc_names(FILE *fp, resource_t *top)
835 * Input :
836 * Output :
837 * Description :
838 * Remarks :
839 *****************************************************************************
841 void write_rsc_names(FILE *fp, resource_t *top)
843 int i, j;
845 if(win32)
847 /* Write the names */
849 for(i = 0; i < rccount; i++)
851 res_count_t *rcp;
853 rcp = &rcarray[i];
855 if(rcp->type.type == name_str)
857 char *name = prep_nid_for_label(&(rcp->type));
858 fprintf(fp, "%s_%s_typename:\n",
859 prefix,
860 name);
861 write_name_str(fp, &(rcp->type));
864 for(j = 0; j < rcp->count32; j++)
866 resource_t *rsc = rcp->rsc32array[j].rsc[0];
868 if(rsc->name->type == name_str)
870 fprintf(fp, "%s%s_name:\n",
871 prefix,
872 rsc->c_name);
873 write_name_str(fp, rsc->name);
878 else
880 /* ResourceNames */
881 for(i = 0; i < rccount; i++)
883 res_count_t *rcp = &rcarray[i];
885 for(j = 0; j < rcp->count; j++)
887 if(rcp->type.type == name_str)
889 fprintf(fp, "%s_%s_typename:\n",
890 prefix,
891 rcp->type.name.s_name->str.cstr);
892 write_name_str(fp, &(rcp->type));
894 if(rcp->rscarray[j]->name->type == name_str)
896 fprintf(fp, "%s%s_name:\n",
897 prefix,
898 rcp->rscarray[j]->c_name);
899 write_name_str(fp, rcp->rscarray[j]->name);
903 /* EndNames */
905 /* This is to end the NE resource table */
906 if(create_dir)
907 fprintf(fp, "\t.byte\t0\n");
910 fprintf(fp, "\n");
914 *****************************************************************************
915 * Function : write_s_file
916 * Syntax : void write_s_file(char *outname, resource_t *top)
917 * Input :
918 * outname - Filename to write to
919 * top - The resource-tree to convert
920 * Output :
921 * Description :
922 * Remarks :
923 *****************************************************************************
925 void write_s_file(char *outname, resource_t *top)
927 FILE *fo;
928 resource_t *rsc;
930 fo = fopen(outname, "wt");
931 if(!fo)
933 error("Could not open %s\n", outname);
936 now = time(NULL);
937 fprintf(fo, s_file_head_str, input_name ? input_name : "stdin",
938 cmdline, ctime(&now));
940 /* Get an idea how many we have and restructure the tables */
941 count_resources(top);
943 /* First write the segment tables */
944 if(create_dir)
946 if(win32)
947 write_pe_segment(fo, top);
948 else
949 write_ne_segment(fo, top);
952 /* Dump the names */
953 write_rsc_names(fo, top);
955 if(!indirect_only)
957 /* Write the resource data */
958 fprintf(fo, "#\n# Resource binary data\n#\n");
959 for(rsc = top; rsc; rsc = rsc->next)
961 if(!rsc->binres)
962 continue;
964 fprintf(fo, "\t.align\t%d\n", win32 ? 4 : alignment);
965 fprintf(fo, "%s%s_data:\n", prefix, rsc->c_name);
966 if(global)
967 fprintf(fo, "\t.globl\t%s%s_data\n", prefix, rsc->c_name);
969 write_s_res(fo, rsc->binres);
971 fprintf(fo, "\n");
975 if(indirect)
977 /* Write the indirection structures */
978 fprintf(fo, "\n#\n# Resource indirection structures\n#\n");
979 fprintf(fo, "\t.align\t4\n");
980 for(rsc = top; rsc; rsc = rsc->next)
982 int type;
983 char *type_name = NULL;
985 if(!rsc->binres)
986 continue;
988 switch(rsc->type)
990 case res_menex:
991 type = WRC_RT_MENU;
992 break;
993 case res_dlgex:
994 type = WRC_RT_DIALOG;
995 break;
996 case res_usr:
997 assert(rsc->res.usr->type != NULL);
998 type_name = prep_nid_for_label(rsc->res.usr->type);
999 type = 0;
1000 break;
1001 default:
1002 type = rsc->type;
1006 * This follows a structure like:
1007 * struct wrc_resource {
1008 * INT32 id;
1009 * RSCNAME *resname;
1010 * INT32 restype;
1011 * RSCNAME *typename;
1012 * void *data;
1013 * UINT32 datasize;
1014 * };
1015 * The 'RSCNAME' is a pascal-style string where the
1016 * first byte/word denotes the size and the rest the string
1017 * itself.
1019 fprintf(fo, "%s%s:\n", prefix, rsc->c_name);
1020 if(global)
1021 fprintf(fo, "\t.globl\t%s%s\n", prefix, rsc->c_name);
1022 fprintf(fo, "\t.long\t%d, %s%s%s, %d, %s%s%s%s, %s%s_data, %d\n",
1023 rsc->name->type == name_ord ? rsc->name->name.i_name : 0,
1024 rsc->name->type == name_ord ? "0" : prefix,
1025 rsc->name->type == name_ord ? "" : rsc->c_name,
1026 rsc->name->type == name_ord ? "" : "_name",
1027 type,
1028 type ? "0" : prefix,
1029 type ? "" : "_",
1030 type ? "" : type_name,
1031 type ? "" : "_typename",
1032 prefix,
1033 rsc->c_name,
1034 rsc->binres->size - rsc->binres->dataidx);
1035 fprintf(fo, "\n");
1037 fprintf(fo, "\n");
1039 /* Write the indirection table */
1040 fprintf(fo, "#\n# Resource indirection table\n#\n");
1041 fprintf(fo, "\t.align\t4\n");
1042 fprintf(fo, "%s%s:\n", prefix, _ResTable);
1043 fprintf(fo, "\t.globl\t%s%s\n", prefix, _ResTable);
1044 for(rsc = top; rsc; rsc = rsc->next)
1046 fprintf(fo, "\t.long\t%s%s\n", prefix, rsc->c_name);
1048 fprintf(fo, "\t.long\t0\n");
1049 fprintf(fo, "\n");
1052 if(auto_register)
1053 fprintf(fo, s_file_autoreg_str, prefix, _ResTable);
1055 fprintf(fo, s_file_tail_str);
1056 fclose(fo);
1060 *****************************************************************************
1061 * Function : write_h_file
1062 * Syntax : void write_h_file(char *outname, resource_t *top)
1063 * Input :
1064 * outname - Filename to write to
1065 * top - The resource-tree to convert
1066 * Output :
1067 * Description :
1068 * Remarks :
1069 *****************************************************************************
1071 void write_h_file(char *outname, resource_t *top)
1073 FILE *fo;
1074 resource_t *rsc;
1075 char *h_prefix;
1077 #ifdef NEED_UNDERSCORE_PREFIX
1078 h_prefix = prefix + 1;
1079 #else
1080 h_prefix = prefix;
1081 #endif
1083 fo = fopen(outname, "wt");
1084 if(!fo)
1086 error("Could not open %s\n", outname);
1089 time(&now);
1090 fprintf(fo, h_file_head_str, input_name ? input_name : "stdin",
1091 cmdline, ctime(&now), now, now);
1093 /* First write the segment tables reference */
1094 if(create_dir)
1096 fprintf(fo, "extern %schar %s%s[];\n\n",
1097 constant ? "const " : "",
1098 h_prefix,
1099 win32 ? _PEResTab : _NEResTab);
1102 /* Write the resource data */
1103 for(rsc = top; global && rsc; rsc = rsc->next)
1105 if(!rsc->binres)
1106 continue;
1108 fprintf(fo, "extern %schar %s%s_data[];\n",
1109 constant ? "const " : "",
1110 h_prefix,
1111 rsc->c_name);
1114 if(indirect)
1116 if(global)
1117 fprintf(fo, "\n");
1119 /* Write the indirection structures */
1120 for(rsc = top; global && rsc; rsc = rsc->next)
1122 fprintf(fo, "extern %swrc_resource%d_t %s%s;\n",
1123 constant ? "const " : "",
1124 win32 ? 32 : 16,
1125 h_prefix,
1126 rsc->c_name);
1129 if(global)
1130 fprintf(fo, "\n");
1132 /* Write the indirection table */
1133 fprintf(fo, "extern %swrc_resource%d_t %s%s[];\n\n",
1134 constant ? "const " : "",
1135 win32 ? 32 : 16,
1136 h_prefix,
1137 _ResTable);
1140 fprintf(fo, h_file_tail_str);
1141 fclose(fo);