Avoid divide by zero if the sound driver returns 0 for speed.
[wine/multimedia.git] / tools / bin2res.c
blob5297b2655ef3e8908f23f6cb2a80655d61fb4cbc
1 /************************************************
3 * Converting binary resources from/to *.rc files
5 * Copyright 1999 Juergen Schmied
6 * Copyright 2003 Dimitrie O. Paun
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.
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.
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
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <sys/stat.h>
31 #ifdef HAVE_SYS_PARAM_H
32 # include <sys/param.h>
33 #endif
35 static const char* help =
36 "Usage: bin2res [-x] | [-a] [-f] [-h] <rsrc.rc>\n"
37 " -a archive binaries into the <rsrc.rc> file\n"
38 " -x extract binaries from the <rsrc.rc> file\n"
39 " -f force processing of older resources\n"
40 " -h print this help screen and exit\n"
41 "\n"
42 "This tool allows the insertion/extractions of embedded binary\n"
43 "resources to/from .rc files, for storage within the cvs tree.\n"
44 "This is accomplished by placing a magic marker in a comment\n"
45 "just above the resource. The marker consists of the BINRES\n"
46 "string followed by the file name. For example, to insert a\n"
47 "brand new binary resource in a .rc file, place the marker\n"
48 "above empty brackets:\n"
49 " /* BINRES idb_std_small.bmp */\n"
50 " {}\n"
51 "To merge the binary resources into the .rc file, run:\n"
52 " bin2res -a myrsrc.rc\n"
53 "Only resources that are newer than the .rc are processed.\n"
54 "To extract the binary resources from the .rc file, run:\n"
55 " bin2res -x myrsrc.rc\n"
56 "Binary files newer than the .rc file are not overwritten.\n"
57 "\n"
58 "To force processing of all resources, use the -f flag.\n";
60 void usage(void)
62 printf(help);
63 exit(1);
66 int insert_hexdump (FILE* outfile, FILE* infile)
68 int i, c;
70 fprintf (outfile, "{\n '");
71 for (i = 0; (c = fgetc(infile)) != EOF; i++)
73 if (i && (i % 16) == 0) fprintf (outfile, "'\n '");
74 if (i % 16) fprintf (outfile, " ");
75 fprintf(outfile, "%02X", c);
77 fprintf (outfile, "'\n}");
79 return 1;
82 int hex2bin(char c)
84 if (!isxdigit(c)) return -1024;
85 if (isdigit(c)) return c - '0';
86 return toupper(c) - 'A' + 10;
89 int extract_hexdump (FILE* outfile, FILE* infile)
91 int byte, c;
93 while ( (c = fgetc(infile)) != EOF && c != '}')
95 if (isspace(c) || c == '\'') continue;
96 byte = 16 * hex2bin(c);
97 c = fgetc(infile);
98 if (c == EOF) return 0;
99 byte += hex2bin(c);
100 if (byte < 0) return 0;
101 fputc(byte, outfile);
103 return 1;
106 const char* parse_marker(const char *line, time_t* last_updated)
108 static char res_file_name[PATH_MAX], *rpos, *wpos;
109 struct stat st;
111 if (!(rpos = strstr(line, "BINRES"))) return 0;
112 for (rpos += 6; *rpos && isspace(*rpos); rpos++) /**/;
113 for (wpos = res_file_name; *rpos && !isspace(*rpos); ) *wpos++ = *rpos++;
114 *wpos = 0;
116 *last_updated = (stat(res_file_name, &st) < 0) ? 0 : st.st_mtime;
118 return res_file_name;
121 int process_resources(const char* input_file_name, int inserting, int force_processing)
123 char buffer[2048], tmp_file_name[PATH_MAX];
124 const char *res_file_name;
125 time_t rc_last_update, res_last_update;
126 FILE *fin, *fres, *ftmp = 0;
127 struct stat st;
128 int fd, c;
130 if (!(fin = fopen(input_file_name, "r"))) return 0;
131 if (stat(input_file_name, &st) < 0) return 0;
132 rc_last_update = st.st_mtime;
134 if (inserting)
136 strcpy(tmp_file_name, input_file_name);
137 strcat(tmp_file_name, "-XXXXXX.temp");
138 if ((fd = mkstemps(tmp_file_name, 5)) == -1)
140 strcpy(tmp_file_name, "/tmp/bin2res-XXXXXX.temp");
141 if ((fd = mkstemps(tmp_file_name, 5)) == -1) return 0;
143 if (!(ftmp = fdopen(fd, "w"))) return 0;
146 for (c = EOF; fgets(buffer, sizeof(buffer), fin); c = EOF)
148 if (inserting) fprintf(ftmp, "%s", buffer);
149 if (!(res_file_name = parse_marker(buffer, &res_last_update))) continue;
150 if (!force_processing && ((rc_last_update < res_last_update) == !inserting))
152 printf("skipping '%s'\n", res_file_name);
153 continue;
156 printf("processing '%s'\n", res_file_name);
157 while ( (c = fgetc(fin)) != EOF && c != '{')
158 if (inserting) fputc(c, ftmp);
159 if (c == EOF) break;
161 if (!(fres = fopen(res_file_name, inserting ? "r" : "w"))) break;
162 if (inserting)
164 if (!insert_hexdump(ftmp, fres)) break;
165 while ( (c = fgetc(fin)) != EOF && c != '}') /**/;
167 else
169 if (!extract_hexdump(fres, fin)) break;
171 fclose(fres);
174 fclose(fin);
176 if (inserting)
178 fclose(ftmp);
179 if (c == EOF && rename(tmp_file_name, input_file_name) < 0)
180 c = '.'; /* force an error */
181 else unlink(tmp_file_name);
184 return c == EOF;
187 int main(int argc, char **argv)
189 int convert_dir = 0, optc;
190 int force_overwrite = 0;
191 const char* input_file_name;
193 while((optc = getopt(argc, argv, "axfh")) != EOF)
195 switch(optc)
197 case 'a':
198 case 'x':
199 if (convert_dir) usage();
200 convert_dir = optc;
201 break;
202 case 'f':
203 force_overwrite = 1;
204 break;
205 case 'h':
206 printf(help);
207 exit(0);
208 break;
209 default:
210 usage();
214 if (optind + 1 != argc) usage();
215 input_file_name = argv[optind];
217 if (!convert_dir) usage();
219 if (!process_resources(input_file_name, convert_dir == 'a', force_overwrite))
221 perror("Processing failed");
222 exit(1);
225 return 0;