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