1*9e94795aSAndroid Build Coastguard Worker /* 2*9e94795aSAndroid Build Coastguard Worker * Copyright (C) 2006 The Android Open Source Project 3*9e94795aSAndroid Build Coastguard Worker * 4*9e94795aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*9e94795aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*9e94795aSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*9e94795aSAndroid Build Coastguard Worker * 8*9e94795aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*9e94795aSAndroid Build Coastguard Worker * 10*9e94795aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*9e94795aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*9e94795aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*9e94795aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*9e94795aSAndroid Build Coastguard Worker * limitations under the License. 15*9e94795aSAndroid Build Coastguard Worker */ 16*9e94795aSAndroid Build Coastguard Worker 17*9e94795aSAndroid Build Coastguard Worker // 18*9e94795aSAndroid Build Coastguard Worker // General-purpose Zip archive access. This class allows both reading and 19*9e94795aSAndroid Build Coastguard Worker // writing to Zip archives, including deletion of existing entries. 20*9e94795aSAndroid Build Coastguard Worker // 21*9e94795aSAndroid Build Coastguard Worker #ifndef __LIBS_ZIPFILE_H 22*9e94795aSAndroid Build Coastguard Worker #define __LIBS_ZIPFILE_H 23*9e94795aSAndroid Build Coastguard Worker 24*9e94795aSAndroid Build Coastguard Worker #include <utils/Vector.h> 25*9e94795aSAndroid Build Coastguard Worker #include <utils/Errors.h> 26*9e94795aSAndroid Build Coastguard Worker #include <stdio.h> 27*9e94795aSAndroid Build Coastguard Worker 28*9e94795aSAndroid Build Coastguard Worker #include "ZipEntry.h" 29*9e94795aSAndroid Build Coastguard Worker 30*9e94795aSAndroid Build Coastguard Worker namespace android { 31*9e94795aSAndroid Build Coastguard Worker 32*9e94795aSAndroid Build Coastguard Worker /* 33*9e94795aSAndroid Build Coastguard Worker * Manipulate a Zip archive. 34*9e94795aSAndroid Build Coastguard Worker * 35*9e94795aSAndroid Build Coastguard Worker * Some changes will not be visible in the until until "flush" is called. 36*9e94795aSAndroid Build Coastguard Worker * 37*9e94795aSAndroid Build Coastguard Worker * The correct way to update a file archive is to make all changes to a 38*9e94795aSAndroid Build Coastguard Worker * copy of the archive in a temporary file, and then unlink/rename over 39*9e94795aSAndroid Build Coastguard Worker * the original after everything completes. Because we're only interested 40*9e94795aSAndroid Build Coastguard Worker * in using this for packaging, we don't worry about such things. Crashing 41*9e94795aSAndroid Build Coastguard Worker * after making changes and before flush() completes could leave us with 42*9e94795aSAndroid Build Coastguard Worker * an unusable Zip archive. 43*9e94795aSAndroid Build Coastguard Worker */ 44*9e94795aSAndroid Build Coastguard Worker class ZipFile { 45*9e94795aSAndroid Build Coastguard Worker public: ZipFile(void)46*9e94795aSAndroid Build Coastguard Worker ZipFile(void) 47*9e94795aSAndroid Build Coastguard Worker : mZipFp(NULL), mReadOnly(false), mNeedCDRewrite(false) 48*9e94795aSAndroid Build Coastguard Worker {} ~ZipFile(void)49*9e94795aSAndroid Build Coastguard Worker ~ZipFile(void) { 50*9e94795aSAndroid Build Coastguard Worker if (!mReadOnly) 51*9e94795aSAndroid Build Coastguard Worker flush(); 52*9e94795aSAndroid Build Coastguard Worker if (mZipFp != NULL) 53*9e94795aSAndroid Build Coastguard Worker fclose(mZipFp); 54*9e94795aSAndroid Build Coastguard Worker discardEntries(); 55*9e94795aSAndroid Build Coastguard Worker } 56*9e94795aSAndroid Build Coastguard Worker 57*9e94795aSAndroid Build Coastguard Worker /* 58*9e94795aSAndroid Build Coastguard Worker * Open a new or existing archive. 59*9e94795aSAndroid Build Coastguard Worker */ 60*9e94795aSAndroid Build Coastguard Worker enum { 61*9e94795aSAndroid Build Coastguard Worker kOpenReadOnly = 0x01, 62*9e94795aSAndroid Build Coastguard Worker kOpenReadWrite = 0x02, 63*9e94795aSAndroid Build Coastguard Worker kOpenCreate = 0x04, // create if it doesn't exist 64*9e94795aSAndroid Build Coastguard Worker kOpenTruncate = 0x08, // if it exists, empty it 65*9e94795aSAndroid Build Coastguard Worker }; 66*9e94795aSAndroid Build Coastguard Worker status_t open(const char* zipFileName, int flags); 67*9e94795aSAndroid Build Coastguard Worker 68*9e94795aSAndroid Build Coastguard Worker /* 69*9e94795aSAndroid Build Coastguard Worker * Add a file to the end of the archive. Specify whether you want the 70*9e94795aSAndroid Build Coastguard Worker * library to try to store it compressed. 71*9e94795aSAndroid Build Coastguard Worker * 72*9e94795aSAndroid Build Coastguard Worker * If "storageName" is specified, the archive will use that instead 73*9e94795aSAndroid Build Coastguard Worker * of "fileName". 74*9e94795aSAndroid Build Coastguard Worker * 75*9e94795aSAndroid Build Coastguard Worker * If there is already an entry with the same name, the call fails. 76*9e94795aSAndroid Build Coastguard Worker * Existing entries with the same name must be removed first. 77*9e94795aSAndroid Build Coastguard Worker * 78*9e94795aSAndroid Build Coastguard Worker * If "ppEntry" is non-NULL, a pointer to the new entry will be returned. 79*9e94795aSAndroid Build Coastguard Worker */ add(const char * fileName,int compressionMethod,ZipEntry ** ppEntry)80*9e94795aSAndroid Build Coastguard Worker status_t add(const char* fileName, int compressionMethod, 81*9e94795aSAndroid Build Coastguard Worker ZipEntry** ppEntry) 82*9e94795aSAndroid Build Coastguard Worker { 83*9e94795aSAndroid Build Coastguard Worker return add(fileName, fileName, compressionMethod, ppEntry); 84*9e94795aSAndroid Build Coastguard Worker } add(const char * fileName,const char * storageName,int compressionMethod,ZipEntry ** ppEntry)85*9e94795aSAndroid Build Coastguard Worker status_t add(const char* fileName, const char* storageName, 86*9e94795aSAndroid Build Coastguard Worker int compressionMethod, ZipEntry** ppEntry) 87*9e94795aSAndroid Build Coastguard Worker { 88*9e94795aSAndroid Build Coastguard Worker return addCommon(fileName, NULL, 0, storageName, 89*9e94795aSAndroid Build Coastguard Worker compressionMethod, ppEntry); 90*9e94795aSAndroid Build Coastguard Worker } 91*9e94795aSAndroid Build Coastguard Worker 92*9e94795aSAndroid Build Coastguard Worker /* 93*9e94795aSAndroid Build Coastguard Worker * Add a file from an in-memory data buffer. 94*9e94795aSAndroid Build Coastguard Worker * 95*9e94795aSAndroid Build Coastguard Worker * If "ppEntry" is non-NULL, a pointer to the new entry will be returned. 96*9e94795aSAndroid Build Coastguard Worker */ add(const void * data,size_t size,const char * storageName,int compressionMethod,ZipEntry ** ppEntry)97*9e94795aSAndroid Build Coastguard Worker status_t add(const void* data, size_t size, const char* storageName, 98*9e94795aSAndroid Build Coastguard Worker int compressionMethod, ZipEntry** ppEntry) 99*9e94795aSAndroid Build Coastguard Worker { 100*9e94795aSAndroid Build Coastguard Worker return addCommon(NULL, data, size, storageName, 101*9e94795aSAndroid Build Coastguard Worker compressionMethod, ppEntry); 102*9e94795aSAndroid Build Coastguard Worker } 103*9e94795aSAndroid Build Coastguard Worker 104*9e94795aSAndroid Build Coastguard Worker /* 105*9e94795aSAndroid Build Coastguard Worker * Add an entry by copying it from another zip file. If "alignment" is 106*9e94795aSAndroid Build Coastguard Worker * nonzero, an appropriate number of bytes will be added to the "extra" 107*9e94795aSAndroid Build Coastguard Worker * field in the header so the entry payload is aligned. 108*9e94795aSAndroid Build Coastguard Worker * 109*9e94795aSAndroid Build Coastguard Worker * If "ppEntry" is non-NULL, a pointer to the new entry will be returned. 110*9e94795aSAndroid Build Coastguard Worker */ 111*9e94795aSAndroid Build Coastguard Worker status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry, 112*9e94795aSAndroid Build Coastguard Worker int alignment, ZipEntry** ppEntry); 113*9e94795aSAndroid Build Coastguard Worker 114*9e94795aSAndroid Build Coastguard Worker /* 115*9e94795aSAndroid Build Coastguard Worker * Add an entry by copying it from another zip file, recompressing with 116*9e94795aSAndroid Build Coastguard Worker * Zopfli if already compressed. 117*9e94795aSAndroid Build Coastguard Worker * 118*9e94795aSAndroid Build Coastguard Worker * If "ppEntry" is non-NULL, a pointer to the new entry will be returned. 119*9e94795aSAndroid Build Coastguard Worker */ 120*9e94795aSAndroid Build Coastguard Worker status_t addRecompress(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry, 121*9e94795aSAndroid Build Coastguard Worker ZipEntry** ppEntry); 122*9e94795aSAndroid Build Coastguard Worker 123*9e94795aSAndroid Build Coastguard Worker /* 124*9e94795aSAndroid Build Coastguard Worker * Mark an entry as having been removed. It is not actually deleted 125*9e94795aSAndroid Build Coastguard Worker * from the archive or our internal data structures until flush() is 126*9e94795aSAndroid Build Coastguard Worker * called. 127*9e94795aSAndroid Build Coastguard Worker */ 128*9e94795aSAndroid Build Coastguard Worker status_t remove(ZipEntry* pEntry); 129*9e94795aSAndroid Build Coastguard Worker 130*9e94795aSAndroid Build Coastguard Worker /* 131*9e94795aSAndroid Build Coastguard Worker * Flush changes. If mNeedCDRewrite is set, this writes the central dir. 132*9e94795aSAndroid Build Coastguard Worker */ 133*9e94795aSAndroid Build Coastguard Worker status_t flush(void); 134*9e94795aSAndroid Build Coastguard Worker 135*9e94795aSAndroid Build Coastguard Worker /* 136*9e94795aSAndroid Build Coastguard Worker * Expand the data into the buffer provided. The buffer must hold 137*9e94795aSAndroid Build Coastguard Worker * at least <uncompressed len> bytes. Variation expands directly 138*9e94795aSAndroid Build Coastguard Worker * to a file. 139*9e94795aSAndroid Build Coastguard Worker * 140*9e94795aSAndroid Build Coastguard Worker * Returns "false" if an error was encountered in the compressed data. 141*9e94795aSAndroid Build Coastguard Worker */ 142*9e94795aSAndroid Build Coastguard Worker //bool uncompress(const ZipEntry* pEntry, void* buf) const; 143*9e94795aSAndroid Build Coastguard Worker //bool uncompress(const ZipEntry* pEntry, FILE* fp) const; 144*9e94795aSAndroid Build Coastguard Worker void* uncompress(const ZipEntry* pEntry) const; 145*9e94795aSAndroid Build Coastguard Worker 146*9e94795aSAndroid Build Coastguard Worker /* 147*9e94795aSAndroid Build Coastguard Worker * Get an entry, by name. Returns NULL if not found. 148*9e94795aSAndroid Build Coastguard Worker * 149*9e94795aSAndroid Build Coastguard Worker * Does not return entries pending deletion. 150*9e94795aSAndroid Build Coastguard Worker */ 151*9e94795aSAndroid Build Coastguard Worker ZipEntry* getEntryByName(const char* fileName) const; 152*9e94795aSAndroid Build Coastguard Worker 153*9e94795aSAndroid Build Coastguard Worker /* 154*9e94795aSAndroid Build Coastguard Worker * Get the Nth entry in the archive. 155*9e94795aSAndroid Build Coastguard Worker * 156*9e94795aSAndroid Build Coastguard Worker * This will return an entry that is pending deletion. 157*9e94795aSAndroid Build Coastguard Worker */ getNumEntries(void)158*9e94795aSAndroid Build Coastguard Worker int getNumEntries(void) const { return mEntries.size(); } 159*9e94795aSAndroid Build Coastguard Worker ZipEntry* getEntryByIndex(int idx) const; 160*9e94795aSAndroid Build Coastguard Worker 161*9e94795aSAndroid Build Coastguard Worker private: 162*9e94795aSAndroid Build Coastguard Worker /* these are private and not defined */ 163*9e94795aSAndroid Build Coastguard Worker ZipFile(const ZipFile& src); 164*9e94795aSAndroid Build Coastguard Worker ZipFile& operator=(const ZipFile& src); 165*9e94795aSAndroid Build Coastguard Worker 166*9e94795aSAndroid Build Coastguard Worker status_t alignEntry(android::ZipEntry* pEntry, uint32_t alignTo); 167*9e94795aSAndroid Build Coastguard Worker 168*9e94795aSAndroid Build Coastguard Worker class EndOfCentralDir { 169*9e94795aSAndroid Build Coastguard Worker public: EndOfCentralDir(void)170*9e94795aSAndroid Build Coastguard Worker EndOfCentralDir(void) : 171*9e94795aSAndroid Build Coastguard Worker mDiskNumber(0), 172*9e94795aSAndroid Build Coastguard Worker mDiskWithCentralDir(0), 173*9e94795aSAndroid Build Coastguard Worker mNumEntries(0), 174*9e94795aSAndroid Build Coastguard Worker mTotalNumEntries(0), 175*9e94795aSAndroid Build Coastguard Worker mCentralDirSize(0), 176*9e94795aSAndroid Build Coastguard Worker mCentralDirOffset(0), 177*9e94795aSAndroid Build Coastguard Worker mCommentLen(0), 178*9e94795aSAndroid Build Coastguard Worker mComment(NULL) 179*9e94795aSAndroid Build Coastguard Worker {} ~EndOfCentralDir(void)180*9e94795aSAndroid Build Coastguard Worker virtual ~EndOfCentralDir(void) { 181*9e94795aSAndroid Build Coastguard Worker delete[] mComment; 182*9e94795aSAndroid Build Coastguard Worker } 183*9e94795aSAndroid Build Coastguard Worker 184*9e94795aSAndroid Build Coastguard Worker status_t readBuf(const uint8_t* buf, int len); 185*9e94795aSAndroid Build Coastguard Worker status_t write(FILE* fp); 186*9e94795aSAndroid Build Coastguard Worker 187*9e94795aSAndroid Build Coastguard Worker //uint32_t mSignature; 188*9e94795aSAndroid Build Coastguard Worker uint16_t mDiskNumber; 189*9e94795aSAndroid Build Coastguard Worker uint16_t mDiskWithCentralDir; 190*9e94795aSAndroid Build Coastguard Worker uint16_t mNumEntries; 191*9e94795aSAndroid Build Coastguard Worker uint16_t mTotalNumEntries; 192*9e94795aSAndroid Build Coastguard Worker uint32_t mCentralDirSize; 193*9e94795aSAndroid Build Coastguard Worker uint32_t mCentralDirOffset; // offset from first disk 194*9e94795aSAndroid Build Coastguard Worker uint16_t mCommentLen; 195*9e94795aSAndroid Build Coastguard Worker uint8_t* mComment; 196*9e94795aSAndroid Build Coastguard Worker 197*9e94795aSAndroid Build Coastguard Worker enum { 198*9e94795aSAndroid Build Coastguard Worker kSignature = 0x06054b50, 199*9e94795aSAndroid Build Coastguard Worker kEOCDLen = 22, // EndOfCentralDir len, excl. comment 200*9e94795aSAndroid Build Coastguard Worker 201*9e94795aSAndroid Build Coastguard Worker kMaxCommentLen = 65535, // longest possible in ushort 202*9e94795aSAndroid Build Coastguard Worker kMaxEOCDSearch = kMaxCommentLen + EndOfCentralDir::kEOCDLen, 203*9e94795aSAndroid Build Coastguard Worker 204*9e94795aSAndroid Build Coastguard Worker }; 205*9e94795aSAndroid Build Coastguard Worker 206*9e94795aSAndroid Build Coastguard Worker void dump(void) const; 207*9e94795aSAndroid Build Coastguard Worker }; 208*9e94795aSAndroid Build Coastguard Worker 209*9e94795aSAndroid Build Coastguard Worker 210*9e94795aSAndroid Build Coastguard Worker /* read all entries in the central dir */ 211*9e94795aSAndroid Build Coastguard Worker status_t readCentralDir(void); 212*9e94795aSAndroid Build Coastguard Worker 213*9e94795aSAndroid Build Coastguard Worker /* crunch deleted entries out */ 214*9e94795aSAndroid Build Coastguard Worker status_t crunchArchive(void); 215*9e94795aSAndroid Build Coastguard Worker 216*9e94795aSAndroid Build Coastguard Worker /* clean up mEntries */ 217*9e94795aSAndroid Build Coastguard Worker void discardEntries(void); 218*9e94795aSAndroid Build Coastguard Worker 219*9e94795aSAndroid Build Coastguard Worker /* common handler for all "add" functions */ 220*9e94795aSAndroid Build Coastguard Worker status_t addCommon(const char* fileName, const void* data, size_t size, 221*9e94795aSAndroid Build Coastguard Worker const char* storageName, int compressionMethod, ZipEntry** ppEntry); 222*9e94795aSAndroid Build Coastguard Worker 223*9e94795aSAndroid Build Coastguard Worker /* copy all of "srcFp" into "dstFp" */ 224*9e94795aSAndroid Build Coastguard Worker status_t copyFpToFp(FILE* dstFp, FILE* srcFp, uint32_t* pCRC32); 225*9e94795aSAndroid Build Coastguard Worker /* copy all of "data" into "dstFp" */ 226*9e94795aSAndroid Build Coastguard Worker status_t copyDataToFp(FILE* dstFp, 227*9e94795aSAndroid Build Coastguard Worker const void* data, size_t size, uint32_t* pCRC32); 228*9e94795aSAndroid Build Coastguard Worker /* copy some of "srcFp" into "dstFp" */ 229*9e94795aSAndroid Build Coastguard Worker status_t copyPartialFpToFp(FILE* dstFp, FILE* srcFp, size_t length, 230*9e94795aSAndroid Build Coastguard Worker uint32_t* pCRC32); 231*9e94795aSAndroid Build Coastguard Worker /* like memmove(), but on parts of a single file */ 232*9e94795aSAndroid Build Coastguard Worker status_t filemove(FILE* fp, off_t dest, off_t src, size_t n); 233*9e94795aSAndroid Build Coastguard Worker /* compress all of "srcFp" into "dstFp", using Deflate */ 234*9e94795aSAndroid Build Coastguard Worker status_t compressFpToFp(FILE* dstFp, FILE* srcFp, 235*9e94795aSAndroid Build Coastguard Worker const void* data, size_t size, uint32_t* pCRC32); 236*9e94795aSAndroid Build Coastguard Worker 237*9e94795aSAndroid Build Coastguard Worker /* get modification date from a file descriptor */ 238*9e94795aSAndroid Build Coastguard Worker time_t getModTime(int fd); 239*9e94795aSAndroid Build Coastguard Worker 240*9e94795aSAndroid Build Coastguard Worker /* 241*9e94795aSAndroid Build Coastguard Worker * We use stdio FILE*, which gives us buffering but makes dealing 242*9e94795aSAndroid Build Coastguard Worker * with files >2GB awkward. Until we support Zip64, we're fine. 243*9e94795aSAndroid Build Coastguard Worker */ 244*9e94795aSAndroid Build Coastguard Worker FILE* mZipFp; // Zip file pointer 245*9e94795aSAndroid Build Coastguard Worker 246*9e94795aSAndroid Build Coastguard Worker /* one of these per file */ 247*9e94795aSAndroid Build Coastguard Worker EndOfCentralDir mEOCD; 248*9e94795aSAndroid Build Coastguard Worker 249*9e94795aSAndroid Build Coastguard Worker /* did we open this read-only? */ 250*9e94795aSAndroid Build Coastguard Worker bool mReadOnly; 251*9e94795aSAndroid Build Coastguard Worker 252*9e94795aSAndroid Build Coastguard Worker /* set this when we trash the central dir */ 253*9e94795aSAndroid Build Coastguard Worker bool mNeedCDRewrite; 254*9e94795aSAndroid Build Coastguard Worker 255*9e94795aSAndroid Build Coastguard Worker /* 256*9e94795aSAndroid Build Coastguard Worker * One ZipEntry per entry in the zip file. I'm using pointers instead 257*9e94795aSAndroid Build Coastguard Worker * of objects because it's easier than making operator= work for the 258*9e94795aSAndroid Build Coastguard Worker * classes and sub-classes. 259*9e94795aSAndroid Build Coastguard Worker */ 260*9e94795aSAndroid Build Coastguard Worker Vector<ZipEntry*> mEntries; 261*9e94795aSAndroid Build Coastguard Worker }; 262*9e94795aSAndroid Build Coastguard Worker 263*9e94795aSAndroid Build Coastguard Worker }; // namespace android 264*9e94795aSAndroid Build Coastguard Worker 265*9e94795aSAndroid Build Coastguard Worker #endif // __LIBS_ZIPFILE_H 266