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