blob: 891b4e1e2d3c14f98a63778998e6e3d121e31c38 [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 */,
Adam Lesinskid5c4f872015-04-21 13:56:10 -0700147 const ZipEntry* pEntry, const char* storageName)
Adam Lesinski769de982015-04-10 19:43:55 -0700148{
149 mCDE = pEntry->mCDE;
Adam Lesinskid5c4f872015-04-21 13:56:10 -0700150 if (storageName && *storageName != 0) {
151 mCDE.mFileNameLength = strlen(storageName);
152 mCDE.mFileName = new unsigned char[mCDE.mFileNameLength + 1];
153 strcpy((char*) mCDE.mFileName, storageName);
154 }
155
Adam Lesinski769de982015-04-10 19:43:55 -0700156 // Check whether we got all the memory needed.
157 if ((mCDE.mFileNameLength > 0 && mCDE.mFileName == NULL) ||
158 (mCDE.mFileCommentLength > 0 && mCDE.mFileComment == NULL) ||
159 (mCDE.mExtraFieldLength > 0 && mCDE.mExtraField == NULL)) {
160 return NO_MEMORY;
161 }
162
163 /* construct the LFH from the CDE */
164 copyCDEtoLFH();
165
166 /*
167 * The LFH "extra" field is independent of the CDE "extra", so we
168 * handle it here.
169 */
170 assert(mLFH.mExtraField == NULL);
171 mLFH.mExtraFieldLength = pEntry->mLFH.mExtraFieldLength;
172 if (mLFH.mExtraFieldLength > 0) {
173 mLFH.mExtraField = new unsigned char[mLFH.mExtraFieldLength+1];
174 if (mLFH.mExtraField == NULL)
175 return NO_MEMORY;
176 memcpy(mLFH.mExtraField, pEntry->mLFH.mExtraField,
177 mLFH.mExtraFieldLength+1);
178 }
179
180 return NO_ERROR;
181}
182
183/*
184 * Insert pad bytes in the LFH by tweaking the "extra" field. This will
185 * potentially confuse something that put "extra" data in here earlier,
186 * but I can't find an actual problem.
187 */
188status_t ZipEntry::addPadding(int padding)
189{
190 if (padding <= 0)
191 return INVALID_OPERATION;
192
193 //ALOGI("HEY: adding %d pad bytes to existing %d in %s\n",
194 // padding, mLFH.mExtraFieldLength, mCDE.mFileName);
195
196 if (mLFH.mExtraFieldLength > 0) {
197 /* extend existing field */
198 unsigned char* newExtra;
199
200 newExtra = new unsigned char[mLFH.mExtraFieldLength + padding];
201 if (newExtra == NULL)
202 return NO_MEMORY;
203 memset(newExtra + mLFH.mExtraFieldLength, 0, padding);
204 memcpy(newExtra, mLFH.mExtraField, mLFH.mExtraFieldLength);
205
206 delete[] mLFH.mExtraField;
207 mLFH.mExtraField = newExtra;
208 mLFH.mExtraFieldLength += padding;
209 } else {
210 /* create new field */
211 mLFH.mExtraField = new unsigned char[padding];
212 memset(mLFH.mExtraField, 0, padding);
213 mLFH.mExtraFieldLength = padding;
214 }
215
216 return NO_ERROR;
217}
218
219/*
220 * Set the fields in the LFH equal to the corresponding fields in the CDE.
221 *
222 * This does not touch the LFH "extra" field.
223 */
224void ZipEntry::copyCDEtoLFH(void)
225{
226 mLFH.mVersionToExtract = mCDE.mVersionToExtract;
227 mLFH.mGPBitFlag = mCDE.mGPBitFlag;
228 mLFH.mCompressionMethod = mCDE.mCompressionMethod;
229 mLFH.mLastModFileTime = mCDE.mLastModFileTime;
230 mLFH.mLastModFileDate = mCDE.mLastModFileDate;
231 mLFH.mCRC32 = mCDE.mCRC32;
232 mLFH.mCompressedSize = mCDE.mCompressedSize;
233 mLFH.mUncompressedSize = mCDE.mUncompressedSize;
234 mLFH.mFileNameLength = mCDE.mFileNameLength;
235 // the "extra field" is independent
236
237 delete[] mLFH.mFileName;
238 if (mLFH.mFileNameLength > 0) {
239 mLFH.mFileName = new unsigned char[mLFH.mFileNameLength+1];
240 strcpy((char*) mLFH.mFileName, (const char*) mCDE.mFileName);
241 } else {
242 mLFH.mFileName = NULL;
243 }
244}
245
246/*
247 * Set some information about a file after we add it.
248 */
249void ZipEntry::setDataInfo(long uncompLen, long compLen, unsigned long crc32,
250 int compressionMethod)
251{
252 mCDE.mCompressionMethod = compressionMethod;
253 mCDE.mCRC32 = crc32;
254 mCDE.mCompressedSize = compLen;
255 mCDE.mUncompressedSize = uncompLen;
256 mCDE.mCompressionMethod = compressionMethod;
257 if (compressionMethod == kCompressDeflated) {
258 mCDE.mGPBitFlag |= 0x0002; // indicates maximum compression used
259 }
260 copyCDEtoLFH();
261}
262
263/*
264 * See if the data in mCDE and mLFH match up. This is mostly useful for
265 * debugging these classes, but it can be used to identify damaged
266 * archives.
267 *
268 * Returns "false" if they differ.
269 */
270bool ZipEntry::compareHeaders(void) const
271{
272 if (mCDE.mVersionToExtract != mLFH.mVersionToExtract) {
273 ALOGV("cmp: VersionToExtract\n");
274 return false;
275 }
276 if (mCDE.mGPBitFlag != mLFH.mGPBitFlag) {
277 ALOGV("cmp: GPBitFlag\n");
278 return false;
279 }
280 if (mCDE.mCompressionMethod != mLFH.mCompressionMethod) {
281 ALOGV("cmp: CompressionMethod\n");
282 return false;
283 }
284 if (mCDE.mLastModFileTime != mLFH.mLastModFileTime) {
285 ALOGV("cmp: LastModFileTime\n");
286 return false;
287 }
288 if (mCDE.mLastModFileDate != mLFH.mLastModFileDate) {
289 ALOGV("cmp: LastModFileDate\n");
290 return false;
291 }
292 if (mCDE.mCRC32 != mLFH.mCRC32) {
293 ALOGV("cmp: CRC32\n");
294 return false;
295 }
296 if (mCDE.mCompressedSize != mLFH.mCompressedSize) {
297 ALOGV("cmp: CompressedSize\n");
298 return false;
299 }
300 if (mCDE.mUncompressedSize != mLFH.mUncompressedSize) {
301 ALOGV("cmp: UncompressedSize\n");
302 return false;
303 }
304 if (mCDE.mFileNameLength != mLFH.mFileNameLength) {
305 ALOGV("cmp: FileNameLength\n");
306 return false;
307 }
308#if 0 // this seems to be used for padding, not real data
309 if (mCDE.mExtraFieldLength != mLFH.mExtraFieldLength) {
310 ALOGV("cmp: ExtraFieldLength\n");
311 return false;
312 }
313#endif
314 if (mCDE.mFileName != NULL) {
315 if (strcmp((char*) mCDE.mFileName, (char*) mLFH.mFileName) != 0) {
316 ALOGV("cmp: FileName\n");
317 return false;
318 }
319 }
320
321 return true;
322}
323
324
325/*
326 * Convert the DOS date/time stamp into a UNIX time stamp.
327 */
328time_t ZipEntry::getModWhen(void) const
329{
330 struct tm parts;
331
332 parts.tm_sec = (mCDE.mLastModFileTime & 0x001f) << 1;
333 parts.tm_min = (mCDE.mLastModFileTime & 0x07e0) >> 5;
334 parts.tm_hour = (mCDE.mLastModFileTime & 0xf800) >> 11;
335 parts.tm_mday = (mCDE.mLastModFileDate & 0x001f);
336 parts.tm_mon = ((mCDE.mLastModFileDate & 0x01e0) >> 5) -1;
337 parts.tm_year = ((mCDE.mLastModFileDate & 0xfe00) >> 9) + 80;
338 parts.tm_wday = parts.tm_yday = 0;
339 parts.tm_isdst = -1; // DST info "not available"
340
341 return mktime(&parts);
342}
343
344/*
345 * Set the CDE/LFH timestamp from UNIX time.
346 */
347void ZipEntry::setModWhen(time_t when)
348{
349#if !defined(_WIN32)
350 struct tm tmResult;
351#endif
352 time_t even;
353 unsigned short zdate, ztime;
354
355 struct tm* ptm;
356
357 /* round up to an even number of seconds */
358 even = (time_t)(((unsigned long)(when) + 1) & (~1));
359
360 /* expand */
361#if !defined(_WIN32)
362 ptm = localtime_r(&even, &tmResult);
363#else
364 ptm = localtime(&even);
365#endif
366
367 int year;
368 year = ptm->tm_year;
369 if (year < 80)
370 year = 80;
371
372 zdate = (year - 80) << 9 | (ptm->tm_mon+1) << 5 | ptm->tm_mday;
373 ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
374
375 mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime;
376 mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate;
377}
378
379
380/*
381 * ===========================================================================
382 * ZipEntry::LocalFileHeader
383 * ===========================================================================
384 */
385
386/*
387 * Read a local file header.
388 *
389 * On entry, "fp" points to the signature at the start of the header.
390 * On exit, "fp" points to the start of data.
391 */
392status_t ZipEntry::LocalFileHeader::read(FILE* fp)
393{
394 status_t result = NO_ERROR;
395 unsigned char buf[kLFHLen];
396
397 assert(mFileName == NULL);
398 assert(mExtraField == NULL);
399
400 if (fread(buf, 1, kLFHLen, fp) != kLFHLen) {
401 result = UNKNOWN_ERROR;
402 goto bail;
403 }
404
405 if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
406 ALOGD("whoops: didn't find expected signature\n");
407 result = UNKNOWN_ERROR;
408 goto bail;
409 }
410
411 mVersionToExtract = ZipEntry::getShortLE(&buf[0x04]);
412 mGPBitFlag = ZipEntry::getShortLE(&buf[0x06]);
413 mCompressionMethod = ZipEntry::getShortLE(&buf[0x08]);
414 mLastModFileTime = ZipEntry::getShortLE(&buf[0x0a]);
415 mLastModFileDate = ZipEntry::getShortLE(&buf[0x0c]);
416 mCRC32 = ZipEntry::getLongLE(&buf[0x0e]);
417 mCompressedSize = ZipEntry::getLongLE(&buf[0x12]);
418 mUncompressedSize = ZipEntry::getLongLE(&buf[0x16]);
419 mFileNameLength = ZipEntry::getShortLE(&buf[0x1a]);
420 mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1c]);
421
422 // TODO: validate sizes
423
424 /* grab filename */
425 if (mFileNameLength != 0) {
426 mFileName = new unsigned char[mFileNameLength+1];
427 if (mFileName == NULL) {
428 result = NO_MEMORY;
429 goto bail;
430 }
431 if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
432 result = UNKNOWN_ERROR;
433 goto bail;
434 }
435 mFileName[mFileNameLength] = '\0';
436 }
437
438 /* grab extra field */
439 if (mExtraFieldLength != 0) {
440 mExtraField = new unsigned char[mExtraFieldLength+1];
441 if (mExtraField == NULL) {
442 result = NO_MEMORY;
443 goto bail;
444 }
445 if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
446 result = UNKNOWN_ERROR;
447 goto bail;
448 }
449 mExtraField[mExtraFieldLength] = '\0';
450 }
451
452bail:
453 return result;
454}
455
456/*
457 * Write a local file header.
458 */
459status_t ZipEntry::LocalFileHeader::write(FILE* fp)
460{
461 unsigned char buf[kLFHLen];
462
463 ZipEntry::putLongLE(&buf[0x00], kSignature);
464 ZipEntry::putShortLE(&buf[0x04], mVersionToExtract);
465 ZipEntry::putShortLE(&buf[0x06], mGPBitFlag);
466 ZipEntry::putShortLE(&buf[0x08], mCompressionMethod);
467 ZipEntry::putShortLE(&buf[0x0a], mLastModFileTime);
468 ZipEntry::putShortLE(&buf[0x0c], mLastModFileDate);
469 ZipEntry::putLongLE(&buf[0x0e], mCRC32);
470 ZipEntry::putLongLE(&buf[0x12], mCompressedSize);
471 ZipEntry::putLongLE(&buf[0x16], mUncompressedSize);
472 ZipEntry::putShortLE(&buf[0x1a], mFileNameLength);
473 ZipEntry::putShortLE(&buf[0x1c], mExtraFieldLength);
474
475 if (fwrite(buf, 1, kLFHLen, fp) != kLFHLen)
476 return UNKNOWN_ERROR;
477
478 /* write filename */
479 if (mFileNameLength != 0) {
480 if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
481 return UNKNOWN_ERROR;
482 }
483
484 /* write "extra field" */
485 if (mExtraFieldLength != 0) {
486 if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
487 return UNKNOWN_ERROR;
488 }
489
490 return NO_ERROR;
491}
492
493
494/*
495 * Dump the contents of a LocalFileHeader object.
496 */
497void ZipEntry::LocalFileHeader::dump(void) const
498{
499 ALOGD(" LocalFileHeader contents:\n");
500 ALOGD(" versToExt=%u gpBits=0x%04x compression=%u\n",
501 mVersionToExtract, mGPBitFlag, mCompressionMethod);
502 ALOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
503 mLastModFileTime, mLastModFileDate, mCRC32);
504 ALOGD(" compressedSize=%lu uncompressedSize=%lu\n",
505 mCompressedSize, mUncompressedSize);
506 ALOGD(" filenameLen=%u extraLen=%u\n",
507 mFileNameLength, mExtraFieldLength);
508 if (mFileName != NULL)
509 ALOGD(" filename: '%s'\n", mFileName);
510}
511
512
513/*
514 * ===========================================================================
515 * ZipEntry::CentralDirEntry
516 * ===========================================================================
517 */
518
519/*
520 * Read the central dir entry that appears next in the file.
521 *
522 * On entry, "fp" should be positioned on the signature bytes for the
523 * entry. On exit, "fp" will point at the signature word for the next
524 * entry or for the EOCD.
525 */
526status_t ZipEntry::CentralDirEntry::read(FILE* fp)
527{
528 status_t result = NO_ERROR;
529 unsigned char buf[kCDELen];
530
531 /* no re-use */
532 assert(mFileName == NULL);
533 assert(mExtraField == NULL);
534 assert(mFileComment == NULL);
535
536 if (fread(buf, 1, kCDELen, fp) != kCDELen) {
537 result = UNKNOWN_ERROR;
538 goto bail;
539 }
540
541 if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
542 ALOGD("Whoops: didn't find expected signature\n");
543 result = UNKNOWN_ERROR;
544 goto bail;
545 }
546
547 mVersionMadeBy = ZipEntry::getShortLE(&buf[0x04]);
548 mVersionToExtract = ZipEntry::getShortLE(&buf[0x06]);
549 mGPBitFlag = ZipEntry::getShortLE(&buf[0x08]);
550 mCompressionMethod = ZipEntry::getShortLE(&buf[0x0a]);
551 mLastModFileTime = ZipEntry::getShortLE(&buf[0x0c]);
552 mLastModFileDate = ZipEntry::getShortLE(&buf[0x0e]);
553 mCRC32 = ZipEntry::getLongLE(&buf[0x10]);
554 mCompressedSize = ZipEntry::getLongLE(&buf[0x14]);
555 mUncompressedSize = ZipEntry::getLongLE(&buf[0x18]);
556 mFileNameLength = ZipEntry::getShortLE(&buf[0x1c]);
557 mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1e]);
558 mFileCommentLength = ZipEntry::getShortLE(&buf[0x20]);
559 mDiskNumberStart = ZipEntry::getShortLE(&buf[0x22]);
560 mInternalAttrs = ZipEntry::getShortLE(&buf[0x24]);
561 mExternalAttrs = ZipEntry::getLongLE(&buf[0x26]);
562 mLocalHeaderRelOffset = ZipEntry::getLongLE(&buf[0x2a]);
563
564 // TODO: validate sizes and offsets
565
566 /* grab filename */
567 if (mFileNameLength != 0) {
568 mFileName = new unsigned char[mFileNameLength+1];
569 if (mFileName == NULL) {
570 result = NO_MEMORY;
571 goto bail;
572 }
573 if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
574 result = UNKNOWN_ERROR;
575 goto bail;
576 }
577 mFileName[mFileNameLength] = '\0';
578 }
579
580 /* read "extra field" */
581 if (mExtraFieldLength != 0) {
582 mExtraField = new unsigned char[mExtraFieldLength+1];
583 if (mExtraField == NULL) {
584 result = NO_MEMORY;
585 goto bail;
586 }
587 if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
588 result = UNKNOWN_ERROR;
589 goto bail;
590 }
591 mExtraField[mExtraFieldLength] = '\0';
592 }
593
594
595 /* grab comment, if any */
596 if (mFileCommentLength != 0) {
597 mFileComment = new unsigned char[mFileCommentLength+1];
598 if (mFileComment == NULL) {
599 result = NO_MEMORY;
600 goto bail;
601 }
602 if (fread(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
603 {
604 result = UNKNOWN_ERROR;
605 goto bail;
606 }
607 mFileComment[mFileCommentLength] = '\0';
608 }
609
610bail:
611 return result;
612}
613
614/*
615 * Write a central dir entry.
616 */
617status_t ZipEntry::CentralDirEntry::write(FILE* fp)
618{
619 unsigned char buf[kCDELen];
620
621 ZipEntry::putLongLE(&buf[0x00], kSignature);
622 ZipEntry::putShortLE(&buf[0x04], mVersionMadeBy);
623 ZipEntry::putShortLE(&buf[0x06], mVersionToExtract);
624 ZipEntry::putShortLE(&buf[0x08], mGPBitFlag);
625 ZipEntry::putShortLE(&buf[0x0a], mCompressionMethod);
626 ZipEntry::putShortLE(&buf[0x0c], mLastModFileTime);
627 ZipEntry::putShortLE(&buf[0x0e], mLastModFileDate);
628 ZipEntry::putLongLE(&buf[0x10], mCRC32);
629 ZipEntry::putLongLE(&buf[0x14], mCompressedSize);
630 ZipEntry::putLongLE(&buf[0x18], mUncompressedSize);
631 ZipEntry::putShortLE(&buf[0x1c], mFileNameLength);
632 ZipEntry::putShortLE(&buf[0x1e], mExtraFieldLength);
633 ZipEntry::putShortLE(&buf[0x20], mFileCommentLength);
634 ZipEntry::putShortLE(&buf[0x22], mDiskNumberStart);
635 ZipEntry::putShortLE(&buf[0x24], mInternalAttrs);
636 ZipEntry::putLongLE(&buf[0x26], mExternalAttrs);
637 ZipEntry::putLongLE(&buf[0x2a], mLocalHeaderRelOffset);
638
639 if (fwrite(buf, 1, kCDELen, fp) != kCDELen)
640 return UNKNOWN_ERROR;
641
642 /* write filename */
643 if (mFileNameLength != 0) {
644 if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
645 return UNKNOWN_ERROR;
646 }
647
648 /* write "extra field" */
649 if (mExtraFieldLength != 0) {
650 if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
651 return UNKNOWN_ERROR;
652 }
653
654 /* write comment */
655 if (mFileCommentLength != 0) {
656 if (fwrite(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
657 return UNKNOWN_ERROR;
658 }
659
660 return NO_ERROR;
661}
662
663/*
664 * Dump the contents of a CentralDirEntry object.
665 */
666void ZipEntry::CentralDirEntry::dump(void) const
667{
668 ALOGD(" CentralDirEntry contents:\n");
669 ALOGD(" versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n",
670 mVersionMadeBy, mVersionToExtract, mGPBitFlag, mCompressionMethod);
671 ALOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
672 mLastModFileTime, mLastModFileDate, mCRC32);
673 ALOGD(" compressedSize=%lu uncompressedSize=%lu\n",
674 mCompressedSize, mUncompressedSize);
675 ALOGD(" filenameLen=%u extraLen=%u commentLen=%u\n",
676 mFileNameLength, mExtraFieldLength, mFileCommentLength);
677 ALOGD(" diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n",
678 mDiskNumberStart, mInternalAttrs, mExternalAttrs,
679 mLocalHeaderRelOffset);
680
681 if (mFileName != NULL)
682 ALOGD(" filename: '%s'\n", mFileName);
683 if (mFileComment != NULL)
684 ALOGD(" comment: '%s'\n", mFileComment);
685}
686
687/*
688 * Copy-assignment operator for CentralDirEntry.
689 */
690ZipEntry::CentralDirEntry& ZipEntry::CentralDirEntry::operator=(const ZipEntry::CentralDirEntry& src) {
691 if (this == &src) {
692 return *this;
693 }
694
695 // Free up old data.
696 delete[] mFileName;
697 delete[] mExtraField;
698 delete[] mFileComment;
699
700 // Copy scalars.
701 mVersionMadeBy = src.mVersionMadeBy;
702 mVersionToExtract = src.mVersionToExtract;
703 mGPBitFlag = src.mGPBitFlag;
704 mCompressionMethod = src.mCompressionMethod;
705 mLastModFileTime = src.mLastModFileTime;
706 mLastModFileDate = src.mLastModFileDate;
707 mCRC32 = src.mCRC32;
708 mCompressedSize = src.mCompressedSize;
709 mUncompressedSize = src.mUncompressedSize;
710 mFileNameLength = src.mFileNameLength;
711 mExtraFieldLength = src.mExtraFieldLength;
712 mFileCommentLength = src.mFileCommentLength;
713 mDiskNumberStart = src.mDiskNumberStart;
714 mInternalAttrs = src.mInternalAttrs;
715 mExternalAttrs = src.mExternalAttrs;
716 mLocalHeaderRelOffset = src.mLocalHeaderRelOffset;
717
718 // Copy strings, if necessary.
719 if (mFileNameLength > 0) {
720 mFileName = new unsigned char[mFileNameLength + 1];
721 if (mFileName != NULL)
722 strcpy((char*)mFileName, (char*)src.mFileName);
723 } else {
724 mFileName = NULL;
725 }
726 if (mFileCommentLength > 0) {
727 mFileComment = new unsigned char[mFileCommentLength + 1];
728 if (mFileComment != NULL)
729 strcpy((char*)mFileComment, (char*)src.mFileComment);
730 } else {
731 mFileComment = NULL;
732 }
733 if (mExtraFieldLength > 0) {
734 /* we null-terminate this, though it may not be a string */
735 mExtraField = new unsigned char[mExtraFieldLength + 1];
736 if (mExtraField != NULL)
737 memcpy(mExtraField, src.mExtraField, mExtraFieldLength + 1);
738 } else {
739 mExtraField = NULL;
740 }
741
742 return *this;
743}
744
745} // namespace aapt