Tue Oct 6 18:20:10 1998 Geoffrey Noer <noer@cygnus.com>
authorGeoffrey Noer <noer@cygnus>
Wed, 7 Oct 1998 01:21:02 +0000 (01:21 +0000)
committerGeoffrey Noer <noer@cygnus>
Wed, 7 Oct 1998 01:21:02 +0000 (01:21 +0000)
        From Anders Norlander <anorland@hem2.passagen.se>.

        * resres.c: New file.  Implementation of read_res_file and
        write_res_file functions for windres.
        * rcparse.y: Handle CONTROL's with named classes.
        * resbin.c: Bug in res_to_bin_dialog and bin_to_res_dialog
        when dialog is extended: The version and signature fields should
        be reversed (despite what the docs say). Id is 32 bits long in
        extended dialogs.
        * resrc.c (write_rc_dialog): properly print controls with named
        classes.
        * windres.c (read_res_file, write_res_file): Remove stubs.
        * resres.c (write_res): Rename RT_ACCELERATORS to RT_ACCELERATOR.
        * Makefile.in (windres_SOURCES): Add resres.c.
        (windres_OBJECTS): Add resres.o.

binutils/ChangeLog
binutils/Makefile.am
binutils/Makefile.in
binutils/resres.c [new file with mode: 0644]

index 112149e..998c18b 100644 (file)
@@ -1,3 +1,21 @@
+Tue Oct  6 18:20:10 1998  Geoffrey Noer  <noer@cygnus.com>
+        From Anders Norlander <anorland@hem2.passagen.se>.
+        * resres.c: New file.  Implementation of read_res_file and
+        write_res_file functions for windres.
+        * rcparse.y: Handle CONTROL's with named classes.
+        * resbin.c: Bug in res_to_bin_dialog and bin_to_res_dialog
+        when dialog is extended: The version and signature fields should
+        be reversed (despite what the docs say). Id is 32 bits long in
+        extended dialogs.
+        * resrc.c (write_rc_dialog): properly print controls with named
+        classes.
+        * windres.c (read_res_file, write_res_file): Remove stubs.
+        * resres.c (write_res): Rename RT_ACCELERATORS to RT_ACCELERATOR.
+        * Makefile.in (windres_SOURCES): Add resres.c.
+        (windres_OBJECTS): Add resres.o.
+
 Sun Oct  4 20:34:42 1998  Ian Lance Taylor  <ian@cygnus.com>
 
        From Nokubi Hirotaka <hnokubi@yyy.or.jp>:
index 8711cb5..4f43424 100644 (file)
@@ -82,7 +82,8 @@ 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 rescoff.c resbin.c winduni.c readelf.c
+       windres.c resrc.c rescoff.c resbin.c winduni.c readelf.c \
+       resres.c
 
 GENERATED_CFILES = \
        underscore.c arparse.c arlex.c sysroff.c sysinfo.c syslex.c \
@@ -252,7 +253,7 @@ nlmconv.o: nlmconv.c $(INCDIR)/coff/sym.h $(INCDIR)/coff/ecoff.h
 nlmconv_SOURCES = nlmconv.c nlmheader.y $(BULIBS)
 
 windres_SOURCES = windres.c resrc.c rescoff.c resbin.c rcparse.y rclex.l \
-       winduni.c $(BULIBS)
+       winduni.c resres.c $(BULIBS)
 windres_LDADD = $(BFDLIB) $(LIBIBERTY) @LEXLIB@ $(INTLLIBS)
 
 DISTSTUFF = arparse.c arparse.h arlex.c nlmheader.c sysinfo.c sysinfo.h \
@@ -338,9 +339,9 @@ install-exec-local: $(bin_PROGRAMS) $(noinst_PROGRAMS)
        for i in $(TOOL_PROGS); do \
          if [ -f $$i$(EXEEXT) ]; then \
            j=`echo $$i | sed -e 's/-new//'`; \
-           rm -f $(tooldir)/bin/$$j$(EXEEXT); \
            k=`echo $$j | sed '$(transform)'`; \
            if [ "$(bindir)/$$k$(EXEEXT)" != "$(tooldir)/bin/$$j$(EXEEXT)" ]; then \
+             rm -f $(tooldir)/bin/$$j$(EXEEXT); \
              ln $(bindir)/$$k$(EXEEXT) $(tooldir)/bin/$$j$(EXEEXT) >/dev/null 2>/dev/null \
                || $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$i$(EXEEXT) $(tooldir)/bin/$$j$(EXEEXT); \
            fi; \
@@ -444,6 +445,7 @@ rescoff.o: rescoff.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
 resbin.o: resbin.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
   bucomm.h config.h $(INCDIR)/fopen-same.h $(INCDIR)/libiberty.h \
   windres.h winduni.h
+resres.o: resres.c windres.h
 winduni.o: winduni.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
   bucomm.h config.h $(INCDIR)/fopen-same.h winduni.h
 readelf.o: readelf.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
index 64a4225..a17bdd8 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated automatically by automake 1.3 from Makefile.am
+# Makefile.in generated automatically by automake 1.3b from Makefile.am
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
 # This Makefile.in is free software; the Free Software Foundation
@@ -32,7 +32,7 @@ mandir = @mandir@
 includedir = @includedir@
 oldincludedir = /usr/include
 
-DISTDIR =
+DESTDIR =
 
 pkgdatadir = $(datadir)/@PACKAGE@
 pkglibdir = $(libdir)/@PACKAGE@
@@ -64,18 +64,46 @@ host_triplet = @host@
 target_alias = @target_alias@
 target_triplet = @target@
 AR = @AR@
+AS = @AS@
 BUILD_DLLTOOL = @BUILD_DLLTOOL@
+BUILD_DLLWRAP = @BUILD_DLLWRAP@
 BUILD_NLMCONV = @BUILD_NLMCONV@
 BUILD_SRCONV = @BUILD_SRCONV@
 BUILD_WINDRES = @BUILD_WINDRES@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
 CC = @CC@
+DATADIRNAME = @DATADIRNAME@
+DLLTOOL = @DLLTOOL@
 DLLTOOL_DEFS = @DLLTOOL_DEFS@
 EXEEXT = @EXEEXT@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GT_NO = @GT_NO@
+GT_YES = @GT_YES@
 HDEFINES = @HDEFINES@
+INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
+INSTOBJEXT = @INSTOBJEXT@
+INTLDEPS = @INTLDEPS@
+INTLOBJS = @INTLOBJS@
+LD = @LD@
 LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
 NLMCONV_DEFS = @NLMCONV_DEFS@
+NM = @NM@
+PACKAGE = @PACKAGE@
+POFILES = @POFILES@
+POSUB = @POSUB@
 RANLIB = @RANLIB@
 UNDERSCORE = @UNDERSCORE@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+l = @l@
 
 INTLLIBS = @INTLLIBS@
 
@@ -154,7 +182,8 @@ 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 rescoff.c resbin.c winduni.c readelf.c
+       windres.c resrc.c rescoff.c resbin.c winduni.c readelf.c \
+       resres.c
 
 GENERATED_CFILES = \
        underscore.c arparse.c arlex.c sysroff.c sysinfo.c syslex.c \
@@ -239,7 +268,7 @@ sysdump_SOURCES = sysdump.c $(BULIBS)
 nlmconv_SOURCES = nlmconv.c nlmheader.y $(BULIBS)
 
 windres_SOURCES = windres.c resrc.c rescoff.c resbin.c rcparse.y rclex.l \
-       winduni.c $(BULIBS)
+       winduni.c resres.c $(BULIBS)
 windres_LDADD = $(BFDLIB) $(LIBIBERTY) @LEXLIB@ $(INTLLIBS)
 
 DISTSTUFF = arparse.c arparse.h arlex.c nlmheader.c sysinfo.c sysinfo.h \
@@ -291,7 +320,7 @@ filemode.o
 dlltool_DEPENDENCIES =  ../bfd/libbfd.la ../libiberty/libiberty.a
 dlltool_LDFLAGS = 
 windres_OBJECTS =  windres.o resrc.o rescoff.o resbin.o rcparse.o \
-rclex.o winduni.o bucomm.o version.o filemode.o
+rclex.o winduni.o resres.o bucomm.o version.o filemode.o
 windres_DEPENDENCIES =  ../bfd/libbfd.la ../libiberty/libiberty.a
 windres_LDFLAGS = 
 size_OBJECTS =  size.o bucomm.o version.o filemode.o
@@ -344,10 +373,9 @@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
 LEXLIB = @LEXLIB@
 YLWRAP = $(top_srcdir)/../ylwrap
 CFLAGS = @CFLAGS@
-COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
-LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
-LINK = $(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -o $@
-MAKEINFO = `if test -f $(top_builddir)/../texinfo/makeinfo/makeinfo; then echo $(top_builddir)/../texinfo/makeinfo/makeinfo; else echo makeinfo; fi`
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LINK = $(LIBTOOL) --mode=link $(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
 TEXI2DVI = `if test -f $(top_srcdir)/../texinfo/util/texi2dvi; then echo $(top_srcdir)/../texinfo/util/texi2dvi; else echo texi2dvi; fi`
 TEXINFO_TEX = $(top_srcdir)/../texinfo/texinfo.tex
 INFO_DEPS = binutils.info
@@ -363,9 +391,6 @@ configure.in deflex.c defparse.c nlmheader.c rclex.c rcparse.c \
 stamp-h.in
 
 
-PACKAGE = @PACKAGE@
-VERSION = @VERSION@
-
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
 TAR = tar
@@ -553,14 +578,14 @@ strip-new$(EXEEXT): $(strip_new_OBJECTS) $(strip_new_DEPENDENCIES)
        @rm -f strip-new$(EXEEXT)
        $(LINK) $(strip_new_LDFLAGS) $(strip_new_OBJECTS) $(strip_new_LDADD) $(LIBS)
 .y.c:
-       $(SHELL) $(YLWRAP) "$(YACC)" $< y.tab.c $*.c y.tab.h $*.h -- $(YFLAGS)
+       $(SHELL) $(YLWRAP) "$(YACC)" $< y.tab.c $*.c y.tab.h $*.h -- $(AM_YFLAGS) $(YFLAGS)
 defparse.h: defparse.c
 arparse.h: arparse.c
 rcparse.h: rcparse.c
 nlmheader.h: nlmheader.c
 
 .l.c:
-       $(SHELL) $(YLWRAP) "$(LEX)" $< $(LEX_OUTPUT_ROOT).c $@ -- $(LFLAGS)
+       $(SHELL) $(YLWRAP) "$(LEX)" $< $(LEX_OUTPUT_ROOT).c $@ -- $(AM_LFLAGS) $(LFLAGS)
 
 binutils.info: binutils.texi
 binutils.dvi: binutils.texi
@@ -881,7 +906,7 @@ uninstall: uninstall-recursive uninstall-am
 install-strip:
        $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
 installdirs: installdirs-recursive
-       $(mkinstalldirs)  $(DATADIR)$(bindir) $(DESTDIR)$(mandir)/man1
+       $(mkinstalldirs)  $(DESTDIR)$(bindir) $(DESTDIR)$(mandir)/man1
 
 
 mostlyclean-generic:
@@ -891,13 +916,12 @@ clean-generic:
        -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
 
 distclean-generic:
-       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f Makefile $(CONFIG_CLEAN_FILES)
        -rm -f config.cache config.log stamp-h stamp-h[0-9]*
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
 
 maintainer-clean-generic:
-       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
-       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+       -test -z "defparsehdefparsecarparseharparsecrcparsehrcparsecnlmheaderhnlmheadercrclexldeflexlarlexl$(MAINTAINERCLEANFILES)" || rm -f defparseh defparsec arparseh arparsec rcparseh rcparsec nlmheaderh nlmheaderc rclexl deflexl arlexl $(MAINTAINERCLEANFILES)
 mostlyclean-am:  mostlyclean-hdr mostlyclean-binPROGRAMS \
                mostlyclean-noinstPROGRAMS mostlyclean-compile \
                mostlyclean-libtool mostlyclean-aminfo mostlyclean-tags \
@@ -1110,9 +1134,9 @@ install-exec-local: $(bin_PROGRAMS) $(noinst_PROGRAMS)
        for i in $(TOOL_PROGS); do \
          if [ -f $$i$(EXEEXT) ]; then \
            j=`echo $$i | sed -e 's/-new//'`; \
-           rm -f $(tooldir)/bin/$$j$(EXEEXT); \
            k=`echo $$j | sed '$(transform)'`; \
            if [ "$(bindir)/$$k$(EXEEXT)" != "$(tooldir)/bin/$$j$(EXEEXT)" ]; then \
+             rm -f $(tooldir)/bin/$$j$(EXEEXT); \
              ln $(bindir)/$$k$(EXEEXT) $(tooldir)/bin/$$j$(EXEEXT) >/dev/null 2>/dev/null \
                || $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$i$(EXEEXT) $(tooldir)/bin/$$j$(EXEEXT); \
            fi; \
@@ -1216,6 +1240,7 @@ rescoff.o: rescoff.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
 resbin.o: resbin.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
   bucomm.h config.h $(INCDIR)/fopen-same.h $(INCDIR)/libiberty.h \
   windres.h winduni.h
+resres.o: resres.c windres.h
 winduni.o: winduni.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
   bucomm.h config.h $(INCDIR)/fopen-same.h winduni.h
 readelf.o: readelf.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
diff --git a/binutils/resres.c b/binutils/resres.c
new file mode 100644 (file)
index 0000000..f79e814
--- /dev/null
@@ -0,0 +1,659 @@
+/* resres.c: read_res_file and write_res_file implementation for windres.
+
+   Copyright 1997, 1998 Free Software Foundation, Inc.
+   Written by Anders Norlander <anorland@hem2.passagen.se>.
+
+   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.  */
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "windres.h"
+
+struct res_hdr
+  {
+    unsigned long data_size;
+    unsigned long header_size;
+  };
+
+static void write_res_directory
+  PARAMS ((const struct res_directory *,
+          const struct res_id *, const struct res_id *,
+          int *, int));
+static void write_res_resource
+  PARAMS ((const struct res_id *, const struct res_id *,
+          const struct res_resource *, int *));
+static void write_res_bin
+  PARAMS ((const struct res_resource *, const struct res_id *,
+          const struct res_id *, const struct res_res_info *));
+
+static void write_res_id PARAMS ((const struct res_id *));
+static void write_res_info PARAMS ((const struct res_res_info *));
+static void write_res_data PARAMS ((const void *, size_t, int));
+static void write_res_header
+  PARAMS ((unsigned long, const struct res_id *, const struct res_id *,
+          const struct res_res_info *));
+
+static int read_resource_entry PARAMS ((void));
+static void read_res_data PARAMS ((void *, size_t, int));
+static void read_res_id PARAMS ((struct res_id *));
+static unichar *read_unistring PARAMS ((int *));
+static void skip_null_resource PARAMS ((void));
+
+static unsigned long get_id_size PARAMS ((const struct res_id *));
+static void res_align_file PARAMS ((void));
+
+static void
+  res_add_resource
+  PARAMS ((struct res_resource *, const struct res_id *,
+          const struct res_id *, int, int));
+
+void
+  res_append_resource
+  PARAMS ((struct res_directory **, struct res_resource *,
+          int, const struct res_id *, int));
+
+static struct res_directory *resources = NULL;
+
+static FILE *fres;
+static const char *filename;
+
+extern char *program_name;
+
+/* Read resource file */
+struct res_directory *
+read_res_file (fn)
+     const char *fn;
+{
+  filename = fn;
+  fres = fopen (filename, "rb");
+  if (fres == NULL)
+    fatal ("can't open `%s' for output: %s", filename, strerror (errno));
+
+  skip_null_resource ();
+
+  while (read_resource_entry ())
+    ;
+
+  fclose (fres);
+
+  return resources;
+}
+
+/* Write resource file */
+void
+write_res_file (fn, resdir)
+     const char *fn;
+     const struct res_directory *resdir;
+{
+  int language;
+  static const unsigned char sign[] =
+  {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+   0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+  long fpos;
+  struct res_entry *e;
+  int i;
+
+  filename = fn;
+
+  fres = fopen (filename, "wb");
+  if (fres == NULL)
+    fatal ("can't open `%s' for output: %s", filename, strerror (errno));
+
+  /* Write 32 bit resource signature */
+  write_res_data (sign, sizeof (sign), 1);
+
+  /* write resources */
+
+  language = -1;
+  write_res_directory (resdir, (const struct res_id *) NULL,
+                      (const struct res_id *) NULL, &language, 1);
+
+  /* end file on DWORD boundary */
+  fpos = ftell (fres);
+  if (fpos % 4)
+    write_res_data (sign, fpos % 4, 1);
+
+  fclose (fres);
+}
+
+/* Read a resource entry, returns 0 when all resources are read */
+static int
+read_resource_entry (void)
+{
+  struct res_id type;
+  struct res_id name;
+  struct res_res_info resinfo;
+  struct res_hdr reshdr;
+  enum res_type rtype;
+  long version;
+  long n;
+  void *buff;
+
+  struct res_resource *r;
+
+  res_align_file ();
+
+  /* Read header */
+  if (fread (&reshdr, sizeof (reshdr), 1, fres) != 1)
+    return 0;
+
+  /* read resource type */
+  read_res_id (&type);
+  /* read resource id */
+  read_res_id (&name);
+
+  res_align_file ();
+
+  /* Read additional resource header */
+  read_res_data (&resinfo.version, sizeof (resinfo.version), 1);
+  read_res_data (&resinfo.memflags, sizeof (resinfo.memflags), 1);
+  read_res_data (&resinfo.language, sizeof (resinfo.language), 1);
+  read_res_data (&version, sizeof (version), 1);
+  read_res_data (&resinfo.characteristics, sizeof (resinfo.characteristics), 1);
+
+  res_align_file ();
+
+  /* Allocate buffer for data */
+  buff = res_alloc (reshdr.data_size);
+  /* Read data */
+  read_res_data (buff, reshdr.data_size, 1);
+  /* Convert binary data to resource */
+  r = bin_to_res (type, buff, reshdr.data_size, 0);
+  r->res_info = resinfo;
+  /* Add resource to resource directory */
+  res_add_resource (r, &type, &name, resinfo.language, 0);
+
+  return 1;
+}
+
+/* write resource directory to binary resource file */
+static void
+write_res_directory (rd, type, name, language, level)
+     const struct res_directory *rd;
+     const struct res_id *type;
+     const struct res_id *name;
+     int *language;
+     int level;
+{
+  const struct res_entry *re;
+
+  for (re = rd->entries; re != NULL; re = re->next)
+    {
+      switch (level)
+       {
+       case 1:
+         /* If we're at level 1, the key of this resource is the
+            type.  This normally duplicates the information we have
+            stored with the resource itself, but we need to remember
+            the type if this is a user define resource type.  */
+         type = &re->id;
+         break;
+
+       case 2:
+         /* If we're at level 2, the key of this resource is the name
+            we are going to use in the rc printout. */
+         name = &re->id;
+         break;
+
+       case 3:
+         /* If we're at level 3, then this key represents a language.
+            Use it to update the current language.  */
+         if (!re->id.named
+             && re->id.u.id != *language
+             && (re->id.u.id & 0xffff) == re->id.u.id)
+           {
+             *language = re->id.u.id;
+           }
+         break;
+
+       default:
+         break;
+       }
+
+      if (re->subdir)
+       write_res_directory (re->u.dir, type, name, language, level + 1);
+      else
+       {
+         if (level == 3)
+           {
+             /* This is the normal case: the three levels are
+                TYPE/NAME/LANGUAGE.  NAME will have been set at level
+                2, and represents the name to use.  We probably just
+                set LANGUAGE, and it will probably match what the
+                resource itself records if anything.  */
+             write_res_resource (type, name, re->u.res, language);
+           }
+         else
+           {
+             fprintf (stderr, "// Resource at unexpected level %d\n", level);
+             write_res_resource (type, (struct res_id *) NULL, re->u.res,
+                                 language);
+           }
+       }
+    }
+
+}
+
+static void
+write_res_resource (type, name, res, language)
+     const struct res_id *type;
+     const struct res_id *name;
+     const struct res_resource *res;
+     int *language;
+{
+  int rt;
+
+  switch (res->type)
+    {
+    default:
+      abort ();
+
+    case RES_TYPE_ACCELERATOR:
+      rt = RT_ACCELERATOR;
+      break;
+
+    case RES_TYPE_BITMAP:
+      rt = RT_BITMAP;
+      break;
+
+    case RES_TYPE_CURSOR:
+      rt = RT_CURSOR;
+      break;
+
+    case RES_TYPE_GROUP_CURSOR:
+      rt = RT_GROUP_CURSOR;
+      break;
+
+    case RES_TYPE_DIALOG:
+      rt = RT_DIALOG;
+      break;
+
+    case RES_TYPE_FONT:
+      rt = RT_FONT;
+      break;
+
+    case RES_TYPE_FONTDIR:
+      rt = RT_FONTDIR;
+      break;
+
+    case RES_TYPE_ICON:
+      rt = RT_ICON;
+      break;
+
+    case RES_TYPE_GROUP_ICON:
+      rt = RT_GROUP_ICON;
+      break;
+
+    case RES_TYPE_MENU:
+      rt = RT_MENU;
+      break;
+
+    case RES_TYPE_MESSAGETABLE:
+      rt = RT_MESSAGETABLE;
+      break;
+
+    case RES_TYPE_RCDATA:
+      rt = RT_RCDATA;
+      break;
+
+    case RES_TYPE_STRINGTABLE:
+      rt = RT_STRING;
+      break;
+
+    case RES_TYPE_USERDATA:
+      rt = 0;
+      break;
+
+    case RES_TYPE_VERSIONINFO:
+      rt = RT_VERSION;
+      break;
+    }
+
+  if (rt != 0
+      && type != NULL
+      && (type->named || type->u.id != rt))
+    {
+      fprintf (stderr, "// Unexpected resource type mismatch: ");
+      res_id_print (stderr, *type, 1);
+      fprintf (stderr, " != %d", rt);
+      abort ();
+    }
+
+  write_res_bin (res, type, name, &res->res_info);
+  return;
+}
+
+/* Write a resource in binary resource format */
+static void
+write_res_bin (res, type, name, resinfo)
+     const struct res_resource *res;
+     const struct res_id *type;
+     const struct res_id *name;
+     const struct res_res_info *resinfo;
+{
+  unsigned long datasize = 0;
+  const struct bindata *bin_rep, *data;
+
+  bin_rep = res_to_bin (res, 0);
+  for (data = bin_rep; data != NULL; data = data->next)
+    datasize += data->length;
+
+  write_res_header (datasize, type, name, resinfo);
+
+  for (data = bin_rep; data != NULL; data = data->next)
+    write_res_data (data->data, data->length, 1);
+}
+
+/* Get number of bytes needed to store an id in binary format */
+static unsigned long
+get_id_size (id)
+     const struct res_id *id;
+{
+  if (id->named)
+    return sizeof (unichar) * (id->u.n.length + 1);
+  else
+    return sizeof (unichar) * 2;
+}
+
+/* Write a resource header */
+static void
+write_res_header (datasize, type, name, resinfo)
+     unsigned long datasize;
+     const struct res_id *type;
+     const struct res_id *name;
+     const struct res_res_info *resinfo;
+{
+  struct res_hdr reshdr;
+  reshdr.data_size = datasize;
+  reshdr.header_size = 24 + get_id_size (type) + get_id_size (name);
+
+  res_align_file ();
+  write_res_data (&reshdr, sizeof (reshdr), 1);
+  write_res_id (type);
+  write_res_id (name);
+
+  res_align_file ();
+
+  write_res_info (resinfo);
+  res_align_file ();
+}
+
+
+/* Write data to file, abort on failure */
+static void
+write_res_data (data, size, count)
+     const void *data;
+     size_t size;
+     int count;
+{
+  if (fwrite (data, size, count, fres) != count)
+    fatal ("%s: %s: could not write to file", program_name, filename);
+}
+
+/* Read data from file, abort on failure */
+static void
+read_res_data (data, size, count)
+     void *data;
+     size_t size;
+     int count;
+{
+  if (fread (data, size, count, fres) != count)
+    fatal ("%s: %s: unexpected end of file", program_name, filename);
+}
+
+/* Write a resource id */
+static void
+write_res_id (id)
+     const struct res_id *id;
+{
+  if (id->named)
+    {
+      unsigned long len = id->u.n.length;
+      unichar null_term = 0;
+      write_res_data (id->u.n.name, len * sizeof (unichar), 1);
+      write_res_data (&null_term, sizeof (null_term), 1);
+    }
+  else
+    {
+      unsigned short i = 0xFFFF;
+      write_res_data (&i, sizeof (i), 1);
+      i = id->u.id;
+      write_res_data (&i, sizeof (i), 1);
+    }
+}
+
+/* Write resource info */
+static void
+write_res_info (info)
+     const struct res_res_info *info;
+{
+  write_res_data (&info->version, sizeof (info->version), 1);
+  write_res_data (&info->memflags, sizeof (info->memflags), 1);
+  write_res_data (&info->language, sizeof (info->language), 1);
+  write_res_data (&info->version, sizeof (info->version), 1);
+  write_res_data (&info->characteristics, sizeof (info->characteristics), 1);
+}
+
+/* read a resource identifier */
+void 
+read_res_id (id)
+     struct res_id *id;
+{
+  unsigned short ord;
+  unichar *id_s = NULL;
+  int len;
+
+  read_res_data (&ord, sizeof (ord), 1);
+  if (ord == 0xFFFF)           /* an ordinal id */
+    {
+      read_res_data (&ord, sizeof (ord), 1);
+      id->named = 0;
+      id->u.id = ord;
+    }
+  else
+    /* named id */
+    {
+      if (fseek (fres, -sizeof (ord), SEEK_CUR) != 0)
+       fatal ("%s: %s: could not seek in file", program_name, filename);
+      id_s = read_unistring (&len);
+      id->named = 1;
+      id->u.n.length = len;
+      id->u.n.name = id_s;
+    }
+}
+
+/* Read a null terminated UNICODE string */
+static unichar *
+read_unistring (len)
+     int *len;
+{
+  unichar *s;
+  unichar c;
+  unichar *p;
+  int n;
+  int l;
+
+  *len = 0;
+  l = 0;
+
+  /* there are hardly any names longer than 256 characters */
+  p = s = (unichar *) xmalloc (sizeof (unichar) * 256);
+  do
+    {
+      read_res_data (&c, sizeof (c), 1);
+      *p++ = c;
+      if (c != 0)
+       l++;
+    }
+  while (c != 0);
+  *len = l;
+  return s;
+}
+
+/* align file on DWORD boundary */
+static void
+res_align_file (void)
+{
+  if (fseek (fres, ftell (fres) % 4, SEEK_CUR) != 0)
+    fatal ("%s: %s: unable to align file", program_name, filename);
+}
+
+/* Check if file is a win32 binary resource file, if so
+   skip past the null resource. Returns 0 if successful, -1 on
+   error.
+ */
+static void
+skip_null_resource (void)
+{
+  struct res_hdr reshdr =
+  {0, 0};
+  read_res_data (&reshdr, sizeof (reshdr), 1);
+  if ((reshdr.data_size != 0) || (reshdr.header_size != 0x20))
+    goto skip_err;
+
+  /* Subtract size of HeaderSize and DataSize */
+  if (fseek (fres, reshdr.header_size - 8, SEEK_CUR) != 0)
+    goto skip_err;
+
+  return;
+
+skip_err:
+  fprintf (stderr, "%s: %s: Not a valid WIN32 resource file\n", program_name,
+          filename);
+  xexit (1);
+}
+
+/* Add a resource to resource directory */
+void
+res_add_resource (r, type, id, language, dupok)
+     struct res_resource *r;
+     const struct res_id *type;
+     const struct res_id *id;
+     int language;
+     int dupok;
+{
+  struct res_id a[3];
+
+  a[0] = *type;
+  a[1] = *id;
+  a[2].named = 0;
+  a[2].u.id = language;
+  res_append_resource (&resources, r, 3, a, dupok);
+}
+
+/* Append a resource to resource directory.
+   This is just copied from define_resource
+   and modified to add an existing resource.
+ */
+void
+res_append_resource (resources, resource, cids, ids, dupok)
+     struct res_directory **resources;
+     struct res_resource *resource;
+     int cids;
+     const struct res_id *ids;
+     int dupok;
+{
+  struct res_entry *re = NULL;
+  int i;
+
+  assert (cids > 0);
+  for (i = 0; i < cids; i++)
+    {
+      struct res_entry **pp;
+
+      if (*resources == NULL)
+       {
+         static unsigned long timeval;
+
+         /* Use the same timestamp for every resource created in a
+            single run.  */
+         if (timeval == 0)
+           timeval = time (NULL);
+
+         *resources = ((struct res_directory *)
+                       res_alloc (sizeof **resources));
+         (*resources)->characteristics = 0;
+         (*resources)->time = timeval;
+         (*resources)->major = 0;
+         (*resources)->minor = 0;
+         (*resources)->entries = NULL;
+       }
+
+      for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
+       if (res_id_cmp ((*pp)->id, ids[i]) == 0)
+         break;
+
+      if (*pp != NULL)
+       re = *pp;
+      else
+       {
+         re = (struct res_entry *) res_alloc (sizeof *re);
+         re->next = NULL;
+         re->id = ids[i];
+         if ((i + 1) < cids)
+           {
+             re->subdir = 1;
+             re->u.dir = NULL;
+           }
+         else
+           {
+             re->subdir = 0;
+             re->u.res = NULL;
+           }
+
+         *pp = re;
+       }
+
+      if ((i + 1) < cids)
+       {
+         if (!re->subdir)
+           {
+             fprintf (stderr, "%s: ", program_name);
+             res_ids_print (stderr, i, ids);
+             fprintf (stderr, ": expected to be a directory\n");
+             xexit (1);
+           }
+
+         resources = &re->u.dir;
+       }
+    }
+
+  if (re->subdir)
+    {
+      fprintf (stderr, "%s: ", program_name);
+      res_ids_print (stderr, cids, ids);
+      fprintf (stderr, ": expected to be a leaf\n");
+      xexit (1);
+    }
+
+  if (re->u.res != NULL)
+    {
+      if (dupok)
+       return;
+
+      fprintf (stderr, "%s: warning: ", program_name);
+      res_ids_print (stderr, cids, ids);
+      fprintf (stderr, ": duplicate value\n");
+    }
+
+  re->u.res = resource;
+}