github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/make/tools/zipalign/ZipEntry.cpp (about)

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