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