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