Release 951003
[wine/multimedia.git] / rc / winerc.c
blobafdd89e8a39fb104d7c3e2444ff7c5af335ad1b3
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 transform_binary_file(void);
35 int yyparse(void);
37 int main(int argc,char *argv[])
39 extern int yydebug;
40 extern char* optarg;
41 int optc,lose,ret,binary;
42 lose=binary=0;
43 while((optc=getopt(argc,argv,"bdp:vo:"))!=EOF)
44 switch(optc)
46 /* bison will print state transitions on stderr */
47 case 'b':binary=1;
48 break;
49 case 'd':yydebug=1;
50 setbuf(stdout,0);
51 setbuf(stderr,0);
52 break;
53 case 'p':prefix=optarg;break;
54 case 'c':constant=1;break;
55 case 'v':verbose=1;
56 setbuf(stderr,0);
57 break;
58 case 'o':set_out_file(optarg);break;
59 default: lose++;break;
61 if(lose)return fprintf(stderr,usage),1;
62 if(!header)header=stdout;
63 if(!code)code=stdout;
64 if(binary)
65 ret=transform_binary_file();
66 else
67 ret=yyparse();
68 fclose(header);
69 fclose(code);
70 return ret;
73 void set_out_file(char *prefix)
75 sprintf(sname,"%s.c",prefix);
76 code=fopen(sname,"w");
77 sprintf(hname,"%s.h",prefix);
78 header=fopen(hname,"w");
81 int transform_binary_file()
83 int i,c;
84 fprintf(header,"#define APPLICATION_HAS_RESOURCES 1\n");
85 fprintf(code,"char _Application_resources[]={");
86 for(i=0;;i++)
88 c=getchar();
89 if(c==-1)break;
90 if(i%16==0)fputc('\n',code);
91 fprintf(code,"%3d,",c);
93 fprintf(code,"\n0}\nint _Aplication_resources_size=%d;\n",i);
94 return 0;
97 /* SunOS' memcpy is wrong for overlapping arrays */
98 char *save_memcpy(char *d,char* s,int l)
100 if(d<s)
101 for(;l;l--)*d++=*s++;
102 else
103 for(d+=l-1,s+=l-1;l;l--)*d--=*s--;
104 return d;
107 /*allow unaligned access*/
108 void put_WORD(unsigned char* p,WORD w)
110 *p=w&0xFF;
111 *(p+1)=w>>8;
114 void put_DWORD(unsigned char* p,DWORD d)
116 put_WORD(p,d&0xFFFF);
117 put_WORD(p+2,d>>16);
120 WORD get_WORD(unsigned char* p)
122 return *p|(*(p+1)<<8);
125 DWORD get_DWORD(unsigned char* p)
127 return get_WORD(p)|(get_WORD(p+2)<<16);
131 /*create a new gen_res, initial size 100*/
132 gen_res *new_res()
133 { gen_res* ret=malloc(sizeof(gen_res)+100);
134 int i;
135 if(!ret)
136 fprintf(stderr,"Out of memory\n"),exit(1);
137 for(i=0;i<sizeof(gen_res)+100;i++)*((char*)ret+i)='\0';
138 ret->g_next=g_start;
139 ret->g_prev=0;
140 g_start=ret;
141 ret->space=100;
142 return ret;
145 /*double the space*/
146 gen_res* grow(gen_res* res)
148 res=realloc(res,sizeof(gen_res)+2*res->space);
149 if(!res)
150 fprintf(stderr,"Out of memory\n"),exit(1);
151 if(!res->g_prev)g_start=res;
152 else res->g_prev->g_next=res;
153 if(res->g_next)res->g_next->g_prev=res;
154 res->space=2*res->space;
155 return res;
159 /* insert bytes at offset 0, increase num_entries */
160 gen_res* insert_at_beginning(gen_res* res,char* entry,int size)
162 while(res->size+size>res->space)res=grow(res);
163 save_memcpy(res->res+size,res->res,res->size);
164 save_memcpy(res->res,entry,size);
165 res->size+=size;
166 res->num_entries++;
167 return res;
170 /* insert length characters from bytes into res, starting at start */
171 gen_res* insert_bytes(gen_res* res,char* bytes,int start,int length)
173 while(res->size+length>res->space)res=grow(res);
174 save_memcpy(res->res+start+length,res->res+start,res->size-start);
175 save_memcpy(res->res+start,bytes,length);
176 res->size+=length;
177 return res;
180 /*delete len bytes from res, starting at start*/
181 gen_res* delete_bytes(gen_res* res,int start,int len)
183 save_memcpy(res->res+start,res->res+start+len,res->size-start-len);
184 res->size-=len;
185 return res;
188 /*create a new style*/
189 rc_style *new_style()
191 rc_style *ret=malloc(sizeof(rc_style));
192 /*initially, no bits have to be reset*/
193 ret->and=-1;
194 /*initially, no bits are set*/
195 ret->or=0;
196 return ret;
199 /* entries are inserted at the beginning, starting from the last one */
200 gen_res* add_accelerator(int ev, int id, int flags, gen_res* prev)
202 char accel_entry[5];
203 if(prev->num_entries==0)flags|=0x80; /* last entry */
204 accel_entry[0]=flags;
205 put_WORD(accel_entry+1,ev);
206 put_WORD(accel_entry+3,id);
207 return insert_at_beginning(prev,accel_entry,5);
211 /* create an integer from the event, taking things as "^c" into account
212 add this as new entry */
213 gen_res* add_string_accelerator(char *ev, int id, int flags, gen_res* prev)
215 int event;
216 if(*ev=='^')
217 event=ev[1]-'a';
218 else
219 event=ev[0];
220 return add_accelerator(event,id,flags,prev);
223 /*is there a difference between ASCII and VIRTKEY accelerators? */
225 gen_res* add_ascii_accelerator(int ev, int id, int flags, gen_res* prev)
227 return add_accelerator(ev,id,flags,prev);
230 gen_res* add_vk_accelerator(int ev, int id, int flags, gen_res* prev)
232 return add_accelerator(ev,id,flags,prev);
235 /* create a new dialog header, set all items to 0 */
236 gen_res* new_dialog()
237 { gen_res* ret=new_res();
238 ret->size=16; /*all strings "\0", no font*/
239 return ret;
242 /* the STYLE option was specified */
243 gen_res* dialog_style(rc_style* style, gen_res* attr)
245 /* default dialog styles? Do we need style->and? */
246 /* DS_SETFONT might have been specified before */
247 put_DWORD(attr->res,get_DWORD(attr->res)|style->or);
248 return attr;
251 /* menu name is at offset 13 */
252 int dialog_get_menu(gen_res* attr)
254 return 13;
257 /* the class is after the menu name */
258 int dialog_get_class(gen_res* attr)
260 int offs=dialog_get_menu(attr);
261 while(attr->res[offs])offs++;
262 offs++;
263 return offs;
266 /* the caption is after the class */
267 int dialog_get_caption(gen_res* attr)
269 int offs=dialog_get_class(attr);
270 while(attr->res[offs])offs++;
271 offs++;
272 return offs;
275 /* the fontsize, if present, is after the caption, followed by the font name */
276 int dialog_get_fontsize(gen_res* attr)
278 int offs=dialog_get_caption(attr);
279 while(attr->res[offs])offs++;
280 offs++;
281 return offs;
285 /* the CAPTION option was specified */
286 gen_res* dialog_caption(char* cap, gen_res*attr)
288 /* we don't need the terminating 0 as it's already there */
289 return insert_bytes(attr,cap,dialog_get_caption(attr),strlen(cap));
293 /* the FONT option was specified, set the DS_SETFONT flag */
294 gen_res* dialog_font(short size,char* font,gen_res *attr)
296 char c_size[2];
297 int offs=dialog_get_fontsize(attr);
298 put_DWORD(attr->res,get_DWORD(attr->res)|DS_SETFONT);
299 put_WORD(c_size,size);
300 attr=insert_bytes(attr,c_size,offs,2);
301 offs+=2;
302 /* as there is no font name by default, copy the '\0' */
303 return insert_bytes(attr,font,offs,strlen(font)+1);
306 gen_res* dialog_class(char* cap, gen_res*attr)
308 return insert_bytes(attr,cap,dialog_get_class(attr),strlen(cap));
311 gen_res* dialog_menu(char* cap, gen_res*attr)
313 return insert_bytes(attr,cap,dialog_get_menu(attr),strlen(cap));
316 /* set the dialogs id, position, extent, and style */
317 gen_res* create_control_desc(int id,int x,int y,int cx, int cy,rc_style *style)
318 { gen_res* ret=new_res();
319 int s=WS_VISIBLE|WS_CHILD; /*defaults styles for any control*/
320 put_WORD(ret->res+0,x);
321 put_WORD(ret->res+2,y);
322 put_WORD(ret->res+4,cx);
323 put_WORD(ret->res+6,cy);
324 put_WORD(ret->res+8,id);
325 if(style)s=(s|style->or)&style->and;
326 put_DWORD(ret->res+10,s);
327 ret->size=17; /*empty strings, unused byte*/
328 return ret;
331 /* insert the control's label */
332 gen_res* label_control_desc(char* label,gen_res* cd)
334 int offs;
335 if(cd->res[14]&0x80)offs=15; /* one-character class */
336 else {
337 for(offs=14;cd->res[offs];offs++);
338 offs++;
340 return insert_bytes(cd,label,offs,strlen(label));
343 /* a CONTROL was specified */
344 gen_res* create_generic_control(char* label,int id,char* class,
345 rc_style*style,int x,int y,int cx,int cy)
346 { char cl;
347 gen_res* ret=new_res();
348 put_WORD(ret->res+0,x);
349 put_WORD(ret->res+2,y);
350 put_WORD(ret->res+4,cx);
351 put_WORD(ret->res+6,cy);
352 put_WORD(ret->res+8,id);
353 put_DWORD(ret->res+10,style->or);
354 ret->size=17;
355 ret=insert_bytes(ret,label,15,strlen(label));
356 /* is it a predefined class? */
357 cl=0;
358 if(!strcmp(class,"BUTTON"))cl=CT_BUTTON;
359 if(!strcmp(class,"EDIT"))cl=CT_EDIT;
360 if(!strcmp(class,"STATIC"))cl=CT_STATIC;
361 if(!strcmp(class,"LISTBOX"))cl=CT_LISTBOX;
362 if(!strcmp(class,"SCROLLBAR"))cl=CT_SCROLLBAR;
363 if(!strcmp(class,"COMBOBOX"))cl=CT_COMBOBOX;
364 if(cl)ret->res[14]=cl;
365 else ret=insert_bytes(ret,class,14,strlen(class));
366 return ret;
369 /* insert cd into rest, set the type, add flags */
370 gen_res* add_control(int type,int flags,gen_res*cd,gen_res* rest)
372 put_DWORD(cd->res+10,get_DWORD(cd->res+10)|flags);
373 cd->res[14]=type;
374 return insert_at_beginning(rest,cd->res,cd->size);
377 /* an ICON control was specified, whf contains width, height, and flags */
378 gen_res* add_icon(char* name,int id,int x,int y,gen_res* whf,gen_res* rest)
380 put_WORD(whf->res+0,x);
381 put_WORD(whf->res+2,y);
382 put_WORD(whf->res+8,id);
383 whf=label_control_desc(name,whf);
384 return add_control(CT_STATIC,SS_ICON,whf,rest);
387 /* insert the generic control into rest */
388 gen_res* add_generic_control(gen_res* ctl, gen_res* rest)
390 return insert_at_beginning(rest,ctl->res,ctl->size);
393 /* create a dialog resource by inserting the header into the controls.
394 Set position and extent */
395 gen_res* make_dialog(gen_res* header,int x,int y,int cx,int cy,gen_res* ctls)
397 header->res[4]=ctls->num_entries;
398 header->type=dlg;
399 put_WORD(header->res+5,x);
400 put_WORD(header->res+7,y);
401 put_WORD(header->res+9,cx);
402 put_WORD(header->res+11,cy);
403 return insert_bytes(header,ctls->res,header->size,ctls->size);
406 /* create {0x15,0x16,0xFF} from '15 16 FF' */
407 gen_res *hex_to_raw(char *hex, gen_res*rest)
409 char r2[16];
410 int i;
411 for(i=0;*hex!='\'';i++)r2[i]=strtoul(hex,&hex,16);
412 return insert_bytes(rest,r2,0,i);
415 /* create a bitmap resource */
416 gen_res *make_bitmap(gen_res* res)
418 res=delete_bytes(res,0,14); /* skip bitmap file header*/
419 res->type=bmp;
420 return res;
423 gen_res *make_icon(gen_res* res)
425 res->type=ico;
426 return res;
429 gen_res *make_cursor(gen_res* res)
431 res->type=cur;
432 return res;
435 /* load resource bytes from the file name */
436 gen_res *load_file(char* name)
438 gen_res *res;
439 struct stat st;
440 int f=open(name,O_RDONLY);
441 if(!f)perror(name);
442 fstat(f,&st);
443 res=new_res();
444 while(res->space<st.st_size)res=grow(res);
445 read(f,res->res,st.st_size);
446 res->size=st.st_size;
447 close(f);
448 return res;
451 /* insert a normal menu item into res, starting from the last item */
452 gen_res *add_menuitem(char* name,int id,int flags,gen_res *res)
454 char item[4];
455 if(res->num_entries==0)flags|=MF_END;
456 put_WORD(item,flags);
457 put_WORD(item+2,id);
458 res=insert_at_beginning(res,name,strlen(name)+1);
459 res=insert_bytes(res,item,0,4);
460 return res;
463 /* insert a popup item into res */
464 gen_res *add_popup(char *name,short flags, gen_res* body, gen_res*res)
466 char c_flags[2];
467 if(res->num_entries==0)flags|=MF_END;
468 put_WORD(c_flags,flags);
469 res=insert_at_beginning(res,body->res,body->size);
470 res=insert_bytes(res,name,0,strlen(name)+1);
471 res=insert_bytes(res,c_flags,0,2);
472 return res;
475 /* prefix the menu header into res */
476 gen_res *make_menu(gen_res* res)
478 static char header[4]={0,0,0,0};
479 res=insert_at_beginning(res,header,4);
480 res->type=men;
481 return res;
484 /* link top-level resources */
485 gen_res *add_resource(gen_res* first,gen_res *rest)
487 first->next=rest;
488 return first;
491 char *get_typename(gen_res* t)
493 switch(t->type){
494 case acc:return "ACCELERATOR";
495 case bmp:return "BITMAP";
496 case cur:return "CURSOR";
497 case dlg:return "DIALOG";
498 case fnt:return "FONT";
499 case ico:return "ICON";
500 case men:return "MENU";
501 case rdt:return "RCDATA";
502 case str:return "STRINGTABLE";
503 default: return "UNKNOWN";
507 /* create strings like _Sysres_DIALOG_2 */
508 char *get_resource_name(gen_res*it)
510 static char buf[1000];
511 if(it->n_type)
512 sprintf(buf,"%s_%s_%s",prefix,get_typename(it),it->n.s_name);
513 else
514 sprintf(buf,"%s_%s_%d",prefix,get_typename(it),it->n.i_name);
515 return buf;
518 #define ISCONSTANT (constant ? "const " : "")
520 /* create the final output */
521 void create_output(gen_res* top)
523 gen_res *it;
526 fprintf( header, "/* %s\n"
527 " * This file is automatically generated. Do not edit!\n"
528 " */\n\n"
529 "struct resource\n"
530 "{\n"
531 " int id, type;\n"
532 " char *name;\n"
533 " unsigned char *bytes;\n"
534 " unsigned int size;\n"
535 "};\n\n", hname );
537 /* Declare the resources */
539 for (it=top;it;it=it->next)
540 fprintf( header,"extern %sstruct resource %s;\n",
541 ISCONSTANT, get_resource_name(it) );
542 fprintf( header,"\nextern %sstruct resource * %sTable[];\n",
543 ISCONSTANT, prefix );
545 /* Print the resources bytes */
547 fprintf( code, "/* %s\n"
548 " * This file is automatically generated. Do not edit!\n"
549 " */\n\n"
550 "#include \"%s\"\n", sname, hname );
551 for(it=top;it;it=it->next)
553 int i;
554 fprintf( code, "static %sunsigned char %s__bytes[] = {\n",
555 ISCONSTANT, get_resource_name(it) );
556 for (i=0;i<it->size-1;i++)
558 fprintf(code,"%#4x,",it->res[i]);
559 if ((i&7)==7)fputc('\n',code);
561 fprintf(code,"%#4x};\n\n",it->res[i]);
564 /* Print the resources */
565 for (it=top;it;it=it->next)
567 int type;
568 switch(it->type)
570 case acc:type=NE_RSCTYPE_ACCELERATOR;break;
571 case bmp:type=NE_RSCTYPE_BITMAP;break;
572 case cur:type=NE_RSCTYPE_CURSOR;break;
573 case dlg:type=NE_RSCTYPE_DIALOG;break;
574 case fnt:type=NE_RSCTYPE_FONT;break;
575 case ico:type=NE_RSCTYPE_ICON;break;
576 case men:type=NE_RSCTYPE_MENU;break;
577 case rdt:type=NE_RSCTYPE_RCDATA;break;
578 case str:type=NE_RSCTYPE_STRING;break;
579 default:fprintf(stderr,"Unknown restype\n");type=-1;break;
581 if(it->n_type)
582 fprintf(code,"%sstruct resource %s = {0,%d,\"%s\",%s__bytes,%d};\n",
583 ISCONSTANT, get_resource_name(it), type, it->n.s_name,
584 get_resource_name(it), it->size );
585 else
586 fprintf(code,"%sstruct resource %s = {%d,%d,\"@%d\",%s__bytes,%d};\n",
587 ISCONSTANT, get_resource_name(it), it->n.i_name, type,
588 it->n.i_name, get_resource_name(it), it->size );
591 /* Print the resource table (NULL terminated) */
593 fprintf(code,"\n%sstruct resource * %sTable[] = {\n", ISCONSTANT, prefix);
594 for (it=top;it;it=it->next)
595 fprintf( code, " &%s,\n", get_resource_name(it) );
596 fprintf( code, " 0\n};\n" );
599 gen_res* make_font(gen_res* res)
601 fprintf(stderr,"Fonts not supported\n");
602 return NULL;
605 gen_res* make_raw(gen_res* res)
607 fprintf(stderr,"RCData not supported\n");
608 return NULL;
611 gen_res* int_to_raw(int i,gen_res* res)
613 fprintf(stderr,"IntToRaw not supported\n");
614 return NULL;
617 /* translate "Hello,\\tworld!\\10" to "Hello,\tworld!\n" */
618 char *parse_c_string(char *in)
620 char *out=malloc(strlen(in)-1);
621 char *it;
622 char tmp[5],*tend;
623 for(it=out,in++;*in;in++)
624 if(*in=='\\')
625 switch(*++in)
626 {case 't':*it++='\t';break;
627 case 'r':*it++='\r';break;
628 case 'n':*it++='\n';break;
629 case 'a':*it++='\a';break;
630 case '0':
631 memset(tmp,0,5);/*make sure it doesn't use more than 4 chars*/
632 memcpy(tmp,in,4);
633 *it++=strtoul(tmp,&tend,0);
634 in+=tend-tmp-1;
635 break;
636 case '1':case '2':case '3':case '4':case '5':
637 case '6':case '7':case '8':case '9':
638 memset(tmp,0,5);
639 memcpy(tmp,in,3);
640 *it++=strtoul(tmp,&tend,10);
641 in+=tend-tmp-1;
642 break;
643 case 'x':
644 memset(tmp,0,5);
645 memcpy(tmp,++in,2);
646 *it++=strtoul(tmp,&tend,16);
647 in+=tend-tmp-1;
648 break;
649 default:*it++=*in;
651 else
652 *it++=*in;
653 *(it-1)='\0';
654 return out;