Commit fb9c47d5 authored by Dimitrie O. Paun's avatar Dimitrie O. Paun Committed by Alexandre Julliard

Complete rewrite of bin2res, for a cleaner codebase.

Add online help describing how the program works. Sanitize command line options.
parent 59b2ad62
...@@ -3,8 +3,7 @@ ...@@ -3,8 +3,7 @@
* Converting binary resources from/to *.rc files * Converting binary resources from/to *.rc files
* *
* Copyright 1999 Juergen Schmied * Copyright 1999 Juergen Schmied
* * Copyright 2003 Dimitrie O. Paun
* 11/99 first release
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
...@@ -22,342 +21,206 @@ ...@@ -22,342 +21,206 @@
*/ */
#include "config.h" #include "config.h"
#include "wine/port.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 <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <ctype.h>
#include <string.h>
#include <fcntl.h> #include <sys/stat.h>
#ifdef HAVE_UNISTD_H #ifdef HAVE_SYS_PARAM_H
# include <unistd.h> # include <sys/param.h>
#endif
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif #endif
#include "windef.h" static const char* help =
#include "winbase.h" "Usage: bin2res [-x] | [-a] [-f] [-h] <rsrc.rc>\n"
#include "wingdi.h" " -a archive binaries into the <rsrc.rc> file\n"
#include "winuser.h" " -x extract binaries from the <rsrc.rc> file\n"
" -f force processing of older resources\n"
extern char* g_lpstrFileName; " -h print this help screen and exit\n"
"\n"
/* global options */ "This tool allows the insertion/extractions of embedded binary\n"
"resources to/from .rc files, for storage within the cvs tree.\n"
char* g_lpstrFileName = NULL; "This is accomplished by placing a magic marker in a comment\n"
char* g_lpstrInputFile = NULL; "just above the resource. The marker consists of the BINRES\n"
int b_to_binary = 0; "string followed by the file name. For example, to insert a\n"
int b_force_overwrite = 0; "brand new binary resource in a .rc file, place the marker\n"
"above empty brackets:\n"
static char* errorOpenFile = "Unable to open file.\n"; " /* BINRES idb_std_small.bmp */\n"
static char* errorRCFormat = "Unexpexted syntax in rc file line %i\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) void usage(void)
{ {
printf("Usage: bin2res [-d bin] [input file]\n"); printf(help);
printf(" -d bin convert a *.res back to a binary\n"); exit(1);
printf(" -f force overwriting newer files\n");
exit(-1);
}
void parse_options(int argc, char **argv)
{
int i;
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();
}
} }
int insert_hex (char * infile, FILE * outfile) int insert_hexdump (FILE* outfile, FILE* infile)
{ {
#ifdef HAVE_MMAP int i, c;
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 '"); fprintf (outfile, "{\n '");
i = 0; for (i = 0; (c = fgetc(infile)) != EOF; i++)
while (1)
{ {
c = fgetc(fp); if (i && (i % 16) == 0) fprintf (outfile, "'\n '");
if ( c == EOF ) if (i % 16) fprintf (outfile, " ");
{
fprintf(stderr, errorOpenFile );
fclose(fp);
exit(1);
}
fprintf(outfile, "%02X", c); fprintf(outfile, "%02X", c);
if (++i >= st.st_size) break;
fprintf(outfile, "%s", (i == (i & 0xfffffff0)) ? "'\n '" :" ");
} }
fprintf (outfile, "'\n}"); fprintf (outfile, "'\n}");
fclose(fp);
return 1; return 1;
#endif /* HAVE_MMAP */
} }
int convert_to_res () int hex2bin(char c)
{ {
FILE *fin, *ftemp; if (!isxdigit(c)) return -1024;
char buffer[255]; if (isdigit(c)) return c - '0';
char infile[255]; return toupper(c) - 'A' + 10;
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;
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) int extract_hexdump (FILE* outfile, FILE* infile)
{ {
/* write a output file */ int byte, c;
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); while ( (c = fgetc(infile)) != EOF && c != '}')
}
else
{ {
printf("[%s:s]", infile); 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;
}
fclose(fin); const char* parse_marker(const char *line, time_t* last_updated)
fclose(ftemp); {
static char res_file_name[PATH_MAX], *rpos, *wpos;
struct stat st;
if (unlink(g_lpstrInputFile) == -1) if (!(rpos = strstr(line, "BINRES"))) return 0;
{ for (rpos += 6; *rpos && isspace(*rpos); rpos++) /**/;
perror("unlink"); for (wpos = res_file_name; *rpos && !isspace(*rpos); ) *wpos++ = *rpos++;
unlink(tmpfile); *wpos = 0;
return 0;
}
if (rename(tmpfile, g_lpstrInputFile) == -1)
{
perror("rename");
unlink(tmpfile);
return 0;
}
return 1;
error_open_file: *last_updated = (stat(res_file_name, &st) < 0) ? 0 : st.st_mtime;
fprintf(stderr, errorOpenFile );
return 0;
error_rc_format: return res_file_name;
fprintf(stderr, errorRCFormat, line);
return 0;
} }
int convert_to_bin() int process_resources(const char* input_file_name, int inserting, int force_processing)
{ {
FILE *fin, *fout; char buffer[2048], tmp_file_name[PATH_MAX];
char buffer[255]; const char *res_file_name;
char outfile[255]; time_t rc_last_update, res_last_update;
char *pos; FILE *fin, *fres, *ftmp = 0;
int len, index, in_resource;
unsigned int byte;
struct stat st; struct stat st;
int line = 0; int fd, c;
time_t tinput;
if( (fin = fopen( g_lpstrInputFile, "r")) == NULL || stat(g_lpstrInputFile, &st)) goto error_open_file; if (!(fin = fopen(input_file_name, "r"))) return 0;
tinput = st.st_ctime; if (stat(input_file_name, &st) < 0) return 0;
rc_last_update = st.st_mtime;
while ( NULL != fgets(buffer, 255, fin)) if (inserting)
{ {
line++; strcpy(tmp_file_name, input_file_name);
if ( (pos = strstr(buffer, "BINRES")) != NULL) strcat(tmp_file_name, "-XXXXXX.temp");
{ if ((fd = mkstemps(tmp_file_name, 5)) == -1)
/* 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; strcpy(tmp_file_name, "/tmp/bin2res-XXXXXX.temp");
line++; if ((fd = mkstemps(tmp_file_name, 5)) == -1) return 0;
}
if (!(ftmp = fdopen(fd, "w"))) return 0;
}
/* parse a line */ for (c = EOF; fgets(buffer, sizeof(buffer), fin); c = EOF)
for ( index = 0; buffer[index] != 0; index++ )
{ {
if ( ! in_resource ) 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))
{ {
if ( buffer[index] == '{' ) in_resource = 1; printf("skipping '%s'\n", res_file_name);
continue; continue;
} }
if ( buffer[index] == ' ' || buffer[index] == '\''|| buffer[index] == '\n' ) continue; printf("processing '%s'\n", res_file_name);
if ( buffer[index] == '}' ) goto end_of_resource; while ( (c = fgetc(fin)) != EOF && c != '{')
if ( ! isxdigit(buffer[index])) goto error_rc_format; if (inserting) fputc(c, ftmp);
index += sscanf(&buffer[index], "%02x", &byte); if (c == EOF) break;
fputc(byte, fout);
} if (!(fres = fopen(res_file_name, inserting ? "r" : "w"))) break;
} if (inserting)
fclose(fout); {
if (!insert_hexdump(ftmp, fres)) break;
while ( (c = fgetc(fin)) != EOF && c != '}') /**/;
} }
else else
{ {
printf("[%s:s]", outfile); if (!extract_hexdump(fres, fin)) break;
}
end_of_resource: ;
} }
fclose(fres);
} }
fclose(fin); fclose(fin);
return 1;
error_open_file: if (inserting)
fprintf(stderr, errorOpenFile ); {
return 0; fclose(ftmp);
if (c == EOF && rename(tmp_file_name, input_file_name) < 0)
c = '.'; /* force an error */
else unlink(tmp_file_name);
}
error_rc_format: return c == EOF;
fprintf(stderr, errorRCFormat, line);
return 0;
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
parse_options( argc, argv); int convert_dir = 0, optc;
int force_overwrite = 0;
const char* input_file_name;
if (b_to_binary == 0) while((optc = getopt(argc, argv, "axfh")) != EOF)
{ {
convert_to_res(); 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();
} }
else }
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))
{ {
convert_to_bin(); perror("Processing failed");
exit(1);
} }
printf("\n");
return 0; return 0;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment