| #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; |
| 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 = clen; |
| 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; |
| } |
| } |