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