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