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> |
| 31 | #ifdef HAVE_SYS_PARAM_H |
| 32 | # include <sys/param.h> |
Patrik Stridvall | 9af5e69 | 1999-12-11 23:02:15 +0000 | [diff] [blame] | 33 | #endif |
François Gouget | 44a1822 | 2000-12-19 04:53:20 +0000 | [diff] [blame] | 34 | |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 35 | static const char* help = |
Dimitrie O. Paun | 4ff35b5 | 2003-10-01 03:13:31 +0000 | [diff] [blame] | 36 | "Usage: bin2res [OPTIONS] <rsrc.rc>\n" |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 37 | " -a archive binaries into the <rsrc.rc> file\n" |
| 38 | " -x extract binaries from the <rsrc.rc> file\n" |
Dimitrie O. Paun | 4ff35b5 | 2003-10-01 03:13:31 +0000 | [diff] [blame] | 39 | " -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. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 41 | " -f force processing of older resources\n" |
Dimitrie O. Paun | d50fdcd | 2003-10-03 03:34:10 +0000 | [diff] [blame] | 42 | " -v causes the command to be verbous during processing\n" |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 43 | " -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. Paun | 4ff35b5 | 2003-10-01 03:13:31 +0000 | [diff] [blame] | 61 | "To force processing of all resources, use the -f flag.\n" |
| 62 | "To process a particular file, use the -i/-o options.\n"; |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 63 | |
| 64 | void usage(void) |
| 65 | { |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 66 | printf(help); |
| 67 | exit(1); |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 68 | } |
| 69 | |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 70 | int insert_hexdump (FILE* outfile, FILE* infile) |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 71 | { |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 72 | int i, c; |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 73 | |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 74 | 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 Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 82 | |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 83 | return 1; |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 84 | } |
| 85 | |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 86 | int hex2bin(char c) |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 87 | { |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 88 | if (!isxdigit(c)) return -1024; |
| 89 | if (isdigit(c)) return c - '0'; |
| 90 | return toupper(c) - 'A' + 10; |
| 91 | } |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 92 | |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 93 | int 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 | |
| 110 | const 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. Paun | d50fdcd | 2003-10-03 03:34:10 +0000 | [diff] [blame] | 125 | int process_resources(const char* input_file_name, const char* specific_file_name, |
| 126 | int inserting, int force_processing, int verbose) |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 127 | { |
| 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 Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 144 | { |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 145 | strcpy(tmp_file_name, "/tmp/bin2res-XXXXXX.temp"); |
| 146 | if ((fd = mkstemps(tmp_file_name, 5)) == -1) return 0; |
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 | 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. Paun | 4ff35b5 | 2003-10-01 03:13:31 +0000 | [diff] [blame] | 155 | if ( (specific_file_name && strcmp(specific_file_name, res_file_name)) || |
| 156 | (!force_processing && ((rc_last_update < res_last_update) == !inserting)) ) |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 157 | { |
Dimitrie O. Paun | d50fdcd | 2003-10-03 03:34:10 +0000 | [diff] [blame] | 158 | if (verbose) printf("skipping '%s'\n", res_file_name); |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 159 | continue; |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 160 | } |
| 161 | |
Dimitrie O. Paun | d50fdcd | 2003-10-03 03:34:10 +0000 | [diff] [blame] | 162 | if (verbose) printf("processing '%s'\n", res_file_name); |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 163 | while ( (c = fgetc(fin)) != EOF && c != '{') |
| 164 | if (inserting) fputc(c, ftmp); |
| 165 | if (c == EOF) break; |
| 166 | |
Pavel Roskin | 671f02c | 2003-10-06 21:05:28 +0000 | [diff] [blame] | 167 | if (!(fres = fopen(res_file_name, inserting ? "rb" : "wb"))) break; |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 168 | if (inserting) |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 169 | { |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 170 | if (!insert_hexdump(ftmp, fres)) break; |
| 171 | while ( (c = fgetc(fin)) != EOF && c != '}') /**/; |
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 | else |
Hidenori Takeshima | a85b0a6 | 2000-11-25 23:54:12 +0000 | [diff] [blame] | 174 | { |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 175 | if (!extract_hexdump(fres, fin)) break; |
Hidenori Takeshima | a85b0a6 | 2000-11-25 23:54:12 +0000 | [diff] [blame] | 176 | } |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 177 | fclose(fres); |
| 178 | } |
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(fin); |
Hidenori Takeshima | a85b0a6 | 2000-11-25 23:54:12 +0000 | [diff] [blame] | 181 | |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 182 | 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 Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 189 | |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 190 | return c == EOF; |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 191 | } |
| 192 | |
| 193 | int main(int argc, char **argv) |
| 194 | { |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 195 | int convert_dir = 0, optc; |
Dimitrie O. Paun | d50fdcd | 2003-10-03 03:34:10 +0000 | [diff] [blame] | 196 | int force_overwrite = 0, verbose = 0; |
Dimitrie O. Paun | 4ff35b5 | 2003-10-01 03:13:31 +0000 | [diff] [blame] | 197 | const char* input_file_name = 0; |
| 198 | const char* specific_file_name = 0; |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 199 | |
Dimitrie O. Paun | 4ff35b5 | 2003-10-01 03:13:31 +0000 | [diff] [blame] | 200 | while((optc = getopt(argc, argv, "axi:o:fh")) != EOF) |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 201 | { |
| 202 | switch(optc) |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 203 | { |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 204 | case 'a': |
| 205 | case 'x': |
| 206 | if (convert_dir) usage(); |
| 207 | convert_dir = optc; |
| 208 | break; |
Dimitrie O. Paun | 4ff35b5 | 2003-10-01 03:13:31 +0000 | [diff] [blame] | 209 | 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. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 217 | case 'f': |
| 218 | force_overwrite = 1; |
| 219 | break; |
Dimitrie O. Paun | d50fdcd | 2003-10-03 03:34:10 +0000 | [diff] [blame] | 220 | case 'v': |
| 221 | verbose = 1; |
| 222 | break; |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 223 | case 'h': |
| 224 | printf(help); |
| 225 | exit(0); |
| 226 | break; |
| 227 | default: |
| 228 | usage(); |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 229 | } |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 230 | } |
| 231 | |
| 232 | if (optind + 1 != argc) usage(); |
| 233 | input_file_name = argv[optind]; |
| 234 | |
| 235 | if (!convert_dir) usage(); |
| 236 | |
Dimitrie O. Paun | 4ff35b5 | 2003-10-01 03:13:31 +0000 | [diff] [blame] | 237 | if (!process_resources(input_file_name, specific_file_name, |
Dimitrie O. Paun | d50fdcd | 2003-10-03 03:34:10 +0000 | [diff] [blame] | 238 | convert_dir == 'a', force_overwrite, verbose)) |
Dimitrie O. Paun | fb9c47d | 2003-09-18 20:53:10 +0000 | [diff] [blame] | 239 | { |
| 240 | perror("Processing failed"); |
| 241 | exit(1); |
| 242 | } |
| 243 | |
| 244 | return 0; |
Juergen Schmied | 04f7fe7 | 1999-11-13 22:32:21 +0000 | [diff] [blame] | 245 | } |