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