diff options
Diffstat (limited to 'libzipfile/zipfile.c')
-rw-r--r-- | libzipfile/zipfile.c | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/libzipfile/zipfile.c b/libzipfile/zipfile.c new file mode 100644 index 000000000..b52d02df7 --- /dev/null +++ b/libzipfile/zipfile.c @@ -0,0 +1,160 @@ +#include <zipfile/zipfile.h> + +#include "private.h" +#include <stdlib.h> +#include <string.h> +#include <zlib.h> +#define DEF_MEM_LEVEL 8 // normally in zutil.h? + +zipfile_t +init_zipfile(const void* data, size_t size) +{ + int err; + + Zipfile *file = malloc(sizeof(Zipfile)); + if (file == NULL) return NULL; + memset(file, 0, sizeof(Zipfile)); + file->buf = data; + file->bufsize = size; + + err = read_central_dir(file); + if (err != 0) goto fail; + + return file; +fail: + free(file); + return NULL; +} + +void +release_zipfile(zipfile_t f) +{ + Zipfile* file = (Zipfile*)f; + Zipentry* entry = file->entries; + while (entry) { + Zipentry* next = entry->next; + free(entry); + entry = next; + } + free(file); +} + +zipentry_t +lookup_zipentry(zipfile_t f, const char* entryName) +{ + Zipfile* file = (Zipfile*)f; + Zipentry* entry = file->entries; + while (entry) { + if (0 == memcmp(entryName, entry->fileName, entry->fileNameLength)) { + return entry; + } + entry = entry->next; + } + return NULL; +} + +size_t +get_zipentry_size(zipentry_t entry) +{ + return ((Zipentry*)entry)->uncompressedSize; +} + +char* +get_zipentry_name(zipentry_t entry) +{ + Zipentry* e = (Zipentry*)entry; + int l = e->fileNameLength; + char* s = malloc(l+1); + memcpy(s, e->fileName, l); + s[l] = '\0'; + return s; +} + +enum { + STORED = 0, + DEFLATED = 8 +}; + +static int +uninflate(unsigned char* out, int unlen, const unsigned char* in, int clen) +{ + z_stream zstream; + unsigned long crc; + int err = 0; + int zerr; + + memset(&zstream, 0, sizeof(zstream)); + zstream.zalloc = Z_NULL; + zstream.zfree = Z_NULL; + zstream.opaque = Z_NULL; + zstream.next_in = (void*)in; + zstream.avail_in = unlen; + zstream.next_out = (Bytef*) out; + zstream.avail_out = unlen; + zstream.data_type = Z_UNKNOWN; + + // Use the undocumented "negative window bits" feature to tell zlib + // that there's no zlib header waiting for it. + zerr = inflateInit2(&zstream, -MAX_WBITS); + if (zerr != Z_OK) { + return -1; + } + + // uncompress the data + zerr = inflate(&zstream, Z_FINISH); + if (zerr != Z_STREAM_END) { + fprintf(stderr, "zerr=%d Z_STREAM_END=%d total_out=%lu\n", zerr, Z_STREAM_END, + zstream.total_out); + err = -1; + } + + inflateEnd(&zstream); + return err; +} + +int +decompress_zipentry(zipentry_t e, void* buf, int bufsize) +{ + Zipentry* entry = (Zipentry*)e; + switch (entry->compressionMethod) + { + case STORED: + memcpy(buf, entry->data, entry->uncompressedSize); + return 0; + case DEFLATED: + return uninflate(buf, bufsize, entry->data, entry->compressedSize); + default: + return -1; + } +} + +void +dump_zipfile(FILE* to, zipfile_t file) +{ + Zipfile* zip = (Zipfile*)file; + Zipentry* entry = zip->entries; + int i; + + fprintf(to, "entryCount=%d\n", zip->entryCount); + for (i=0; i<zip->entryCount; i++) { + fprintf(to, " file \""); + fwrite(entry->fileName, entry->fileNameLength, 1, to); + fprintf(to, "\"\n"); + entry = entry->next; + } +} + +zipentry_t +iterate_zipfile(zipfile_t file, void** cookie) +{ + Zipentry* entry = (Zipentry*)*cookie; + if (entry == NULL) { + Zipfile* zip = (Zipfile*)file; + *cookie = zip->entries; + return *cookie; + } else { + entry = entry->next; + *cookie = entry; + return entry; + } +} |