1dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include "private.h"
2dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdio.h>
3dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <string.h>
4dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdlib.h>
5dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
6dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectenum {
7dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // finding the directory
8dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    CD_SIGNATURE = 0x06054b50,
9dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    EOCD_LEN     = 22,        // EndOfCentralDir len, excl. comment
10dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    MAX_COMMENT_LEN = 65535,
11dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    MAX_EOCD_SEARCH = MAX_COMMENT_LEN + EOCD_LEN,
12dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
13dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // central directory entries
14dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ENTRY_SIGNATURE = 0x02014b50,
15dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ENTRY_LEN = 46,          // CentralDirEnt len, excl. var fields
16287c71ca84533da008e9cc240224910a9d05139eDoug Zongker
17dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // local file header
18dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    LFH_SIZE = 30,
19dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project};
20dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
21dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectunsigned int
22dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectread_le_int(const unsigned char* buf)
23dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
24dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
25dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
26dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
27dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectunsigned int
28dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectread_le_short(const unsigned char* buf)
29dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
30dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return buf[0] | (buf[1] << 8);
31dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
32dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
33dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int
34dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectread_central_dir_values(Zipfile* file, const unsigned char* buf, int len)
35dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
36dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (len < EOCD_LEN) {
37dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // looks like ZIP file got truncated
38dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        fprintf(stderr, " Zip EOCD: expected >= %d bytes, found %d\n",
39dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                EOCD_LEN, len);
40dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
41dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
42dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
43dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    file->disknum = read_le_short(&buf[0x04]);
44dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    file->diskWithCentralDir = read_le_short(&buf[0x06]);
45dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    file->entryCount = read_le_short(&buf[0x08]);
46dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    file->totalEntryCount = read_le_short(&buf[0x0a]);
47dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    file->centralDirSize = read_le_int(&buf[0x0c]);
48dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    file->centralDirOffest = read_le_int(&buf[0x10]);
49dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    file->commentLen = read_le_short(&buf[0x14]);
50dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
51dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (file->commentLen > 0) {
52dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (EOCD_LEN + file->commentLen > len) {
53dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            fprintf(stderr, "EOCD(%d) + comment(%d) exceeds len (%d)\n",
54dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    EOCD_LEN, file->commentLen, len);
55dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            return -1;
56dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
57dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        file->comment = buf + EOCD_LEN;
58dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
59dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
60dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
61dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
62dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
63dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int
64dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectread_central_directory_entry(Zipfile* file, Zipentry* entry,
65dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                const unsigned char** buf, ssize_t* len)
66dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
67dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    const unsigned char* p;
68dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
69dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned short  versionMadeBy;
70dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned short  versionToExtract;
71dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned short  gpBitFlag;
72dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned short  compressionMethod;
73dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned short  lastModFileTime;
74dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned short  lastModFileDate;
75dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned long   crc32;
76dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned short  extraFieldLength;
77dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned short  fileCommentLength;
78dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned short  diskNumberStart;
79dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned short  internalAttrs;
80dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned long   externalAttrs;
81dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned long   localHeaderRelOffset;
82dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    const unsigned char*  extraField;
83dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    const unsigned char*  fileComment;
84dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned int dataOffset;
85dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned short lfhExtraFieldSize;
86287c71ca84533da008e9cc240224910a9d05139eDoug Zongker
87dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
88dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    p = *buf;
89dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
90dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (*len < ENTRY_LEN) {
91dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        fprintf(stderr, "cde entry not large enough\n");
92dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
93dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
94dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
95dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (read_le_int(&p[0x00]) != ENTRY_SIGNATURE) {
96dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        fprintf(stderr, "Whoops: didn't find expected signature\n");
97dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
98dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
99dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
100dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    versionMadeBy = read_le_short(&p[0x04]);
101dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    versionToExtract = read_le_short(&p[0x06]);
102dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    gpBitFlag = read_le_short(&p[0x08]);
103dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    entry->compressionMethod = read_le_short(&p[0x0a]);
104dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    lastModFileTime = read_le_short(&p[0x0c]);
105dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    lastModFileDate = read_le_short(&p[0x0e]);
106dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    crc32 = read_le_int(&p[0x10]);
107287c71ca84533da008e9cc240224910a9d05139eDoug Zongker    entry->compressedSize = read_le_int(&p[0x14]);
108dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    entry->uncompressedSize = read_le_int(&p[0x18]);
109dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    entry->fileNameLength = read_le_short(&p[0x1c]);
110dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    extraFieldLength = read_le_short(&p[0x1e]);
111dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    fileCommentLength = read_le_short(&p[0x20]);
112dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    diskNumberStart = read_le_short(&p[0x22]);
113dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    internalAttrs = read_le_short(&p[0x24]);
114dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    externalAttrs = read_le_int(&p[0x26]);
115dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    localHeaderRelOffset = read_le_int(&p[0x2a]);
116dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
117dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    p += ENTRY_LEN;
118dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
119dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // filename
120dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (entry->fileNameLength != 0) {
121dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        entry->fileName = p;
122dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
123dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        entry->fileName = NULL;
124dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
125dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    p += entry->fileNameLength;
126dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
127dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // extra field
128dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (extraFieldLength != 0) {
129dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        extraField = p;
130dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
131dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        extraField = NULL;
132dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
133dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    p += extraFieldLength;
134dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
135dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // comment, if any
136dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (fileCommentLength != 0) {
137dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        fileComment = p;
138dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
139dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        fileComment = NULL;
140dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
141dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    p += fileCommentLength;
142287c71ca84533da008e9cc240224910a9d05139eDoug Zongker
143dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    *buf = p;
144dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
145dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // the size of the extraField in the central dir is how much data there is,
146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // but the one in the local file header also contains some padding.
147dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    p = file->buf + localHeaderRelOffset;
148dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    extraFieldLength = read_le_short(&p[0x1c]);
149287c71ca84533da008e9cc240224910a9d05139eDoug Zongker
150dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dataOffset = localHeaderRelOffset + LFH_SIZE
151dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        + entry->fileNameLength + extraFieldLength;
152dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    entry->data = file->buf + dataOffset;
153dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if 0
154dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    printf("file->buf=%p entry->data=%p dataOffset=%x localHeaderRelOffset=%d "
155dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project           "entry->fileNameLength=%d extraFieldLength=%d\n",
156dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project           file->buf, entry->data, dataOffset, localHeaderRelOffset,
157dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project           entry->fileNameLength, extraFieldLength);
158dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
159dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
160dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
161dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
162dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/*
163dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Find the central directory and read the contents.
164dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
165dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * The fun thing about ZIP archives is that they may or may not be
166dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * readable from start to end.  In some cases, notably for archives
167dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * that were written to stdout, the only length information is in the
168dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * central directory at the end of the file.
169dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
170dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Of course, the central directory can be followed by a variable-length
171dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * comment field, so we have to scan through it backwards.  The comment
172dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
173dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * itself, plus apparently sometimes people throw random junk on the end
174dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * just for the fun of it.
175dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
176dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * This is all a little wobbly.  If the wrong value ends up in the EOCD
177dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * area, we're hosed.  This appears to be the way that everbody handles
178dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * it though, so we're in pretty good company if this fails.
179dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
180dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint
181dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectread_central_dir(Zipfile *file)
182dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
183dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int err;
184dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
185dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    const unsigned char* buf = file->buf;
186dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ssize_t bufsize = file->bufsize;
187dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    const unsigned char* eocd;
188dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    const unsigned char* p;
189dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    const unsigned char* start;
190dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ssize_t len;
191dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int i;
192dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
193dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // too small to be a ZIP archive?
194dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (bufsize < EOCD_LEN) {
195dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        fprintf(stderr, "Length is %d -- too small\n", bufsize);
196dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        goto bail;
197dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
198dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
199dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // find the end-of-central-dir magic
200dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (bufsize > MAX_EOCD_SEARCH) {
201dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        start = buf + bufsize - MAX_EOCD_SEARCH;
202dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
203dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        start = buf;
204dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
205dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    p = buf + bufsize - 4;
206dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while (p >= start) {
207dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (*p == 0x50 && read_le_int(p) == CD_SIGNATURE) {
208dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            eocd = p;
209dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
210dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
211dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        p--;
212dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
213dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (p < start) {
214dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        fprintf(stderr, "EOCD not found, not Zip\n");
215dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        goto bail;
216dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
217dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
218dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // extract eocd values
219dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    err = read_central_dir_values(file, eocd, (buf+bufsize)-eocd);
220dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (err != 0) {
221dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        goto bail;
222dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
223dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
224dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (file->disknum != 0
225dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project          || file->diskWithCentralDir != 0
226dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project          || file->entryCount != file->totalEntryCount) {
227dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        fprintf(stderr, "Archive spanning not supported\n");
228dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        goto bail;
229dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
230dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
231dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Loop through and read the central dir entries.
232dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    p = buf + file->centralDirOffest;
233dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    len = (buf+bufsize)-p;
234dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for (i=0; i < file->totalEntryCount; i++) {
235dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        Zipentry* entry = malloc(sizeof(Zipentry));
23690764cfc76d65ae67755a375eb8ef429e44b9822Elliott Hughes        memset(entry, 0, sizeof(Zipentry));
237dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
238dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        err = read_central_directory_entry(file, entry, &p, &len);
239dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (err != 0) {
240dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            fprintf(stderr, "read_central_directory_entry failed\n");
241dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            free(entry);
242dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            goto bail;
243dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
244287c71ca84533da008e9cc240224910a9d05139eDoug Zongker
245dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // add it to our list
246dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        entry->next = file->entries;
247dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        file->entries = entry;
248dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
249dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
250dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
251dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectbail:
252dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return -1;
253dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
254