ZipFile.cpp revision 1f5762e646bed2290934280464832782766ee68e
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Access to Zip archives.
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "zip"
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
231f5762e646bed2290934280464832782766ee68eMathias Agopian#include <androidfw/ZipUtils.h>
248ae2335a3c93d0c00e998fdec18f64dfe43b94cbMathias Agopian#include <utils/Log.h>
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2655e3d60da5626752ffe1d15150d35ccb8fa644e7Mathias Agopian#include "ZipFile.h"
2755e3d60da5626752ffe1d15150d35ccb8fa644e7Mathias Agopian
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <zlib.h>
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define DEF_MEM_LEVEL 8                // normally in zutil.h?
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <memory.h>
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/stat.h>
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <errno.h>
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <assert.h>
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectusing namespace android;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Some environments require the "b", some choke on it.
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define FILE_OPEN_RO        "rb"
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define FILE_OPEN_RW        "r+b"
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define FILE_OPEN_RW_CREATE "w+b"
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* should live somewhere else? */
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic status_t errnoToStatus(int err)
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (err == ENOENT)
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NAME_NOT_FOUND;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    else if (err == EACCES)
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return PERMISSION_DENIED;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    else
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return UNKNOWN_ERROR;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Open a file and parse its guts.
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t ZipFile::open(const char* zipFileName, int flags)
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    bool newArchive = false;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    assert(mZipFp == NULL);     // no reopen
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if ((flags & kOpenTruncate))
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        flags |= kOpenCreate;           // trunc implies create
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite))
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return INVALID_OPERATION;       // not both
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite)))
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return INVALID_OPERATION;       // not neither
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if ((flags & kOpenCreate) && !(flags & kOpenReadWrite))
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return INVALID_OPERATION;       // create requires write
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (flags & kOpenTruncate) {
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        newArchive = true;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        newArchive = (access(zipFileName, F_OK) != 0);
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!(flags & kOpenCreate) && newArchive) {
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /* not creating, must already exist */
815baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("File %s does not exist", zipFileName);
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return NAME_NOT_FOUND;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* open the file */
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char* openflags;
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (flags & kOpenReadWrite) {
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (newArchive)
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            openflags = FILE_OPEN_RW_CREATE;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        else
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            openflags = FILE_OPEN_RW;
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        openflags = FILE_OPEN_RO;
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mZipFp = fopen(zipFileName, openflags);
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mZipFp == NULL) {
98e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        int err = errno;
995baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("fopen failed: %d\n", err);
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return errnoToStatus(err);
101e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    }
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    status_t result;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!newArchive) {
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Load the central directory.  If that fails, then this probably
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * isn't a Zip archive.
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = readCentralDir();
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Newly-created.  The EndOfCentralDir constructor actually
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * sets everything to be the way we want it (all zeroes).  We
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * set mNeedCDRewrite so that we create *something* if the
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * caller doesn't add any files.  (We could also just unlink
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * the file if it's brand new and nothing was added, but that's
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * probably doing more than we really should -- the user might
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * have a need for empty zip files.)
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mNeedCDRewrite = true;
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = NO_ERROR;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (flags & kOpenReadOnly)
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mReadOnly = true;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    else
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        assert(!mReadOnly);
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return result;
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the Nth entry in the archive.
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectZipEntry* ZipFile::getEntryByIndex(int idx) const
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (idx < 0 || idx >= (int) mEntries.size())
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return mEntries[idx];
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Find an entry by name.
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectZipEntry* ZipFile::getEntryByName(const char* fileName) const
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Do a stupid linear string-compare search.
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * There are various ways to speed this up, especially since it's rare
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to intermingle changes to the archive with "get by name" calls.  We
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * don't want to sort the mEntries vector itself, however, because
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * it's used to recreate the Central Directory.
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (Hash table works, parallel list of pointers in sorted order is good.)
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int idx;
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (idx = mEntries.size()-1; idx >= 0; idx--) {
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ZipEntry* pEntry = mEntries[idx];
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!pEntry->getDeleted() &&
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            strcmp(fileName, pEntry->getFileName()) == 0)
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return pEntry;
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NULL;
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Empty the mEntries vector.
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid ZipFile::discardEntries(void)
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int count = mEntries.size();
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while (--count >= 0)
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        delete mEntries[count];
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEntries.clear();
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Find the central directory and read the contents.
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The fun thing about ZIP archives is that they may or may not be
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * readable from start to end.  In some cases, notably for archives
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * that were written to stdout, the only length information is in the
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * central directory at the end of the file.
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Of course, the central directory can be followed by a variable-length
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * comment field, so we have to scan through it backwards.  The comment
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * itself, plus apparently sometimes people throw random junk on the end
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * just for the fun of it.
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is all a little wobbly.  If the wrong value ends up in the EOCD
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * area, we're hosed.  This appears to be the way that everbody handles
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * it though, so we're in pretty good company if this fails.
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t ZipFile::readCentralDir(void)
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    status_t result = NO_ERROR;
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned char* buf = NULL;
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    off_t fileLength, seekStart;
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    long readAmount;
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int i;
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    fseek(mZipFp, 0, SEEK_END);
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    fileLength = ftell(mZipFp);
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    rewind(mZipFp);
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* too small to be a ZIP archive? */
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fileLength < EndOfCentralDir::kEOCDLen) {
2185baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Length is %ld -- too small\n", (long)fileLength);
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = INVALID_OPERATION;
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch];
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (buf == NULL) {
2255baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Failure allocating %d bytes for EOCD search",
226e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen             EndOfCentralDir::kMaxEOCDSearch);
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = NO_MEMORY;
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fileLength > EndOfCentralDir::kMaxEOCDSearch) {
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch;
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        readAmount = EndOfCentralDir::kMaxEOCDSearch;
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        seekStart = 0;
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        readAmount = (long) fileLength;
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fseek(mZipFp, seekStart, SEEK_SET) != 0) {
2395baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Failure seeking to end of zip at %ld", (long) seekStart);
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = UNKNOWN_ERROR;
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* read the last part of the file into the buffer */
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) {
2465baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("short file? wanted %ld\n", readAmount);
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = UNKNOWN_ERROR;
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* find the end-of-central-dir magic */
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (i = readAmount - 4; i >= 0; i--) {
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (buf[i] == 0x50 &&
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature)
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {
25671f2cf116aab893e224056c38ab146bd1538dd3eSteve Block            ALOGV("+++ Found EOCD at buf+%d\n", i);
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (i < 0) {
2615baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("EOCD not found, not Zip\n");
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = INVALID_OPERATION;
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* extract eocd values */
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    result = mEOCD.readBuf(buf + i, readAmount - i);
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (result != NO_ERROR) {
2695baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
271e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    }
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    //mEOCD.dump();
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 ||
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEOCD.mNumEntries != mEOCD.mTotalNumEntries)
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {
2775baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Archive spanning not supported\n");
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = INVALID_OPERATION;
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * So far so good.  "mCentralDirSize" is the size in bytes of the
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * central directory, so we can just seek back that far to find it.
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * We can also seek forward mCentralDirOffset bytes from the
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * start of the file.
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * We're not guaranteed to have the rest of the central dir in the
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * buffer, nor are we guaranteed that the central dir will have any
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * sort of convenient size.  We need to skip to the start of it and
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * read the header, then the other goodies.
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The only thing we really need right now is the file comment, which
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * we're hoping to preserve.
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
2975baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("Failure seeking to central dir offset %ld\n",
298e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen             mEOCD.mCentralDirOffset);
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = UNKNOWN_ERROR;
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Loop through and read the central dir entries.
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
30671f2cf116aab893e224056c38ab146bd1538dd3eSteve Block    ALOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries);
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int entry;
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) {
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ZipEntry* pEntry = new ZipEntry;
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = pEntry->initFromCDE(mZipFp);
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (result != NO_ERROR) {
3135baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("initFromCDE failed\n");
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            delete pEntry;
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            goto bail;
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEntries.add(pEntry);
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If all went well, we should now be back at the EOCD.
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        unsigned char checkBuf[4];
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fread(checkBuf, 1, 4, mZipFp) != 4) {
3285baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("EOCD check read failed\n");
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            result = INVALID_OPERATION;
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            goto bail;
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) {
3335baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("EOCD read check failed\n");
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            result = UNKNOWN_ERROR;
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            goto bail;
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33771f2cf116aab893e224056c38ab146bd1538dd3eSteve Block        ALOGV("+++ EOCD read check passed\n");
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectbail:
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    delete[] buf;
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return result;
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Add a new file to the archive.
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This requires creating and populating a ZipEntry structure, and copying
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the data into the file at the appropriate position.  The "appropriate
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * position" is the current location of the central directory, which we
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * casually overwrite (we can put it back later).
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If we were concerned about safety, we would want to make all changes
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in a temp file and then overwrite the original after everything was
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * safely written.  Not really a concern for us.
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t ZipFile::addCommon(const char* fileName, const void* data, size_t size,
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const char* storageName, int sourceType, int compressionMethod,
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ZipEntry** ppEntry)
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ZipEntry* pEntry = NULL;
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    status_t result = NO_ERROR;
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    long lfhPosn, startPosn, endPosn, uncompressedLen;
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    FILE* inputFp = NULL;
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned long crc;
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    time_t modWhen;
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mReadOnly)
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return INVALID_OPERATION;
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    assert(compressionMethod == ZipEntry::kCompressDeflated ||
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           compressionMethod == ZipEntry::kCompressStored);
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* make sure we're in a reasonable state */
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    assert(mZipFp != NULL);
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    assert(mEntries.size() == mEOCD.mTotalNumEntries);
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* make sure it doesn't already exist */
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (getEntryByName(storageName) != NULL)
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ALREADY_EXISTS;
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!data) {
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        inputFp = fopen(fileName, FILE_OPEN_RO);
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (inputFp == NULL)
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return errnoToStatus(errno);
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = UNKNOWN_ERROR;
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pEntry = new ZipEntry;
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pEntry->initNew(storageName, NULL);
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * From here on out, failures are more interesting.
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mNeedCDRewrite = true;
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Write the LFH, even though it's still mostly blank.  We need it
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * as a place-holder.  In theory the LFH isn't necessary, but in
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * practice some utilities demand it.
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    lfhPosn = ftell(mZipFp);
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pEntry->mLFH.write(mZipFp);
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    startPosn = ftell(mZipFp);
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Copy the data in, possibly compressing it as we go.
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (sourceType == ZipEntry::kCompressStored) {
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (compressionMethod == ZipEntry::kCompressDeflated) {
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bool failed = false;
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            result = compressFpToFp(mZipFp, inputFp, data, size, &crc);
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (result != NO_ERROR) {
4195baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("compression failed, storing\n");
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                failed = true;
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /*
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * Make sure it has compressed "enough".  This probably ought
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * to be set through an API call, but I don't expect our
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * criteria to change over time.
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 */
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                long src = inputFp ? ftell(inputFp) : size;
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                long dst = ftell(mZipFp) - startPosn;
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (dst + (dst / 10) > src) {
4305baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                    ALOGD("insufficient compression (src=%ld dst=%ld), storing\n",
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        src, dst);
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    failed = true;
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (failed) {
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                compressionMethod = ZipEntry::kCompressStored;
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (inputFp) rewind(inputFp);
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                fseek(mZipFp, startPosn, SEEK_SET);
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /* fall through to kCompressStored case */
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* handle "no compression" request, or failed compression from above */
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (compressionMethod == ZipEntry::kCompressStored) {
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (inputFp) {
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                result = copyFpToFp(mZipFp, inputFp, &crc);
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                result = copyDataToFp(mZipFp, data, size, &crc);
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (result != NO_ERROR) {
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // don't need to truncate; happens in CDE rewrite
4525baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("failed copying data in\n");
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                goto bail;
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // currently seeked to end of file
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        uncompressedLen = inputFp ? ftell(inputFp) : size;
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else if (sourceType == ZipEntry::kCompressDeflated) {
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* we should support uncompressed-from-compressed, but it's not
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * important right now */
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        assert(compressionMethod == ZipEntry::kCompressDeflated);
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        bool scanResult;
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int method;
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long compressedLen;
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen,
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        &compressedLen, &crc);
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!scanResult || method != ZipEntry::kCompressDeflated) {
4715baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("this isn't a deflated gzip file?");
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            result = UNKNOWN_ERROR;
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            goto bail;
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL);
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (result != NO_ERROR) {
4785baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("failed copying gzip data in\n");
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            goto bail;
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        assert(false);
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = UNKNOWN_ERROR;
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * We could write the "Data Descriptor", but there doesn't seem to
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * be any point since we're going to go back and write the LFH.
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Update file offsets.
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    endPosn = ftell(mZipFp);            // seeked to end of compressed data
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Success!  Fill out new values.
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc,
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        compressionMethod);
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp));
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pEntry->setModWhen(modWhen);
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pEntry->setLFHOffset(lfhPosn);
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEOCD.mNumEntries++;
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEOCD.mTotalNumEntries++;
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEOCD.mCentralDirOffset = endPosn;
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Go back and write the LFH.
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = UNKNOWN_ERROR;
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pEntry->mLFH.write(mZipFp);
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Add pEntry to the list.
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEntries.add(pEntry);
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (ppEntry != NULL)
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        *ppEntry = pEntry;
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pEntry = NULL;
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectbail:
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (inputFp != NULL)
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fclose(inputFp);
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    delete pEntry;
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return result;
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Add an entry by copying it from another zip file.  If "padding" is
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * nonzero, the specified number of bytes will be added to the "extra"
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * field in the header.
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int padding, ZipEntry** ppEntry)
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ZipEntry* pEntry = NULL;
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    status_t result;
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    long lfhPosn, endPosn;
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mReadOnly)
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return INVALID_OPERATION;
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* make sure we're in a reasonable state */
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    assert(mZipFp != NULL);
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    assert(mEntries.size() == mEOCD.mTotalNumEntries);
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = UNKNOWN_ERROR;
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pEntry = new ZipEntry;
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (pEntry == NULL) {
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = NO_MEMORY;
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (result != NO_ERROR)
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (padding != 0) {
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = pEntry->addPadding(padding);
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (result != NO_ERROR)
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            goto bail;
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * From here on out, failures are more interesting.
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mNeedCDRewrite = true;
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Write the LFH.  Since we're not recompressing the data, we already
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * have all of the fields filled out.
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    lfhPosn = ftell(mZipFp);
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pEntry->mLFH.write(mZipFp);
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Copy the data over.
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If the "has data descriptor" flag is set, we want to copy the DD
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * fields as well.  This is a fixed-size area immediately following
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the data.
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = UNKNOWN_ERROR;
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    off_t copyLen;
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    copyLen = pSourceEntry->getCompressedLen();
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        copyLen += ZipEntry::kDataDescriptorLen;
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        != NO_ERROR)
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {
6068564c8da817a845353d213acd8636b76f567b234Steve Block        ALOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        result = UNKNOWN_ERROR;
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Update file offsets.
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    endPosn = ftell(mZipFp);
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Success!  Fill out new values.
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pEntry->setLFHOffset(lfhPosn);      // sets mCDE.mLocalHeaderRelOffset
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEOCD.mNumEntries++;
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEOCD.mTotalNumEntries++;
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEOCD.mCentralDirOffset = endPosn;
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Add pEntry to the list.
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEntries.add(pEntry);
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (ppEntry != NULL)
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        *ppEntry = pEntry;
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pEntry = NULL;
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    result = NO_ERROR;
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectbail:
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    delete pEntry;
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return result;
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copy all of the bytes in "src" to "dst".
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will be seeked immediately past the data.
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32)
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned char tmpBuf[32768];
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t count;
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    *pCRC32 = crc32(0L, Z_NULL, 0);
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while (1) {
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp);
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ferror(srcFp) || ferror(dstFp))
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return errnoToStatus(errno);
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (count == 0)
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        *pCRC32 = crc32(*pCRC32, tmpBuf, count);
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fwrite(tmpBuf, 1, count, dstFp) != count) {
6635baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("fwrite %d bytes failed\n", (int) count);
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return UNKNOWN_ERROR;
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copy all of the bytes in "src" to "dst".
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * On exit, "dstFp" will be seeked immediately past the data.
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t ZipFile::copyDataToFp(FILE* dstFp,
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const void* data, size_t size, unsigned long* pCRC32)
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t count;
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    *pCRC32 = crc32(0L, Z_NULL, 0);
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (size > 0) {
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size);
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fwrite(data, 1, size, dstFp) != size) {
6855baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("fwrite %d bytes failed\n", (int) size);
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return UNKNOWN_ERROR;
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copy some of the bytes in "src" to "dst".
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If "pCRC32" is NULL, the CRC will not be computed.
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will be seeked immediately past the data just written.
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned long* pCRC32)
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned char tmpBuf[32768];
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t count;
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (pCRC32 != NULL)
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        *pCRC32 = crc32(0L, Z_NULL, 0);
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while (length) {
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long readSize;
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        readSize = sizeof(tmpBuf);
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (readSize > length)
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            readSize = length;
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        count = fread(tmpBuf, 1, readSize, srcFp);
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((long) count != readSize) {     // error or unexpected EOF
7195baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("fread %d bytes failed\n", (int) readSize);
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return UNKNOWN_ERROR;
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pCRC32 != NULL)
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            *pCRC32 = crc32(*pCRC32, tmpBuf, count);
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fwrite(tmpBuf, 1, count, dstFp) != count) {
7275baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("fwrite %d bytes failed\n", (int) count);
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return UNKNOWN_ERROR;
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        length -= readSize;
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Compress all of the data in "srcFp" and write it to "dstFp".
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will be seeked immediately past the compressed data.
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp,
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const void* data, size_t size, unsigned long* pCRC32)
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    status_t result = NO_ERROR;
747e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    const size_t kBufSize = 32768;
748e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    unsigned char* inBuf = NULL;
749e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    unsigned char* outBuf = NULL;
750e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    z_stream zstream;
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    bool atEof = false;     // no feof() aviailable yet
752e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    unsigned long crc;
753e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    int zerr;
754e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
755e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    /*
756e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen     * Create an input buffer and an output buffer.
757e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen     */
758e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    inBuf = new unsigned char[kBufSize];
759e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    outBuf = new unsigned char[kBufSize];
760e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    if (inBuf == NULL || outBuf == NULL) {
761e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        result = NO_MEMORY;
762e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        goto bail;
763e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    }
764e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
765e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    /*
766e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen     * Initialize the zlib stream.
767e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen     */
768e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    memset(&zstream, 0, sizeof(zstream));
769e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    zstream.zalloc = Z_NULL;
770e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    zstream.zfree = Z_NULL;
771e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    zstream.opaque = Z_NULL;
772e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    zstream.next_in = NULL;
773e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    zstream.avail_in = 0;
774e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    zstream.next_out = outBuf;
775e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    zstream.avail_out = kBufSize;
776e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    zstream.data_type = Z_UNKNOWN;
777e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
778e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION,
779e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
780e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    if (zerr != Z_OK) {
781e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        result = UNKNOWN_ERROR;
782e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        if (zerr == Z_VERSION_ERROR) {
7833762c311729fe9f3af085c14c5c1fb471d994c03Steve Block            ALOGE("Installed zlib is not compatible with linked version (%s)\n",
784e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                ZLIB_VERSION);
785e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        } else {
7865baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr);
787e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        }
788e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        goto bail;
789e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    }
790e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
791e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    crc = crc32(0L, Z_NULL, 0);
792e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
793e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    /*
794e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen     * Loop while we have data.
795e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen     */
796e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    do {
797e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        size_t getSize;
798e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        int flush;
799e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
800e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        /* only read if the input buffer is empty */
801e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        if (zstream.avail_in == 0 && !atEof) {
80271f2cf116aab893e224056c38ab146bd1538dd3eSteve Block            ALOGV("+++ reading %d bytes\n", (int)kBufSize);
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (data) {
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                getSize = size > kBufSize ? kBufSize : size;
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                memcpy(inBuf, data, getSize);
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                data = ((const char*)data) + getSize;
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                size -= getSize;
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                getSize = fread(inBuf, 1, kBufSize, srcFp);
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (ferror(srcFp)) {
8115baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                    ALOGD("deflate read failed (errno=%d)\n", errno);
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    goto z_bail;
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (getSize < kBufSize) {
81671f2cf116aab893e224056c38ab146bd1538dd3eSteve Block                ALOGV("+++  got %d bytes, EOF reached\n",
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (int)getSize);
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                atEof = true;
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
821e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            crc = crc32(crc, inBuf, getSize);
822e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
823e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            zstream.next_in = inBuf;
824e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            zstream.avail_in = getSize;
825e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        }
826e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
827e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        if (atEof)
828e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            flush = Z_FINISH;       /* tell zlib that we're done */
829e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        else
830e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            flush = Z_NO_FLUSH;     /* more to come! */
831e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
832e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        zerr = deflate(&zstream, flush);
833e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        if (zerr != Z_OK && zerr != Z_STREAM_END) {
8345baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("zlib deflate call failed (zerr=%d)\n", zerr);
835e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            result = UNKNOWN_ERROR;
836e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            goto z_bail;
837e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        }
838e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
839e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        /* write when we're full or when we're done */
840e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        if (zstream.avail_out == 0 ||
841e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize))
842e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        {
84371f2cf116aab893e224056c38ab146bd1538dd3eSteve Block            ALOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf));
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) !=
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (size_t)(zstream.next_out - outBuf))
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            {
8475baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("write %d failed in deflate\n",
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (int) (zstream.next_out - outBuf));
849e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                goto z_bail;
850e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            }
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
852e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            zstream.next_out = outBuf;
853e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            zstream.avail_out = kBufSize;
854e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        }
855e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    } while (zerr == Z_OK);
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
857e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
859e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    *pCRC32 = crc;
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectz_bail:
862e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    deflateEnd(&zstream);        /* free up any allocated structures */
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectbail:
865e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    delete[] inBuf;
866e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    delete[] outBuf;
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
868e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    return result;
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Mark an entry as deleted.
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * We will eventually need to crunch the file down, but if several files
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * are being removed (perhaps as part of an "update" process) we can make
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * things considerably faster by deferring the removal to "flush" time.
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t ZipFile::remove(ZipEntry* pEntry)
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Should verify that pEntry is actually part of this archive, and
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * not some stray ZipEntry from a different file.
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* mark entry as deleted, and mark archive as dirty */
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    pEntry->setDeleted();
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mNeedCDRewrite = true;
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Flush any pending writes.
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * In particular, this will crunch out deleted entries, and write the
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Central Directory and EOCD if we have stomped on them.
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t ZipFile::flush(void)
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    status_t result = NO_ERROR;
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    long eocdPosn;
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int i, count;
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mReadOnly)
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return INVALID_OPERATION;
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!mNeedCDRewrite)
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NO_ERROR;
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    assert(mZipFp != NULL);
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    result = crunchArchive();
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (result != NO_ERROR)
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return result;
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0)
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return UNKNOWN_ERROR;
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    count = mEntries.size();
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (i = 0; i < count; i++) {
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ZipEntry* pEntry = mEntries[i];
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        pEntry->mCDE.write(mZipFp);
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eocdPosn = ftell(mZipFp);
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset;
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEOCD.write(mZipFp);
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If we had some stuff bloat up during compression and get replaced
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * with plain files, or if we deleted some entries, there's a lot
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * of wasted space at the end of the file.  Remove it now.
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) {
9348564c8da817a845353d213acd8636b76f567b234Steve Block        ALOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno));
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // not fatal
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* should we clear the "newly added" flag in all entries now? */
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mNeedCDRewrite = false;
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Crunch deleted files out of an archive by shifting the later files down.
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Because we're not using a temp file, we do the operation inside the
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * current file.
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t ZipFile::crunchArchive(void)
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    status_t result = NO_ERROR;
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int i, count;
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    long delCount, adjust;
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#if 0
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    printf("CONTENTS:\n");
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (i = 0; i < (int) mEntries.size(); i++) {
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        printf(" %d: lfhOff=%ld del=%d\n",
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted());
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    printf("  END is %ld\n", (long) mEOCD.mCentralDirOffset);
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Roll through the set of files, shifting them as appropriate.  We
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * could probably get a slight performance improvement by sliding
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * multiple files down at once (because we could use larger reads
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * when operating on batches of small files), but it's not that useful.
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    count = mEntries.size();
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    delCount = adjust = 0;
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (i = 0; i < count; i++) {
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ZipEntry* pEntry = mEntries[i];
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long span;
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pEntry->getLFHOffset() != 0) {
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long nextOffset;
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /* Get the length of this entry by finding the offset
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * of the next entry.  Directory entries don't have
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * file offsets, so we need to find the next non-directory
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * entry.
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            nextOffset = 0;
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int ii = i+1; nextOffset == 0 && ii < count; ii++)
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                nextOffset = mEntries[ii]->getLFHOffset();
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (nextOffset == 0)
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                nextOffset = mEOCD.mCentralDirOffset;
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            span = nextOffset - pEntry->getLFHOffset();
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            assert(span >= ZipEntry::LocalFileHeader::kLFHLen);
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /* This is a directory entry.  It doesn't have
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * any actual file contents, so there's no need to
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * move anything.
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            span = 0;
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n",
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //    i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count);
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pEntry->getDeleted()) {
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            adjust += span;
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            delCount++;
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            delete pEntry;
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEntries.removeAt(i);
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /* adjust loop control */
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            count--;
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            i--;
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (span != 0 && adjust > 0) {
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /* shuffle this entry back */
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //printf("+++ Shuffling '%s' back %ld\n",
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //    pEntry->getFileName(), adjust);
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            result = filemove(mZipFp, pEntry->getLFHOffset() - adjust,
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        pEntry->getLFHOffset(), span);
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (result != NO_ERROR) {
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /* this is why you use a temp file */
10223762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                ALOGE("error during crunch - archive is toast\n");
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return result;
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust);
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fix EOCD info.  We have to wait until the end to do some of this
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * because we use mCentralDirOffset to determine "span" for the
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * last entry.
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEOCD.mCentralDirOffset -= adjust;
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEOCD.mNumEntries -= delCount;
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEOCD.mTotalNumEntries -= delCount;
10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mEOCD.mCentralDirSize = 0;  // mark invalid; set by flush()
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries);
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    assert(mEOCD.mNumEntries == count);
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return result;
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Works like memmove(), but on pieces of a file.
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n)
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (dst == src || n <= 0)
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NO_ERROR;
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned char readBuf[32768];
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (dst < src) {
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* shift stuff toward start of file; must read from start */
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (n != 0) {
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            size_t getSize = sizeof(readBuf);
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (getSize > n)
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                getSize = n;
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (fseek(fp, (long) src, SEEK_SET) != 0) {
10645baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("filemove src seek %ld failed\n", (long) src);
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return UNKNOWN_ERROR;
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (fread(readBuf, 1, getSize, fp) != getSize) {
10695baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("filemove read %ld off=%ld failed\n",
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (long) getSize, (long) src);
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return UNKNOWN_ERROR;
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (fseek(fp, (long) dst, SEEK_SET) != 0) {
10755baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("filemove dst seek %ld failed\n", (long) dst);
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return UNKNOWN_ERROR;
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (fwrite(readBuf, 1, getSize, fp) != getSize) {
10805baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                ALOGD("filemove write %ld off=%ld failed\n",
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (long) getSize, (long) dst);
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return UNKNOWN_ERROR;
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            src += getSize;
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dst += getSize;
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            n -= getSize;
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* shift stuff toward end of file; must read from end */
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        assert(false);      // write this someday, maybe
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return UNKNOWN_ERROR;
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the modification time from a file descriptor.
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projecttime_t ZipFile::getModTime(int fd)
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    struct stat sb;
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fstat(fd, &sb) < 0) {
11075baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("HEY: fstat on fd %d failed\n", fd);
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (time_t) -1;
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return sb.st_mtime;
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#if 0       /* this is a bad idea */
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get a copy of the Zip file descriptor.
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * We don't allow this if the file was opened read-write because we tend
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to leave the file contents in an uncertain state between calls to
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * flush().  The duplicated file descriptor should only be valid for reads.
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint ZipFile::getZipFd(void) const
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!mReadOnly)
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return INVALID_OPERATION;
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    assert(mZipFp != NULL);
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int fd;
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    fd = dup(fileno(mZipFp));
11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fd < 0) {
11325baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD("didn't work, errno=%d\n", errno);
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return fd;
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#if 0
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Expand data.
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectbool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return false;
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// free the memory when you're done
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid* ZipFile::uncompress(const ZipEntry* entry)
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t unlen = entry->getUncompressedLen();
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t clen = entry->getCompressedLen();
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void* buf = malloc(unlen);
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (buf == NULL) {
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    fseek(mZipFp, 0, SEEK_SET);
11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    off_t offset = entry->getFileOffset();
11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fseek(mZipFp, offset, SEEK_SET) != 0) {
11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        goto bail;
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    switch (entry->getCompressionMethod())
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case ZipEntry::kCompressStored: {
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ssize_t amt = fread(buf, 1, unlen, mZipFp);
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (amt != (ssize_t)unlen) {
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                goto bail;
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#if 0
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            printf("data...\n");
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            const unsigned char* p = (unsigned char*)buf;
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            const unsigned char* end = p+unlen;
11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i=0; i<32 && p < end; i++) {
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                printf("0x%08x ", (int)(offset+(i*0x10)));
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int j=0; j<0x10 && p < end; j++) {
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    printf(" %02x", *p);
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    p++;
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                printf("\n");
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case ZipEntry::kCompressDeflated: {
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) {
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                goto bail;
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            goto bail;
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return buf;
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectbail:
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    free(buf);
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NULL;
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ===========================================================================
1210e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen *      ZipFile::EndOfCentralDir
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ===========================================================================
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Read the end-of-central-dir fields.
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * "buf" should be positioned at the EOCD signature, and should contain
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the entire EOCD area including the comment.
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len)
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* don't allow re-use */
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    assert(mComment == NULL);
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (len < kEOCDLen) {
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* looks like ZIP file got truncated */
12275baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        ALOGD(" Zip EOCD: expected >= %d bytes, found %d\n",
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            kEOCDLen, len);
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return INVALID_OPERATION;
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* this should probably be an assert() */
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (ZipEntry::getLongLE(&buf[0x00]) != kSignature)
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return UNKNOWN_ERROR;
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mDiskNumber = ZipEntry::getShortLE(&buf[0x04]);
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]);
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mNumEntries = ZipEntry::getShortLE(&buf[0x08]);
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]);
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]);
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]);
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mCommentLen = ZipEntry::getShortLE(&buf[0x14]);
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // TODO: validate mCentralDirOffset
12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mCommentLen > 0) {
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (kEOCDLen + mCommentLen > len) {
12485baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            ALOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n",
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                kEOCDLen, mCommentLen, len);
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return UNKNOWN_ERROR;
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mComment = new unsigned char[mCommentLen];
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        memcpy(mComment, buf + kEOCDLen, mCommentLen);
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Write an end-of-central-directory section.
12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t ZipFile::EndOfCentralDir::write(FILE* fp)
12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    unsigned char buf[kEOCDLen];
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ZipEntry::putLongLE(&buf[0x00], kSignature);
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ZipEntry::putShortLE(&buf[0x04], mDiskNumber);
12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir);
12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ZipEntry::putShortLE(&buf[0x08], mNumEntries);
12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries);
12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize);
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset);
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ZipEntry::putShortLE(&buf[0x14], mCommentLen);
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen)
12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return UNKNOWN_ERROR;
12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mCommentLen > 0) {
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        assert(mComment != NULL);
12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen)
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return UNKNOWN_ERROR;
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NO_ERROR;
12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Dump the contents of an EndOfCentralDir object.
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid ZipFile::EndOfCentralDir::dump(void) const
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
12915baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD(" EndOfCentralDir contents:\n");
12925baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("  diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n",
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries);
12945baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    ALOGD("  centDirSize=%lu centDirOff=%lu commentLen=%u\n",
12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCentralDirSize, mCentralDirOffset, mCommentLen);
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1298