bin2res: rewrite

Dimitrie O. Paun dimi at intelliware.ca
Wed Sep 17 19:36:22 CDT 2003


This one has been bugging me for a while...

ChangeLog
    Dimitrie O. Paun <dpaun at rogers.com>
    Complete rewrite of bin2res, for a cleaner codebase.
    Add online help describing how the program works.
    Sanitize command line options.


Index: tools/bin2res.c
===================================================================
RCS file: /var/cvs/wine/tools/bin2res.c,v
retrieving revision 1.15
diff -u -r1.15 bin2res.c
--- tools/bin2res.c	22 Aug 2003 05:05:56 -0000	1.15
+++ tools/bin2res.c	18 Sep 2003 00:31:56 -0000
@@ -3,8 +3,7 @@
  * Converting binary resources from/to *.rc files
  *
  * Copyright 1999 Juergen Schmied
- *
- * 11/99 first release
+ * Copyright 2003 Dimitrie O. Paun
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,342 +21,206 @@
  */
 
 #include "config.h"
-
-#ifdef HAVE_SYS_PARAM_H
-# include <sys/param.h>
-#endif
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <ctype.h>
-#include <string.h>
+#include "wine/port.h"
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdarg.h>
-
-#include <fcntl.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#ifdef HAVE_SYS_MMAN_H
-# include <sys/mman.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
 #endif
 
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-
-extern char*   g_lpstrFileName;
-
-/* global options */
-
-char*	g_lpstrFileName = NULL;
-char*   g_lpstrInputFile = NULL;
-int	b_to_binary = 0;
-int	b_force_overwrite = 0;
-
-static char*    errorOpenFile = "Unable to open file.\n";
-static char*    errorRCFormat = "Unexpexted syntax in rc file line %i\n";
+static const char* help =
+    	"Usage: bin2res [-x] | [-a] [-f] [-h] <rsrc.rc>\n"
+	"  -a archive binaries into the <rsrc.rc> file\n"
+	"  -x extract binaries from the <rsrc.rc> file\n"
+	"  -f force processing of older resources\n"
+	"  -h print this help screen and exit\n"
+	"\n"
+	"This tool allows the insertion/extractions of embedded binary\n"
+	"resources to/from .rc files, for storage within the cvs tree.\n"
+	"This is accomplished by placing a magic marker in a comment\n"
+	"just above the resource. The marker consists of the BINRES\n"
+	"string followed by the file name. For example, to insert a\n"
+	"brand new binary resource in a .rc file, place the marker\n"
+	"above empty brackets:\n"
+	"    /* BINRES idb_std_small.bmp */\n"
+	"   {}\n"
+	"To merge the binary resources into the .rc file, run:\n"
+	"   bin2res -a myrsrc.rc\n"
+	"Only resources that are newer than the .rc are processed.\n"
+	"To extract the binary resources from the .rc file, run:\n"
+	"  bin2res -x myrsrc.rc\n"
+	"Binary files newer than the .rc file are not overwritten.\n"
+	"\n"
+	"To force processing of all resources, use the -f flag.\n";
 
 void usage(void)
 {
-    printf("Usage: bin2res [-d bin] [input file]\n");
-    printf("  -d bin convert a *.res back to a binary\n");
-    printf("  -f force overwriting newer files\n");
-    exit(-1);
+    printf(help);
+    exit(1);
 }
 
-void parse_options(int argc, char **argv)
+int insert_hexdump (FILE* outfile, FILE* infile)
 {
-  int i;
+    int i, c;
+
+    fprintf (outfile, "{\n '");
+    for (i = 0; (c = fgetc(infile)) != EOF; i++)
+    {
+	if (i && (i % 16) == 0) fprintf (outfile, "'\n '");
+	if (i % 16)  fprintf (outfile, " ");
+        fprintf(outfile, "%02X", c);
+    }	
+    fprintf (outfile, "'\n}");
 
-  switch( argc )
-  {
-    case 2:
-	 g_lpstrInputFile = argv[1];
-	 break;
-
-    case 3:
-    case 4:
-    case 5:
-	 for( i = 1; i < argc - 1; i++ )
-	 {
-	   if( argv[i][0] != '-' ||
-	       strlen(argv[i]) != 2 ) break;
-
-	   if( argv[i][1] == 'd')
-	   {
-	     if (strcmp ("bin", argv[i+1])==0)
-	     {
-	       b_to_binary =1;
-	       i++;
-	     }
-	     else
-	     {
-	       usage();
-	     }
-
-	   }
-	   else if ( argv[i][1] == 'f')
-	   {
-	     b_force_overwrite = 1;
-	   }
-	   else
-	   {
-	     usage();
-	   }
-	 }
-	 if( i == argc - 1 )
-	 {
-	   g_lpstrInputFile = argv[i];
-	   break;
-	 }
-    default: usage();
-  }
+    return 1;
 }
 
-int insert_hex (char * infile, FILE * outfile)
+int hex2bin(char c)
 {
-#ifdef	HAVE_MMAP
-	unsigned int i;
-	int 		fd;
-	struct stat	st;
-	LPBYTE p_in_file = NULL;
-
-	if( (fd = open( infile, O_RDONLY))==-1 )
-	{
-	  fprintf(stderr, errorOpenFile );
-	  exit(1);
-	}
-        if ((fstat(fd, &st) == -1) || (p_in_file = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == (void *)-1)
-        {
-	  fprintf(stderr, errorOpenFile );
-          close(fd);
-	  exit(1);
-        }
-
-	fprintf (outfile, "{\n '");
-	i = 0;
-	while (1)
-	{
-	  fprintf(outfile, "%02X", p_in_file[i]);
-	  if (++i >= st.st_size) break;
-	  fprintf(outfile, "%s", (i == (i & 0xfffffff0)) ? "'\n '" :" ");
-	}
-	fprintf (outfile, "'\n}");
-        munmap(p_in_file, st.st_size);
-        close(fd);
-	return 1;
-#else	/* HAVE_MMAP */
-	FILE*	fp;
-	struct stat	st;
-	unsigned int	i;
-	int		c;
-
-	fp = fopen( infile, "r" );
-	if ( fp == NULL )
-	{
-	  fprintf(stderr, errorOpenFile );
-	  exit(1);
-	}
-	if (fstat(fileno(fp), &st) == -1)
-	{
-	  fprintf(stderr, errorOpenFile );
-	  fclose(fp);
-	  exit(1);
-	}
-
-	fprintf (outfile, "{\n '");
-	i = 0;
-	while (1)
-	{
-	  c = fgetc(fp);
-	  if ( c == EOF )
-	  {
-	    fprintf(stderr, errorOpenFile );
-	    fclose(fp);
-	    exit(1);
-	  }
-	  fprintf(outfile, "%02X", c);
-	  if (++i >= st.st_size) break;
-	  fprintf(outfile, "%s", (i == (i & 0xfffffff0)) ? "'\n '" :" ");
-	}
-	fprintf (outfile, "'\n}");
-
-	fclose(fp);
-	return 1;
-#endif	/* HAVE_MMAP */
+    if (!isxdigit(c)) return -1024;
+    if (isdigit(c)) return c - '0';
+    return toupper(c) - 'A' + 10;
 }
 
-int convert_to_res ()
+int extract_hexdump (FILE* outfile, FILE* infile)
 {
-	FILE 	*fin, *ftemp;
-	char	buffer[255];
-	char	infile[255];
-	char	tmpfile[255];
-	char	*pos;
-	int	c, len;
-	struct stat	st;
-	int line = 0;
-	time_t	tinput;
-	long startpos, endpos;
-
-        strcpy( tmpfile, g_lpstrInputFile );
-        strcat( tmpfile, "-tmp" );
-        /* FIXME: should use better tmp name and create with O_EXCL */
-	if( (ftemp = fopen( tmpfile, "w")) == NULL ) goto error_open_file;
+    int byte, c;
 
-	if( (fin = fopen( g_lpstrInputFile, "r")) == NULL || stat(g_lpstrInputFile, &st)) goto error_open_file;
-	tinput = st.st_ctime;
-
-	while ( NULL != fgets(buffer, 255, fin))
-	{
-	  fputs(buffer, ftemp);
-	  line++;
-	  if ( (pos = strstr(buffer, "BINRES")) != NULL)
-	  {
-	    /* get the out-file name */
-	    len = 0; pos += 6; startpos=0; endpos=0;
-	    while ( *pos == ' ') pos++;
-	    while ( pos[len] != ' ') len++;
-	    strncpy(infile, pos, len);
-	    infile[len]=0;
-
-	    if ( (!stat(infile, &st) && st.st_ctime > tinput) || b_force_overwrite)
-	    {
-	      /* write a output file */
-	      printf("[%s:c]", infile);
-	      while((c = fgetc(fin))!='{' && c != EOF) fputc(c, ftemp);
-	      if (c == EOF ) goto error_rc_format;
-	      while((c = fgetc(fin))!='}' && c != EOF);
-	      if (c == EOF ) goto error_rc_format;
-
-	      insert_hex(infile, ftemp);
-	    }
-	    else
-	    {
-	      printf("[%s:s]", infile);
-	    }
-	  }
-	}
-
-        fclose(fin);
-	fclose(ftemp);
-
-	if (unlink(g_lpstrInputFile) == -1)
-	{
-            perror("unlink");
-            unlink(tmpfile);
-            return 0;
-	}
-	if (rename(tmpfile, g_lpstrInputFile) == -1)
-        {
-            perror("rename");
-            unlink(tmpfile);
-            return 0;
-        }
-	return 1;
-
-error_open_file:
-	fprintf(stderr, errorOpenFile );
-	return 0;
-
-error_rc_format:
-	fprintf(stderr, errorRCFormat, line);
-	return 0;
+    while ( (c = fgetc(infile)) != EOF && c != '}')
+    {
+        if (isspace(c) || c == '\'') continue;
+	byte = 16 * hex2bin(c);
+	c = fgetc(infile);	
+	if (c == EOF) return 0;
+	byte += hex2bin(c);
+	if (byte < 0) return 0;
+	fputc(byte, outfile);
+    }
+    return 1;
 }
 
-int convert_to_bin()
+const char* parse_marker(const char *line, time_t* last_updated)
 {
-	FILE 	*fin, *fout;
-	char	buffer[255];
-	char	outfile[255];
-	char	*pos;
-	int	len, index, in_resource;
-	unsigned int	byte;
-	struct stat	st;
-	int line = 0;
-	time_t	tinput;
+    static char res_file_name[PATH_MAX], *rpos, *wpos;
+    struct stat st;
 
-	if( (fin = fopen( g_lpstrInputFile, "r")) == NULL || stat(g_lpstrInputFile, &st)) goto error_open_file;
-	tinput = st.st_ctime;
+    if (!(rpos = strstr(line, "BINRES"))) return 0;
+    for (rpos += 6; *rpos && isspace(*rpos); rpos++) /**/;    
+    for (wpos = res_file_name; *rpos && !isspace(*rpos); ) *wpos++ = *rpos++;
+    *wpos = 0;
+	
+    *last_updated = (stat(res_file_name, &st) < 0) ? 0 : st.st_mtime;
 
-	while ( NULL != fgets(buffer, 255, fin))
-	{
-	  line++;
-	  if ( (pos = strstr(buffer, "BINRES")) != NULL)
-	  {
-	    /* get the out-file name */
-	    len = 0; pos += 6;
-	    while ( *pos == ' ') pos++;
-	    while ( pos[len] != ' ') len++;
-	    strncpy(outfile, pos, len);
-	    outfile[len]=0;
-
-	    if ( stat(outfile, &st) || st.st_ctime < tinput || b_force_overwrite)
-	    {
-	      /* write a output file */
-	      printf("[%s:c]", outfile);
-	      if ( (fout = fopen( outfile, "w")) == NULL) goto error_open_file;
-
-	      in_resource = 0;
-	      while (1)
-	      {
-	        if ( NULL == fgets(buffer, 255, fin)) goto error_rc_format;
-	        line++;
-
-	        /* parse a line */
-	        for ( index = 0; buffer[index] != 0; index++ )
-	        {
-	          if ( ! in_resource )
-		  {
-		    if ( buffer[index] == '{' ) in_resource = 1;
-		    continue;
-		  }
-
-	          if ( buffer[index] == ' ' || buffer[index] == '\''|| buffer[index] == '\n' ) continue;
-	          if ( buffer[index] == '}' ) goto end_of_resource;
-	          if ( ! isxdigit(buffer[index])) goto error_rc_format;
-		  index += sscanf(&buffer[index], "%02x", &byte);
-		  fputc(byte, fout);
-	        }
-	      }
-	      fclose(fout);
-	    }
-	    else
-	    {
-	      printf("[%s:s]", outfile);
-	    }
-end_of_resource: ;
-	  }
-	}
+    return res_file_name;
+}
 
-        fclose(fin);
-	return 1;
+int process_resources(const char* input_file_name, int inserting, int force_processing)
+{
+    char buffer[2048], tmp_file_name[PATH_MAX];
+    const char *res_file_name;
+    time_t rc_last_update, res_last_update;
+    FILE *fin, *fres, *ftmp = 0;
+    struct stat st;
+    int fd, c;
+
+    if (!(fin = fopen(input_file_name, "r"))) return 0;
+    if (stat(input_file_name, &st) < 0) return 0;
+    rc_last_update = st.st_mtime;
+
+    if (inserting)
+    {
+	strcpy(tmp_file_name, input_file_name);
+	strcat(tmp_file_name, "-XXXXXX.temp");
+	if ((fd = mkstemps(tmp_file_name, 5)) == -1)
+	{
+	    strcpy(tmp_file_name, "/tmp/bin2res-XXXXXX.temp");
+	    if ((fd = mkstemps(tmp_file_name, 5)) == -1) return 0;
+	}
+	if (!(ftmp = fdopen(fd, "w"))) return 0;
+    }
+
+    for (c = EOF; fgets(buffer, sizeof(buffer), fin); c = EOF)
+    {
+	if (inserting) fprintf(ftmp, "%s", buffer);
+	if (!(res_file_name = parse_marker(buffer, &res_last_update))) continue;
+        if (!force_processing && ((rc_last_update < res_last_update) == !inserting))
+        {
+	    printf("skipping '%s'\n", res_file_name);
+            continue;
+        }
 
-error_open_file:
-	fprintf(stderr, errorOpenFile );
-	return 0;
-
-error_rc_format:
-	fprintf(stderr, errorRCFormat, line);
-	return 0;
+        printf("processing '%s'\n", res_file_name);
+	while ( (c = fgetc(fin)) != EOF && c != '{')
+	    if (inserting) fputc(c, ftmp);
+	if (c == EOF) break;
+
+	if (!(fres = fopen(res_file_name, inserting ? "r" : "w"))) break;
+	if (inserting)
+	{
+	    if (!insert_hexdump(ftmp, fres)) break;
+	    while ( (c = fgetc(fin)) != EOF && c != '}') /**/;
+	}
+	else 
+	{
+	    if (!extract_hexdump(fres, fin)) break;
+	}
+	fclose(fres);
+    }
+
+    fclose(fin);
+
+    if (inserting) 
+    {
+	fclose(ftmp);
+	if (c == EOF && rename(tmp_file_name, input_file_name) < 0) 
+	    c = '.'; /* force an error */
+	else unlink(tmp_file_name);
+    }
+    
+    return c == EOF;
 }
 
 int main(int argc, char **argv)
 {
-	parse_options( argc, argv);
+    int convert_dir = 0, optc;
+    int force_overwrite = 0;
+    const char* input_file_name;
+
+    while((optc = getopt(argc, argv, "axfh")) != EOF)
+    {
+	switch(optc)
+	{
+	case 'a':
+	case 'x':
+	    if (convert_dir) usage();
+	    convert_dir = optc;
+	break;
+	case 'f':
+	    force_overwrite = 1;
+	break;
+	case 'h':
+	    printf(help);
+	    exit(0);
+	break;
+	default:
+	    usage();
+	}
+    }
+
+    if (optind + 1 != argc) usage();
+    input_file_name = argv[optind];
+
+    if (!convert_dir) usage();
+
+    if (!process_resources(input_file_name, convert_dir == 'a', force_overwrite))
+    {
+	perror("Processing failed");
+	exit(1);
+    }
 
-	if (b_to_binary == 0)
-	{
-	  convert_to_res();
-	}
-	else
-	{
-	  convert_to_bin();
-	}
-	printf("\n");
-	return 0;
+    return 0;
 }
-- 
Dimi.




More information about the wine-patches mailing list