xref: /aosp_15_r20/frameworks/base/tools/aapt/ZipEntry.cpp (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 // Access to entries in a Zip archive.
19*d57664e9SAndroid Build Coastguard Worker //
20*d57664e9SAndroid Build Coastguard Worker 
21*d57664e9SAndroid Build Coastguard Worker #define _POSIX_THREAD_SAFE_FUNCTIONS // For mingw localtime_r().
22*d57664e9SAndroid Build Coastguard Worker 
23*d57664e9SAndroid Build Coastguard Worker #define LOG_TAG "zip"
24*d57664e9SAndroid Build Coastguard Worker 
25*d57664e9SAndroid Build Coastguard Worker #include "ZipEntry.h"
26*d57664e9SAndroid Build Coastguard Worker #include <utils/Log.h>
27*d57664e9SAndroid Build Coastguard Worker 
28*d57664e9SAndroid Build Coastguard Worker #include <assert.h>
29*d57664e9SAndroid Build Coastguard Worker #include <stdio.h>
30*d57664e9SAndroid Build Coastguard Worker #include <string.h>
31*d57664e9SAndroid Build Coastguard Worker #include <time.h>
32*d57664e9SAndroid Build Coastguard Worker 
33*d57664e9SAndroid Build Coastguard Worker using namespace android;
34*d57664e9SAndroid Build Coastguard Worker 
35*d57664e9SAndroid Build Coastguard Worker /*
36*d57664e9SAndroid Build Coastguard Worker  * Initialize a new ZipEntry structure from a FILE* positioned at a
37*d57664e9SAndroid Build Coastguard Worker  * CentralDirectoryEntry.
38*d57664e9SAndroid Build Coastguard Worker  *
39*d57664e9SAndroid Build Coastguard Worker  * On exit, the file pointer will be at the start of the next CDE or
40*d57664e9SAndroid Build Coastguard Worker  * at the EOCD.
41*d57664e9SAndroid Build Coastguard Worker  */
initFromCDE(FILE * fp)42*d57664e9SAndroid Build Coastguard Worker status_t ZipEntry::initFromCDE(FILE* fp)
43*d57664e9SAndroid Build Coastguard Worker {
44*d57664e9SAndroid Build Coastguard Worker     status_t result;
45*d57664e9SAndroid Build Coastguard Worker     long posn;
46*d57664e9SAndroid Build Coastguard Worker     bool hasDD;
47*d57664e9SAndroid Build Coastguard Worker 
48*d57664e9SAndroid Build Coastguard Worker     //ALOGV("initFromCDE ---\n");
49*d57664e9SAndroid Build Coastguard Worker 
50*d57664e9SAndroid Build Coastguard Worker     /* read the CDE */
51*d57664e9SAndroid Build Coastguard Worker     result = mCDE.read(fp);
52*d57664e9SAndroid Build Coastguard Worker     if (result != NO_ERROR) {
53*d57664e9SAndroid Build Coastguard Worker         ALOGD("mCDE.read failed\n");
54*d57664e9SAndroid Build Coastguard Worker         return result;
55*d57664e9SAndroid Build Coastguard Worker     }
56*d57664e9SAndroid Build Coastguard Worker 
57*d57664e9SAndroid Build Coastguard Worker     //mCDE.dump();
58*d57664e9SAndroid Build Coastguard Worker 
59*d57664e9SAndroid Build Coastguard Worker     /* using the info in the CDE, go load up the LFH */
60*d57664e9SAndroid Build Coastguard Worker     posn = ftell(fp);
61*d57664e9SAndroid Build Coastguard Worker     if (fseek(fp, mCDE.mLocalHeaderRelOffset, SEEK_SET) != 0) {
62*d57664e9SAndroid Build Coastguard Worker         ALOGD("local header seek failed (%ld)\n",
63*d57664e9SAndroid Build Coastguard Worker             mCDE.mLocalHeaderRelOffset);
64*d57664e9SAndroid Build Coastguard Worker         return UNKNOWN_ERROR;
65*d57664e9SAndroid Build Coastguard Worker     }
66*d57664e9SAndroid Build Coastguard Worker 
67*d57664e9SAndroid Build Coastguard Worker     result = mLFH.read(fp);
68*d57664e9SAndroid Build Coastguard Worker     if (result != NO_ERROR) {
69*d57664e9SAndroid Build Coastguard Worker         ALOGD("mLFH.read failed\n");
70*d57664e9SAndroid Build Coastguard Worker         return result;
71*d57664e9SAndroid Build Coastguard Worker     }
72*d57664e9SAndroid Build Coastguard Worker 
73*d57664e9SAndroid Build Coastguard Worker     if (fseek(fp, posn, SEEK_SET) != 0)
74*d57664e9SAndroid Build Coastguard Worker         return UNKNOWN_ERROR;
75*d57664e9SAndroid Build Coastguard Worker 
76*d57664e9SAndroid Build Coastguard Worker     //mLFH.dump();
77*d57664e9SAndroid Build Coastguard Worker 
78*d57664e9SAndroid Build Coastguard Worker     /*
79*d57664e9SAndroid Build Coastguard Worker      * We *might* need to read the Data Descriptor at this point and
80*d57664e9SAndroid Build Coastguard Worker      * integrate it into the LFH.  If this bit is set, the CRC-32,
81*d57664e9SAndroid Build Coastguard Worker      * compressed size, and uncompressed size will be zero.  In practice
82*d57664e9SAndroid Build Coastguard Worker      * these seem to be rare.
83*d57664e9SAndroid Build Coastguard Worker      */
84*d57664e9SAndroid Build Coastguard Worker     hasDD = (mLFH.mGPBitFlag & kUsesDataDescr) != 0;
85*d57664e9SAndroid Build Coastguard Worker     if (hasDD) {
86*d57664e9SAndroid Build Coastguard Worker         // do something clever
87*d57664e9SAndroid Build Coastguard Worker         //ALOGD("+++ has data descriptor\n");
88*d57664e9SAndroid Build Coastguard Worker     }
89*d57664e9SAndroid Build Coastguard Worker 
90*d57664e9SAndroid Build Coastguard Worker     /*
91*d57664e9SAndroid Build Coastguard Worker      * Sanity-check the LFH.  Note that this will fail if the "kUsesDataDescr"
92*d57664e9SAndroid Build Coastguard Worker      * flag is set, because the LFH is incomplete.  (Not a problem, since we
93*d57664e9SAndroid Build Coastguard Worker      * prefer the CDE values.)
94*d57664e9SAndroid Build Coastguard Worker      */
95*d57664e9SAndroid Build Coastguard Worker     if (!hasDD && !compareHeaders()) {
96*d57664e9SAndroid Build Coastguard Worker         ALOGW("warning: header mismatch\n");
97*d57664e9SAndroid Build Coastguard Worker         // keep going?
98*d57664e9SAndroid Build Coastguard Worker     }
99*d57664e9SAndroid Build Coastguard Worker 
100*d57664e9SAndroid Build Coastguard Worker     /*
101*d57664e9SAndroid Build Coastguard Worker      * If the mVersionToExtract is greater than 20, we may have an
102*d57664e9SAndroid Build Coastguard Worker      * issue unpacking the record -- could be encrypted, compressed
103*d57664e9SAndroid Build Coastguard Worker      * with something we don't support, or use Zip64 extensions.  We
104*d57664e9SAndroid Build Coastguard Worker      * can defer worrying about that to when we're extracting data.
105*d57664e9SAndroid Build Coastguard Worker      */
106*d57664e9SAndroid Build Coastguard Worker 
107*d57664e9SAndroid Build Coastguard Worker     return NO_ERROR;
108*d57664e9SAndroid Build Coastguard Worker }
109*d57664e9SAndroid Build Coastguard Worker 
110*d57664e9SAndroid Build Coastguard Worker /*
111*d57664e9SAndroid Build Coastguard Worker  * Initialize a new entry.  Pass in the file name and an optional comment.
112*d57664e9SAndroid Build Coastguard Worker  *
113*d57664e9SAndroid Build Coastguard Worker  * Initializes the CDE and the LFH.
114*d57664e9SAndroid Build Coastguard Worker  */
initNew(const char * fileName,const char * comment)115*d57664e9SAndroid Build Coastguard Worker void ZipEntry::initNew(const char* fileName, const char* comment)
116*d57664e9SAndroid Build Coastguard Worker {
117*d57664e9SAndroid Build Coastguard Worker     assert(fileName != NULL && *fileName != '\0');  // name required
118*d57664e9SAndroid Build Coastguard Worker 
119*d57664e9SAndroid Build Coastguard Worker     /* most fields are properly initialized by constructor */
120*d57664e9SAndroid Build Coastguard Worker     mCDE.mVersionMadeBy = kDefaultMadeBy;
121*d57664e9SAndroid Build Coastguard Worker     mCDE.mVersionToExtract = kDefaultVersion;
122*d57664e9SAndroid Build Coastguard Worker     mCDE.mCompressionMethod = kCompressStored;
123*d57664e9SAndroid Build Coastguard Worker     mCDE.mFileNameLength = strlen(fileName);
124*d57664e9SAndroid Build Coastguard Worker     if (comment != NULL)
125*d57664e9SAndroid Build Coastguard Worker         mCDE.mFileCommentLength = strlen(comment);
126*d57664e9SAndroid Build Coastguard Worker     mCDE.mExternalAttrs = 0x81b60020;   // matches what WinZip does
127*d57664e9SAndroid Build Coastguard Worker 
128*d57664e9SAndroid Build Coastguard Worker     if (mCDE.mFileNameLength > 0) {
129*d57664e9SAndroid Build Coastguard Worker         mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
130*d57664e9SAndroid Build Coastguard Worker         strcpy((char*) mCDE.mFileName, fileName);
131*d57664e9SAndroid Build Coastguard Worker     }
132*d57664e9SAndroid Build Coastguard Worker     if (mCDE.mFileCommentLength > 0) {
133*d57664e9SAndroid Build Coastguard Worker         /* TODO: stop assuming null-terminated ASCII here? */
134*d57664e9SAndroid Build Coastguard Worker         mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
135*d57664e9SAndroid Build Coastguard Worker         strcpy((char*) mCDE.mFileComment, comment);
136*d57664e9SAndroid Build Coastguard Worker     }
137*d57664e9SAndroid Build Coastguard Worker 
138*d57664e9SAndroid Build Coastguard Worker     copyCDEtoLFH();
139*d57664e9SAndroid Build Coastguard Worker }
140*d57664e9SAndroid Build Coastguard Worker 
141*d57664e9SAndroid Build Coastguard Worker /*
142*d57664e9SAndroid Build Coastguard Worker  * Initialize a new entry, starting with the ZipEntry from a different
143*d57664e9SAndroid Build Coastguard Worker  * archive.
144*d57664e9SAndroid Build Coastguard Worker  *
145*d57664e9SAndroid Build Coastguard Worker  * Initializes the CDE and the LFH.
146*d57664e9SAndroid Build Coastguard Worker  */
initFromExternal(const ZipFile *,const ZipEntry * pEntry)147*d57664e9SAndroid Build Coastguard Worker status_t ZipEntry::initFromExternal(const ZipFile* /* pZipFile */,
148*d57664e9SAndroid Build Coastguard Worker     const ZipEntry* pEntry)
149*d57664e9SAndroid Build Coastguard Worker {
150*d57664e9SAndroid Build Coastguard Worker     mCDE = pEntry->mCDE;
151*d57664e9SAndroid Build Coastguard Worker     // Check whether we got all the memory needed.
152*d57664e9SAndroid Build Coastguard Worker     if ((mCDE.mFileNameLength > 0 && mCDE.mFileName == NULL) ||
153*d57664e9SAndroid Build Coastguard Worker             (mCDE.mFileCommentLength > 0 && mCDE.mFileComment == NULL) ||
154*d57664e9SAndroid Build Coastguard Worker             (mCDE.mExtraFieldLength > 0 && mCDE.mExtraField == NULL)) {
155*d57664e9SAndroid Build Coastguard Worker         return NO_MEMORY;
156*d57664e9SAndroid Build Coastguard Worker     }
157*d57664e9SAndroid Build Coastguard Worker 
158*d57664e9SAndroid Build Coastguard Worker     /* construct the LFH from the CDE */
159*d57664e9SAndroid Build Coastguard Worker     copyCDEtoLFH();
160*d57664e9SAndroid Build Coastguard Worker 
161*d57664e9SAndroid Build Coastguard Worker     /*
162*d57664e9SAndroid Build Coastguard Worker      * The LFH "extra" field is independent of the CDE "extra", so we
163*d57664e9SAndroid Build Coastguard Worker      * handle it here.
164*d57664e9SAndroid Build Coastguard Worker      */
165*d57664e9SAndroid Build Coastguard Worker     assert(mLFH.mExtraField == NULL);
166*d57664e9SAndroid Build Coastguard Worker     mLFH.mExtraFieldLength = pEntry->mLFH.mExtraFieldLength;
167*d57664e9SAndroid Build Coastguard Worker     if (mLFH.mExtraFieldLength > 0) {
168*d57664e9SAndroid Build Coastguard Worker         mLFH.mExtraField = new unsigned char[mLFH.mExtraFieldLength+1];
169*d57664e9SAndroid Build Coastguard Worker         if (mLFH.mExtraField == NULL)
170*d57664e9SAndroid Build Coastguard Worker             return NO_MEMORY;
171*d57664e9SAndroid Build Coastguard Worker         memcpy(mLFH.mExtraField, pEntry->mLFH.mExtraField,
172*d57664e9SAndroid Build Coastguard Worker             mLFH.mExtraFieldLength+1);
173*d57664e9SAndroid Build Coastguard Worker     }
174*d57664e9SAndroid Build Coastguard Worker 
175*d57664e9SAndroid Build Coastguard Worker     return NO_ERROR;
176*d57664e9SAndroid Build Coastguard Worker }
177*d57664e9SAndroid Build Coastguard Worker 
178*d57664e9SAndroid Build Coastguard Worker /*
179*d57664e9SAndroid Build Coastguard Worker  * Insert pad bytes in the LFH by tweaking the "extra" field.  This will
180*d57664e9SAndroid Build Coastguard Worker  * potentially confuse something that put "extra" data in here earlier,
181*d57664e9SAndroid Build Coastguard Worker  * but I can't find an actual problem.
182*d57664e9SAndroid Build Coastguard Worker  */
addPadding(int padding)183*d57664e9SAndroid Build Coastguard Worker status_t ZipEntry::addPadding(int padding)
184*d57664e9SAndroid Build Coastguard Worker {
185*d57664e9SAndroid Build Coastguard Worker     if (padding <= 0)
186*d57664e9SAndroid Build Coastguard Worker         return INVALID_OPERATION;
187*d57664e9SAndroid Build Coastguard Worker 
188*d57664e9SAndroid Build Coastguard Worker     //ALOGI("HEY: adding %d pad bytes to existing %d in %s\n",
189*d57664e9SAndroid Build Coastguard Worker     //    padding, mLFH.mExtraFieldLength, mCDE.mFileName);
190*d57664e9SAndroid Build Coastguard Worker 
191*d57664e9SAndroid Build Coastguard Worker     if (mLFH.mExtraFieldLength > 0) {
192*d57664e9SAndroid Build Coastguard Worker         /* extend existing field */
193*d57664e9SAndroid Build Coastguard Worker         unsigned char* newExtra;
194*d57664e9SAndroid Build Coastguard Worker 
195*d57664e9SAndroid Build Coastguard Worker         newExtra = new unsigned char[mLFH.mExtraFieldLength + padding];
196*d57664e9SAndroid Build Coastguard Worker         if (newExtra == NULL)
197*d57664e9SAndroid Build Coastguard Worker             return NO_MEMORY;
198*d57664e9SAndroid Build Coastguard Worker         memset(newExtra + mLFH.mExtraFieldLength, 0, padding);
199*d57664e9SAndroid Build Coastguard Worker         memcpy(newExtra, mLFH.mExtraField, mLFH.mExtraFieldLength);
200*d57664e9SAndroid Build Coastguard Worker 
201*d57664e9SAndroid Build Coastguard Worker         delete[] mLFH.mExtraField;
202*d57664e9SAndroid Build Coastguard Worker         mLFH.mExtraField = newExtra;
203*d57664e9SAndroid Build Coastguard Worker         mLFH.mExtraFieldLength += padding;
204*d57664e9SAndroid Build Coastguard Worker     } else {
205*d57664e9SAndroid Build Coastguard Worker         /* create new field */
206*d57664e9SAndroid Build Coastguard Worker         mLFH.mExtraField = new unsigned char[padding];
207*d57664e9SAndroid Build Coastguard Worker         memset(mLFH.mExtraField, 0, padding);
208*d57664e9SAndroid Build Coastguard Worker         mLFH.mExtraFieldLength = padding;
209*d57664e9SAndroid Build Coastguard Worker     }
210*d57664e9SAndroid Build Coastguard Worker 
211*d57664e9SAndroid Build Coastguard Worker     return NO_ERROR;
212*d57664e9SAndroid Build Coastguard Worker }
213*d57664e9SAndroid Build Coastguard Worker 
214*d57664e9SAndroid Build Coastguard Worker /*
215*d57664e9SAndroid Build Coastguard Worker  * Set the fields in the LFH equal to the corresponding fields in the CDE.
216*d57664e9SAndroid Build Coastguard Worker  *
217*d57664e9SAndroid Build Coastguard Worker  * This does not touch the LFH "extra" field.
218*d57664e9SAndroid Build Coastguard Worker  */
copyCDEtoLFH(void)219*d57664e9SAndroid Build Coastguard Worker void ZipEntry::copyCDEtoLFH(void)
220*d57664e9SAndroid Build Coastguard Worker {
221*d57664e9SAndroid Build Coastguard Worker     mLFH.mVersionToExtract  = mCDE.mVersionToExtract;
222*d57664e9SAndroid Build Coastguard Worker     mLFH.mGPBitFlag         = mCDE.mGPBitFlag;
223*d57664e9SAndroid Build Coastguard Worker     mLFH.mCompressionMethod = mCDE.mCompressionMethod;
224*d57664e9SAndroid Build Coastguard Worker     mLFH.mLastModFileTime   = mCDE.mLastModFileTime;
225*d57664e9SAndroid Build Coastguard Worker     mLFH.mLastModFileDate   = mCDE.mLastModFileDate;
226*d57664e9SAndroid Build Coastguard Worker     mLFH.mCRC32             = mCDE.mCRC32;
227*d57664e9SAndroid Build Coastguard Worker     mLFH.mCompressedSize    = mCDE.mCompressedSize;
228*d57664e9SAndroid Build Coastguard Worker     mLFH.mUncompressedSize  = mCDE.mUncompressedSize;
229*d57664e9SAndroid Build Coastguard Worker     mLFH.mFileNameLength    = mCDE.mFileNameLength;
230*d57664e9SAndroid Build Coastguard Worker     // the "extra field" is independent
231*d57664e9SAndroid Build Coastguard Worker 
232*d57664e9SAndroid Build Coastguard Worker     delete[] mLFH.mFileName;
233*d57664e9SAndroid Build Coastguard Worker     if (mLFH.mFileNameLength > 0) {
234*d57664e9SAndroid Build Coastguard Worker         mLFH.mFileName = new unsigned char[mLFH.mFileNameLength+1];
235*d57664e9SAndroid Build Coastguard Worker         strcpy((char*) mLFH.mFileName, (const char*) mCDE.mFileName);
236*d57664e9SAndroid Build Coastguard Worker     } else {
237*d57664e9SAndroid Build Coastguard Worker         mLFH.mFileName = NULL;
238*d57664e9SAndroid Build Coastguard Worker     }
239*d57664e9SAndroid Build Coastguard Worker }
240*d57664e9SAndroid Build Coastguard Worker 
241*d57664e9SAndroid Build Coastguard Worker /*
242*d57664e9SAndroid Build Coastguard Worker  * Set some information about a file after we add it.
243*d57664e9SAndroid Build Coastguard Worker  */
setDataInfo(long uncompLen,long compLen,unsigned long crc32,int compressionMethod)244*d57664e9SAndroid Build Coastguard Worker void ZipEntry::setDataInfo(long uncompLen, long compLen, unsigned long crc32,
245*d57664e9SAndroid Build Coastguard Worker     int compressionMethod)
246*d57664e9SAndroid Build Coastguard Worker {
247*d57664e9SAndroid Build Coastguard Worker     mCDE.mCompressionMethod = compressionMethod;
248*d57664e9SAndroid Build Coastguard Worker     mCDE.mCRC32 = crc32;
249*d57664e9SAndroid Build Coastguard Worker     mCDE.mCompressedSize = compLen;
250*d57664e9SAndroid Build Coastguard Worker     mCDE.mUncompressedSize = uncompLen;
251*d57664e9SAndroid Build Coastguard Worker     mCDE.mCompressionMethod = compressionMethod;
252*d57664e9SAndroid Build Coastguard Worker     if (compressionMethod == kCompressDeflated) {
253*d57664e9SAndroid Build Coastguard Worker         mCDE.mGPBitFlag |= 0x0002;      // indicates maximum compression used
254*d57664e9SAndroid Build Coastguard Worker     }
255*d57664e9SAndroid Build Coastguard Worker     copyCDEtoLFH();
256*d57664e9SAndroid Build Coastguard Worker }
257*d57664e9SAndroid Build Coastguard Worker 
258*d57664e9SAndroid Build Coastguard Worker /*
259*d57664e9SAndroid Build Coastguard Worker  * See if the data in mCDE and mLFH match up.  This is mostly useful for
260*d57664e9SAndroid Build Coastguard Worker  * debugging these classes, but it can be used to identify damaged
261*d57664e9SAndroid Build Coastguard Worker  * archives.
262*d57664e9SAndroid Build Coastguard Worker  *
263*d57664e9SAndroid Build Coastguard Worker  * Returns "false" if they differ.
264*d57664e9SAndroid Build Coastguard Worker  */
compareHeaders(void) const265*d57664e9SAndroid Build Coastguard Worker bool ZipEntry::compareHeaders(void) const
266*d57664e9SAndroid Build Coastguard Worker {
267*d57664e9SAndroid Build Coastguard Worker     if (mCDE.mVersionToExtract != mLFH.mVersionToExtract) {
268*d57664e9SAndroid Build Coastguard Worker         ALOGV("cmp: VersionToExtract\n");
269*d57664e9SAndroid Build Coastguard Worker         return false;
270*d57664e9SAndroid Build Coastguard Worker     }
271*d57664e9SAndroid Build Coastguard Worker     if (mCDE.mGPBitFlag != mLFH.mGPBitFlag) {
272*d57664e9SAndroid Build Coastguard Worker         ALOGV("cmp: GPBitFlag\n");
273*d57664e9SAndroid Build Coastguard Worker         return false;
274*d57664e9SAndroid Build Coastguard Worker     }
275*d57664e9SAndroid Build Coastguard Worker     if (mCDE.mCompressionMethod != mLFH.mCompressionMethod) {
276*d57664e9SAndroid Build Coastguard Worker         ALOGV("cmp: CompressionMethod\n");
277*d57664e9SAndroid Build Coastguard Worker         return false;
278*d57664e9SAndroid Build Coastguard Worker     }
279*d57664e9SAndroid Build Coastguard Worker     if (mCDE.mLastModFileTime != mLFH.mLastModFileTime) {
280*d57664e9SAndroid Build Coastguard Worker         ALOGV("cmp: LastModFileTime\n");
281*d57664e9SAndroid Build Coastguard Worker         return false;
282*d57664e9SAndroid Build Coastguard Worker     }
283*d57664e9SAndroid Build Coastguard Worker     if (mCDE.mLastModFileDate != mLFH.mLastModFileDate) {
284*d57664e9SAndroid Build Coastguard Worker         ALOGV("cmp: LastModFileDate\n");
285*d57664e9SAndroid Build Coastguard Worker         return false;
286*d57664e9SAndroid Build Coastguard Worker     }
287*d57664e9SAndroid Build Coastguard Worker     if (mCDE.mCRC32 != mLFH.mCRC32) {
288*d57664e9SAndroid Build Coastguard Worker         ALOGV("cmp: CRC32\n");
289*d57664e9SAndroid Build Coastguard Worker         return false;
290*d57664e9SAndroid Build Coastguard Worker     }
291*d57664e9SAndroid Build Coastguard Worker     if (mCDE.mCompressedSize != mLFH.mCompressedSize) {
292*d57664e9SAndroid Build Coastguard Worker         ALOGV("cmp: CompressedSize\n");
293*d57664e9SAndroid Build Coastguard Worker         return false;
294*d57664e9SAndroid Build Coastguard Worker     }
295*d57664e9SAndroid Build Coastguard Worker     if (mCDE.mUncompressedSize != mLFH.mUncompressedSize) {
296*d57664e9SAndroid Build Coastguard Worker         ALOGV("cmp: UncompressedSize\n");
297*d57664e9SAndroid Build Coastguard Worker         return false;
298*d57664e9SAndroid Build Coastguard Worker     }
299*d57664e9SAndroid Build Coastguard Worker     if (mCDE.mFileNameLength != mLFH.mFileNameLength) {
300*d57664e9SAndroid Build Coastguard Worker         ALOGV("cmp: FileNameLength\n");
301*d57664e9SAndroid Build Coastguard Worker         return false;
302*d57664e9SAndroid Build Coastguard Worker     }
303*d57664e9SAndroid Build Coastguard Worker #if 0       // this seems to be used for padding, not real data
304*d57664e9SAndroid Build Coastguard Worker     if (mCDE.mExtraFieldLength != mLFH.mExtraFieldLength) {
305*d57664e9SAndroid Build Coastguard Worker         ALOGV("cmp: ExtraFieldLength\n");
306*d57664e9SAndroid Build Coastguard Worker         return false;
307*d57664e9SAndroid Build Coastguard Worker     }
308*d57664e9SAndroid Build Coastguard Worker #endif
309*d57664e9SAndroid Build Coastguard Worker     if (mCDE.mFileName != NULL) {
310*d57664e9SAndroid Build Coastguard Worker         if (strcmp((char*) mCDE.mFileName, (char*) mLFH.mFileName) != 0) {
311*d57664e9SAndroid Build Coastguard Worker             ALOGV("cmp: FileName\n");
312*d57664e9SAndroid Build Coastguard Worker             return false;
313*d57664e9SAndroid Build Coastguard Worker         }
314*d57664e9SAndroid Build Coastguard Worker     }
315*d57664e9SAndroid Build Coastguard Worker 
316*d57664e9SAndroid Build Coastguard Worker     return true;
317*d57664e9SAndroid Build Coastguard Worker }
318*d57664e9SAndroid Build Coastguard Worker 
319*d57664e9SAndroid Build Coastguard Worker 
320*d57664e9SAndroid Build Coastguard Worker /*
321*d57664e9SAndroid Build Coastguard Worker  * Convert the DOS date/time stamp into a UNIX time stamp.
322*d57664e9SAndroid Build Coastguard Worker  */
getModWhen(void) const323*d57664e9SAndroid Build Coastguard Worker time_t ZipEntry::getModWhen(void) const
324*d57664e9SAndroid Build Coastguard Worker {
325*d57664e9SAndroid Build Coastguard Worker     struct tm parts;
326*d57664e9SAndroid Build Coastguard Worker 
327*d57664e9SAndroid Build Coastguard Worker     parts.tm_sec = (mCDE.mLastModFileTime & 0x001f) << 1;
328*d57664e9SAndroid Build Coastguard Worker     parts.tm_min = (mCDE.mLastModFileTime & 0x07e0) >> 5;
329*d57664e9SAndroid Build Coastguard Worker     parts.tm_hour = (mCDE.mLastModFileTime & 0xf800) >> 11;
330*d57664e9SAndroid Build Coastguard Worker     parts.tm_mday = (mCDE.mLastModFileDate & 0x001f);
331*d57664e9SAndroid Build Coastguard Worker     parts.tm_mon = ((mCDE.mLastModFileDate & 0x01e0) >> 5) -1;
332*d57664e9SAndroid Build Coastguard Worker     parts.tm_year = ((mCDE.mLastModFileDate & 0xfe00) >> 9) + 80;
333*d57664e9SAndroid Build Coastguard Worker     parts.tm_wday = parts.tm_yday = 0;
334*d57664e9SAndroid Build Coastguard Worker     parts.tm_isdst = -1;        // DST info "not available"
335*d57664e9SAndroid Build Coastguard Worker 
336*d57664e9SAndroid Build Coastguard Worker     return mktime(&parts);
337*d57664e9SAndroid Build Coastguard Worker }
338*d57664e9SAndroid Build Coastguard Worker 
339*d57664e9SAndroid Build Coastguard Worker /*
340*d57664e9SAndroid Build Coastguard Worker  * Set the CDE/LFH timestamp from UNIX time.
341*d57664e9SAndroid Build Coastguard Worker  */
setModWhen(time_t when)342*d57664e9SAndroid Build Coastguard Worker void ZipEntry::setModWhen(time_t when) {
343*d57664e9SAndroid Build Coastguard Worker     /* round up to an even number of seconds */
344*d57664e9SAndroid Build Coastguard Worker     time_t even = (time_t)(((unsigned long)(when) + 1) & (~1));
345*d57664e9SAndroid Build Coastguard Worker 
346*d57664e9SAndroid Build Coastguard Worker     /* expand */
347*d57664e9SAndroid Build Coastguard Worker     struct tm tmResult;
348*d57664e9SAndroid Build Coastguard Worker     struct tm* ptm = localtime_r(&even, &tmResult);
349*d57664e9SAndroid Build Coastguard Worker 
350*d57664e9SAndroid Build Coastguard Worker     int year;
351*d57664e9SAndroid Build Coastguard Worker     year = ptm->tm_year;
352*d57664e9SAndroid Build Coastguard Worker     if (year < 80)
353*d57664e9SAndroid Build Coastguard Worker         year = 80;
354*d57664e9SAndroid Build Coastguard Worker 
355*d57664e9SAndroid Build Coastguard Worker     unsigned short zdate = (year - 80) << 9 | (ptm->tm_mon + 1) << 5 | ptm->tm_mday;
356*d57664e9SAndroid Build Coastguard Worker     unsigned short ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
357*d57664e9SAndroid Build Coastguard Worker 
358*d57664e9SAndroid Build Coastguard Worker     mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime;
359*d57664e9SAndroid Build Coastguard Worker     mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate;
360*d57664e9SAndroid Build Coastguard Worker }
361*d57664e9SAndroid Build Coastguard Worker 
362*d57664e9SAndroid Build Coastguard Worker /*
363*d57664e9SAndroid Build Coastguard Worker  * ===========================================================================
364*d57664e9SAndroid Build Coastguard Worker  *      ZipEntry::LocalFileHeader
365*d57664e9SAndroid Build Coastguard Worker  * ===========================================================================
366*d57664e9SAndroid Build Coastguard Worker  */
367*d57664e9SAndroid Build Coastguard Worker 
368*d57664e9SAndroid Build Coastguard Worker /*
369*d57664e9SAndroid Build Coastguard Worker  * Read a local file header.
370*d57664e9SAndroid Build Coastguard Worker  *
371*d57664e9SAndroid Build Coastguard Worker  * On entry, "fp" points to the signature at the start of the header.
372*d57664e9SAndroid Build Coastguard Worker  * On exit, "fp" points to the start of data.
373*d57664e9SAndroid Build Coastguard Worker  */
read(FILE * fp)374*d57664e9SAndroid Build Coastguard Worker status_t ZipEntry::LocalFileHeader::read(FILE* fp)
375*d57664e9SAndroid Build Coastguard Worker {
376*d57664e9SAndroid Build Coastguard Worker     status_t result = NO_ERROR;
377*d57664e9SAndroid Build Coastguard Worker     unsigned char buf[kLFHLen];
378*d57664e9SAndroid Build Coastguard Worker 
379*d57664e9SAndroid Build Coastguard Worker     assert(mFileName == NULL);
380*d57664e9SAndroid Build Coastguard Worker     assert(mExtraField == NULL);
381*d57664e9SAndroid Build Coastguard Worker 
382*d57664e9SAndroid Build Coastguard Worker     if (fread(buf, 1, kLFHLen, fp) != kLFHLen) {
383*d57664e9SAndroid Build Coastguard Worker         result = UNKNOWN_ERROR;
384*d57664e9SAndroid Build Coastguard Worker         goto bail;
385*d57664e9SAndroid Build Coastguard Worker     }
386*d57664e9SAndroid Build Coastguard Worker 
387*d57664e9SAndroid Build Coastguard Worker     if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
388*d57664e9SAndroid Build Coastguard Worker         ALOGD("whoops: didn't find expected signature\n");
389*d57664e9SAndroid Build Coastguard Worker         result = UNKNOWN_ERROR;
390*d57664e9SAndroid Build Coastguard Worker         goto bail;
391*d57664e9SAndroid Build Coastguard Worker     }
392*d57664e9SAndroid Build Coastguard Worker 
393*d57664e9SAndroid Build Coastguard Worker     mVersionToExtract = ZipEntry::getShortLE(&buf[0x04]);
394*d57664e9SAndroid Build Coastguard Worker     mGPBitFlag = ZipEntry::getShortLE(&buf[0x06]);
395*d57664e9SAndroid Build Coastguard Worker     mCompressionMethod = ZipEntry::getShortLE(&buf[0x08]);
396*d57664e9SAndroid Build Coastguard Worker     mLastModFileTime = ZipEntry::getShortLE(&buf[0x0a]);
397*d57664e9SAndroid Build Coastguard Worker     mLastModFileDate = ZipEntry::getShortLE(&buf[0x0c]);
398*d57664e9SAndroid Build Coastguard Worker     mCRC32 = ZipEntry::getLongLE(&buf[0x0e]);
399*d57664e9SAndroid Build Coastguard Worker     mCompressedSize = ZipEntry::getLongLE(&buf[0x12]);
400*d57664e9SAndroid Build Coastguard Worker     mUncompressedSize = ZipEntry::getLongLE(&buf[0x16]);
401*d57664e9SAndroid Build Coastguard Worker     mFileNameLength = ZipEntry::getShortLE(&buf[0x1a]);
402*d57664e9SAndroid Build Coastguard Worker     mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1c]);
403*d57664e9SAndroid Build Coastguard Worker 
404*d57664e9SAndroid Build Coastguard Worker     // TODO: validate sizes
405*d57664e9SAndroid Build Coastguard Worker 
406*d57664e9SAndroid Build Coastguard Worker     /* grab filename */
407*d57664e9SAndroid Build Coastguard Worker     if (mFileNameLength != 0) {
408*d57664e9SAndroid Build Coastguard Worker         mFileName = new unsigned char[mFileNameLength+1];
409*d57664e9SAndroid Build Coastguard Worker         if (mFileName == NULL) {
410*d57664e9SAndroid Build Coastguard Worker             result = NO_MEMORY;
411*d57664e9SAndroid Build Coastguard Worker             goto bail;
412*d57664e9SAndroid Build Coastguard Worker         }
413*d57664e9SAndroid Build Coastguard Worker         if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
414*d57664e9SAndroid Build Coastguard Worker             result = UNKNOWN_ERROR;
415*d57664e9SAndroid Build Coastguard Worker             goto bail;
416*d57664e9SAndroid Build Coastguard Worker         }
417*d57664e9SAndroid Build Coastguard Worker         mFileName[mFileNameLength] = '\0';
418*d57664e9SAndroid Build Coastguard Worker     }
419*d57664e9SAndroid Build Coastguard Worker 
420*d57664e9SAndroid Build Coastguard Worker     /* grab extra field */
421*d57664e9SAndroid Build Coastguard Worker     if (mExtraFieldLength != 0) {
422*d57664e9SAndroid Build Coastguard Worker         mExtraField = new unsigned char[mExtraFieldLength+1];
423*d57664e9SAndroid Build Coastguard Worker         if (mExtraField == NULL) {
424*d57664e9SAndroid Build Coastguard Worker             result = NO_MEMORY;
425*d57664e9SAndroid Build Coastguard Worker             goto bail;
426*d57664e9SAndroid Build Coastguard Worker         }
427*d57664e9SAndroid Build Coastguard Worker         if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
428*d57664e9SAndroid Build Coastguard Worker             result = UNKNOWN_ERROR;
429*d57664e9SAndroid Build Coastguard Worker             goto bail;
430*d57664e9SAndroid Build Coastguard Worker         }
431*d57664e9SAndroid Build Coastguard Worker         mExtraField[mExtraFieldLength] = '\0';
432*d57664e9SAndroid Build Coastguard Worker     }
433*d57664e9SAndroid Build Coastguard Worker 
434*d57664e9SAndroid Build Coastguard Worker bail:
435*d57664e9SAndroid Build Coastguard Worker     return result;
436*d57664e9SAndroid Build Coastguard Worker }
437*d57664e9SAndroid Build Coastguard Worker 
438*d57664e9SAndroid Build Coastguard Worker /*
439*d57664e9SAndroid Build Coastguard Worker  * Write a local file header.
440*d57664e9SAndroid Build Coastguard Worker  */
write(FILE * fp)441*d57664e9SAndroid Build Coastguard Worker status_t ZipEntry::LocalFileHeader::write(FILE* fp)
442*d57664e9SAndroid Build Coastguard Worker {
443*d57664e9SAndroid Build Coastguard Worker     unsigned char buf[kLFHLen];
444*d57664e9SAndroid Build Coastguard Worker 
445*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putLongLE(&buf[0x00], kSignature);
446*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x04], mVersionToExtract);
447*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x06], mGPBitFlag);
448*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x08], mCompressionMethod);
449*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x0a], mLastModFileTime);
450*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x0c], mLastModFileDate);
451*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putLongLE(&buf[0x0e], mCRC32);
452*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putLongLE(&buf[0x12], mCompressedSize);
453*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putLongLE(&buf[0x16], mUncompressedSize);
454*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x1a], mFileNameLength);
455*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x1c], mExtraFieldLength);
456*d57664e9SAndroid Build Coastguard Worker 
457*d57664e9SAndroid Build Coastguard Worker     if (fwrite(buf, 1, kLFHLen, fp) != kLFHLen)
458*d57664e9SAndroid Build Coastguard Worker         return UNKNOWN_ERROR;
459*d57664e9SAndroid Build Coastguard Worker 
460*d57664e9SAndroid Build Coastguard Worker     /* write filename */
461*d57664e9SAndroid Build Coastguard Worker     if (mFileNameLength != 0) {
462*d57664e9SAndroid Build Coastguard Worker         if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
463*d57664e9SAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
464*d57664e9SAndroid Build Coastguard Worker     }
465*d57664e9SAndroid Build Coastguard Worker 
466*d57664e9SAndroid Build Coastguard Worker     /* write "extra field" */
467*d57664e9SAndroid Build Coastguard Worker     if (mExtraFieldLength != 0) {
468*d57664e9SAndroid Build Coastguard Worker         if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
469*d57664e9SAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
470*d57664e9SAndroid Build Coastguard Worker     }
471*d57664e9SAndroid Build Coastguard Worker 
472*d57664e9SAndroid Build Coastguard Worker     return NO_ERROR;
473*d57664e9SAndroid Build Coastguard Worker }
474*d57664e9SAndroid Build Coastguard Worker 
475*d57664e9SAndroid Build Coastguard Worker 
476*d57664e9SAndroid Build Coastguard Worker /*
477*d57664e9SAndroid Build Coastguard Worker  * Dump the contents of a LocalFileHeader object.
478*d57664e9SAndroid Build Coastguard Worker  */
dump(void) const479*d57664e9SAndroid Build Coastguard Worker void ZipEntry::LocalFileHeader::dump(void) const
480*d57664e9SAndroid Build Coastguard Worker {
481*d57664e9SAndroid Build Coastguard Worker     ALOGD(" LocalFileHeader contents:\n");
482*d57664e9SAndroid Build Coastguard Worker     ALOGD("  versToExt=%u gpBits=0x%04x compression=%u\n",
483*d57664e9SAndroid Build Coastguard Worker         mVersionToExtract, mGPBitFlag, mCompressionMethod);
484*d57664e9SAndroid Build Coastguard Worker     ALOGD("  modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
485*d57664e9SAndroid Build Coastguard Worker         mLastModFileTime, mLastModFileDate, mCRC32);
486*d57664e9SAndroid Build Coastguard Worker     ALOGD("  compressedSize=%lu uncompressedSize=%lu\n",
487*d57664e9SAndroid Build Coastguard Worker         mCompressedSize, mUncompressedSize);
488*d57664e9SAndroid Build Coastguard Worker     ALOGD("  filenameLen=%u extraLen=%u\n",
489*d57664e9SAndroid Build Coastguard Worker         mFileNameLength, mExtraFieldLength);
490*d57664e9SAndroid Build Coastguard Worker     if (mFileName != NULL)
491*d57664e9SAndroid Build Coastguard Worker         ALOGD("  filename: '%s'\n", mFileName);
492*d57664e9SAndroid Build Coastguard Worker }
493*d57664e9SAndroid Build Coastguard Worker 
494*d57664e9SAndroid Build Coastguard Worker 
495*d57664e9SAndroid Build Coastguard Worker /*
496*d57664e9SAndroid Build Coastguard Worker  * ===========================================================================
497*d57664e9SAndroid Build Coastguard Worker  *      ZipEntry::CentralDirEntry
498*d57664e9SAndroid Build Coastguard Worker  * ===========================================================================
499*d57664e9SAndroid Build Coastguard Worker  */
500*d57664e9SAndroid Build Coastguard Worker 
501*d57664e9SAndroid Build Coastguard Worker /*
502*d57664e9SAndroid Build Coastguard Worker  * Read the central dir entry that appears next in the file.
503*d57664e9SAndroid Build Coastguard Worker  *
504*d57664e9SAndroid Build Coastguard Worker  * On entry, "fp" should be positioned on the signature bytes for the
505*d57664e9SAndroid Build Coastguard Worker  * entry.  On exit, "fp" will point at the signature word for the next
506*d57664e9SAndroid Build Coastguard Worker  * entry or for the EOCD.
507*d57664e9SAndroid Build Coastguard Worker  */
read(FILE * fp)508*d57664e9SAndroid Build Coastguard Worker status_t ZipEntry::CentralDirEntry::read(FILE* fp)
509*d57664e9SAndroid Build Coastguard Worker {
510*d57664e9SAndroid Build Coastguard Worker     status_t result = NO_ERROR;
511*d57664e9SAndroid Build Coastguard Worker     unsigned char buf[kCDELen];
512*d57664e9SAndroid Build Coastguard Worker 
513*d57664e9SAndroid Build Coastguard Worker     /* no re-use */
514*d57664e9SAndroid Build Coastguard Worker     assert(mFileName == NULL);
515*d57664e9SAndroid Build Coastguard Worker     assert(mExtraField == NULL);
516*d57664e9SAndroid Build Coastguard Worker     assert(mFileComment == NULL);
517*d57664e9SAndroid Build Coastguard Worker 
518*d57664e9SAndroid Build Coastguard Worker     if (fread(buf, 1, kCDELen, fp) != kCDELen) {
519*d57664e9SAndroid Build Coastguard Worker         result = UNKNOWN_ERROR;
520*d57664e9SAndroid Build Coastguard Worker         goto bail;
521*d57664e9SAndroid Build Coastguard Worker     }
522*d57664e9SAndroid Build Coastguard Worker 
523*d57664e9SAndroid Build Coastguard Worker     if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
524*d57664e9SAndroid Build Coastguard Worker         ALOGD("Whoops: didn't find expected signature\n");
525*d57664e9SAndroid Build Coastguard Worker         result = UNKNOWN_ERROR;
526*d57664e9SAndroid Build Coastguard Worker         goto bail;
527*d57664e9SAndroid Build Coastguard Worker     }
528*d57664e9SAndroid Build Coastguard Worker 
529*d57664e9SAndroid Build Coastguard Worker     mVersionMadeBy = ZipEntry::getShortLE(&buf[0x04]);
530*d57664e9SAndroid Build Coastguard Worker     mVersionToExtract = ZipEntry::getShortLE(&buf[0x06]);
531*d57664e9SAndroid Build Coastguard Worker     mGPBitFlag = ZipEntry::getShortLE(&buf[0x08]);
532*d57664e9SAndroid Build Coastguard Worker     mCompressionMethod = ZipEntry::getShortLE(&buf[0x0a]);
533*d57664e9SAndroid Build Coastguard Worker     mLastModFileTime = ZipEntry::getShortLE(&buf[0x0c]);
534*d57664e9SAndroid Build Coastguard Worker     mLastModFileDate = ZipEntry::getShortLE(&buf[0x0e]);
535*d57664e9SAndroid Build Coastguard Worker     mCRC32 = ZipEntry::getLongLE(&buf[0x10]);
536*d57664e9SAndroid Build Coastguard Worker     mCompressedSize = ZipEntry::getLongLE(&buf[0x14]);
537*d57664e9SAndroid Build Coastguard Worker     mUncompressedSize = ZipEntry::getLongLE(&buf[0x18]);
538*d57664e9SAndroid Build Coastguard Worker     mFileNameLength = ZipEntry::getShortLE(&buf[0x1c]);
539*d57664e9SAndroid Build Coastguard Worker     mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1e]);
540*d57664e9SAndroid Build Coastguard Worker     mFileCommentLength = ZipEntry::getShortLE(&buf[0x20]);
541*d57664e9SAndroid Build Coastguard Worker     mDiskNumberStart = ZipEntry::getShortLE(&buf[0x22]);
542*d57664e9SAndroid Build Coastguard Worker     mInternalAttrs = ZipEntry::getShortLE(&buf[0x24]);
543*d57664e9SAndroid Build Coastguard Worker     mExternalAttrs = ZipEntry::getLongLE(&buf[0x26]);
544*d57664e9SAndroid Build Coastguard Worker     mLocalHeaderRelOffset = ZipEntry::getLongLE(&buf[0x2a]);
545*d57664e9SAndroid Build Coastguard Worker 
546*d57664e9SAndroid Build Coastguard Worker     // TODO: validate sizes and offsets
547*d57664e9SAndroid Build Coastguard Worker 
548*d57664e9SAndroid Build Coastguard Worker     /* grab filename */
549*d57664e9SAndroid Build Coastguard Worker     if (mFileNameLength != 0) {
550*d57664e9SAndroid Build Coastguard Worker         mFileName = new unsigned char[mFileNameLength+1];
551*d57664e9SAndroid Build Coastguard Worker         if (mFileName == NULL) {
552*d57664e9SAndroid Build Coastguard Worker             result = NO_MEMORY;
553*d57664e9SAndroid Build Coastguard Worker             goto bail;
554*d57664e9SAndroid Build Coastguard Worker         }
555*d57664e9SAndroid Build Coastguard Worker         if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
556*d57664e9SAndroid Build Coastguard Worker             result = UNKNOWN_ERROR;
557*d57664e9SAndroid Build Coastguard Worker             goto bail;
558*d57664e9SAndroid Build Coastguard Worker         }
559*d57664e9SAndroid Build Coastguard Worker         mFileName[mFileNameLength] = '\0';
560*d57664e9SAndroid Build Coastguard Worker     }
561*d57664e9SAndroid Build Coastguard Worker 
562*d57664e9SAndroid Build Coastguard Worker     /* read "extra field" */
563*d57664e9SAndroid Build Coastguard Worker     if (mExtraFieldLength != 0) {
564*d57664e9SAndroid Build Coastguard Worker         mExtraField = new unsigned char[mExtraFieldLength+1];
565*d57664e9SAndroid Build Coastguard Worker         if (mExtraField == NULL) {
566*d57664e9SAndroid Build Coastguard Worker             result = NO_MEMORY;
567*d57664e9SAndroid Build Coastguard Worker             goto bail;
568*d57664e9SAndroid Build Coastguard Worker         }
569*d57664e9SAndroid Build Coastguard Worker         if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
570*d57664e9SAndroid Build Coastguard Worker             result = UNKNOWN_ERROR;
571*d57664e9SAndroid Build Coastguard Worker             goto bail;
572*d57664e9SAndroid Build Coastguard Worker         }
573*d57664e9SAndroid Build Coastguard Worker         mExtraField[mExtraFieldLength] = '\0';
574*d57664e9SAndroid Build Coastguard Worker     }
575*d57664e9SAndroid Build Coastguard Worker 
576*d57664e9SAndroid Build Coastguard Worker 
577*d57664e9SAndroid Build Coastguard Worker     /* grab comment, if any */
578*d57664e9SAndroid Build Coastguard Worker     if (mFileCommentLength != 0) {
579*d57664e9SAndroid Build Coastguard Worker         mFileComment = new unsigned char[mFileCommentLength+1];
580*d57664e9SAndroid Build Coastguard Worker         if (mFileComment == NULL) {
581*d57664e9SAndroid Build Coastguard Worker             result = NO_MEMORY;
582*d57664e9SAndroid Build Coastguard Worker             goto bail;
583*d57664e9SAndroid Build Coastguard Worker         }
584*d57664e9SAndroid Build Coastguard Worker         if (fread(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
585*d57664e9SAndroid Build Coastguard Worker         {
586*d57664e9SAndroid Build Coastguard Worker             result = UNKNOWN_ERROR;
587*d57664e9SAndroid Build Coastguard Worker             goto bail;
588*d57664e9SAndroid Build Coastguard Worker         }
589*d57664e9SAndroid Build Coastguard Worker         mFileComment[mFileCommentLength] = '\0';
590*d57664e9SAndroid Build Coastguard Worker     }
591*d57664e9SAndroid Build Coastguard Worker 
592*d57664e9SAndroid Build Coastguard Worker bail:
593*d57664e9SAndroid Build Coastguard Worker     return result;
594*d57664e9SAndroid Build Coastguard Worker }
595*d57664e9SAndroid Build Coastguard Worker 
596*d57664e9SAndroid Build Coastguard Worker /*
597*d57664e9SAndroid Build Coastguard Worker  * Write a central dir entry.
598*d57664e9SAndroid Build Coastguard Worker  */
write(FILE * fp)599*d57664e9SAndroid Build Coastguard Worker status_t ZipEntry::CentralDirEntry::write(FILE* fp)
600*d57664e9SAndroid Build Coastguard Worker {
601*d57664e9SAndroid Build Coastguard Worker     unsigned char buf[kCDELen];
602*d57664e9SAndroid Build Coastguard Worker 
603*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putLongLE(&buf[0x00], kSignature);
604*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x04], mVersionMadeBy);
605*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x06], mVersionToExtract);
606*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x08], mGPBitFlag);
607*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x0a], mCompressionMethod);
608*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x0c], mLastModFileTime);
609*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x0e], mLastModFileDate);
610*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putLongLE(&buf[0x10], mCRC32);
611*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putLongLE(&buf[0x14], mCompressedSize);
612*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putLongLE(&buf[0x18], mUncompressedSize);
613*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x1c], mFileNameLength);
614*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x1e], mExtraFieldLength);
615*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x20], mFileCommentLength);
616*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x22], mDiskNumberStart);
617*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putShortLE(&buf[0x24], mInternalAttrs);
618*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putLongLE(&buf[0x26], mExternalAttrs);
619*d57664e9SAndroid Build Coastguard Worker     ZipEntry::putLongLE(&buf[0x2a], mLocalHeaderRelOffset);
620*d57664e9SAndroid Build Coastguard Worker 
621*d57664e9SAndroid Build Coastguard Worker     if (fwrite(buf, 1, kCDELen, fp) != kCDELen)
622*d57664e9SAndroid Build Coastguard Worker         return UNKNOWN_ERROR;
623*d57664e9SAndroid Build Coastguard Worker 
624*d57664e9SAndroid Build Coastguard Worker     /* write filename */
625*d57664e9SAndroid Build Coastguard Worker     if (mFileNameLength != 0) {
626*d57664e9SAndroid Build Coastguard Worker         if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
627*d57664e9SAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
628*d57664e9SAndroid Build Coastguard Worker     }
629*d57664e9SAndroid Build Coastguard Worker 
630*d57664e9SAndroid Build Coastguard Worker     /* write "extra field" */
631*d57664e9SAndroid Build Coastguard Worker     if (mExtraFieldLength != 0) {
632*d57664e9SAndroid Build Coastguard Worker         if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
633*d57664e9SAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
634*d57664e9SAndroid Build Coastguard Worker     }
635*d57664e9SAndroid Build Coastguard Worker 
636*d57664e9SAndroid Build Coastguard Worker     /* write comment */
637*d57664e9SAndroid Build Coastguard Worker     if (mFileCommentLength != 0) {
638*d57664e9SAndroid Build Coastguard Worker         if (fwrite(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
639*d57664e9SAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
640*d57664e9SAndroid Build Coastguard Worker     }
641*d57664e9SAndroid Build Coastguard Worker 
642*d57664e9SAndroid Build Coastguard Worker     return NO_ERROR;
643*d57664e9SAndroid Build Coastguard Worker }
644*d57664e9SAndroid Build Coastguard Worker 
645*d57664e9SAndroid Build Coastguard Worker /*
646*d57664e9SAndroid Build Coastguard Worker  * Dump the contents of a CentralDirEntry object.
647*d57664e9SAndroid Build Coastguard Worker  */
dump(void) const648*d57664e9SAndroid Build Coastguard Worker void ZipEntry::CentralDirEntry::dump(void) const
649*d57664e9SAndroid Build Coastguard Worker {
650*d57664e9SAndroid Build Coastguard Worker     ALOGD(" CentralDirEntry contents:\n");
651*d57664e9SAndroid Build Coastguard Worker     ALOGD("  versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n",
652*d57664e9SAndroid Build Coastguard Worker         mVersionMadeBy, mVersionToExtract, mGPBitFlag, mCompressionMethod);
653*d57664e9SAndroid Build Coastguard Worker     ALOGD("  modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
654*d57664e9SAndroid Build Coastguard Worker         mLastModFileTime, mLastModFileDate, mCRC32);
655*d57664e9SAndroid Build Coastguard Worker     ALOGD("  compressedSize=%lu uncompressedSize=%lu\n",
656*d57664e9SAndroid Build Coastguard Worker         mCompressedSize, mUncompressedSize);
657*d57664e9SAndroid Build Coastguard Worker     ALOGD("  filenameLen=%u extraLen=%u commentLen=%u\n",
658*d57664e9SAndroid Build Coastguard Worker         mFileNameLength, mExtraFieldLength, mFileCommentLength);
659*d57664e9SAndroid Build Coastguard Worker     ALOGD("  diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n",
660*d57664e9SAndroid Build Coastguard Worker         mDiskNumberStart, mInternalAttrs, mExternalAttrs,
661*d57664e9SAndroid Build Coastguard Worker         mLocalHeaderRelOffset);
662*d57664e9SAndroid Build Coastguard Worker 
663*d57664e9SAndroid Build Coastguard Worker     if (mFileName != NULL)
664*d57664e9SAndroid Build Coastguard Worker         ALOGD("  filename: '%s'\n", mFileName);
665*d57664e9SAndroid Build Coastguard Worker     if (mFileComment != NULL)
666*d57664e9SAndroid Build Coastguard Worker         ALOGD("  comment: '%s'\n", mFileComment);
667*d57664e9SAndroid Build Coastguard Worker }
668*d57664e9SAndroid Build Coastguard Worker 
669*d57664e9SAndroid Build Coastguard Worker /*
670*d57664e9SAndroid Build Coastguard Worker  * Copy-assignment operator for CentralDirEntry.
671*d57664e9SAndroid Build Coastguard Worker  */
operator =(const ZipEntry::CentralDirEntry & src)672*d57664e9SAndroid Build Coastguard Worker ZipEntry::CentralDirEntry& ZipEntry::CentralDirEntry::operator=(const ZipEntry::CentralDirEntry& src) {
673*d57664e9SAndroid Build Coastguard Worker     if (this == &src) {
674*d57664e9SAndroid Build Coastguard Worker         return *this;
675*d57664e9SAndroid Build Coastguard Worker     }
676*d57664e9SAndroid Build Coastguard Worker 
677*d57664e9SAndroid Build Coastguard Worker     // Free up old data.
678*d57664e9SAndroid Build Coastguard Worker     delete[] mFileName;
679*d57664e9SAndroid Build Coastguard Worker     delete[] mExtraField;
680*d57664e9SAndroid Build Coastguard Worker     delete[] mFileComment;
681*d57664e9SAndroid Build Coastguard Worker 
682*d57664e9SAndroid Build Coastguard Worker     // Copy scalars.
683*d57664e9SAndroid Build Coastguard Worker     mVersionMadeBy = src.mVersionMadeBy;
684*d57664e9SAndroid Build Coastguard Worker     mVersionToExtract = src.mVersionToExtract;
685*d57664e9SAndroid Build Coastguard Worker     mGPBitFlag = src.mGPBitFlag;
686*d57664e9SAndroid Build Coastguard Worker     mCompressionMethod = src.mCompressionMethod;
687*d57664e9SAndroid Build Coastguard Worker     mLastModFileTime = src.mLastModFileTime;
688*d57664e9SAndroid Build Coastguard Worker     mLastModFileDate = src.mLastModFileDate;
689*d57664e9SAndroid Build Coastguard Worker     mCRC32 = src.mCRC32;
690*d57664e9SAndroid Build Coastguard Worker     mCompressedSize = src.mCompressedSize;
691*d57664e9SAndroid Build Coastguard Worker     mUncompressedSize = src.mUncompressedSize;
692*d57664e9SAndroid Build Coastguard Worker     mFileNameLength = src.mFileNameLength;
693*d57664e9SAndroid Build Coastguard Worker     mExtraFieldLength = src.mExtraFieldLength;
694*d57664e9SAndroid Build Coastguard Worker     mFileCommentLength = src.mFileCommentLength;
695*d57664e9SAndroid Build Coastguard Worker     mDiskNumberStart = src.mDiskNumberStart;
696*d57664e9SAndroid Build Coastguard Worker     mInternalAttrs = src.mInternalAttrs;
697*d57664e9SAndroid Build Coastguard Worker     mExternalAttrs = src.mExternalAttrs;
698*d57664e9SAndroid Build Coastguard Worker     mLocalHeaderRelOffset = src.mLocalHeaderRelOffset;
699*d57664e9SAndroid Build Coastguard Worker 
700*d57664e9SAndroid Build Coastguard Worker     // Copy strings, if necessary.
701*d57664e9SAndroid Build Coastguard Worker     if (mFileNameLength > 0) {
702*d57664e9SAndroid Build Coastguard Worker         mFileName = new unsigned char[mFileNameLength + 1];
703*d57664e9SAndroid Build Coastguard Worker         if (mFileName != NULL)
704*d57664e9SAndroid Build Coastguard Worker             strcpy((char*)mFileName, (char*)src.mFileName);
705*d57664e9SAndroid Build Coastguard Worker     } else {
706*d57664e9SAndroid Build Coastguard Worker         mFileName = NULL;
707*d57664e9SAndroid Build Coastguard Worker     }
708*d57664e9SAndroid Build Coastguard Worker     if (mFileCommentLength > 0) {
709*d57664e9SAndroid Build Coastguard Worker         mFileComment = new unsigned char[mFileCommentLength + 1];
710*d57664e9SAndroid Build Coastguard Worker         if (mFileComment != NULL)
711*d57664e9SAndroid Build Coastguard Worker             strcpy((char*)mFileComment, (char*)src.mFileComment);
712*d57664e9SAndroid Build Coastguard Worker     } else {
713*d57664e9SAndroid Build Coastguard Worker         mFileComment = NULL;
714*d57664e9SAndroid Build Coastguard Worker     }
715*d57664e9SAndroid Build Coastguard Worker     if (mExtraFieldLength > 0) {
716*d57664e9SAndroid Build Coastguard Worker         /* we null-terminate this, though it may not be a string */
717*d57664e9SAndroid Build Coastguard Worker         mExtraField = new unsigned char[mExtraFieldLength + 1];
718*d57664e9SAndroid Build Coastguard Worker         if (mExtraField != NULL)
719*d57664e9SAndroid Build Coastguard Worker             memcpy(mExtraField, src.mExtraField, mExtraFieldLength + 1);
720*d57664e9SAndroid Build Coastguard Worker     } else {
721*d57664e9SAndroid Build Coastguard Worker         mExtraField = NULL;
722*d57664e9SAndroid Build Coastguard Worker     }
723*d57664e9SAndroid Build Coastguard Worker 
724*d57664e9SAndroid Build Coastguard Worker     return *this;
725*d57664e9SAndroid Build Coastguard Worker }
726