| /* | |
| * 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> | |
| #include <time.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 offset of the local file header. | |
| */ | |
| off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; } | |
| /* | |
| * 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); | |
| /* | |
| * 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); | |
| CentralDirEntry& operator=(const CentralDirEntry& src); | |
| // 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 |