3 // Copyright (C) 2007 Daniel Hokka Zakrisson <daniel@hozac.com>
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or (at your option)
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #include <sys/types.h>
37 #include "lib/internal.h"
38 #include "pathconfig.h"
40 #define ENSC_WRAPPERS_PREFIX "h2ext: "
41 #define ENSC_WRAPPERS_UNISTD 1
42 #define ENSC_WRAPPERS_FCNTL 1
43 #define ENSC_WRAPPERS_STAT 1
46 #define MAX_PEEK_SIZE 4096
47 #define MIN(a,b) (((a) > (b)) ? (b) : (a))
50 /* where the value would be in the file */
66 /* length of the value */
68 /* program to use for extraction */
70 /* should we try to process the contents as well? */
73 struct file_format *next;
75 typedef struct file_format file_format_t;
77 int wrapper_exit_code = 255;
79 #define CMD_HELP 0x4001
80 #define CMD_VERSION 0x4002
84 { "help", no_argument, 0, CMD_HELP },
85 { "version", no_argument, 0, CMD_VERSION },
86 { "desc", required_argument, 0, 'd' },
87 { "silent", no_argument, 0, 'q' },
92 showHelp(int fd, char const *cmd, int res)
94 WRITE_MSG(fd, "Usage:\n ");
97 " -d <descriptions file> <file1> [<file2>...]\n\n"
98 "Please report bugs to " PACKAGE_BUGREPORT "\n");
107 "h2ext " VERSION " -- determines how to extract a file\n"
108 "This program is part of " PACKAGE_STRING "\n\n"
109 "Copyright (C) 2007 Daniel Hokka Zakrisson\n"
110 VERSION_COPYRIGHT_DISCLAIMER);
114 static file_format_t *
115 find_format(file_format_t *head, char *data)
119 for (i = head; i; i = i->next) {
120 switch (i->type & ~(FFT_LE|FFT_BE)) {
122 if (memcmp(i->value.st, data + i->offset, i->len) == 0)
126 if (i->value.sh == *((__typeof__(i->value.sh) *)data + i->offset))
130 if (i->value.lo == *((__typeof__(i->value.lo) *)data + i->offset))
140 process_file(file_format_t *head, const char *file, file_format_t *ret[2])
146 fd = EopenD(file, O_RDONLY, 0);
148 mapping = mmap(NULL, MIN(st.st_size, MAX_PEEK_SIZE), PROT_READ, MAP_SHARED, fd, 0);
155 ret[0] = find_format(head, mapping);
157 munmap(mapping, MIN(st.st_size, MAX_PEEK_SIZE));
159 if (ret[0] && ret[0]->peek_inside) {
163 Elseek(fd, 0, SEEK_SET);
168 char *argv[3] = { PROG_H2EXT_WORKER, ret[0]->extractor, NULL };
171 EexecvpD(PROG_H2EXT_WORKER, argv);
174 char *buf = calloc(MAX_PEEK_SIZE, sizeof(char)), *cur, *end;
177 /* read MAX_PEEK_SIZE bytes from the decompressor */
179 end = buf + MAX_PEEK_SIZE;
180 while (cur < end && (bytes_read = Eread(fds[0], cur, end - cur - 1)) > 0)
183 /* get rid of the child */
184 kill(child, SIGTERM);
187 ret[1] = find_format(head, buf);
200 byteswap(void *p, size_t len)
204 for (i = 0; i < (len >> 1); i++) {
205 tmp = buf[len - i - 1];
206 buf[len - i - 1] = buf[i];
211 static inline ALWAYSINLINE void
212 WRITE_INT(int fd, int num)
214 char buf[sizeof(num)*3+2];
217 l = utilvserver_fmt_long(buf,num);
223 load_description(const char *file, file_format_t **head)
225 file_format_t *prev = NULL,
236 fd = EopenD(file, O_RDONLY, 0);
240 if ((eol = strchr(buf, '\n')) == NULL && (end - buf) < (sizeof(buf) - 1)) {
241 bytes_read = Eread(fd, end, sizeof(buf) - 1 - (end - buf));
242 /* EOF, implicit newline */
243 if (bytes_read == 0) {
253 else if (eol == NULL) {
254 WRITE_MSG(2, ENSC_WRAPPERS_PREFIX);
257 WRITE_INT(2, line_no);
258 WRITE_MSG(2, " is a really long line\n");
265 if (*buf == '#' || *buf == '\0')
268 i = *head = calloc(1, sizeof(file_format_t));
270 i->next = calloc(1, sizeof(file_format_t));
276 #define get_field() for (ptr++; *ptr == '\t' && *ptr != '\0'; ptr++); \
277 for (field = ptr; *ptr != '\t' && *ptr != '\0'; ptr++); \
280 while (*ptr != '\t' && *ptr != '\0')
284 goto new_line_and_free;
285 i->offset = strtol(field, NULL, 0);
288 if (strcmp(field, "string") == 0)
289 i->type = FFT_STRING;
290 else if (strcmp(field, "short") == 0)
292 else if (strcmp(field, "long") == 0)
294 else if (strcmp(field, "leshort") == 0)
295 i->type = FFT_SHORT|FFT_LE;
296 else if (strcmp(field, "beshort") == 0)
297 i->type = FFT_SHORT|FFT_BE;
298 else if (strcmp(field, "lelong") == 0)
299 i->type = FFT_LONG|FFT_LE;
300 else if (strcmp(field, "belong") == 0)
301 i->type = FFT_LONG|FFT_BE;
303 WRITE_MSG(2, ENSC_WRAPPERS_PREFIX);
306 WRITE_INT(2, line_no);
307 WRITE_MSG(2, " has an unknown type: ");
310 goto new_line_and_free;
314 switch (i->type & ~(FFT_BE|FFT_LE)) {
318 i->value.st = tmp = calloc(strlen(field) + 1, sizeof(char));
319 for (c = field; *c; c++) {
322 *(tmp++) = (char)strtol(c + 1, &endptr, 8);
329 i->len = tmp - i->value.st;
333 i->len = sizeof(i->value.sh);
334 i->value.sh = (__typeof__(i->value.sh))strtol(field, NULL, 0);
335 #if BYTE_ORDER != BIG_ENDIAN
336 if (i->type & FFT_BE)
337 #elif BYTE_ORDER != LITTLE_ENDIAN
338 if (i->type & FFT_LE)
340 # error UNKNOWN BYTE ORDER
342 byteswap(&i->value.sh, i->len);
345 i->len = sizeof(i->value.lo);
346 i->value.lo = (__typeof__(i->value.lo))strtol(field, NULL, 0);
347 #if BYTE_ORDER != BIG_ENDIAN
348 if (i->type & FFT_BE)
349 #elif BYTE_ORDER != LITTLE_ENDIAN
350 if (i->type & FFT_LE)
352 # error UNKNOWN BYTE ORDER
354 byteswap(&i->value.lo, i->len);
359 i->extractor = strdup(field);
362 i->peek_inside = (int)strtol(field, NULL, 0);
377 memmove(buf, eol + 1, end - (eol + 1));
378 end = buf + (end - (eol + 1));
385 int main(int argc, char *argv[])
389 file_format_t *head = NULL;
393 int c = getopt_long(argc, argv, "+d:q", CMDLINE_OPTIONS, 0);
397 case CMD_HELP: showHelp(1, argv[0], 0);
398 case CMD_VERSION: showVersion();
399 case 'd': desc = optarg; break;
400 case 'q': quiet = 1; break;
402 WRITE_MSG(2, "Try '");
403 WRITE_STR(2, argv[0]);
404 WRITE_MSG(2, " --help' for more information.\n");
405 return wrapper_exit_code;
410 WRITE_MSG(2, "No descriptions supplied, try '");
411 WRITE_STR(2, argv[0]);
412 WRITE_MSG(2, " --help' for more information.\n");
413 return wrapper_exit_code;
417 if (load_description(desc, &head) == -1)
420 for (file = argv + optind; *file; file++) {
421 file_format_t *formats[2];
426 if (!process_file(head, *file, formats) && formats[0]) {
427 WRITE_STR(1, formats[0]->extractor);
428 if (formats[0]->peek_inside) {
430 WRITE_STR(1, formats[1] ? formats[1]->extractor : "unknown format");
434 WRITE_MSG(1, "unknown format");