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