/* * Generate .res format from a resource-tree * * Copyright 1998 Bertho A. Stultiens * * 25-May-1998 BS - Added simple unicode -> char conversion for resource * names in .s and .h files. */ #include #include #include #include #include #include #include "wrc.h" #include "genres.h" #include "utils.h" #define SetResSize(res, tag) *(DWORD *)&((res)->data[(tag)]) = \ (res)->size - *(DWORD *)&((res)->data[(tag)]) res_t *new_res(void) { res_t *r; r = (res_t *)xmalloc(sizeof(res_t)); r->allocsize = RES_BLOCKSIZE; r->size = 0; r->data = (char *)xmalloc(RES_BLOCKSIZE); return r; } res_t *grow_res(res_t *r, int add) { r->allocsize += add; r->data = (char *)xrealloc(r->data, r->allocsize); return r; } /* ***************************************************************************** * Function : put_byte * put_word * put_dword * Syntax : void put_byte(res_t *res, unsigned c) * void put_word(res_t *res, unsigned w) * void put_dword(res_t *res, unsigned d) * Input : * res - Binary resource to put the data in * c, w, d - Data to put * Output : nop * Description : Put primitives that put an item in the binary resource. * The data array grows automatically. * Remarks : ***************************************************************************** */ void put_byte(res_t *res, unsigned c) { if(res->allocsize - res->size < sizeof(char)) grow_res(res, RES_BLOCKSIZE); *(char *)&(res->data[res->size]) = (char)c; res->size += sizeof(char); } void put_word(res_t *res, unsigned w) { if(res->allocsize - res->size < sizeof(WORD)) grow_res(res, RES_BLOCKSIZE); *(WORD *)&(res->data[res->size]) = (WORD)w; res->size += sizeof(WORD); } void put_dword(res_t *res, unsigned d) { if(res->allocsize - res->size < sizeof(DWORD)) grow_res(res, RES_BLOCKSIZE); *(DWORD *)&(res->data[res->size]) = (DWORD)d; res->size += sizeof(DWORD); } void put_pad(res_t *res) { while(res->size & 0x3) put_byte(res, 0); } /* ***************************************************************************** * Function : string_to_upper * Syntax : void string_to_upper(string_t *str) * Input : * Output : * Description : * Remarks : FIXME: codepages... ***************************************************************************** */ void string_to_upper(string_t *str) { if(str->type == str_char) { char *cptr = str->str.cstr; for(; *cptr; cptr++) *cptr = (char)toupper(*cptr); } else if(str->type == str_unicode) { short *sptr = str->str.wstr; for(; *sptr; sptr++) if(isalpha(*sptr)) *sptr = (short)toupper(*sptr); } else { internal_error(__FILE__, __LINE__, "Invalid string type %d", str->type); } } /* ***************************************************************************** * Function : put_string * Syntax : void put_string(res_t *res, string_t *str, enum str_e type, * int isterm) * Input : * res - Binary resource to put the data in * str - String to put * type - Data has to be written in either str_char or str_unicode * isterm - The string is '\0' terminated (disregard the string's * size member) * Output : nop * Description : * Remarks : ***************************************************************************** */ void put_string(res_t *res, string_t *str, enum str_e type, int isterm) { int cnt; int c = !0; assert(res != NULL); assert(str != NULL); if(!isterm && str->size == 0) { warning("String length is zero, not written"); return; } if(str->type == str_unicode && type == str_unicode) { for(cnt = 0; cnt < str->size; cnt++) { c = str->str.wstr[cnt]; put_word(res, c); if(isterm && !c) break; } if(isterm && (str->size == 0 || (cnt == str->size && c))) put_word(res, 0); } else if(str->type == str_char && type == str_char) { for(cnt = 0; cnt < str->size; cnt++) { c = str->str.cstr[cnt]; put_byte(res, c); if(isterm && !c) break; } if(isterm && (str->size == 0 || (cnt == str->size && c))) put_byte(res, 0); } else if(str->type == str_unicode && type == str_char) { for(cnt = 0; cnt < str->size; cnt++) { c = str->str.wstr[cnt]; put_byte(res, c); if(isterm && !c) break; } if(isterm && (str->size == 0 || (cnt == str->size && c))) put_byte(res, 0); } else /* str->type == str_char && type == str_unicode */ { for(cnt = 0; cnt < str->size; cnt++) { c = str->str.cstr[cnt]; put_word(res, c & 0xff); if(isterm && !c) break; } if(isterm && (str->size == 0 || (cnt == str->size && c))) put_word(res, 0); } } /* ***************************************************************************** * Function : put_name_id * Syntax : void put_name_id(res_t *res, name_id_t *nid, int upcase) * Input : * Output : * Description : * Remarks : ***************************************************************************** */ void put_name_id(res_t *res, name_id_t *nid, int upcase) { if(nid->type == name_ord) { if(win32) put_word(res, 0xffff); else put_byte(res, 0xff); put_word(res, (WORD)nid->name.i_name); } else if(nid->type == name_str) { if(upcase) string_to_upper(nid->name.s_name); put_string(res, nid->name.s_name, win32 ? str_unicode : str_char, TRUE); } else { internal_error(__FILE__, __LINE__, "Invalid name_id type %d", nid->type); } } /* ***************************************************************************** * Function : put_lvc * Syntax : void put_lvc(res_t *res, lvc_t *lvc) * Input : * Output : * Description : * Remarks : ***************************************************************************** */ void put_lvc(res_t *res, lvc_t *lvc) { if(lvc && lvc->language) put_word(res, MAKELANGID(lvc->language->id, lvc->language->sub)); else put_word(res, 0); /* Neutral */ if(lvc && lvc->version) put_dword(res, *(lvc->version)); else put_dword(res, 0); if(lvc && lvc->characts) put_dword(res, *(lvc->characts)); else put_dword(res, 0); } /* ***************************************************************************** * Function : put_raw_data * Syntax : void put_raw_data(res_t *res, raw_data_t *raw, int offset) * Input : * Output : * Description : * Remarks : ***************************************************************************** */ void put_raw_data(res_t *res, raw_data_t *raw, int offset) { int wsize = raw->size - offset; if(res->allocsize - res->size < wsize) grow_res(res, wsize); memcpy(&(res->data[res->size]), raw->data + offset, wsize); res->size += wsize; } /* ***************************************************************************** * Function : put_res_header * Syntax : intput_res_header(res_t *res, int type, name_id_t *ntype, * name_id_t *name, DWORD memopt, lvc_t *lvc) * * Input : * res - Binary resource descriptor to write to * type - Resource identifier (if ntype == NULL) * ntype - Name id of type * name - Resource's name * memopt - Resource's memory options to write * lvc - Language, version and characteristics (win32 only) * Output : An index to the resource size field. The resource size field * contains the header size upon exit. * Description : * Remarks : ***************************************************************************** */ int put_res_header(res_t *res, int type, name_id_t *ntype, name_id_t *name, DWORD memopt, lvc_t *lvc) { if(win32) { put_dword(res, 0); /* We will overwrite these later */ put_dword(res, 0); if(!ntype) { put_word(res, 0xffff); /* ResType */ put_word(res, type); } else put_name_id(res, ntype, TRUE); put_name_id(res, name, TRUE); /* ResName */ put_pad(res); put_dword(res, 0); /* DataVersion */ put_word(res, memopt); /* Memory options */ put_lvc(res, lvc); /* Language, version and characts */ ((DWORD *)res->data)[0] = res->size; /* Set preliminary resource */ ((DWORD *)res->data)[1] = res->size; /* Set HeaderSize */ res->dataidx = res->size; return 0; } else /* win16 */ { int tag; if(!ntype) { put_byte(res, 0xff); /* ResType */ put_word(res, type); } else put_name_id(res, ntype, TRUE); put_name_id(res, name, TRUE); /* ResName */ put_word(res, memopt); /* Memory options */ tag = res->size; put_dword(res, 0); /* ResSize overwritten later*/ *(DWORD *)&(res->data[tag]) = res->size; res->dataidx = res->size; return tag; } } /* ***************************************************************************** * Function : accelerator2res * Syntax : res_t *accelerator2res(name_id_t *name, accelerator_t *acc) * Input : * name - Name/ordinal of the resource * acc - The accelerator descriptor * Output : New .res format structure * Description : * Remarks : ***************************************************************************** */ res_t *accelerator2res(name_id_t *name, accelerator_t *acc) { int restag; res_t *res; event_t *ev; assert(name != NULL); assert(acc != NULL); ev = acc->events; res = new_res(); if(win32) { restag = put_res_header(res, WRC_RT_ACCELERATOR, NULL, name, acc->memopt, &(acc->lvc)); while(ev) { put_word(res, ev->flags | (ev->next ? 0 : 0x80)); put_word(res, ev->key); put_word(res, ev->id); put_word(res, 0); /* Padding */ ev = ev->next; } put_pad(res); } else /* win16 */ { restag = put_res_header(res, WRC_RT_ACCELERATOR, NULL, name, acc->memopt, NULL); while(ev) { put_byte(res, ev->flags | (ev->next ? 0 : 0x80)); put_word(res, ev->key); put_word(res, ev->id); ev = ev->next; } } /* Set ResourceSize */ SetResSize(res, restag); return res; } /* ***************************************************************************** * Function : dialog2res * Syntax : res_t *dialog2res(name_id_t *name, dialog_t *dlg) * Input : * name - Name/ordinal of the resource * dlg - The dialog descriptor * Output : New .res format structure * Description : * Remarks : ***************************************************************************** */ res_t *dialog2res(name_id_t *name, dialog_t *dlg) { int restag; res_t *res; control_t *ctrl; int tag_nctrl; int nctrl = 0; assert(name != NULL); assert(dlg != NULL); ctrl = dlg->controls; res = new_res(); if(win32) { restag = put_res_header(res, WRC_RT_DIALOG, NULL, name, dlg->memopt, &(dlg->lvc)); put_dword(res, dlg->style); put_dword(res, dlg->gotexstyle ? dlg->exstyle : 0); tag_nctrl = res->size; put_word(res, 0); /* Number of controls */ put_word(res, dlg->x); put_word(res, dlg->y); put_word(res, dlg->width); put_word(res, dlg->height); if(dlg->menu) put_name_id(res, dlg->menu, TRUE); else put_word(res, 0); if(dlg->dlgclass) put_name_id(res, dlg->dlgclass, TRUE); else put_word(res, 0); if(dlg->title) put_string(res, dlg->title, str_unicode, TRUE); else put_word(res, 0); if(dlg->font) { put_word(res, dlg->font->size); put_string(res, dlg->font->name, str_unicode, TRUE); } put_pad(res); while(ctrl) { /* FIXME: what is default control style? */ put_dword(res, ctrl->gotstyle ? ctrl->style : WS_CHILD); put_dword(res, ctrl->gotexstyle ? ctrl->exstyle : 0); put_word(res, ctrl->x); put_word(res, ctrl->y); put_word(res, ctrl->width); put_word(res, ctrl->height); put_word(res, ctrl->id); if(ctrl->ctlclass) put_name_id(res, ctrl->ctlclass, TRUE); else internal_error(__FILE__, __LINE__, "Control has no control-class"); if(ctrl->title) put_string(res, ctrl->title, str_unicode, TRUE); else put_word(res, 0); if(ctrl->extra) { put_word(res, ctrl->extra->size+2); put_pad(res); put_raw_data(res, ctrl->extra, 0); } else put_word(res, 0); if(ctrl->next) put_pad(res); nctrl++; ctrl = ctrl->next; } /* Set number of controls */ *(WORD *)&((char *)res->data)[tag_nctrl] = (WORD)nctrl; } else /* win16 */ { restag = put_res_header(res, WRC_RT_DIALOG, NULL, name, dlg->memopt, NULL); put_dword(res, dlg->gotstyle ? dlg->style : WS_POPUPWINDOW); tag_nctrl = res->size; put_byte(res, 0); /* Number of controls */ put_word(res, dlg->x); put_word(res, dlg->y); put_word(res, dlg->width); put_word(res, dlg->height); if(dlg->menu) put_name_id(res, dlg->menu, TRUE); else put_byte(res, 0); if(dlg->dlgclass) put_name_id(res, dlg->dlgclass, TRUE); else put_byte(res, 0); if(dlg->title) put_string(res, dlg->title, str_char, TRUE); else put_byte(res, 0); if(dlg->font) { put_word(res, dlg->font->size); put_string(res, dlg->font->name, str_char, TRUE); } while(ctrl) { put_word(res, ctrl->x); put_word(res, ctrl->y); put_word(res, ctrl->width); put_word(res, ctrl->height); put_word(res, ctrl->id); put_dword(res, ctrl->gotstyle ? ctrl->style : WS_CHILD); if(ctrl->ctlclass) { if(ctrl->ctlclass->type == name_ord && ctrl->ctlclass->name.i_name >= 0x80 && ctrl->ctlclass->name.i_name <= 0x85) put_byte(res, ctrl->ctlclass->name.i_name); else if(ctrl->ctlclass->type == name_str) put_name_id(res, ctrl->ctlclass, FALSE); else error("Unknown control-class %04x", ctrl->ctlclass->name.i_name); } else internal_error(__FILE__, __LINE__, "Control has no control-class"); if(ctrl->title) put_string(res, ctrl->title, str_char, TRUE); else put_byte(res, 0); /* FIXME: What is this extra byte doing here? */ put_byte(res, 0); nctrl++; ctrl = ctrl->next; } /* Set number of controls */ ((char *)res->data)[tag_nctrl] = (char)nctrl; } /* Set ResourceSize */ SetResSize(res, restag); return res; } /* ***************************************************************************** * Function : dialogex2res * Syntax : res_t *dialogex2res(name_id_t *name, dialogex_t *dlgex) * Input : * name - Name/ordinal of the resource * dlgex - The dialogex descriptor * Output : New .res format structure * Description : * Remarks : ***************************************************************************** */ res_t *dialogex2res(name_id_t *name, dialogex_t *dlgex) { int restag; res_t *res; control_t *ctrl; int tag_nctrl; int nctrl = 0; assert(name != NULL); assert(dlgex != NULL); ctrl = dlgex->controls; res = new_res(); if(win32) { restag = put_res_header(res, WRC_RT_DIALOG, NULL, name, dlgex->memopt, &(dlgex->lvc)); /* FIXME: MS doc says thet the first word must contain 0xffff * and the second 0x0001 to signal a DLGTEMPLATEEX. Borland's * compiler reverses the two words. * I don't know which one to choose, but I write it as Mr. B * writes it. */ put_word(res, 1); /* Signature */ put_word(res, 0xffff); /* DlgVer */ put_dword(res, dlgex->gothelpid ? dlgex->helpid : 0); put_dword(res, dlgex->gotexstyle ? dlgex->exstyle : 0); put_dword(res, dlgex->gotstyle ? dlgex->style : WS_POPUPWINDOW); tag_nctrl = res->size; put_word(res, 0); /* Number of controls */ put_word(res, dlgex->x); put_word(res, dlgex->y); put_word(res, dlgex->width); put_word(res, dlgex->height); if(dlgex->menu) put_name_id(res, dlgex->menu, TRUE); else put_word(res, 0); if(dlgex->dlgclass) put_name_id(res, dlgex->dlgclass, TRUE); else put_word(res, 0); if(dlgex->title) put_string(res, dlgex->title, str_unicode, TRUE); else put_word(res, 0); if(dlgex->font) { put_word(res, dlgex->font->size); put_word(res, dlgex->font->weight); /* FIXME: ? TRUE should be sufficient to say that its * italic, but Borland's compiler says its 0x0101. * I just copy it here, and hope for the best. */ put_word(res, dlgex->font->italic ? 0x0101 : 0); put_string(res, dlgex->font->name, str_unicode, TRUE); } put_pad(res); while(ctrl) { put_dword(res, ctrl->gothelpid ? ctrl->helpid : 0); put_dword(res, ctrl->gotexstyle ? ctrl->exstyle : 0); /* FIXME: what is default control style? */ put_dword(res, ctrl->gotstyle ? ctrl->style : WS_CHILD | WS_VISIBLE); put_word(res, ctrl->x); put_word(res, ctrl->y); put_word(res, ctrl->width); put_word(res, ctrl->height); put_word(res, ctrl->id); /* FIXME: Pad is _NOT_ documented!?! */ put_pad(res); if(ctrl->ctlclass) put_name_id(res, ctrl->ctlclass, TRUE); else internal_error(__FILE__, __LINE__, "Control has no control-class"); if(ctrl->title) put_string(res, ctrl->title, str_unicode, TRUE); else put_word(res, 0); if(ctrl->extra) { put_pad(res); put_word(res, ctrl->extra->size); put_raw_data(res, ctrl->extra, 0); } else put_word(res, 0); put_pad(res); nctrl++; ctrl = ctrl->next; } /* Set number of controls */ *(WORD *)&((char *)res->data)[tag_nctrl] = (WORD)nctrl; /* Set ResourceSize */ SetResSize(res, restag); put_pad(res); } else /* win16 */ { /* Do not generate anything in 16-bit mode */ free(res->data); free(res); return NULL; } return res; } /* ***************************************************************************** * Function : menuitem2res * Syntax : void menuitem2res(res_t *res, menu_item_t *item) * Input : * Output : * Description : * Remarks : Self recursive ***************************************************************************** */ void menuitem2res(res_t *res, menu_item_t *menitem) { menu_item_t *itm = menitem; if(win32) { while(itm) { put_word(res, itm->state | (itm->popup ? MF_POPUP : 0) | (!itm->next ? MF_END : 0)); if(!itm->popup) put_word(res, itm->id); if(itm->name) put_string(res, itm->name, str_unicode, TRUE); else put_word(res, 0); if(itm->popup) menuitem2res(res, itm->popup); itm = itm->next; } } else /* win16 */ { while(itm) { put_word(res, itm->state | (itm->popup ? MF_POPUP : 0) | (!itm->next ? MF_END : 0)); if(!itm->popup) put_word(res, itm->id); if(itm->name) put_string(res, itm->name, str_char, TRUE); else put_byte(res, 0); if(itm->popup) menuitem2res(res, itm->popup); itm = itm->next; } } } /* ***************************************************************************** * Function : menu2res * Syntax : res_t *menu2res(name_id_t *name, menu_t *men) * Input : * name - Name/ordinal of the resource * men - The menu descriptor * Output : New .res format structure * Description : * Remarks : ***************************************************************************** */ res_t *menu2res(name_id_t *name, menu_t *men) { int restag; res_t *res; assert(name != NULL); assert(men != NULL); res = new_res(); restag = put_res_header(res, WRC_RT_MENU, NULL, name, men->memopt, win32 ? &(men->lvc) : NULL); put_dword(res, 0); /* Menuheader: Version and HeaderSize */ menuitem2res(res, men->items); /* Set ResourceSize */ SetResSize(res, restag); if(win32) put_pad(res); return res; } /* ***************************************************************************** * Function : menuexitem2res * Syntax : void menuexitem2res(res_t *res, menuex_item_t *item) * Input : * Output : nop * Description : * Remarks : Self recursive ***************************************************************************** */ void menuexitem2res(res_t *res, menuex_item_t *menitem) { menuex_item_t *itm = menitem; assert(win32 != 0); while(itm) { put_dword(res, itm->gottype ? itm->type : 0); put_dword(res, itm->gotstate ? itm->state : 0); put_dword(res, itm->gotid ? itm->id : 0); /* FIXME: Docu. says word */ put_word(res, (itm->popup ? 0x01 : 0) | (!itm->next ? MF_END : 0)); if(itm->name) put_string(res, itm->name, str_unicode, TRUE); else put_word(res, 0); put_pad(res); if(itm->popup) { put_dword(res, itm->gothelpid ? itm->helpid : 0); menuexitem2res(res, itm->popup); } itm = itm->next; } } /* ***************************************************************************** * Function : menuex2res * Syntax : res_t *menuex2res(name_id_t *name, menuex_t *menex) * Input : * name - Name/ordinal of the resource * menex - The menuex descriptor * Output : New .res format structure * Description : * Remarks : ***************************************************************************** */ res_t *menuex2res(name_id_t *name, menuex_t *menex) { int restag; res_t *res; assert(name != NULL); assert(menex != NULL); res = new_res(); if(win32) { restag = put_res_header(res, WRC_RT_MENU, NULL, name, menex->memopt, &(menex->lvc)); put_word(res, 1); /* Menuheader: Version */ put_word(res, 4); /* Offset */ put_dword(res, 0); /* HelpId */ put_pad(res); menuexitem2res(res, menex->items); /* Set ResourceSize */ SetResSize(res, restag); put_pad(res); } else /* win16 */ { /* Do not generate anything in 16-bit mode */ free(res->data); free(res); return NULL; } return res; } /* ***************************************************************************** * Function : cursorgroup2res * Syntax : res_t *cursorgroup2res(name_id_t *name, cursor_group_t *curg) * Input : * name - Name/ordinal of the resource * curg - The cursor descriptor * Output : New .res format structure * Description : * Remarks : ***************************************************************************** */ res_t *cursorgroup2res(name_id_t *name, cursor_group_t *curg) { int restag; res_t *res; cursor_t *cur; assert(name != NULL); assert(curg != NULL); res = new_res(); restag = put_res_header(res, WRC_RT_GROUP_CURSOR, NULL, name, curg->memopt, &(curg->lvc)); if(win32) { put_word(res, 0); /* Reserved */ /* FIXME: The ResType in the NEWHEADER structure should * contain 14 according to the MS win32 doc. This is * not the case with the BRC compiler and I really doubt * the latter. Putting one here is compliant to win16 spec, * but who knows the true value? */ put_word(res, 2); /* ResType */ put_word(res, curg->ncursor); #if 0 for(cur = curg->cursorlist; cur; cur = cur->next) #else cur = curg->cursorlist; while(cur->next) cur = cur->next; for(; cur; cur = cur->prev) #endif { put_word(res, cur->width); /* FIXME: The height of a cursor is half the size of * the bitmap's height. BRC puts the height from the * BITMAPINFOHEADER here instead of the cursorfile's * height. MS doesn't seem to care... */ put_word(res, cur->height); /* FIXME: The next two are reversed in BRC and I don't * know why. Probably a bug. But, we can safely ignore * it because win16 does not support color cursors. * A warning should have been generated by the parser. */ put_word(res, cur->planes); put_word(res, cur->bits); /* FIXME: The +4 is the hotspot in the cursor resource. * However, I cound not find this in the documentation. * The hotspot bytes must either be included or MS * doesn't care. */ put_dword(res, cur->data->size +4); put_word(res, cur->id); } } else /* win16 */ { put_word(res, 0); /* Reserved */ put_word(res, 2); /* ResType */ put_word(res, curg->ncursor); #if 0 for(cur = curg->cursorlist; cur; cur = cur->next) #else cur = curg->cursorlist; while(cur->next) cur = cur->next; for(; cur; cur = cur->prev) #endif { put_word(res, cur->width); /* FIXME: The height of a cursor is half the size of * the bitmap's height. BRC puts the height from the * BITMAPINFOHEADER here instead of the cursorfile's * height. MS doesn't seem to care... */ put_word(res, cur->height); /* FIXME: The next two are reversed in BRC and I don't * know why. Probably a bug. But, we can safely ignore * it because win16 does not support color cursors. * A warning should have been generated by the parser. */ put_word(res, cur->planes); put_word(res, cur->bits); /* FIXME: The +4 is the hotspot in the cursor resource. * However, I cound not find this in the documentation. * The hotspot bytes must either be included or MS * doesn't care. */ put_dword(res, cur->data->size +4); put_word(res, cur->id); } } SetResSize(res, restag); /* Set ResourceSize */ if(win32) put_pad(res); return res; } /* ***************************************************************************** * Function : cursor2res * Syntax : res_t *cursor2res(cursor_t *cur) * Input : * cur - The cursor descriptor * Output : New .res format structure * Description : * Remarks : ***************************************************************************** */ res_t *cursor2res(cursor_t *cur) { int restag; res_t *res; name_id_t name; assert(cur != NULL); res = new_res(); name.type = name_ord; name.name.i_name = cur->id; restag = put_res_header(res, WRC_RT_CURSOR, NULL, &name, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE, &(cur->lvc)); put_word(res, cur->xhot); put_word(res, cur->yhot); put_raw_data(res, cur->data, 0); SetResSize(res, restag); /* Set ResourceSize */ if(win32) put_pad(res); return res; } /* ***************************************************************************** * Function : icongroup2res * Syntax : res_t *icongroup2res(name_id_t *name, icon_group_t *icog) * Input : * name - Name/ordinal of the resource * icog - The icon group descriptor * Output : New .res format structure * Description : * Remarks : ***************************************************************************** */ res_t *icongroup2res(name_id_t *name, icon_group_t *icog) { int restag; res_t *res; icon_t *ico; assert(name != NULL); assert(icog != NULL); res = new_res(); restag = put_res_header(res, WRC_RT_GROUP_ICON, NULL, name, icog->memopt, &(icog->lvc)); if(win32) { put_word(res, 0); /* Reserved */ /* FIXME: The ResType in the NEWHEADER structure should * contain 14 according to the MS win32 doc. This is * not the case with the BRC compiler and I really doubt * the latter. Putting one here is compliant to win16 spec, * but who knows the true value? */ put_word(res, 1); /* ResType */ put_word(res, icog->nicon); for(ico = icog->iconlist; ico; ico = ico->next) { put_byte(res, ico->width); put_byte(res, ico->height); put_byte(res, ico->nclr); put_byte(res, 0); /* Reserved */ put_word(res, ico->planes); put_word(res, ico->bits); put_dword(res, ico->data->size); put_word(res, ico->id); } } else /* win16 */ { put_word(res, 0); /* Reserved */ put_word(res, 1); /* ResType */ put_word(res, icog->nicon); for(ico = icog->iconlist; ico; ico = ico->next) { put_byte(res, ico->width); put_byte(res, ico->height); put_byte(res, ico->nclr); put_byte(res, 0); /* Reserved */ put_word(res, ico->planes); put_word(res, ico->bits); put_dword(res, ico->data->size); put_word(res, ico->id); } } SetResSize(res, restag); /* Set ResourceSize */ if(win32) put_pad(res); return res; } /* ***************************************************************************** * Function : icon2res * Syntax : res_t *icon2res(icon_t *ico) * Input : * ico - The icon descriptor * Output : New .res format structure * Description : * Remarks : ***************************************************************************** */ res_t *icon2res(icon_t *ico) { int restag; res_t *res; name_id_t name; assert(ico != NULL); res = new_res(); name.type = name_ord; name.name.i_name = ico->id; restag = put_res_header(res, WRC_RT_ICON, NULL, &name, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE, &(ico->lvc)); put_raw_data(res, ico->data, 0); SetResSize(res, restag); /* Set ResourceSize */ if(win32) put_pad(res); return res; } /* ***************************************************************************** * Function : bitmap2res * Syntax : res_t *bitmap2res(name_id_t *name, bitmap_t *bmp) * Input : * name - Name/ordinal of the resource * bmp - The bitmap descriptor * Output : New .res format structure * Description : * Remarks : ***************************************************************************** */ res_t *bitmap2res(name_id_t *name, bitmap_t *bmp) { int restag; res_t *res; assert(name != NULL); assert(bmp != NULL); HEAPCHECK(); res = new_res(); HEAPCHECK(); restag = put_res_header(res, WRC_RT_BITMAP, NULL, name, bmp->memopt, NULL); HEAPCHECK(); if(bmp->data->data[0] == 'B' && bmp->data->data[1] == 'M' && ((BITMAPFILEHEADER *)bmp->data->data)->bfSize == bmp->data->size && bmp->data->size >= sizeof(BITMAPFILEHEADER)) { /* The File header is still attached, don't write it */ put_raw_data(res, bmp->data, sizeof(BITMAPFILEHEADER)); } else { put_raw_data(res, bmp->data, 0); } HEAPCHECK(); /* Set ResourceSize */ SetResSize(res, restag); HEAPCHECK(); if(win32) put_pad(res); HEAPCHECK(); return res; } /* ***************************************************************************** * Function : font2res * Syntax : res_t *font2res(name_id_t *name, font_t *fnt) * Input : * name - Name/ordinal of the resource * fnt - The font descriptor * Output : New .res format structure * Description : * Remarks : ***************************************************************************** */ res_t *font2res(name_id_t *name, font_t *fnt) { assert(name != NULL); assert(fnt != NULL); warning("Fonts not yet implemented"); return NULL; } /* ***************************************************************************** * Function : rcdata2res * Syntax : res_t *rcdata2res(name_id_t *name, rcdata_t *rdt) * Input : * name - Name/ordinal of the resource * rdt - The rcdata descriptor * Output : New .res format structure * Description : * Remarks : ***************************************************************************** */ res_t *rcdata2res(name_id_t *name, rcdata_t *rdt) { int restag; res_t *res; assert(name != NULL); assert(rdt != NULL); res = new_res(); restag = put_res_header(res, WRC_RT_RCDATA, NULL, name, rdt->memopt, NULL); put_raw_data(res, rdt->data, 0); /* Set ResourceSize */ SetResSize(res, restag); if(win32) put_pad(res); return res; } /* ***************************************************************************** * Function : messagetable2res * Syntax : res_t *messagetable2res(name_id_t *name, messagetable_t *msg) * Input : * name - Name/ordinal of the resource * msg - The messagetable descriptor * Output : New .res format structure * Description : * Remarks : ***************************************************************************** */ res_t *messagetable2res(name_id_t *name, messagetable_t *msg) { assert(name != NULL); assert(msg != NULL); warning("Messagetable not yet implemented"); return NULL; } /* ***************************************************************************** * Function : stringtable2res * Syntax : res_t *stringtable2res(stringtable_t *stt) * Input : * stt - The stringtable descriptor * Output : New .res format structure * Description : * Remarks : ***************************************************************************** */ res_t *stringtable2res(stringtable_t *stt) { res_t *res; name_id_t name; int i; int restag; DWORD lastsize = 0; assert(stt != NULL); res = new_res(); for(; stt; stt = stt->next) { if(!stt->nentries) { warning("Empty internal stringtable"); continue; } name.type = name_ord; name.name.i_name = (stt->idbase >> 4) + 1; restag = put_res_header(res, WRC_RT_STRING, NULL, &name, stt->memopt, win32 ? &(stt->lvc) : NULL); for(i = 0; i < stt->nentries; i++) { if(stt->entries[i].str) { if(win32) put_word(res, stt->entries[i].str->size); else put_byte(res, stt->entries[i].str->size); put_string(res, stt->entries[i].str, win32 ? str_unicode : str_char, FALSE); } else { if(win32) put_word(res, 0); else put_byte(res, 0); } } /* Set ResourceSize */ SetResSize(res, restag - lastsize); if(win32) put_pad(res); lastsize = res->size; } return res; } /* ***************************************************************************** * Function : user2res * Syntax : res_t *user2res(name_id_t *name, user_t *usr) * Input : * name - Name/ordinal of the resource * usr - The userresource descriptor * Output : New .res format structure * Description : * Remarks : ***************************************************************************** */ res_t *user2res(name_id_t *name, user_t *usr) { int restag; res_t *res; assert(name != NULL); assert(usr != NULL); res = new_res(); restag = put_res_header(res, 0, usr->type, name, usr->memopt, NULL); put_raw_data(res, usr->data, 0); /* Set ResourceSize */ SetResSize(res, restag); if(win32) put_pad(res); return res; } /* ***************************************************************************** * Function : versionblock2res * Syntax : void versionblock2res(res_t *res, ver_block_t *blk) * Input : * res - Binary resource to write to * blk - The version block to be written * Output : * Description : * Remarks : Self recursive ***************************************************************************** */ void versionblock2res(res_t *res, ver_block_t *blk, int level) { ver_value_t *val; int blksizetag; int valblksizetag; int valvalsizetag; int tag; int i; blksizetag = res->size; put_word(res, 0); /* Will be overwritten later */ put_word(res, 0); if(win32) put_word(res, 0); /* level ? */ put_string(res, blk->name, win32 ? str_unicode : str_char, TRUE); put_pad(res); for(val = blk->values; val; val = val->next) { if(val->type == val_str) { valblksizetag = res->size; put_word(res, 0); /* Will be overwritten later */ valvalsizetag = res->size; put_word(res, 0); /* Will be overwritten later */ if(win32) { put_word(res, level); } put_string(res, val->key, win32 ? str_unicode : str_char, TRUE); put_pad(res); tag = res->size; put_string(res, val->value.str, win32 ? str_unicode : str_char, TRUE); if(win32) *(WORD *)&(res->data[valvalsizetag]) = (WORD)((res->size - tag) >> 1); else *(WORD *)&(res->data[valvalsizetag]) = (WORD)(res->size - tag); *(WORD *)&(res->data[valblksizetag]) = (WORD)(res->size - valblksizetag); put_pad(res); } else if(val->type == val_words) { valblksizetag = res->size; put_word(res, 0); /* Will be overwritten later */ valvalsizetag = res->size; put_word(res, 0); /* Will be overwritten later */ if(win32) { put_word(res, level); } put_string(res, val->key, win32 ? str_unicode : str_char, TRUE); put_pad(res); tag = res->size; for(i = 0; i < val->value.words->nwords; i++) { put_word(res, val->value.words->words[i]); } *(WORD *)&(res->data[valvalsizetag]) = (WORD)(res->size - tag); *(WORD *)&(res->data[valblksizetag]) = (WORD)(res->size - valblksizetag); put_pad(res); } else if(val->type == val_block) { versionblock2res(res, val->value.block, level+1); } else { internal_error(__FILE__, __LINE__, "Invalid value indicator %d in VERSIONINFO", val->type); } } /* Set blocksize */ *(WORD *)&(res->data[blksizetag]) = (WORD)(res->size - blksizetag); } /* ***************************************************************************** * Function : versioninfo2res * Syntax : res_t *versioninfo2res(name_id_t *name, versioninfo_t *ver) * Input : * name - Name/ordinal of the resource * ver - The versioninfo descriptor * Output : New .res format structure * Description : * Remarks : ***************************************************************************** */ res_t *versioninfo2res(name_id_t *name, versioninfo_t *ver) { int restag; int rootblocksizetag; int valsizetag; int tag; res_t *res; string_t vsvi; ver_block_t *blk; assert(name != NULL); assert(ver != NULL); vsvi.type = str_char; vsvi.str.cstr = "VS_VERSION_INFO"; vsvi.size = 15; /* Excl. termination */ res = new_res(); restag = put_res_header(res, WRC_RT_VERSION, NULL, name, WRC_MO_MOVEABLE | WRC_MO_PURE, NULL); rootblocksizetag = res->size; put_word(res, 0); /* BlockSize filled in later */ valsizetag = res->size; put_word(res, 0); /* ValueSize filled in later*/ if(win32) put_word(res, 0); /* Tree-level ? */ put_string(res, &vsvi, win32 ? str_unicode : str_char, TRUE); if(win32) put_pad(res); tag = res->size; put_dword(res, VS_FFI_SIGNATURE); put_dword(res, VS_FFI_STRUCVERSION); put_dword(res, (ver->filever_maj1 << 16) + (ver->filever_maj2 & 0xffff)); put_dword(res, (ver->filever_min1 << 16) + (ver->filever_min2 & 0xffff)); put_dword(res, (ver->prodver_maj1 << 16) + (ver->prodver_maj2 & 0xffff)); put_dword(res, (ver->prodver_min1 << 16) + (ver->prodver_min2 & 0xffff)); put_dword(res, ver->fileflagsmask); put_dword(res, ver->fileflags); put_dword(res, ver->fileos); put_dword(res, ver->filetype); put_dword(res, ver->filesubtype); put_dword(res, 0); /* FileDateMS */ put_dword(res, 0); /* FileDateLS */ /* Set ValueSize */ *(WORD *)&(res->data[valsizetag]) = (WORD)(res->size - tag); /* Descend into the blocks */ for(blk = ver->blocks; blk; blk = blk->next) versionblock2res(res, blk, 0); /* Set root block's size */ *(WORD *)&(res->data[rootblocksizetag]) = (WORD)(res->size - rootblocksizetag); SetResSize(res, restag); if(win32) put_pad(res); return res; } /* ***************************************************************************** * Function : prep_nid_for_label * Syntax : char *prep_nid_for_label(name_id_t *nid) * Input : * Output : * Description : Converts a resource name into the first 32 (or less) * characters of the name with conversions. * Remarks : ***************************************************************************** */ #define MAXNAMELEN 32 char *prep_nid_for_label(name_id_t *nid) { static char buf[MAXNAMELEN+1]; assert(nid != NULL); if(nid->type == name_str && nid->name.s_name->type == str_unicode) { short *sptr; int i; sptr = nid->name.s_name->str.wstr; buf[0] = '\0'; for(i = 0; *sptr && i < MAXNAMELEN; i++) { if((unsigned)*sptr < 0x80 && isprint((char)*sptr)) buf[i] = *sptr++; else warning("Resourcename (str_unicode) contain unprintable characters or invalid translation, ignored"); } buf[i] = '\0'; } else if(nid->type == name_str && nid->name.s_name->type == str_char) { char *cptr; int i; cptr = nid->name.s_name->str.cstr; buf[0] = '\0'; for(i = 0; *cptr && i < MAXNAMELEN; i++) { if((unsigned)*cptr < 0x80 && isprint(*cptr)) buf[i] = *cptr++; else warning("Resourcename (str_char) contain unprintable characters, ignored"); } buf[i] = '\0'; } else if(nid->type == name_ord) { sprintf(buf, "%u", nid->name.i_name); } else { internal_error(__FILE__, __LINE__, "Resource name_id with invalid type %d", nid->type); } return buf; } #undef MAXNAMELEN /* ***************************************************************************** * Function : make_c_name * Syntax : char *make_c_name(char *base, name_id_t *nid, language_t *lan) * Input : * Output : * Description : Converts a resource name into a valid c-identifier in the * form "_base_nid". * Remarks : ***************************************************************************** */ char *make_c_name(char *base, name_id_t *nid, language_t *lan) { int nlen; char *buf; char *ret; char lanbuf[6]; sprintf(lanbuf, "%d", lan ? MAKELANGID(lan->id, lan->sub) : 0); buf = prep_nid_for_label(nid); nlen = strlen(buf) + strlen(lanbuf); nlen += strlen(base) + 4; /* three time '_' and '\0' */ ret = (char *)xmalloc(nlen); strcpy(ret, "_"); strcat(ret, base); strcat(ret, "_"); strcat(ret, buf); strcat(ret, "_"); strcat(ret, lanbuf); return ret; } /* ***************************************************************************** * Function : get_c_typename * Syntax : char *get_c_typename(enum res_e type) * Input : * Output : * Description : Convert resource enum to char string to be used in c-name * creation. * Remarks : ***************************************************************************** */ char *get_c_typename(enum res_e type) { switch(type) { case res_acc: return "Acc"; case res_bmp: return "Bmp"; case res_cur: return "Cur"; case res_curg: return "CurGrp"; case res_dlg: case res_dlgex: return "Dlg"; case res_fnt: return "Fnt"; case res_ico: return "Ico"; case res_icog: return "IcoGrp"; case res_men: case res_menex: return "Men"; case res_rdt: return "RCDat"; case res_stt: return "StrTab"; case res_usr: return "Usr"; case res_msg: return "MsgTab"; case res_ver: return "VerInf"; default: return "Oops"; } } /* ***************************************************************************** * Function : resources2res * Syntax : void resources2res(resource_t *top) * Input : * top - The resource-tree to convert * Output : * Description : Convert logical resource descriptors into binary data * Remarks : ***************************************************************************** */ void resources2res(resource_t *top) { while(top) { switch(top->type) { case res_acc: if(!top->binres) top->binres = accelerator2res(top->name, top->res.acc); break; case res_bmp: if(!top->binres) top->binres = bitmap2res(top->name, top->res.bmp); break; case res_cur: if(!top->binres) top->binres = cursor2res(top->res.cur); break; case res_curg: if(!top->binres) top->binres = cursorgroup2res(top->name, top->res.curg); break; case res_dlg: if(!top->binres) top->binres = dialog2res(top->name, top->res.dlg); break; case res_dlgex: if(!top->binres) top->binres = dialogex2res(top->name, top->res.dlgex); break; case res_fnt: if(!top->binres) top->binres = font2res(top->name, top->res.fnt); break; case res_ico: if(!top->binres) top->binres = icon2res(top->res.ico); break; case res_icog: if(!top->binres) top->binres = icongroup2res(top->name, top->res.icog); break; case res_men: if(!top->binres) top->binres = menu2res(top->name, top->res.men); break; case res_menex: if(!top->binres) top->binres = menuex2res(top->name, top->res.menex); break; case res_rdt: if(!top->binres) top->binres = rcdata2res(top->name, top->res.rdt); break; case res_stt: if(!top->binres) top->binres = stringtable2res(top->res.stt); break; case res_usr: if(!top->binres) top->binres = user2res(top->name, top->res.usr); break; case res_msg: if(!top->binres) top->binres = messagetable2res(top->name, top->res.msg); break; case res_ver: if(!top->binres) top->binres = versioninfo2res(top->name, top->res.ver); break; default: internal_error(__FILE__, __LINE__, "Unknown resource type encountered %d in binary res generation", top->type); } top->c_name = make_c_name(get_c_typename(top->type), top->name, top->lan); top = top->next; } }