Release 950727
[wine/multimedia.git] / rc / winerc.c
blobc8832cf17358a656ac8fba37f9a2d4af745ca5b3
1 /*
3 * Copyright Martin von Loewis, 1994
5 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/stat.h>
10 #include <sys/fcntl.h>
11 #include <sys/types.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <windows.h>
15 #include <neexe.h>
16 #include "parser.h"
17 #include "y.tab.h"
19 char usage[]="winerc -bdvc -p prefix -o outfile < infile \n"
20 " -b Create a C array from a binary .res file\n"
21 " -d Output debugging information\n"
22 " -p prefix Give a prefix for the generated names\n"
23 " -v Show each resource as it is processed\n"
24 " -o file Output to file.c and file.h\n";
27 /*might be overwritten by command line*/
28 char *prefix="_Resource";
29 int verbose,constant;
30 gen_res* g_start;
31 FILE *header,*code;
32 char hname[256],sname[256];
34 int main(int argc,char *argv[])
36 extern int yydebug;
37 extern char* optarg;
38 int optc,lose,ret,binary;
39 lose=binary=0;
40 while((optc=getopt(argc,argv,"bdp:vo:"))!=EOF)
41 switch(optc)
43 /* bison will print state transitions on stderr */
44 case 'b':binary=1;
45 break;
46 case 'd':yydebug=1;
47 setbuf(stdout,0);
48 setbuf(stderr,0);
49 break;
50 case 'p':prefix=optarg;break;
51 case 'c':constant=1;break;
52 case 'v':verbose=1;
53 setbuf(stderr,0);
54 break;
55 case 'o':set_out_file(optarg);break;
56 default: lose++;break;
58 if(lose)return fprintf(stderr,usage),1;
59 if(!header)header=stdout;
60 if(!code)code=stdout;
61 if(binary)
62 ret=transform_binary_file();
63 else
64 ret=yyparse();
65 fclose(header);
66 fclose(code);
67 return ret;
70 void set_out_file(char *prefix)
72 sprintf(sname,"%s.c",prefix);
73 code=fopen(sname,"w");
74 sprintf(hname,"%s.h",prefix);
75 header=fopen(hname,"w");
78 int transform_binary_file()
80 int i,c;
81 fprintf(header,"#define APPLICATION_HAS_RESOURCES 1\n");
82 fprintf(code,"char _Application_resources[]={");
83 for(i=0;;i++)
85 c=getchar();
86 if(c==-1)break;
87 if(i%16==0)fputc('\n',code);
88 fprintf(code,"%3d,",c);
90 fprintf(code,"\n0}\nint _Aplication_resources_size=%d;\n",i);
93 /* SunOS' memcpy is wrong for overlapping arrays */
94 char *save_memcpy(char *d,char* s,int l)
96 if(d<s)
97 for(;l;l--)*d++=*s++;
98 else
99 for(d+=l-1,s+=l-1;l;l--)*d--=*s--;
100 return d;
103 /*allow unaligned access*/
104 void put_WORD(unsigned char* p,WORD w)
106 *p=w&0xFF;
107 *(p+1)=w>>8;
110 void put_DWORD(unsigned char* p,DWORD d)
112 put_WORD(p,d&0xFFFF);
113 put_WORD(p+2,d>>16);
116 WORD get_WORD(unsigned char* p)
118 return *p|(*(p+1)<<8);
121 DWORD get_DWORD(unsigned char* p)
123 return get_WORD(p)|(get_WORD(p+2)<<16);
127 /*create a new gen_res, initial size 100*/
128 gen_res *new_res()
129 { gen_res* ret=malloc(sizeof(gen_res)+100);
130 int i;
131 if(!ret)
132 fprintf(stderr,"Out of memory\n"),exit(1);
133 for(i=0;i<sizeof(gen_res)+100;i++)*((char*)ret+i)='\0';
134 ret->g_next=g_start;
135 ret->g_prev=0;
136 g_start=ret;
137 ret->space=100;
138 return ret;
141 /*double the space*/
142 gen_res* grow(gen_res* res)
144 res=realloc(res,sizeof(gen_res)+2*res->space);
145 if(!res)
146 fprintf(stderr,"Out of memory\n"),exit(1);
147 if(!res->g_prev)g_start=res;
148 else res->g_prev->g_next=res;
149 if(res->g_next)res->g_next->g_prev=res;
150 res->space=2*res->space;
151 return res;
155 /* insert bytes at offset 0, increase num_entries */
156 gen_res* insert_at_beginning(gen_res* res,char* entry,int size)
158 while(res->size+size>res->space)res=grow(res);
159 save_memcpy(res->res+size,res->res,res->size);
160 save_memcpy(res->res,entry,size);
161 res->size+=size;
162 res->num_entries++;
163 return res;
166 /* insert length characters from bytes into res, starting at start */
167 gen_res* insert_bytes(gen_res* res,char* bytes,int start,int length)
169 while(res->size+length>res->space)res=grow(res);
170 save_memcpy(res->res+start+length,res->res+start,res->size-start);
171 save_memcpy(res->res+start,bytes,length);
172 res->size+=length;
173 return res;
176 /*delete len bytes from res, starting at start*/
177 gen_res* delete_bytes(gen_res* res,int start,int len)
179 save_memcpy(res->res+start,res->res+start+len,res->size-start-len);
180 res->size-=len;
181 return res;
184 /*create a new style*/
185 rc_style *new_style()
187 rc_style *ret=malloc(sizeof(rc_style));
188 /*initially, no bits have to be reset*/
189 ret->and=-1;
190 /*initially, no bits are set*/
191 ret->or=0;
192 return ret;
195 /* entries are inserted at the beginning, starting from the last one */
196 gen_res* add_accelerator(int ev, int id, int flags, gen_res* prev)
198 char accel_entry[5];
199 if(prev->num_entries==0)flags|=0x80; /* last entry */
200 accel_entry[0]=flags;
201 put_WORD(accel_entry+1,ev);
202 put_WORD(accel_entry+3,id);
203 return insert_at_beginning(prev,accel_entry,5);
207 /* create an integer from the event, taking things as "^c" into account
208 add this as new entry */
209 gen_res* add_string_accelerator(char *ev, int id, int flags, gen_res* prev)
211 int event;
212 if(*ev=='^')
213 event=ev[1]-'a';
214 else
215 event=ev[0];
216 return add_accelerator(event,id,flags,prev);
219 /*is there a difference between ASCII and VIRTKEY accelerators? */
221 gen_res* add_ascii_accelerator(int ev, int id, int flags, gen_res* prev)
223 return add_accelerator(ev,id,flags,prev);
226 gen_res* add_vk_accelerator(int ev, int id, int flags, gen_res* prev)
228 return add_accelerator(ev,id,flags,prev);
231 /* create a new dialog header, set all items to 0 */
232 gen_res* new_dialog()
233 { gen_res* ret=new_res();
234 ret->size=16; /*all strings "\0", no font*/
235 return ret;
238 /* the STYLE option was specified */
239 gen_res* dialog_style(rc_style* style, gen_res* attr)
241 /* default dialog styles? Do we need style->and? */
242 /* DS_SETFONT might have been specified before */
243 put_DWORD(attr->res,get_DWORD(attr->res)|style->or);
244 return attr;
247 /* menu name is at offset 13 */
248 int dialog_get_menu(gen_res* attr)
250 return 13;
253 /* the class is after the menu name */
254 int dialog_get_class(gen_res* attr)
256 int offs=dialog_get_menu(attr);
257 while(attr->res[offs])offs++;
258 offs++;
259 return offs;
262 /* the caption is after the class */
263 int dialog_get_caption(gen_res* attr)
265 int offs=dialog_get_class(attr);
266 while(attr->res[offs])offs++;
267 offs++;
268 return offs;
271 /* the fontsize, if present, is after the caption, followed by the font name */
272 int dialog_get_fontsize(gen_res* attr)
274 int offs=dialog_get_caption(attr);
275 while(attr->res[offs])offs++;
276 offs++;
277 return offs;
281 /* the CAPTION option was specified */
282 gen_res* dialog_caption(char* cap, gen_res*attr)
284 /* we don't need the terminating 0 as it's already there */
285 return insert_bytes(attr,cap,dialog_get_caption(attr),strlen(cap));
289 /* the FONT option was specified, set the DS_SETFONT flag */
290 gen_res* dialog_font(short size,char* font,gen_res *attr)
292 char c_size[2];
293 int offs=dialog_get_fontsize(attr);
294 put_DWORD(attr->res,get_DWORD(attr->res)|DS_SETFONT);
295 put_WORD(c_size,size);
296 attr=insert_bytes(attr,c_size,offs,2);
297 offs+=2;
298 /* as there is no font name by default, copy the '\0' */
299 return insert_bytes(attr,font,offs,strlen(font)+1);
302 gen_res* dialog_class(char* cap, gen_res*attr)
304 return insert_bytes(attr,cap,dialog_get_class(attr),strlen(cap));
307 gen_res* dialog_menu(char* cap, gen_res*attr)
309 return insert_bytes(attr,cap,dialog_get_menu(attr),strlen(cap));
312 /* set the dialogs id, position, extent, and style */
313 gen_res* create_control_desc(int id,int x,int y,int cx, int cy,rc_style *style)
314 { gen_res* ret=new_res();
315 int s=WS_VISIBLE|WS_CHILD; /*defaults styles for any control*/
316 put_WORD(ret->res+0,x);
317 put_WORD(ret->res+2,y);
318 put_WORD(ret->res+4,cx);
319 put_WORD(ret->res+6,cy);
320 put_WORD(ret->res+8,id);
321 if(style)s=(s|style->or)&style->and;
322 put_DWORD(ret->res+10,s);
323 ret->size=17; /*empty strings, unused byte*/
324 return ret;
327 /* insert the control's label */
328 gen_res* label_control_desc(char* label,gen_res* cd)
330 int offs;
331 if(cd->res[14]&0x80)offs=15; /* one-character class */
332 else {
333 for(offs=14;cd->res[offs];offs++);
334 offs++;
336 return insert_bytes(cd,label,offs,strlen(label));
339 /* a CONTROL was specified */
340 gen_res* create_generic_control(char* label,int id,char* class,
341 rc_style*style,int x,int y,int cx,int cy)
342 { char cl;
343 gen_res* ret=new_res();
344 put_WORD(ret->res+0,x);
345 put_WORD(ret->res+2,y);
346 put_WORD(ret->res+4,cx);
347 put_WORD(ret->res+6,cy);
348 put_WORD(ret->res+8,id);
349 put_DWORD(ret->res+10,style->or);
350 ret->size=17;
351 ret=insert_bytes(ret,label,15,strlen(label));
352 /* is it a predefined class? */
353 cl=0;
354 if(!strcmp(class,"BUTTON"))cl=CT_BUTTON;
355 if(!strcmp(class,"EDIT"))cl=CT_EDIT;
356 if(!strcmp(class,"STATIC"))cl=CT_STATIC;
357 if(!strcmp(class,"LISTBOX"))cl=CT_LISTBOX;
358 if(!strcmp(class,"SCROLLBAR"))cl=CT_SCROLLBAR;
359 if(!strcmp(class,"COMBOBOX"))cl=CT_COMBOBOX;
360 if(cl)ret->res[14]=cl;
361 else ret=insert_bytes(ret,class,14,strlen(class));
362 return ret;
365 /* insert cd into rest, set the type, add flags */
366 gen_res* add_control(int type,int flags,gen_res*cd,gen_res* rest)
368 put_DWORD(cd->res+10,get_DWORD(cd->res+10)|flags);
369 cd->res[14]=type;
370 return insert_at_beginning(rest,cd->res,cd->size);
373 /* an ICON control was specified, whf contains width, height, and flags */
374 gen_res* add_icon(char* name,int id,int x,int y,gen_res* whf,gen_res* rest)
376 put_WORD(whf->res+0,x);
377 put_WORD(whf->res+2,y);
378 put_WORD(whf->res+8,id);
379 whf=label_control_desc(name,whf);
380 return add_control(CT_STATIC,SS_ICON,whf,rest);
383 /* insert the generic control into rest */
384 gen_res* add_generic_control(gen_res* ctl, gen_res* rest)
386 return insert_at_beginning(rest,ctl->res,ctl->size);
389 /* create a dialog resource by inserting the header into the controls.
390 Set position and extent */
391 gen_res* make_dialog(gen_res* header,int x,int y,int cx,int cy,gen_res* ctls)
393 header->res[4]=ctls->num_entries;
394 header->type=dlg;
395 put_WORD(header->res+5,x);
396 put_WORD(header->res+7,y);
397 put_WORD(header->res+9,cx);
398 put_WORD(header->res+11,cy);
399 return insert_bytes(header,ctls->res,header->size,ctls->size);
402 /* create {0x15,0x16,0xFF} from '15 16 FF' */
403 gen_res *hex_to_raw(char *hex, gen_res*rest)
405 char r2[16];
406 int i;
407 for(i=0;*hex!='\'';i++)r2[i]=strtoul(hex,&hex,16);
408 return insert_bytes(rest,r2,0,i);
411 /* create a bitmap resource */
412 gen_res *make_bitmap(gen_res* res)
414 res=delete_bytes(res,0,14); /* skip bitmap file header*/
415 res->type=bmp;
416 return res;
419 gen_res *make_icon(gen_res* res)
421 res->type=ico;
422 return res;
425 gen_res *make_cursor(gen_res* res)
427 res->type=cur;
428 return res;
431 /* load resource bytes from the file name */
432 gen_res *load_file(char* name)
434 gen_res *res;
435 struct stat st;
436 int f=open(name,O_RDONLY);
437 if(!f)perror(name);
438 fstat(f,&st);
439 res=new_res();
440 while(res->space<st.st_size)res=grow(res);
441 read(f,res->res,st.st_size);
442 res->size=st.st_size;
443 close(f);
444 return res;
447 /* insert a normal menu item into res, starting from the last item */
448 gen_res *add_menuitem(char* name,int id,int flags,gen_res *res)
450 char item[4];
451 if(res->num_entries==0)flags|=MF_END;
452 put_WORD(item,flags);
453 put_WORD(item+2,id);
454 res=insert_at_beginning(res,name,strlen(name)+1);
455 res=insert_bytes(res,item,0,4);
456 return res;
459 /* insert a popup item into res */
460 gen_res *add_popup(char *name,short flags, gen_res* body, gen_res*res)
462 char c_flags[2];
463 if(res->num_entries==0)flags|=MF_END;
464 put_WORD(c_flags,flags);
465 res=insert_at_beginning(res,body->res,body->size);
466 res=insert_bytes(res,name,0,strlen(name)+1);
467 res=insert_bytes(res,c_flags,0,2);
468 return res;
471 /* prefix the menu header into res */
472 gen_res *make_menu(gen_res* res)
474 static char header[4]={0,0,0,0};
475 res=insert_at_beginning(res,header,4);
476 res->type=men;
477 return res;
480 /* link top-level resources */
481 gen_res *add_resource(gen_res* first,gen_res *rest)
483 first->next=rest;
484 return first;
487 char *get_typename(gen_res* t)
489 switch(t->type){
490 case acc:return "ACCELERATOR";
491 case bmp:return "BITMAP";
492 case cur:return "CURSOR";
493 case dlg:return "DIALOG";
494 case fnt:return "FONT";
495 case ico:return "ICON";
496 case men:return "MENU";
497 case rdt:return "RCDATA";
498 case str:return "STRINGTABLE";
499 default: return "UNKNOWN";
503 /* create strings like _Sysres_DIALOG_2 */
504 char *get_resource_name(gen_res*it)
506 static char buf[1000];
507 if(it->n_type)
508 sprintf(buf,"%s_%s_%s",prefix,get_typename(it),it->n.s_name);
509 else
510 sprintf(buf,"%s_%s_%d",prefix,get_typename(it),it->n.i_name);
511 return buf;
514 #define ISCONSTANT constant?"const ":""
515 /* create the final output */
516 void create_output(gen_res* top)
518 gen_res *it;
519 fprintf(header,"/*\t\t%s\n * This File is automatically generated."
520 " Do not edit\n */\n#include \"resource.h\"\n",hname);
521 fprintf(code,"/*\t\t%s\n * This File is automatically generated."
522 " Do not edit\n */\n",sname);
523 /* declare the resources */
524 for(it=top;it;it=it->next)
525 fprintf(header,"extern %sunsigned char %s[];\n",ISCONSTANT,
526 get_resource_name(it));
527 fprintf(header,"extern %sstruct ResourceTable %sTable[];\n",
528 ISCONSTANT,prefix);
530 fprintf(code,"#include \"windows.h\"\n#include \"%s\"\n",hname);
532 /* print the resource table (0 terminated) */
533 fprintf(code,"\n%sstruct ResourceTable %sTable[]={\n",ISCONSTANT,prefix);
534 for(it=top;it;it=it->next)
535 { int type;
536 switch(it->type)
537 {case acc:type=NE_RSCTYPE_ACCELERATOR;break;
538 case bmp:type=NE_RSCTYPE_BITMAP;break;
539 case cur:type=NE_RSCTYPE_CURSOR;break;
540 case dlg:type=NE_RSCTYPE_DIALOG;break;
541 case fnt:type=NE_RSCTYPE_FONT;break;
542 case ico:type=NE_RSCTYPE_ICON;break;
543 case men:type=NE_RSCTYPE_MENU;break;
544 case rdt:type=NE_RSCTYPE_RCDATA;break;
545 case str:type=NE_RSCTYPE_STRING;break;
546 default:fprintf(stderr,"Unknown restype\n");type=-1;break;
548 if(it->n_type)
549 fprintf(code,"{0,%d,\"%s\",%s,%d},\n",
550 type,it->n.s_name,get_resource_name(it),it->size);
551 else
552 fprintf(code,"{%d,%d,\"@%d\",%s,%d},\n",
553 it->n.i_name,type,it->n.i_name,get_resource_name(it),
554 it->size);
556 fprintf(code,"{0,0,0,0}};\n\n");
558 /* print the resources */
559 for(it=top;it;it=it->next)
560 { int i;
561 fprintf(code,"%sunsigned char %s[]={\n",
562 ISCONSTANT,get_resource_name(it));
563 for(i=0;i<it->size-1;i++)
565 fprintf(code,"%#4x,",it->res[i]);
566 if((i&7)==7)fputc('\n',code);
568 fprintf(code,"%#4x};\n",it->res[i]);
572 void make_font()
574 fprintf(stderr,"Fonts not supported\n");
577 void make_raw()
579 fprintf(stderr,"RCData not supported\n");
582 void int_to_raw()
584 fprintf(stderr,"IntToRaw not supported\n");
587 /* translate "Hello,\\tworld!\\10" to "Hello,\tworld!\n" */
588 char *parse_c_string(char *in)
590 char *out=malloc(strlen(in)-1);
591 char *it;
592 char tmp[5],*tend;
593 for(it=out,in++;*in;in++)
594 if(*in=='\\')
595 switch(*++in)
596 {case 't':*it++='\t';break;
597 case 'r':*it++='\r';break;
598 case 'n':*it++='\n';break;
599 case 'a':*it++='\a';break;
600 case '0':
601 memset(tmp,0,5);/*make sure it doesn't use more than 4 chars*/
602 memcpy(tmp,in,4);
603 *it++=strtoul(tmp,&tend,0);
604 in+=tend-tmp-1;
605 break;
606 case '1':case '2':case '3':case '4':case '5':
607 case '6':case '7':case '8':case '9':
608 memset(tmp,0,5);
609 memcpy(tmp,in,3);
610 *it++=strtoul(tmp,&tend,10);
611 in+=tend-tmp-1;
612 break;
613 case 'x':
614 memset(tmp,0,5);
615 memcpy(tmp,++in,2);
616 *it++=strtoul(tmp,&tend,16);
617 in+=tend-tmp-1;
618 break;
619 default:*it++=*in;
621 else
622 *it++=*in;
623 *(it-1)='\0';
624 return out;