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