Another windres snapshot. Can now read the COFF resources directory,
authorIan Lance Taylor <ian@airs.com>
Mon, 23 Jun 1997 00:08:54 +0000 (00:08 +0000)
committerIan Lance Taylor <ian@airs.com>
Mon, 23 Jun 1997 00:08:54 +0000 (00:08 +0000)
although it doesn't yet parse out the binary format.

binutils/.Sanitize
binutils/ChangeLog
binutils/Makefile.in
binutils/rescoff.c [new file with mode: 0644]
binutils/resrc.c
binutils/windres.c

index 5bae795714150a4eee54080725f522e294fe5ff1..e66607a21d9706469d898ed0b4453a4968f90468 100644 (file)
@@ -84,6 +84,7 @@ ranlib.1
 ranlib.sh
 rclex.l
 rcparse.y
+rescoff.c
 resrc.c
 rdcoff.c
 rddbg.c
index 2a685dcc519fc19269eaf70f4caf4b40897831b6..3c8f28b210fcffcfe88ba8a06007a8a04ba9bae6 100644 (file)
@@ -6,6 +6,7 @@ Sun Jun 22 17:29:41 1997  Ian Lance Taylor  <ian@cygnus.com>
        * resrc.c: New file.
        * rcparse.y: New file.
        * rclex.l: New file.
+       * rescoff.c: New file.
        * configure.in: Define and substitute BUILD_WINDRES.
        * configure: Rebuild.
        * Makefile.in: Rebuild dependencies.
index 65d25f79fa41ad48cb1c1bec2bc4db720ef5c24a..3a0eb41c6a84ae8005209db51a5d30462b974e97 100644 (file)
@@ -138,7 +138,7 @@ CFILES = addr2line.c ar.c arsup.c bucomm.c coffdump.c coffgrok.c debug.c \
        maybe-strip.c nlmconv.c nm.c not-ranlib.c not-strip.c \
        objcopy.c objdump.c prdbg.c rdcoff.c rddbg.c size.c srconv.c \
        stabs.c strings.c sysdump.c version.c wrstabs.c \
-       windres.c resrc.c
+       windres.c resrc.c rescoff.c
 
 GENERATED_CFILES = \
        underscore.c arparse.c arlex.c sysroff.c sysinfo.c syslex.c \
@@ -409,7 +409,7 @@ nlmconv.o: nlmconv.c $(INCDIR)/coff/sym.h $(INCDIR)/coff/ecoff.h
 $(NLMCONV_PROG): nlmconv.o nlmheader.o $(ADDL_DEPS)
        $(HLDENV) $(CC) $(HLDFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ nlmconv.o nlmheader.o $(ADDL_LIBS) $(EXTRALIBS)
 
-WINDRES_OBJS = windres.o resrc.o rcparse.o rclex.o
+WINDRES_OBJS = windres.o resrc.o rescoff.o rcparse.o rclex.o
 
 $(WINDRES_PROG): $(WINDRES_OBJS) $(ADDL_DEPS)
        $(HLDENV) $(CC) $(HLDFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(WINDRES_OBJS) $(ADDL_LIBS) $(EXTRALIBS)
@@ -766,6 +766,10 @@ windres.o: windres.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
 resrc.o: resrc.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
   bucomm.h config.h $(INCDIR)/fopen-same.h $(INCDIR)/libiberty.h \
   windres.h
+rescoff.o: rescoff.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
+  bucomm.h config.h $(INCDIR)/fopen-same.h $(INCDIR)/libiberty.h \
+  windres.h $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h \
+  $(INCDIR)/bfdlink.h
 underscore.o: underscore.c
 arparse.o: arparse.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
   bucomm.h config.h $(INCDIR)/fopen-same.h arsup.h
diff --git a/binutils/rescoff.c b/binutils/rescoff.c
new file mode 100644 (file)
index 0000000..65df9bf
--- /dev/null
@@ -0,0 +1,342 @@
+/* resrc.c -- read and write Windows rc files.
+   Copyright 1997 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support.
+
+   This file is part of GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+/* This file contains function that read and write Windows resources
+   in COFF files.  */
+
+#include "bfd.h"
+#include "bucomm.h"
+#include "libiberty.h"
+#include "windres.h"
+
+/* In order to use the address of a resource data entry, we need to
+   get the image base of the file.  Right now we extract it from
+   internal BFD information.  FIXME.  */
+
+#include "coff/internal.h"
+#include "libcoff.h"
+
+/* Information we extract from the file.  */
+
+struct coff_file_info
+{
+  /* File name.  */
+  const char *filename;
+  /* Data read from the file.  */
+  const bfd_byte *data;
+  /* End of data read from file.  */
+  const bfd_byte *data_end;
+  /* Address of the resource section minus the image base of the file.  */
+  bfd_vma secaddr;
+  /* Non-zero if the file is big endian.  */
+  int big_endian;
+};
+
+/* A resource directory table in a COFF file.  */
+
+struct extern_res_directory
+{
+  /* Characteristics.  */
+  bfd_byte characteristics[4];
+  /* Time stamp.  */
+  bfd_byte time[4];
+  /* Major version number.  */
+  bfd_byte major[2];
+  /* Minor version number.  */
+  bfd_byte minor[2];
+  /* Number of named directory entries.  */
+  bfd_byte name_count[2];
+  /* Number of directory entries with IDs.  */
+  bfd_byte id_count[2];
+};
+
+/* A resource directory entry in a COFF file.  */
+
+struct extern_res_entry
+{
+  /* Name or ID.  */
+  bfd_byte name[4];
+  /* Address of resource entry or subdirectory.  */
+  bfd_byte rva[4];
+};
+
+/* A resource data entry in a COFF file.  */
+
+struct extern_res_data
+{
+  /* Address of resource data.  This is apparently a file relative
+     address, rather than a section offset.  */
+  bfd_byte rva[4];
+  /* Size of resource data.  */
+  bfd_byte size[4];
+  /* Code page.  */
+  bfd_byte codepage[4];
+  /* Reserved.  */
+  bfd_byte reserved[4];
+};
+
+/* Macros to swap in values.  */
+
+#define get_16(fi, s) ((fi)->big_endian ? bfd_getb16 (s) : bfd_getl16 (s))
+#define get_32(fi, s) ((fi)->big_endian ? bfd_getb32 (s) : bfd_getl32 (s))
+
+/* Local functions.  */
+
+static void overrun PARAMS ((const struct coff_file_info *, const char *));
+static struct res_directory *read_coff_res_dir
+  PARAMS ((const bfd_byte *, const struct coff_file_info *));
+static struct res_resource *read_coff_data_entry
+  PARAMS ((const bfd_byte *, const struct coff_file_info *));
+\f
+/* Read the resources in a COFF file.  */
+
+struct res_directory *
+read_coff_rsrc (filename, target)
+     const char *filename;
+     const char *target;
+{
+  bfd *abfd;
+  char **matching;
+  asection *sec;
+  bfd_size_type size;
+  bfd_byte *data;
+  struct coff_file_info finfo;
+
+  abfd = bfd_openr (filename, target);
+  if (abfd == NULL)
+    bfd_fatal (filename);
+
+  if (! bfd_check_format_matches (abfd, bfd_object, &matching))
+    {
+      bfd_nonfatal (bfd_get_filename (abfd));
+      if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
+       list_matching_formats (matching);
+      xexit (1);
+    }
+
+  sec = bfd_get_section_by_name (abfd, ".rsrc");
+  if (sec == NULL)
+    {
+      fprintf (stderr, "%s: %s: no resource section\n", program_name,
+              filename);
+      xexit (1);
+    }
+
+  size = bfd_section_size (abfd, sec);
+  data = (bfd_byte *) xmalloc (size);
+
+  if (! bfd_get_section_contents (abfd, sec, data, 0, size))
+    bfd_fatal ("can't read resource section");
+
+  finfo.filename = filename;
+  finfo.data = data;
+  finfo.data_end = data + size;
+  finfo.secaddr = (bfd_get_section_vma (abfd, sec)
+                  - pe_data (abfd)->pe_opthdr.ImageBase);
+  finfo.big_endian = bfd_big_endian (abfd);
+
+  bfd_close (abfd);
+
+  /* Now just read in the top level resource directory.  Note that we
+     don't free data, since we create resource entries that point into
+     it.  If we ever want to free up the resource information we read,
+     this will have to be cleaned up.  */
+
+  return read_coff_res_dir (data, &finfo);
+}
+
+/* Give an error if we are out of bounds.  */
+
+static void
+overrun (finfo, msg)
+     const struct coff_file_info *finfo;
+     const char *msg;
+{
+  fatal ("%s: %s: address out of bounds", finfo->filename, msg);
+}
+
+/* Read a resource directory.  */
+
+static struct res_directory *
+read_coff_res_dir (data, finfo)
+     const bfd_byte *data;
+     const struct coff_file_info *finfo;
+{
+  const struct extern_res_directory *erd;
+  struct res_directory *rd;
+  int name_count, id_count, i;
+  struct res_entry **pp;
+  const struct extern_res_entry *ere;
+
+  if (finfo->data_end - data < sizeof (struct extern_res_directory))
+    overrun (finfo, "directory");
+
+  erd = (const struct extern_res_directory *) data;
+
+  rd = (struct res_directory *) xmalloc (sizeof *rd);
+  rd->characteristics = get_32 (finfo, erd->characteristics);
+  rd->time = get_32 (finfo, erd->time);
+  rd->major = get_16 (finfo, erd->major);
+  rd->minor = get_16 (finfo, erd->minor);
+  rd->entries = NULL;
+
+  name_count = get_16 (finfo, erd->name_count);
+  id_count = get_16 (finfo, erd->id_count);
+
+  pp = &rd->entries;
+
+  /* The resource directory entries immediately follow the directory
+     table.  */
+  ere = (const struct extern_res_entry *) (erd + 1);
+
+  for (i = 0; i < name_count; i++, ere++)
+    {
+      unsigned long name, rva;
+      struct res_entry *re;
+      const bfd_byte *ers;
+      int length, j;
+
+      if ((const bfd_byte *) ere >= finfo->data_end)
+       overrun (finfo, "named directory entry");
+
+      name = get_32 (finfo, ere->name);
+      rva = get_32 (finfo, ere->rva);
+
+      /* For some reason the high bit in NAME is set.  */
+      name &=~ 0x80000000;
+
+      if (name > finfo->data_end - finfo->data)
+       overrun (finfo, "directory entry name");
+
+      ers = finfo->data + name;
+
+      re = (struct res_entry *) xmalloc (sizeof *re);
+      re->next = NULL;
+      re->id.named = 1;
+      length = get_16 (finfo, ers);
+      re->id.u.n.length = length;
+      re->id.u.n.name = ((unsigned short *)
+                        xmalloc (length * sizeof (unsigned short)));
+      for (j = 0; j < length; j++)
+       re->id.u.n.name[j] = get_16 (finfo, ers + j * 2 + 2);
+
+      if ((rva & 0x80000000) != 0)
+       {
+         rva &=~ 0x80000000;
+         if (rva >= finfo->data_end - finfo->data)
+           overrun (finfo, "named subdirectory");
+         re->subdir = 1;
+         re->u.dir = read_coff_res_dir (finfo->data + rva, finfo);
+       }
+      else
+       {
+         if (rva >= finfo->data_end - finfo->data)
+           overrun (finfo, "named resource");
+         re->subdir = 0;
+         re->u.res = read_coff_data_entry (finfo->data + rva, finfo);
+       }
+
+      *pp = re;
+      pp = &re->next;
+    }
+
+  for (i = 0; i < id_count; i++, ere++)
+    {
+      unsigned long name, rva;
+      struct res_entry *re;
+
+      if ((const bfd_byte *) ere >= finfo->data_end)
+       overrun (finfo, "ID directory entry");
+
+      name = get_32 (finfo, ere->name);
+      rva = get_32 (finfo, ere->rva);
+
+      re = (struct res_entry *) xmalloc (sizeof *re);
+      re->next = NULL;
+      re->id.named = 0;
+      re->id.u.id = name;
+
+      if ((rva & 0x80000000) != 0)
+       {
+         rva &=~ 0x80000000;
+         if (rva >= finfo->data_end - finfo->data)
+           overrun (finfo, "ID subdirectory");
+         re->subdir = 1;
+         re->u.dir = read_coff_res_dir (finfo->data + rva, finfo);
+       }
+      else
+       {
+         if (rva >= finfo->data_end - finfo->data)
+           overrun (finfo, "ID resource");
+         re->subdir = 0;
+         re->u.res = read_coff_data_entry (finfo->data + rva, finfo);
+       }
+
+      *pp = re;
+      pp = &re->next;
+    }
+
+  return rd;
+}
+
+/* Read a resource data entry.  */
+
+static struct res_resource *
+read_coff_data_entry (data, finfo)
+     const bfd_byte *data;
+     const struct coff_file_info *finfo;
+{
+  const struct extern_res_data *erd;
+  struct res_resource *r;
+  unsigned long size, rva;
+  const bfd_byte *resdata;
+
+  if (finfo->data_end - data < sizeof (struct extern_res_data))
+    overrun (finfo, "data entry");
+
+  erd = (const struct extern_res_data *) data;
+
+  r = (struct res_resource *) xmalloc (sizeof *r);
+  memset (&r->res_info, 0, sizeof (struct res_res_info));
+  r->coff_info.codepage = get_32 (finfo, erd->codepage);
+  r->coff_info.reserved = get_32 (finfo, erd->reserved);
+
+  size = get_32 (finfo, erd->size);
+  rva = get_32 (finfo, erd->rva);
+  if (rva < finfo->secaddr
+      || rva - finfo->secaddr >= finfo->data_end - finfo->data)
+    overrun (finfo, "resource data");
+
+  resdata = finfo->data + (rva - finfo->secaddr);
+
+  r->type = RES_TYPE_USERDATA;
+  r->u.userdata = ((struct rcdata_data *)
+                  xmalloc (sizeof (struct rcdata_data)));
+  r->u.userdata->first = ((struct rcdata_item *)
+                         xmalloc (sizeof (struct rcdata_item)));
+  r->u.userdata->last = r->u.userdata->first;
+  r->u.userdata->first->next = NULL;
+  r->u.userdata->first->type = RCDATA_BUFFER;
+  r->u.userdata->first->u.buffer.length = size;
+  r->u.userdata->first->u.buffer.data = (unsigned char *) resdata;
+
+  return r;
+}
index 64c6c787ea6dd93dd6c40b53405add17cb75ba95..fb340fa00410077426ce91f47bb8a3440712e52a 100644 (file)
@@ -2009,7 +2009,7 @@ write_rc_rcdata (e, rcdata, ind)
                else
                  {
                    fprintf (e, ",\n");
-                   indent (e, ind);
+                   indent (e, ind + 2);
                  }
                fprintf (e, "%luL", l);
              }
@@ -2024,7 +2024,7 @@ write_rc_rcdata (e, rcdata, ind)
                else
                  {
                    fprintf (e, ",\n");
-                   indent (e, ind);
+                   indent (e, ind + 2);
                  }
                fprintf (e, "%d", i);
                i += 2;
@@ -2037,7 +2037,7 @@ write_rc_rcdata (e, rcdata, ind)
                else
                  {
                    fprintf (e, ",\n");
-                   indent (e, ind);
+                   indent (e, ind + 2);
                  }
                if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
                    && isprint (ri->u.buffer.data[i]))
index d08fb97a82d4eea030f9d045616f4242126effc8..bd17aaf0e84eee1bd3d5dffb39217064ef5140ab 100644 (file)
@@ -306,22 +306,9 @@ res_id_print (stream, id, quote)
     fprintf (stream, "%lu", id.u.id);
   else
     {
-      unsigned short *s, *se;
-
       if (quote)
        putc ('"', stream);
-      s = id.u.n.name;
-      se = s + id.u.n.length;
-      while (s < se)
-       {
-         if (*s == '"')
-           fprintf (stream, "\\\"");
-         else if ((*s & 0xff) == *s && isprint (*s))
-           putc (*s, stream);
-         else
-           fprintf (stream, "\\%03o", *s);
-         ++s;
-       }
+      unicode_print (stream, id.u.n.name, id.u.n.length);
       if (quote)
        putc ('"', stream);
     }
@@ -600,8 +587,8 @@ format_from_filename (filename, input)
 
   fclose (e);
 
-  /* A PE executable starts with 0x4d 0x5a 0x90 0x00.  */
-  if (b1 == 0x4d && b2 == 0x5a && b3 == 0x90 && b4 == 0)
+  /* A PE executable starts with 0x4d 0x5a.  */
+  if (b1 == 0x4d && b2 == 0x5a)
     return RES_FORMAT_COFF;
 
   /* A COFF .o file starts with a COFF magic number.  */
@@ -885,15 +872,6 @@ read_res_file (filename)
   return NULL;
 }
 
-struct res_directory *
-read_coff_rsrc (filename, target)
-     const char *filename;
-     const char *target;
-{
-  fatal ("read_coff_rsrc unimplemented");
-  return NULL;
-}
-
 void
 write_res_file (filename, resources)
      const char *filename;