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