41bc424c32
getLongLE would return a 64-bit number with the upper 32-bits set when decoding a 32-bit number with the top bit set. Per the zip file format, it was only expected to return a 32-bit number. Use explicitly sized types so that we use the proper sizes and don't do any implicit extensions. Change-Id: I5a4304dc99ce5f8f17284d4ca3094ae115207a1e
346 lines
9.9 KiB
C++
346 lines
9.9 KiB
C++
/*
|
|
* 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 <stdint.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.
|
|
*/
|
|
uint32_t 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 uint16_t getShortLE(const uint8_t* buf) {
|
|
return buf[0] | (buf[1] << 8);
|
|
}
|
|
static inline uint32_t getLongLE(const uint8_t* buf) {
|
|
return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
|
}
|
|
static inline void putShortLE(uint8_t* buf, uint16_t val) {
|
|
buf[0] = (uint8_t) val;
|
|
buf[1] = (uint8_t) (val >> 8);
|
|
}
|
|
static inline void putLongLE(uint8_t* buf, uint32_t val) {
|
|
buf[0] = (uint8_t) val;
|
|
buf[1] = (uint8_t) (val >> 8);
|
|
buf[2] = (uint8_t) (val >> 16);
|
|
buf[3] = (uint8_t) (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, uint32_t 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 = (uint32_t) 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);
|
|
|
|
// uint32_t mSignature;
|
|
uint16_t mVersionToExtract;
|
|
uint16_t mGPBitFlag;
|
|
uint16_t mCompressionMethod;
|
|
uint16_t mLastModFileTime;
|
|
uint16_t mLastModFileDate;
|
|
uint32_t mCRC32;
|
|
uint32_t mCompressedSize;
|
|
uint32_t mUncompressedSize;
|
|
uint16_t mFileNameLength;
|
|
uint16_t mExtraFieldLength;
|
|
uint8_t* mFileName;
|
|
uint8_t* 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);
|
|
|
|
// uint32_t mSignature;
|
|
uint16_t mVersionMadeBy;
|
|
uint16_t mVersionToExtract;
|
|
uint16_t mGPBitFlag;
|
|
uint16_t mCompressionMethod;
|
|
uint16_t mLastModFileTime;
|
|
uint16_t mLastModFileDate;
|
|
uint32_t mCRC32;
|
|
uint32_t mCompressedSize;
|
|
uint32_t mUncompressedSize;
|
|
uint16_t mFileNameLength;
|
|
uint16_t mExtraFieldLength;
|
|
uint16_t mFileCommentLength;
|
|
uint16_t mDiskNumberStart;
|
|
uint16_t mInternalAttrs;
|
|
uint32_t mExternalAttrs;
|
|
uint32_t mLocalHeaderRelOffset;
|
|
uint8_t* mFileName;
|
|
uint8_t* mExtraField;
|
|
uint8_t* 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
|