/* * Scan for and extract gzip from stdin stream to stdout * * Written by Harry Sintonen . * Public Domain. * * USAGE * * ./scangzip numgzip < infile > outfile * ...where numgzip is the index of the gzip file to extract, starting * from 0. * * NOTES * * If false positive is found, the program will still report success. * If this happens just bump the index to skip the bogus entry. */ #include #include #include #include #include #ifndef STDIN_FILENO #define STDIN_FILENO 0 #endif typedef unsigned char u8; #define GZF_ASCII (1 << 0) #define GZF_CONTINUATION (1 << 1) #define GZF_EXTRA_FIELD (1 << 2) #define GZF_ORIG_NAME (1 << 3) #define GZF_COMMENT (1 << 4) #define GZF_ENCRYPTED (1 << 5) #define GZF_RESERVED0 (1 << 6) #define GZF_RESERVED1 (1 << 7) #define INVALIDFLAGS (GZF_CONTINUATION | GZF_ENCRYPTED | GZF_RESERVED0 | GZF_RESERVED1) #define MSIZE 4 static const u8 gzip_magic[MSIZE * 2] = { 0x1f, 0x8b, 0x08, 0, 0xff, 0xff, 0xff, INVALIDFLAGS }; static const u8 old_gzip_magic[MSIZE * 2] = { 0x1f, 0x9e, 0x08, 0, 0xff, 0xff, 0xff, INVALIDFLAGS }; static int gunzip(u8 *header, int hsize) { FILE *fh; ssize_t actual; u8 buf[4096]; int rc = -1; fh = popen("gzip -d", "w"); if (!fh) { perror("popen"); return rc; } if (hsize && fwrite(header, 1, hsize, fh) != hsize) { perror("fwrite"); return rc; } rc = 0; while ((actual = fread(buf, 1, sizeof(buf), stdin)) > 0) { if (fwrite(buf, 1, actual, fh) != actual) { if (errno != EPIPE) { perror("fwrite"); rc = -1; } break; } } if (actual < 0) { perror("fread"); rc = -1; } if (pclose(fh) < 0) { perror("pclose"); rc = -1; } return rc; } struct data { int c; int offs; int cnt; int num; }; static inline void chkgzip(struct data *data, const u8 *magic, int *ip) { u8 c = (u8) data->c; int i = *ip; if ((c & magic[i + MSIZE]) == magic[i]) { if (i == MSIZE - 1) { fprintf(stderr, "%d: found potential gzip header at offset 0x%x\n", data->cnt, data->offs - 3); if (data->cnt == data->num) { u8 buf[4] = {magic[0], magic[1], magic[2], (u8)c}; int rc; rc = gunzip(buf, sizeof(buf)); if (rc == 0) { fprintf(stderr, "Ok\n"); exit(EXIT_SUCCESS); } } data->cnt++; *ip = 0; } else { *ip = i + 1; } } else { *ip = 0; } } int main(int argc, char **argv) { struct data data; int gmi, ogmi; if (argc != 2) { fprintf(stderr, "usage: %s numgzip < infile > outfile\n", argv[0]); return EXIT_FAILURE; } data.offs = 0; data.cnt = 0; data.num = atoi(argv[1]); gmi = 0; ogmi = 0; signal(SIGPIPE, SIG_IGN); for (;;) { data.c = getchar(); if (data.c == EOF) { break; } chkgzip(&data, gzip_magic, &gmi); chkgzip(&data, old_gzip_magic, &ogmi); data.offs++; } fprintf(stderr, "could not find gzip number %d\n", data.num); return EXIT_FAILURE; }