/* zipcat.c -- inflate a single-file PKZIP archive to stdout * by Sam Hocevar */ #include #include #include #include #include #define READSIZE 128 /* Read buffer size */ #define WRITESIZE 128 /* Inflate buffer size */ /* ZIP file handle structure */ struct zipfile { unsigned char read_buffer[READSIZE]; z_stream stream; gzFile gz; }; typedef struct zipfile *zipfile; /* Open ZIP file */ static zipfile zipopen(const char *filename) { uint8_t buf[4]; unsigned int skip_size = 0; zipfile zip = malloc(sizeof(*zip)); zip->gz = gzopen(filename, "rb"); if(!zip->gz) { free(zip); return NULL; } /* Parse ZIP file and go to start of first file */ gzread(zip->gz, buf, 4); if(memcmp(buf, "PK\3\4", 4)) { free(zip); gzclose(zip->gz); return NULL; } gzseek(zip->gz, 22, SEEK_CUR); gzread(zip->gz, buf, 2); /* Filename size */ skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8); gzread(zip->gz, buf, 2); /* Extra field size */ skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8); gzseek(zip->gz, skip_size, SEEK_CUR); /* Initialise inflate stream */ zip->stream.total_out = 0; zip->stream.zalloc = NULL; zip->stream.zfree = NULL; zip->stream.opaque = NULL; zip->stream.next_in = NULL; zip->stream.avail_in = 0; if(inflateInit2(&zip->stream, -MAX_WBITS)) { free(zip); gzclose(zip->gz); return NULL; } return zip; } /* Read ZIP file */ static int zipread(zipfile zip, void *buf, unsigned int len) { unsigned int total_read = 0; if(len == 0) return 0; zip->stream.next_out = buf; zip->stream.avail_out = len; while(zip->stream.avail_out > 0) { unsigned int tmp; int ret = 0; if(zip->stream.avail_in == 0 && !gzeof(zip->gz)) { int read; read = gzread(zip->gz, zip->read_buffer, READSIZE); if(read < 0) return -1; zip->stream.next_in = zip->read_buffer; zip->stream.avail_in = read; } tmp = zip->stream.total_out; ret = inflate(&zip->stream, Z_SYNC_FLUSH); total_read += zip->stream.total_out - tmp; if(ret == Z_STREAM_END) return total_read; if(ret != Z_OK) return ret; } return total_read; } /* Close ZIP file */ static int zipclose(zipfile zip) { inflateEnd(&zip->stream); gzclose(zip->gz); free(zip); return 0; } int main(int argc, char *argv[]) { unsigned char buf[WRITESIZE]; zipfile zip; int read; zip = zipopen(argv[1]); if(!zip) return -1; while((read = zipread(zip, buf, WRITESIZE)) > 0) { if(fwrite(buf, read, 1, stdout) != 1) { fprintf(stderr, "write error\n"); zipclose(zip); return -1; } } zipclose(zip); if(read < 0) { fprintf(stderr, "read error\n"); return -1; } return 0; }