/* * 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; }
/* * Add an entry by copying it from another zip file, recompressing with * Zopfli if already compressed. * * If "ppEntry" is non-NULL, a pointer to the new entry will be returned. */ status_t ZipFile::addRecompress(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry, ZipEntry** ppEntry) { ZipEntry* pEntry = NULL; status_t result; long lfhPosn, startPosn, endPosn, uncompressedLen; 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(pSourceEntry); if (result != NO_ERROR) goto bail; /* * From here on out, failures are more interesting. */ mNeedCDRewrite = true; /* * Write the LFH, even though it's still mostly blank. We need it * as a place-holder. In theory the LFH isn't necessary, but in * practice some utilities demand it. */ lfhPosn = ftell(mZipFp); pEntry->mLFH.write(mZipFp); startPosn = ftell(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; } uncompressedLen = pSourceEntry->getUncompressedLen(); if (pSourceEntry->isCompressed()) { void *buf = pSourceZip->uncompress(pSourceEntry); if (buf == NULL) { result = NO_MEMORY; goto bail; } long startPosn = ftell(mZipFp); uint32_t crc; if (compressFpToFp(mZipFp, NULL, buf, uncompressedLen, &crc) != NO_ERROR) { ALOGW("recompress of '%s' failed\n", pEntry->mCDE.mFileName); result = UNKNOWN_ERROR; free(buf); goto bail; } long endPosn = ftell(mZipFp); pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, pSourceEntry->getCRC32(), ZipEntry::kCompressDeflated); free(buf); } else { 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) { ALOGW("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); mEOCD.mNumEntries++; mEOCD.mTotalNumEntries++; mEOCD.mCentralDirSize = 0; // mark invalid; set by flush() mEOCD.mCentralDirOffset = endPosn; /* * Go back and write the LFH. */ if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) { result = UNKNOWN_ERROR; goto bail; } pEntry->mLFH.write(mZipFp); /* * Add pEntry to the list. */ mEntries.add(pEntry); if (ppEntry != NULL) *ppEntry = pEntry; pEntry = NULL; result = NO_ERROR; bail: delete pEntry; return result; }