(linenum→info "unix/slp.c:2238")

binutils/2.18/binutils/resbin.c

    1: /* resbin.c -- manipulate the Windows binary resource format.
    2:    Copyright 1997, 1998, 1999, 2002, 2003, 2007
    3:    Free Software Foundation, Inc.
    4:    Written by Ian Lance Taylor, Cygnus Support.
    5:    Rewritten by Kai Tietz, Onevision.
    6: 
    7:    This file is part of GNU Binutils.
    8: 
    9:    This program is free software; you can redistribute it and/or modify
   10:    it under the terms of the GNU General Public License as published by
   11:    the Free Software Foundation; either version 3 of the License, or
   12:    (at your option) any later version.
   13: 
   14:    This program is distributed in the hope that it will be useful,
   15:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   16:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17:    GNU General Public License for more details.
   18: 
   19:    You should have received a copy of the GNU General Public License
   20:    along with this program; if not, write to the Free Software
   21:    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
   22:    02110-1301, USA.  */
   23: 
   24: 
   25: /* This file contains functions to convert between the binary resource
   26:    format and the internal structures that we want to use.  The same
   27:    binary resource format is used in both res and COFF files.  */
   28: 
   29: #include "sysdep.h"
   30: #include "bfd.h"
   31: #include "bucomm.h"
   32: #include "libiberty.h"
   33: #include "windres.h"
   34: 
   35: /* Local functions.  */
   36: 
   37: static void toosmall (const char *);
   38: 
   39: static unichar *get_unicode (windres_bfd *, const bfd_byte *, rc_uint_type, rc_uint_type *);
   40: static int get_resid (windres_bfd *, rc_res_id *, const bfd_byte *, rc_uint_type);
   41: static rc_res_resource *bin_to_res_generic (windres_bfd *, enum rc_res_type,
   42:                                             const bfd_byte *, rc_uint_type);
   43: static rc_res_resource *bin_to_res_cursor (windres_bfd *, const bfd_byte *, rc_uint_type);
   44: static rc_res_resource *bin_to_res_menu (windres_bfd *,const bfd_byte *, rc_uint_type);
   45: static rc_menuitem *bin_to_res_menuitems (windres_bfd *, const bfd_byte *, rc_uint_type,
   46:                                           rc_uint_type *);
   47: static rc_menuitem *bin_to_res_menuexitems (windres_bfd *, const bfd_byte *, rc_uint_type,
   48:                                             rc_uint_type *);
   49: static rc_res_resource *bin_to_res_dialog (windres_bfd *, const bfd_byte *, rc_uint_type);
   50: static rc_res_resource *bin_to_res_string (windres_bfd *,const bfd_byte *, rc_uint_type);
   51: static rc_res_resource *bin_to_res_fontdir (windres_bfd *, const bfd_byte *, rc_uint_type);
   52: static rc_res_resource *bin_to_res_accelerators (windres_bfd *, const bfd_byte *, rc_uint_type);
   53: static rc_res_resource *bin_to_res_rcdata (windres_bfd *, const bfd_byte *, rc_uint_type, int);
   54: static rc_res_resource *bin_to_res_group_cursor (windres_bfd *, const bfd_byte *, rc_uint_type);
   55: static rc_res_resource *bin_to_res_group_icon (windres_bfd *, const bfd_byte *, rc_uint_type);
   56: static rc_res_resource *bin_to_res_version (windres_bfd *, const bfd_byte *, rc_uint_type);
   57: static rc_res_resource *bin_to_res_userdata (windres_bfd *, const bfd_byte *, rc_uint_type);
   58: static rc_res_resource *bin_to_res_toolbar (windres_bfd *, const bfd_byte *, rc_uint_type);
   59: static void get_version_header (windres_bfd *, const bfd_byte *, rc_uint_type, const char *,
   60:                                 unichar **, rc_uint_type *, rc_uint_type *, rc_uint_type *,
   61:                                 rc_uint_type *);
   62: 
   63: /* Given a resource type ID, a pointer to data, a length, return a
   64:    rc_res_resource structure which represents that resource.  The caller
   65:    is responsible for initializing the res_info and coff_info fields
   66:    of the returned structure.  */
   67: 
   68: rc_res_resource *
   69: bin_to_res (windres_bfd *wrbfd, rc_res_id type, const bfd_byte *data,
   70:             rc_uint_type length)
   71: {
   72:   if (type.named)
   73:     return bin_to_res_userdata (wrbfd, data, length);
   74:   else
   75:     {
   76:       switch (type.u.id)
   77:         {
   78:         default:
   79:           return bin_to_res_userdata (wrbfd, data, length);
   80:         case RT_CURSOR:
   81:           return bin_to_res_cursor (wrbfd, data, length);
   82:         case RT_BITMAP:
   83:           return bin_to_res_generic (wrbfd, RES_TYPE_BITMAP, data, length);
   84:         case RT_ICON:
   85:           return bin_to_res_generic (wrbfd, RES_TYPE_ICON, data, length);
   86:         case RT_MENU:
   87:           return bin_to_res_menu (wrbfd, data, length);
   88:         case RT_DIALOG:
   89:           return bin_to_res_dialog (wrbfd, data, length);
   90:         case RT_STRING:
   91:           return bin_to_res_string (wrbfd, data, length);
   92:         case RT_FONTDIR:
   93:           return bin_to_res_fontdir (wrbfd, data, length);
   94:         case RT_FONT:
   95:           return bin_to_res_generic (wrbfd, RES_TYPE_FONT, data, length);
   96:         case RT_ACCELERATOR:
   97:           return bin_to_res_accelerators (wrbfd, data, length);
   98:         case RT_RCDATA:
   99:           return bin_to_res_rcdata (wrbfd, data, length, RES_TYPE_RCDATA);
  100:         case RT_MESSAGETABLE:
  101:           return bin_to_res_generic (wrbfd, RES_TYPE_MESSAGETABLE, data, length);
  102:         case RT_GROUP_CURSOR:
  103:           return bin_to_res_group_cursor (wrbfd, data, length);
  104:         case RT_GROUP_ICON:
  105:           return bin_to_res_group_icon (wrbfd, data, length);
  106:         case RT_VERSION:
  107:           return bin_to_res_version (wrbfd, data, length);
  108:         case RT_TOOLBAR:
  109:           return  bin_to_res_toolbar (wrbfd, data, length);
  110: 
  111:         }
  112:     }
  113: }
  114: 
  115: /* Give an error if the binary data is too small.  */
  116: 
  117: static void
  118: toosmall (const char *msg)
  119: {
  120:   fatal (_("%s: not enough binary data"), msg);
  121: }
  122: 
  123: /* Swap in a NULL terminated unicode string.  */
  124: 
  125: static unichar *
  126: get_unicode (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
  127:              rc_uint_type *retlen)
  128: {
  129:   rc_uint_type c, i;
  130:   unichar *ret;
  131: 
  132:   c = 0;
  133:   while (1)
  134:     {
  135:       if (length < c * 2 + 2)
  136:         toosmall (_("null terminated unicode string"));
  137:       if (windres_get_16 (wrbfd, data + c * 2, 2) == 0)
  138:         break;
  139:       ++c;
  140:     }
  141: 
  142:   ret = (unichar *) res_alloc ((c + 1) * sizeof (unichar));
  143: 
  144:   for (i = 0; i < c; i++)
  145:     ret[i] = windres_get_16 (wrbfd, data + i * 2, 2);
  146:   ret[i] = 0;
  147: 
  148:   if (retlen != NULL)
  149:     *retlen = c;
  150: 
  151:   return ret;
  152: }
  153: 
  154: /* Get a resource identifier.  This returns the number of bytes used.  */
  155: 
  156: static int
  157: get_resid (windres_bfd *wrbfd, rc_res_id *id, const bfd_byte *data,
  158:            rc_uint_type length)
  159: {
  160:   rc_uint_type first;
  161: 
  162:   if (length < 2)
  163:     toosmall (_("resource ID"));
  164: 
  165:   first = windres_get_16 (wrbfd, data, 2);
  166:   if (first == 0xffff)
  167:     {
  168:       if (length < 4)
  169:         toosmall (_("resource ID"));
  170:       id->named = 0;
  171:       id->u.id = windres_get_16 (wrbfd, data + 2, 2);
  172:       return 4;
  173:     }
  174:   else
  175:     {
  176:       id->named = 1;
  177:       id->u.n.name = get_unicode (wrbfd, data, length, &id->u.n.length);
  178:       return id->u.n.length * 2 + 2;
  179:     }
  180: }
  181: 
  182: /* Convert a resource which just stores uninterpreted data from
  183:    binary.  */
  184: 
  185: rc_res_resource *
  186: bin_to_res_generic (windres_bfd *wrbfd ATTRIBUTE_UNUSED, enum rc_res_type type,
  187:                     const bfd_byte *data, rc_uint_type length)
  188: {
  189:   rc_res_resource *r;
  190: 
  191:   r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
  192:   r->type = type;
  193:   r->u.data.data = data;
  194:   r->u.data.length = length;
  195: 
  196:   return r;
  197: }
  198: 
  199: /* Convert a cursor resource from binary.  */
  200: 
  201: rc_res_resource *
  202: bin_to_res_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
  203: {
  204:   rc_cursor *c;
  205:   rc_res_resource *r;
  206: 
  207:   if (length < 4)
  208:     toosmall (_("cursor"));
  209: 
  210:   c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
  211:   c->xhotspot = windres_get_16 (wrbfd, data, 2);
  212:   c->yhotspot = windres_get_16 (wrbfd, data + 2, 2);
  213:   c->length = length - 4;
  214:   c->data = data + 4;
  215: 
  216:   r = (rc_res_resource *) res_alloc (sizeof *r);
  217:   r->type = RES_TYPE_CURSOR;
  218:   r->u.cursor = c;
  219: 
  220:   return r;
  221: }
  222: 
  223: /* Convert a menu resource from binary.  */
  224: 
  225: rc_res_resource *
  226: bin_to_res_menu (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
  227: {
  228:   rc_res_resource *r;
  229:   rc_menu *m;
  230:   rc_uint_type version, read;
  231: 
  232:   r = (rc_res_resource *) res_alloc (sizeof *r);
  233:   r->type = RES_TYPE_MENU;
  234: 
  235:   m = (rc_menu *) res_alloc (sizeof (rc_menu));
  236:   r->u.menu = m;
  237: 
  238:   if (length < 2)
  239:     toosmall (_("menu header"));
  240: 
  241:   version = windres_get_16 (wrbfd, data, 2);
  242: 
  243:   if (version == 0)
  244:     {
  245:       if (length < 4)
  246:         toosmall (_("menu header"));
  247:       m->help = 0;
  248:       m->items = bin_to_res_menuitems (wrbfd, data + 4, length - 4, &read);
  249:     }
  250:   else if (version == 1)
  251:     {
  252:       rc_uint_type offset;
  253: 
  254:       if (length < 8)
  255:         toosmall (_("menuex header"));
  256:       m->help = windres_get_32 (wrbfd, data + 4, 4);
  257:       offset = windres_get_16 (wrbfd, data + 2, 2);
  258:       if (offset + 4 >= length)
  259:         toosmall (_("menuex offset"));
  260:       m->items = bin_to_res_menuexitems (wrbfd, data + 4 + offset,
  261:                                          length - (4 + offset), &read);
  262:     }
  263:   else
  264:     fatal (_("unsupported menu version %d"), (int) version);
  265: 
  266:   return r;
  267: }
  268: 
  269: /* Convert menu items from binary.  */
  270: 
  271: static rc_menuitem *
  272: bin_to_res_menuitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
  273:                       rc_uint_type *read)
  274: {
  275:   rc_menuitem *first, **pp;
  276: 
  277:   first = NULL;
  278:   pp = &first;
  279: 
  280:   *read = 0;
  281: 
  282:   while (length > 0)
  283:     {
  284:       rc_uint_type flags, slen, itemlen;
  285:       rc_uint_type stroff;
  286:       rc_menuitem *mi;
  287: 
  288:       if (length < 4)
  289:         toosmall (_("menuitem header"));
  290: 
  291:       mi = (rc_menuitem *) res_alloc (sizeof *mi);
  292:       mi->state = 0;
  293:       mi->help = 0;
  294: 
  295:       flags = windres_get_16 (wrbfd, data, 2);
  296:       mi->type = flags &~ (MENUITEM_POPUP | MENUITEM_ENDMENU);
  297: 
  298:       if ((flags & MENUITEM_POPUP) == 0)
  299:         stroff = 4;
  300:       else
  301:         stroff = 2;
  302: 
  303:       if (length < stroff + 2)
  304:         toosmall (_("menuitem header"));
  305: 
  306:       if (windres_get_16 (wrbfd, data + stroff, 2) == 0)
  307:         {
  308:           slen = 0;
  309:           mi->text = NULL;
  310:         }
  311:       else
  312:         mi->text = get_unicode (wrbfd, data + stroff, length - stroff, &slen);
  313: 
  314:       itemlen = stroff + slen * 2 + 2;
  315: 
  316:       if ((flags & MENUITEM_POPUP) == 0)
  317:         {
  318:           mi->popup = NULL;
  319:           mi->id = windres_get_16 (wrbfd, data + 2, 2);
  320:         }
  321:       else
  322:         {
  323:           rc_uint_type subread;
  324: 
  325:           mi->id = 0;
  326:           mi->popup = bin_to_res_menuitems (wrbfd, data + itemlen, length - itemlen,
  327:                                            &subread);
  328:           itemlen += subread;
  329:         }
  330: 
  331:       mi->next = NULL;
  332:       *pp = mi;
  333:       pp = &mi->next;
  334: 
  335:       data += itemlen;
  336:       length -= itemlen;
  337:       *read += itemlen;
  338: 
  339:       if ((flags & MENUITEM_ENDMENU) != 0)
  340:         return first;
  341:     }
  342: 
  343:   return first;
  344: }
  345: 
  346: /* Convert menuex items from binary.  */
  347: 
  348: static rc_menuitem *
  349: bin_to_res_menuexitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
  350:                         rc_uint_type *read)
  351: {
  352:   rc_menuitem *first, **pp;
  353: 
  354:   first = NULL;
  355:   pp = &first;
  356: 
  357:   *read = 0;
  358: 
  359:   while (length > 0)
  360:     {
  361:       rc_uint_type flags, slen;
  362:       rc_uint_type itemlen;
  363:       rc_menuitem *mi;
  364: 
  365:       if (length < 16)
  366:         toosmall (_("menuitem header"));
  367: 
  368:       mi = (rc_menuitem *) res_alloc (sizeof (rc_menuitem));
  369:       mi->type = windres_get_32 (wrbfd, data, 4);
  370:       mi->state = windres_get_32 (wrbfd, data + 4, 4);
  371:       mi->id = windres_get_32 (wrbfd, data + 8, 4);
  372: 
  373:       flags = windres_get_16 (wrbfd, data + 12, 2);
  374: 
  375:       if (windres_get_16 (wrbfd, data + 14, 2) == 0)
  376:         {
  377:           slen = 0;
  378:           mi->text = NULL;
  379:         }
  380:       else
  381:         mi->text = get_unicode (wrbfd, data + 14, length - 14, &slen);
  382: 
  383:       itemlen = 14 + slen * 2 + 2;
  384:       itemlen = (itemlen + 3) &~ 3;
  385: 
  386:       if ((flags & 1) == 0)
  387:         {
  388:           mi->popup = NULL;
  389:           mi->help = 0;
  390:         }
  391:       else
  392:         {
  393:           rc_uint_type subread;
  394: 
  395:           if (length < itemlen + 4)
  396:             toosmall (_("menuitem"));
  397:           mi->help = windres_get_32 (wrbfd, data + itemlen, 4);
  398:           itemlen += 4;
  399: 
  400:           mi->popup = bin_to_res_menuexitems (wrbfd, data + itemlen,
  401:                                               length - itemlen, &subread);
  402:           itemlen += subread;
  403:         }
  404: 
  405:       mi->next = NULL;
  406:       *pp = mi;
  407:       pp = &mi->next;
  408: 
  409:       data += itemlen;
  410:       length -= itemlen;
  411:       *read += itemlen;
  412: 
  413:       if ((flags & 0x80) != 0)
  414:         return first;
  415:     }
  416: 
  417:   return first;
  418: }
  419: 
  420: /* Convert a dialog resource from binary.  */
  421: 
  422: static rc_res_resource *
  423: bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
  424: {
  425:   rc_uint_type signature;
  426:   rc_dialog *d;
  427:   rc_uint_type c, sublen, i;
  428:   rc_uint_type off;
  429:   rc_dialog_control **pp;
  430:   rc_res_resource *r;
  431: 
  432:   if (length < 18)
  433:     toosmall (_("dialog header"));
  434: 
  435:   d = (rc_dialog *) res_alloc (sizeof (rc_dialog));
  436: 
  437:   signature = windres_get_16 (wrbfd, data + 2, 2);
  438:   if (signature != 0xffff)
  439:     {
  440:       d->ex = NULL;
  441:       d->style = windres_get_32 (wrbfd, data, 4);
  442:       d->exstyle = windres_get_32 (wrbfd, data + 4, 4);
  443:       off = 8;
  444:     }
  445:   else
  446:     {
  447:       int version;
  448: 
  449:       version = windres_get_16 (wrbfd, data, 2);
  450:       if (version != 1)
  451:         fatal (_("unexpected DIALOGEX version %d"), version);
  452: 
  453:       d->ex = (rc_dialog_ex *) res_alloc (sizeof (rc_dialog_ex));
  454:       d->ex->help = windres_get_32 (wrbfd, data + 4, 4);
  455:       d->exstyle = windres_get_32 (wrbfd, data + 8, 4);
  456:       d->style = windres_get_32 (wrbfd, data + 12, 4);
  457:       off = 16;
  458:     }
  459: 
  460:   if (length < off + 10)
  461:     toosmall (_("dialog header"));
  462: 
  463:   c = windres_get_16 (wrbfd, data + off, 2);
  464:   d->x = windres_get_16 (wrbfd, data + off + 2, 2);
  465:   d->y = windres_get_16 (wrbfd, data + off + 4, 2);
  466:   d->width = windres_get_16 (wrbfd, data + off + 6, 2);
  467:   d->height = windres_get_16 (wrbfd, data + off + 8, 2);
  468: 
  469:   off += 10;
  470: 
  471:   sublen = get_resid (wrbfd, &d->menu, data + off, length - off);
  472:   off += sublen;
  473: 
  474:   sublen = get_resid (wrbfd, &d->class, data + off, length - off);
  475:   off += sublen;
  476: 
  477:   d->caption = get_unicode (wrbfd, data + off, length - off, &sublen);
  478:   off += sublen * 2 + 2;
  479:   if (sublen == 0)
  480:     d->caption = NULL;
  481: 
  482:   if ((d->style & DS_SETFONT) == 0)
  483:     {
  484:       d->pointsize = 0;
  485:       d->font = NULL;
  486:       if (d->ex != NULL)
  487:         {
  488:           d->ex->weight = 0;
  489:           d->ex->italic = 0;
  490:           d->ex->charset = 1; /* Default charset.  */
  491:         }
  492:     }
  493:   else
  494:     {
  495:       if (length < off + 2)
  496:         toosmall (_("dialog font point size"));
  497: 
  498:       d->pointsize = windres_get_16 (wrbfd, data + off, 2);
  499:       off += 2;
  500: 
  501:       if (d->ex != NULL)
  502:         {
  503:           if (length < off + 4)
  504:             toosmall (_("dialogex font information"));
  505:           d->ex->weight = windres_get_16 (wrbfd, data + off, 2);
  506:           d->ex->italic = windres_get_8 (wrbfd, data + off + 2, 1);
  507:           d->ex->charset = windres_get_8 (wrbfd, data + off + 3, 1);
  508:           off += 4;
  509:         }
  510: 
  511:       d->font = get_unicode (wrbfd, data + off, length - off, &sublen);
  512:       off += sublen * 2 + 2;
  513:     }
  514: 
  515:   d->controls = NULL;
  516:   pp = &d->controls;
  517: 
  518:   for (i = 0; i < c; i++)
  519:     {
  520:       rc_dialog_control *dc;
  521:       int datalen;
  522: 
  523:       off = (off + 3) &~ 3;
  524: 
  525:       dc = (rc_dialog_control *) res_alloc (sizeof (rc_dialog_control));
  526: 
  527:       if (d->ex == NULL)
  528:         {
  529:           if (length < off + 8)
  530:             toosmall (_("dialog control"));
  531: 
  532:           dc->style = windres_get_32 (wrbfd, data + off, 4);
  533:           dc->exstyle = windres_get_32 (wrbfd, data + off + 4, 4);
  534:           dc->help = 0;
  535:           off += 8;
  536:         }
  537:       else
  538:         {
  539:           if (length < off + 12)
  540:             toosmall (_("dialogex control"));
  541:           dc->help = windres_get_32 (wrbfd, data + off, 4);
  542:           dc->exstyle = windres_get_32 (wrbfd, data + off + 4, 4);
  543:           dc->style = windres_get_32 (wrbfd, data + off + 8, 4);
  544:           off += 12;
  545:         }