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