Release 951226
[wine/gsoc-2012-control.git] / rc / winerc.c
blobf5ec38074bd7fb7676188bb9309be0fddf3626b2
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 " -c Add 'const' prefix to C constants\n"
22 " -d Output debugging information\n"
23 " -p prefix Give a prefix for the generated names\n"
24 " -v Show each resource as it is processed\n"
25 " -o file Output to file.c and file.h\n";
28 /*might be overwritten by command line*/
29 char *prefix="_Resource";
30 int verbose,constant;
31 gen_res* g_start;
32 FILE *header,*code;
33 char hname[256],sname[256];
35 int transform_binary_file(void);
36 int yyparse(void);
38 static void *xmalloc (size_t size)
40 void *res;
42 res = malloc (size ? size : 1);
43 if (res == NULL)
45 fprintf (stderr, "Virtual memory exhausted.\n");
46 exit (1);
48 return res;
52 int main(int argc,char *argv[])
54 extern int yydebug;
55 extern char* optarg;
56 int optc,lose,ret,binary;
57 lose=binary=0;
58 while((optc=getopt(argc,argv,"bcdp:vo:"))!=EOF)
59 switch(optc)
61 /* bison will print state transitions on stderr */
62 case 'b':binary=1;
63 break;
64 case 'd':yydebug=1;
65 setbuf(stdout,0);
66 setbuf(stderr,0);
67 break;
68 case 'p':prefix=optarg;break;
69 case 'c':constant=1;break;
70 case 'v':verbose=1;
71 setbuf(stderr,0);
72 break;
73 case 'o':set_out_file(optarg);break;
74 default: lose++;break;
76 if(lose)return fprintf(stderr,usage),1;
77 if(!header)header=stdout;
78 if(!code)code=stdout;
79 if(binary)
80 ret=transform_binary_file();
81 else
82 ret=yyparse();
83 fclose(header);
84 fclose(code);
85 return ret;
88 void set_out_file(char *prefix)
90 sprintf(sname,"%s.c",prefix);
91 code=fopen(sname,"w");
92 sprintf(hname,"%s.h",prefix);
93 header=fopen(hname,"w");
96 int transform_binary_file()
98 int i,c;
99 fprintf(header,"#define APPLICATION_HAS_RESOURCES 1\n");
100 fprintf(code,"char _Application_resources[]={");
101 for(i=0;;i++)
103 c=getchar();
104 if(c==-1)break;
105 if(i%16==0)fputc('\n',code);
106 fprintf(code,"%3d,",c);
108 fprintf(code,"\n0}\nint _Aplication_resources_size=%d;\n",i);
109 return 0;
112 /* SunOS' memcpy is wrong for overlapping arrays */
113 char *save_memcpy(char *d,char* s,int l)
115 if(d<s)
116 for(;l;l--)*d++=*s++;
117 else
118 for(d+=l-1,s+=l-1;l;l--)*d--=*s--;
119 return d;
122 /*allow unaligned access*/
123 void put_WORD(unsigned char* p,WORD w)
125 *p=w&0xFF;
126 *(p+1)=w>>8;
129 void put_DWORD(unsigned char* p,DWORD d)
131 put_WORD(p,d&0xFFFF);
132 put_WORD(p+2,d>>16);
135 WORD get_WORD(unsigned char* p)
137 return *p|(*(p+1)<<8);
140 DWORD get_DWORD(unsigned char* p)
142 return get_WORD(p)|(get_WORD(p+2)<<16);
146 /*create a new gen_res, initial size 100*/
147 gen_res *new_res()
148 { gen_res* ret=xmalloc(sizeof(gen_res)+100);
149 int i;
150 for(i=0;i<sizeof(gen_res)+100;i++)*((char*)ret+i)='\0';
151 ret->g_next=g_start;
152 ret->g_prev=0;
153 g_start=ret;
154 ret->space=100;
155 return ret;
158 /*double the space*/
159 gen_res* grow(gen_res* res)
161 res=realloc(res,sizeof(gen_res)+2*res->space);
162 if(!res)
163 fprintf(stderr,"Out of memory\n"),exit(1);
164 if(!res->g_prev)g_start=res;
165 else res->g_prev->g_next=res;
166 if(res->g_next)res->g_next->g_prev=res;
167 res->space=2*res->space;
168 return res;
172 /* insert bytes at offset 0, increase num_entries */
173 gen_res* insert_at_beginning(gen_res* res,char* entry,int size)
175 while(res->size+size>res->space)res=grow(res);
176 save_memcpy(res->res+size,res->res,res->size);
177 save_memcpy(res->res,entry,size);
178 res->size+=size;
179 res->num_entries++;
180 return res;
183 /* insert length characters from bytes into res, starting at start */
184 gen_res* insert_bytes(gen_res* res,char* bytes,int start,int length)
186 while(res->size+length>res->space)res=grow(res);
187 save_memcpy(res->res+start+length,res->res+start,res->size-start);
188 save_memcpy(res->res+start,bytes,length);
189 res->size+=length;
190 return res;
193 /*delete len bytes from res, starting at start*/
194 gen_res* delete_bytes(gen_res* res,int start,int len)
196 save_memcpy(res->res+start,res->res+start+len,res->size-start-len);
197 res->size-=len;
198 return res;
201 /*create a new style*/
202 rc_style *new_style()
204 rc_style *ret=xmalloc(sizeof(rc_style));
205 /*initially, no bits have to be reset*/
206 ret->and=-1;
207 /*initially, no bits are set*/
208 ret->or=0;
209 return ret;
212 /* entries are inserted at the beginning, starting from the last one */
213 gen_res* add_accelerator(int ev, int id, int flags, gen_res* prev)
215 char accel_entry[5];
216 if(prev->num_entries==0)flags|=0x80; /* last entry */
217 accel_entry[0]=flags;
218 put_WORD(accel_entry+1,ev);
219 put_WORD(accel_entry+3,id);
220 return insert_at_beginning(prev,accel_entry,5);
224 /* create an integer from the event, taking things as "^c" into account
225 add this as new entry */
226 gen_res* add_string_accelerator(char *ev, int id, int flags, gen_res* prev)
228 int event;
229 if(*ev=='^')
230 event=ev[1]-'a';
231 else
232 event=ev[0];
233 return add_accelerator(event,id,flags,prev);
236 /*is there a difference between ASCII and VIRTKEY accelerators? */
238 gen_res* add_ascii_accelerator(int ev, int id, int flags, gen_res* prev)
240 return add_accelerator(ev,id,flags,prev);
243 gen_res* add_vk_accelerator(int ev, int id, int flags, gen_res* prev)
245 return add_accelerator(ev,id,flags,prev);
248 /* create a new dialog header, set all items to 0 */
249 gen_res* new_dialog()
250 { gen_res* ret=new_res();
251 ret->size=16; /*all strings "\0", no font*/
252 return ret;
255 /* the STYLE option was specified */
256 gen_res* dialog_style(rc_style* style, gen_res* attr)
258 /* default dialog styles? Do we need style->and? */
259 /* DS_SETFONT might have been specified before */
260 put_DWORD(attr->res,get_DWORD(attr->res)|style->or);
261 return attr;
264 /* menu name is at offset 13 */
265 int dialog_get_menu(gen_res* attr)
267 return 13;
270 /* the class is after the menu name */
271 int dialog_get_class(gen_res* attr)
273 int offs=dialog_get_menu(attr);
274 while(attr->res[offs])offs++;
275 offs++;
276 return offs;
279 /* the caption is after the class */
280 int dialog_get_caption(gen_res* attr)
282 int offs=dialog_get_class(attr);
283 while(attr->res[offs])offs++;
284 offs++;
285 return offs;
288 /* the fontsize, if present, is after the caption, followed by the font name */
289 int dialog_get_fontsize(gen_res* attr)
291 int offs=dialog_get_caption(attr);
292 while(attr->res[offs])offs++;
293 offs++;
294 return offs;
298 /* the CAPTION option was specified */
299 gen_res* dialog_caption(char* cap, gen_res*attr)
301 /* we don't need the terminating 0 as it's already there */
302 return insert_bytes(attr,cap,dialog_get_caption(attr),strlen(cap));
306 /* the FONT option was specified, set the DS_SETFONT flag */
307 gen_res* dialog_font(short size,char* font,gen_res *attr)
309 char c_size[2];
310 int offs=dialog_get_fontsize(attr);
311 put_DWORD(attr->res,get_DWORD(attr->res)|DS_SETFONT);
312 put_WORD(c_size,size);
313 attr=insert_bytes(attr,c_size,offs,2);
314 offs+=2;
315 /* as there is no font name by default, copy the '\0' */
316 return insert_bytes(attr,font,offs,strlen(font)+1);
319 gen_res* dialog_class(char* cap, gen_res*attr)
321 return insert_bytes(attr,cap,dialog_get_class(attr),strlen(cap));
324 gen_res* dialog_menu(char* cap, gen_res*attr)
326 return insert_bytes(attr,cap,dialog_get_menu(attr),strlen(cap));
329 /* set the dialogs id, position, extent, and style */
330 gen_res* create_control_desc(int id,int x,int y,int cx, int cy,rc_style *style)
331 { gen_res* ret=new_res();
332 int s=WS_VISIBLE|WS_CHILD; /*defaults styles for any control*/
333 put_WORD(ret->res+0,x);
334 put_WORD(ret->res+2,y);
335 put_WORD(ret->res+4,cx);
336 put_WORD(ret->res+6,cy);
337 put_WORD(ret->res+8,id);
338 if(style)s=(s|style->or)&style->and;
339 put_DWORD(ret->res+10,s);
340 ret->size=17; /*empty strings, unused byte*/
341 return ret;
344 /* insert the control's label */
345 gen_res* label_control_desc(char* label,gen_res* cd)
347 int offs;
348 if(cd->res[14]&0x80)offs=15; /* one-character class */
349 else {
350 for(offs=14;cd->res[offs];offs++);
351 offs++;
353 return insert_bytes(cd,label,offs,strlen(label));
356 /* a CONTROL was specified */
357 gen_res* create_generic_control(char* label,int id,char* class,
358 rc_style*style,int x,int y,int cx,int cy)
359 { char cl;
360 gen_res* ret=new_res();
361 put_WORD(ret->res+0,x);
362 put_WORD(ret->res+2,y);
363 put_WORD(ret->res+4,cx);
364 put_WORD(ret->res+6,cy);
365 put_WORD(ret->res+8,id);
366 put_DWORD(ret->res+10,style->or);
367 ret->size=17;
368 ret=insert_bytes(ret,label,15,strlen(label));
369 /* is it a predefined class? */
370 cl=0;
371 if(!strcmp(class,"BUTTON"))cl=CT_BUTTON;
372 if(!strcmp(class,"EDIT"))cl=CT_EDIT;
373 if(!strcmp(class,"STATIC"))cl=CT_STATIC;
374 if(!strcmp(class,"LISTBOX"))cl=CT_LISTBOX;
375 if(!strcmp(class,"SCROLLBAR"))cl=CT_SCROLLBAR;
376 if(!strcmp(class,"COMBOBOX"))cl=CT_COMBOBOX;
377 if(cl)ret->res[14]=cl;
378 else ret=insert_bytes(ret,class,14,strlen(class));
379 return ret;
382 /* insert cd into rest, set the type, add flags */
383 gen_res* add_control(int type,int flags,gen_res*cd,gen_res* rest)
385 put_DWORD(cd->res+10,get_DWORD(cd->res+10)|flags);
386 cd->res[14]=type;
387 return insert_at_beginning(rest,cd->res,cd->size);
390 /* an ICON control was specified, whf contains width, height, and flags */
391 gen_res* add_icon(char* name,int id,int x,int y,gen_res* whf,gen_res* rest)
393 put_WORD(whf->res+0,x);
394 put_WORD(whf->res+2,y);
395 put_WORD(whf->res+8,id);
396 whf=label_control_desc(name,whf);
397 return add_control(CT_STATIC,SS_ICON,whf,rest);
400 /* insert the generic control into rest */
401 gen_res* add_generic_control(gen_res* ctl, gen_res* rest)
403 return insert_at_beginning(rest,ctl->res,ctl->size);
406 /* create a dialog resource by inserting the header into the controls.
407 Set position and extent */
408 gen_res* make_dialog(gen_res* header,int x,int y,int cx,int cy,gen_res* ctls)
410 header->res[4]=ctls->num_entries;
411 header->type=dlg;
412 put_WORD(header->res+5,x);
413 put_WORD(header->res+7,y);
414 put_WORD(header->res+9,cx);
415 put_WORD(header->res+11,cy);
416 return insert_bytes(header,ctls->res,header->size,ctls->size);
419 /* create {0x15,0x16,0xFF} from '15 16 FF' */
420 gen_res *hex_to_raw(char *hex, gen_res*rest)
422 char r2[16];
423 int i;
424 for(i=0;*hex!='\'';i++)r2[i]=strtoul(hex,&hex,16);
425 return insert_bytes(rest,r2,0,i);
428 /* create a bitmap resource */
429 gen_res *make_bitmap(gen_res* res)
431 res=delete_bytes(res,0,14); /* skip bitmap file header*/
432 res->type=bmp;
433 return res;
436 gen_res *make_icon(gen_res* res)
438 res->type=ico;
439 return res;
442 gen_res *make_cursor(gen_res* res)
444 res->type=cur;
445 return res;
448 /* load resource bytes from the file name */
449 gen_res *load_file(char* name)
451 gen_res *res;
452 struct stat st;
453 int f=open(name,O_RDONLY);
454 if(!f)perror(name);
455 fstat(f,&st);
456 res=new_res();
457 while(res->space<st.st_size)res=grow(res);
458 read(f,res->res,st.st_size);
459 res->size=st.st_size;
460 close(f);
461 return res;
464 /* insert a normal menu item into res, starting from the last item */
465 gen_res *add_menuitem(char* name,int id,int flags,gen_res *res)
467 char item[4];
468 if(res->num_entries==0)flags|=MF_END;
469 put_WORD(item,flags);
470 put_WORD(item+2,id);
471 res=insert_at_beginning(res,name,strlen(name)+1);
472 res=insert_bytes(res,item,0,4);
473 return res;
476 /* insert a popup item into res */
477 gen_res *add_popup(char *name,short flags, gen_res* body, gen_res*res)
479 char c_flags[2];
480 flags|=MF_POPUP;
481 if(res->num_entries==0)flags|=MF_END;
482 put_WORD(c_flags,flags);
483 res=insert_at_beginning(res,body->res,body->size);
484 res=insert_bytes(res,name,0,strlen(name)+1);
485 res=insert_bytes(res,c_flags,0,2);
486 return res;
489 /* prefix the menu header into res */
490 gen_res *make_menu(gen_res* res)
492 static char header[4]={0,0,0,0};
493 res=insert_at_beginning(res,header,4);
494 res->type=men;
495 return res;
498 /* link top-level resources */
499 gen_res *add_resource(gen_res* first,gen_res *rest)
501 first->next=rest;
502 return first;
505 char *get_typename(gen_res* t)
507 switch(t->type){
508 case acc:return "ACCELERATOR";
509 case bmp:return "BITMAP";
510 case cur:return "CURSOR";
511 case dlg:return "DIALOG";
512 case fnt:return "FONT";
513 case ico:return "ICON";
514 case men:return "MENU";
515 case rdt:return "RCDATA";
516 case str:return "STRINGTABLE";
517 default: return "UNKNOWN";
521 /* create strings like _Sysres_DIALOG_2 */
522 char *get_resource_name(gen_res*it)
524 static char buf[1000];
525 if(it->n_type)
526 sprintf(buf,"%s_%s_%s",prefix,get_typename(it),it->n.s_name);
527 else
528 sprintf(buf,"%s_%s_%d",prefix,get_typename(it),it->n.i_name);
529 return buf;
532 #define ISCONSTANT (constant ? "const " : "")
534 /* create the final output */
535 void create_output(gen_res* top)
537 gen_res *it;
540 fprintf( header, "/* %s\n"
541 " * This file is automatically generated. Do not edit!\n"
542 " */\n\n"
543 "#include \"resource.h\"\n", hname );
545 /* Declare the resources */
547 for (it=top;it;it=it->next)
548 fprintf( header,"extern %sstruct resource %s;\n",
549 ISCONSTANT, get_resource_name(it) );
550 fprintf( header,"\nextern %sstruct resource * %s%s_Table[];\n",
551 ISCONSTANT, ISCONSTANT, prefix );
553 /* Print the resources bytes */
555 fprintf( code, "/* %s\n"
556 " * This file is automatically generated. Do not edit!\n"
557 " */\n\n"
558 "#include \"%s\"\n", sname, hname );
559 for(it=top;it;it=it->next)
561 int i;
562 fprintf( code, "static %sunsigned char %s__bytes[] = {\n",
563 ISCONSTANT, get_resource_name(it) );
564 for (i=0;i<it->size-1;i++)
566 fprintf(code,"0x%02x, ",it->res[i]);
567 if ((i&7)==7)fputc('\n',code);
569 fprintf(code,"0x%02x };\n\n",it->res[i]);
572 /* Print the resources */
573 for (it=top;it;it=it->next)
575 int type;
576 switch(it->type)
578 case acc:type=(int)RT_ACCELERATOR;break;
579 case bmp:type=(int)RT_BITMAP;break;
580 case cur:type=(int)RT_CURSOR;break;
581 case dlg:type=(int)RT_DIALOG;break;
582 case fnt:type=(int)RT_FONT;break;
583 case ico:type=(int)RT_ICON;break;
584 case men:type=(int)RT_MENU;break;
585 case rdt:type=(int)RT_RCDATA;break;
586 case str:type=(int)RT_STRING;break;
587 default:fprintf(stderr,"Unknown restype\n");type=-1;break;
589 if(it->n_type)
590 fprintf(code,"%sstruct resource %s = {0,%d,\"%s\",%s__bytes,%d};\n",
591 ISCONSTANT, get_resource_name(it), type, it->n.s_name,
592 get_resource_name(it), it->size );
593 else
594 fprintf(code,"%sstruct resource %s = {%d,%d,\"@%d\",%s__bytes,%d};\n",
595 ISCONSTANT, get_resource_name(it), it->n.i_name, type,
596 it->n.i_name, get_resource_name(it), it->size );
599 /* Print the resource table (NULL terminated) */
601 fprintf(code,"\n%sstruct resource * %s%s_Table[] = {\n",
602 ISCONSTANT, ISCONSTANT, prefix);
603 for (it=top;it;it=it->next)
604 fprintf( code, " &%s,\n", get_resource_name(it) );
605 fprintf( code, " 0\n};\n" );
607 /* Perform autoregistration */
608 fprintf( code,
609 "#ifdef WINELIB\n"
610 "static void DoIt() WINE_CONSTRUCTOR;\n"
611 "static void DoIt()\n"
612 "{\n"
613 "\tLIBRES_RegisterResources(%s_Table);\n"
614 "}\n\n"
615 "#ifndef HAVE_WINE_CONSTRUCTOR\n"
616 "void LIBWINE_Register_%s(){\n"
617 "\tDoIt();\n"
618 "}\n"
619 "#endif\n"
620 "#endif /*WINELIB*/\n"
621 ,prefix,prefix);
624 gen_res* make_font(gen_res* res)
626 fprintf(stderr,"Fonts not supported\n");
627 return NULL;
630 gen_res* make_raw(gen_res* res)
632 fprintf(stderr,"RCData not supported\n");
633 return NULL;
636 gen_res* int_to_raw(int i,gen_res* res)
638 fprintf(stderr,"IntToRaw not supported\n");
639 return NULL;
642 /* translate "Hello,\\tworld!\\10" to "Hello,\tworld!\n" */
643 char *parse_c_string(char *in)
645 char *out=xmalloc(strlen(in)-1);
646 char *it;
647 char tmp[5],*tend;
648 for(it=out,in++;*in;in++)
649 if(*in=='\\')
650 switch(*++in)
651 {case 't':*it++='\t';break;
652 case 'r':*it++='\r';break;
653 case 'n':*it++='\n';break;
654 case 'a':*it++='\a';break;
655 case '0':
656 memset(tmp,0,5);/*make sure it doesn't use more than 4 chars*/
657 memcpy(tmp,in,4);
658 *it++=strtoul(tmp,&tend,0);
659 in+=tend-tmp-1;
660 break;
661 case '1':case '2':case '3':case '4':case '5':
662 case '6':case '7':case '8':case '9':
663 memset(tmp,0,5);
664 memcpy(tmp,in,3);
665 *it++=strtoul(tmp,&tend,10);
666 in+=tend-tmp-1;
667 break;
668 case 'x':
669 memset(tmp,0,5);
670 memcpy(tmp,++in,2);
671 *it++=strtoul(tmp,&tend,16);
672 in+=tend-tmp-1;
673 break;
674 default:*it++=*in;
676 else
677 *it++=*in;
678 *(it-1)='\0';
679 return out;