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 aapt {
31
32using android::status_t;
33
34class 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 */
48class ZipEntry {
49public:
50    friend class ZipFile;
51
52    ZipEntry(void)
53        : mDeleted(false), mMarked(false)
54        {}
55    ~ZipEntry(void) {}
56
57    /*
58     * Returns "true" if the data is compressed.
59     */
60    bool isCompressed(void) const {
61        return mCDE.mCompressionMethod != kCompressStored;
62    }
63    int getCompressionMethod(void) const { return mCDE.mCompressionMethod; }
64
65    /*
66     * Return the uncompressed length.
67     */
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     */
74    off_t getCompressedLen(void) const { return mCDE.mCompressedSize; }
75
76    /*
77     * Return the offset of the local file header.
78     */
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     */
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     */
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     */
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     */
111    bool getMarked(void) const { return mMarked; }
112    void setMarked(bool val) { mMarked = val; }
113
114    /*
115     * Some basic functions for raw data manipulation.  "LE" means
116     * Little Endian.
117     */
118    static inline unsigned short getShortLE(const unsigned char* buf) {
119        return buf[0] | (buf[1] << 8);
120    }
121    static inline unsigned long getLongLE(const unsigned char* buf) {
122        return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
123    }
124    static inline void putShortLE(unsigned char* buf, short val) {
125        buf[0] = (unsigned char) val;
126        buf[1] = (unsigned char) (val >> 8);
127    }
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     */
156    bool getDeleted(void) const { return mDeleted; }
157
158protected:
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     */
200    void setLFHOffset(off_t offset) {
201        mCDE.mLocalHeaderRelOffset = (long) offset;
202    }
203
204    /* mark for deletion; used by ZipFile::remove() */
205    void setDeleted(void) { mDeleted = true; }
206
207private:
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:
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        {}
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:
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        {}
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