Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 1 | /************************************************ |
| 2 | * |
| 3 | * Converting binary resources from/to *.rc files |
| 4 | * |
| 5 | * Copyright 1999 Juergen Schmied |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 6 | * Copyright 2003 Dimitrie O. Paun |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 7 | * |
| 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 Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 21 | */ |
| 22 | |
| 23 | #include "config.h" |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 24 | #include "wine/port.h" |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 25 | |
| 26 | #include <stdio.h> |
| 27 | #include <stdlib.h> |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 28 | #include <ctype.h> |
| 29 | #include <string.h> |
| 30 | #include <sys/stat.h> |
Robert Lunnon | 16bd45d | 2004-01-14 05:12:33 +0000 | [diff] [blame] | 31 | #include <limits.h> |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 32 | #ifdef HAVE_SYS_PARAM_H |
| 33 | # include <sys/param.h> |
Patrik Stridvall | 9af5e69 | 1999-12-11 23:02:15 +0000 | [diff] [blame] | 34 | #endif |
François Gouget | 44a1822 | 2000-12-19 04:53:20 +0000 | [diff] [blame] | 35 | |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 36 | static const char* help = |
Dimitrie O. Paun | 4ff35b5 | 2003-10-01 03:13:31 +0000 | [diff] [blame] | 37 | "Usage: bin2res [OPTIONS] <rsrc.rc>\n" |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 38 | " -a archive binaries into the <rsrc.rc> file\n" |
| 39 | " -x extract binaries from the <rsrc.rc> file\n" |
Dimitrie O. Paun | 4ff35b5 | 2003-10-01 03:13:31 +0000 | [diff] [blame] | 40 | " -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. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 42 | " -f force processing of older resources\n" |
Dimitrie O. Paun | d50fdcd | 2003-10-03 03:34:10 +0000 | [diff] [blame] | 43 | " -v causes the command to be verbous during processing\n" |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 44 | " -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 Shearman | e548339 | 2004-09-06 20:26:35 +0000 | [diff] [blame] | 54 | " IDB_STD_SMALL BITMAP idb_std_small.bmp\n" |
| 55 | " /* {\n" |
| 56 | " } */\n" |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 57 | "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. Paun | 4ff35b5 | 2003-10-01 03:13:31 +0000 | [diff] [blame] | 64 | "To force processing of all resources, use the -f flag.\n" |
| 65 | "To process a particular file, use the -i/-o options.\n"; |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 66 | |
Stefan Huehner | e546238 | 2005-06-15 18:10:39 +0000 | [diff] [blame] | 67 | static void usage(void) |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 68 | { |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 69 | printf(help); |
| 70 | exit(1); |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 71 | } |
| 72 | |
Stefan Huehner | e546238 | 2005-06-15 18:10:39 +0000 | [diff] [blame] | 73 | static int insert_hexdump (FILE* outfile, FILE* infile) |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 74 | { |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 75 | int i, c; |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 76 | |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 77 | 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 Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 85 | |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 86 | return 1; |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 87 | } |
| 88 | |
Stefan Huehner | e546238 | 2005-06-15 18:10:39 +0000 | [diff] [blame] | 89 | static int hex2bin(char c) |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 90 | { |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 91 | if (!isxdigit(c)) return -1024; |
| 92 | if (isdigit(c)) return c - '0'; |
| 93 | return toupper(c) - 'A' + 10; |
| 94 | } |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 95 | |
Stefan Huehner | e546238 | 2005-06-15 18:10:39 +0000 | [diff] [blame] | 96 | static int extract_hexdump (FILE* outfile, FILE* infile) |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 97 | { |
| 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 Huehner | e546238 | 2005-06-15 18:10:39 +0000 | [diff] [blame] | 113 | static const char* parse_marker(const char *line, time_t* last_updated) |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 114 | { |
| 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 Huehner | e546238 | 2005-06-15 18:10:39 +0000 | [diff] [blame] | 128 | static int process_resources(const char* input_file_name, const char* specific_file_name, |
Dimitrie O. Paun | d50fdcd | 2003-10-03 03:34:10 +0000 | [diff] [blame] | 129 | int inserting, int force_processing, int verbose) |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 130 | { |
| 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 Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 147 | { |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 148 | strcpy(tmp_file_name, "/tmp/bin2res-XXXXXX.temp"); |
| 149 | if ((fd = mkstemps(tmp_file_name, 5)) == -1) return 0; |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 150 | } |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 151 | 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. Paun | 4ff35b5 | 2003-10-01 03:13:31 +0000 | [diff] [blame] | 158 | if ( (specific_file_name && strcmp(specific_file_name, res_file_name)) || |
| 159 | (!force_processing && ((rc_last_update < res_last_update) == !inserting)) ) |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 160 | { |
Dimitrie O. Paun | d50fdcd | 2003-10-03 03:34:10 +0000 | [diff] [blame] | 161 | if (verbose) printf("skipping '%s'\n", res_file_name); |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 162 | continue; |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 163 | } |
| 164 | |
Dimitrie O. Paun | d50fdcd | 2003-10-03 03:34:10 +0000 | [diff] [blame] | 165 | if (verbose) printf("processing '%s'\n", res_file_name); |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 166 | while ( (c = fgetc(fin)) != EOF && c != '{') |
| 167 | if (inserting) fputc(c, ftmp); |
| 168 | if (c == EOF) break; |
| 169 | |
Pavel Roskin | 671f02c | 2003-10-06 21:05:28 +0000 | [diff] [blame] | 170 | if (!(fres = fopen(res_file_name, inserting ? "rb" : "wb"))) break; |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 171 | if (inserting) |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 172 | { |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 173 | if (!insert_hexdump(ftmp, fres)) break; |
| 174 | while ( (c = fgetc(fin)) != EOF && c != '}') /**/; |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 175 | } |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 176 | else |
Hidenori Takeshima | a85b0a6 | 2000-11-25 23:54:12 +0000 | [diff] [blame] | 177 | { |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 178 | if (!extract_hexdump(fres, fin)) break; |
Hidenori Takeshima | a85b0a6 | 2000-11-25 23:54:12 +0000 | [diff] [blame] | 179 | } |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 180 | fclose(fres); |
| 181 | } |
Hidenori Takeshima | a85b0a6 | 2000-11-25 23:54:12 +0000 | [diff] [blame] | 182 | |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 183 | fclose(fin); |
Hidenori Takeshima | a85b0a6 | 2000-11-25 23:54:12 +0000 | [diff] [blame] | 184 | |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 185 | if (inserting) |
| 186 | { |
| 187 | fclose(ftmp); |
Alexandre Julliard | e97fb4b | 2004-01-18 23:32:56 +0000 | [diff] [blame] | 188 | 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. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 200 | else unlink(tmp_file_name); |
| 201 | } |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 202 | |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 203 | return c == EOF; |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 204 | } |
| 205 | |
| 206 | int main(int argc, char **argv) |
| 207 | { |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 208 | int convert_dir = 0, optc; |
Dimitrie O. Paun | d50fdcd | 2003-10-03 03:34:10 +0000 | [diff] [blame] | 209 | int force_overwrite = 0, verbose = 0; |
Dimitrie O. Paun | 4ff35b5 | 2003-10-01 03:13:31 +0000 | [diff] [blame] | 210 | const char* input_file_name = 0; |
| 211 | const char* specific_file_name = 0; |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 212 | |
Robert Shearman | cadf6fc | 2004-03-09 03:44:22 +0000 | [diff] [blame] | 213 | while((optc = getopt(argc, argv, "axi:o:fhv")) != EOF) |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 214 | { |
| 215 | switch(optc) |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 216 | { |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 217 | case 'a': |
| 218 | case 'x': |
| 219 | if (convert_dir) usage(); |
| 220 | convert_dir = optc; |
| 221 | break; |
Dimitrie O. Paun | 4ff35b5 | 2003-10-01 03:13:31 +0000 | [diff] [blame] | 222 | 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. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 230 | case 'f': |
| 231 | force_overwrite = 1; |
| 232 | break; |
Dimitrie O. Paun | d50fdcd | 2003-10-03 03:34:10 +0000 | [diff] [blame] | 233 | case 'v': |
| 234 | verbose = 1; |
| 235 | break; |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 236 | case 'h': |
| 237 | printf(help); |
| 238 | exit(0); |
| 239 | break; |
| 240 | default: |
| 241 | usage(); |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 242 | } |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 243 | } |
| 244 | |
| 245 | if (optind + 1 != argc) usage(); |
| 246 | input_file_name = argv[optind]; |
| 247 | |
| 248 | if (!convert_dir) usage(); |
| 249 | |
Dimitrie O. Paun | 4ff35b5 | 2003-10-01 03:13:31 +0000 | [diff] [blame] | 250 | if (!process_resources(input_file_name, specific_file_name, |
Dimitrie O. Paun | d50fdcd | 2003-10-03 03:34:10 +0000 | [diff] [blame] | 251 | convert_dir == 'a', force_overwrite, verbose)) |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 252 | { |
| 253 | perror("Processing failed"); |
| 254 | exit(1); |
| 255 | } |
| 256 | |
| 257 | return 0; |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 258 | } |