/* * 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; }