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