Added stdcall64 entry point type to allow correct relay debugging
[wine] / tools / wrc / writeres.c
1 /*
2  * Write .res, .s and .h file(s) from a resource-tree
3  *
4  * Copyright 1998 Bertho A. Stultiens
5  *
6  */
7
8 #include "config.h"
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <assert.h>
14
15 #include "wrc.h"
16 #include "writeres.h"
17 #include "genres.h"
18 #include "newstruc.h"
19 #include "utils.h"
20
21 #ifdef NEED_UNDERSCORE_PREFIX
22 char Underscore[] = "_";
23 #else
24 char Underscore[] = "";
25 #endif
26
27 static char s_file_head_str[] =
28         "/* This file is generated with wrc version " WRC_FULLVERSION ". Do not edit! */\n"
29         "/* Source : %s */\n"
30         "/* Cmdline: %s */\n"
31         "/* Date   : %s */\n"
32         "\n"
33         "\t.data\n"
34         "\n"
35         ;
36
37 static char s_file_tail_str[] =
38         "/* <eof> */\n"
39         "\n"
40         ;
41
42 static char s_file_autoreg_str[] =
43         "\t.text\n"
44         ".LAuto_Register:\n"
45         "\tpushl\t$%s%s\n"
46 #ifdef NEED_UNDERSCORE_PREFIX
47         "\tcall\t_LIBRES_RegisterResources\n"
48 #else
49         "\tcall\tLIBRES_RegisterResources\n"
50 #endif
51         "\taddl\t$4,%%esp\n"
52         "\tret\n\n"
53 #ifdef __NetBSD__
54         ".stabs \"___CTOR_LIST__\",22,0,0,.LAuto_Register\n\n"
55 #else
56         "\t.section .ctors,\"aw\"\n"
57         "\t.long\t.LAuto_Register\n\n"
58 #endif
59         ;
60
61 static char h_file_head_str[] =
62         "/*\n"
63         " * This file is generated with wrc version " WRC_FULLVERSION ". Do not edit!\n"
64         " * Source : %s\n"
65         " * Cmdline: %s\n"
66         " * Date   : %s"
67         " */\n"
68         "\n"
69         "#ifndef __%08lx_H\n"   /* This becomes the date of compile */
70         "#define __%08lx_H\n"
71         "\n"
72         "#include <wrc_rsc.h>\n"
73         "\n"
74         ;
75
76 static char h_file_tail_str[] =
77         "#endif\n"
78         "/* <eof> */\n\n"
79         ;
80
81 char _NEResTab[] = "_NEResTab";
82 char _PEResTab[] = "_PEResTab";
83 char _ResTable[] = "_ResTable";
84
85 /* Variables used for resource sorting */
86 res_count_t *rcarray = NULL;    /* Type-level count array */
87 int rccount = 0;                /* Nr of entries in the type-level array */
88 int n_id_entries = 0;           /* win32 only: Nr of unique ids in the type-level array */ 
89 int n_name_entries = 0;         /* win32 only: Nr of unique namess in the type-level array */
90
91 static int direntries;          /* win32 only: Total number of unique resources */
92
93 /*
94  *****************************************************************************
95  * Function     : write_resfile
96  * Syntax       : void write_resfile(char *outname, resource_t *top)
97  * Input        :
98  *      outname - Filename to write to
99  *      top     - The resource-tree to convert
100  * Output       :
101  * Description  :
102  * Remarks      :
103  *****************************************************************************
104 */
105 void write_resfile(char *outname, resource_t *top)
106 {
107         FILE *fo;
108         int ret;
109         char zeros[3] = {0, 0, 0};
110
111         fo = fopen(outname, "wb");
112         if(!fo)
113         {
114                 error("Could not open %s\n", outname);
115         }
116
117         if(win32)
118         {
119                 /* Put an empty resource first to signal win32 format */
120                 res_t *res = new_res();
121                 put_dword(res, 0);              /* ResSize */
122                 put_dword(res, 0x00000020);     /* HeaderSize */
123                 put_word(res, 0xffff);          /* ResType */
124                 put_word(res, 0);
125                 put_word(res, 0xffff);          /* ResName */
126                 put_word(res, 0);
127                 put_dword(res, 0);              /* DataVersion */
128                 put_word(res, 0);               /* Memory options */
129                 put_word(res, 0);               /* Language */
130                 put_dword(res, 0);              /* Version */
131                 put_dword(res, 0);              /* Charateristics */
132                 ret = fwrite(res->data, 1, res->size, fo);
133                 if(ret != res->size)
134                 {
135                         fclose(fo);
136                         error("Error writing %s", outname);
137                 }
138                 free(res);
139         }
140
141         for(; top; top = top->next)
142         {
143                 if(!top->binres)
144                         continue;
145
146                 ret = fwrite(top->binres->data, 1, top->binres->size, fo);
147                 if(ret != top->binres->size)
148                 {
149                         fclose(fo);
150                         error("Error writing %s", outname);
151                 }
152                 if(win32 && (top->binres->size & 0x03))
153                 {
154                         /* Write padding */
155                         ret = fwrite(zeros, 1, 4 - (top->binres->size & 0x03), fo);
156                         if(ret != 4 - (top->binres->size & 0x03))
157                         {
158                                 fclose(fo);
159                                 error("Error writing %s", outname);
160                         }
161                 }
162         }
163         fclose(fo);
164 }
165
166 /*
167  *****************************************************************************
168  * Function     : write_s_res
169  * Syntax       : void write_s_res(FILE *fp, res_t *res)
170  * Input        :
171  * Output       :
172  * Description  :
173  * Remarks      :
174  *****************************************************************************
175 */
176 #define BYTESPERLINE    8
177 static void write_s_res(FILE *fp, res_t *res)
178 {
179         int idx = res->dataidx;
180         int end = res->size;
181         int rest = (end - idx) % BYTESPERLINE;
182         int lines = (end - idx) / BYTESPERLINE;
183         int i, j;
184
185         for(i = 0 ; i < lines; i++)
186         {
187                 fprintf(fp, "\t.byte\t");
188                 for(j = 0; j < BYTESPERLINE; j++, idx++)
189                 {
190                         fprintf(fp, "0x%02x%s", res->data[idx] & 0xff,
191                                         j == BYTESPERLINE-1 ? "" : ", ");
192                 }
193                 fprintf(fp, "\n");
194         }
195         if(rest)
196         {
197                 fprintf(fp, "\t.byte\t");
198                 for(j = 0; j < rest; j++, idx++)
199                 {
200                         fprintf(fp, "0x%02x%s", res->data[idx] & 0xff,
201                                         j == rest-1 ? "" : ", ");
202                 }
203                 fprintf(fp, "\n");
204         }
205 }
206 #undef BYTESPERLINE
207
208 /*
209  *****************************************************************************
210  * Function     : write_name_str
211  * Syntax       : void write_name_str(FILE *fp, name_id_t *nid)
212  * Input        :
213  * Output       :
214  * Description  :
215  * Remarks      : One level self recursive for string type conversion
216  *****************************************************************************
217 */
218 static void write_name_str(FILE *fp, name_id_t *nid)
219 {
220         res_t res;
221         assert(nid->type == name_str);
222
223         if(!win32 && nid->name.s_name->type == str_char)
224         {
225                 res.size = strlen(nid->name.s_name->str.cstr);
226                 if(res.size > 254)
227                         error("Can't write strings larger than 254 bytes");
228                 if(res.size == 0)
229                         internal_error(__FILE__, __LINE__, "Attempt to write empty string");
230                 res.dataidx = 0;
231                 res.data = (char *)xmalloc(res.size + 1);
232                 res.data[0] = (char)res.size;
233                 res.size++;     /* We need to write the length byte as well */
234                 strcpy(res.data+1, nid->name.s_name->str.cstr);
235                 write_s_res(fp, &res);
236                 free(res.data);
237         }
238         else if(!win32 && nid->name.s_name->type == str_unicode)
239         {
240                 name_id_t lnid;
241                 string_t str;
242
243                 lnid.type = name_str;
244                 lnid.name.s_name = &str;
245                 str.type = str_char;
246                 str.str.cstr = dupwstr2cstr(nid->name.s_name->str.wstr);
247                 write_name_str(fp, &lnid);
248                 free(str.str.cstr);
249         }
250         else if(win32 && nid->name.s_name->type == str_char)
251         {
252                 name_id_t lnid;
253                 string_t str;
254
255                 lnid.type = name_str;
256                 lnid.name.s_name = &str;
257                 str.type = str_unicode;
258                 str.str.wstr = dupcstr2wstr(nid->name.s_name->str.cstr);
259                 write_name_str(fp, &lnid);
260                 free(str.str.wstr);
261         }
262         else  if(win32 && nid->name.s_name->type == str_unicode)
263         {
264                 res.size = wstrlen(nid->name.s_name->str.wstr);
265                 if(res.size > 65534)
266                         error("Can't write strings larger than 65534 bytes");
267                 if(res.size == 0)
268                         internal_error(__FILE__, __LINE__, "Attempt to write empty string");
269                 res.dataidx = 0;
270                 res.data = (char *)xmalloc((res.size + 1) * 2);
271                 ((short *)res.data)[0] = (short)res.size;
272                 wstrcpy((short *)(res.data+2), nid->name.s_name->str.wstr);
273                 res.size *= 2; /* Function writes bytes, not shorts... */
274                 res.size += 2; /* We need to write the length word as well */
275                 write_s_res(fp, &res);
276                 free(res.data);
277         }
278         else
279         {
280                 internal_error(__FILE__, __LINE__, "Hmm, requested to write a string of unknown type %d",
281                                 nid->name.s_name->type);
282         }
283 }
284
285 /*
286  *****************************************************************************
287  * Function     : find_counter
288  * Syntax       : res_count_t *find_counter(name_id_t *type)
289  * Input        :
290  * Output       :
291  * Description  :
292  * Remarks      :
293  *****************************************************************************
294 */
295 static res_count_t *find_counter(name_id_t *type)
296 {
297         int i;
298         for(i = 0; i < rccount; i++)
299         {
300                 if(!compare_name_id(type, &(rcarray[i].type)))
301                         return &rcarray[i];
302         }
303         return NULL;
304 }
305
306 /*
307  *****************************************************************************
308  * Function     : count_resources
309  * Syntax       : res_count_t *count_resources(resource_t *top)
310  * Input        :
311  * Output       :
312  * Description  :
313  * Remarks      : The whole lot is converted into arrays because they are
314  *                easy sortable. Makes the lot almost unreadable, but it
315  *                works (I hope). Basically you have to keep in mind that
316  *                the lot is a three-dimensional structure for win32 and a
317  *                two-dimensional structure for win16.
318  *****************************************************************************
319 */
320 #define RCT(v)  (*((resource_t **)(v)))
321 /* qsort sorting function */
322 static int sort_name_id(const void *e1, const void *e2)
323 {
324         return compare_name_id(RCT(e1)->name, RCT(e2)->name);
325 }
326
327 static int sort_language(const void *e1, const void *e2)
328 {
329         assert((RCT(e1)->lan) != NULL);
330         assert((RCT(e2)->lan) != NULL);
331
332         return MAKELANGID(RCT(e1)->lan->id, RCT(e1)->lan->sub)
333              - MAKELANGID(RCT(e2)->lan->id, RCT(e2)->lan->sub);
334 }
335 #undef RCT
336 #define RCT(v)  ((res_count_t *)(v))
337 static int sort_type(const void *e1, const void *e2)
338 {
339         return compare_name_id(&(RCT(e1)->type), &(RCT(e2)->type));
340 }
341 #undef RCT
342
343 static void count_resources(resource_t *top)
344 {
345         resource_t *rsc;
346         res_count_t *rcp;
347         name_id_t nid;
348         int i, j;
349
350         for(rsc = top; rsc; rsc = rsc->next)
351         {
352                 if(!rsc->binres)
353                         continue;
354                 switch(rsc->type)
355                 {
356                 case res_dlgex:
357                         nid.name.i_name = WRC_RT_DIALOG;
358                         nid.type = name_ord;
359                         break;
360                 case res_menex:
361                         nid.name.i_name = WRC_RT_MENU;
362                         nid.type = name_ord;
363                         break;
364                 case res_usr:
365                         nid = *(rsc->res.usr->type);
366                         break;
367                 default:
368                         nid.name.i_name = rsc->type;
369                         nid.type = name_ord;
370                 }
371
372                 if((rcp = find_counter(&nid)) == NULL)
373                 {
374                         /* Count the number of uniq ids and names */
375
376                         if(nid.type == name_ord)
377                                 n_id_entries++;
378                         else
379                                 n_name_entries++;
380
381                         if(!rcarray)
382                         {
383                                 rcarray = (res_count_t *)xmalloc(sizeof(res_count_t));
384                                 rccount = 1;
385                                 rcarray[0].count = 1;
386                                 rcarray[0].type = nid;
387                                 rcarray[0].rscarray = (resource_t **)xmalloc(sizeof(resource_t *));
388                                 rcarray[0].rscarray[0] = rsc;
389                         }
390                         else
391                         {
392                                 rccount++;
393                                 rcarray = (res_count_t *)xrealloc(rcarray, rccount * sizeof(res_count_t));
394                                 rcarray[rccount-1].count = 1;
395                                 rcarray[rccount-1].type = nid;
396                                 rcarray[rccount-1].rscarray = (resource_t **)xmalloc(sizeof(resource_t *));
397                                 rcarray[rccount-1].rscarray[0] = rsc;
398                         }
399                 }
400                 else
401                 {
402                         rcp->count++;
403                         rcp->rscarray = (resource_t **)xrealloc(rcp->rscarray, rcp->count * sizeof(resource_t *));
404                         rcp->rscarray[rcp->count-1] = rsc;
405                 }
406         }
407
408         if(!win32)
409         {
410                 /* We're done, win16 requires no special sorting */
411                 return;
412         }
413
414         /* We now have a unsorted list of types with an array of res_count_t
415          * in rcarray[0..rccount-1]. And we have names of one type in the
416          * rcarray[x].rsc[0..rcarray[x].count-1] arrays.
417          * The list needs to be sorted for win32's top level tree structure.
418          */
419
420         /* Sort the types */
421         if(rccount > 1)
422                 qsort(rcarray, rccount, sizeof(rcarray[0]), sort_type);
423
424         /* Now sort the name-id arrays */
425         for(i = 0; i < rccount; i++)
426         {
427                 if(rcarray[i].count > 1)
428                         qsort(rcarray[i].rscarray, rcarray[i].count, sizeof(rcarray[0].rscarray[0]), sort_name_id);
429         }
430
431         /* Now split the name-id arrays into name/language
432          * subs. Don't look at the awfull expressions...
433          * We do this by taking the array elements out of rscarray and putting
434          * together a new array in rsc32array.
435          */
436         for(i = 0; i < rccount; i++)
437         {
438                 res_count_t *rcap;
439
440                 assert(rcarray[i].count >= 1);
441
442                 /* rcap points to the current type we are dealing with */
443                 rcap = &(rcarray[i]);
444
445                 /* Insert the first name-id */
446                 rcap->rsc32array = (res32_count_t *)xmalloc(sizeof(res32_count_t));
447                 rcap->count32 = 1;
448                 rcap->rsc32array[0].rsc = (resource_t **)xmalloc(sizeof(resource_t *));
449                 rcap->rsc32array[0].count = 1;
450                 rcap->rsc32array[0].rsc[0] = rcap->rscarray[0];
451                 if(rcap->rscarray[0]->name->type == name_ord)
452                 {
453                         rcap->n_id_entries = 1;
454                         rcap->n_name_entries = 0;
455                 }
456                 else
457                 {
458                         rcap->n_id_entries = 0;
459                         rcap->n_name_entries = 1;
460                 }
461
462                 /* Now loop over the resting resources of the current type
463                  * to find duplicate names (which should have different
464                  * languages).
465                  */
466                 for(j = 1; j < rcap->count; j++)
467                 {
468                         res32_count_t *r32cp;
469
470                         /* r32cp points to the current res32_count structure
471                          * that holds the resource name we are processing.
472                          */
473                         r32cp = &(rcap->rsc32array[rcap->count32-1]);
474
475                         if(!compare_name_id(r32cp->rsc[0]->name, rcarray[i].rscarray[j]->name))
476                         {
477                                 /* Names are the same, add to list */
478                                 r32cp->count++;
479                                 r32cp->rsc = (resource_t **)xrealloc(r32cp->rsc, r32cp->count * sizeof(resource_t *));
480                                 r32cp->rsc[r32cp->count-1] = rcap->rscarray[j];
481                         }
482                         else
483                         {
484                                 /* New name-id, sort the old one by
485                                  * language and create new list
486                                  */
487                                 if(r32cp->count > 1)
488                                         qsort(r32cp->rsc, r32cp->count, sizeof(r32cp->rsc[0]), sort_language);
489                                 rcap->count32++;
490                                 rcap->rsc32array = (res32_count_t*)xrealloc(rcap->rsc32array, rcap->count32 * sizeof(res32_count_t));
491                                 rcap->rsc32array[rcap->count32-1].rsc = (resource_t **)xmalloc(sizeof(resource_t *));
492                                 rcap->rsc32array[rcap->count32-1].count = 1;
493                                 rcap->rsc32array[rcap->count32-1].rsc[0] = rcap->rscarray[j];
494
495                                 if(rcap->rscarray[j]->name->type == name_ord)
496                                         rcap->n_id_entries++;
497                                 else
498                                         rcap->n_name_entries++;
499                         }
500                 }
501                 /* Also sort the languages of the last name group */
502                 if(rcap->rsc32array[rcap->count32-1].count > 1)
503                         qsort(rcap->rsc32array[rcap->count32-1].rsc,
504                               rcap->rsc32array[rcap->count32-1].count,
505                               sizeof(rcap->rsc32array[rcap->count32-1].rsc[0]),
506                               sort_language);
507         }
508 }
509
510 /*
511  *****************************************************************************
512  * Function     : write_pe_segment
513  * Syntax       : void write_pe_segment(FILE *fp, resource_t *top)
514  * Input        :
515  * Output       :
516  * Description  :
517  * Remarks      :
518  *****************************************************************************
519 */
520 static void write_pe_segment(FILE *fp, resource_t *top)
521 {
522         int i;
523
524         fprintf(fp, "\t.align\t4\n");
525         fprintf(fp, "%s%s:\n", prefix, _PEResTab);
526         fprintf(fp, "\t.globl\t%s%s\n", prefix, _PEResTab);
527         /* Flags */
528         fprintf(fp, "\t.long\t0\n");
529         /* Time/Date stamp */
530         fprintf(fp, "\t.long\t0x%08lx\n", (long)now);
531         /* Version */
532         fprintf(fp, "\t.long\t0\n");    /* FIXME: must version be filled out? */
533         /* # of id entries, # of name entries */
534         fprintf(fp, "\t.short\t%d, %d\n", n_name_entries, n_id_entries);
535
536         /* Write the type level of the tree */
537         for(i = 0; i < rccount; i++)
538         {
539                 res_count_t *rcp;
540                 char *label;
541
542                 rcp = &rcarray[i];
543
544                 /* TypeId */
545                 if(rcp->type.type == name_ord)
546                         fprintf(fp, "\t.long\t%d\n", rcp->type.name.i_name);
547                 else
548                 {
549                         char *name = prep_nid_for_label(&(rcp->type));
550                         fprintf(fp, "\t.long\t(%s_%s_typename - %s%s) | 0x80000000\n",
551                                 prefix,
552                                 name,
553                                 prefix,
554                                 _PEResTab);
555                 }
556                 /* Offset */
557                 label = prep_nid_for_label(&(rcp->type));
558                 fprintf(fp, "\t.long\t(.L%s - %s%s) | 0x80000000\n",
559                         label,
560                         prefix,
561                         _PEResTab);
562         }
563
564         /* Write the name level of the tree */
565
566         for(i = 0; i < rccount; i++)
567         {
568                 res_count_t *rcp;
569                 char *typelabel;
570                 char *namelabel;
571                 int j;
572
573                 rcp = &rcarray[i];
574
575                 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
576                 fprintf(fp, ".L%s:\n", typelabel);
577
578                 fprintf(fp, "\t.long\t0\n");            /* Flags */
579                 fprintf(fp, "\t.long\t0x%08lx\n", (long)now);   /* TimeDate */
580                 fprintf(fp, "\t.long\t0\n");    /* FIXME: must version be filled out? */
581                 fprintf(fp, "\t.short\t%d, %d\n", rcp->n_name_entries, rcp->n_id_entries);
582                 for(j = 0; j < rcp->count32; j++)
583                 {
584                         resource_t *rsc = rcp->rsc32array[j].rsc[0];
585                         /* NameId */
586                         if(rsc->name->type == name_ord)
587                                 fprintf(fp, "\t.long\t%d\n", rsc->name->name.i_name);
588                         else
589                         {
590                                 fprintf(fp, "\t.long\t(%s%s_name - %s%s) | 0x80000000\n",
591                                         prefix,
592                                         rsc->c_name,
593                                         prefix,
594                                         _PEResTab);
595                         }
596                         /* Maybe FIXME: Unescape the tree (ommit 0x80000000) and
597                          * put the offset to the resource data entry.
598                          * ?? Is unescaping worth while ??
599                          */
600                         /* Offset */
601                         namelabel = prep_nid_for_label(rsc->name);
602                         fprintf(fp, "\t.long\t(.L%s_%s - %s%s) | 0x80000000\n",
603                                 typelabel,
604                                 namelabel,
605                                 prefix,
606                                 _PEResTab);
607                 }
608                 free(typelabel);
609         }
610
611         /* Write the language level of the tree */
612
613         for(i = 0; i < rccount; i++)
614         {
615                 res_count_t *rcp;
616                 char *namelabel;
617                 char *typelabel;
618                 int j;
619
620                 rcp = &rcarray[i];
621                 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
622
623                 for(j = 0; j < rcp->count32; j++)
624                 {
625                         res32_count_t *r32cp = &(rcp->rsc32array[j]);
626                         int k;
627
628                         namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
629                         fprintf(fp, ".L%s_%s:\n", typelabel, namelabel);
630
631                         fprintf(fp, "\t.long\t0\n");            /* Flags */
632                         fprintf(fp, "\t.long\t0x%08lx\n", (long)now);   /* TimeDate */
633                         fprintf(fp, "\t.long\t0\n");    /* FIXME: must version be filled out? */
634                         fprintf(fp, "\t.short\t0, %d\n", r32cp->count);
635
636                         for(k = 0; k < r32cp->count; k++)
637                         {
638                                 resource_t *rsc = r32cp->rsc[k];
639                                 assert(rsc->lan != NULL);
640                                 /* LanguageId */
641                                 fprintf(fp, "\t.long\t0x%08x\n", rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
642                                 /* Offset */
643                                 fprintf(fp, "\t.long\t.L%s_%s_%d - %s%s\n",
644                                         typelabel,
645                                         namelabel,
646                                         rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0,
647                                         prefix,
648                                         _PEResTab);
649                         }
650                         free(namelabel);
651                 }
652                 free(typelabel);
653         }
654
655         /* Write the resource table itself */
656         fprintf(fp, "%s_ResourceDirectory:\n", prefix);
657         fprintf(fp, "\t.globl\t%s_ResourceDirectory\n", prefix);
658         direntries = 0;
659
660         for(i = 0; i < rccount; i++)
661         {
662                 res_count_t *rcp;
663                 char *namelabel;
664                 char *typelabel;
665                 int j;
666
667                 rcp = &rcarray[i];
668                 typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
669
670                 for(j = 0; j < rcp->count32; j++)
671                 {
672                         res32_count_t *r32cp = &(rcp->rsc32array[j]);
673                         int k;
674
675                         namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
676
677                         for(k = 0; k < r32cp->count; k++)
678                         {
679                                 resource_t *rsc = r32cp->rsc[k];
680
681                                 assert(rsc->lan != NULL);
682
683                                 fprintf(fp, ".L%s_%s_%d:\n",
684                                         typelabel,
685                                         namelabel,
686                                         rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
687
688                                 /* Data RVA */
689                                 fprintf(fp, "\t.long\t%s%s_data - %s%s\n",
690                                         prefix,
691                                         rsc->c_name,
692                                         prefix,
693                                         _PEResTab);
694                                 /* Size */
695                                 fprintf(fp, "\t.long\t%d\n",
696                                         rsc->binres->size - rsc->binres->dataidx);
697                                 /* CodePage */
698                                 fprintf(fp, "\t.long\t%ld\n", codepage);
699                                 /* Reserved */
700                                 fprintf(fp, "\t.long\t0\n");
701
702                                 direntries++;
703                         }
704                         free(namelabel);
705                 }
706                 free(typelabel);
707         }
708 }
709
710 /*
711  *****************************************************************************
712  * Function     : write_ne_segment
713  * Syntax       : void write_ne_segment(FILE *fp, resource_t *top)
714  * Input        :
715  * Output       :
716  * Description  :
717  * Remarks      :
718  *****************************************************************************
719 */
720 static void write_ne_segment(FILE *fp, resource_t *top)
721 {
722         int i, j;
723
724         fprintf(fp, "\t.align\t4\n");
725         fprintf(fp, "%s%s:\n", prefix, _NEResTab);
726         fprintf(fp, "\t.globl\t%s%s\n", prefix, _NEResTab);
727
728         /* AlignmentShift */
729         fprintf(fp, "\t.short\t%d\n", alignment_pwr);
730
731         /* TypeInfo */
732         for(i = 0; i < rccount; i++)
733         {
734                 res_count_t *rcp = &rcarray[i];
735
736                 /* TypeId */
737                 if(rcp->type.type == name_ord)
738                         fprintf(fp, "\t.short\t0x%04x\n", rcp->type.name.i_name | 0x8000);
739                 else
740                         fprintf(fp, "\t.short\t%s_%s_typename - %s%s\n",
741                                 prefix,
742                                 rcp->type.name.s_name->str.cstr,
743                                 prefix,
744                                 _NEResTab);
745                 /* ResourceCount */
746                 fprintf(fp, "\t.short\t%d\n", rcp->count);
747                 /* Reserved */
748                 fprintf(fp, "\t.long\t0\n");
749                 /* NameInfo */
750                 for(j = 0; j < rcp->count; j++)
751                 {
752 /*
753  * VERY IMPORTANT:
754  * The offset is relative to the beginning of the NE resource segment
755  * and _NOT_ to the file-beginning. This is because we do not have a
756  * file based resource, but a simulated NE segment. The offset _is_
757  * scaled by the AlignShift field.
758  * All other things are as the MS doc describes (alignment etc.)
759  */
760                         /* Offset */
761                         fprintf(fp, "\t.short\t(%s%s_data - %s%s) >> %d\n",
762                                 prefix,
763                                 rcp->rscarray[j]->c_name,
764                                 prefix,
765                                 _NEResTab,
766                                 alignment_pwr);
767                         /* Length */
768                         fprintf(fp, "\t.short\t%d\n",
769                                 rcp->rscarray[j]->binres->size - rcp->rscarray[j]->binres->dataidx);
770                         /* Flags */
771                         fprintf(fp, "\t.short\t0x%04x\n", (WORD)rcp->rscarray[j]->memopt);
772                         /* Id */
773                         if(rcp->rscarray[j]->name->type == name_ord)
774                                 fprintf(fp, "\t.short\t0x%04x\n", rcp->rscarray[j]->name->name.i_name | 0x8000);
775                         else
776                                 fprintf(fp, "\t.short\t%s%s_name - %s%s\n",
777                                 prefix,
778                                 rcp->rscarray[j]->c_name,
779                                 prefix,
780                                 _NEResTab);
781                         /* Handle and Usage */
782                         fprintf(fp, "\t.short\t0, 0\n");
783                 }
784         }
785         /* EndTypes */
786         fprintf(fp, "\t.short\t0\n");
787 }
788
789 /*
790  *****************************************************************************
791  * Function     : write_rsc_names
792  * Syntax       : void write_rsc_names(FILE *fp, resource_t *top)
793  * Input        :
794  * Output       :
795  * Description  :
796  * Remarks      :
797  *****************************************************************************
798 */
799 static void write_rsc_names(FILE *fp, resource_t *top)
800 {
801         int i, j;
802         
803         if(win32)
804         {
805                 /* Write the names */
806
807                 for(i = 0; i < rccount; i++)
808                 {
809                         res_count_t *rcp;
810
811                         rcp = &rcarray[i];
812
813                         if(rcp->type.type == name_str)
814                         {
815                                 char *name = prep_nid_for_label(&(rcp->type));
816                                 fprintf(fp, "%s_%s_typename:\n",
817                                         prefix,
818                                         name);
819                                 write_name_str(fp, &(rcp->type));
820                         }
821
822                         for(j = 0; j < rcp->count32; j++)
823                         {
824                                 resource_t *rsc = rcp->rsc32array[j].rsc[0];
825
826                                 if(rsc->name->type == name_str)
827                                 {
828                                         fprintf(fp, "%s%s_name:\n",
829                                                 prefix,
830                                                 rsc->c_name);
831                                         write_name_str(fp, rsc->name);
832                                 }
833                         }
834                 }
835         }
836         else
837         {
838                 /* ResourceNames */
839                 for(i = 0; i < rccount; i++)
840                 {
841                         res_count_t *rcp = &rcarray[i];
842
843                         for(j = 0; j < rcp->count; j++)
844                         {
845                                 if(rcp->type.type == name_str)
846                                 {
847                                         fprintf(fp, "%s_%s_typename:\n",
848                                                 prefix,
849                                                 rcp->type.name.s_name->str.cstr);
850                                         write_name_str(fp, &(rcp->type));
851                                 }
852                                 if(rcp->rscarray[j]->name->type == name_str)
853                                 {
854                                         fprintf(fp, "%s%s_name:\n",
855                                                 prefix,
856                                                 rcp->rscarray[j]->c_name);
857                                         write_name_str(fp, rcp->rscarray[j]->name);
858                                 }
859                         }
860                 }
861                 /* EndNames */
862                 
863                 /* This is to end the NE resource table */
864                 if(create_dir)
865                         fprintf(fp, "\t.byte\t0\n");
866         }
867
868         fprintf(fp, "\n");
869 }
870
871 /*
872  *****************************************************************************
873  * Function     : write_s_file
874  * Syntax       : void write_s_file(char *outname, resource_t *top)
875  * Input        :
876  *      outname - Filename to write to
877  *      top     - The resource-tree to convert
878  * Output       :
879  * Description  :
880  * Remarks      :
881  *****************************************************************************
882 */
883 void write_s_file(char *outname, resource_t *top)
884 {
885         FILE *fo;
886         resource_t *rsc;
887
888         fo = fopen(outname, "wt");
889         if(!fo)
890         {
891                 error("Could not open %s\n", outname);
892                 return;
893         }
894
895         {
896                 char *s, *p;
897                 s = ctime(&now);
898                 p = strchr(s, '\n');
899                 if(p) *p = '\0';
900                 fprintf(fo, s_file_head_str, input_name ? input_name : "stdin",
901                         cmdline, s);
902         }
903
904         /* Get an idea how many we have and restructure the tables */
905         count_resources(top);
906
907         /* First write the segment tables */
908         if(create_dir)
909         {
910                 if(win32)
911                         write_pe_segment(fo, top);
912                 else
913                         write_ne_segment(fo, top);
914         }
915
916         /* Dump the names */
917         write_rsc_names(fo, top);
918
919         if(create_dir)
920                 fprintf(fo, ".LResTabEnd:\n");
921         
922         if(!indirect_only)
923         {
924                 /* Write the resource data */
925                 fprintf(fo, "\n/* Resource binary data */\n\n");
926                 for(rsc = top; rsc; rsc = rsc->next)
927                 {
928                         if(!rsc->binres)
929                                 continue;
930
931                         fprintf(fo, "\t.align\t%d\n", win32 ? 4 : alignment);
932                         fprintf(fo, "%s%s_data:\n", prefix, rsc->c_name);
933                         if(global)
934                                 fprintf(fo, "\t.globl\t%s%s_data\n", prefix, rsc->c_name);
935
936                         write_s_res(fo, rsc->binres);
937
938                         fprintf(fo, "\n");
939                 }
940
941                 if(create_dir)
942                 {
943                         /* Add a resource descriptor for built-in and elf-dlls */
944                         fprintf(fo, "\t.align\t4\n");
945                         fprintf(fo, "%s_ResourceDescriptor:\n", prefix);
946                         fprintf(fo, "\t.globl\t%s_ResourceDescriptor\n", prefix);
947                         fprintf(fo, "%s_ResourceTable:\n", prefix);
948                         if(global)
949                                 fprintf(fo, "\t.globl\t%s_ResourceTable\n", prefix);
950                         fprintf(fo, "\t.long\t%s%s\n", prefix, win32 ? _PEResTab : _NEResTab);
951                         fprintf(fo, "%s_NumberOfResources:\n", prefix);
952                         if(global)
953                                 fprintf(fo, "\t.globl\t%s_NumberOfResources\n", prefix);
954                         fprintf(fo, "\t.long\t%d\n", direntries);
955                         fprintf(fo, "%s_ResourceSectionSize:\n", prefix);
956                         if(global)
957                                 fprintf(fo, "\t.globl\t%s_ResourceSectionSize\n", prefix);
958                         fprintf(fo, "\t.long\t.LResTabEnd - %s%s\n", prefix, win32 ? _PEResTab : _NEResTab);
959                         if(win32)
960                         {
961                                 fprintf(fo, "%s_ResourcesEntries:\n", prefix);
962                                 if(global)
963                                         fprintf(fo, "\t.globl\t%s_ResourcesEntries\n", prefix);
964                                 fprintf(fo, "\t.long\t%s_ResourceDirectory\n", prefix);
965                         }
966                 }
967         }
968
969         if(indirect)
970         {
971                 /* Write the indirection structures */
972                 fprintf(fo, "\n/* Resource indirection structures */\n\n");
973                 fprintf(fo, "\t.align\t4\n");
974                 for(rsc = top; rsc; rsc = rsc->next)
975                 {
976                         int type;
977                         char *type_name = NULL;
978
979                         if(!rsc->binres)
980                                 continue;
981
982                         switch(rsc->type)
983                         {
984                         case res_menex:
985                                 type = WRC_RT_MENU;
986                                 break;
987                         case res_dlgex:
988                                 type = WRC_RT_DIALOG;
989                                 break;
990                         case res_usr:
991                                 assert(rsc->res.usr->type != NULL);
992                                 type_name = prep_nid_for_label(rsc->res.usr->type);
993                                 type = 0;
994                                 break;
995                         default:
996                                 type = rsc->type;
997                         }
998
999                         /*
1000                          * This follows a structure like:
1001                          * struct wrc_resource {
1002                          *      INT32   id;
1003                          *      RSCNAME *resname;
1004                          *      INT32   restype;
1005                          *      RSCNAME *typename;
1006                          *      void    *data;
1007                          *      UINT32  datasize;
1008                          * };
1009                          * The 'RSCNAME' is a pascal-style string where the
1010                          * first byte/word denotes the size and the rest the string
1011                          * itself.
1012                          */
1013                         fprintf(fo, "%s%s:\n", prefix, rsc->c_name);
1014                         if(global)
1015                                 fprintf(fo, "\t.globl\t%s%s\n", prefix, rsc->c_name);
1016                         fprintf(fo, "\t.long\t%d, %s%s%s, %d, %s%s%s%s, %s%s_data, %d\n",
1017                                 rsc->name->type == name_ord ? rsc->name->name.i_name : 0,
1018                                 rsc->name->type == name_ord ? "0" : prefix,
1019                                 rsc->name->type == name_ord ? "" : rsc->c_name,
1020                                 rsc->name->type == name_ord ? "" : "_name",
1021                                 type,
1022                                 type ? "0" : prefix,
1023                                 type ? "" : "_",
1024                                 type ? "" : type_name,
1025                                 type ? "" : "_typename",
1026                                 prefix,
1027                                 rsc->c_name,
1028                                 rsc->binres->size - rsc->binres->dataidx);
1029                         fprintf(fo, "\n");
1030                 }
1031                 fprintf(fo, "\n");
1032
1033                 /* Write the indirection table */
1034                 fprintf(fo, "/* Resource indirection table */\n\n");
1035                 fprintf(fo, "\t.align\t4\n");
1036                 fprintf(fo, "%s%s:\n", prefix, _ResTable);
1037                 fprintf(fo, "\t.globl\t%s%s\n", prefix, _ResTable);
1038                 for(rsc = top; rsc; rsc = rsc->next)
1039                 {
1040                         fprintf(fo, "\t.long\t%s%s\n", prefix, rsc->c_name);
1041                 }
1042                 fprintf(fo, "\t.long\t0\n");
1043                 fprintf(fo, "\n");
1044         }
1045
1046         if(auto_register)
1047                 fprintf(fo, s_file_autoreg_str, prefix, _ResTable);
1048
1049         fprintf(fo, s_file_tail_str);
1050         fclose(fo);
1051 }
1052
1053 /*
1054  *****************************************************************************
1055  * Function     : write_h_file
1056  * Syntax       : void write_h_file(char *outname, resource_t *top)
1057  * Input        :
1058  *      outname - Filename to write to
1059  *      top     - The resource-tree to convert
1060  * Output       :
1061  * Description  :
1062  * Remarks      :
1063  *****************************************************************************
1064 */
1065 void write_h_file(char *outname, resource_t *top)
1066 {
1067         FILE *fo;
1068         resource_t *rsc;
1069         char *h_prefix;
1070
1071 #ifdef NEED_UNDERSCORE_PREFIX
1072         h_prefix = prefix + 1;
1073 #else
1074         h_prefix = prefix;
1075 #endif
1076
1077         fo = fopen(outname, "wt");
1078         if(!fo)
1079         {
1080                 error("Could not open %s\n", outname);
1081         }
1082
1083         fprintf(fo, h_file_head_str, input_name ? input_name : "stdin",
1084                 cmdline, ctime(&now), (long)now, (long)now);
1085
1086         /* First write the segment tables reference */
1087         if(create_dir)
1088         {
1089                 fprintf(fo, "extern %schar %s%s[];\n\n",
1090                         constant ? "const " : "",
1091                         h_prefix,
1092                         win32 ? _PEResTab : _NEResTab);
1093         }
1094
1095         /* Write the resource data */
1096         for(rsc = top; global && rsc; rsc = rsc->next)
1097         {
1098                 if(!rsc->binres)
1099                         continue;
1100
1101                 fprintf(fo, "extern %schar %s%s_data[];\n",
1102                         constant ? "const " : "",
1103                         h_prefix,
1104                         rsc->c_name);
1105         }
1106
1107         if(indirect)
1108         {
1109                 if(global)
1110                         fprintf(fo, "\n");
1111
1112                 /* Write the indirection structures */
1113                 for(rsc = top; global && rsc; rsc = rsc->next)
1114                 {
1115                         fprintf(fo, "extern %swrc_resource%d_t %s%s;\n",
1116                                 constant ? "const " : "",
1117                                 win32 ? 32 : 16,
1118                                 h_prefix,
1119                                 rsc->c_name);
1120                 }
1121
1122                 if(global)
1123                         fprintf(fo, "\n");
1124
1125                 /* Write the indirection table */
1126                 fprintf(fo, "extern %swrc_resource%d_t %s%s[];\n\n",
1127                         constant ? "const " : "",
1128                         win32 ? 32 : 16,
1129                         h_prefix,
1130                         _ResTable);
1131         }
1132
1133         fprintf(fo, h_file_tail_str);
1134         fclose(fo);
1135 }
1136