1769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
2769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Copyright (C) 2006 The Android Open Source Project
3769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
4769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * you may not use this file except in compliance with the License.
6769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * You may obtain a copy of the License at
7769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
8769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
10769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Unless required by applicable law or agreed to in writing, software
11769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * See the License for the specific language governing permissions and
14769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * limitations under the License.
15769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
16769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
17769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski//
18769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski// Access to Zip archives.
19769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski//
20769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
21769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#define LOG_TAG "zip"
22769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
23769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#include <androidfw/ZipUtils.h>
24769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#include <utils/Log.h>
25769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
26769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#include "ZipFile.h"
27769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#include "Util.h"
28769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
29769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#include <zlib.h>
30769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#define DEF_MEM_LEVEL 8                // normally in zutil.h?
31769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
32769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#include <memory.h>
33769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#include <sys/stat.h>
34769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#include <errno.h>
35769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#include <assert.h>
36769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
37769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskinamespace aapt {
38769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
39769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskiusing namespace android;
40769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
41769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
42769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Some environments require the "b", some choke on it.
43769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
44769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#define FILE_OPEN_RO        "rb"
45769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#define FILE_OPEN_RW        "r+b"
46769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#define FILE_OPEN_RW_CREATE "w+b"
47769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
48769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/* should live somewhere else? */
49769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskistatic status_t errnoToStatus(int err)
50769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
51769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (err == ENOENT)
52769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return NAME_NOT_FOUND;
53769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    else if (err == EACCES)
54769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return PERMISSION_DENIED;
55769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    else
56769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return UNKNOWN_ERROR;
57769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
58769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
59769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
60769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Open a file and parse its guts.
61769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
62769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskistatus_t ZipFile::open(const char* zipFileName, int flags)
63769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
64769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    bool newArchive = false;
65769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
66769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    assert(mZipFp == NULL);     // no reopen
67769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
68769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if ((flags & kOpenTruncate))
69769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        flags |= kOpenCreate;           // trunc implies create
70769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
71769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite))
72769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return INVALID_OPERATION;       // not both
73769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite)))
74769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return INVALID_OPERATION;       // not neither
75769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if ((flags & kOpenCreate) && !(flags & kOpenReadWrite))
76769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return INVALID_OPERATION;       // create requires write
77769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
78769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (flags & kOpenTruncate) {
79769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        newArchive = true;
80769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    } else {
81769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        newArchive = (access(zipFileName, F_OK) != 0);
82769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (!(flags & kOpenCreate) && newArchive) {
83769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            /* not creating, must already exist */
84769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGD("File %s does not exist", zipFileName);
85769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            return NAME_NOT_FOUND;
86769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
87769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
88769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
89769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /* open the file */
90769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    const char* openflags;
91769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (flags & kOpenReadWrite) {
92769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (newArchive)
93769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            openflags = FILE_OPEN_RW_CREATE;
94769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        else
95769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            openflags = FILE_OPEN_RW;
96769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    } else {
97769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        openflags = FILE_OPEN_RO;
98769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
99769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mZipFp = fopen(zipFileName, openflags);
100769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (mZipFp == NULL) {
101769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        int err = errno;
102769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ALOGD("fopen failed: %d\n", err);
103769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return errnoToStatus(err);
104769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
105769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
106769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    status_t result;
107769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (!newArchive) {
108769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        /*
109769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski         * Load the central directory.  If that fails, then this probably
110769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski         * isn't a Zip archive.
111769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski         */
112769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = readCentralDir();
113769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    } else {
114769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        /*
115769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski         * Newly-created.  The EndOfCentralDir constructor actually
116769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski         * sets everything to be the way we want it (all zeroes).  We
117769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski         * set mNeedCDRewrite so that we create *something* if the
118769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski         * caller doesn't add any files.  (We could also just unlink
119769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski         * the file if it's brand new and nothing was added, but that's
120769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski         * probably doing more than we really should -- the user might
121769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski         * have a need for empty zip files.)
122769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski         */
123769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        mNeedCDRewrite = true;
124769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = NO_ERROR;
125769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
126769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
127769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (flags & kOpenReadOnly)
128769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        mReadOnly = true;
129769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    else
130769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        assert(!mReadOnly);
131769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
132769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return result;
133769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
134769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
135769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
136769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Return the Nth entry in the archive.
137769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
138769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam LesinskiZipEntry* ZipFile::getEntryByIndex(int idx) const
139769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
140769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (idx < 0 || idx >= (int) mEntries.size())
141769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return NULL;
142769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
143769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return mEntries[idx];
144769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
145769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
146769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
147769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Find an entry by name.
148769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
149769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam LesinskiZipEntry* ZipFile::getEntryByName(const char* fileName) const
150769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
151769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
152769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Do a stupid linear string-compare search.
153769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     *
154769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * There are various ways to speed this up, especially since it's rare
155769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * to intermingle changes to the archive with "get by name" calls.  We
156769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * don't want to sort the mEntries vector itself, however, because
157769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * it's used to recreate the Central Directory.
158769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     *
159769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * (Hash table works, parallel list of pointers in sorted order is good.)
160769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
161769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    int idx;
162769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
163769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    for (idx = mEntries.size()-1; idx >= 0; idx--) {
164769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ZipEntry* pEntry = mEntries[idx];
165769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (!pEntry->getDeleted() &&
166769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            strcmp(fileName, pEntry->getFileName()) == 0)
167769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        {
168769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            return pEntry;
169769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
170769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
171769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
172769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return NULL;
173769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
174769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
175769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
176769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Empty the mEntries vector.
177769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
178769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskivoid ZipFile::discardEntries(void)
179769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
180769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    int count = mEntries.size();
181769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
182769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    while (--count >= 0)
183769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        delete mEntries[count];
184769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
185769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEntries.clear();
186769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
187769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
188769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
189769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
190769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Find the central directory and read the contents.
191769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
192769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * The fun thing about ZIP archives is that they may or may not be
193769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * readable from start to end.  In some cases, notably for archives
194769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * that were written to stdout, the only length information is in the
195769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * central directory at the end of the file.
196769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
197769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Of course, the central directory can be followed by a variable-length
198769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * comment field, so we have to scan through it backwards.  The comment
199769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
200769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * itself, plus apparently sometimes people throw random junk on the end
201769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * just for the fun of it.
202769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
203769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * This is all a little wobbly.  If the wrong value ends up in the EOCD
204769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * area, we're hosed.  This appears to be the way that everbody handles
205769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * it though, so we're in pretty good company if this fails.
206769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
207769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskistatus_t ZipFile::readCentralDir(void)
208769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
209769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    status_t result = NO_ERROR;
210769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    unsigned char* buf = NULL;
211769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    off_t fileLength, seekStart;
212769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    long readAmount;
213769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    int i;
214769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
215769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    fseek(mZipFp, 0, SEEK_END);
216769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    fileLength = ftell(mZipFp);
217769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    rewind(mZipFp);
218769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
219769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /* too small to be a ZIP archive? */
220769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (fileLength < EndOfCentralDir::kEOCDLen) {
221769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ALOGD("Length is %ld -- too small\n", (long)fileLength);
222769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = INVALID_OPERATION;
223769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
224769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
225769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
226769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch];
227769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (buf == NULL) {
228769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ALOGD("Failure allocating %d bytes for EOCD search",
229769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski             EndOfCentralDir::kMaxEOCDSearch);
230769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = NO_MEMORY;
231769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
232769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
233769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
234769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (fileLength > EndOfCentralDir::kMaxEOCDSearch) {
235769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch;
236769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        readAmount = EndOfCentralDir::kMaxEOCDSearch;
237769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    } else {
238769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        seekStart = 0;
239769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        readAmount = (long) fileLength;
240769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
241769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (fseek(mZipFp, seekStart, SEEK_SET) != 0) {
242769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ALOGD("Failure seeking to end of zip at %ld", (long) seekStart);
243769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = UNKNOWN_ERROR;
244769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
245769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
246769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
247769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /* read the last part of the file into the buffer */
248769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) {
249769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ALOGD("short file? wanted %ld\n", readAmount);
250769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = UNKNOWN_ERROR;
251769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
252769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
253769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
254769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /* find the end-of-central-dir magic */
255769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    for (i = readAmount - 4; i >= 0; i--) {
256769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (buf[i] == 0x50 &&
257769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature)
258769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        {
259769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGV("+++ Found EOCD at buf+%d\n", i);
260769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            break;
261769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
262769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
263769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (i < 0) {
264769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ALOGD("EOCD not found, not Zip\n");
265769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = INVALID_OPERATION;
266769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
267769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
268769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
269769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /* extract eocd values */
270769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    result = mEOCD.readBuf(buf + i, readAmount - i);
271769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (result != NO_ERROR) {
272769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ALOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
273769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
274769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
275769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    //mEOCD.dump();
276769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
277769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 ||
278769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        mEOCD.mNumEntries != mEOCD.mTotalNumEntries)
279769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    {
280769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ALOGD("Archive spanning not supported\n");
281769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = INVALID_OPERATION;
282769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
283769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
284769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
285769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
286769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * So far so good.  "mCentralDirSize" is the size in bytes of the
287769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * central directory, so we can just seek back that far to find it.
288769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * We can also seek forward mCentralDirOffset bytes from the
289769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * start of the file.
290769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     *
291769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * We're not guaranteed to have the rest of the central dir in the
292769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * buffer, nor are we guaranteed that the central dir will have any
293769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * sort of convenient size.  We need to skip to the start of it and
294769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * read the header, then the other goodies.
295769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     *
296769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * The only thing we really need right now is the file comment, which
297769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * we're hoping to preserve.
298769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
299769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
300769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ALOGD("Failure seeking to central dir offset %ld\n",
301769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski             mEOCD.mCentralDirOffset);
302769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = UNKNOWN_ERROR;
303769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
304769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
305769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
306769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
307769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Loop through and read the central dir entries.
308769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
309769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    ALOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries);
310769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    int entry;
311769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) {
312769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ZipEntry* pEntry = new ZipEntry;
313769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
314769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = pEntry->initFromCDE(mZipFp);
315769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (result != NO_ERROR) {
316769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGD("initFromCDE failed\n");
317769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            delete pEntry;
318769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            goto bail;
319769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
320769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
321769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        mEntries.push_back(pEntry);
322769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
323769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
324769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
325769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
326769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * If all went well, we should now be back at the EOCD.
327769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
328769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    {
329769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        unsigned char checkBuf[4];
330769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (fread(checkBuf, 1, 4, mZipFp) != 4) {
331769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGD("EOCD check read failed\n");
332769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            result = INVALID_OPERATION;
333769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            goto bail;
334769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
335769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) {
336769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGD("EOCD read check failed\n");
337769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            result = UNKNOWN_ERROR;
338769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            goto bail;
339769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
340769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ALOGV("+++ EOCD read check passed\n");
341769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
342769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
343769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskibail:
344769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    delete[] buf;
345769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return result;
346769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
347769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
348769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskistatus_t ZipFile::add(const BigBuffer& buffer, const char* storageName, int compressionMethod,
349769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                      ZipEntry** ppEntry) {
350769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    std::unique_ptr<uint8_t[]> data = util::copy(buffer);
351769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return add(data.get(), buffer.size(), storageName, compressionMethod, ppEntry);
352769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
353769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
354769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
355769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
356769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Add a new file to the archive.
357769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
358769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * This requires creating and populating a ZipEntry structure, and copying
359769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * the data into the file at the appropriate position.  The "appropriate
360769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * position" is the current location of the central directory, which we
361769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * casually overwrite (we can put it back later).
362769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
363769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * If we were concerned about safety, we would want to make all changes
364769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * in a temp file and then overwrite the original after everything was
365769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * safely written.  Not really a concern for us.
366769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
367769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskistatus_t ZipFile::addCommon(const char* fileName, const void* data, size_t size,
368769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    const char* storageName, int sourceType, int compressionMethod,
369769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    ZipEntry** ppEntry)
370769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
371769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    ZipEntry* pEntry = NULL;
372769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    status_t result = NO_ERROR;
373769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    long lfhPosn, startPosn, endPosn, uncompressedLen;
374769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    FILE* inputFp = NULL;
375769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    unsigned long crc;
376769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    time_t modWhen;
377769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
378769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (mReadOnly)
379769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return INVALID_OPERATION;
380769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
381769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    assert(compressionMethod == ZipEntry::kCompressDeflated ||
382769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski           compressionMethod == ZipEntry::kCompressStored);
383769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
384769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /* make sure we're in a reasonable state */
385769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    assert(mZipFp != NULL);
386769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    assert(mEntries.size() == mEOCD.mTotalNumEntries);
387769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
388769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /* make sure it doesn't already exist */
389769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (getEntryByName(storageName) != NULL)
390769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return ALREADY_EXISTS;
391769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
392769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (!data) {
393769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        inputFp = fopen(fileName, FILE_OPEN_RO);
394769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (inputFp == NULL)
395769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            return errnoToStatus(errno);
396769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
397769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
398769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
399769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = UNKNOWN_ERROR;
400769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
401769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
402769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
403769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    pEntry = new ZipEntry;
404769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    pEntry->initNew(storageName, NULL);
405769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
406769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
407769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * From here on out, failures are more interesting.
408769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
409769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mNeedCDRewrite = true;
410769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
411769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
412769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Write the LFH, even though it's still mostly blank.  We need it
413769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * as a place-holder.  In theory the LFH isn't necessary, but in
414769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * practice some utilities demand it.
415769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
416769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    lfhPosn = ftell(mZipFp);
417769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    pEntry->mLFH.write(mZipFp);
418769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    startPosn = ftell(mZipFp);
419769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
420769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
421769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Copy the data in, possibly compressing it as we go.
422769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
423769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (sourceType == ZipEntry::kCompressStored) {
424769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (compressionMethod == ZipEntry::kCompressDeflated) {
425769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            bool failed = false;
426769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            result = compressFpToFp(mZipFp, inputFp, data, size, &crc);
427769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (result != NO_ERROR) {
428769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                ALOGD("compression failed, storing\n");
429769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                failed = true;
430769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            } else {
431769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                /*
432769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                 * Make sure it has compressed "enough".  This probably ought
433769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                 * to be set through an API call, but I don't expect our
434769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                 * criteria to change over time.
435769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                 */
436769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                long src = inputFp ? ftell(inputFp) : size;
437769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                long dst = ftell(mZipFp) - startPosn;
438769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                if (dst + (dst / 10) > src) {
439769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                    ALOGD("insufficient compression (src=%ld dst=%ld), storing\n",
440769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                        src, dst);
441769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                    failed = true;
442769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                }
443769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
444769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
445769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (failed) {
446769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                compressionMethod = ZipEntry::kCompressStored;
447769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                if (inputFp) rewind(inputFp);
448769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                fseek(mZipFp, startPosn, SEEK_SET);
449769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                /* fall through to kCompressStored case */
450769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
451769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
452769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        /* handle "no compression" request, or failed compression from above */
453769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (compressionMethod == ZipEntry::kCompressStored) {
454769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (inputFp) {
455769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                result = copyFpToFp(mZipFp, inputFp, &crc);
456769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            } else {
457769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                result = copyDataToFp(mZipFp, data, size, &crc);
458769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
459769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (result != NO_ERROR) {
460769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                // don't need to truncate; happens in CDE rewrite
461769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                ALOGD("failed copying data in\n");
462769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                goto bail;
463769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
464769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
465769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
466769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        // currently seeked to end of file
467769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        uncompressedLen = inputFp ? ftell(inputFp) : size;
468769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    } else if (sourceType == ZipEntry::kCompressDeflated) {
469769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        /* we should support uncompressed-from-compressed, but it's not
470769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski         * important right now */
471769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        assert(compressionMethod == ZipEntry::kCompressDeflated);
472769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
473769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        bool scanResult;
474769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        int method;
475769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        long compressedLen;
476769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
477769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen,
478769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                        &compressedLen, &crc);
479769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (!scanResult || method != ZipEntry::kCompressDeflated) {
480769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGD("this isn't a deflated gzip file?");
481769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            result = UNKNOWN_ERROR;
482769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            goto bail;
483769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
484769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
485769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL);
486769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (result != NO_ERROR) {
487769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGD("failed copying gzip data in\n");
488769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            goto bail;
489769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
490769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    } else {
491769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        assert(false);
492769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = UNKNOWN_ERROR;
493769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
494769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
495769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
496769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
497769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * We could write the "Data Descriptor", but there doesn't seem to
498769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * be any point since we're going to go back and write the LFH.
499769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     *
500769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Update file offsets.
501769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
502769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    endPosn = ftell(mZipFp);            // seeked to end of compressed data
503769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
504769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
505769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Success!  Fill out new values.
506769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
507769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc,
508769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        compressionMethod);
509769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp));
510769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    pEntry->setModWhen(modWhen);
511769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    pEntry->setLFHOffset(lfhPosn);
512769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEOCD.mNumEntries++;
513769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEOCD.mTotalNumEntries++;
514769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
515769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEOCD.mCentralDirOffset = endPosn;
516769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
517769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
518769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Go back and write the LFH.
519769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
520769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
521769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = UNKNOWN_ERROR;
522769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
523769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
524769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    pEntry->mLFH.write(mZipFp);
525769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
526769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
527769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Add pEntry to the list.
528769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
529769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEntries.push_back(pEntry);
530769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (ppEntry != NULL)
531769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        *ppEntry = pEntry;
532769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    pEntry = NULL;
533769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
534769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskibail:
535769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (inputFp != NULL)
536769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        fclose(inputFp);
537769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    delete pEntry;
538769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return result;
539769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
540769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
541769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
542769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Add an entry by copying it from another zip file.  If "padding" is
543769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * nonzero, the specified number of bytes will be added to the "extra"
544769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * field in the header.
545769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
546769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
547769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
548769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskistatus_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
549d5c4f8723c2b2c85b588fa07a5d4e7afb671d257Adam Lesinski                      const char* storageName, int padding, ZipEntry** ppEntry)
550769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
551769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    ZipEntry* pEntry = NULL;
552769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    status_t result;
553769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    long lfhPosn, endPosn;
554769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
555769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (mReadOnly)
556769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return INVALID_OPERATION;
557769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
558769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /* make sure we're in a reasonable state */
559769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    assert(mZipFp != NULL);
560769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    assert(mEntries.size() == mEOCD.mTotalNumEntries);
561769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
562769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
563769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = UNKNOWN_ERROR;
564769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
565769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
566769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
567769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    pEntry = new ZipEntry;
568769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (pEntry == NULL) {
569769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = NO_MEMORY;
570769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
571769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
572769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
573d5c4f8723c2b2c85b588fa07a5d4e7afb671d257Adam Lesinski    result = pEntry->initFromExternal(pSourceZip, pSourceEntry, storageName);
574d5c4f8723c2b2c85b588fa07a5d4e7afb671d257Adam Lesinski    if (result != NO_ERROR) {
575769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
576d5c4f8723c2b2c85b588fa07a5d4e7afb671d257Adam Lesinski    }
577769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (padding != 0) {
578769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = pEntry->addPadding(padding);
579769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (result != NO_ERROR)
580769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            goto bail;
581769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
582769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
583769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
584769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * From here on out, failures are more interesting.
585769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
586769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mNeedCDRewrite = true;
587769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
588769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
589769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Write the LFH.  Since we're not recompressing the data, we already
590769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * have all of the fields filled out.
591769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
592769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    lfhPosn = ftell(mZipFp);
593769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    pEntry->mLFH.write(mZipFp);
594769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
595769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
596769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Copy the data over.
597769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     *
598769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * If the "has data descriptor" flag is set, we want to copy the DD
599769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * fields as well.  This is a fixed-size area immediately following
600769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * the data.
601769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
602769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
603769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    {
604769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = UNKNOWN_ERROR;
605769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
606769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
607769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
608769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    off_t copyLen;
609769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    copyLen = pSourceEntry->getCompressedLen();
610769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
611769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        copyLen += ZipEntry::kDataDescriptorLen;
612769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
613769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
614769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        != NO_ERROR)
615769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    {
616769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ALOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
617769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = UNKNOWN_ERROR;
618769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
619769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
620769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
621769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
622769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Update file offsets.
623769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
624769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    endPosn = ftell(mZipFp);
625769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
626769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
627769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Success!  Fill out new values.
628769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
629769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    pEntry->setLFHOffset(lfhPosn);      // sets mCDE.mLocalHeaderRelOffset
630769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEOCD.mNumEntries++;
631769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEOCD.mTotalNumEntries++;
632769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
633769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEOCD.mCentralDirOffset = endPosn;
634769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
635769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
636769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Add pEntry to the list.
637769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
638769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEntries.push_back(pEntry);
639769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (ppEntry != NULL)
640769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        *ppEntry = pEntry;
641769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    pEntry = NULL;
642769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
643769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    result = NO_ERROR;
644769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
645769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskibail:
646769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    delete pEntry;
647769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return result;
648769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
649769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
650769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
651769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Copy all of the bytes in "src" to "dst".
652769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
653769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
654769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * will be seeked immediately past the data.
655769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
656769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskistatus_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32)
657769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
658769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    unsigned char tmpBuf[32768];
659769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    size_t count;
660769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
661769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    *pCRC32 = crc32(0L, Z_NULL, 0);
662769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
663769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    while (1) {
664769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp);
665769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (ferror(srcFp) || ferror(dstFp))
666769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            return errnoToStatus(errno);
667769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (count == 0)
668769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            break;
669769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
670769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        *pCRC32 = crc32(*pCRC32, tmpBuf, count);
671769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
672769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (fwrite(tmpBuf, 1, count, dstFp) != count) {
673769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGD("fwrite %d bytes failed\n", (int) count);
674769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            return UNKNOWN_ERROR;
675769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
676769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
677769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
678769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return NO_ERROR;
679769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
680769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
681769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
682769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Copy all of the bytes in "src" to "dst".
683769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
684769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * On exit, "dstFp" will be seeked immediately past the data.
685769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
686769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskistatus_t ZipFile::copyDataToFp(FILE* dstFp,
687769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    const void* data, size_t size, unsigned long* pCRC32)
688769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
689769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    *pCRC32 = crc32(0L, Z_NULL, 0);
690769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (size > 0) {
691769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size);
692769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (fwrite(data, 1, size, dstFp) != size) {
693769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGD("fwrite %d bytes failed\n", (int) size);
694769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            return UNKNOWN_ERROR;
695769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
696769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
697769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
698769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return NO_ERROR;
699769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
700769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
701769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
702769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Copy some of the bytes in "src" to "dst".
703769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
704769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * If "pCRC32" is NULL, the CRC will not be computed.
705769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
706769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
707769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * will be seeked immediately past the data just written.
708769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
709769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskistatus_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
710769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    unsigned long* pCRC32)
711769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
712769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    unsigned char tmpBuf[32768];
713769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    size_t count;
714769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
715769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (pCRC32 != NULL)
716769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        *pCRC32 = crc32(0L, Z_NULL, 0);
717769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
718769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    while (length) {
719769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        long readSize;
720769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
721769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        readSize = sizeof(tmpBuf);
722769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (readSize > length)
723769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            readSize = length;
724769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
725769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        count = fread(tmpBuf, 1, readSize, srcFp);
726769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if ((long) count != readSize) {     // error or unexpected EOF
727769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGD("fread %d bytes failed\n", (int) readSize);
728769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            return UNKNOWN_ERROR;
729769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
730769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
731769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (pCRC32 != NULL)
732769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            *pCRC32 = crc32(*pCRC32, tmpBuf, count);
733769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
734769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (fwrite(tmpBuf, 1, count, dstFp) != count) {
735769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGD("fwrite %d bytes failed\n", (int) count);
736769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            return UNKNOWN_ERROR;
737769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
738769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
739769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        length -= readSize;
740769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
741769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
742769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return NO_ERROR;
743769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
744769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
745769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
746769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Compress all of the data in "srcFp" and write it to "dstFp".
747769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
748769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
749769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * will be seeked immediately past the compressed data.
750769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
751769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskistatus_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp,
752769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    const void* data, size_t size, unsigned long* pCRC32)
753769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
754769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    status_t result = NO_ERROR;
755769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    const size_t kBufSize = 32768;
756769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    unsigned char* inBuf = NULL;
757769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    unsigned char* outBuf = NULL;
758769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    z_stream zstream;
759769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    bool atEof = false;     // no feof() aviailable yet
760769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    unsigned long crc;
761769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    int zerr;
762769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
763769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
764769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Create an input buffer and an output buffer.
765769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
766769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    inBuf = new unsigned char[kBufSize];
767769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    outBuf = new unsigned char[kBufSize];
768769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (inBuf == NULL || outBuf == NULL) {
769769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = NO_MEMORY;
770769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
771769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
772769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
773769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
774769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Initialize the zlib stream.
775769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
776769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    memset(&zstream, 0, sizeof(zstream));
777769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    zstream.zalloc = Z_NULL;
778769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    zstream.zfree = Z_NULL;
779769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    zstream.opaque = Z_NULL;
780769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    zstream.next_in = NULL;
781769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    zstream.avail_in = 0;
782769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    zstream.next_out = outBuf;
783769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    zstream.avail_out = kBufSize;
784769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    zstream.data_type = Z_UNKNOWN;
785769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
786769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION,
787769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
788769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (zerr != Z_OK) {
789769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        result = UNKNOWN_ERROR;
790769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (zerr == Z_VERSION_ERROR) {
791769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGE("Installed zlib is not compatible with linked version (%s)\n",
792769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                ZLIB_VERSION);
793769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        } else {
794769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr);
795769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
796769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
797769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
798769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
799769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    crc = crc32(0L, Z_NULL, 0);
800769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
801769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
802769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Loop while we have data.
803769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
804769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    do {
805769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        size_t getSize;
806769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        int flush;
807769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
808769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        /* only read if the input buffer is empty */
809769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (zstream.avail_in == 0 && !atEof) {
810769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGV("+++ reading %d bytes\n", (int)kBufSize);
811769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (data) {
812769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                getSize = size > kBufSize ? kBufSize : size;
813769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                memcpy(inBuf, data, getSize);
814769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                data = ((const char*)data) + getSize;
815769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                size -= getSize;
816769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            } else {
817769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                getSize = fread(inBuf, 1, kBufSize, srcFp);
818769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                if (ferror(srcFp)) {
819769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                    ALOGD("deflate read failed (errno=%d)\n", errno);
820769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                    goto z_bail;
821769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                }
822769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
823769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (getSize < kBufSize) {
824769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                ALOGV("+++  got %d bytes, EOF reached\n",
825769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                    (int)getSize);
826769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                atEof = true;
827769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
828769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
829769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            crc = crc32(crc, inBuf, getSize);
830769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
831769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            zstream.next_in = inBuf;
832769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            zstream.avail_in = getSize;
833769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
834769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
835769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (atEof)
836769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            flush = Z_FINISH;       /* tell zlib that we're done */
837769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        else
838769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            flush = Z_NO_FLUSH;     /* more to come! */
839769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
840769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        zerr = deflate(&zstream, flush);
841769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (zerr != Z_OK && zerr != Z_STREAM_END) {
842769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGD("zlib deflate call failed (zerr=%d)\n", zerr);
843769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            result = UNKNOWN_ERROR;
844769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            goto z_bail;
845769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
846769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
847769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        /* write when we're full or when we're done */
848769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (zstream.avail_out == 0 ||
849769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize))
850769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        {
851769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf));
852769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) !=
853769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                (size_t)(zstream.next_out - outBuf))
854769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            {
855769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                ALOGD("write %d failed in deflate\n",
856769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                    (int) (zstream.next_out - outBuf));
857769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                goto z_bail;
858769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
859769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
860769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            zstream.next_out = outBuf;
861769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            zstream.avail_out = kBufSize;
862769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
863769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    } while (zerr == Z_OK);
864769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
865769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
866769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
867769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    *pCRC32 = crc;
868769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
869769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskiz_bail:
870769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    deflateEnd(&zstream);        /* free up any allocated structures */
871769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
872769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskibail:
873769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    delete[] inBuf;
874769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    delete[] outBuf;
875769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
876769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return result;
877769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
878769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
879769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
880769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Mark an entry as deleted.
881769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
882769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * We will eventually need to crunch the file down, but if several files
883769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * are being removed (perhaps as part of an "update" process) we can make
884769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * things considerably faster by deferring the removal to "flush" time.
885769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
886769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskistatus_t ZipFile::remove(ZipEntry* pEntry)
887769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
888769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
889769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Should verify that pEntry is actually part of this archive, and
890769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * not some stray ZipEntry from a different file.
891769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
892769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
893769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /* mark entry as deleted, and mark archive as dirty */
894769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    pEntry->setDeleted();
895769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mNeedCDRewrite = true;
896769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return NO_ERROR;
897769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
898769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
899769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
900769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Flush any pending writes.
901769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
902769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * In particular, this will crunch out deleted entries, and write the
903769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Central Directory and EOCD if we have stomped on them.
904769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
905769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskistatus_t ZipFile::flush(void)
906769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
907769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    status_t result = NO_ERROR;
908769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    long eocdPosn;
909769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    int i, count;
910769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
911769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (mReadOnly)
912769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return INVALID_OPERATION;
913769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (!mNeedCDRewrite)
914769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return NO_ERROR;
915769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
916769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    assert(mZipFp != NULL);
917769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
918769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    result = crunchArchive();
919769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (result != NO_ERROR)
920769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return result;
921769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
922769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0)
923769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return UNKNOWN_ERROR;
924769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
925769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    count = mEntries.size();
926769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    for (i = 0; i < count; i++) {
927769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ZipEntry* pEntry = mEntries[i];
928769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        pEntry->mCDE.write(mZipFp);
929769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
930769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
931769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    eocdPosn = ftell(mZipFp);
932769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset;
933769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
934769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEOCD.write(mZipFp);
935769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
936769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
937769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * If we had some stuff bloat up during compression and get replaced
938769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * with plain files, or if we deleted some entries, there's a lot
939769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * of wasted space at the end of the file.  Remove it now.
940769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
941769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) {
942769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ALOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno));
943769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        // not fatal
944769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
945769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
946769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /* should we clear the "newly added" flag in all entries now? */
947769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
948769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mNeedCDRewrite = false;
949769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return NO_ERROR;
950769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
951769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
952769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
953769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Crunch deleted files out of an archive by shifting the later files down.
954769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
955769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Because we're not using a temp file, we do the operation inside the
956769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * current file.
957769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
958769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskistatus_t ZipFile::crunchArchive(void)
959769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
960769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    status_t result = NO_ERROR;
961769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    int i, count;
962769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    long delCount, adjust;
963769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
964769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#if 0
965769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    printf("CONTENTS:\n");
966769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    for (i = 0; i < (int) mEntries.size(); i++) {
967769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        printf(" %d: lfhOff=%ld del=%d\n",
968769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted());
969769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
970769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    printf("  END is %ld\n", (long) mEOCD.mCentralDirOffset);
971769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#endif
972769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
973769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
974769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Roll through the set of files, shifting them as appropriate.  We
975769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * could probably get a slight performance improvement by sliding
976769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * multiple files down at once (because we could use larger reads
977769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * when operating on batches of small files), but it's not that useful.
978769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
979769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    count = mEntries.size();
980769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    delCount = adjust = 0;
981769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    for (i = 0; i < count; i++) {
982769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ZipEntry* pEntry = mEntries[i];
983769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        long span;
984769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
985769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (pEntry->getLFHOffset() != 0) {
986769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            long nextOffset;
987769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
988769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            /* Get the length of this entry by finding the offset
989769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski             * of the next entry.  Directory entries don't have
990769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski             * file offsets, so we need to find the next non-directory
991769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski             * entry.
992769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski             */
993769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            nextOffset = 0;
994769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            for (int ii = i+1; nextOffset == 0 && ii < count; ii++)
995769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                nextOffset = mEntries[ii]->getLFHOffset();
996769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (nextOffset == 0)
997769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                nextOffset = mEOCD.mCentralDirOffset;
998769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            span = nextOffset - pEntry->getLFHOffset();
999769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1000769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            assert(span >= ZipEntry::LocalFileHeader::kLFHLen);
1001769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        } else {
1002769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            /* This is a directory entry.  It doesn't have
1003769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski             * any actual file contents, so there's no need to
1004769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski             * move anything.
1005769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski             */
1006769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            span = 0;
1007769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
1008769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1009769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n",
1010769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        //    i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count);
1011769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1012769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (pEntry->getDeleted()) {
1013769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            adjust += span;
1014769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            delCount++;
1015769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1016769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            delete pEntry;
1017769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            mEntries.erase(mEntries.begin() + i);
1018769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1019769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            /* adjust loop control */
1020769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            count--;
1021769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            i--;
1022769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        } else if (span != 0 && adjust > 0) {
1023769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            /* shuffle this entry back */
1024769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            //printf("+++ Shuffling '%s' back %ld\n",
1025769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            //    pEntry->getFileName(), adjust);
1026769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            result = filemove(mZipFp, pEntry->getLFHOffset() - adjust,
1027769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                        pEntry->getLFHOffset(), span);
1028769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (result != NO_ERROR) {
1029769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                /* this is why you use a temp file */
1030769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                ALOGE("error during crunch - archive is toast\n");
1031769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                return result;
1032769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
1033769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1034769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust);
1035769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
1036769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
1037769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1038769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /*
1039769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * Fix EOCD info.  We have to wait until the end to do some of this
1040769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * because we use mCentralDirOffset to determine "span" for the
1041769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     * last entry.
1042769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski     */
1043769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEOCD.mCentralDirOffset -= adjust;
1044769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEOCD.mNumEntries -= delCount;
1045769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEOCD.mTotalNumEntries -= delCount;
1046769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mEOCD.mCentralDirSize = 0;  // mark invalid; set by flush()
1047769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1048769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries);
1049769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    assert(mEOCD.mNumEntries == count);
1050769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1051769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return result;
1052769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
1053769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1054769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
1055769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Works like memmove(), but on pieces of a file.
1056769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
1057769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskistatus_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n)
1058769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
1059769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (dst == src || n <= 0)
1060769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return NO_ERROR;
1061769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1062769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    unsigned char readBuf[32768];
1063769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1064769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (dst < src) {
1065769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        /* shift stuff toward start of file; must read from start */
1066769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        while (n != 0) {
1067769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            size_t getSize = sizeof(readBuf);
1068769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (getSize > n)
1069769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                getSize = n;
1070769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1071769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (fseek(fp, (long) src, SEEK_SET) != 0) {
1072769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                ALOGD("filemove src seek %ld failed\n", (long) src);
1073769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                return UNKNOWN_ERROR;
1074769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
1075769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1076769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (fread(readBuf, 1, getSize, fp) != getSize) {
1077769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                ALOGD("filemove read %ld off=%ld failed\n",
1078769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                    (long) getSize, (long) src);
1079769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                return UNKNOWN_ERROR;
1080769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
1081769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1082769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (fseek(fp, (long) dst, SEEK_SET) != 0) {
1083769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                ALOGD("filemove dst seek %ld failed\n", (long) dst);
1084769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                return UNKNOWN_ERROR;
1085769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
1086769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1087769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (fwrite(readBuf, 1, getSize, fp) != getSize) {
1088769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                ALOGD("filemove write %ld off=%ld failed\n",
1089769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                    (long) getSize, (long) dst);
1090769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                return UNKNOWN_ERROR;
1091769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
1092769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1093769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            src += getSize;
1094769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            dst += getSize;
1095769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            n -= getSize;
1096769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
1097769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    } else {
1098769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        /* shift stuff toward end of file; must read from end */
1099769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        assert(false);      // write this someday, maybe
1100769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return UNKNOWN_ERROR;
1101769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
1102769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1103769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return NO_ERROR;
1104769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
1105769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1106769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1107769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
1108769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Get the modification time from a file descriptor.
1109769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
1110769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskitime_t ZipFile::getModTime(int fd)
1111769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
1112769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    struct stat sb;
1113769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1114769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (fstat(fd, &sb) < 0) {
1115769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ALOGD("HEY: fstat on fd %d failed\n", fd);
1116769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return (time_t) -1;
1117769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
1118769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1119769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return sb.st_mtime;
1120769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
1121769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1122769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1123769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#if 0       /* this is a bad idea */
1124769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
1125769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Get a copy of the Zip file descriptor.
1126769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
1127769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * We don't allow this if the file was opened read-write because we tend
1128769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * to leave the file contents in an uncertain state between calls to
1129769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * flush().  The duplicated file descriptor should only be valid for reads.
1130769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
1131769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskiint ZipFile::getZipFd(void) const
1132769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
1133769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (!mReadOnly)
1134769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return INVALID_OPERATION;
1135769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    assert(mZipFp != NULL);
1136769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1137769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    int fd;
1138769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    fd = dup(fileno(mZipFp));
1139769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (fd < 0) {
1140769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ALOGD("didn't work, errno=%d\n", errno);
1141769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
1142769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1143769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return fd;
1144769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
1145769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#endif
1146769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1147769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1148769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#if 0
1149769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
1150769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Expand data.
1151769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
1152769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskibool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const
1153769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
1154769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return false;
1155769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
1156769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#endif
1157769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1158769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski// free the memory when you're done
1159769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskivoid* ZipFile::uncompress(const ZipEntry* entry)
1160769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
1161769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    size_t unlen = entry->getUncompressedLen();
1162769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    size_t clen = entry->getCompressedLen();
1163769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1164769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    void* buf = malloc(unlen);
1165769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (buf == NULL) {
1166769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return NULL;
1167769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
1168769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1169769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    fseek(mZipFp, 0, SEEK_SET);
1170769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1171769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    off_t offset = entry->getFileOffset();
1172769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (fseek(mZipFp, offset, SEEK_SET) != 0) {
1173769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        goto bail;
1174769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
1175769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1176769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    switch (entry->getCompressionMethod())
1177769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    {
1178769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        case ZipEntry::kCompressStored: {
1179769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ssize_t amt = fread(buf, 1, unlen, mZipFp);
1180769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (amt != (ssize_t)unlen) {
1181769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                goto bail;
1182769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
1183769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#if 0
1184769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            printf("data...\n");
1185769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            const unsigned char* p = (unsigned char*)buf;
1186769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            const unsigned char* end = p+unlen;
1187769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            for (int i=0; i<32 && p < end; i++) {
1188769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                printf("0x%08x ", (int)(offset+(i*0x10)));
1189769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                for (int j=0; j<0x10 && p < end; j++) {
1190769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                    printf(" %02x", *p);
1191769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                    p++;
1192769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                }
1193769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                printf("\n");
1194769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
1195769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#endif
1196769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1197769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
1198769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            break;
1199769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        case ZipEntry::kCompressDeflated: {
1200769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) {
1201769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                goto bail;
1202769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
1203769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            }
1204769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            break;
1205769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        default:
1206769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            goto bail;
1207769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
1208769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return buf;
1209769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1210769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskibail:
1211769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    free(buf);
1212769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return NULL;
1213769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
1214769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1215769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1216769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
1217769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * ===========================================================================
1218769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *      ZipFile::EndOfCentralDir
1219769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * ===========================================================================
1220769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
1221769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1222769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
1223769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Read the end-of-central-dir fields.
1224769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski *
1225769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * "buf" should be positioned at the EOCD signature, and should contain
1226769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * the entire EOCD area including the comment.
1227769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
1228769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskistatus_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len)
1229769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
1230769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /* don't allow re-use */
1231769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    assert(mComment == NULL);
1232769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1233769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (len < kEOCDLen) {
1234769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        /* looks like ZIP file got truncated */
1235769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        ALOGD(" Zip EOCD: expected >= %d bytes, found %d\n",
1236769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            kEOCDLen, len);
1237769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return INVALID_OPERATION;
1238769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
1239769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1240769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    /* this should probably be an assert() */
1241769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (ZipEntry::getLongLE(&buf[0x00]) != kSignature)
1242769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return UNKNOWN_ERROR;
1243769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1244769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mDiskNumber = ZipEntry::getShortLE(&buf[0x04]);
1245769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]);
1246769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mNumEntries = ZipEntry::getShortLE(&buf[0x08]);
1247769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]);
1248769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]);
1249769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]);
1250769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    mCommentLen = ZipEntry::getShortLE(&buf[0x14]);
1251769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1252769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    // TODO: validate mCentralDirOffset
1253769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1254769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (mCommentLen > 0) {
1255769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (kEOCDLen + mCommentLen > len) {
1256769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            ALOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n",
1257769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski                kEOCDLen, mCommentLen, len);
1258769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            return UNKNOWN_ERROR;
1259769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        }
1260769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        mComment = new unsigned char[mCommentLen];
1261769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        memcpy(mComment, buf + kEOCDLen, mCommentLen);
1262769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
1263769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1264769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return NO_ERROR;
1265769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
1266769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1267769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
1268769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Write an end-of-central-directory section.
1269769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
1270769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskistatus_t ZipFile::EndOfCentralDir::write(FILE* fp)
1271769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
1272769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    unsigned char buf[kEOCDLen];
1273769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1274769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    ZipEntry::putLongLE(&buf[0x00], kSignature);
1275769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    ZipEntry::putShortLE(&buf[0x04], mDiskNumber);
1276769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir);
1277769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    ZipEntry::putShortLE(&buf[0x08], mNumEntries);
1278769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries);
1279769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize);
1280769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset);
1281769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    ZipEntry::putShortLE(&buf[0x14], mCommentLen);
1282769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1283769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen)
1284769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        return UNKNOWN_ERROR;
1285769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    if (mCommentLen > 0) {
1286769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        assert(mComment != NULL);
1287769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen)
1288769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski            return UNKNOWN_ERROR;
1289769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    }
1290769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1291769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    return NO_ERROR;
1292769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
1293769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1294769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski/*
1295769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski * Dump the contents of an EndOfCentralDir object.
1296769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski */
1297769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinskivoid ZipFile::EndOfCentralDir::dump(void) const
1298769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski{
1299769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    ALOGD(" EndOfCentralDir contents:\n");
1300769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    ALOGD("  diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n",
1301769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries);
1302769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski    ALOGD("  centDirSize=%lu centDirOff=%lu commentLen=%u\n",
1303769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski        mCentralDirSize, mCentralDirOffset, mCommentLen);
1304769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
1305769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
1306769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski} // namespace aapt
1307