zipfile.c revision 287c71ca84533da008e9cc240224910a9d05139e
1#include <zipfile/zipfile.h>
2
3#include "private.h"
4#include <stdlib.h>
5#include <string.h>
6#include <zlib.h>
7#define DEF_MEM_LEVEL 8                // normally in zutil.h?
8
9zipfile_t
10init_zipfile(const void* data, size_t size)
11{
12    int err;
13
14    Zipfile *file = malloc(sizeof(Zipfile));
15    if (file == NULL) return NULL;
16    memset(file, 0, sizeof(Zipfile));
17    file->buf = data;
18    file->bufsize = size;
19
20    err = read_central_dir(file);
21    if (err != 0) goto fail;
22
23    return file;
24fail:
25    free(file);
26    return NULL;
27}
28
29void
30release_zipfile(zipfile_t f)
31{
32    Zipfile* file = (Zipfile*)f;
33    Zipentry* entry = file->entries;
34    while (entry) {
35        Zipentry* next = entry->next;
36        free(entry);
37        entry = next;
38    }
39    free(file);
40}
41
42zipentry_t
43lookup_zipentry(zipfile_t f, const char* entryName)
44{
45    Zipfile* file = (Zipfile*)f;
46    Zipentry* entry = file->entries;
47    while (entry) {
48        if (0 == memcmp(entryName, entry->fileName, entry->fileNameLength)) {
49            return entry;
50        }
51        entry = entry->next;
52    }
53    return NULL;
54}
55
56size_t
57get_zipentry_size(zipentry_t entry)
58{
59    return ((Zipentry*)entry)->uncompressedSize;
60}
61
62char*
63get_zipentry_name(zipentry_t entry)
64{
65    Zipentry* e = (Zipentry*)entry;
66    int l = e->fileNameLength;
67    char* s = malloc(l+1);
68    memcpy(s, e->fileName, l);
69    s[l] = '\0';
70    return s;
71}
72
73enum {
74    STORED = 0,
75    DEFLATED = 8
76};
77
78static int
79uninflate(unsigned char* out, int unlen, const unsigned char* in, int clen)
80{
81    z_stream zstream;
82    unsigned long crc;
83    int err = 0;
84    int zerr;
85
86    memset(&zstream, 0, sizeof(zstream));
87    zstream.zalloc = Z_NULL;
88    zstream.zfree = Z_NULL;
89    zstream.opaque = Z_NULL;
90    zstream.next_in = (void*)in;
91    zstream.avail_in = clen;
92    zstream.next_out = (Bytef*) out;
93    zstream.avail_out = unlen;
94    zstream.data_type = Z_UNKNOWN;
95
96    // Use the undocumented "negative window bits" feature to tell zlib
97    // that there's no zlib header waiting for it.
98    zerr = inflateInit2(&zstream, -MAX_WBITS);
99    if (zerr != Z_OK) {
100        return -1;
101    }
102
103    // uncompress the data
104    zerr = inflate(&zstream, Z_FINISH);
105    if (zerr != Z_STREAM_END) {
106        fprintf(stderr, "zerr=%d Z_STREAM_END=%d total_out=%lu\n", zerr, Z_STREAM_END,
107                    zstream.total_out);
108        err = -1;
109    }
110
111     inflateEnd(&zstream);
112    return err;
113}
114
115int
116decompress_zipentry(zipentry_t e, void* buf, int bufsize)
117{
118    Zipentry* entry = (Zipentry*)e;
119    switch (entry->compressionMethod)
120    {
121        case STORED:
122            memcpy(buf, entry->data, entry->uncompressedSize);
123            return 0;
124        case DEFLATED:
125            return uninflate(buf, bufsize, entry->data, entry->compressedSize);
126        default:
127            return -1;
128    }
129}
130
131void
132dump_zipfile(FILE* to, zipfile_t file)
133{
134    Zipfile* zip = (Zipfile*)file;
135    Zipentry* entry = zip->entries;
136    int i;
137
138    fprintf(to, "entryCount=%d\n", zip->entryCount);
139    for (i=0; i<zip->entryCount; i++) {
140        fprintf(to, "  file \"");
141        fwrite(entry->fileName, entry->fileNameLength, 1, to);
142        fprintf(to, "\"\n");
143        entry = entry->next;
144    }
145}
146
147zipentry_t
148iterate_zipfile(zipfile_t file, void** cookie)
149{
150    Zipentry* entry = (Zipentry*)*cookie;
151    if (entry == NULL) {
152        Zipfile* zip = (Zipfile*)file;
153        *cookie = zip->entries;
154        return *cookie;
155    } else {
156        entry = entry->next;
157        *cookie = entry;
158        return entry;
159    }
160}
161