]>
git.saurik.com Git - android/aapt.git/blob - ZipEntry.cpp
2 * Copyright (C) 2006 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 // Access to entries in a Zip archive.
24 #include <utils/Log.h>
30 using namespace android
;
33 * Initialize a new ZipEntry structure from a FILE* positioned at a
34 * CentralDirectoryEntry.
36 * On exit, the file pointer will be at the start of the next CDE or
39 status_t
ZipEntry::initFromCDE(FILE* fp
)
45 //ALOGV("initFromCDE ---\n");
48 result
= mCDE
.read(fp
);
49 if (result
!= NO_ERROR
) {
50 ALOGD("mCDE.read failed\n");
56 /* using the info in the CDE, go load up the LFH */
58 if (fseek(fp
, mCDE
.mLocalHeaderRelOffset
, SEEK_SET
) != 0) {
59 ALOGD("local header seek failed (%ld)\n",
60 mCDE
.mLocalHeaderRelOffset
);
64 result
= mLFH
.read(fp
);
65 if (result
!= NO_ERROR
) {
66 ALOGD("mLFH.read failed\n");
70 if (fseek(fp
, posn
, SEEK_SET
) != 0)
76 * We *might* need to read the Data Descriptor at this point and
77 * integrate it into the LFH. If this bit is set, the CRC-32,
78 * compressed size, and uncompressed size will be zero. In practice
79 * these seem to be rare.
81 hasDD
= (mLFH
.mGPBitFlag
& kUsesDataDescr
) != 0;
83 // do something clever
84 //ALOGD("+++ has data descriptor\n");
88 * Sanity-check the LFH. Note that this will fail if the "kUsesDataDescr"
89 * flag is set, because the LFH is incomplete. (Not a problem, since we
90 * prefer the CDE values.)
92 if (!hasDD
&& !compareHeaders()) {
93 LOGW("warning: header mismatch\n");
98 * If the mVersionToExtract is greater than 20, we may have an
99 * issue unpacking the record -- could be encrypted, compressed
100 * with something we don't support, or use Zip64 extensions. We
101 * can defer worrying about that to when we're extracting data.
108 * Initialize a new entry. Pass in the file name and an optional comment.
110 * Initializes the CDE and the LFH.
112 void ZipEntry::initNew(const char* fileName
, const char* comment
)
114 assert(fileName
!= NULL
&& *fileName
!= '\0'); // name required
116 /* most fields are properly initialized by constructor */
117 mCDE
.mVersionMadeBy
= kDefaultMadeBy
;
118 mCDE
.mVersionToExtract
= kDefaultVersion
;
119 mCDE
.mCompressionMethod
= kCompressStored
;
120 mCDE
.mFileNameLength
= strlen(fileName
);
122 mCDE
.mFileCommentLength
= strlen(comment
);
123 mCDE
.mExternalAttrs
= 0x81b60020; // matches what WinZip does
125 if (mCDE
.mFileNameLength
> 0) {
126 mCDE
.mFileName
= new unsigned char[mCDE
.mFileNameLength
+1];
127 strcpy((char*) mCDE
.mFileName
, fileName
);
129 if (mCDE
.mFileCommentLength
> 0) {
130 /* TODO: stop assuming null-terminated ASCII here? */
131 mCDE
.mFileComment
= new unsigned char[mCDE
.mFileCommentLength
+1];
132 strcpy((char*) mCDE
.mFileComment
, comment
);
139 * Initialize a new entry, starting with the ZipEntry from a different
142 * Initializes the CDE and the LFH.
144 status_t
ZipEntry::initFromExternal(const ZipFile
* pZipFile
,
145 const ZipEntry
* pEntry
)
148 * Copy everything in the CDE over, then fix up the hairy bits.
150 memcpy(&mCDE
, &pEntry
->mCDE
, sizeof(mCDE
));
152 if (mCDE
.mFileNameLength
> 0) {
153 mCDE
.mFileName
= new unsigned char[mCDE
.mFileNameLength
+1];
154 if (mCDE
.mFileName
== NULL
)
156 strcpy((char*) mCDE
.mFileName
, (char*)pEntry
->mCDE
.mFileName
);
158 if (mCDE
.mFileCommentLength
> 0) {
159 mCDE
.mFileComment
= new unsigned char[mCDE
.mFileCommentLength
+1];
160 if (mCDE
.mFileComment
== NULL
)
162 strcpy((char*) mCDE
.mFileComment
, (char*)pEntry
->mCDE
.mFileComment
);
164 if (mCDE
.mExtraFieldLength
> 0) {
165 /* we null-terminate this, though it may not be a string */
166 mCDE
.mExtraField
= new unsigned char[mCDE
.mExtraFieldLength
+1];
167 if (mCDE
.mExtraField
== NULL
)
169 memcpy(mCDE
.mExtraField
, pEntry
->mCDE
.mExtraField
,
170 mCDE
.mExtraFieldLength
+1);
173 /* construct the LFH from the CDE */
177 * The LFH "extra" field is independent of the CDE "extra", so we
180 assert(mLFH
.mExtraField
== NULL
);
181 mLFH
.mExtraFieldLength
= pEntry
->mLFH
.mExtraFieldLength
;
182 if (mLFH
.mExtraFieldLength
> 0) {
183 mLFH
.mExtraField
= new unsigned char[mLFH
.mExtraFieldLength
+1];
184 if (mLFH
.mExtraField
== NULL
)
186 memcpy(mLFH
.mExtraField
, pEntry
->mLFH
.mExtraField
,
187 mLFH
.mExtraFieldLength
+1);
194 * Insert pad bytes in the LFH by tweaking the "extra" field. This will
195 * potentially confuse something that put "extra" data in here earlier,
196 * but I can't find an actual problem.
198 status_t
ZipEntry::addPadding(int padding
)
201 return INVALID_OPERATION
;
203 //ALOGI("HEY: adding %d pad bytes to existing %d in %s\n",
204 // padding, mLFH.mExtraFieldLength, mCDE.mFileName);
206 if (mLFH
.mExtraFieldLength
> 0) {
207 /* extend existing field */
208 unsigned char* newExtra
;
210 newExtra
= new unsigned char[mLFH
.mExtraFieldLength
+ padding
];
211 if (newExtra
== NULL
)
213 memset(newExtra
+ mLFH
.mExtraFieldLength
, 0, padding
);
214 memcpy(newExtra
, mLFH
.mExtraField
, mLFH
.mExtraFieldLength
);
216 delete[] mLFH
.mExtraField
;
217 mLFH
.mExtraField
= newExtra
;
218 mLFH
.mExtraFieldLength
+= padding
;
220 /* create new field */
221 mLFH
.mExtraField
= new unsigned char[padding
];
222 memset(mLFH
.mExtraField
, 0, padding
);
223 mLFH
.mExtraFieldLength
= padding
;
230 * Set the fields in the LFH equal to the corresponding fields in the CDE.
232 * This does not touch the LFH "extra" field.
234 void ZipEntry::copyCDEtoLFH(void)
236 mLFH
.mVersionToExtract
= mCDE
.mVersionToExtract
;
237 mLFH
.mGPBitFlag
= mCDE
.mGPBitFlag
;
238 mLFH
.mCompressionMethod
= mCDE
.mCompressionMethod
;
239 mLFH
.mLastModFileTime
= mCDE
.mLastModFileTime
;
240 mLFH
.mLastModFileDate
= mCDE
.mLastModFileDate
;
241 mLFH
.mCRC32
= mCDE
.mCRC32
;
242 mLFH
.mCompressedSize
= mCDE
.mCompressedSize
;
243 mLFH
.mUncompressedSize
= mCDE
.mUncompressedSize
;
244 mLFH
.mFileNameLength
= mCDE
.mFileNameLength
;
245 // the "extra field" is independent
247 delete[] mLFH
.mFileName
;
248 if (mLFH
.mFileNameLength
> 0) {
249 mLFH
.mFileName
= new unsigned char[mLFH
.mFileNameLength
+1];
250 strcpy((char*) mLFH
.mFileName
, (const char*) mCDE
.mFileName
);
252 mLFH
.mFileName
= NULL
;
257 * Set some information about a file after we add it.
259 void ZipEntry::setDataInfo(long uncompLen
, long compLen
, unsigned long crc32
,
260 int compressionMethod
)
262 mCDE
.mCompressionMethod
= compressionMethod
;
264 mCDE
.mCompressedSize
= compLen
;
265 mCDE
.mUncompressedSize
= uncompLen
;
266 mCDE
.mCompressionMethod
= compressionMethod
;
267 if (compressionMethod
== kCompressDeflated
) {
268 mCDE
.mGPBitFlag
|= 0x0002; // indicates maximum compression used
274 * See if the data in mCDE and mLFH match up. This is mostly useful for
275 * debugging these classes, but it can be used to identify damaged
278 * Returns "false" if they differ.
280 bool ZipEntry::compareHeaders(void) const
282 if (mCDE
.mVersionToExtract
!= mLFH
.mVersionToExtract
) {
283 ALOGV("cmp: VersionToExtract\n");
286 if (mCDE
.mGPBitFlag
!= mLFH
.mGPBitFlag
) {
287 ALOGV("cmp: GPBitFlag\n");
290 if (mCDE
.mCompressionMethod
!= mLFH
.mCompressionMethod
) {
291 ALOGV("cmp: CompressionMethod\n");
294 if (mCDE
.mLastModFileTime
!= mLFH
.mLastModFileTime
) {
295 ALOGV("cmp: LastModFileTime\n");
298 if (mCDE
.mLastModFileDate
!= mLFH
.mLastModFileDate
) {
299 ALOGV("cmp: LastModFileDate\n");
302 if (mCDE
.mCRC32
!= mLFH
.mCRC32
) {
303 ALOGV("cmp: CRC32\n");
306 if (mCDE
.mCompressedSize
!= mLFH
.mCompressedSize
) {
307 ALOGV("cmp: CompressedSize\n");
310 if (mCDE
.mUncompressedSize
!= mLFH
.mUncompressedSize
) {
311 ALOGV("cmp: UncompressedSize\n");
314 if (mCDE
.mFileNameLength
!= mLFH
.mFileNameLength
) {
315 ALOGV("cmp: FileNameLength\n");
318 #if 0 // this seems to be used for padding, not real data
319 if (mCDE
.mExtraFieldLength
!= mLFH
.mExtraFieldLength
) {
320 ALOGV("cmp: ExtraFieldLength\n");
324 if (mCDE
.mFileName
!= NULL
) {
325 if (strcmp((char*) mCDE
.mFileName
, (char*) mLFH
.mFileName
) != 0) {
326 ALOGV("cmp: FileName\n");
336 * Convert the DOS date/time stamp into a UNIX time stamp.
338 time_t ZipEntry::getModWhen(void) const
342 parts
.tm_sec
= (mCDE
.mLastModFileTime
& 0x001f) << 1;
343 parts
.tm_min
= (mCDE
.mLastModFileTime
& 0x07e0) >> 5;
344 parts
.tm_hour
= (mCDE
.mLastModFileTime
& 0xf800) >> 11;
345 parts
.tm_mday
= (mCDE
.mLastModFileDate
& 0x001f);
346 parts
.tm_mon
= ((mCDE
.mLastModFileDate
& 0x01e0) >> 5) -1;
347 parts
.tm_year
= ((mCDE
.mLastModFileDate
& 0xfe00) >> 9) + 80;
348 parts
.tm_wday
= parts
.tm_yday
= 0;
349 parts
.tm_isdst
= -1; // DST info "not available"
351 return mktime(&parts
);
355 * Set the CDE/LFH timestamp from UNIX time.
357 void ZipEntry::setModWhen(time_t when
)
359 #ifdef HAVE_LOCALTIME_R
363 unsigned short zdate
, ztime
;
367 /* round up to an even number of seconds */
368 even
= (time_t)(((unsigned long)(when
) + 1) & (~1));
371 #ifdef HAVE_LOCALTIME_R
372 ptm
= localtime_r(&even
, &tmResult
);
374 ptm
= localtime(&even
);
382 zdate
= (year
- 80) << 9 | (ptm
->tm_mon
+1) << 5 | ptm
->tm_mday
;
383 ztime
= ptm
->tm_hour
<< 11 | ptm
->tm_min
<< 5 | ptm
->tm_sec
>> 1;
385 mCDE
.mLastModFileTime
= mLFH
.mLastModFileTime
= ztime
;
386 mCDE
.mLastModFileDate
= mLFH
.mLastModFileDate
= zdate
;
391 * ===========================================================================
392 * ZipEntry::LocalFileHeader
393 * ===========================================================================
397 * Read a local file header.
399 * On entry, "fp" points to the signature at the start of the header.
400 * On exit, "fp" points to the start of data.
402 status_t
ZipEntry::LocalFileHeader::read(FILE* fp
)
404 status_t result
= NO_ERROR
;
405 unsigned char buf
[kLFHLen
];
407 assert(mFileName
== NULL
);
408 assert(mExtraField
== NULL
);
410 if (fread(buf
, 1, kLFHLen
, fp
) != kLFHLen
) {
411 result
= UNKNOWN_ERROR
;
415 if (ZipEntry::getLongLE(&buf
[0x00]) != kSignature
) {
416 ALOGD("whoops: didn't find expected signature\n");
417 result
= UNKNOWN_ERROR
;
421 mVersionToExtract
= ZipEntry::getShortLE(&buf
[0x04]);
422 mGPBitFlag
= ZipEntry::getShortLE(&buf
[0x06]);
423 mCompressionMethod
= ZipEntry::getShortLE(&buf
[0x08]);
424 mLastModFileTime
= ZipEntry::getShortLE(&buf
[0x0a]);
425 mLastModFileDate
= ZipEntry::getShortLE(&buf
[0x0c]);
426 mCRC32
= ZipEntry::getLongLE(&buf
[0x0e]);
427 mCompressedSize
= ZipEntry::getLongLE(&buf
[0x12]);
428 mUncompressedSize
= ZipEntry::getLongLE(&buf
[0x16]);
429 mFileNameLength
= ZipEntry::getShortLE(&buf
[0x1a]);
430 mExtraFieldLength
= ZipEntry::getShortLE(&buf
[0x1c]);
432 // TODO: validate sizes
435 if (mFileNameLength
!= 0) {
436 mFileName
= new unsigned char[mFileNameLength
+1];
437 if (mFileName
== NULL
) {
441 if (fread(mFileName
, 1, mFileNameLength
, fp
) != mFileNameLength
) {
442 result
= UNKNOWN_ERROR
;
445 mFileName
[mFileNameLength
] = '\0';
448 /* grab extra field */
449 if (mExtraFieldLength
!= 0) {
450 mExtraField
= new unsigned char[mExtraFieldLength
+1];
451 if (mExtraField
== NULL
) {
455 if (fread(mExtraField
, 1, mExtraFieldLength
, fp
) != mExtraFieldLength
) {
456 result
= UNKNOWN_ERROR
;
459 mExtraField
[mExtraFieldLength
] = '\0';
467 * Write a local file header.
469 status_t
ZipEntry::LocalFileHeader::write(FILE* fp
)
471 unsigned char buf
[kLFHLen
];
473 ZipEntry::putLongLE(&buf
[0x00], kSignature
);
474 ZipEntry::putShortLE(&buf
[0x04], mVersionToExtract
);
475 ZipEntry::putShortLE(&buf
[0x06], mGPBitFlag
);
476 ZipEntry::putShortLE(&buf
[0x08], mCompressionMethod
);
477 ZipEntry::putShortLE(&buf
[0x0a], mLastModFileTime
);
478 ZipEntry::putShortLE(&buf
[0x0c], mLastModFileDate
);
479 ZipEntry::putLongLE(&buf
[0x0e], mCRC32
);
480 ZipEntry::putLongLE(&buf
[0x12], mCompressedSize
);
481 ZipEntry::putLongLE(&buf
[0x16], mUncompressedSize
);
482 ZipEntry::putShortLE(&buf
[0x1a], mFileNameLength
);
483 ZipEntry::putShortLE(&buf
[0x1c], mExtraFieldLength
);
485 if (fwrite(buf
, 1, kLFHLen
, fp
) != kLFHLen
)
486 return UNKNOWN_ERROR
;
489 if (mFileNameLength
!= 0) {
490 if (fwrite(mFileName
, 1, mFileNameLength
, fp
) != mFileNameLength
)
491 return UNKNOWN_ERROR
;
494 /* write "extra field" */
495 if (mExtraFieldLength
!= 0) {
496 if (fwrite(mExtraField
, 1, mExtraFieldLength
, fp
) != mExtraFieldLength
)
497 return UNKNOWN_ERROR
;
505 * Dump the contents of a LocalFileHeader object.
507 void ZipEntry::LocalFileHeader::dump(void) const
509 ALOGD(" LocalFileHeader contents:\n");
510 ALOGD(" versToExt=%u gpBits=0x%04x compression=%u\n",
511 mVersionToExtract
, mGPBitFlag
, mCompressionMethod
);
512 ALOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
513 mLastModFileTime
, mLastModFileDate
, mCRC32
);
514 ALOGD(" compressedSize=%lu uncompressedSize=%lu\n",
515 mCompressedSize
, mUncompressedSize
);
516 ALOGD(" filenameLen=%u extraLen=%u\n",
517 mFileNameLength
, mExtraFieldLength
);
518 if (mFileName
!= NULL
)
519 ALOGD(" filename: '%s'\n", mFileName
);
524 * ===========================================================================
525 * ZipEntry::CentralDirEntry
526 * ===========================================================================
530 * Read the central dir entry that appears next in the file.
532 * On entry, "fp" should be positioned on the signature bytes for the
533 * entry. On exit, "fp" will point at the signature word for the next
534 * entry or for the EOCD.
536 status_t
ZipEntry::CentralDirEntry::read(FILE* fp
)
538 status_t result
= NO_ERROR
;
539 unsigned char buf
[kCDELen
];
542 assert(mFileName
== NULL
);
543 assert(mExtraField
== NULL
);
544 assert(mFileComment
== NULL
);
546 if (fread(buf
, 1, kCDELen
, fp
) != kCDELen
) {
547 result
= UNKNOWN_ERROR
;
551 if (ZipEntry::getLongLE(&buf
[0x00]) != kSignature
) {
552 ALOGD("Whoops: didn't find expected signature\n");
553 result
= UNKNOWN_ERROR
;
557 mVersionMadeBy
= ZipEntry::getShortLE(&buf
[0x04]);
558 mVersionToExtract
= ZipEntry::getShortLE(&buf
[0x06]);
559 mGPBitFlag
= ZipEntry::getShortLE(&buf
[0x08]);
560 mCompressionMethod
= ZipEntry::getShortLE(&buf
[0x0a]);
561 mLastModFileTime
= ZipEntry::getShortLE(&buf
[0x0c]);
562 mLastModFileDate
= ZipEntry::getShortLE(&buf
[0x0e]);
563 mCRC32
= ZipEntry::getLongLE(&buf
[0x10]);
564 mCompressedSize
= ZipEntry::getLongLE(&buf
[0x14]);
565 mUncompressedSize
= ZipEntry::getLongLE(&buf
[0x18]);
566 mFileNameLength
= ZipEntry::getShortLE(&buf
[0x1c]);
567 mExtraFieldLength
= ZipEntry::getShortLE(&buf
[0x1e]);
568 mFileCommentLength
= ZipEntry::getShortLE(&buf
[0x20]);
569 mDiskNumberStart
= ZipEntry::getShortLE(&buf
[0x22]);
570 mInternalAttrs
= ZipEntry::getShortLE(&buf
[0x24]);
571 mExternalAttrs
= ZipEntry::getLongLE(&buf
[0x26]);
572 mLocalHeaderRelOffset
= ZipEntry::getLongLE(&buf
[0x2a]);
574 // TODO: validate sizes and offsets
577 if (mFileNameLength
!= 0) {
578 mFileName
= new unsigned char[mFileNameLength
+1];
579 if (mFileName
== NULL
) {
583 if (fread(mFileName
, 1, mFileNameLength
, fp
) != mFileNameLength
) {
584 result
= UNKNOWN_ERROR
;
587 mFileName
[mFileNameLength
] = '\0';
590 /* read "extra field" */
591 if (mExtraFieldLength
!= 0) {
592 mExtraField
= new unsigned char[mExtraFieldLength
+1];
593 if (mExtraField
== NULL
) {
597 if (fread(mExtraField
, 1, mExtraFieldLength
, fp
) != mExtraFieldLength
) {
598 result
= UNKNOWN_ERROR
;
601 mExtraField
[mExtraFieldLength
] = '\0';
605 /* grab comment, if any */
606 if (mFileCommentLength
!= 0) {
607 mFileComment
= new unsigned char[mFileCommentLength
+1];
608 if (mFileComment
== NULL
) {
612 if (fread(mFileComment
, 1, mFileCommentLength
, fp
) != mFileCommentLength
)
614 result
= UNKNOWN_ERROR
;
617 mFileComment
[mFileCommentLength
] = '\0';
625 * Write a central dir entry.
627 status_t
ZipEntry::CentralDirEntry::write(FILE* fp
)
629 unsigned char buf
[kCDELen
];
631 ZipEntry::putLongLE(&buf
[0x00], kSignature
);
632 ZipEntry::putShortLE(&buf
[0x04], mVersionMadeBy
);
633 ZipEntry::putShortLE(&buf
[0x06], mVersionToExtract
);
634 ZipEntry::putShortLE(&buf
[0x08], mGPBitFlag
);
635 ZipEntry::putShortLE(&buf
[0x0a], mCompressionMethod
);
636 ZipEntry::putShortLE(&buf
[0x0c], mLastModFileTime
);
637 ZipEntry::putShortLE(&buf
[0x0e], mLastModFileDate
);
638 ZipEntry::putLongLE(&buf
[0x10], mCRC32
);
639 ZipEntry::putLongLE(&buf
[0x14], mCompressedSize
);
640 ZipEntry::putLongLE(&buf
[0x18], mUncompressedSize
);
641 ZipEntry::putShortLE(&buf
[0x1c], mFileNameLength
);
642 ZipEntry::putShortLE(&buf
[0x1e], mExtraFieldLength
);
643 ZipEntry::putShortLE(&buf
[0x20], mFileCommentLength
);
644 ZipEntry::putShortLE(&buf
[0x22], mDiskNumberStart
);
645 ZipEntry::putShortLE(&buf
[0x24], mInternalAttrs
);
646 ZipEntry::putLongLE(&buf
[0x26], mExternalAttrs
);
647 ZipEntry::putLongLE(&buf
[0x2a], mLocalHeaderRelOffset
);
649 if (fwrite(buf
, 1, kCDELen
, fp
) != kCDELen
)
650 return UNKNOWN_ERROR
;
653 if (mFileNameLength
!= 0) {
654 if (fwrite(mFileName
, 1, mFileNameLength
, fp
) != mFileNameLength
)
655 return UNKNOWN_ERROR
;
658 /* write "extra field" */
659 if (mExtraFieldLength
!= 0) {
660 if (fwrite(mExtraField
, 1, mExtraFieldLength
, fp
) != mExtraFieldLength
)
661 return UNKNOWN_ERROR
;
665 if (mFileCommentLength
!= 0) {
666 if (fwrite(mFileComment
, 1, mFileCommentLength
, fp
) != mFileCommentLength
)
667 return UNKNOWN_ERROR
;
674 * Dump the contents of a CentralDirEntry object.
676 void ZipEntry::CentralDirEntry::dump(void) const
678 ALOGD(" CentralDirEntry contents:\n");
679 ALOGD(" versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n",
680 mVersionMadeBy
, mVersionToExtract
, mGPBitFlag
, mCompressionMethod
);
681 ALOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
682 mLastModFileTime
, mLastModFileDate
, mCRC32
);
683 ALOGD(" compressedSize=%lu uncompressedSize=%lu\n",
684 mCompressedSize
, mUncompressedSize
);
685 ALOGD(" filenameLen=%u extraLen=%u commentLen=%u\n",
686 mFileNameLength
, mExtraFieldLength
, mFileCommentLength
);
687 ALOGD(" diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n",
688 mDiskNumberStart
, mInternalAttrs
, mExternalAttrs
,
689 mLocalHeaderRelOffset
);
691 if (mFileName
!= NULL
)
692 ALOGD(" filename: '%s'\n", mFileName
);
693 if (mFileComment
!= NULL
)
694 ALOGD(" comment: '%s'\n", mFileComment
);