コード例 #1
0
/*
 * Add an entry by copying it from another zip file.  If "padding" is
 * nonzero, the specified number of bytes will be added to the "extra"
 * field in the header.
 *
 * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
 */
status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
    int padding, ZipEntry** ppEntry)
{
    ZipEntry* pEntry = NULL;
    status_t result;
    long lfhPosn, endPosn;

    if (mReadOnly)
        return INVALID_OPERATION;

    /* make sure we're in a reasonable state */
    assert(mZipFp != NULL);
    assert(mEntries.size() == mEOCD.mTotalNumEntries);

    if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
        result = UNKNOWN_ERROR;
        goto bail;
    }

    pEntry = new ZipEntry;
    if (pEntry == NULL) {
        result = NO_MEMORY;
        goto bail;
    }

    result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
    if (result != NO_ERROR)
        goto bail;
    if (padding != 0) {
        result = pEntry->addPadding(padding);
        if (result != NO_ERROR)
            goto bail;
    }

    /*
     * From here on out, failures are more interesting.
     */
    mNeedCDRewrite = true;

    /*
     * Write the LFH.  Since we're not recompressing the data, we already
     * have all of the fields filled out.
     */
    lfhPosn = ftell(mZipFp);
    pEntry->mLFH.write(mZipFp);

    /*
     * Copy the data over.
     *
     * If the "has data descriptor" flag is set, we want to copy the DD
     * fields as well.  This is a fixed-size area immediately following
     * the data.
     */
    if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
    {
        result = UNKNOWN_ERROR;
        goto bail;
    }

    off_t copyLen;
    copyLen = pSourceEntry->getCompressedLen();
    if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
        copyLen += ZipEntry::kDataDescriptorLen;

    if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
        != NO_ERROR)
    {
        LOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
        result = UNKNOWN_ERROR;
        goto bail;
    }

    /*
     * Update file offsets.
     */
    endPosn = ftell(mZipFp);

    /*
     * Success!  Fill out new values.
     */
    pEntry->setLFHOffset(lfhPosn);      // sets mCDE.mLocalHeaderRelOffset
    mEOCD.mNumEntries++;
    mEOCD.mTotalNumEntries++;
    mEOCD.mCentralDirSize = 0;      // mark invalid; set by flush()
    mEOCD.mCentralDirOffset = endPosn;

    /*
     * Add pEntry to the list.
     */
    mEntries.add(pEntry);
    if (ppEntry != NULL)
        *ppEntry = pEntry;
    pEntry = NULL;

    result = NO_ERROR;

bail:
    delete pEntry;
    return result;
}