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