blob: 7a45f65505d09dad695c9bd11ff8ff9f36e5d122 [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>
Robert Lunnon16bd45d2004-01-14 05:12:33 +000031#include <limits.h>
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000032#ifdef HAVE_SYS_PARAM_H
33# include <sys/param.h>
Patrik Stridvall9af5e691999-12-11 23:02:15 +000034#endif
François Gouget44a18222000-12-19 04:53:20 +000035
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000036static const char* help =
Dimitrie O. Paun4ff35b52003-10-01 03:13:31 +000037 "Usage: bin2res [OPTIONS] <rsrc.rc>\n"
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000038 " -a archive binaries into the <rsrc.rc> file\n"
39 " -x extract binaries from the <rsrc.rc> file\n"
Dimitrie O. Paun4ff35b52003-10-01 03:13:31 +000040 " -i <filename> archive the named file into the <rsrc.rc> file\n"
41 " -o <filename> extract the named file from the <rsrc.rc> file\n"
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000042 " -f force processing of older resources\n"
Dimitrie O. Paund50fdcd2003-10-03 03:34:10 +000043 " -v causes the command to be verbous during processing\n"
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000044 " -h print this help screen and exit\n"
45 "\n"
46 "This tool allows the insertion/extractions of embedded binary\n"
47 "resources to/from .rc files, for storage within the cvs tree.\n"
48 "This is accomplished by placing a magic marker in a comment\n"
49 "just above the resource. The marker consists of the BINRES\n"
50 "string followed by the file name. For example, to insert a\n"
51 "brand new binary resource in a .rc file, place the marker\n"
52 "above empty brackets:\n"
53 " /* BINRES idb_std_small.bmp */\n"
Robert Shearmane5483392004-09-06 20:26:35 +000054 " IDB_STD_SMALL BITMAP idb_std_small.bmp\n"
55 " /* {\n"
56 " } */\n"
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000057 "To merge the binary resources into the .rc file, run:\n"
58 " bin2res -a myrsrc.rc\n"
59 "Only resources that are newer than the .rc are processed.\n"
60 "To extract the binary resources from the .rc file, run:\n"
61 " bin2res -x myrsrc.rc\n"
62 "Binary files newer than the .rc file are not overwritten.\n"
63 "\n"
Dimitrie O. Paun4ff35b52003-10-01 03:13:31 +000064 "To force processing of all resources, use the -f flag.\n"
65 "To process a particular file, use the -i/-o options.\n";
Juergen Schmied04f7fe71999-11-13 22:32:21 +000066
Stefan Huehnere5462382005-06-15 18:10:39 +000067static void usage(void)
Juergen Schmied04f7fe71999-11-13 22:32:21 +000068{
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000069 printf(help);
70 exit(1);
Juergen Schmied04f7fe71999-11-13 22:32:21 +000071}
72
Stefan Huehnere5462382005-06-15 18:10:39 +000073static int insert_hexdump (FILE* outfile, FILE* infile)
Juergen Schmied04f7fe71999-11-13 22:32:21 +000074{
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000075 int i, c;
Juergen Schmied04f7fe71999-11-13 22:32:21 +000076
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000077 fprintf (outfile, "{\n '");
78 for (i = 0; (c = fgetc(infile)) != EOF; i++)
79 {
80 if (i && (i % 16) == 0) fprintf (outfile, "'\n '");
81 if (i % 16) fprintf (outfile, " ");
82 fprintf(outfile, "%02X", c);
83 }
84 fprintf (outfile, "'\n}");
Juergen Schmied04f7fe71999-11-13 22:32:21 +000085
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000086 return 1;
Juergen Schmied04f7fe71999-11-13 22:32:21 +000087}
88
Stefan Huehnere5462382005-06-15 18:10:39 +000089static int hex2bin(char c)
Juergen Schmied04f7fe71999-11-13 22:32:21 +000090{
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000091 if (!isxdigit(c)) return -1024;
92 if (isdigit(c)) return c - '0';
93 return toupper(c) - 'A' + 10;
94}
Juergen Schmied04f7fe71999-11-13 22:32:21 +000095
Stefan Huehnere5462382005-06-15 18:10:39 +000096static int extract_hexdump (FILE* outfile, FILE* infile)
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +000097{
98 int byte, c;
99
100 while ( (c = fgetc(infile)) != EOF && c != '}')
101 {
102 if (isspace(c) || c == '\'') continue;
103 byte = 16 * hex2bin(c);
104 c = fgetc(infile);
105 if (c == EOF) return 0;
106 byte += hex2bin(c);
107 if (byte < 0) return 0;
108 fputc(byte, outfile);
109 }
110 return 1;
111}
112
Stefan Huehnere5462382005-06-15 18:10:39 +0000113static const char* parse_marker(const char *line, time_t* last_updated)
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000114{
115 static char res_file_name[PATH_MAX], *rpos, *wpos;
116 struct stat st;
117
118 if (!(rpos = strstr(line, "BINRES"))) return 0;
119 for (rpos += 6; *rpos && isspace(*rpos); rpos++) /**/;
120 for (wpos = res_file_name; *rpos && !isspace(*rpos); ) *wpos++ = *rpos++;
121 *wpos = 0;
122
123 *last_updated = (stat(res_file_name, &st) < 0) ? 0 : st.st_mtime;
124
125 return res_file_name;
126}
127
Stefan Huehnere5462382005-06-15 18:10:39 +0000128static int process_resources(const char* input_file_name, const char* specific_file_name,
Dimitrie O. Paund50fdcd2003-10-03 03:34:10 +0000129 int inserting, int force_processing, int verbose)
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000130{
131 char buffer[2048], tmp_file_name[PATH_MAX];
132 const char *res_file_name;
133 time_t rc_last_update, res_last_update;
134 FILE *fin, *fres, *ftmp = 0;
135 struct stat st;
136 int fd, c;
137
138 if (!(fin = fopen(input_file_name, "r"))) return 0;
139 if (stat(input_file_name, &st) < 0) return 0;
140 rc_last_update = st.st_mtime;
141
142 if (inserting)
143 {
144 strcpy(tmp_file_name, input_file_name);
145 strcat(tmp_file_name, "-XXXXXX.temp");
146 if ((fd = mkstemps(tmp_file_name, 5)) == -1)
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000147 {
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000148 strcpy(tmp_file_name, "/tmp/bin2res-XXXXXX.temp");
149 if ((fd = mkstemps(tmp_file_name, 5)) == -1) return 0;
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000150 }
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000151 if (!(ftmp = fdopen(fd, "w"))) return 0;
152 }
153
154 for (c = EOF; fgets(buffer, sizeof(buffer), fin); c = EOF)
155 {
156 if (inserting) fprintf(ftmp, "%s", buffer);
157 if (!(res_file_name = parse_marker(buffer, &res_last_update))) continue;
Dimitrie O. Paun4ff35b52003-10-01 03:13:31 +0000158 if ( (specific_file_name && strcmp(specific_file_name, res_file_name)) ||
159 (!force_processing && ((rc_last_update < res_last_update) == !inserting)) )
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000160 {
Dimitrie O. Paund50fdcd2003-10-03 03:34:10 +0000161 if (verbose) printf("skipping '%s'\n", res_file_name);
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000162 continue;
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000163 }
164
Dimitrie O. Paund50fdcd2003-10-03 03:34:10 +0000165 if (verbose) printf("processing '%s'\n", res_file_name);
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000166 while ( (c = fgetc(fin)) != EOF && c != '{')
167 if (inserting) fputc(c, ftmp);
168 if (c == EOF) break;
169
Pavel Roskin671f02c2003-10-06 21:05:28 +0000170 if (!(fres = fopen(res_file_name, inserting ? "rb" : "wb"))) break;
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000171 if (inserting)
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000172 {
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000173 if (!insert_hexdump(ftmp, fres)) break;
174 while ( (c = fgetc(fin)) != EOF && c != '}') /**/;
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000175 }
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000176 else
Hidenori Takeshimaa85b0a62000-11-25 23:54:12 +0000177 {
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000178 if (!extract_hexdump(fres, fin)) break;
Hidenori Takeshimaa85b0a62000-11-25 23:54:12 +0000179 }
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000180 fclose(fres);
181 }
Hidenori Takeshimaa85b0a62000-11-25 23:54:12 +0000182
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000183 fclose(fin);
Hidenori Takeshimaa85b0a62000-11-25 23:54:12 +0000184
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000185 if (inserting)
186 {
187 fclose(ftmp);
Alexandre Julliarde97fb4b2004-01-18 23:32:56 +0000188 if (c == EOF)
189 {
190 if (rename(tmp_file_name, input_file_name) < 0)
191 {
192 /* try unlinking first, Windows rename is brain-damaged */
193 if (unlink(input_file_name) < 0 || rename(tmp_file_name, input_file_name) < 0)
194 {
195 unlink(tmp_file_name);
196 return 0;
197 }
198 }
199 }
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000200 else unlink(tmp_file_name);
201 }
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000202
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000203 return c == EOF;
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000204}
205
206int main(int argc, char **argv)
207{
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000208 int convert_dir = 0, optc;
Dimitrie O. Paund50fdcd2003-10-03 03:34:10 +0000209 int force_overwrite = 0, verbose = 0;
Dimitrie O. Paun4ff35b52003-10-01 03:13:31 +0000210 const char* input_file_name = 0;
211 const char* specific_file_name = 0;
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000212
Robert Shearmancadf6fc2004-03-09 03:44:22 +0000213 while((optc = getopt(argc, argv, "axi:o:fhv")) != EOF)
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000214 {
215 switch(optc)
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000216 {
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000217 case 'a':
218 case 'x':
219 if (convert_dir) usage();
220 convert_dir = optc;
221 break;
Dimitrie O. Paun4ff35b52003-10-01 03:13:31 +0000222 case 'i':
223 case 'o':
224 if (specific_file_name) usage();
225 specific_file_name = optarg;
226 optc = ((optc == 'i') ? 'a' : 'x');
227 if (convert_dir && convert_dir != optc) usage();
228 convert_dir = optc;
229 break;
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000230 case 'f':
231 force_overwrite = 1;
232 break;
Dimitrie O. Paund50fdcd2003-10-03 03:34:10 +0000233 case 'v':
234 verbose = 1;
235 break;
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000236 case 'h':
237 printf(help);
238 exit(0);
239 break;
240 default:
241 usage();
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000242 }
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000243 }
244
245 if (optind + 1 != argc) usage();
246 input_file_name = argv[optind];
247
248 if (!convert_dir) usage();
249
Dimitrie O. Paun4ff35b52003-10-01 03:13:31 +0000250 if (!process_resources(input_file_name, specific_file_name,
Dimitrie O. Paund50fdcd2003-10-03 03:34:10 +0000251 convert_dir == 'a', force_overwrite, verbose))
Dimitrie O. Paunfb9c47d2003-09-18 20:53:10 +0000252 {
253 perror("Processing failed");
254 exit(1);
255 }
256
257 return 0;
Juergen Schmied04f7fe71999-11-13 22:32:21 +0000258}