3 * Copyright Martin von Loewis, 1994
11 #include <sys/fcntl.h>
12 #include <sys/types.h>
16 /* #include <neexe.h> */
20 char usage
[]="winerc -bdvc -p prefix -o outfile < infile \n"
21 " -b Create a C array from a binary .res file\n"
22 " -c Add 'const' prefix to C constants\n"
23 " -d Output debugging information\n"
24 " -p prefix Give a prefix for the generated names\n"
25 " -v Show each resource as it is processed\n"
26 " -o file Output to file.c and file.h\n";
29 /*might be overwritten by command line*/
30 char *prefix
="_Resource";
34 char hname
[256],sname
[256];
36 int transform_binary_file(void);
39 static void *xmalloc (size_t size
)
43 res
= malloc (size
? size
: 1);
46 fprintf (stderr
, "Virtual memory exhausted.\n");
53 int main(int argc
,char *argv
[])
58 int optc
,lose
,ret
,binary
;
60 while((optc
=getopt(argc
,argv
,"bcdp:vo:"))!=EOF
)
63 /* bison will print state transitions on stderr */
70 case 'p':prefix
=strdup(optarg
);
71 if(!isalpha(*prefix
))*prefix
='_';
72 for(tmpc
=prefix
;*tmpc
;tmpc
++)
73 if( !isalnum(*tmpc
) && *tmpc
!='_')
76 case 'c':constant
=1;break;
80 case 'o':set_out_file(optarg
);break;
81 default: lose
++;break;
83 if(lose
)return fprintf(stderr
,usage
),1;
84 if(!header
)header
=stdout
;
87 ret
=transform_binary_file();
95 void set_out_file(char *prefix
)
97 sprintf(sname
,"%s.c",prefix
);
98 code
=fopen(sname
,"w");
99 sprintf(hname
,"%s.h",prefix
);
100 header
=fopen(hname
,"w");
103 int transform_binary_file()
106 fprintf(header
,"#define APPLICATION_HAS_RESOURCES 1\n");
107 fprintf(code
,"char _Application_resources[]={");
112 if(i
%16==0)fputc('\n',code
);
113 fprintf(code
,"%3d,",c
);
115 fprintf(code
,"\n 0};\nint _Application_resources_size=%d;\n",i
);
119 /* SunOS' memcpy is wrong for overlapping arrays */
120 char *save_memcpy(char *d
,char* s
,int l
)
123 for(;l
;l
--)*d
++=*s
++;
125 for(d
+=l
-1,s
+=l
-1;l
;l
--)*d
--=*s
--;
129 /*allow unaligned access*/
130 void put_WORD(unsigned char* p
,WORD w
)
136 void put_DWORD(unsigned char* p
,DWORD d
)
138 put_WORD(p
,d
&0xFFFF);
142 WORD
get_WORD(unsigned char* p
)
144 return *p
|(*(p
+1)<<8);
147 DWORD
get_DWORD(unsigned char* p
)
149 return get_WORD(p
)|(get_WORD(p
+2)<<16);
153 /*create a new gen_res, initial size 100*/
155 { gen_res
* ret
=xmalloc(sizeof(gen_res
)+100);
157 for(i
=0;i
<sizeof(gen_res
)+100;i
++)*((char*)ret
+i
)='\0';
166 gen_res
* grow(gen_res
* res
)
168 res
=realloc(res
,sizeof(gen_res
)+2*res
->space
);
170 fprintf(stderr
,"Out of memory\n"),exit(1);
171 if(!res
->g_prev
)g_start
=res
;
172 else res
->g_prev
->g_next
=res
;
173 if(res
->g_next
)res
->g_next
->g_prev
=res
;
174 res
->space
=2*res
->space
;
179 /* insert bytes at offset 0, increase num_entries */
180 gen_res
* insert_at_beginning(gen_res
* res
,char* entry
,int size
)
182 while(res
->size
+size
>res
->space
)res
=grow(res
);
183 save_memcpy(res
->res
+size
,res
->res
,res
->size
);
184 save_memcpy(res
->res
,entry
,size
);
190 /* insert length characters from bytes into res, starting at start */
191 gen_res
* insert_bytes(gen_res
* res
,char* bytes
,int start
,int length
)
193 while(res
->size
+length
>res
->space
)res
=grow(res
);
194 save_memcpy(res
->res
+start
+length
,res
->res
+start
,res
->size
-start
);
195 save_memcpy(res
->res
+start
,bytes
,length
);
200 /*delete len bytes from res, starting at start*/
201 gen_res
* delete_bytes(gen_res
* res
,int start
,int len
)
203 save_memcpy(res
->res
+start
,res
->res
+start
+len
,res
->size
-start
-len
);
208 /*create a new style*/
209 rc_style
*new_style()
211 rc_style
*ret
=xmalloc(sizeof(rc_style
));
212 /*initially, no bits have to be reset*/
214 /*initially, no bits are set*/
215 ret
->or=WS_CHILD
| WS_VISIBLE
;
219 /* entries are inserted at the beginning, starting from the last one */
220 gen_res
* add_accelerator(int ev
, int id
, int flags
, gen_res
* prev
)
223 if(prev
->num_entries
==0)flags
|=0x80; /* last entry */
224 accel_entry
[0]=flags
;
225 put_WORD(accel_entry
+1,ev
);
226 put_WORD(accel_entry
+3,id
);
227 return insert_at_beginning(prev
,accel_entry
,5);
231 /* create an integer from the event, taking things as "^c" into account
232 add this as new entry */
233 gen_res
* add_string_accelerator(char *ev
, int id
, int flags
, gen_res
* prev
)
240 return add_accelerator(event
,id
,flags
,prev
);
243 /*is there a difference between ASCII and VIRTKEY accelerators? */
245 gen_res
* add_ascii_accelerator(int ev
, int id
, int flags
, gen_res
* prev
)
247 return add_accelerator(ev
,id
,flags
,prev
);
250 gen_res
* add_vk_accelerator(int ev
, int id
, int flags
, gen_res
* prev
)
252 return add_accelerator(ev
,id
,flags
,prev
);
255 /* create a new dialog header, set all items to 0 */
256 gen_res
* new_dialog()
257 { gen_res
* ret
=new_res();
258 ret
->size
=16; /*all strings "\0", no font*/
262 /* the STYLE option was specified */
263 gen_res
* dialog_style(rc_style
* style
, gen_res
* attr
)
265 /* default dialog styles? Do we need style->and? */
266 /* DS_SETFONT might have been specified before */
267 put_DWORD(attr
->res
,get_DWORD(attr
->res
)|style
->or);
271 /* menu name is at offset 13 */
272 int dialog_get_menu(gen_res
* attr
)
277 /* the class is after the menu name */
278 int dialog_get_class(gen_res
* attr
)
280 int offs
=dialog_get_menu(attr
);
281 while(attr
->res
[offs
])offs
++;
286 /* the caption is after the class */
287 int dialog_get_caption(gen_res
* attr
)
289 int offs
=dialog_get_class(attr
);
290 while(attr
->res
[offs
])offs
++;
295 /* the fontsize, if present, is after the caption, followed by the font name */
296 int dialog_get_fontsize(gen_res
* attr
)
298 int offs
=dialog_get_caption(attr
);
299 while(attr
->res
[offs
])offs
++;
305 /* the CAPTION option was specified */
306 gen_res
* dialog_caption(char* cap
, gen_res
*attr
)
308 /* we don't need the terminating 0 as it's already there */
309 return insert_bytes(attr
,cap
,dialog_get_caption(attr
),strlen(cap
));
313 /* the FONT option was specified, set the DS_SETFONT flag */
314 gen_res
* dialog_font(short size
,char* font
,gen_res
*attr
)
317 int offs
=dialog_get_fontsize(attr
);
318 put_DWORD(attr
->res
,get_DWORD(attr
->res
)|DS_SETFONT
);
319 put_WORD(c_size
,size
);
320 attr
=insert_bytes(attr
,c_size
,offs
,2);
322 /* as there is no font name by default, copy the '\0' */
323 return insert_bytes(attr
,font
,offs
,strlen(font
)+1);
326 gen_res
* dialog_class(char* cap
, gen_res
*attr
)
328 return insert_bytes(attr
,cap
,dialog_get_class(attr
),strlen(cap
));
331 gen_res
* dialog_menu(char* cap
, gen_res
*attr
)
333 return insert_bytes(attr
,cap
,dialog_get_menu(attr
),strlen(cap
));
336 /* set the dialogs id, position, extent, and style */
337 gen_res
* create_control_desc(int id
,int x
,int y
,int cx
, int cy
,rc_style
*style
)
338 { gen_res
* ret
=new_res();
339 int s
=WS_VISIBLE
|WS_CHILD
; /*defaults styles for any control*/
340 put_WORD(ret
->res
+0,x
);
341 put_WORD(ret
->res
+2,y
);
342 put_WORD(ret
->res
+4,cx
);
343 put_WORD(ret
->res
+6,cy
);
344 put_WORD(ret
->res
+8,id
);
345 if(style
)s
=(s
|style
->or)&style
->and;
346 put_DWORD(ret
->res
+10,s
);
347 ret
->size
=17; /*empty strings, unused byte*/
351 /* insert the control's label */
352 gen_res
* label_control_desc(char* label
,gen_res
* cd
)
355 if(cd
->res
[14]&0x80)offs
=15; /* one-character class */
357 for(offs
=14;cd
->res
[offs
];offs
++);
360 return insert_bytes(cd
,label
,offs
,strlen(label
));
363 /* a CONTROL was specified */
364 gen_res
* create_generic_control(char* label
,int id
,char* class,
365 rc_style
*style
,int x
,int y
,int cx
,int cy
)
367 gen_res
* ret
=new_res();
368 put_WORD(ret
->res
+0,x
);
369 put_WORD(ret
->res
+2,y
);
370 put_WORD(ret
->res
+4,cx
);
371 put_WORD(ret
->res
+6,cy
);
372 put_WORD(ret
->res
+8,id
);
373 put_DWORD(ret
->res
+10,style
->or);
375 ret
=insert_bytes(ret
,label
,15,strlen(label
));
376 /* is it a predefined class? */
378 if(!strcmp(class,"BUTTON"))cl
=CT_BUTTON
;
379 if(!strcmp(class,"EDIT"))cl
=CT_EDIT
;
380 if(!strcmp(class,"STATIC"))cl
=CT_STATIC
;
381 if(!strcmp(class,"LISTBOX"))cl
=CT_LISTBOX
;
382 if(!strcmp(class,"SCROLLBAR"))cl
=CT_SCROLLBAR
;
383 if(!strcmp(class,"COMBOBOX"))cl
=CT_COMBOBOX
;
384 if(cl
)ret
->res
[14]=cl
;
385 else ret
=insert_bytes(ret
,class,14,strlen(class));
389 /* insert cd into rest, set the type, add flags */
390 gen_res
* add_control(int type
,int flags
,gen_res
*cd
,gen_res
* rest
)
392 put_DWORD(cd
->res
+10,get_DWORD(cd
->res
+10)|flags
);
394 return insert_at_beginning(rest
,cd
->res
,cd
->size
);
397 /* an ICON control was specified, whf contains width, height, and flags */
398 gen_res
* add_icon(char* name
,int id
,int x
,int y
,gen_res
* whf
,gen_res
* rest
)
400 put_WORD(whf
->res
+0,x
);
401 put_WORD(whf
->res
+2,y
);
402 put_WORD(whf
->res
+8,id
);
403 whf
=label_control_desc(name
,whf
);
404 return add_control(CT_STATIC
,SS_ICON
,whf
,rest
);
407 /* insert the generic control into rest */
408 gen_res
* add_generic_control(gen_res
* ctl
, gen_res
* rest
)
410 return insert_at_beginning(rest
,ctl
->res
,ctl
->size
);
413 /* create a dialog resource by inserting the header into the controls.
414 Set position and extent */
415 gen_res
* make_dialog(gen_res
* header
,int x
,int y
,int cx
,int cy
,gen_res
* ctls
)
417 header
->res
[4]=ctls
->num_entries
;
419 put_WORD(header
->res
+5,x
);
420 put_WORD(header
->res
+7,y
);
421 put_WORD(header
->res
+9,cx
);
422 put_WORD(header
->res
+11,cy
);
423 return insert_bytes(header
,ctls
->res
,header
->size
,ctls
->size
);
426 /* create {0x15,0x16,0xFF} from '15 16 FF' */
427 gen_res
*hex_to_raw(char *hex
, gen_res
*rest
)
431 for(i
=0;*hex
!='\'';i
++)r2
[i
]=strtoul(hex
,&hex
,16);
432 return insert_bytes(rest
,r2
,0,i
);
435 /* create a bitmap resource */
436 gen_res
*make_bitmap(gen_res
* res
)
438 res
=delete_bytes(res
,0,14); /* skip bitmap file header*/
443 gen_res
*make_icon(gen_res
* res
)
449 gen_res
*make_cursor(gen_res
* res
)
455 /* load resource bytes from the file name */
456 gen_res
*load_file(char* name
)
460 int f
=open(name
,O_RDONLY
);
464 while(res
->space
<st
.st_size
)res
=grow(res
);
465 read(f
,res
->res
,st
.st_size
);
466 res
->size
=st
.st_size
;
471 /* insert a normal menu item into res, starting from the last item */
472 gen_res
*add_menuitem(char* name
,int id
,int flags
,gen_res
*res
)
475 if(res
->num_entries
==0)flags
|=MF_END
;
476 put_WORD(item
,flags
);
478 res
=insert_at_beginning(res
,name
,strlen(name
)+1);
479 res
=insert_bytes(res
,item
,0,4);
483 /* insert a popup item into res */
484 gen_res
*add_popup(char *name
,short flags
, gen_res
* body
, gen_res
*res
)
488 if(res
->num_entries
==0)flags
|=MF_END
;
489 put_WORD(c_flags
,flags
);
490 res
=insert_at_beginning(res
,body
->res
,body
->size
);
491 res
=insert_bytes(res
,name
,0,strlen(name
)+1);
492 res
=insert_bytes(res
,c_flags
,0,2);
496 /* prefix the menu header into res */
497 gen_res
*make_menu(gen_res
* res
)
499 static char header
[4]={0,0,0,0};
500 res
=insert_at_beginning(res
,header
,4);
505 /* link top-level resources */
506 gen_res
*add_resource(gen_res
* first
,gen_res
*rest
)
517 typedef struct str_tbl_elm
{
519 struct str_tbl_elm
*next
;
523 str_tbl_elm
* string_table
=NULL
; /* sorted by group */
525 void add_str_tbl_elm(int id
,char* str
)
530 str_tbl_elm
** elm
=&string_table
;
531 while(*elm
&& (*elm
)->group
<group
) elm
=&(*elm
)->next
;
532 if(!*elm
|| (*elm
)->group
!=group
)
534 str_tbl_elm
* new=xmalloc(sizeof(str_tbl_elm
));
539 (*elm
)->strings
[idx
]=str
;
542 gen_res
* add_string_table(gen_res
* t
)
550 if(!string_table
) return t
;
551 for(ste
=string_table
; ste
; ste
=ste
->next
)
553 for(size
=0,i
=0; i
<16; i
++)
554 size
+= ste
->strings
[i
] ? strlen(ste
->strings
[i
])+1 : 1;
556 while(res
->space
<size
)res
=grow(res
);
558 res
->n
.i_name
=ste
->group
;
561 for(p
=res
->res
,i
=0; i
<16; i
++)
562 if((q
=ste
->strings
[i
])==NULL
)
567 while(*q
) *p
++ = *q
++;
569 t
=add_resource(res
,t
);
574 char *get_typename(gen_res
* t
)
577 case acc
:return "ACCELERATOR";
578 case bmp
:return "BITMAP";
579 case cur
:return "CURSOR";
580 case dlg
:return "DIALOG";
581 case fnt
:return "FONT";
582 case ico
:return "ICON";
583 case men
:return "MENU";
584 case rdt
:return "RCDATA";
585 case str
:return "STRINGTABLE";
586 default: return "UNKNOWN";
590 /* create strings like _Sysres_DIALOG_2 */
591 char *get_resource_name(gen_res
*it
)
593 static char buf
[1000];
595 sprintf(buf
,"%s_%s_%s",prefix
,get_typename(it
),it
->n
.s_name
);
597 sprintf(buf
,"%s_%s_%d",prefix
,get_typename(it
),it
->n
.i_name
);
601 #define ISCONSTANT (constant ? "const " : "")
603 /* create the final output */
604 void create_output(gen_res
* top
)
608 top
=add_string_table(top
);
610 fprintf( header
, "/* %s\n"
611 " * This file is automatically generated. Do not edit!\n"
613 "#include \"resource.h\"\n", hname
);
615 /* Declare the resources */
617 for (it
=top
;it
;it
=it
->next
)
618 fprintf( header
,"extern %sstruct resource %s;\n",
619 ISCONSTANT
, get_resource_name(it
) );
620 fprintf( header
,"\nextern %sstruct resource * %s%s_Table[];\n",
621 ISCONSTANT
, ISCONSTANT
, prefix
);
623 /* Print the resources bytes */
625 fprintf( code
, "/* %s\n"
626 " * This file is automatically generated. Do not edit!\n"
628 "#include \"%s\"\n", sname
, hname
);
630 for(it
=top
;it
;it
=it
->next
)
633 fprintf( code
, "static %sunsigned char %s__bytes[] = {\n",
634 ISCONSTANT
, get_resource_name(it
) );
635 for (i
=0;i
<it
->size
-1;i
++)
637 fprintf(code
,"0x%02x, ",it
->res
[i
]);
638 if ((i
&7)==7)fputc('\n',code
);
640 fprintf(code
,"0x%02x };\n\n",it
->res
[i
]);
643 /* Print the resources */
644 for (it
=top
;it
;it
=it
->next
)
649 case acc
:type
=(int)RT_ACCELERATOR
;break;
650 case bmp
:type
=(int)RT_BITMAP
;break;
651 case cur
:type
=(int)RT_CURSOR
;break;
652 case dlg
:type
=(int)RT_DIALOG
;break;
653 case fnt
:type
=(int)RT_FONT
;break;
654 case ico
:type
=(int)RT_ICON
;break;
655 case men
:type
=(int)RT_MENU
;break;
656 case rdt
:type
=(int)RT_RCDATA
;break;
657 case str
:type
=(int)RT_STRING
;break;
658 default:fprintf(stderr
,"Unknown restype\n");type
=-1;break;
661 fprintf(code
,"%sstruct resource %s = {0,%d,\"%s\",%s__bytes,%d};\n",
662 ISCONSTANT
, get_resource_name(it
), type
, it
->n
.s_name
,
663 get_resource_name(it
), it
->size
);
665 fprintf(code
,"%sstruct resource %s = {%d,%d,\"@%d\",%s__bytes,%d};\n",
666 ISCONSTANT
, get_resource_name(it
), it
->n
.i_name
, type
,
667 it
->n
.i_name
, get_resource_name(it
), it
->size
);
670 /* Print the resource table (NULL terminated) */
672 fprintf(code
,"\n%sstruct resource * %s%s_Table[] = {\n",
673 ISCONSTANT
, ISCONSTANT
, prefix
);
674 for (it
=top
;it
;it
=it
->next
)
675 fprintf( code
, " &%s,\n", get_resource_name(it
) );
676 fprintf( code
, " 0\n};\n" );
678 /* Perform autoregistration */
681 "static void DoIt() WINE_CONSTRUCTOR;\n"
682 "static void DoIt()\n"
684 "\tLIBRES_RegisterResources(%s_Table);\n"
686 "#ifndef HAVE_WINE_CONSTRUCTOR\n"
687 "void LIBWINE_Register_%s(){\n"
691 "#endif /*WINELIB*/\n"
695 gen_res
* make_font(gen_res
* res
)
697 fprintf(stderr
,"Fonts not supported\n");
701 gen_res
* make_raw(gen_res
* res
)
703 fprintf(stderr
,"RCData not supported\n");
707 gen_res
* int_to_raw(int i
,gen_res
* res
)
709 fprintf(stderr
,"IntToRaw not supported\n");
713 /* translate "Hello,\\tworld!\\10" to "Hello,\tworld!\n" */
714 char *parse_c_string(char *in
)
716 char *out
=xmalloc(strlen(in
)-1);
719 for(it
=out
,in
++;*in
;in
++)
722 {case 't':*it
++='\t';break;
723 case 'r':*it
++='\r';break;
724 case 'n':*it
++='\n';break;
725 case 'a':*it
++='\a';break;
727 memset(tmp
,0,5);/*make sure it doesn't use more than 4 chars*/
729 *it
++=strtoul(tmp
,&tend
,0);
732 case '1':case '2':case '3':case '4':case '5':
733 case '6':case '7':case '8':case '9':
736 *it
++=strtoul(tmp
,&tend
,10);
742 *it
++=strtoul(tmp
,&tend
,16);