break dependency on utils/ZipEntry.h and utils/ZipFile.h

This commit is contained in:
Mathias Agopian
2009-06-05 14:55:48 -07:00
parent 81d04d57f2
commit 3344b2e9b2
6 changed files with 2612 additions and 2 deletions

View File

@@ -8,7 +8,9 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
ZipAlign.cpp
ZipAlign.cpp \
ZipEntry.cpp \
ZipFile.cpp
LOCAL_C_INCLUDES += external/zlib

View File

@@ -16,7 +16,7 @@
/*
* Zip alignment tool
*/
#include "utils/ZipFile.h"
#include "ZipFile.h"
#include <stdlib.h>
#include <stdio.h>

696
tools/zipalign/ZipEntry.cpp Normal file
View File

@@ -0,0 +1,696 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Access to entries in a Zip archive.
//
#define LOG_TAG "zip"
#include "ZipEntry.h"
#include <utils/Log.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
using namespace android;
/*
* Initialize a new ZipEntry structure from a FILE* positioned at a
* CentralDirectoryEntry.
*
* On exit, the file pointer will be at the start of the next CDE or
* at the EOCD.
*/
status_t ZipEntry::initFromCDE(FILE* fp)
{
status_t result;
long posn;
bool hasDD;
//LOGV("initFromCDE ---\n");
/* read the CDE */
result = mCDE.read(fp);
if (result != NO_ERROR) {
LOGD("mCDE.read failed\n");
return result;
}
//mCDE.dump();
/* using the info in the CDE, go load up the LFH */
posn = ftell(fp);
if (fseek(fp, mCDE.mLocalHeaderRelOffset, SEEK_SET) != 0) {
LOGD("local header seek failed (%ld)\n",
mCDE.mLocalHeaderRelOffset);
return UNKNOWN_ERROR;
}
result = mLFH.read(fp);
if (result != NO_ERROR) {
LOGD("mLFH.read failed\n");
return result;
}
if (fseek(fp, posn, SEEK_SET) != 0)
return UNKNOWN_ERROR;
//mLFH.dump();
/*
* We *might* need to read the Data Descriptor at this point and
* integrate it into the LFH. If this bit is set, the CRC-32,
* compressed size, and uncompressed size will be zero. In practice
* these seem to be rare.
*/
hasDD = (mLFH.mGPBitFlag & kUsesDataDescr) != 0;
if (hasDD) {
// do something clever
//LOGD("+++ has data descriptor\n");
}
/*
* Sanity-check the LFH. Note that this will fail if the "kUsesDataDescr"
* flag is set, because the LFH is incomplete. (Not a problem, since we
* prefer the CDE values.)
*/
if (!hasDD && !compareHeaders()) {
LOGW("WARNING: header mismatch\n");
// keep going?
}
/*
* If the mVersionToExtract is greater than 20, we may have an
* issue unpacking the record -- could be encrypted, compressed
* with something we don't support, or use Zip64 extensions. We
* can defer worrying about that to when we're extracting data.
*/
return NO_ERROR;
}
/*
* Initialize a new entry. Pass in the file name and an optional comment.
*
* Initializes the CDE and the LFH.
*/
void ZipEntry::initNew(const char* fileName, const char* comment)
{
assert(fileName != NULL && *fileName != '\0'); // name required
/* most fields are properly initialized by constructor */
mCDE.mVersionMadeBy = kDefaultMadeBy;
mCDE.mVersionToExtract = kDefaultVersion;
mCDE.mCompressionMethod = kCompressStored;
mCDE.mFileNameLength = strlen(fileName);
if (comment != NULL)
mCDE.mFileCommentLength = strlen(comment);
mCDE.mExternalAttrs = 0x81b60020; // matches what WinZip does
if (mCDE.mFileNameLength > 0) {
mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
strcpy((char*) mCDE.mFileName, fileName);
}
if (mCDE.mFileCommentLength > 0) {
/* TODO: stop assuming null-terminated ASCII here? */
mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
strcpy((char*) mCDE.mFileComment, comment);
}
copyCDEtoLFH();
}
/*
* Initialize a new entry, starting with the ZipEntry from a different
* archive.
*
* Initializes the CDE and the LFH.
*/
status_t ZipEntry::initFromExternal(const ZipFile* pZipFile,
const ZipEntry* pEntry)
{
/*
* Copy everything in the CDE over, then fix up the hairy bits.
*/
memcpy(&mCDE, &pEntry->mCDE, sizeof(mCDE));
if (mCDE.mFileNameLength > 0) {
mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
if (mCDE.mFileName == NULL)
return NO_MEMORY;
strcpy((char*) mCDE.mFileName, (char*)pEntry->mCDE.mFileName);
}
if (mCDE.mFileCommentLength > 0) {
mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
if (mCDE.mFileComment == NULL)
return NO_MEMORY;
strcpy((char*) mCDE.mFileComment, (char*)pEntry->mCDE.mFileComment);
}
if (mCDE.mExtraFieldLength > 0) {
/* we null-terminate this, though it may not be a string */
mCDE.mExtraField = new unsigned char[mCDE.mExtraFieldLength+1];
if (mCDE.mExtraField == NULL)
return NO_MEMORY;
memcpy(mCDE.mExtraField, pEntry->mCDE.mExtraField,
mCDE.mExtraFieldLength+1);
}
/* construct the LFH from the CDE */
copyCDEtoLFH();
/*
* The LFH "extra" field is independent of the CDE "extra", so we
* handle it here.
*/
assert(mLFH.mExtraField == NULL);
mLFH.mExtraFieldLength = pEntry->mLFH.mExtraFieldLength;
if (mLFH.mExtraFieldLength > 0) {
mLFH.mExtraField = new unsigned char[mLFH.mExtraFieldLength+1];
if (mLFH.mExtraField == NULL)
return NO_MEMORY;
memcpy(mLFH.mExtraField, pEntry->mLFH.mExtraField,
mLFH.mExtraFieldLength+1);
}
return NO_ERROR;
}
/*
* Insert pad bytes in the LFH by tweaking the "extra" field. This will
* potentially confuse something that put "extra" data in here earlier,
* but I can't find an actual problem.
*/
status_t ZipEntry::addPadding(int padding)
{
if (padding <= 0)
return INVALID_OPERATION;
//LOGI("HEY: adding %d pad bytes to existing %d in %s\n",
// padding, mLFH.mExtraFieldLength, mCDE.mFileName);
if (mLFH.mExtraFieldLength > 0) {
/* extend existing field */
unsigned char* newExtra;
newExtra = new unsigned char[mLFH.mExtraFieldLength + padding];
if (newExtra == NULL)
return NO_MEMORY;
memset(newExtra + mLFH.mExtraFieldLength, 0, padding);
memcpy(newExtra, mLFH.mExtraField, mLFH.mExtraFieldLength);
delete[] mLFH.mExtraField;
mLFH.mExtraField = newExtra;
mLFH.mExtraFieldLength += padding;
} else {
/* create new field */
mLFH.mExtraField = new unsigned char[padding];
memset(mLFH.mExtraField, 0, padding);
mLFH.mExtraFieldLength = padding;
}
return NO_ERROR;
}
/*
* Set the fields in the LFH equal to the corresponding fields in the CDE.
*
* This does not touch the LFH "extra" field.
*/
void ZipEntry::copyCDEtoLFH(void)
{
mLFH.mVersionToExtract = mCDE.mVersionToExtract;
mLFH.mGPBitFlag = mCDE.mGPBitFlag;
mLFH.mCompressionMethod = mCDE.mCompressionMethod;
mLFH.mLastModFileTime = mCDE.mLastModFileTime;
mLFH.mLastModFileDate = mCDE.mLastModFileDate;
mLFH.mCRC32 = mCDE.mCRC32;
mLFH.mCompressedSize = mCDE.mCompressedSize;
mLFH.mUncompressedSize = mCDE.mUncompressedSize;
mLFH.mFileNameLength = mCDE.mFileNameLength;
// the "extra field" is independent
delete[] mLFH.mFileName;
if (mLFH.mFileNameLength > 0) {
mLFH.mFileName = new unsigned char[mLFH.mFileNameLength+1];
strcpy((char*) mLFH.mFileName, (const char*) mCDE.mFileName);
} else {
mLFH.mFileName = NULL;
}
}
/*
* Set some information about a file after we add it.
*/
void ZipEntry::setDataInfo(long uncompLen, long compLen, unsigned long crc32,
int compressionMethod)
{
mCDE.mCompressionMethod = compressionMethod;
mCDE.mCRC32 = crc32;
mCDE.mCompressedSize = compLen;
mCDE.mUncompressedSize = uncompLen;
mCDE.mCompressionMethod = compressionMethod;
if (compressionMethod == kCompressDeflated) {
mCDE.mGPBitFlag |= 0x0002; // indicates maximum compression used
}
copyCDEtoLFH();
}
/*
* See if the data in mCDE and mLFH match up. This is mostly useful for
* debugging these classes, but it can be used to identify damaged
* archives.
*
* Returns "false" if they differ.
*/
bool ZipEntry::compareHeaders(void) const
{
if (mCDE.mVersionToExtract != mLFH.mVersionToExtract) {
LOGV("cmp: VersionToExtract\n");
return false;
}
if (mCDE.mGPBitFlag != mLFH.mGPBitFlag) {
LOGV("cmp: GPBitFlag\n");
return false;
}
if (mCDE.mCompressionMethod != mLFH.mCompressionMethod) {
LOGV("cmp: CompressionMethod\n");
return false;
}
if (mCDE.mLastModFileTime != mLFH.mLastModFileTime) {
LOGV("cmp: LastModFileTime\n");
return false;
}
if (mCDE.mLastModFileDate != mLFH.mLastModFileDate) {
LOGV("cmp: LastModFileDate\n");
return false;
}
if (mCDE.mCRC32 != mLFH.mCRC32) {
LOGV("cmp: CRC32\n");
return false;
}
if (mCDE.mCompressedSize != mLFH.mCompressedSize) {
LOGV("cmp: CompressedSize\n");
return false;
}
if (mCDE.mUncompressedSize != mLFH.mUncompressedSize) {
LOGV("cmp: UncompressedSize\n");
return false;
}
if (mCDE.mFileNameLength != mLFH.mFileNameLength) {
LOGV("cmp: FileNameLength\n");
return false;
}
#if 0 // this seems to be used for padding, not real data
if (mCDE.mExtraFieldLength != mLFH.mExtraFieldLength) {
LOGV("cmp: ExtraFieldLength\n");
return false;
}
#endif
if (mCDE.mFileName != NULL) {
if (strcmp((char*) mCDE.mFileName, (char*) mLFH.mFileName) != 0) {
LOGV("cmp: FileName\n");
return false;
}
}
return true;
}
/*
* Convert the DOS date/time stamp into a UNIX time stamp.
*/
time_t ZipEntry::getModWhen(void) const
{
struct tm parts;
parts.tm_sec = (mCDE.mLastModFileTime & 0x001f) << 1;
parts.tm_min = (mCDE.mLastModFileTime & 0x07e0) >> 5;
parts.tm_hour = (mCDE.mLastModFileTime & 0xf800) >> 11;
parts.tm_mday = (mCDE.mLastModFileDate & 0x001f);
parts.tm_mon = ((mCDE.mLastModFileDate & 0x01e0) >> 5) -1;
parts.tm_year = ((mCDE.mLastModFileDate & 0xfe00) >> 9) + 80;
parts.tm_wday = parts.tm_yday = 0;
parts.tm_isdst = -1; // DST info "not available"
return mktime(&parts);
}
/*
* Set the CDE/LFH timestamp from UNIX time.
*/
void ZipEntry::setModWhen(time_t when)
{
#ifdef HAVE_LOCALTIME_R
struct tm tmResult;
#endif
time_t even;
unsigned short zdate, ztime;
struct tm* ptm;
/* round up to an even number of seconds */
even = (time_t)(((unsigned long)(when) + 1) & (~1));
/* expand */
#ifdef HAVE_LOCALTIME_R
ptm = localtime_r(&even, &tmResult);
#else
ptm = localtime(&even);
#endif
int year;
year = ptm->tm_year;
if (year < 80)
year = 80;
zdate = (year - 80) << 9 | (ptm->tm_mon+1) << 5 | ptm->tm_mday;
ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime;
mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate;
}
/*
* ===========================================================================
* ZipEntry::LocalFileHeader
* ===========================================================================
*/
/*
* Read a local file header.
*
* On entry, "fp" points to the signature at the start of the header.
* On exit, "fp" points to the start of data.
*/
status_t ZipEntry::LocalFileHeader::read(FILE* fp)
{
status_t result = NO_ERROR;
unsigned char buf[kLFHLen];
assert(mFileName == NULL);
assert(mExtraField == NULL);
if (fread(buf, 1, kLFHLen, fp) != kLFHLen) {
result = UNKNOWN_ERROR;
goto bail;
}
if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
LOGD("whoops: didn't find expected signature\n");
result = UNKNOWN_ERROR;
goto bail;
}
mVersionToExtract = ZipEntry::getShortLE(&buf[0x04]);
mGPBitFlag = ZipEntry::getShortLE(&buf[0x06]);
mCompressionMethod = ZipEntry::getShortLE(&buf[0x08]);
mLastModFileTime = ZipEntry::getShortLE(&buf[0x0a]);
mLastModFileDate = ZipEntry::getShortLE(&buf[0x0c]);
mCRC32 = ZipEntry::getLongLE(&buf[0x0e]);
mCompressedSize = ZipEntry::getLongLE(&buf[0x12]);
mUncompressedSize = ZipEntry::getLongLE(&buf[0x16]);
mFileNameLength = ZipEntry::getShortLE(&buf[0x1a]);
mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1c]);
// TODO: validate sizes
/* grab filename */
if (mFileNameLength != 0) {
mFileName = new unsigned char[mFileNameLength+1];
if (mFileName == NULL) {
result = NO_MEMORY;
goto bail;
}
if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
result = UNKNOWN_ERROR;
goto bail;
}
mFileName[mFileNameLength] = '\0';
}
/* grab extra field */
if (mExtraFieldLength != 0) {
mExtraField = new unsigned char[mExtraFieldLength+1];
if (mExtraField == NULL) {
result = NO_MEMORY;
goto bail;
}
if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
result = UNKNOWN_ERROR;
goto bail;
}
mExtraField[mExtraFieldLength] = '\0';
}
bail:
return result;
}
/*
* Write a local file header.
*/
status_t ZipEntry::LocalFileHeader::write(FILE* fp)
{
unsigned char buf[kLFHLen];
ZipEntry::putLongLE(&buf[0x00], kSignature);
ZipEntry::putShortLE(&buf[0x04], mVersionToExtract);
ZipEntry::putShortLE(&buf[0x06], mGPBitFlag);
ZipEntry::putShortLE(&buf[0x08], mCompressionMethod);
ZipEntry::putShortLE(&buf[0x0a], mLastModFileTime);
ZipEntry::putShortLE(&buf[0x0c], mLastModFileDate);
ZipEntry::putLongLE(&buf[0x0e], mCRC32);
ZipEntry::putLongLE(&buf[0x12], mCompressedSize);
ZipEntry::putLongLE(&buf[0x16], mUncompressedSize);
ZipEntry::putShortLE(&buf[0x1a], mFileNameLength);
ZipEntry::putShortLE(&buf[0x1c], mExtraFieldLength);
if (fwrite(buf, 1, kLFHLen, fp) != kLFHLen)
return UNKNOWN_ERROR;
/* write filename */
if (mFileNameLength != 0) {
if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
return UNKNOWN_ERROR;
}
/* write "extra field" */
if (mExtraFieldLength != 0) {
if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
return UNKNOWN_ERROR;
}
return NO_ERROR;
}
/*
* Dump the contents of a LocalFileHeader object.
*/
void ZipEntry::LocalFileHeader::dump(void) const
{
LOGD(" LocalFileHeader contents:\n");
LOGD(" versToExt=%u gpBits=0x%04x compression=%u\n",
mVersionToExtract, mGPBitFlag, mCompressionMethod);
LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
mLastModFileTime, mLastModFileDate, mCRC32);
LOGD(" compressedSize=%lu uncompressedSize=%lu\n",
mCompressedSize, mUncompressedSize);
LOGD(" filenameLen=%u extraLen=%u\n",
mFileNameLength, mExtraFieldLength);
if (mFileName != NULL)
LOGD(" filename: '%s'\n", mFileName);
}
/*
* ===========================================================================
* ZipEntry::CentralDirEntry
* ===========================================================================
*/
/*
* Read the central dir entry that appears next in the file.
*
* On entry, "fp" should be positioned on the signature bytes for the
* entry. On exit, "fp" will point at the signature word for the next
* entry or for the EOCD.
*/
status_t ZipEntry::CentralDirEntry::read(FILE* fp)
{
status_t result = NO_ERROR;
unsigned char buf[kCDELen];
/* no re-use */
assert(mFileName == NULL);
assert(mExtraField == NULL);
assert(mFileComment == NULL);
if (fread(buf, 1, kCDELen, fp) != kCDELen) {
result = UNKNOWN_ERROR;
goto bail;
}
if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
LOGD("Whoops: didn't find expected signature\n");
result = UNKNOWN_ERROR;
goto bail;
}
mVersionMadeBy = ZipEntry::getShortLE(&buf[0x04]);
mVersionToExtract = ZipEntry::getShortLE(&buf[0x06]);
mGPBitFlag = ZipEntry::getShortLE(&buf[0x08]);
mCompressionMethod = ZipEntry::getShortLE(&buf[0x0a]);
mLastModFileTime = ZipEntry::getShortLE(&buf[0x0c]);
mLastModFileDate = ZipEntry::getShortLE(&buf[0x0e]);
mCRC32 = ZipEntry::getLongLE(&buf[0x10]);
mCompressedSize = ZipEntry::getLongLE(&buf[0x14]);
mUncompressedSize = ZipEntry::getLongLE(&buf[0x18]);
mFileNameLength = ZipEntry::getShortLE(&buf[0x1c]);
mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1e]);
mFileCommentLength = ZipEntry::getShortLE(&buf[0x20]);
mDiskNumberStart = ZipEntry::getShortLE(&buf[0x22]);
mInternalAttrs = ZipEntry::getShortLE(&buf[0x24]);
mExternalAttrs = ZipEntry::getLongLE(&buf[0x26]);
mLocalHeaderRelOffset = ZipEntry::getLongLE(&buf[0x2a]);
// TODO: validate sizes and offsets
/* grab filename */
if (mFileNameLength != 0) {
mFileName = new unsigned char[mFileNameLength+1];
if (mFileName == NULL) {
result = NO_MEMORY;
goto bail;
}
if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
result = UNKNOWN_ERROR;
goto bail;
}
mFileName[mFileNameLength] = '\0';
}
/* read "extra field" */
if (mExtraFieldLength != 0) {
mExtraField = new unsigned char[mExtraFieldLength+1];
if (mExtraField == NULL) {
result = NO_MEMORY;
goto bail;
}
if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
result = UNKNOWN_ERROR;
goto bail;
}
mExtraField[mExtraFieldLength] = '\0';
}
/* grab comment, if any */
if (mFileCommentLength != 0) {
mFileComment = new unsigned char[mFileCommentLength+1];
if (mFileComment == NULL) {
result = NO_MEMORY;
goto bail;
}
if (fread(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
{
result = UNKNOWN_ERROR;
goto bail;
}
mFileComment[mFileCommentLength] = '\0';
}
bail:
return result;
}
/*
* Write a central dir entry.
*/
status_t ZipEntry::CentralDirEntry::write(FILE* fp)
{
unsigned char buf[kCDELen];
ZipEntry::putLongLE(&buf[0x00], kSignature);
ZipEntry::putShortLE(&buf[0x04], mVersionMadeBy);
ZipEntry::putShortLE(&buf[0x06], mVersionToExtract);
ZipEntry::putShortLE(&buf[0x08], mGPBitFlag);
ZipEntry::putShortLE(&buf[0x0a], mCompressionMethod);
ZipEntry::putShortLE(&buf[0x0c], mLastModFileTime);
ZipEntry::putShortLE(&buf[0x0e], mLastModFileDate);
ZipEntry::putLongLE(&buf[0x10], mCRC32);
ZipEntry::putLongLE(&buf[0x14], mCompressedSize);
ZipEntry::putLongLE(&buf[0x18], mUncompressedSize);
ZipEntry::putShortLE(&buf[0x1c], mFileNameLength);
ZipEntry::putShortLE(&buf[0x1e], mExtraFieldLength);
ZipEntry::putShortLE(&buf[0x20], mFileCommentLength);
ZipEntry::putShortLE(&buf[0x22], mDiskNumberStart);
ZipEntry::putShortLE(&buf[0x24], mInternalAttrs);
ZipEntry::putLongLE(&buf[0x26], mExternalAttrs);
ZipEntry::putLongLE(&buf[0x2a], mLocalHeaderRelOffset);
if (fwrite(buf, 1, kCDELen, fp) != kCDELen)
return UNKNOWN_ERROR;
/* write filename */
if (mFileNameLength != 0) {
if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
return UNKNOWN_ERROR;
}
/* write "extra field" */
if (mExtraFieldLength != 0) {
if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
return UNKNOWN_ERROR;
}
/* write comment */
if (mFileCommentLength != 0) {
if (fwrite(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
return UNKNOWN_ERROR;
}
return NO_ERROR;
}
/*
* Dump the contents of a CentralDirEntry object.
*/
void ZipEntry::CentralDirEntry::dump(void) const
{
LOGD(" CentralDirEntry contents:\n");
LOGD(" versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n",
mVersionMadeBy, mVersionToExtract, mGPBitFlag, mCompressionMethod);
LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
mLastModFileTime, mLastModFileDate, mCRC32);
LOGD(" compressedSize=%lu uncompressedSize=%lu\n",
mCompressedSize, mUncompressedSize);
LOGD(" filenameLen=%u extraLen=%u commentLen=%u\n",
mFileNameLength, mExtraFieldLength, mFileCommentLength);
LOGD(" diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n",
mDiskNumberStart, mInternalAttrs, mExternalAttrs,
mLocalHeaderRelOffset);
if (mFileName != NULL)
LOGD(" filename: '%s'\n", mFileName);
if (mFileComment != NULL)
LOGD(" comment: '%s'\n", mFileComment);
}

345
tools/zipalign/ZipEntry.h Normal file
View File

@@ -0,0 +1,345 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Zip archive entries.
//
// The ZipEntry class is tightly meshed with the ZipFile class.
//
#ifndef __LIBS_ZIPENTRY_H
#define __LIBS_ZIPENTRY_H
#include <utils/Errors.h>
#include <stdlib.h>
#include <stdio.h>
namespace android {
class ZipFile;
/*
* ZipEntry objects represent a single entry in a Zip archive.
*
* You can use one of these to get or set information about an entry, but
* there are no functions here for accessing the data itself. (We could
* tuck a pointer to the ZipFile in here for convenience, but that raises
* the likelihood of using ZipEntry objects after discarding the ZipFile.)
*
* File information is stored in two places: next to the file data (the Local
* File Header, and possibly a Data Descriptor), and at the end of the file
* (the Central Directory Entry). The two must be kept in sync.
*/
class ZipEntry {
public:
friend class ZipFile;
ZipEntry(void)
: mDeleted(false), mMarked(false)
{}
~ZipEntry(void) {}
/*
* Returns "true" if the data is compressed.
*/
bool isCompressed(void) const {
return mCDE.mCompressionMethod != kCompressStored;
}
int getCompressionMethod(void) const { return mCDE.mCompressionMethod; }
/*
* Return the uncompressed length.
*/
off_t getUncompressedLen(void) const { return mCDE.mUncompressedSize; }
/*
* Return the compressed length. For uncompressed data, this returns
* the same thing as getUncompresesdLen().
*/
off_t getCompressedLen(void) const { return mCDE.mCompressedSize; }
/*
* Return the absolute file offset of the start of the compressed or
* uncompressed data.
*/
off_t getFileOffset(void) const {
return mCDE.mLocalHeaderRelOffset +
LocalFileHeader::kLFHLen +
mLFH.mFileNameLength +
mLFH.mExtraFieldLength;
}
/*
* Return the data CRC.
*/
unsigned long getCRC32(void) const { return mCDE.mCRC32; }
/*
* Return file modification time in UNIX seconds-since-epoch.
*/
time_t getModWhen(void) const;
/*
* Return the archived file name.
*/
const char* getFileName(void) const { return (const char*) mCDE.mFileName; }
/*
* Application-defined "mark". Can be useful when synchronizing the
* contents of an archive with contents on disk.
*/
bool getMarked(void) const { return mMarked; }
void setMarked(bool val) { mMarked = val; }
/*
* Some basic functions for raw data manipulation. "LE" means
* Little Endian.
*/
static inline unsigned short getShortLE(const unsigned char* buf) {
return buf[0] | (buf[1] << 8);
}
static inline unsigned long getLongLE(const unsigned char* buf) {
return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
}
static inline void putShortLE(unsigned char* buf, short val) {
buf[0] = (unsigned char) val;
buf[1] = (unsigned char) (val >> 8);
}
static inline void putLongLE(unsigned char* buf, long val) {
buf[0] = (unsigned char) val;
buf[1] = (unsigned char) (val >> 8);
buf[2] = (unsigned char) (val >> 16);
buf[3] = (unsigned char) (val >> 24);
}
/* defined for Zip archives */
enum {
kCompressStored = 0, // no compression
// shrunk = 1,
// reduced 1 = 2,
// reduced 2 = 3,
// reduced 3 = 4,
// reduced 4 = 5,
// imploded = 6,
// tokenized = 7,
kCompressDeflated = 8, // standard deflate
// Deflate64 = 9,
// lib imploded = 10,
// reserved = 11,
// bzip2 = 12,
};
/*
* Deletion flag. If set, the entry will be removed on the next
* call to "flush".
*/
bool getDeleted(void) const { return mDeleted; }
protected:
/*
* Initialize the structure from the file, which is pointing at
* our Central Directory entry.
*/
status_t initFromCDE(FILE* fp);
/*
* Initialize the structure for a new file. We need the filename
* and comment so that we can properly size the LFH area. The
* filename is mandatory, the comment is optional.
*/
void initNew(const char* fileName, const char* comment);
/*
* Initialize the structure with the contents of a ZipEntry from
* another file.
*/
status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry);
/*
* Add some pad bytes to the LFH. We do this by adding or resizing
* the "extra" field.
*/
status_t addPadding(int padding);
/*
* Set information about the data for this entry.
*/
void setDataInfo(long uncompLen, long compLen, unsigned long crc32,
int compressionMethod);
/*
* Set the modification date.
*/
void setModWhen(time_t when);
/*
* Return the offset of the local file header.
*/
off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
/*
* Set the offset of the local file header, relative to the start of
* the current file.
*/
void setLFHOffset(off_t offset) {
mCDE.mLocalHeaderRelOffset = (long) offset;
}
/* mark for deletion; used by ZipFile::remove() */
void setDeleted(void) { mDeleted = true; }
private:
/* these are private and not defined */
ZipEntry(const ZipEntry& src);
ZipEntry& operator=(const ZipEntry& src);
/* returns "true" if the CDE and the LFH agree */
bool compareHeaders(void) const;
void copyCDEtoLFH(void);
bool mDeleted; // set if entry is pending deletion
bool mMarked; // app-defined marker
/*
* Every entry in the Zip archive starts off with one of these.
*/
class LocalFileHeader {
public:
LocalFileHeader(void) :
mVersionToExtract(0),
mGPBitFlag(0),
mCompressionMethod(0),
mLastModFileTime(0),
mLastModFileDate(0),
mCRC32(0),
mCompressedSize(0),
mUncompressedSize(0),
mFileNameLength(0),
mExtraFieldLength(0),
mFileName(NULL),
mExtraField(NULL)
{}
virtual ~LocalFileHeader(void) {
delete[] mFileName;
delete[] mExtraField;
}
status_t read(FILE* fp);
status_t write(FILE* fp);
// unsigned long mSignature;
unsigned short mVersionToExtract;
unsigned short mGPBitFlag;
unsigned short mCompressionMethod;
unsigned short mLastModFileTime;
unsigned short mLastModFileDate;
unsigned long mCRC32;
unsigned long mCompressedSize;
unsigned long mUncompressedSize;
unsigned short mFileNameLength;
unsigned short mExtraFieldLength;
unsigned char* mFileName;
unsigned char* mExtraField;
enum {
kSignature = 0x04034b50,
kLFHLen = 30, // LocalFileHdr len, excl. var fields
};
void dump(void) const;
};
/*
* Every entry in the Zip archive has one of these in the "central
* directory" at the end of the file.
*/
class CentralDirEntry {
public:
CentralDirEntry(void) :
mVersionMadeBy(0),
mVersionToExtract(0),
mGPBitFlag(0),
mCompressionMethod(0),
mLastModFileTime(0),
mLastModFileDate(0),
mCRC32(0),
mCompressedSize(0),
mUncompressedSize(0),
mFileNameLength(0),
mExtraFieldLength(0),
mFileCommentLength(0),
mDiskNumberStart(0),
mInternalAttrs(0),
mExternalAttrs(0),
mLocalHeaderRelOffset(0),
mFileName(NULL),
mExtraField(NULL),
mFileComment(NULL)
{}
virtual ~CentralDirEntry(void) {
delete[] mFileName;
delete[] mExtraField;
delete[] mFileComment;
}
status_t read(FILE* fp);
status_t write(FILE* fp);
// unsigned long mSignature;
unsigned short mVersionMadeBy;
unsigned short mVersionToExtract;
unsigned short mGPBitFlag;
unsigned short mCompressionMethod;
unsigned short mLastModFileTime;
unsigned short mLastModFileDate;
unsigned long mCRC32;
unsigned long mCompressedSize;
unsigned long mUncompressedSize;
unsigned short mFileNameLength;
unsigned short mExtraFieldLength;
unsigned short mFileCommentLength;
unsigned short mDiskNumberStart;
unsigned short mInternalAttrs;
unsigned long mExternalAttrs;
unsigned long mLocalHeaderRelOffset;
unsigned char* mFileName;
unsigned char* mExtraField;
unsigned char* mFileComment;
void dump(void) const;
enum {
kSignature = 0x02014b50,
kCDELen = 46, // CentralDirEnt len, excl. var fields
};
};
enum {
//kDataDescriptorSignature = 0x08074b50, // currently unused
kDataDescriptorLen = 16, // four 32-bit fields
kDefaultVersion = 20, // need deflate, nothing much else
kDefaultMadeBy = 0x0317, // 03=UNIX, 17=spec v2.3
kUsesDataDescr = 0x0008, // GPBitFlag bit 3
};
LocalFileHeader mLFH;
CentralDirEntry mCDE;
};
}; // namespace android
#endif // __LIBS_ZIPENTRY_H

1297
tools/zipalign/ZipFile.cpp Normal file

File diff suppressed because it is too large Load Diff

270
tools/zipalign/ZipFile.h Normal file
View File

@@ -0,0 +1,270 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// General-purpose Zip archive access. This class allows both reading and
// writing to Zip archives, including deletion of existing entries.
//
#ifndef __LIBS_ZIPFILE_H
#define __LIBS_ZIPFILE_H
#include <utils/Vector.h>
#include <utils/Errors.h>
#include <stdio.h>
#include "ZipEntry.h"
namespace android {
/*
* Manipulate a Zip archive.
*
* Some changes will not be visible in the until until "flush" is called.
*
* The correct way to update a file archive is to make all changes to a
* copy of the archive in a temporary file, and then unlink/rename over
* the original after everything completes. Because we're only interested
* in using this for packaging, we don't worry about such things. Crashing
* after making changes and before flush() completes could leave us with
* an unusable Zip archive.
*/
class ZipFile {
public:
ZipFile(void)
: mZipFp(NULL), mReadOnly(false), mNeedCDRewrite(false)
{}
~ZipFile(void) {
if (!mReadOnly)
flush();
if (mZipFp != NULL)
fclose(mZipFp);
discardEntries();
}
/*
* Open a new or existing archive.
*/
typedef enum {
kOpenReadOnly = 0x01,
kOpenReadWrite = 0x02,
kOpenCreate = 0x04, // create if it doesn't exist
kOpenTruncate = 0x08, // if it exists, empty it
};
status_t open(const char* zipFileName, int flags);
/*
* Add a file to the end of the archive. Specify whether you want the
* library to try to store it compressed.
*
* If "storageName" is specified, the archive will use that instead
* of "fileName".
*
* If there is already an entry with the same name, the call fails.
* Existing entries with the same name must be removed first.
*
* If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
*/
status_t add(const char* fileName, int compressionMethod,
ZipEntry** ppEntry)
{
return add(fileName, fileName, compressionMethod, ppEntry);
}
status_t add(const char* fileName, const char* storageName,
int compressionMethod, ZipEntry** ppEntry)
{
return addCommon(fileName, NULL, 0, storageName,
ZipEntry::kCompressStored,
compressionMethod, ppEntry);
}
/*
* Add a file that is already compressed with gzip.
*
* If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
*/
status_t addGzip(const char* fileName, const char* storageName,
ZipEntry** ppEntry)
{
return addCommon(fileName, NULL, 0, storageName,
ZipEntry::kCompressDeflated,
ZipEntry::kCompressDeflated, ppEntry);
}
/*
* Add a file from an in-memory data buffer.
*
* If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
*/
status_t add(const void* data, size_t size, const char* storageName,
int compressionMethod, ZipEntry** ppEntry)
{
return addCommon(NULL, data, size, storageName,
ZipEntry::kCompressStored,
compressionMethod, ppEntry);
}
/*
* 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 add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
int padding, ZipEntry** ppEntry);
/*
* Mark an entry as having been removed. It is not actually deleted
* from the archive or our internal data structures until flush() is
* called.
*/
status_t remove(ZipEntry* pEntry);
/*
* Flush changes. If mNeedCDRewrite is set, this writes the central dir.
*/
status_t flush(void);
/*
* Expand the data into the buffer provided. The buffer must hold
* at least <uncompressed len> bytes. Variation expands directly
* to a file.
*
* Returns "false" if an error was encountered in the compressed data.
*/
//bool uncompress(const ZipEntry* pEntry, void* buf) const;
//bool uncompress(const ZipEntry* pEntry, FILE* fp) const;
void* uncompress(const ZipEntry* pEntry);
/*
* Get an entry, by name. Returns NULL if not found.
*
* Does not return entries pending deletion.
*/
ZipEntry* getEntryByName(const char* fileName) const;
/*
* Get the Nth entry in the archive.
*
* This will return an entry that is pending deletion.
*/
int getNumEntries(void) const { return mEntries.size(); }
ZipEntry* getEntryByIndex(int idx) const;
private:
/* these are private and not defined */
ZipFile(const ZipFile& src);
ZipFile& operator=(const ZipFile& src);
class EndOfCentralDir {
public:
EndOfCentralDir(void) :
mDiskNumber(0),
mDiskWithCentralDir(0),
mNumEntries(0),
mTotalNumEntries(0),
mCentralDirSize(0),
mCentralDirOffset(0),
mCommentLen(0),
mComment(NULL)
{}
virtual ~EndOfCentralDir(void) {
delete[] mComment;
}
status_t readBuf(const unsigned char* buf, int len);
status_t write(FILE* fp);
//unsigned long mSignature;
unsigned short mDiskNumber;
unsigned short mDiskWithCentralDir;
unsigned short mNumEntries;
unsigned short mTotalNumEntries;
unsigned long mCentralDirSize;
unsigned long mCentralDirOffset; // offset from first disk
unsigned short mCommentLen;
unsigned char* mComment;
enum {
kSignature = 0x06054b50,
kEOCDLen = 22, // EndOfCentralDir len, excl. comment
kMaxCommentLen = 65535, // longest possible in ushort
kMaxEOCDSearch = kMaxCommentLen + EndOfCentralDir::kEOCDLen,
};
void dump(void) const;
};
/* read all entries in the central dir */
status_t readCentralDir(void);
/* crunch deleted entries out */
status_t crunchArchive(void);
/* clean up mEntries */
void discardEntries(void);
/* common handler for all "add" functions */
status_t addCommon(const char* fileName, const void* data, size_t size,
const char* storageName, int sourceType, int compressionMethod,
ZipEntry** ppEntry);
/* copy all of "srcFp" into "dstFp" */
status_t copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32);
/* copy all of "data" into "dstFp" */
status_t copyDataToFp(FILE* dstFp,
const void* data, size_t size, unsigned long* pCRC32);
/* copy some of "srcFp" into "dstFp" */
status_t copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
unsigned long* pCRC32);
/* like memmove(), but on parts of a single file */
status_t filemove(FILE* fp, off_t dest, off_t src, size_t n);
/* compress all of "srcFp" into "dstFp", using Deflate */
status_t compressFpToFp(FILE* dstFp, FILE* srcFp,
const void* data, size_t size, unsigned long* pCRC32);
/* get modification date from a file descriptor */
time_t getModTime(int fd);
/*
* We use stdio FILE*, which gives us buffering but makes dealing
* with files >2GB awkward. Until we support Zip64, we're fine.
*/
FILE* mZipFp; // Zip file pointer
/* one of these per file */
EndOfCentralDir mEOCD;
/* did we open this read-only? */
bool mReadOnly;
/* set this when we trash the central dir */
bool mNeedCDRewrite;
/*
* One ZipEntry per entry in the zip file. I'm using pointers instead
* of objects because it's easier than making operator= work for the
* classes and sub-classes.
*/
Vector<ZipEntry*> mEntries;
};
}; // namespace android
#endif // __LIBS_ZIPFILE_H