#include <stdio.h> #include <string.h> #include <stdlib.h> #include <stdint.h> struct file_record { uint32_t signature; uint16_t version; uint16_t flag; uint16_t compression; uint16_t mod_time; uint16_t mod_date; uint32_t crc32; uint32_t compressed_size; uint32_t uncompressed_size; uint16_t file_name_len; uint16_t extra_len; } /* Don't pad this struct, i.e. guaranteed that sizeof(struct file_record) = * sum of the sizes of its elements. This makes the code a bit nicer; * we can just fread() the first sizeof(struct file_record) bytes in the * file directly into the struct. */ __attribute__((packed)); typedef struct file_record file_record_t; const int UNCOMPRESSED = 0; const int DEFLATE = 8; void unzip(FILE *fp) { file_record_t *record = (file_record_t *) malloc(sizeof(file_record_t)); if (!record) { fprintf(stderr, "error: memory error\n"); exit(1); } /* Read metadata */ fread(record, 1, sizeof(file_record_t), fp); char *fname = (char *) malloc(record->file_name_len); fread(fname, 1, record->file_name_len, fp); /* Move pointer to start of file data */ fseek(fp, record->extra_len, SEEK_CUR); int size; if (record->compression == UNCOMPRESSED) { size = record->uncompressed_size; } else if (record->compression == DEFLATE) { size = record->compressed_size; strcat(fname, ".deflate"); } else { fprintf(stderr, "error: invalid compression\n"); exit(1); } FILE *out = fopen(fname, "wb"); /* TODO is there a better way to do this? * worried about storing a huge buffer for large files... */ char *buf = (char *) malloc(size * sizeof(char)); fread(buf, 1, size, fp); fwrite(buf, 1, size, out); fclose(out); free(record); } int main(int argc, char *argv[]) { FILE *fp; if (argc != 2) { fprintf(stderr, "usage: myunzip0 [filename]\n"); return 1; } fp = fopen(argv[1], "rb"); if (!fp) { fprintf(stderr, "error: no such file\n"); return 1; } unzip(fp); fclose(fp); return 0; }