blob: 9075839b999d1bffe07c06dc04b6221661417b30 [file] [log] [blame]
Juergen Schmied04f7fe71999-11-13 22:32:21 +00001/************************************************
2 *
3 * Converting binary resources from/to *.rc files
4 *
5 * Copyright 1999 Juergen Schmied
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +00006 * Copyright 2003 Dimitrie O. Paun
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00007 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Juergen Schmied04f7fe71999-11-13 22:32:21 +000021 */
22
23#include "config.h"
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000024#include "wine/port.h"
Juergen Schmied04f7fe71999-11-13 22:32:21 +000025
26#include <stdio.h>
27#include <stdlib.h>
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000028#include <ctype.h>
29#include <string.h>
30#include <sys/stat.h>
31#ifdef HAVE_SYS_PARAM_H
32# include <sys/param.h>
Patrik Stridvall9af5e691999-12-11 23:02:15 +000033#endif
François Gouget44a18222000-12-19 04:53:20 +000034
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000035static const char* help =
Dimitrie O. Paun4ff35b52003-10-01 03:13:31 +000036 "Usage: bin2res [OPTIONS] <rsrc.rc>\n"
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000037 " -a archive binaries into the <rsrc.rc> file\n"
38 " -x extract binaries from the <rsrc.rc> file\n"
Dimitrie O. Paun4ff35b52003-10-01 03:13:31 +000039 " -i <filename> archive the named file into the <rsrc.rc> file\n"
40 " -o <filename> extract the named file from the <rsrc.rc> file\n"
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000041 " -f force processing of older resources\n"
Dimitrie O. Paund50fdcd2003-10-03 03:34:10 +000042 " -v causes the command to be verbous during processing\n"
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000043 " -h print this help screen and exit\n"
44 "\n"
45 "This tool allows the insertion/extractions of embedded binary\n"
46 "resources to/from .rc files, for storage within the cvs tree.\n"
47 "This is accomplished by placing a magic marker in a comment\n"
48 "just above the resource. The marker consists of the BINRES\n"
49 "string followed by the file name. For example, to insert a\n"
50 "brand new binary resource in a .rc file, place the marker\n"
51 "above empty brackets:\n"
52 " /* BINRES idb_std_small.bmp */\n"
53 " {}\n"
54 "To merge the binary resources into the .rc file, run:\n"
55 " bin2res -a myrsrc.rc\n"
56 "Only resources that are newer than the .rc are processed.\n"
57 "To extract the binary resources from the .rc file, run:\n"
58 " bin2res -x myrsrc.rc\n"
59 "Binary files newer than the .rc file are not overwritten.\n"
60 "\n"
Dimitrie O. Paun4ff35b52003-10-01 03:13:31 +000061 "To force processing of all resources, use the -f flag.\n"
62 "To process a particular file, use the -i/-o options.\n";
Juergen Schmied04f7fe71999-11-13 22:32:21 +000063
64void usage(void)
65{
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000066 printf(help);
67 exit(1);
Juergen Schmied04f7fe71999-11-13 22:32:21 +000068}
69
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000070int insert_hexdump (FILE* outfile, FILE* infile)
Juergen Schmied04f7fe71999-11-13 22:32:21 +000071{
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000072 int i, c;
Juergen Schmied04f7fe71999-11-13 22:32:21 +000073
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000074 fprintf (outfile, "{\n '");
75 for (i = 0; (c = fgetc(infile)) != EOF; i++)
76 {
77 if (i && (i % 16) == 0) fprintf (outfile, "'\n '");
78 if (i % 16) fprintf (outfile, " ");
79 fprintf(outfile, "%02X", c);
80 }
81 fprintf (outfile, "'\n}");
Juergen Schmied04f7fe71999-11-13 22:32:21 +000082
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000083 return 1;
Juergen Schmied04f7fe71999-11-13 22:32:21 +000084}
85
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000086int hex2bin(char c)
Juergen Schmied04f7fe71999-11-13 22:32:21 +000087{
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000088 if (!isxdigit(c)) return -1024;
89 if (isdigit(c)) return c - '0';
90 return toupper(c) - 'A' + 10;
91}
Juergen Schmied04f7fe71999-11-13 22:32:21 +000092
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000093int extract_hexdump (FILE* outfile, FILE* infile)
94{
95 int byte, c;
96
97 while ( (c = fgetc(infile)) != EOF && c != '}')
98 {
99 if (isspace(c) || c == '\'') continue;
100 byte = 16 * hex2bin(c);
101 c = fgetc(infile);
102 if (c == EOF) return 0;
103 byte += hex2bin(c);
104 if (byte < 0) return 0;
105 fputc(byte, outfile);
106 }
107 return 1;
108}
109
110const char* parse_marker(const char *line, time_t* last_updated)
111{
112 static char res_file_name[PATH_MAX], *rpos, *wpos;
113 struct stat st;
114
115 if (!(rpos = strstr(line, "BINRES"))) return 0;
116 for (rpos += 6; *rpos && isspace(*rpos); rpos++) /**/;
117 for (wpos = res_file_name; *rpos && !isspace(*rpos); ) *wpos++ = *rpos++;
118 *wpos = 0;
119
120 *last_updated = (stat(res_file_name, &st) < 0) ? 0 : st.st_mtime;
121
122 return res_file_name;
123}
124
Dimitrie O. Paund50fdcd2003-10-03 03:34:10 +0000125int process_resources(const char* input_file_name, const char* specific_file_name,
126 int inserting, int force_processing, int verbose)
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000127{
128 char buffer[2048], tmp_file_name[PATH_MAX];
129 const char *res_file_name;
130 time_t rc_last_update, res_last_update;
131 FILE *fin, *fres, *ftmp = 0;
132 struct stat st;
133 int fd, c;
134
135 if (!(fin = fopen(input_file_name, "r"))) return 0;
136 if (stat(input_file_name, &st) < 0) return 0;
137 rc_last_update = st.st_mtime;
138
139 if (inserting)
140 {
141 strcpy(tmp_file_name, input_file_name);
142 strcat(tmp_file_name, "-XXXXXX.temp");
143 if ((fd = mkstemps(tmp_file_name, 5)) == -1)
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000144 {
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000145 strcpy(tmp_file_name, "/tmp/bin2res-XXXXXX.temp");
146 if ((fd = mkstemps(tmp_file_name, 5)) == -1) return 0;
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000147 }
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000148 if (!(ftmp = fdopen(fd, "w"))) return 0;
149 }
150
151 for (c = EOF; fgets(buffer, sizeof(buffer), fin); c = EOF)
152 {
153 if (inserting) fprintf(ftmp, "%s", buffer);
154 if (!(res_file_name = parse_marker(buffer, &res_last_update))) continue;
Dimitrie O. Paun4ff35b52003-10-01 03:13:31 +0000155 if ( (specific_file_name && strcmp(specific_file_name, res_file_name)) ||
156 (!force_processing && ((rc_last_update < res_last_update) == !inserting)) )
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000157 {
Dimitrie O. Paund50fdcd2003-10-03 03:34:10 +0000158 if (verbose) printf("skipping '%s'\n", res_file_name);
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000159 continue;
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000160 }
161
Dimitrie O. Paund50fdcd2003-10-03 03:34:10 +0000162 if (verbose) printf("processing '%s'\n", res_file_name);
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000163 while ( (c = fgetc(fin)) != EOF && c != '{')
164 if (inserting) fputc(c, ftmp);
165 if (c == EOF) break;
166
Pavel Roskin671f02c2003-10-06 21:05:28 +0000167 if (!(fres = fopen(res_file_name, inserting ? "rb" : "wb"))) break;
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000168 if (inserting)
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000169 {
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000170 if (!insert_hexdump(ftmp, fres)) break;
171 while ( (c = fgetc(fin)) != EOF && c != '}') /**/;
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000172 }
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000173 else
Hidenori Takeshimaa85b0a62000-11-25 23:54:12 +0000174 {
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000175 if (!extract_hexdump(fres, fin)) break;
Hidenori Takeshimaa85b0a62000-11-25 23:54:12 +0000176 }
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000177 fclose(fres);
178 }
Hidenori Takeshimaa85b0a62000-11-25 23:54:12 +0000179
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000180 fclose(fin);
Hidenori Takeshimaa85b0a62000-11-25 23:54:12 +0000181
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000182 if (inserting)
183 {
184 fclose(ftmp);
185 if (c == EOF && rename(tmp_file_name, input_file_name) < 0)
186 c = '.'; /* force an error */
187 else unlink(tmp_file_name);
188 }
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000189
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000190 return c == EOF;
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000191}
192
193int main(int argc, char **argv)
194{
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000195 int convert_dir = 0, optc;
Dimitrie O. Paund50fdcd2003-10-03 03:34:10 +0000196 int force_overwrite = 0, verbose = 0;
Dimitrie O. Paun4ff35b52003-10-01 03:13:31 +0000197 const char* input_file_name = 0;
198 const char* specific_file_name = 0;
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000199
Dimitrie O. Paun4ff35b52003-10-01 03:13:31 +0000200 while((optc = getopt(argc, argv, "axi:o:fh")) != EOF)
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000201 {
202 switch(optc)
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000203 {
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000204 case 'a':
205 case 'x':
206 if (convert_dir) usage();
207 convert_dir = optc;
208 break;
Dimitrie O. Paun4ff35b52003-10-01 03:13:31 +0000209 case 'i':
210 case 'o':
211 if (specific_file_name) usage();
212 specific_file_name = optarg;
213 optc = ((optc == 'i') ? 'a' : 'x');
214 if (convert_dir && convert_dir != optc) usage();
215 convert_dir = optc;
216 break;
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000217 case 'f':
218 force_overwrite = 1;
219 break;
Dimitrie O. Paund50fdcd2003-10-03 03:34:10 +0000220 case 'v':
221 verbose = 1;
222 break;
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000223 case 'h':
224 printf(help);
225 exit(0);
226 break;
227 default:
228 usage();
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000229 }
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000230 }
231
232 if (optind + 1 != argc) usage();
233 input_file_name = argv[optind];
234
235 if (!convert_dir) usage();
236
Dimitrie O. Paun4ff35b52003-10-01 03:13:31 +0000237 if (!process_resources(input_file_name, specific_file_name,
Dimitrie O. Paund50fdcd2003-10-03 03:34:10 +0000238 convert_dir == 'a', force_overwrite, verbose))
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000239 {
240 perror("Processing failed");
241 exit(1);
242 }
243
244 return 0;
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000245}