diff --git a/myunzip0.c b/myunzip0.c new file mode 100644 index 0000000000000000000000000000000000000000..0f158ea75d6a9b123fee13d014bb1d659df4bcf9 --- /dev/null +++ b/myunzip0.c @@ -0,0 +1,89 @@ +#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; +} diff --git a/spec.pdf b/spec.pdf new file mode 100644 index 0000000000000000000000000000000000000000..37c33225f706e766fed766e7c7e7e3068c9304f1 Binary files /dev/null and b/spec.pdf differ