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