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