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

binutils/2.18/binutils/resres.c

    1: /* resres.c: read_res_file and write_res_file implementation for windres.
    2:    Copyright 1998, 1999, 2001, 2002, 2007
    3:    Free Software Foundation, Inc.
    4:    Written by Anders Norlander <anorland@hem2.passagen.se>.
    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: /* FIXME: This file does not work correctly in a cross configuration.
   25:    It assumes that it can use fread and fwrite to read and write
   26:    integers.  It does no swapping.  */
   27: 
   28: #include "sysdep.h"
   29: #include "bfd.h"
   30: #include "bucomm.h"
   31: #include "libiberty.h"
   32: #include "windres.h"
   33: 
   34: #include <assert.h>
   35: #include <time.h>
   36: 
   37: static rc_uint_type write_res_directory (windres_bfd *, rc_uint_type,
   38:                                              const rc_res_directory *, const rc_res_id *,
   39:                                              const rc_res_id *, rc_uint_type *, int);
   40: static rc_uint_type write_res_resource (windres_bfd *, rc_uint_type,const rc_res_id *,
   41:                                     const rc_res_id *, const rc_res_resource *,
   42:                                     rc_uint_type *);
   43: static rc_uint_type write_res_bin (windres_bfd *, rc_uint_type, const rc_res_resource *,
   44:                                    const rc_res_id *, const rc_res_id *,
   45:                                    const rc_res_res_info *);
   46: 
   47: static rc_uint_type write_res_id (windres_bfd *, rc_uint_type, const rc_res_id *);
   48: static rc_uint_type write_res_info (windres_bfd *, rc_uint_type, const rc_res_res_info *);
   49: static rc_uint_type write_res_data_hdr (windres_bfd *, rc_uint_type, res_hdr *);
   50: 
   51: static rc_uint_type write_res_header (windres_bfd *, rc_uint_type, rc_uint_type,
   52:                                       const rc_res_id *, const rc_res_id *,
   53:                                       const rc_res_res_info *);
   54: 
   55: static int read_resource_entry (windres_bfd *, rc_uint_type *, rc_uint_type);
   56: static void read_res_data (windres_bfd *, rc_uint_type *, rc_uint_type, void *,
   57:                            rc_uint_type);
   58: static void read_res_data_hdr (windres_bfd *, rc_uint_type *, rc_uint_type, res_hdr *);
   59: static void read_res_id (windres_bfd *, rc_uint_type *, rc_uint_type, rc_res_id *);
   60: static unichar *read_unistring (windres_bfd *, rc_uint_type *, rc_uint_type, rc_uint_type *);
   61: static void skip_null_resource (windres_bfd *, rc_uint_type *, rc_uint_type);
   62: static int probe_binary (windres_bfd *wrbfd, rc_uint_type);
   63: 
   64: static unsigned long get_id_size (const rc_res_id *);
   65: 
   66: static void res_add_resource (rc_res_resource *, const rc_res_id *,
   67:                               const rc_res_id *, rc_uint_type, int);
   68: 
   69: static void res_append_resource (rc_res_directory **, rc_res_resource *,
   70:                                  int, const rc_res_id *, int);
   71: 
   72: static rc_res_directory *resources = NULL;
   73: 
   74: static const char *filename;
   75: 
   76: extern char *program_name;
   77: 
   78: /* Read resource file */
   79: rc_res_directory *
   80: read_res_file (const char *fn)
   81: {
   82:   rc_uint_type off, flen;
   83:   windres_bfd wrbfd;
   84:   bfd *abfd;
   85:   asection *sec;
   86:   filename = fn;
   87: 
   88:   flen = (rc_uint_type) get_file_size (filename);
   89:   if (! flen)
   90:     fatal ("can't open '%s' for input.", filename);
   91:   abfd = windres_open_as_binary (filename, 1);
   92:   sec = bfd_get_section_by_name (abfd, ".data");
   93:   if (sec == NULL)
   94:     bfd_fatal ("bfd_get_section_by_name");
   95:   set_windres_bfd (&wrbfd, abfd, sec,
   96:                    (target_is_bigendian ? WR_KIND_BFD_BIN_B
   97:                                         : WR_KIND_BFD_BIN_L));
   98:   off = 0;
   99: 
  100:   if (! probe_binary (&wrbfd, flen))
  101:     set_windres_bfd_endianess (&wrbfd, ! target_is_bigendian);
  102: 
  103:   skip_null_resource (&wrbfd, &off, flen);
  104: 
  105:   while (read_resource_entry (&wrbfd, &off, flen))
  106:     ;
  107: 
  108:   bfd_close (abfd);
  109: 
  110:   return resources;
  111: }
  112: 
  113: /* Write resource file */
  114: void
  115: write_res_file (const char *fn,const rc_res_directory *resdir)
  116: {
  117:   asection *sec;
  118:   rc_uint_type language;
  119:   bfd *abfd;
  120:   windres_bfd wrbfd;
  121:   unsigned long sec_length = 0,sec_length_wrote;
  122:   static const bfd_byte sign[] =
  123:   {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
  124:    0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
  125:    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  126:    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  127: 
  128:   filename = fn;
  129: 
  130:   abfd = windres_open_as_binary (filename, 0);
  131:   sec = bfd_make_section (abfd, ".data");
  132:   if (sec == NULL)
  133:     bfd_fatal ("bfd_make_section");
  134:   if (! bfd_set_section_flags (abfd, sec,
  135:                                (SEC_HAS_CONTENTS | SEC_ALLOC
  136:                                 | SEC_LOAD | SEC_DATA)))
  137:     bfd_fatal ("bfd_set_section_flags");
  138:   /* Requiring this is probably a bug in BFD.  */
  139:   sec->output_section = sec;
  140: 
  141:   set_windres_bfd (&wrbfd, abfd, sec,
  142:                    (target_is_bigendian ? WR_KIND_BFD_BIN_B
  143:                                         : WR_KIND_BFD_BIN_L));
  144: 
  145:   language = -1;
  146:   sec_length = write_res_directory ((windres_bfd *) NULL, 0x20UL, resdir,
  147:                                     (const rc_res_id *) NULL,
  148:                                     (const rc_res_id *) NULL, &language, 1);
  149:   if (! bfd_set_section_size (abfd, sec, (sec_length + 3) & ~3))
  150:     bfd_fatal ("bfd_set_section_size");
  151:   if ((sec_length & 3) != 0)
  152:     set_windres_bfd_content (&wrbfd, sign, sec_length, 4-(sec_length & 3));
  153:   set_windres_bfd_content (&wrbfd, sign, 0, sizeof (sign));
  154:   language = -1;
  155:   sec_length_wrote = write_res_directory (&wrbfd, 0x20UL, resdir,
  156:                                           (const rc_res_id *) NULL,
  157:                                           (const rc_res_id *) NULL,
  158:                                           &language, 1);
  159:   if (sec_length != sec_length_wrote)
  160:     fatal ("res write failed with different sizes (%lu/%lu).", (long) sec_length,
  161:            (long) sec_length_wrote);
  162: 
  163:   bfd_close (abfd);
  164:   return;
  165: }
  166: 
  167: /* Read a resource entry, returns 0 when all resources are read */
  168: static int
  169: read_resource_entry (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax)
  170: {
  171:   rc_res_id type;
  172:   rc_res_id name;
  173:   rc_res_res_info resinfo;
  174:   res_hdr reshdr;
  175:   void *buff;
  176: 
  177:   rc_res_resource *r;
  178:   struct bin_res_info l;
  179: 
  180:   off[0] = (off[0] + 3) & ~3;
  181: 
  182:   /* Read header */
  183:   if ((off[0] + 8) > omax)
  184:     return 0;
  185:   read_res_data_hdr (wrbfd, off, omax, &reshdr);
  186: 
  187:   /* read resource type */
  188:   read_res_id (wrbfd, off, omax, &type);
  189:   /* read resource id */
  190:   read_res_id (wrbfd, off, omax, &name);
  191: 
  192:   off[0] = (off[0] + 3) & ~3;
  193: 
  194:   /* Read additional resource header */
  195:   read_res_data (wrbfd, off, omax, &l, BIN_RES_INFO_SIZE);
  196:   resinfo.version = windres_get_32 (wrbfd, l.version, 4);
  197:   resinfo.memflags = windres_get_16 (wrbfd, l.memflags, 2);
  198:   resinfo.language = windres_get_16 (wrbfd, l.language, 2);
  199:   /* resinfo.version2 = windres_get_32 (wrbfd, l.version2, 4); */
  200:   resinfo.characteristics = windres_get_32 (wrbfd, l.characteristics, 4);
  201: 
  202:   off[0] = (off[0] + 3) & ~3;
  203: 
  204:   /* Allocate buffer for data */
  205:   buff = res_alloc (reshdr.data_size);
  206:   /* Read data */
  207:   read_res_data (wrbfd, off, omax, buff, reshdr.data_size);
  208:   /* Convert binary data to resource */
  209:   r = bin_to_res (wrbfd, type, buff, reshdr.data_size);
  210:   r->res_info = resinfo;
  211:   /* Add resource to resource directory */
  212:   res_add_resource (r, &type, &name, resinfo.language, 0);
  213: 
  214:   return 1;
  215: }
  216: 
  217: /* write resource directory to binary resource file */
  218: static rc_uint_type
  219: write_res_directory (windres_bfd *wrbfd, rc_uint_type off, const rc_res_directory *rd,
  220:                      const rc_res_id *type, const rc_res_id *name, rc_uint_type *language,
  221:                      int level)
  222: {
  223:   const rc_res_entry *re;
  224: 
  225:   for (re = rd->entries; re != NULL; re = re->next)
  226:     {
  227:       switch (level)
  228:         {
  229:         case 1:
  230:           /* If we're at level 1, the key of this resource is the
  231:              type.  This normally duplicates the information we have
  232:              stored with the resource itself, but we need to remember
  233:              the type if this is a user define resource type.  */
  234:           type = &re->id;
  235:           break;
  236: 
  237:         case 2:
  238:           /* If we're at level 2, the key of this resource is the name
  239:              we are going to use in the rc printout.  */
  240:           name = &re->id;
  241:           break;
  242: 
  243:         case 3:
  244:           /* If we're at level 3, then this key represents a language.
  245:              Use it to update the current language.  */
  246:           if (! re->id.named
  247:               && re->id.u.id != (unsigned long) *language
  248:               && (re->id.u.id & 0xffff) == re->id.u.id)
  249:             {
  250:               *language = re->id.u.id;
  251:             }
  252:           break;
  253: 
  254:         default:
  255:           break;
  256:         }
  257: 
  258:       if (re->subdir)
  259:         off = write_res_directory (wrbfd, off, re->u.dir, type, name, language,
  260:                                    level + 1);
  261:       else
  262:         {
  263:           if (level == 3)
  264:             {
  265:               /* This is the normal case: the three levels are
  266:                  TYPE/NAME/LANGUAGE.  NAME will have been set at level
  267:                  2, and represents the name to use.  We probably just
  268:                  set LANGUAGE, and it will probably match what the
  269:                  resource itself records if anything.  */
  270:               off = write_res_resource (wrbfd, off, type, name, re->u.res,
  271:                                        language);
  272:             }
  273:           else
  274:             {
  275:               fprintf (stderr, "// Resource at unexpected level %d\n", level);
  276:               off = write_res_resource (wrbfd, off, type, (rc_res_id *) NULL,
  277:                                        re->u.res, language);
  278:             }
  279:         }
  280:     }
  281: 
  282:   return off;
  283: }
  284: 
  285: static rc_uint_type
  286: write_res_resource (windres_bfd *wrbfd, rc_uint_type off, const rc_res_id *type,
  287:                     const rc_res_id *name, const rc_res_resource *res,
  288:                     rc_uint_type *language ATTRIBUTE_UNUSED)
  289: {
  290:   int rt;
  291: 
  292:   switch (res->type)
  293:     {
  294:     default:
  295:       abort ();
  296: 
  297:     case RES_TYPE_ACCELERATOR:
  298:       rt = RT_ACCELERATOR;
  299:       break;
  300: 
  301:     case RES_TYPE_BITMAP:
  302:       rt = RT_BITMAP;
  303:       break;
  304: 
  305:     case RES_TYPE_CURSOR:
  306:       rt = RT_CURSOR;
  307:       break;
  308: 
  309:     case RES_TYPE_GROUP_CURSOR:
  310:       rt = RT_GROUP_CURSOR;
  311:       break;
  312: 
  313:     case RES_TYPE_DIALOG:
  314:       rt = RT_DIALOG;
  315:       break;
  316: 
  317:     case RES_TYPE_FONT:
  318:       rt = RT_FONT;
  319:       break;
  320: 
  321:     case RES_TYPE_FONTDIR:
  322:       rt = RT_FONTDIR;
  323:       break;
  324: 
  325:     case RES_TYPE_ICON:
  326:       rt = RT_ICON;
  327:       break;
  328: 
  329:     case RES_TYPE_GROUP_ICON:
  330:       rt = RT_GROUP_ICON;
  331:       break;
  332: 
  333:     case RES_TYPE_MENU:
  334:       rt = RT_MENU;
  335:       break;
  336: 
  337:     case RES_TYPE_MESSAGETABLE:
  338:       rt = RT_MESSAGETABLE;
  339:       break;
  340: 
  341:     case RES_TYPE_RCDATA:
  342:       rt = RT_RCDATA;
  343:       break;
  344: 
  345:     case RES_TYPE_STRINGTABLE:
  346:       rt = RT_STRING;
  347:       break;
  348: 
  349:     case RES_TYPE_USERDATA:
  350:       rt = 0;
  351:       break;
  352: 
  353:     case RES_TYPE_VERSIONINFO:
  354:       rt = RT_VERSION;
  355:       break;
  356: 
  357:     case RES_TYPE_TOOLBAR:
  358:       rt = RT_TOOLBAR;
  359:       break;
  360:     }
  361: 
  362:   if (rt != 0
  363:       && type != NULL
  364:       && (type->named || type->u.id != (unsigned long) rt))
  365:     {
  366:       fprintf (stderr, "// Unexpected resource type mismatch: ");
  367:       res_id_print (stderr, *type, 1);
  368:       fprintf (stderr, " != %d", rt);
  369:       abort ();
  370:     }
  371: 
  372:   return write_res_bin (wrbfd, off, res, type, name, &res->res_info);
  373: }
  374: 
  375: /* Write a resource in binary resource format */
  376: static rc_uint_type
  377: write_res_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res,
  378:                const rc_res_id *type, const rc_res_id *name,
  379:                const rc_res_res_info *resinfo)
  380: {
  381:   rc_uint_type noff;
  382:   rc_uint_type datasize = 0;
  383: 
  384:   noff = res_to_bin ((windres_bfd *) NULL, off, res);
  385:   datasize = noff - off;
  386: 
  387:   off = write_res_header (wrbfd, off, datasize, type, name, resinfo);
  388:   return res_to_bin (wrbfd, off, res);
  389: }
  390: 
  391: /* Get number of bytes needed to store an id in binary format */
  392: static unsigned long
  393: get_id_size (id)
  394:      const rc_res_id *id;
  395: {
  396:   if (id->named)
  397:     return sizeof (unichar) * (id->u.n.length + 1);
  398:   else
  399:     return sizeof (unichar) * 2;
  400: }
  401: 
  402: /* Write a resource header */
  403: static rc_uint_type
  404: write_res_header (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type datasize,
  405:                   const rc_res_id *type, const rc_res_id *name,
  406:                   const rc_res_res_info *resinfo)
  407: {
  408:   res_hdr reshdr;
  409:   reshdr.data_size = datasize;
  410:   reshdr.header_size = 24 + get_id_size (type) + get_id_size (name);
  411: 
  412:   reshdr.header_size = (reshdr.header_size + 3) & ~3;
  413: 
  414:   off = (off + 3) & ~3;
  415: 
  416:   off = write_res_data_hdr (wrbfd, off, &reshdr);
  417:   off = write_res_id (wrbfd, off, type);
  418:   off = write_res_id (wrbfd, off, name);
  419: 
  420:   off = (off + 3) & ~3;
  421: 
  422:   off = write_res_info (wrbfd, off, resinfo);
  423:   off = (off + 3) & ~3;
  424:   return off;
  425: }
  426: 
  427: static rc_uint_type
  428: write_res_data_hdr (windres_bfd *wrbfd, rc_uint_type off, res_hdr *hdr)
  429: {
  430:   if (wrbfd)
  431:     {
  432:       struct bin_res_hdr brh;
  433:       windres_put_32 (wrbfd, brh.data_size, hdr->data_size);
  434:       windres_put_32 (wrbfd, brh.header_size, hdr->header_size);
  435:       set_windres_bfd_content (wrbfd, &brh, off, BIN_RES_HDR_SIZE);
  436:     }
  437:   return off + BIN_RES_HDR_SIZE;
  438: }
  439: 
  440: static void
  441: read_res_data_hdr (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax,
  442:                    res_hdr *reshdr)
  443: {
  444:   struct bin_res_hdr brh;
  445: 
  446:   if ((off[0] + BIN_RES_HDR_SIZE) > omax)
  447:     fatal ("%s: unexpected end of file %ld/%ld", filename,(long) off[0], (long) omax);
  448: 
  449:   get_windres_bfd_content (wrbfd, &brh, off[0], BIN_RES_HDR_SIZE);
  450:   reshdr->data_size = windres_get_32 (wrbfd, brh.data_size, 4);
  451:   reshdr->header_size = windres_get_32 (wrbfd, brh.header_size, 4);
  452:   off[0] += BIN_RES_HDR_SIZE;
  453: }
  454: 
  455: /* Read data from file, abort on failure */
  456: static void
  457: read_res_data (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, void *data,
  458:                rc_uint_type size)
  459: {
  460:   if ((off[0] + size) > omax)
  461:     fatal ("%s: unexpected end of file %ld/%ld %ld", filename,(long) off[0],
  462:            (long) omax, (long) size);
  463:   get_windres_bfd_content (wrbfd, data, off[0], size);
  464:   off[0] += size;
  465: }
  466: 
  467: /* Write a resource id */
  468: static rc_uint_type
  469: write_res_id (windres_bfd *wrbfd, rc_uint_type off, const rc_res_id *id)
  470: {
  471:   if (id->named)
  472:     {
  473:       rc_uint_type len = (((bfd_signed_vma) id->u.n.length < 0 ? 0 : id->u.n.length) + 1);
  474:       if (wrbfd)
  475:         {
  476:           rc_uint_type i;
  477:           bfd_byte *d = (bfd_byte *) xmalloc (len * sizeof (unichar));
  478:           for (i = 0; i < (len - 1); i++)
  479:             windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id->u.n.name[i]);
  480:           windres_put_16 (wrbfd, d + (i * sizeof (unichar)), 0);
  481:           set_windres_bfd_content (wrbfd, d, off, (len * sizeof (unichar)));
  482:         }
  483:       off += (len * sizeof (unichar));
  484:     }
  485:   else
  486:     {
  487:       if (wrbfd)
  488:         {
  489:           struct bin_res_id bid;
  490:           windres_put_16 (wrbfd, bid.sig, 0xffff);
  491:           windres_put_16 (wrbfd, bid.id, id->u.id);
  492:           set_windres_bfd_content (wrbfd, &bid, off, BIN_RES_ID);
  493:         }
  494:       off += BIN_RES_ID;
  495:     }
  496:   return off;
  497: }
  498: 
  499: /* Write resource info */
  500: static rc_uint_type
  501: write_res_info (windres_bfd *wrbfd, rc_uint_type off, const rc_res_res_info *info)
  502: {
  503:   if (wrbfd)
  504:     {
  505:       struct bin_res_info l;
  506:       
  507:       windres_put_32 (wrbfd, l.version, info->version);
  508:       windres_put_16 (wrbfd, l.memflags, info->memflags);
  509:       windres_put_16 (wrbfd, l.language, info->language);
  510:       windres_put_32 (wrbfd, l.version2, info->version);
  511:       windres_put_32 (wrbfd, l.characteristics, info->characteristics);
  512:       set_windres_bfd_content (wrbfd, &l, off, BIN_RES_INFO_SIZE);
  513:     }
  514:   return off + BIN_RES_INFO_SIZE;
  515: }
  516: 
  517: /* read a resource identifier */
  518: static void
  519: read_res_id (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, rc_res_id *id)
  520: {
  521:   struct bin_res_id bid;
  522:   unsigned short ord;
  523:   unichar *id_s = NULL;
  524:   rc_uint_type len;
  525: 
  526:   read_res_data (wrbfd, off, omax, &bid, BIN_RES_ID - 2);
  527:   ord = (unsigned short) windres_get_16 (wrbfd, bid.sig, 2);
  528:   if (ord == 0xFFFF)            /* an ordinal id */
  529:     {
  530:       read_res_data (wrbfd, off, omax, bid.id, BIN_RES_ID - 2);
  531:       id->named = 0;
  532:       id->u.id = windres_get_16 (wrbfd, bid.id, 2);
  533:     }
  534:   else
  535:     /* named id */
  536:     {
  537:       off[0] -= 2;
  538:       id_s = read_unistring (wrbfd, off, omax, &len);
  539:       id->named = 1;
  540:       id->u.n.length = len;
  541:       id->u.n.name = id_s;
  542:     }
  543: }
  544: 
  545: /* Read a null terminated UNICODE string */