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