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