Complete rewrite of bin2res, for a cleaner codebase.
Add online help describing how the program works. Sanitize command line options.
This commit is contained in:
parent
59b2ad62db
commit
fb9c47d522
471
tools/bin2res.c
471
tools/bin2res.c
|
@ -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;
|
||||
|
||||
switch( argc )
|
||||
{
|
||||
case 2:
|
||||
g_lpstrInputFile = argv[1];
|
||||
break;
|
||||
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}");
|
||||
|
||||
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 (!isxdigit(c)) return -1024;
|
||||
if (isdigit(c)) return c - '0';
|
||||
return toupper(c) - 'A' + 10;
|
||||
}
|
||||
|
||||
if( (fd = open( infile, O_RDONLY))==-1 )
|
||||
int extract_hexdump (FILE* outfile, FILE* infile)
|
||||
{
|
||||
int byte, c;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const char* parse_marker(const char *line, time_t* last_updated)
|
||||
{
|
||||
static char res_file_name[PATH_MAX], *rpos, *wpos;
|
||||
struct stat st;
|
||||
|
||||
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;
|
||||
|
||||
return res_file_name;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
fprintf(stderr, errorOpenFile );
|
||||
exit(1);
|
||||
strcpy(tmp_file_name, "/tmp/bin2res-XXXXXX.temp");
|
||||
if ((fd = mkstemps(tmp_file_name, 5)) == -1) return 0;
|
||||
}
|
||||
if ((fstat(fd, &st) == -1) || (p_in_file = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == (void *)-1)
|
||||
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))
|
||||
{
|
||||
fprintf(stderr, errorOpenFile );
|
||||
close(fd);
|
||||
exit(1);
|
||||
printf("skipping '%s'\n", res_file_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf (outfile, "{\n '");
|
||||
i = 0;
|
||||
while (1)
|
||||
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)
|
||||
{
|
||||
fprintf(outfile, "%02X", p_in_file[i]);
|
||||
if (++i >= st.st_size) break;
|
||||
fprintf(outfile, "%s", (i == (i & 0xfffffff0)) ? "'\n '" :" ");
|
||||
if (!insert_hexdump(ftmp, fres)) break;
|
||||
while ( (c = fgetc(fin)) != EOF && c != '}') /**/;
|
||||
}
|
||||
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 )
|
||||
else
|
||||
{
|
||||
fprintf(stderr, errorOpenFile );
|
||||
exit(1);
|
||||
}
|
||||
if (fstat(fileno(fp), &st) == -1)
|
||||
{
|
||||
fprintf(stderr, errorOpenFile );
|
||||
fclose(fp);
|
||||
exit(1);
|
||||
if (!extract_hexdump(fres, fin)) break;
|
||||
}
|
||||
fclose(fres);
|
||||
}
|
||||
|
||||
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(fin);
|
||||
|
||||
fclose(fp);
|
||||
return 1;
|
||||
#endif /* HAVE_MMAP */
|
||||
}
|
||||
if (inserting)
|
||||
{
|
||||
fclose(ftmp);
|
||||
if (c == EOF && rename(tmp_file_name, input_file_name) < 0)
|
||||
c = '.'; /* force an error */
|
||||
else unlink(tmp_file_name);
|
||||
}
|
||||
|
||||
int convert_to_res ()
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int convert_to_bin()
|
||||
{
|
||||
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;
|
||||
|
||||
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))
|
||||
{
|
||||
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: ;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fin);
|
||||
return 1;
|
||||
|
||||
error_open_file:
|
||||
fprintf(stderr, errorOpenFile );
|
||||
return 0;
|
||||
|
||||
error_rc_format:
|
||||
fprintf(stderr, errorRCFormat, line);
|
||||
return 0;
|
||||
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;
|
||||
|
||||
if (b_to_binary == 0)
|
||||
while((optc = getopt(argc, argv, "axfh")) != EOF)
|
||||
{
|
||||
switch(optc)
|
||||
{
|
||||
convert_to_res();
|
||||
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
|
||||
{
|
||||
convert_to_bin();
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue