xref: /aosp_15_r20/build/make/tools/zipalign/ZipFile.h (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
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