1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //
18 // Zip archive entries.
19 //
20 // The ZipEntry class is tightly meshed with the ZipFile class.
21 //
22 #ifndef __LIBS_ZIPENTRY_H
23 #define __LIBS_ZIPENTRY_H
24 
25 #include <utils/Errors.h>
26 
27 #include <stdlib.h>
28 #include <stdio.h>
29 
30 namespace aapt {
31 
32 using android::status_t;
33 
34 class ZipFile;
35 
36 /*
37  * ZipEntry objects represent a single entry in a Zip archive.
38  *
39  * You can use one of these to get or set information about an entry, but
40  * there are no functions here for accessing the data itself.  (We could
41  * tuck a pointer to the ZipFile in here for convenience, but that raises
42  * the likelihood of using ZipEntry objects after discarding the ZipFile.)
43  *
44  * File information is stored in two places: next to the file data (the Local
45  * File Header, and possibly a Data Descriptor), and at the end of the file
46  * (the Central Directory Entry).  The two must be kept in sync.
47  */
48 class ZipEntry {
49 public:
50     friend class ZipFile;
51 
ZipEntry(void)52     ZipEntry(void)
53         : mDeleted(false), mMarked(false)
54         {}
~ZipEntry(void)55     ~ZipEntry(void) {}
56 
57     /*
58      * Returns "true" if the data is compressed.
59      */
isCompressed(void)60     bool isCompressed(void) const {
61         return mCDE.mCompressionMethod != kCompressStored;
62     }
getCompressionMethod(void)63     int getCompressionMethod(void) const { return mCDE.mCompressionMethod; }
64 
65     /*
66      * Return the uncompressed length.
67      */
getUncompressedLen(void)68     off_t getUncompressedLen(void) const { return mCDE.mUncompressedSize; }
69 
70     /*
71      * Return the compressed length.  For uncompressed data, this returns
72      * the same thing as getUncompresesdLen().
73      */
getCompressedLen(void)74     off_t getCompressedLen(void) const { return mCDE.mCompressedSize; }
75 
76     /*
77      * Return the offset of the local file header.
78      */
getLFHOffset(void)79     off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
80 
81     /*
82      * Return the absolute file offset of the start of the compressed or
83      * uncompressed data.
84      */
getFileOffset(void)85     off_t getFileOffset(void) const {
86         return mCDE.mLocalHeaderRelOffset +
87                 LocalFileHeader::kLFHLen +
88                 mLFH.mFileNameLength +
89                 mLFH.mExtraFieldLength;
90     }
91 
92     /*
93      * Return the data CRC.
94      */
getCRC32(void)95     unsigned long getCRC32(void) const { return mCDE.mCRC32; }
96 
97     /*
98      * Return file modification time in UNIX seconds-since-epoch.
99      */
100     time_t getModWhen(void) const;
101 
102     /*
103      * Return the archived file name.
104      */
getFileName(void)105     const char* getFileName(void) const { return (const char*) mCDE.mFileName; }
106 
107     /*
108      * Application-defined "mark".  Can be useful when synchronizing the
109      * contents of an archive with contents on disk.
110      */
getMarked(void)111     bool getMarked(void) const { return mMarked; }
setMarked(bool val)112     void setMarked(bool val) { mMarked = val; }
113 
114     /*
115      * Some basic functions for raw data manipulation.  "LE" means
116      * Little Endian.
117      */
getShortLE(const unsigned char * buf)118     static inline unsigned short getShortLE(const unsigned char* buf) {
119         return buf[0] | (buf[1] << 8);
120     }
getLongLE(const unsigned char * buf)121     static inline unsigned long getLongLE(const unsigned char* buf) {
122         return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
123     }
putShortLE(unsigned char * buf,short val)124     static inline void putShortLE(unsigned char* buf, short val) {
125         buf[0] = (unsigned char) val;
126         buf[1] = (unsigned char) (val >> 8);
127     }
putLongLE(unsigned char * buf,long val)128     static inline void putLongLE(unsigned char* buf, long val) {
129         buf[0] = (unsigned char) val;
130         buf[1] = (unsigned char) (val >> 8);
131         buf[2] = (unsigned char) (val >> 16);
132         buf[3] = (unsigned char) (val >> 24);
133     }
134 
135     /* defined for Zip archives */
136     enum {
137         kCompressStored     = 0,        // no compression
138         // shrunk           = 1,
139         // reduced 1        = 2,
140         // reduced 2        = 3,
141         // reduced 3        = 4,
142         // reduced 4        = 5,
143         // imploded         = 6,
144         // tokenized        = 7,
145         kCompressDeflated   = 8,        // standard deflate
146         // Deflate64        = 9,
147         // lib imploded     = 10,
148         // reserved         = 11,
149         // bzip2            = 12,
150     };
151 
152     /*
153      * Deletion flag.  If set, the entry will be removed on the next
154      * call to "flush".
155      */
getDeleted(void)156     bool getDeleted(void) const { return mDeleted; }
157 
158 protected:
159     /*
160      * Initialize the structure from the file, which is pointing at
161      * our Central Directory entry.
162      */
163     status_t initFromCDE(FILE* fp);
164 
165     /*
166      * Initialize the structure for a new file.  We need the filename
167      * and comment so that we can properly size the LFH area.  The
168      * filename is mandatory, the comment is optional.
169      */
170     void initNew(const char* fileName, const char* comment);
171 
172     /*
173      * Initialize the structure with the contents of a ZipEntry from
174      * another file. If fileName is non-NULL, override the name with fileName.
175      */
176     status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry,
177                               const char* fileName);
178 
179     /*
180      * Add some pad bytes to the LFH.  We do this by adding or resizing
181      * the "extra" field.
182      */
183     status_t addPadding(int padding);
184 
185     /*
186      * Set information about the data for this entry.
187      */
188     void setDataInfo(long uncompLen, long compLen, unsigned long crc32,
189         int compressionMethod);
190 
191     /*
192      * Set the modification date.
193      */
194     void setModWhen(time_t when);
195 
196     /*
197      * Set the offset of the local file header, relative to the start of
198      * the current file.
199      */
setLFHOffset(off_t offset)200     void setLFHOffset(off_t offset) {
201         mCDE.mLocalHeaderRelOffset = (long) offset;
202     }
203 
204     /* mark for deletion; used by ZipFile::remove() */
setDeleted(void)205     void setDeleted(void) { mDeleted = true; }
206 
207 private:
208     /* these are private and not defined */
209     ZipEntry(const ZipEntry& src);
210     ZipEntry& operator=(const ZipEntry& src);
211 
212     /* returns "true" if the CDE and the LFH agree */
213     bool compareHeaders(void) const;
214     void copyCDEtoLFH(void);
215 
216     bool        mDeleted;       // set if entry is pending deletion
217     bool        mMarked;        // app-defined marker
218 
219     /*
220      * Every entry in the Zip archive starts off with one of these.
221      */
222     class LocalFileHeader {
223     public:
LocalFileHeader(void)224         LocalFileHeader(void) :
225             mVersionToExtract(0),
226             mGPBitFlag(0),
227             mCompressionMethod(0),
228             mLastModFileTime(0),
229             mLastModFileDate(0),
230             mCRC32(0),
231             mCompressedSize(0),
232             mUncompressedSize(0),
233             mFileNameLength(0),
234             mExtraFieldLength(0),
235             mFileName(NULL),
236             mExtraField(NULL)
237         {}
~LocalFileHeader(void)238         virtual ~LocalFileHeader(void) {
239             delete[] mFileName;
240             delete[] mExtraField;
241         }
242 
243         status_t read(FILE* fp);
244         status_t write(FILE* fp);
245 
246         // unsigned long mSignature;
247         unsigned short  mVersionToExtract;
248         unsigned short  mGPBitFlag;
249         unsigned short  mCompressionMethod;
250         unsigned short  mLastModFileTime;
251         unsigned short  mLastModFileDate;
252         unsigned long   mCRC32;
253         unsigned long   mCompressedSize;
254         unsigned long   mUncompressedSize;
255         unsigned short  mFileNameLength;
256         unsigned short  mExtraFieldLength;
257         unsigned char*  mFileName;
258         unsigned char*  mExtraField;
259 
260         enum {
261             kSignature      = 0x04034b50,
262             kLFHLen         = 30,       // LocalFileHdr len, excl. var fields
263         };
264 
265         void dump(void) const;
266     };
267 
268     /*
269      * Every entry in the Zip archive has one of these in the "central
270      * directory" at the end of the file.
271      */
272     class CentralDirEntry {
273     public:
CentralDirEntry(void)274         CentralDirEntry(void) :
275             mVersionMadeBy(0),
276             mVersionToExtract(0),
277             mGPBitFlag(0),
278             mCompressionMethod(0),
279             mLastModFileTime(0),
280             mLastModFileDate(0),
281             mCRC32(0),
282             mCompressedSize(0),
283             mUncompressedSize(0),
284             mFileNameLength(0),
285             mExtraFieldLength(0),
286             mFileCommentLength(0),
287             mDiskNumberStart(0),
288             mInternalAttrs(0),
289             mExternalAttrs(0),
290             mLocalHeaderRelOffset(0),
291             mFileName(NULL),
292             mExtraField(NULL),
293             mFileComment(NULL)
294         {}
~CentralDirEntry(void)295         virtual ~CentralDirEntry(void) {
296             delete[] mFileName;
297             delete[] mExtraField;
298             delete[] mFileComment;
299         }
300 
301         status_t read(FILE* fp);
302         status_t write(FILE* fp);
303 
304         CentralDirEntry& operator=(const CentralDirEntry& src);
305 
306         // unsigned long mSignature;
307         unsigned short  mVersionMadeBy;
308         unsigned short  mVersionToExtract;
309         unsigned short  mGPBitFlag;
310         unsigned short  mCompressionMethod;
311         unsigned short  mLastModFileTime;
312         unsigned short  mLastModFileDate;
313         unsigned long   mCRC32;
314         unsigned long   mCompressedSize;
315         unsigned long   mUncompressedSize;
316         unsigned short  mFileNameLength;
317         unsigned short  mExtraFieldLength;
318         unsigned short  mFileCommentLength;
319         unsigned short  mDiskNumberStart;
320         unsigned short  mInternalAttrs;
321         unsigned long   mExternalAttrs;
322         unsigned long   mLocalHeaderRelOffset;
323         unsigned char*  mFileName;
324         unsigned char*  mExtraField;
325         unsigned char*  mFileComment;
326 
327         void dump(void) const;
328 
329         enum {
330             kSignature      = 0x02014b50,
331             kCDELen         = 46,       // CentralDirEnt len, excl. var fields
332         };
333     };
334 
335     enum {
336         //kDataDescriptorSignature  = 0x08074b50,   // currently unused
337         kDataDescriptorLen  = 16,           // four 32-bit fields
338 
339         kDefaultVersion     = 20,           // need deflate, nothing much else
340         kDefaultMadeBy      = 0x0317,       // 03=UNIX, 17=spec v2.3
341         kUsesDataDescr      = 0x0008,       // GPBitFlag bit 3
342     };
343 
344     LocalFileHeader     mLFH;
345     CentralDirEntry     mCDE;
346 };
347 
348 }; // namespace aapt
349 
350 #endif // __LIBS_ZIPENTRY_H
351