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