13344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
23344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Copyright (C) 2006 The Android Open Source Project
33344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
43344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Licensed under the Apache License, Version 2.0 (the "License");
53344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * you may not use this file except in compliance with the License.
63344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * You may obtain a copy of the License at
73344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
83344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *      http://www.apache.org/licenses/LICENSE-2.0
93344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Unless required by applicable law or agreed to in writing, software
113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * distributed under the License is distributed on an "AS IS" BASIS,
123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * See the License for the specific language governing permissions and
143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * limitations under the License.
153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian//
183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian// Access to Zip archives.
193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian//
203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#define LOG_TAG "zip"
223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
23f14d85d6fcb740930f15325611609406d658684cMathias Agopian#include <androidfw/ZipUtils.h>
243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#include <utils/Log.h>
253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#include "ZipFile.h"
273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#include <zlib.h>
293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#define DEF_MEM_LEVEL 8                // normally in zutil.h?
303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
31093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien#include "zopfli/deflate.h"
32093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#include <memory.h>
343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#include <sys/stat.h>
353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#include <errno.h>
363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#include <assert.h>
373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianusing namespace android;
393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Some environments require the "b", some choke on it.
423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#define FILE_OPEN_RO        "rb"
443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#define FILE_OPEN_RW        "r+b"
453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#define FILE_OPEN_RW_CREATE "w+b"
463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/* should live somewhere else? */
483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatic status_t errnoToStatus(int err)
493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (err == ENOENT)
513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return NAME_NOT_FOUND;
523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    else if (err == EACCES)
533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return PERMISSION_DENIED;
543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    else
553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return UNKNOWN_ERROR;
563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Open a file and parse its guts.
603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::open(const char* zipFileName, int flags)
623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    bool newArchive = false;
643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    assert(mZipFp == NULL);     // no reopen
663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if ((flags & kOpenTruncate))
683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        flags |= kOpenCreate;           // trunc implies create
693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite))
713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return INVALID_OPERATION;       // not both
723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite)))
733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return INVALID_OPERATION;       // not neither
743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if ((flags & kOpenCreate) && !(flags & kOpenReadWrite))
753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return INVALID_OPERATION;       // create requires write
763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (flags & kOpenTruncate) {
783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        newArchive = true;
793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    } else {
803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        newArchive = (access(zipFileName, F_OK) != 0);
813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (!(flags & kOpenCreate) && newArchive) {
823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            /* not creating, must already exist */
8315fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block            ALOGD("File %s does not exist", zipFileName);
843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            return NAME_NOT_FOUND;
853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /* open the file */
893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    const char* openflags;
903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (flags & kOpenReadWrite) {
913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (newArchive)
923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            openflags = FILE_OPEN_RW_CREATE;
933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        else
943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            openflags = FILE_OPEN_RW;
953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    } else {
963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        openflags = FILE_OPEN_RO;
973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mZipFp = fopen(zipFileName, openflags);
993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (mZipFp == NULL) {
1003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        int err = errno;
10115fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block        ALOGD("fopen failed: %d\n", err);
1023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return errnoToStatus(err);
1033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
1043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
1053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    status_t result;
1063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (!newArchive) {
1073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        /*
1083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian         * Load the central directory.  If that fails, then this probably
1093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian         * isn't a Zip archive.
1103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian         */
1113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = readCentralDir();
1123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    } else {
1133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        /*
1143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian         * Newly-created.  The EndOfCentralDir constructor actually
1153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian         * sets everything to be the way we want it (all zeroes).  We
1163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian         * set mNeedCDRewrite so that we create *something* if the
1173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian         * caller doesn't add any files.  (We could also just unlink
1183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian         * the file if it's brand new and nothing was added, but that's
1193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian         * probably doing more than we really should -- the user might
1203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian         * have a need for empty zip files.)
1213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian         */
1223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        mNeedCDRewrite = true;
1233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = NO_ERROR;
1243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
1253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
1263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (flags & kOpenReadOnly)
1273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        mReadOnly = true;
1283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    else
1293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        assert(!mReadOnly);
1303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
1313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return result;
1323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
1333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
1343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
1353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Return the Nth entry in the archive.
1363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
1373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias AgopianZipEntry* ZipFile::getEntryByIndex(int idx) const
1383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
1393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (idx < 0 || idx >= (int) mEntries.size())
1403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return NULL;
1413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
1423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return mEntries[idx];
1433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
1443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
1453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
1463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Find an entry by name.
1473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
1483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias AgopianZipEntry* ZipFile::getEntryByName(const char* fileName) const
1493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
1503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
1513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * Do a stupid linear string-compare search.
1523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     *
1533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * There are various ways to speed this up, especially since it's rare
1543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * to intermingle changes to the archive with "get by name" calls.  We
1553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * don't want to sort the mEntries vector itself, however, because
1563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * it's used to recreate the Central Directory.
1573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     *
1583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * (Hash table works, parallel list of pointers in sorted order is good.)
1593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
1603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    int idx;
1613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
1623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    for (idx = mEntries.size()-1; idx >= 0; idx--) {
1633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        ZipEntry* pEntry = mEntries[idx];
1643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (!pEntry->getDeleted() &&
1653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            strcmp(fileName, pEntry->getFileName()) == 0)
1663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        {
1673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            return pEntry;
1683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
1693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
1703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
1713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return NULL;
1723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
1733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
1743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
1753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Empty the mEntries vector.
1763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
1773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianvoid ZipFile::discardEntries(void)
1783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
1793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    int count = mEntries.size();
1803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
1813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    while (--count >= 0)
1823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        delete mEntries[count];
1833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
1843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEntries.clear();
1853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
1863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
1873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
1883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
1893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Find the central directory and read the contents.
1903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
1913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * The fun thing about ZIP archives is that they may or may not be
1923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * readable from start to end.  In some cases, notably for archives
1933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * that were written to stdout, the only length information is in the
1943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * central directory at the end of the file.
1953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
1963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Of course, the central directory can be followed by a variable-length
1973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * comment field, so we have to scan through it backwards.  The comment
1983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
1993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * itself, plus apparently sometimes people throw random junk on the end
2003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * just for the fun of it.
2013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
2023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * This is all a little wobbly.  If the wrong value ends up in the EOCD
2033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * area, we're hosed.  This appears to be the way that everbody handles
2043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * it though, so we're in pretty good company if this fails.
2053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
2063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::readCentralDir(void)
2073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
2083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    status_t result = NO_ERROR;
2093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    unsigned char* buf = NULL;
2103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    off_t fileLength, seekStart;
2113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    long readAmount;
2123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    int i;
2133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
2143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    fseek(mZipFp, 0, SEEK_END);
2153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    fileLength = ftell(mZipFp);
2163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    rewind(mZipFp);
2173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
2183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /* too small to be a ZIP archive? */
2193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (fileLength < EndOfCentralDir::kEOCDLen) {
22015fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block        ALOGD("Length is %ld -- too small\n", (long)fileLength);
2213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = INVALID_OPERATION;
2223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
2233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
2243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
2253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch];
2263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (buf == NULL) {
22715fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block        ALOGD("Failure allocating %d bytes for EOCD search",
2283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian             EndOfCentralDir::kMaxEOCDSearch);
2293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = NO_MEMORY;
2303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
2313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
2323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
2333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (fileLength > EndOfCentralDir::kMaxEOCDSearch) {
2343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch;
2353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        readAmount = EndOfCentralDir::kMaxEOCDSearch;
2363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    } else {
2373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        seekStart = 0;
2383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        readAmount = (long) fileLength;
2393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
2403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (fseek(mZipFp, seekStart, SEEK_SET) != 0) {
24115fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block        ALOGD("Failure seeking to end of zip at %ld", (long) seekStart);
2423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = UNKNOWN_ERROR;
2433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
2443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
2453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
2463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /* read the last part of the file into the buffer */
2473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) {
24815fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block        ALOGD("short file? wanted %ld\n", readAmount);
2493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = UNKNOWN_ERROR;
2503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
2513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
2523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
2533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /* find the end-of-central-dir magic */
2543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    for (i = readAmount - 4; i >= 0; i--) {
2553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (buf[i] == 0x50 &&
2563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature)
2573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        {
2582da72c6265bab1322876fa9702f7580bff7fd8beSteve Block            ALOGV("+++ Found EOCD at buf+%d\n", i);
2593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            break;
2603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
2613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
2623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (i < 0) {
26315fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block        ALOGD("EOCD not found, not Zip\n");
2643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = INVALID_OPERATION;
2653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
2663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
2673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
2683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /* extract eocd values */
2693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    result = mEOCD.readBuf(buf + i, readAmount - i);
2703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (result != NO_ERROR) {
27115fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block        ALOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
2723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
2733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
2743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    //mEOCD.dump();
2753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
2763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 ||
2773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        mEOCD.mNumEntries != mEOCD.mTotalNumEntries)
2783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    {
27915fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block        ALOGD("Archive spanning not supported\n");
2803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = INVALID_OPERATION;
2813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
2823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
2833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
2843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
2853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * So far so good.  "mCentralDirSize" is the size in bytes of the
2863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * central directory, so we can just seek back that far to find it.
2873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * We can also seek forward mCentralDirOffset bytes from the
2883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * start of the file.
2893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     *
2903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * We're not guaranteed to have the rest of the central dir in the
2913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * buffer, nor are we guaranteed that the central dir will have any
2923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * sort of convenient size.  We need to skip to the start of it and
2933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * read the header, then the other goodies.
2943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     *
2953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * The only thing we really need right now is the file comment, which
2963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * we're hoping to preserve.
2973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
2983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
29915fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block        ALOGD("Failure seeking to central dir offset %ld\n",
3003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian             mEOCD.mCentralDirOffset);
3013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = UNKNOWN_ERROR;
3023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
3033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
3043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
3053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
3063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * Loop through and read the central dir entries.
3073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
3082da72c6265bab1322876fa9702f7580bff7fd8beSteve Block    ALOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries);
3093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    int entry;
3103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) {
3113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        ZipEntry* pEntry = new ZipEntry;
3123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
3133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = pEntry->initFromCDE(mZipFp);
3143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (result != NO_ERROR) {
31515fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block            ALOGD("initFromCDE failed\n");
3163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            delete pEntry;
3173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            goto bail;
3183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
3193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
3203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        mEntries.add(pEntry);
3213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
3223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
3233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
3243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
3253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * If all went well, we should now be back at the EOCD.
3263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
3273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    {
3283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        unsigned char checkBuf[4];
3293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (fread(checkBuf, 1, 4, mZipFp) != 4) {
33015fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block            ALOGD("EOCD check read failed\n");
3313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            result = INVALID_OPERATION;
3323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            goto bail;
3333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
3343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) {
33515fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block            ALOGD("EOCD read check failed\n");
3363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            result = UNKNOWN_ERROR;
3373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            goto bail;
3383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
3392da72c6265bab1322876fa9702f7580bff7fd8beSteve Block        ALOGV("+++ EOCD read check passed\n");
3403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
3413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
3423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianbail:
3433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    delete[] buf;
3443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return result;
3453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
3463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
3473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
3483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
3493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Add a new file to the archive.
3503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
3513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * This requires creating and populating a ZipEntry structure, and copying
3523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * the data into the file at the appropriate position.  The "appropriate
3533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * position" is the current location of the central directory, which we
3543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * casually overwrite (we can put it back later).
3553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
3563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * If we were concerned about safety, we would want to make all changes
3573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * in a temp file and then overwrite the original after everything was
3583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * safely written.  Not really a concern for us.
3593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
3603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::addCommon(const char* fileName, const void* data, size_t size,
3613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    const char* storageName, int sourceType, int compressionMethod,
3623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    ZipEntry** ppEntry)
3633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
3643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    ZipEntry* pEntry = NULL;
3653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    status_t result = NO_ERROR;
3663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    long lfhPosn, startPosn, endPosn, uncompressedLen;
3673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    FILE* inputFp = NULL;
3683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    unsigned long crc;
3693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    time_t modWhen;
3703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
3713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (mReadOnly)
3723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return INVALID_OPERATION;
3733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
3743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    assert(compressionMethod == ZipEntry::kCompressDeflated ||
3753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian           compressionMethod == ZipEntry::kCompressStored);
3763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
3773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /* make sure we're in a reasonable state */
3783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    assert(mZipFp != NULL);
3793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    assert(mEntries.size() == mEOCD.mTotalNumEntries);
3803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
3813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /* make sure it doesn't already exist */
3823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (getEntryByName(storageName) != NULL)
3833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return ALREADY_EXISTS;
3843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
3853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (!data) {
3863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        inputFp = fopen(fileName, FILE_OPEN_RO);
3873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (inputFp == NULL)
3883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            return errnoToStatus(errno);
3893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
3903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
3913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
3923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = UNKNOWN_ERROR;
3933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
3943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
3953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
3963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    pEntry = new ZipEntry;
3973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    pEntry->initNew(storageName, NULL);
3983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
3993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
4003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * From here on out, failures are more interesting.
4013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
4023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mNeedCDRewrite = true;
4033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
4043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
4053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * Write the LFH, even though it's still mostly blank.  We need it
4063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * as a place-holder.  In theory the LFH isn't necessary, but in
4073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * practice some utilities demand it.
4083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
4093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    lfhPosn = ftell(mZipFp);
4103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    pEntry->mLFH.write(mZipFp);
4113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    startPosn = ftell(mZipFp);
4123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
4133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
4143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * Copy the data in, possibly compressing it as we go.
4153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
4163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (sourceType == ZipEntry::kCompressStored) {
4173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (compressionMethod == ZipEntry::kCompressDeflated) {
4183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            bool failed = false;
4193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            result = compressFpToFp(mZipFp, inputFp, data, size, &crc);
4203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            if (result != NO_ERROR) {
42115fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block                ALOGD("compression failed, storing\n");
4223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                failed = true;
4233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            } else {
4243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                /*
4253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                 * Make sure it has compressed "enough".  This probably ought
4263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                 * to be set through an API call, but I don't expect our
4273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                 * criteria to change over time.
4283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                 */
4293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                long src = inputFp ? ftell(inputFp) : size;
4303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                long dst = ftell(mZipFp) - startPosn;
4313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                if (dst + (dst / 10) > src) {
43215fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block                    ALOGD("insufficient compression (src=%ld dst=%ld), storing\n",
4333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                        src, dst);
4343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                    failed = true;
4353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                }
4363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            }
4373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
4383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            if (failed) {
4393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                compressionMethod = ZipEntry::kCompressStored;
4403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                if (inputFp) rewind(inputFp);
4413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                fseek(mZipFp, startPosn, SEEK_SET);
4423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                /* fall through to kCompressStored case */
4433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            }
4443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
4453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        /* handle "no compression" request, or failed compression from above */
4463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (compressionMethod == ZipEntry::kCompressStored) {
4473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            if (inputFp) {
4483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                result = copyFpToFp(mZipFp, inputFp, &crc);
4493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            } else {
4503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                result = copyDataToFp(mZipFp, data, size, &crc);
4513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            }
4523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            if (result != NO_ERROR) {
4533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                // don't need to truncate; happens in CDE rewrite
45415fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block                ALOGD("failed copying data in\n");
4553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                goto bail;
4563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            }
4573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
4583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
4593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        // currently seeked to end of file
4603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        uncompressedLen = inputFp ? ftell(inputFp) : size;
4613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    } else if (sourceType == ZipEntry::kCompressDeflated) {
4623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        /* we should support uncompressed-from-compressed, but it's not
4633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian         * important right now */
4643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        assert(compressionMethod == ZipEntry::kCompressDeflated);
4653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
4663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        bool scanResult;
4673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        int method;
4683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        long compressedLen;
4693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
4703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen,
4713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                        &compressedLen, &crc);
4723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (!scanResult || method != ZipEntry::kCompressDeflated) {
47315fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block            ALOGD("this isn't a deflated gzip file?");
4743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            result = UNKNOWN_ERROR;
4753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            goto bail;
4763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
4773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
4783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL);
4793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (result != NO_ERROR) {
48015fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block            ALOGD("failed copying gzip data in\n");
4813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            goto bail;
4823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
4833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    } else {
4843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        assert(false);
4853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = UNKNOWN_ERROR;
4863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
4873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
4883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
4893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
4903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * We could write the "Data Descriptor", but there doesn't seem to
4913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * be any point since we're going to go back and write the LFH.
4923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     *
4933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * Update file offsets.
4943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
4953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    endPosn = ftell(mZipFp);            // seeked to end of compressed data
4963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
4973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
4983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * Success!  Fill out new values.
4993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
5003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc,
5013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        compressionMethod);
5023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp));
5033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    pEntry->setModWhen(modWhen);
5043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    pEntry->setLFHOffset(lfhPosn);
5053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEOCD.mNumEntries++;
5063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEOCD.mTotalNumEntries++;
5073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
5083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEOCD.mCentralDirOffset = endPosn;
5093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
5103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
5113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * Go back and write the LFH.
5123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
5133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
5143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = UNKNOWN_ERROR;
5153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
5163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
5173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    pEntry->mLFH.write(mZipFp);
5183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
5193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
5203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * Add pEntry to the list.
5213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
5223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEntries.add(pEntry);
5233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (ppEntry != NULL)
5243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        *ppEntry = pEntry;
5253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    pEntry = NULL;
5263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
5273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianbail:
5283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (inputFp != NULL)
5293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        fclose(inputFp);
5303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    delete pEntry;
5313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return result;
5323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
5333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
5343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
5353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Add an entry by copying it from another zip file.  If "padding" is
5363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * nonzero, the specified number of bytes will be added to the "extra"
5373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * field in the header.
5383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
5393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
5403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
5413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
5423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    int padding, ZipEntry** ppEntry)
5433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
5443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    ZipEntry* pEntry = NULL;
5453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    status_t result;
5463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    long lfhPosn, endPosn;
5473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
5483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (mReadOnly)
5493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return INVALID_OPERATION;
5503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
5513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /* make sure we're in a reasonable state */
5523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    assert(mZipFp != NULL);
5533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    assert(mEntries.size() == mEOCD.mTotalNumEntries);
5543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
5553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
5563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = UNKNOWN_ERROR;
5573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
5583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
5593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
5603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    pEntry = new ZipEntry;
5613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (pEntry == NULL) {
5623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = NO_MEMORY;
5633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
5643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
5653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
5663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
5673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (result != NO_ERROR)
5683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
5693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (padding != 0) {
5703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = pEntry->addPadding(padding);
5713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (result != NO_ERROR)
5723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            goto bail;
5733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
5743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
5753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
5763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * From here on out, failures are more interesting.
5773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
5783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mNeedCDRewrite = true;
5793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
5803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
5813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * Write the LFH.  Since we're not recompressing the data, we already
5823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * have all of the fields filled out.
5833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
5843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    lfhPosn = ftell(mZipFp);
5853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    pEntry->mLFH.write(mZipFp);
5863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
5873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
5883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * Copy the data over.
5893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     *
5903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * If the "has data descriptor" flag is set, we want to copy the DD
5913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * fields as well.  This is a fixed-size area immediately following
5923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * the data.
5933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
5943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
5953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    {
5963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = UNKNOWN_ERROR;
5973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
5983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
5993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
6003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    off_t copyLen;
6013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    copyLen = pSourceEntry->getCompressedLen();
6023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
6033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        copyLen += ZipEntry::kDataDescriptorLen;
6043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
6053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
6063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        != NO_ERROR)
6073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    {
608c0b74df335aa99e3c3f6f752de531836faa0c7c5Steve Block        ALOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
6093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        result = UNKNOWN_ERROR;
6103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
6113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
6123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
6133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
6143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * Update file offsets.
6153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
6163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    endPosn = ftell(mZipFp);
6173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
6183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
6193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * Success!  Fill out new values.
6203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
6213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    pEntry->setLFHOffset(lfhPosn);      // sets mCDE.mLocalHeaderRelOffset
6223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEOCD.mNumEntries++;
6233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEOCD.mTotalNumEntries++;
6243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
6253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEOCD.mCentralDirOffset = endPosn;
6263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
6273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
6283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * Add pEntry to the list.
6293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
6303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEntries.add(pEntry);
6313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (ppEntry != NULL)
6323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        *ppEntry = pEntry;
6333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    pEntry = NULL;
6343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
6353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    result = NO_ERROR;
6363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
6373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianbail:
6383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    delete pEntry;
6393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return result;
6403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
6413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
6423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
643093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * Add an entry by copying it from another zip file, recompressing with
644093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * Zopfli if already compressed.
645093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien *
646093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
647093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien */
648093d04c631aa2a4af3317912e9561672c5642bb8Raph Levienstatus_t ZipFile::addRecompress(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
649093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    ZipEntry** ppEntry)
650093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien{
651093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    ZipEntry* pEntry = NULL;
652093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    status_t result;
653093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    long lfhPosn, startPosn, endPosn, uncompressedLen;
654093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
655093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    if (mReadOnly)
656093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        return INVALID_OPERATION;
657093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
658093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    /* make sure we're in a reasonable state */
659093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    assert(mZipFp != NULL);
660093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    assert(mEntries.size() == mEOCD.mTotalNumEntries);
661093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
662093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
663093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        result = UNKNOWN_ERROR;
664093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        goto bail;
665093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    }
666093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
667093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    pEntry = new ZipEntry;
668093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    if (pEntry == NULL) {
669093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        result = NO_MEMORY;
670093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        goto bail;
671093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    }
672093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
673093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
674093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    if (result != NO_ERROR)
675093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        goto bail;
676093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
677093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    /*
678093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     * From here on out, failures are more interesting.
679093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     */
680093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    mNeedCDRewrite = true;
681093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
682093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    /*
683093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     * Write the LFH, even though it's still mostly blank.  We need it
684093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     * as a place-holder.  In theory the LFH isn't necessary, but in
685093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     * practice some utilities demand it.
686093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     */
687093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    lfhPosn = ftell(mZipFp);
688093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    pEntry->mLFH.write(mZipFp);
689093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    startPosn = ftell(mZipFp);
690093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
691093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    /*
692093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     * Copy the data over.
693093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     *
694093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     * If the "has data descriptor" flag is set, we want to copy the DD
695093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     * fields as well.  This is a fixed-size area immediately following
696093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     * the data.
697093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     */
698093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
699093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    {
700093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        result = UNKNOWN_ERROR;
701093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        goto bail;
702093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    }
703093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
704093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    uncompressedLen = pSourceEntry->getUncompressedLen();
705093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
706093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    if (pSourceEntry->isCompressed()) {
707093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        void *buf = pSourceZip->uncompress(pSourceEntry);
708093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        if (buf == NULL) {
709093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            result = NO_MEMORY;
710093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            goto bail;
711093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        }
712093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        long startPosn = ftell(mZipFp);
713093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        unsigned long crc;
714093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        if (compressFpToFp(mZipFp, NULL, buf, uncompressedLen, &crc) != NO_ERROR) {
715093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            ALOGW("recompress of '%s' failed\n", pEntry->mCDE.mFileName);
716093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            result = UNKNOWN_ERROR;
717093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            free(buf);
718093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            goto bail;
719093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        }
720093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        long endPosn = ftell(mZipFp);
721093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        pEntry->setDataInfo(uncompressedLen, endPosn - startPosn,
722093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            pSourceEntry->getCRC32(), ZipEntry::kCompressDeflated);
723093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        free(buf);
724093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    } else {
725093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        off_t copyLen;
726093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        copyLen = pSourceEntry->getCompressedLen();
727093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
728093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            copyLen += ZipEntry::kDataDescriptorLen;
729093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
730093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
731093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            != NO_ERROR)
732093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        {
733093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            ALOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
734093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            result = UNKNOWN_ERROR;
735093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            goto bail;
736093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        }
737093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    }
738093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
739093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    /*
740093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     * Update file offsets.
741093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     */
742093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    endPosn = ftell(mZipFp);
743093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
744093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    /*
745093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     * Success!  Fill out new values.
746093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     */
747093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    pEntry->setLFHOffset(lfhPosn);
748093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    mEOCD.mNumEntries++;
749093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    mEOCD.mTotalNumEntries++;
750093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
751093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    mEOCD.mCentralDirOffset = endPosn;
752093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
753093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    /*
754093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     * Go back and write the LFH.
755093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     */
756093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
757093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        result = UNKNOWN_ERROR;
758093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        goto bail;
759093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    }
760093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    pEntry->mLFH.write(mZipFp);
761093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
762093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    /*
763093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     * Add pEntry to the list.
764093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien     */
765093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    mEntries.add(pEntry);
766093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    if (ppEntry != NULL)
767093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        *ppEntry = pEntry;
768093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    pEntry = NULL;
769093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
770093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    result = NO_ERROR;
771093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
772093d04c631aa2a4af3317912e9561672c5642bb8Raph Levienbail:
773093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    delete pEntry;
774093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    return result;
775093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien}
776093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
777093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien/*
7783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Copy all of the bytes in "src" to "dst".
7793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
7803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
7813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * will be seeked immediately past the data.
7823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
7833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32)
7843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
7853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    unsigned char tmpBuf[32768];
7863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    size_t count;
7873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
7883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    *pCRC32 = crc32(0L, Z_NULL, 0);
7893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
7903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    while (1) {
7913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp);
7923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (ferror(srcFp) || ferror(dstFp))
7933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            return errnoToStatus(errno);
7943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (count == 0)
7953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            break;
7963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
7973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        *pCRC32 = crc32(*pCRC32, tmpBuf, count);
7983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
7993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (fwrite(tmpBuf, 1, count, dstFp) != count) {
80015fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block            ALOGD("fwrite %d bytes failed\n", (int) count);
8013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            return UNKNOWN_ERROR;
8023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
8033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
8043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
8053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return NO_ERROR;
8063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
8073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
8083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
8093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Copy all of the bytes in "src" to "dst".
8103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
8113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * On exit, "dstFp" will be seeked immediately past the data.
8123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
8133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::copyDataToFp(FILE* dstFp,
8143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    const void* data, size_t size, unsigned long* pCRC32)
8153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
8163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    size_t count;
8173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
8183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    *pCRC32 = crc32(0L, Z_NULL, 0);
8193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (size > 0) {
8203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size);
8213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (fwrite(data, 1, size, dstFp) != size) {
82215fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block            ALOGD("fwrite %d bytes failed\n", (int) size);
8233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            return UNKNOWN_ERROR;
8243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
8253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
8263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
8273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return NO_ERROR;
8283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
8293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
8303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
8313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Copy some of the bytes in "src" to "dst".
8323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
8333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * If "pCRC32" is NULL, the CRC will not be computed.
8343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
8353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
8363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * will be seeked immediately past the data just written.
8373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
8383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
8393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    unsigned long* pCRC32)
8403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
8413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    unsigned char tmpBuf[32768];
8423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    size_t count;
8433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
8443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (pCRC32 != NULL)
8453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        *pCRC32 = crc32(0L, Z_NULL, 0);
8463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
8473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    while (length) {
8483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        long readSize;
8493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
8503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        readSize = sizeof(tmpBuf);
8513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (readSize > length)
8523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            readSize = length;
8533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
8543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        count = fread(tmpBuf, 1, readSize, srcFp);
8553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if ((long) count != readSize) {     // error or unexpected EOF
85615fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block            ALOGD("fread %d bytes failed\n", (int) readSize);
8573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            return UNKNOWN_ERROR;
8583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
8593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
8603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (pCRC32 != NULL)
8613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            *pCRC32 = crc32(*pCRC32, tmpBuf, count);
8623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
8633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (fwrite(tmpBuf, 1, count, dstFp) != count) {
86415fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block            ALOGD("fwrite %d bytes failed\n", (int) count);
8653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            return UNKNOWN_ERROR;
8663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
8673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
8683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        length -= readSize;
8693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
8703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
8713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return NO_ERROR;
8723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
8733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
8743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
8753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Compress all of the data in "srcFp" and write it to "dstFp".
8763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
8773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
8783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * will be seeked immediately past the compressed data.
8793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
8803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp,
8813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    const void* data, size_t size, unsigned long* pCRC32)
8823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
8833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    status_t result = NO_ERROR;
884093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    const size_t kBufSize = 1024 * 1024;
8853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    unsigned char* inBuf = NULL;
8863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    unsigned char* outBuf = NULL;
887093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    size_t outSize = 0;
8883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    bool atEof = false;     // no feof() aviailable yet
8893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    unsigned long crc;
890093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    ZopfliOptions options;
891093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    unsigned char bp = 0;
8923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
893093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    ZopfliInitOptions(&options);
8943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
8953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    crc = crc32(0L, Z_NULL, 0);
8963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
897093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    if (data) {
898093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        crc = crc32(crc, (const unsigned char*)data, size);
899093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        ZopfliDeflate(&options, 2, true, (const unsigned char*)data, size, &bp,
900093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            &outBuf, &outSize);
901093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    } else {
902093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        /*
903093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien         * Create an input buffer and an output buffer.
904093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien         */
905093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        inBuf = new unsigned char[kBufSize];
906093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        if (inBuf == NULL) {
907093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            result = NO_MEMORY;
908093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            goto bail;
909093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        }
910093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien
911093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        /*
912093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien         * Loop while we have data.
913093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien         */
914093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        do {
915093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            size_t getSize;
916093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            getSize = fread(inBuf, 1, kBufSize, srcFp);
917093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            if (ferror(srcFp)) {
918093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien                ALOGD("deflate read failed (errno=%d)\n", errno);
919093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien                delete[] inBuf;
920093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien                goto bail;
9213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            }
9223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            if (getSize < kBufSize) {
9232da72c6265bab1322876fa9702f7580bff7fd8beSteve Block                ALOGV("+++  got %d bytes, EOF reached\n",
9243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                    (int)getSize);
9253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                atEof = true;
9263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            }
9273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
9283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            crc = crc32(crc, inBuf, getSize);
929093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien            ZopfliDeflate(&options, 2, atEof, inBuf, getSize, &bp, &outBuf, &outSize);
930093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        } while (!atEof);
931093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        delete[] inBuf;
932093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    }
9333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
934093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    ALOGV("+++ writing %d bytes\n", (int)outSize);
935093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    if (fwrite(outBuf, 1, outSize, dstFp) != outSize) {
936093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        ALOGD("write %d failed in deflate\n", (int)outSize);
937093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien        goto bail;
938093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    }
9393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
9403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    *pCRC32 = crc;
9413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
9423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianbail:
943093d04c631aa2a4af3317912e9561672c5642bb8Raph Levien    free(outBuf);
9443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
9453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return result;
9463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
9473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
9483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
9493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Mark an entry as deleted.
9503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
9513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * We will eventually need to crunch the file down, but if several files
9523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * are being removed (perhaps as part of an "update" process) we can make
9533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * things considerably faster by deferring the removal to "flush" time.
9543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
9553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::remove(ZipEntry* pEntry)
9563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
9573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
9583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * Should verify that pEntry is actually part of this archive, and
9593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * not some stray ZipEntry from a different file.
9603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
9613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
9623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /* mark entry as deleted, and mark archive as dirty */
9633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    pEntry->setDeleted();
9643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mNeedCDRewrite = true;
9653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return NO_ERROR;
9663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
9673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
9683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
9693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Flush any pending writes.
9703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
9713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * In particular, this will crunch out deleted entries, and write the
9723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Central Directory and EOCD if we have stomped on them.
9733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
9743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::flush(void)
9753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
9763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    status_t result = NO_ERROR;
9773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    long eocdPosn;
9783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    int i, count;
9793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
9803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (mReadOnly)
9813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return INVALID_OPERATION;
9823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (!mNeedCDRewrite)
9833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return NO_ERROR;
9843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
9853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    assert(mZipFp != NULL);
9863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
9873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    result = crunchArchive();
9883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (result != NO_ERROR)
9893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return result;
9903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
9913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0)
9923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return UNKNOWN_ERROR;
9933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
9943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    count = mEntries.size();
9953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    for (i = 0; i < count; i++) {
9963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        ZipEntry* pEntry = mEntries[i];
9973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        pEntry->mCDE.write(mZipFp);
9983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
9993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
10003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    eocdPosn = ftell(mZipFp);
10013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset;
10023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
10033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEOCD.write(mZipFp);
10043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
10053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
10063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * If we had some stuff bloat up during compression and get replaced
10073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * with plain files, or if we deleted some entries, there's a lot
10083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * of wasted space at the end of the file.  Remove it now.
10093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
10103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) {
1011c0b74df335aa99e3c3f6f752de531836faa0c7c5Steve Block        ALOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno));
10123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        // not fatal
10133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
10143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
10153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /* should we clear the "newly added" flag in all entries now? */
10163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
10173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mNeedCDRewrite = false;
10183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return NO_ERROR;
10193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
10203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
10213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
10223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Crunch deleted files out of an archive by shifting the later files down.
10233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
10243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Because we're not using a temp file, we do the operation inside the
10253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * current file.
10263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
10273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::crunchArchive(void)
10283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
10293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    status_t result = NO_ERROR;
10303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    int i, count;
10313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    long delCount, adjust;
10323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
10333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#if 0
10343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    printf("CONTENTS:\n");
10353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    for (i = 0; i < (int) mEntries.size(); i++) {
10363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        printf(" %d: lfhOff=%ld del=%d\n",
10373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted());
10383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
10393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    printf("  END is %ld\n", (long) mEOCD.mCentralDirOffset);
10403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#endif
10413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
10423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
10433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * Roll through the set of files, shifting them as appropriate.  We
10443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * could probably get a slight performance improvement by sliding
10453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * multiple files down at once (because we could use larger reads
10463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * when operating on batches of small files), but it's not that useful.
10473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
10483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    count = mEntries.size();
10493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    delCount = adjust = 0;
10503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    for (i = 0; i < count; i++) {
10513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        ZipEntry* pEntry = mEntries[i];
10523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        long span;
10533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
10543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (pEntry->getLFHOffset() != 0) {
10553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            long nextOffset;
10563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
10573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            /* Get the length of this entry by finding the offset
10583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian             * of the next entry.  Directory entries don't have
10593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian             * file offsets, so we need to find the next non-directory
10603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian             * entry.
10613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian             */
10623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            nextOffset = 0;
10633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            for (int ii = i+1; nextOffset == 0 && ii < count; ii++)
10643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                nextOffset = mEntries[ii]->getLFHOffset();
10653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            if (nextOffset == 0)
10663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                nextOffset = mEOCD.mCentralDirOffset;
10673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            span = nextOffset - pEntry->getLFHOffset();
10683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
10693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            assert(span >= ZipEntry::LocalFileHeader::kLFHLen);
10703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        } else {
10713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            /* This is a directory entry.  It doesn't have
10723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian             * any actual file contents, so there's no need to
10733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian             * move anything.
10743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian             */
10753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            span = 0;
10763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
10773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
10783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n",
10793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        //    i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count);
10803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
10813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (pEntry->getDeleted()) {
10823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            adjust += span;
10833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            delCount++;
10843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
10853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            delete pEntry;
10863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            mEntries.removeAt(i);
10873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
10883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            /* adjust loop control */
10893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            count--;
10903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            i--;
10913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        } else if (span != 0 && adjust > 0) {
10923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            /* shuffle this entry back */
10933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            //printf("+++ Shuffling '%s' back %ld\n",
10943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            //    pEntry->getFileName(), adjust);
10953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            result = filemove(mZipFp, pEntry->getLFHOffset() - adjust,
10963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                        pEntry->getLFHOffset(), span);
10973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            if (result != NO_ERROR) {
10983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                /* this is why you use a temp file */
1099ca1df5a380069163bbabc7cfed1d48829b8e135eSteve Block                ALOGE("error during crunch - archive is toast\n");
11003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                return result;
11013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            }
11023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust);
11043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
11053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
11063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /*
11083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * Fix EOCD info.  We have to wait until the end to do some of this
11093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * because we use mCentralDirOffset to determine "span" for the
11103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     * last entry.
11113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian     */
11123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEOCD.mCentralDirOffset -= adjust;
11133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEOCD.mNumEntries -= delCount;
11143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEOCD.mTotalNumEntries -= delCount;
11153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mEOCD.mCentralDirSize = 0;  // mark invalid; set by flush()
11163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries);
11183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    assert(mEOCD.mNumEntries == count);
11193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return result;
11213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
11223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
11243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Works like memmove(), but on pieces of a file.
11253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
11263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n)
11273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
11283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (dst == src || n <= 0)
11293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return NO_ERROR;
11303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    unsigned char readBuf[32768];
11323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (dst < src) {
11343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        /* shift stuff toward start of file; must read from start */
11353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        while (n != 0) {
11363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            size_t getSize = sizeof(readBuf);
11373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            if (getSize > n)
11383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                getSize = n;
11393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            if (fseek(fp, (long) src, SEEK_SET) != 0) {
114115fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block                ALOGD("filemove src seek %ld failed\n", (long) src);
11423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                return UNKNOWN_ERROR;
11433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            }
11443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            if (fread(readBuf, 1, getSize, fp) != getSize) {
114615fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block                ALOGD("filemove read %ld off=%ld failed\n",
11473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                    (long) getSize, (long) src);
11483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                return UNKNOWN_ERROR;
11493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            }
11503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            if (fseek(fp, (long) dst, SEEK_SET) != 0) {
115215fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block                ALOGD("filemove dst seek %ld failed\n", (long) dst);
11533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                return UNKNOWN_ERROR;
11543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            }
11553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            if (fwrite(readBuf, 1, getSize, fp) != getSize) {
115715fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block                ALOGD("filemove write %ld off=%ld failed\n",
11583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                    (long) getSize, (long) dst);
11593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                return UNKNOWN_ERROR;
11603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            }
11613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            src += getSize;
11633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            dst += getSize;
11643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            n -= getSize;
11653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
11663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    } else {
11673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        /* shift stuff toward end of file; must read from end */
11683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        assert(false);      // write this someday, maybe
11693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return UNKNOWN_ERROR;
11703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
11713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return NO_ERROR;
11733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
11743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
11773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Get the modification time from a file descriptor.
11783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
11793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopiantime_t ZipFile::getModTime(int fd)
11803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
11813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    struct stat sb;
11823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (fstat(fd, &sb) < 0) {
118415fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block        ALOGD("HEY: fstat on fd %d failed\n", fd);
11853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return (time_t) -1;
11863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
11873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return sb.st_mtime;
11893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
11903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
11923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#if 0       /* this is a bad idea */
11933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
11943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Get a copy of the Zip file descriptor.
11953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
11963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * We don't allow this if the file was opened read-write because we tend
11973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * to leave the file contents in an uncertain state between calls to
11983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * flush().  The duplicated file descriptor should only be valid for reads.
11993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
12003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianint ZipFile::getZipFd(void) const
12013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
12023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (!mReadOnly)
12033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return INVALID_OPERATION;
12043344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    assert(mZipFp != NULL);
12053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
12063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    int fd;
12073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    fd = dup(fileno(mZipFp));
12083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (fd < 0) {
120915fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block        ALOGD("didn't work, errno=%d\n", errno);
12103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
12113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
12123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return fd;
12133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
12143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#endif
12153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
12163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
12173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#if 0
12183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
12193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Expand data.
12203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
12213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianbool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const
12223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
12233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return false;
12243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
12253344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#endif
12263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
12273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian// free the memory when you're done
1228093d04c631aa2a4af3317912e9561672c5642bb8Raph Levienvoid* ZipFile::uncompress(const ZipEntry* entry) const
12293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
12303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    size_t unlen = entry->getUncompressedLen();
12313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    size_t clen = entry->getCompressedLen();
12323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
12333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    void* buf = malloc(unlen);
12343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (buf == NULL) {
12353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return NULL;
12363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
12373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
12383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    fseek(mZipFp, 0, SEEK_SET);
12393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
12403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    off_t offset = entry->getFileOffset();
12413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (fseek(mZipFp, offset, SEEK_SET) != 0) {
12423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        goto bail;
12433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
12443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
12453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    switch (entry->getCompressionMethod())
12463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    {
12473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        case ZipEntry::kCompressStored: {
12483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            ssize_t amt = fread(buf, 1, unlen, mZipFp);
12493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            if (amt != (ssize_t)unlen) {
12503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                goto bail;
12513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            }
12523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#if 0
12533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            printf("data...\n");
12543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            const unsigned char* p = (unsigned char*)buf;
12553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            const unsigned char* end = p+unlen;
12563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            for (int i=0; i<32 && p < end; i++) {
12573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                printf("0x%08x ", (int)(offset+(i*0x10)));
12583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                for (int j=0; j<0x10 && p < end; j++) {
12593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                    printf(" %02x", *p);
12603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                    p++;
12613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                }
12623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                printf("\n");
12633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            }
12643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian#endif
12653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
12663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            }
12673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            break;
12683344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        case ZipEntry::kCompressDeflated: {
12693344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) {
12703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                goto bail;
12713344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            }
12723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            }
12733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            break;
12743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        default:
12753344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            goto bail;
12763344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
12773344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return buf;
12783344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
12793344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianbail:
12803344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    free(buf);
12813344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return NULL;
12823344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
12833344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
12843344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
12853344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
12863344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * ===========================================================================
12873344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *      ZipFile::EndOfCentralDir
12883344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * ===========================================================================
12893344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
12903344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
12913344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
12923344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Read the end-of-central-dir fields.
12933344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian *
12943344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * "buf" should be positioned at the EOCD signature, and should contain
12953344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * the entire EOCD area including the comment.
12963344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
12973344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len)
12983344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
12993344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /* don't allow re-use */
13003344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    assert(mComment == NULL);
13013344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
13023344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (len < kEOCDLen) {
13033344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        /* looks like ZIP file got truncated */
130415fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block        ALOGD(" Zip EOCD: expected >= %d bytes, found %d\n",
13053344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            kEOCDLen, len);
13063344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return INVALID_OPERATION;
13073344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
13083344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
13093344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    /* this should probably be an assert() */
13103344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (ZipEntry::getLongLE(&buf[0x00]) != kSignature)
13113344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return UNKNOWN_ERROR;
13123344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
13133344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mDiskNumber = ZipEntry::getShortLE(&buf[0x04]);
13143344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]);
13153344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mNumEntries = ZipEntry::getShortLE(&buf[0x08]);
13163344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]);
13173344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]);
13183344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]);
13193344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    mCommentLen = ZipEntry::getShortLE(&buf[0x14]);
13203344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
13213344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    // TODO: validate mCentralDirOffset
13223344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
13233344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (mCommentLen > 0) {
13243344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (kEOCDLen + mCommentLen > len) {
132515fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block            ALOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n",
13263344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian                kEOCDLen, mCommentLen, len);
13273344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            return UNKNOWN_ERROR;
13283344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        }
13293344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        mComment = new unsigned char[mCommentLen];
13303344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        memcpy(mComment, buf + kEOCDLen, mCommentLen);
13313344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
13323344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
13333344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return NO_ERROR;
13343344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
13353344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
13363344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
13373344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Write an end-of-central-directory section.
13383344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
13393344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianstatus_t ZipFile::EndOfCentralDir::write(FILE* fp)
13403344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
13413344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    unsigned char buf[kEOCDLen];
13423344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
13433344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    ZipEntry::putLongLE(&buf[0x00], kSignature);
13443344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    ZipEntry::putShortLE(&buf[0x04], mDiskNumber);
13453344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir);
13463344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    ZipEntry::putShortLE(&buf[0x08], mNumEntries);
13473344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries);
13483344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize);
13493344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset);
13503344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    ZipEntry::putShortLE(&buf[0x14], mCommentLen);
13513344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
13523344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen)
13533344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        return UNKNOWN_ERROR;
13543344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    if (mCommentLen > 0) {
13553344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        assert(mComment != NULL);
13563344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen)
13573344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian            return UNKNOWN_ERROR;
13583344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    }
13593344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
13603344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian    return NO_ERROR;
13613344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
13623344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
13633344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian/*
13643344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian * Dump the contents of an EndOfCentralDir object.
13653344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian */
13663344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopianvoid ZipFile::EndOfCentralDir::dump(void) const
13673344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian{
136815fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block    ALOGD(" EndOfCentralDir contents:\n");
136915fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block    ALOGD("  diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n",
13703344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries);
137115fab1aa8c1ac4d92222dba349c473a8edd7ce99Steve Block    ALOGD("  centDirSize=%lu centDirOff=%lu commentLen=%u\n",
13723344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian        mCentralDirSize, mCentralDirOffset, mCommentLen);
13733344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian}
13743344b2e9b27466111524dfcfb64d7258153e0cb7Mathias Agopian
1375