tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsZipArchive.cpp (37550B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 /*
      7 * This module implements a simple archive extractor for the PKZIP format.
      8 */
      9 
     10 #define READTYPE int32_t
     11 #include "zlib.h"
     12 #include "nsISupportsUtils.h"
     13 #include "mozilla/MmapFaultHandler.h"
     14 #include "prio.h"
     15 #include "mozilla/Attributes.h"
     16 #include "mozilla/Logging.h"
     17 #include "mozilla/MemUtils.h"
     18 #include "mozilla/UniquePtrExtensions.h"
     19 #include "mozilla/StaticMutex.h"
     20 #include "mozilla/StaticPrefs_network.h"
     21 #include "stdlib.h"
     22 #include "nsDirectoryService.h"
     23 #include "nsWildCard.h"
     24 #include "nsXULAppAPI.h"
     25 #include "nsZipArchive.h"
     26 #include "nsString.h"
     27 #include "prenv.h"
     28 #if defined(XP_WIN)
     29 #  include <windows.h>
     30 #endif
     31 
     32 // For placement new used for arena allocations of zip file list
     33 #include <new>
     34 #define ZIP_ARENABLOCKSIZE (1 * 1024)
     35 
     36 #ifdef XP_UNIX
     37 #  include <sys/mman.h>
     38 #  include <sys/types.h>
     39 #  include <sys/stat.h>
     40 #  include <limits.h>
     41 #  include <unistd.h>
     42 #elif defined(XP_WIN)
     43 #  include <io.h>
     44 #endif
     45 
     46 #ifdef __SYMBIAN32__
     47 #  include <sys/syslimits.h>
     48 #endif /*__SYMBIAN32__*/
     49 
     50 #ifndef XP_UNIX /* we need some constants defined in limits.h and unistd.h */
     51 #  ifndef S_IFMT
     52 #    define S_IFMT 0170000
     53 #  endif
     54 #  ifndef S_IFLNK
     55 #    define S_IFLNK 0120000
     56 #  endif
     57 #  ifndef PATH_MAX
     58 #    define PATH_MAX 1024
     59 #  endif
     60 #endif /* XP_UNIX */
     61 
     62 #ifdef XP_WIN
     63 #  include "private/pprio.h"  // To get PR_ImportFile
     64 #endif
     65 
     66 using namespace mozilla;
     67 
     68 static LazyLogModule gZipLog("nsZipArchive");
     69 
     70 #ifdef LOG
     71 #  undef LOG
     72 #endif
     73 #ifdef LOG_ENABLED
     74 #  undef LOG_ENABLED
     75 #endif
     76 
     77 #define LOG(args) MOZ_LOG(gZipLog, mozilla::LogLevel::Debug, args)
     78 #define LOG_ENABLED() MOZ_LOG_TEST(gZipLog, mozilla::LogLevel::Debug)
     79 
     80 static const uint32_t kMaxNameLength = PATH_MAX; /* Maximum name length */
     81 // For synthetic zip entries. Date/time corresponds to 1980-01-01 00:00.
     82 static const uint16_t kSyntheticTime = 0;
     83 static const uint16_t kSyntheticDate = (1 + (1 << 5) + (0 << 9));
     84 
     85 static uint16_t xtoint(const uint8_t* ii);
     86 static uint32_t xtolong(const uint8_t* ll);
     87 static uint32_t HashName(const char* aName, uint16_t nameLen);
     88 
     89 class ZipArchiveLogger {
     90 public:
     91  void Init(const char* env) {
     92    StaticMutexAutoLock lock(sLock);
     93 
     94    // AddRef
     95    MOZ_ASSERT(mRefCnt >= 0);
     96    ++mRefCnt;
     97 
     98    if (!mFd) {
     99      nsCOMPtr<nsIFile> logFile;
    100      nsresult rv =
    101          NS_NewLocalFile(NS_ConvertUTF8toUTF16(env), getter_AddRefs(logFile));
    102      if (NS_FAILED(rv)) return;
    103 
    104      // Create the log file and its parent directory (in case it doesn't exist)
    105      rv = logFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
    106      if (NS_FAILED(rv)) return;
    107 
    108      PRFileDesc* file;
    109 #ifdef XP_WIN
    110      // PR_APPEND is racy on Windows, so open a handle ourselves with flags
    111      // that will work, and use PR_ImportFile to make it a PRFileDesc. This can
    112      // go away when bug 840435 is fixed.
    113      nsAutoString path;
    114      logFile->GetPath(path);
    115      if (path.IsEmpty()) return;
    116      HANDLE handle =
    117          CreateFileW(path.get(), FILE_APPEND_DATA, FILE_SHARE_WRITE, nullptr,
    118                      OPEN_ALWAYS, 0, nullptr);
    119      if (handle == INVALID_HANDLE_VALUE) return;
    120      file = PR_ImportFile((PROsfd)handle);
    121      if (!file) return;
    122 #else
    123      rv = logFile->OpenNSPRFileDesc(
    124          PR_WRONLY | PR_CREATE_FILE | PR_APPEND | PR_SYNC, 0644, &file);
    125      if (NS_FAILED(rv)) return;
    126 #endif
    127      mFd = file;
    128    }
    129  }
    130 
    131  void Write(const nsACString& zip, const char* entry) {
    132    StaticMutexAutoLock lock(sLock);
    133 
    134    if (mFd) {
    135      nsCString buf(zip);
    136      buf.Append(' ');
    137      buf.Append(entry);
    138      buf.Append('\n');
    139      PR_Write(mFd, buf.get(), buf.Length());
    140    }
    141  }
    142 
    143  void Release() {
    144    StaticMutexAutoLock lock(sLock);
    145 
    146    MOZ_ASSERT(mRefCnt > 0);
    147    if ((0 == --mRefCnt) && mFd) {
    148      PR_Close(mFd);
    149      mFd = nullptr;
    150    }
    151  }
    152 
    153 private:
    154  static StaticMutex sLock;
    155  int mRefCnt MOZ_GUARDED_BY(sLock);
    156  PRFileDesc* mFd MOZ_GUARDED_BY(sLock);
    157 };
    158 
    159 StaticMutex ZipArchiveLogger::sLock;
    160 static ZipArchiveLogger zipLog;
    161 
    162 //***********************************************************
    163 // For every inflation the following allocations are done:
    164 // malloc(1 * 9520)
    165 // malloc(32768 * 1)
    166 //***********************************************************
    167 
    168 nsresult gZlibInit(z_stream* zs) {
    169  memset(zs, 0, sizeof(z_stream));
    170  int zerr = inflateInit2(zs, -MAX_WBITS);
    171  if (zerr != Z_OK) return NS_ERROR_OUT_OF_MEMORY;
    172 
    173  return NS_OK;
    174 }
    175 
    176 nsZipHandle::nsZipHandle()
    177    : mFileData(nullptr),
    178      mLen(0),
    179      mMap(nullptr),
    180      mRefCnt(0),
    181      mFileStart(nullptr),
    182      mTotalLen(0) {}
    183 
    184 NS_IMPL_ADDREF(nsZipHandle)
    185 NS_IMPL_RELEASE(nsZipHandle)
    186 
    187 nsresult nsZipHandle::Init(nsIFile* file, nsZipHandle** ret, PRFileDesc** aFd) {
    188  mozilla::AutoFDClose fd;
    189  int32_t flags = PR_RDONLY;
    190 #if defined(XP_WIN)
    191  flags |= nsIFile::OS_READAHEAD;
    192 #endif
    193  LOG(("ZipHandle::Init %s", file->HumanReadablePath().get()));
    194  nsresult rv = file->OpenNSPRFileDesc(flags, 0000, getter_Transfers(fd));
    195  if (NS_FAILED(rv)) return rv;
    196 
    197  int64_t size = PR_Available64(fd.get());
    198  if (size >= INT32_MAX) return NS_ERROR_FILE_TOO_BIG;
    199 
    200  PRFileMap* map = PR_CreateFileMap(fd.get(), size, PR_PROT_READONLY);
    201  if (!map) return NS_ERROR_FAILURE;
    202 
    203  uint8_t* buf = (uint8_t*)PR_MemMap(map, 0, (uint32_t)size);
    204  // Bug 525755: PR_MemMap fails when fd points at something other than a normal
    205  // file.
    206  if (!buf) {
    207    PR_CloseFileMap(map);
    208    return NS_ERROR_FAILURE;
    209  }
    210 
    211  RefPtr<nsZipHandle> handle = new nsZipHandle();
    212  if (!handle) {
    213    PR_MemUnmap(buf, (uint32_t)size);
    214    PR_CloseFileMap(map);
    215    return NS_ERROR_OUT_OF_MEMORY;
    216  }
    217 
    218 #if defined(XP_WIN)
    219  if (aFd) {
    220    *aFd = fd.release();
    221  }
    222 #else
    223  handle->mNSPRFileDesc = std::move(fd);
    224 #endif
    225  handle->mFile.Init(file);
    226  handle->mTotalLen = (uint32_t)size;
    227  handle->mFileStart = buf;
    228  rv = handle->findDataStart();
    229  if (NS_FAILED(rv)) {
    230    PR_MemUnmap(buf, (uint32_t)size);
    231    handle->mFileStart = nullptr;
    232    PR_CloseFileMap(map);
    233    return rv;
    234  }
    235  handle->mMap = map;
    236  handle.forget(ret);
    237  return NS_OK;
    238 }
    239 
    240 nsresult nsZipHandle::Init(nsZipArchive* zip, const nsACString& entry,
    241                           nsZipHandle** ret) {
    242  RefPtr<nsZipHandle> handle = new nsZipHandle();
    243  if (!handle) return NS_ERROR_OUT_OF_MEMORY;
    244 
    245  LOG(("ZipHandle::Init entry %s", PromiseFlatCString(entry).get()));
    246 
    247  nsZipItem* item = zip->GetItem(entry);
    248  if (item && item->Compression() == DEFLATED &&
    249      StaticPrefs::network_jar_max_entry_size()) {
    250    if (item->RealSize() > StaticPrefs::network_jar_max_entry_size()) {
    251      return NS_ERROR_OUT_OF_MEMORY;
    252    }
    253  }
    254 
    255  handle->mBuf = MakeUnique<nsZipItemPtr<uint8_t>>(zip, entry);
    256  if (!handle->mBuf) return NS_ERROR_OUT_OF_MEMORY;
    257 
    258  if (!handle->mBuf->Buffer()) return NS_ERROR_UNEXPECTED;
    259 
    260  handle->mMap = nullptr;
    261  handle->mFile.Init(zip, entry);
    262  handle->mTotalLen = handle->mBuf->Length();
    263  handle->mFileStart = handle->mBuf->Buffer();
    264  nsresult rv = handle->findDataStart();
    265  if (NS_FAILED(rv)) {
    266    return rv;
    267  }
    268  handle.forget(ret);
    269  return NS_OK;
    270 }
    271 
    272 nsresult nsZipHandle::Init(const uint8_t* aData, uint32_t aLen,
    273                           nsZipHandle** aRet) {
    274  RefPtr<nsZipHandle> handle = new nsZipHandle();
    275 
    276  handle->mFileStart = aData;
    277  handle->mTotalLen = aLen;
    278  nsresult rv = handle->findDataStart();
    279  if (NS_FAILED(rv)) {
    280    return rv;
    281  }
    282  handle.forget(aRet);
    283  return NS_OK;
    284 }
    285 
    286 // This function finds the start of the ZIP data. If the file is a regular ZIP,
    287 // this is just the start of the file. If the file is a CRX file, the start of
    288 // the data is after the CRX header.
    289 //
    290 // CRX header reference, version 2:
    291 //    Header requires little-endian byte ordering with 4-byte alignment.
    292 //    32 bits       : magicNumber   - Defined as a |char m[] = "Cr24"|.
    293 //                                    Equivilant to |uint32_t m = 0x34327243|.
    294 //    32 bits       : version       - Unsigned integer representing the CRX file
    295 //                                    format version. Currently equal to 2.
    296 //    32 bits       : pubKeyLength  - Unsigned integer representing the length
    297 //                                    of the public key in bytes.
    298 //    32 bits       : sigLength     - Unsigned integer representing the length
    299 //                                    of the signature in bytes.
    300 //    pubKeyLength  : publicKey     - Contents of the author's public key.
    301 //    sigLength     : signature     - Signature of the ZIP content.
    302 //                                    Signature is created using the RSA
    303 //                                    algorithm with the SHA-1 hash function.
    304 //
    305 // CRX header reference, version 3:
    306 //    Header requires little-endian byte ordering with 4-byte alignment.
    307 //    32 bits       : magicNumber   - Defined as a |char m[] = "Cr24"|.
    308 //                                    Equivilant to |uint32_t m = 0x34327243|.
    309 //    32 bits       : version       - Unsigned integer representing the CRX file
    310 //                                    format version. Currently equal to 3.
    311 //    32 bits       : headerLength  - Unsigned integer representing the length
    312 //                                    of the CRX header in bytes.
    313 //    headerLength  : header        - CRXv3 header.
    314 nsresult nsZipHandle::findDataStart() {
    315  // In the CRX header, integers are 32 bits. Our pointer to the file is of
    316  // type |uint8_t|, which is guaranteed to be 8 bits.
    317  const uint32_t CRXIntSize = 4;
    318 
    319  MMAP_FAULT_HANDLER_BEGIN_HANDLE(this)
    320  if (mTotalLen > CRXIntSize * 4 && xtolong(mFileStart) == kCRXMagic) {
    321    const uint8_t* headerData = mFileStart;
    322    headerData += CRXIntSize;  // Skip magic number
    323    uint32_t version = xtolong(headerData);
    324    headerData += CRXIntSize;  // Skip version
    325    uint32_t headerSize = CRXIntSize * 2;
    326    if (version == 3) {
    327      uint32_t subHeaderSize = xtolong(headerData);
    328      headerSize += CRXIntSize + subHeaderSize;
    329    } else if (version < 3) {
    330      uint32_t pubKeyLength = xtolong(headerData);
    331      headerData += CRXIntSize;
    332      uint32_t sigLength = xtolong(headerData);
    333      headerSize += CRXIntSize * 2 + pubKeyLength + sigLength;
    334    } else {
    335      return NS_ERROR_FILE_CORRUPTED;
    336    }
    337    if (mTotalLen > headerSize) {
    338      mLen = mTotalLen - headerSize;
    339      mFileData = mFileStart + headerSize;
    340      return NS_OK;
    341    }
    342    return NS_ERROR_FILE_CORRUPTED;
    343  }
    344  mLen = mTotalLen;
    345  mFileData = mFileStart;
    346  MMAP_FAULT_HANDLER_CATCH(NS_ERROR_FAILURE)
    347  return NS_OK;
    348 }
    349 
    350 int64_t nsZipHandle::SizeOfMapping() { return mTotalLen; }
    351 
    352 nsresult nsZipHandle::GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc) {
    353  if (!aNSPRFileDesc) {
    354    return NS_ERROR_ILLEGAL_VALUE;
    355  }
    356 
    357  *aNSPRFileDesc = mNSPRFileDesc.get();
    358  if (!mNSPRFileDesc) {
    359    return NS_ERROR_NOT_AVAILABLE;
    360  }
    361 
    362  return NS_OK;
    363 }
    364 
    365 nsZipHandle::~nsZipHandle() {
    366  if (mMap) {
    367    PR_MemUnmap((void*)mFileStart, mTotalLen);
    368    PR_CloseFileMap(mMap);
    369  }
    370  mFileStart = nullptr;
    371  mFileData = nullptr;
    372  mMap = nullptr;
    373  mBuf = nullptr;
    374 }
    375 
    376 //***********************************************************
    377 //      nsZipArchive  --  public methods
    378 //***********************************************************
    379 
    380 //---------------------------------------------
    381 //  nsZipArchive::OpenArchive
    382 //---------------------------------------------
    383 /* static */
    384 already_AddRefed<nsZipArchive> nsZipArchive::OpenArchive(
    385    nsZipHandle* aZipHandle, PRFileDesc* aFd) {
    386  nsresult rv;
    387  RefPtr<nsZipArchive> self(new nsZipArchive(aZipHandle, aFd, rv));
    388  LOG(("ZipHandle::OpenArchive[%p]", self.get()));
    389  if (NS_FAILED(rv)) {
    390    self = nullptr;
    391  }
    392  return self.forget();
    393 }
    394 
    395 /* static */
    396 already_AddRefed<nsZipArchive> nsZipArchive::OpenArchive(nsIFile* aFile) {
    397  RefPtr<nsZipHandle> handle;
    398 #if defined(XP_WIN)
    399  mozilla::AutoFDClose fd;
    400  nsresult rv =
    401      nsZipHandle::Init(aFile, getter_AddRefs(handle), getter_Transfers(fd));
    402 #else
    403  nsresult rv = nsZipHandle::Init(aFile, getter_AddRefs(handle));
    404 #endif
    405  if (NS_FAILED(rv)) return nullptr;
    406 
    407 #if defined(XP_WIN)
    408  return OpenArchive(handle, fd.get());
    409 #else
    410  return OpenArchive(handle);
    411 #endif
    412 }
    413 
    414 //---------------------------------------------
    415 //  nsZipArchive::Test
    416 //---------------------------------------------
    417 nsresult nsZipArchive::Test(const nsACString& aEntryName) {
    418  nsZipItem* currItem;
    419 
    420  if (aEntryName.Length())  // only test specified item
    421  {
    422    currItem = GetItem(aEntryName);
    423    if (!currItem) return NS_ERROR_FILE_NOT_FOUND;
    424    //-- don't test (synthetic) directory items
    425    if (currItem->IsDirectory()) return NS_OK;
    426    return ExtractFile(currItem, 0, 0);
    427  }
    428 
    429  // test all items in archive
    430  for (auto* item : mFiles) {
    431    for (currItem = item; currItem; currItem = currItem->next) {
    432      //-- don't test (synthetic) directory items
    433      if (currItem->IsDirectory()) continue;
    434      nsresult rv = ExtractFile(currItem, 0, 0);
    435      if (rv != NS_OK) return rv;
    436    }
    437  }
    438 
    439  return NS_OK;
    440 }
    441 
    442 //---------------------------------------------
    443 // nsZipArchive::GetItem
    444 //---------------------------------------------
    445 nsZipItem* nsZipArchive::GetItem(const nsACString& aEntryName) {
    446  MutexAutoLock lock(mLock);
    447 
    448  LOG(("ZipHandle::GetItem[%p] %s", this,
    449       PromiseFlatCString(aEntryName).get()));
    450  if (aEntryName.Length()) {
    451    uint32_t len = aEntryName.Length();
    452    //-- If the request is for a directory, make sure that synthetic entries
    453    //-- are created for the directories without their own entry.
    454    if (!mBuiltSynthetics) {
    455      if ((len > 0) && (aEntryName[len - 1] == '/')) {
    456        if (BuildSynthetics() != NS_OK) return 0;
    457      }
    458    }
    459    MMAP_FAULT_HANDLER_BEGIN_HANDLE(mFd)
    460    nsZipItem* item = mFiles[HashName(aEntryName.BeginReading(), len)];
    461    while (item) {
    462      if ((len == item->nameLength) &&
    463          (!memcmp(aEntryName.BeginReading(), item->Name(), len))) {
    464        // Successful GetItem() is a good indicator that the file is about to be
    465        // read
    466        if (mUseZipLog && mURI.Length()) {
    467          zipLog.Write(mURI, aEntryName.BeginReading());
    468        }
    469        return item;  //-- found it
    470      }
    471      item = item->next;
    472    }
    473    MMAP_FAULT_HANDLER_CATCH(nullptr)
    474  }
    475  return nullptr;
    476 }
    477 
    478 //---------------------------------------------
    479 // nsZipArchive::ExtractFile
    480 // This extracts the item to the filehandle provided.
    481 // If 'aFd' is null, it only tests the extraction.
    482 // On extraction error(s) it removes the file.
    483 //---------------------------------------------
    484 nsresult nsZipArchive::ExtractFile(nsZipItem* item, nsIFile* outFile,
    485                                   PRFileDesc* aFd) {
    486  MutexAutoLock lock(mLock);
    487  LOG(("ZipHandle::ExtractFile[%p]", this));
    488  if (!item) return NS_ERROR_ILLEGAL_VALUE;
    489  if (!mFd) return NS_ERROR_FAILURE;
    490 
    491  // Directory extraction is handled in nsJAR::Extract,
    492  // so the item to be extracted should never be a directory
    493  MOZ_ASSERT(!item->IsDirectory());
    494 
    495  Bytef outbuf[ZIP_BUFLEN];
    496 
    497  nsZipCursor cursor(item, this, outbuf, ZIP_BUFLEN, true);
    498 
    499  nsresult rv = NS_OK;
    500 
    501  while (true) {
    502    uint32_t count = 0;
    503    uint8_t* buf = cursor.Read(&count);
    504    if (!buf) {
    505      rv = NS_ERROR_FILE_CORRUPTED;
    506      break;
    507    }
    508    if (count == 0) {
    509      break;
    510    }
    511 
    512    if (aFd && PR_Write(aFd, buf, count) < (READTYPE)count) {
    513      rv = NS_ERROR_FILE_NO_DEVICE_SPACE;
    514      break;
    515    }
    516  }
    517 
    518  //-- delete the file on errors
    519  if (aFd) {
    520    PR_Close(aFd);
    521    if (NS_FAILED(rv) && outFile) {
    522      outFile->Remove(false);
    523    }
    524  }
    525 
    526  return rv;
    527 }
    528 
    529 //---------------------------------------------
    530 // nsZipArchive::FindInit
    531 //---------------------------------------------
    532 nsresult nsZipArchive::FindInit(const char* aPattern, nsZipFind** aFind) {
    533  if (!aFind) return NS_ERROR_ILLEGAL_VALUE;
    534 
    535  MutexAutoLock lock(mLock);
    536 
    537  LOG(("ZipHandle::FindInit[%p]", this));
    538  // null out param in case an error happens
    539  *aFind = nullptr;
    540 
    541  bool regExp = false;
    542  char* pattern = 0;
    543 
    544  // Create synthetic directory entries on demand
    545  nsresult rv = BuildSynthetics();
    546  if (rv != NS_OK) return rv;
    547 
    548  // validate the pattern
    549  if (aPattern) {
    550    switch (NS_WildCardValid((char*)aPattern)) {
    551      case INVALID_SXP:
    552        return NS_ERROR_ILLEGAL_VALUE;
    553 
    554      case NON_SXP:
    555        regExp = false;
    556        break;
    557 
    558      case VALID_SXP:
    559        regExp = true;
    560        break;
    561 
    562      default:
    563        // undocumented return value from RegExpValid!
    564        MOZ_ASSERT(false);
    565        return NS_ERROR_ILLEGAL_VALUE;
    566    }
    567 
    568    pattern = strdup(aPattern);
    569    if (!pattern) return NS_ERROR_OUT_OF_MEMORY;
    570  }
    571 
    572  *aFind = new nsZipFind(this, pattern, regExp);
    573  if (!*aFind) {
    574    free(pattern);
    575    return NS_ERROR_OUT_OF_MEMORY;
    576  }
    577 
    578  return NS_OK;
    579 }
    580 
    581 //---------------------------------------------
    582 // nsZipFind::FindNext
    583 //---------------------------------------------
    584 nsresult nsZipFind::FindNext(const char** aResult, uint16_t* aNameLen) {
    585  if (!aResult || !aNameLen) return NS_ERROR_ILLEGAL_VALUE;
    586  NS_ENSURE_TRUE(mArchive, NS_ERROR_FILE_NOT_FOUND);
    587 
    588  MutexAutoLock lock(mArchive->mLock);
    589  *aResult = 0;
    590  *aNameLen = 0;
    591  MMAP_FAULT_HANDLER_BEGIN_HANDLE(mArchive->GetFD())
    592  // we start from last match, look for next
    593  while (mSlot < ZIP_TABSIZE) {
    594    // move to next in current chain, or move to new slot
    595    mItem = mItem ? mItem->next : mArchive->mFiles[mSlot];
    596 
    597    bool found = false;
    598    if (!mItem)
    599      ++mSlot;  // no more in this chain, move to next slot
    600    else if (!mPattern)
    601      found = true;  // always match
    602    else if (mRegExp) {
    603      char buf[kMaxNameLength + 1];
    604      memcpy(buf, mItem->Name(), mItem->nameLength);
    605      buf[mItem->nameLength] = '\0';
    606      found = (NS_WildCardMatch(buf, mPattern, false) == MATCH);
    607    } else
    608      found = ((mItem->nameLength == strlen(mPattern)) &&
    609               (memcmp(mItem->Name(), mPattern, mItem->nameLength) == 0));
    610    if (found) {
    611      // Need also to return the name length, as it is NOT zero-terminatdd...
    612      *aResult = mItem->Name();
    613      *aNameLen = mItem->nameLength;
    614      LOG(("ZipHandle::FindNext[%p] %s", this, *aResult));
    615      return NS_OK;
    616    }
    617  }
    618  MMAP_FAULT_HANDLER_CATCH(NS_ERROR_FAILURE)
    619  LOG(("ZipHandle::FindNext[%p] not found %s", this, mPattern));
    620  // Release the archive.
    621  mArchive = nullptr;
    622  mItem = nullptr;
    623  return NS_ERROR_FILE_NOT_FOUND;
    624 }
    625 
    626 //***********************************************************
    627 //      nsZipArchive  --  private implementation
    628 //***********************************************************
    629 
    630 //---------------------------------------------
    631 //  nsZipArchive::CreateZipItem
    632 //---------------------------------------------
    633 nsZipItem* nsZipArchive::CreateZipItem() {
    634  // Arena allocate the nsZipItem
    635  return (nsZipItem*)mArena.Allocate(sizeof(nsZipItem), mozilla::fallible);
    636 }
    637 
    638 //---------------------------------------------
    639 //  nsZipArchive::BuildFileList
    640 //---------------------------------------------
    641 nsresult nsZipArchive::BuildFileList(PRFileDesc* aFd)
    642    MOZ_NO_THREAD_SAFETY_ANALYSIS {
    643  // We're only called from the constructor, but need to call
    644  // CreateZipItem(), which touches locked data, and modify mFiles.  Turn
    645  // off thread-safety, which normally doesn't apply for constructors
    646  // anyways
    647 
    648  // Get archive size using end pos
    649  const uint8_t* buf;
    650  const uint8_t* startp = mFd->mFileData;
    651  const uint8_t* endp = startp + mFd->mLen;
    652  MMAP_FAULT_HANDLER_BEGIN_HANDLE(mFd)
    653  uint32_t centralOffset = 4;
    654  LOG(("ZipHandle::BuildFileList[%p]", this));
    655  // Only perform readahead in the parent process. Children processes
    656  // don't need readahead when the file has already been readahead by
    657  // the parent process, and readahead only really happens for omni.ja,
    658  // which is used in the parent process.
    659  if (XRE_IsParentProcess() && mFd->mLen > ZIPCENTRAL_SIZE &&
    660      xtolong(startp + centralOffset) == CENTRALSIG) {
    661    // Success means optimized jar layout from bug 559961 is in effect
    662    uint32_t readaheadLength = xtolong(startp);
    663    mozilla::PrefetchMemory(const_cast<uint8_t*>(startp), readaheadLength);
    664  } else {
    665    for (buf = endp - ZIPEND_SIZE; buf > startp; buf--) {
    666      if (xtolong(buf) == ENDSIG) {
    667        centralOffset = xtolong(((ZipEnd*)buf)->offset_central_dir);
    668        break;
    669      }
    670    }
    671  }
    672 
    673  if (!centralOffset) {
    674    return NS_ERROR_FILE_CORRUPTED;
    675  }
    676 
    677  buf = startp + centralOffset;
    678 
    679  // avoid overflow of startp + centralOffset.
    680  if (buf < startp) {
    681    return NS_ERROR_FILE_CORRUPTED;
    682  }
    683 
    684  //-- Read the central directory headers
    685  uint32_t sig = 0;
    686  while ((buf + int32_t(sizeof(uint32_t)) > buf) &&
    687         (buf + int32_t(sizeof(uint32_t)) <= endp) &&
    688         ((sig = xtolong(buf)) == CENTRALSIG)) {
    689    // Make sure there is enough data available.
    690    if ((buf > endp) || (endp - buf < ZIPCENTRAL_SIZE)) {
    691      return NS_ERROR_FILE_CORRUPTED;
    692    }
    693 
    694    // Read the fixed-size data.
    695    ZipCentral* central = (ZipCentral*)buf;
    696 
    697    uint16_t namelen = xtoint(central->filename_len);
    698    uint16_t extralen = xtoint(central->extrafield_len);
    699    uint16_t commentlen = xtoint(central->commentfield_len);
    700    uint32_t diff = ZIPCENTRAL_SIZE + namelen + extralen + commentlen;
    701 
    702    // Sanity check variable sizes and refuse to deal with
    703    // anything too big: it's likely a corrupt archive.
    704    if (namelen < 1 || namelen > kMaxNameLength) {
    705      return NS_ERROR_FILE_CORRUPTED;
    706    }
    707    if (buf >= buf + diff ||  // No overflow
    708        buf >= endp - diff) {
    709      return NS_ERROR_FILE_CORRUPTED;
    710    }
    711 
    712    // Point to the next item at the top of loop
    713    buf += diff;
    714 
    715    nsZipItem* item = CreateZipItem();
    716    if (!item) return NS_ERROR_OUT_OF_MEMORY;
    717 
    718    item->central = central;
    719    item->nameLength = namelen;
    720    item->isSynthetic = false;
    721 
    722    // Add item to file table
    723 #ifdef DEBUG
    724    nsDependentCSubstring name(item->Name(), namelen);
    725    LOG(("   %s", PromiseFlatCString(name).get()));
    726 #endif
    727    uint32_t hash = HashName(item->Name(), namelen);
    728    item->next = mFiles[hash];
    729    mFiles[hash] = item;
    730 
    731    sig = 0;
    732  } /* while reading central directory records */
    733 
    734  if (sig != ENDSIG && sig != ENDSIG64) {
    735    return NS_ERROR_FILE_CORRUPTED;
    736  }
    737 
    738  MMAP_FAULT_HANDLER_CATCH(NS_ERROR_FAILURE)
    739  return NS_OK;
    740 }
    741 
    742 //---------------------------------------------
    743 //  nsZipArchive::BuildSynthetics
    744 //---------------------------------------------
    745 nsresult nsZipArchive::BuildSynthetics() {
    746  mLock.AssertCurrentThreadOwns();
    747 
    748  if (mBuiltSynthetics) return NS_OK;
    749  mBuiltSynthetics = true;
    750 
    751  MMAP_FAULT_HANDLER_BEGIN_HANDLE(mFd)
    752  // Create synthetic entries for any missing directories.
    753  // Do this when all ziptable has scanned to prevent double entries.
    754  for (auto* item : mFiles) {
    755    for (; item != nullptr; item = item->next) {
    756      if (item->isSynthetic) continue;
    757 
    758      //-- add entries for directories in the current item's path
    759      //-- go from end to beginning, because then we can stop trying
    760      //-- to create diritems if we find that the diritem we want to
    761      //-- create already exists
    762      //-- start just before the last char so as to not add the item
    763      //-- twice if it's a directory
    764      uint16_t namelen = item->nameLength;
    765      MOZ_ASSERT(namelen > 0,
    766                 "Attempt to build synthetic for zero-length entry name!");
    767      const char* name = item->Name();
    768      for (uint16_t dirlen = namelen - 1; dirlen > 0; dirlen--) {
    769        if (name[dirlen - 1] != '/') continue;
    770 
    771        // The character before this is '/', so if this is also '/' then we
    772        // have an empty path component. Skip it.
    773        if (name[dirlen] == '/') continue;
    774 
    775        // Is the directory already in the file table?
    776        uint32_t hash = HashName(item->Name(), dirlen);
    777        bool found = false;
    778        for (nsZipItem* zi = mFiles[hash]; zi != nullptr; zi = zi->next) {
    779          if ((dirlen == zi->nameLength) &&
    780              (0 == memcmp(item->Name(), zi->Name(), dirlen))) {
    781            // we've already added this dir and all its parents
    782            found = true;
    783            break;
    784          }
    785        }
    786        // if the directory was found, break out of the directory
    787        // creation loop now that we know all implicit directories
    788        // are there -- otherwise, start creating the zip item
    789        if (found) break;
    790 
    791        nsZipItem* diritem = CreateZipItem();
    792        if (!diritem) return NS_ERROR_OUT_OF_MEMORY;
    793 
    794        // Point to the central record of the original item for the name part.
    795        diritem->central = item->central;
    796        diritem->nameLength = dirlen;
    797        diritem->isSynthetic = true;
    798 
    799        // add diritem to the file table
    800        diritem->next = mFiles[hash];
    801        mFiles[hash] = diritem;
    802      } /* end processing of dirs in item's name */
    803    }
    804  }
    805  MMAP_FAULT_HANDLER_CATCH(NS_ERROR_FAILURE)
    806  return NS_OK;
    807 }
    808 
    809 //---------------------------------------------
    810 // nsZipArchive::GetFD
    811 //---------------------------------------------
    812 nsZipHandle* nsZipArchive::GetFD() const { return mFd.get(); }
    813 
    814 //---------------------------------------------
    815 // nsZipArchive::GetDataOffset
    816 // Returns 0 on an error; 0 is not a valid result for any success case
    817 //---------------------------------------------
    818 uint32_t nsZipArchive::GetDataOffset(nsZipItem* aItem) {
    819  MOZ_ASSERT(aItem);
    820  MOZ_DIAGNOSTIC_ASSERT(mFd);
    821 
    822  uint32_t offset;
    823  MMAP_FAULT_HANDLER_BEGIN_HANDLE(mFd)
    824  //-- read local header to get variable length values and calculate
    825  //-- the real data offset
    826  uint32_t len = mFd->mLen;
    827  MOZ_DIAGNOSTIC_ASSERT(len <= UINT32_MAX, "mLen > 2GB");
    828  const uint8_t* data = mFd->mFileData;
    829  offset = aItem->LocalOffset();
    830  if (len < ZIPLOCAL_SIZE || offset > len - ZIPLOCAL_SIZE) {
    831    return 0;
    832  }
    833  // Check there's enough space for the signature
    834  if (offset > mFd->mLen) {
    835    NS_WARNING("Corrupt local offset in JAR file");
    836    return 0;
    837  }
    838 
    839  // -- check signature before using the structure, in case the zip file is
    840  // corrupt
    841  ZipLocal* Local = (ZipLocal*)(data + offset);
    842  if ((xtolong(Local->signature) != LOCALSIG)) return 0;
    843 
    844  //-- NOTE: extralen is different in central header and local header
    845  //--       for archives created using the Unix "zip" utility. To set
    846  //--       the offset accurately we need the _local_ extralen.
    847  offset += ZIPLOCAL_SIZE + xtoint(Local->filename_len) +
    848            xtoint(Local->extrafield_len);
    849  // Check data points inside the file.
    850  if (offset > mFd->mLen) {
    851    NS_WARNING("Corrupt data offset in JAR file");
    852    return 0;
    853  }
    854 
    855  MMAP_FAULT_HANDLER_CATCH(0)
    856  // can't be 0
    857  return offset;
    858 }
    859 
    860 //---------------------------------------------
    861 // nsZipArchive::GetData
    862 //---------------------------------------------
    863 const uint8_t* nsZipArchive::GetData(nsZipItem* aItem) {
    864  MOZ_DIAGNOSTIC_ASSERT(aItem);
    865  if (!aItem) {
    866    return nullptr;
    867  }
    868  uint32_t offset = GetDataOffset(aItem);
    869 
    870  MMAP_FAULT_HANDLER_BEGIN_HANDLE(mFd)
    871  // -- check if there is enough source data in the file
    872  if (!offset || mFd->mLen < aItem->Size() ||
    873      offset > mFd->mLen - aItem->Size() ||
    874      (aItem->Compression() == STORED && aItem->Size() != aItem->RealSize())) {
    875    return nullptr;
    876  }
    877  MMAP_FAULT_HANDLER_CATCH(nullptr)
    878 
    879  return mFd->mFileData + offset;
    880 }
    881 
    882 //---------------------------------------------
    883 // nsZipArchive::SizeOfMapping
    884 //---------------------------------------------
    885 int64_t nsZipArchive::SizeOfMapping() { return mFd ? mFd->SizeOfMapping() : 0; }
    886 
    887 //------------------------------------------
    888 // nsZipArchive constructor and destructor
    889 //------------------------------------------
    890 
    891 nsZipArchive::nsZipArchive(nsZipHandle* aZipHandle, PRFileDesc* aFd,
    892                           nsresult& aRv)
    893    : mRefCnt(0), mFd(aZipHandle), mUseZipLog(false), mBuiltSynthetics(false) {
    894  // initialize the table to nullptr
    895  memset(mFiles, 0, sizeof(mFiles));
    896  MOZ_DIAGNOSTIC_ASSERT(aZipHandle);
    897 
    898  //-- get table of contents for archive
    899  aRv = BuildFileList(aFd);
    900  if (NS_FAILED(aRv)) {
    901    return;  // whomever created us must destroy us in this case
    902  }
    903  if (aZipHandle->mFile && XRE_IsParentProcess()) {
    904    static char* env = PR_GetEnv("MOZ_JAR_LOG_FILE");
    905    if (env) {
    906      mUseZipLog = true;
    907 
    908      zipLog.Init(env);
    909      // We only log accesses in jar/zip archives within the NS_GRE_DIR
    910      // and/or the APK on Android. For the former, we log the archive path
    911      // relative to NS_GRE_DIR, and for the latter, the nested-archive
    912      // path within the APK. This makes the path match the path of the
    913      // archives relative to the packaged dist/$APP_NAME directory in a
    914      // build.
    915      if (aZipHandle->mFile.IsZip()) {
    916        // Nested archive, likely omni.ja in APK.
    917        aZipHandle->mFile.GetPath(mURI);
    918      } else if (nsDirectoryService::gService) {
    919        // We can reach here through the initialization of Omnijar from
    920        // XRE_InitCommandLine, which happens before the directory service
    921        // is initialized. When that happens, it means the opened archive is
    922        // the APK, and we don't care to log that one, so we just skip
    923        // when the directory service is not initialized.
    924        nsCOMPtr<nsIFile> dir = aZipHandle->mFile.GetBaseFile();
    925        nsCOMPtr<nsIFile> gre_dir;
    926        nsAutoCString path;
    927        if (NS_SUCCEEDED(nsDirectoryService::gService->Get(
    928                NS_GRE_DIR, NS_GET_IID(nsIFile), getter_AddRefs(gre_dir)))) {
    929          nsAutoCString leaf;
    930          nsCOMPtr<nsIFile> parent;
    931          while (NS_SUCCEEDED(dir->GetNativeLeafName(leaf)) &&
    932                 NS_SUCCEEDED(dir->GetParent(getter_AddRefs(parent)))) {
    933            if (!parent) {
    934              break;
    935            }
    936            dir = parent;
    937            if (path.Length()) {
    938              path.Insert('/', 0);
    939            }
    940            path.Insert(leaf, 0);
    941            bool equals;
    942            if (NS_SUCCEEDED(dir->Equals(gre_dir, &equals)) && equals) {
    943              mURI.Assign(path);
    944              break;
    945            }
    946          }
    947        }
    948      }
    949    }
    950  }
    951 }
    952 
    953 NS_IMPL_ADDREF(nsZipArchive)
    954 NS_IMPL_RELEASE(nsZipArchive)
    955 
    956 nsZipArchive::~nsZipArchive() {
    957  LOG(("Closing nsZipArchive[%p]", this));
    958  if (mUseZipLog) {
    959    zipLog.Release();
    960  }
    961 }
    962 
    963 //------------------------------------------
    964 // nsZipFind constructor and destructor
    965 //------------------------------------------
    966 
    967 nsZipFind::nsZipFind(nsZipArchive* aZip, char* aPattern, bool aRegExp)
    968    : mArchive(aZip),
    969      mPattern(aPattern),
    970      mItem(nullptr),
    971      mSlot(0),
    972      mRegExp(aRegExp) {
    973  MOZ_COUNT_CTOR(nsZipFind);
    974  MOZ_ASSERT(mArchive);
    975 }
    976 
    977 nsZipFind::~nsZipFind() {
    978  free(mPattern);
    979 
    980  MOZ_COUNT_DTOR(nsZipFind);
    981 }
    982 
    983 //------------------------------------------
    984 // helper functions
    985 //------------------------------------------
    986 
    987 /*
    988 * HashName
    989 *
    990 * returns a hash key for the entry name
    991 */
    992 MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
    993 static uint32_t HashName(const char* aName, uint16_t len) {
    994  MOZ_ASSERT(aName != 0);
    995 
    996  const uint8_t* p = (const uint8_t*)aName;
    997  const uint8_t* endp = p + len;
    998  uint32_t val = 0;
    999  while (p != endp) {
   1000    val = val * 37 + *p++;
   1001  }
   1002 
   1003  return (val % ZIP_TABSIZE);
   1004 }
   1005 
   1006 /*
   1007 *  x t o i n t
   1008 *
   1009 *  Converts a two byte ugly endianed integer
   1010 *  to our platform's integer.
   1011 */
   1012 static uint16_t xtoint(const uint8_t* ii) {
   1013  return (uint16_t)((ii[0]) | (ii[1] << 8));
   1014 }
   1015 
   1016 /*
   1017 *  x t o l o n g
   1018 *
   1019 *  Converts a four byte ugly endianed integer
   1020 *  to our platform's integer.
   1021 */
   1022 static uint32_t xtolong(const uint8_t* ll) {
   1023  return (uint32_t)((ll[0] << 0) | (ll[1] << 8) | (ll[2] << 16) |
   1024                    (ll[3] << 24));
   1025 }
   1026 
   1027 /*
   1028 * GetModTime
   1029 *
   1030 * returns last modification time in microseconds
   1031 */
   1032 static PRTime GetModTime(uint16_t aDate, uint16_t aTime) {
   1033  // Note that on DST shift we can't handle correctly the hour that is valid
   1034  // in both DST zones
   1035  PRExplodedTime time;
   1036 
   1037  time.tm_usec = 0;
   1038 
   1039  time.tm_hour = (aTime >> 11) & 0x1F;
   1040  time.tm_min = (aTime >> 5) & 0x3F;
   1041  time.tm_sec = (aTime & 0x1F) * 2;
   1042 
   1043  time.tm_year = (aDate >> 9) + 1980;
   1044  time.tm_month = ((aDate >> 5) & 0x0F) - 1;
   1045  time.tm_mday = aDate & 0x1F;
   1046 
   1047  time.tm_params.tp_gmt_offset = 0;
   1048  time.tm_params.tp_dst_offset = 0;
   1049 
   1050  PR_NormalizeTime(&time, PR_GMTParameters);
   1051  time.tm_params.tp_gmt_offset = PR_LocalTimeParameters(&time).tp_gmt_offset;
   1052  PR_NormalizeTime(&time, PR_GMTParameters);
   1053  time.tm_params.tp_dst_offset = PR_LocalTimeParameters(&time).tp_dst_offset;
   1054 
   1055  return PR_ImplodeTime(&time);
   1056 }
   1057 
   1058 nsZipItem::nsZipItem()
   1059    : next(nullptr), central(nullptr), nameLength(0), isSynthetic(false) {}
   1060 
   1061 uint32_t nsZipItem::LocalOffset() { return xtolong(central->localhdr_offset); }
   1062 
   1063 uint32_t nsZipItem::Size() { return isSynthetic ? 0 : xtolong(central->size); }
   1064 
   1065 uint32_t nsZipItem::RealSize() {
   1066  return isSynthetic ? 0 : xtolong(central->orglen);
   1067 }
   1068 
   1069 uint32_t nsZipItem::CRC32() {
   1070  return isSynthetic ? 0 : xtolong(central->crc32);
   1071 }
   1072 
   1073 uint16_t nsZipItem::Date() {
   1074  return isSynthetic ? kSyntheticDate : xtoint(central->date);
   1075 }
   1076 
   1077 uint16_t nsZipItem::Time() {
   1078  return isSynthetic ? kSyntheticTime : xtoint(central->time);
   1079 }
   1080 
   1081 uint16_t nsZipItem::Compression() {
   1082  return isSynthetic ? STORED : xtoint(central->method);
   1083 }
   1084 
   1085 bool nsZipItem::IsDirectory() {
   1086  return isSynthetic || ((nameLength > 0) && ('/' == Name()[nameLength - 1]));
   1087 }
   1088 
   1089 uint16_t nsZipItem::Mode() {
   1090  if (isSynthetic) return 0755;
   1091  return ((uint16_t)(central->external_attributes[2]) | 0x100);
   1092 }
   1093 
   1094 const uint8_t* nsZipItem::GetExtraField(uint16_t aTag, uint16_t* aBlockSize) {
   1095  if (isSynthetic) return nullptr;
   1096 
   1097  const unsigned char* buf =
   1098      ((const unsigned char*)central) + ZIPCENTRAL_SIZE + nameLength;
   1099  uint32_t buflen;
   1100 
   1101  MMAP_FAULT_HANDLER_BEGIN_BUFFER(central, ZIPCENTRAL_SIZE + nameLength)
   1102  buflen = (uint32_t)xtoint(central->extrafield_len);
   1103  MMAP_FAULT_HANDLER_CATCH(nullptr)
   1104 
   1105  uint32_t pos = 0;
   1106  uint16_t tag, blocksize;
   1107 
   1108  MMAP_FAULT_HANDLER_BEGIN_BUFFER(buf, buflen)
   1109  while (buf && (pos + 4) <= buflen) {
   1110    tag = xtoint(buf + pos);
   1111    blocksize = xtoint(buf + pos + 2);
   1112 
   1113    if (aTag == tag && (pos + 4 + blocksize) <= buflen) {
   1114      *aBlockSize = blocksize;
   1115      return buf + pos;
   1116    }
   1117 
   1118    pos += blocksize + 4;
   1119  }
   1120  MMAP_FAULT_HANDLER_CATCH(nullptr)
   1121 
   1122  return nullptr;
   1123 }
   1124 
   1125 PRTime nsZipItem::LastModTime() {
   1126  if (isSynthetic) return GetModTime(kSyntheticDate, kSyntheticTime);
   1127 
   1128  // Try to read timestamp from extra field
   1129  uint16_t blocksize;
   1130  const uint8_t* tsField = GetExtraField(EXTENDED_TIMESTAMP_FIELD, &blocksize);
   1131  if (tsField && blocksize >= 5 && tsField[4] & EXTENDED_TIMESTAMP_MODTIME) {
   1132    return (PRTime)(xtolong(tsField + 5)) * PR_USEC_PER_SEC;
   1133  }
   1134 
   1135  return GetModTime(Date(), Time());
   1136 }
   1137 
   1138 nsZipCursor::nsZipCursor(nsZipItem* item, nsZipArchive* aZip, uint8_t* aBuf,
   1139                         uint32_t aBufSize, bool doCRC)
   1140    : mItem(item),
   1141      mBuf(aBuf),
   1142      mBufSize(aBufSize),
   1143      mZs(),
   1144      mCRC(0),
   1145      mDoCRC(doCRC) {
   1146  if (mItem->Compression() == DEFLATED) {
   1147 #ifdef DEBUG
   1148    nsresult status =
   1149 #endif
   1150        gZlibInit(&mZs);
   1151    NS_ASSERTION(status == NS_OK, "Zlib failed to initialize");
   1152    NS_ASSERTION(aBuf, "Must pass in a buffer for DEFLATED nsZipItem");
   1153  }
   1154 
   1155  mZs.avail_in = item->Size();
   1156  mZs.next_in = (Bytef*)aZip->GetData(item);
   1157 
   1158  if (doCRC) mCRC = crc32(0L, Z_NULL, 0);
   1159 }
   1160 
   1161 nsZipCursor::~nsZipCursor() {
   1162  if (mItem->Compression() == DEFLATED) {
   1163    inflateEnd(&mZs);
   1164  }
   1165 }
   1166 
   1167 uint8_t* nsZipCursor::ReadOrCopy(uint32_t* aBytesRead, bool aCopy) {
   1168  int zerr;
   1169  uint8_t* buf = nullptr;
   1170  bool verifyCRC = true;
   1171 
   1172  if (!mZs.next_in) return nullptr;
   1173  MMAP_FAULT_HANDLER_BEGIN_BUFFER(mZs.next_in, mZs.avail_in)
   1174  switch (mItem->Compression()) {
   1175    case STORED:
   1176      if (!aCopy) {
   1177        *aBytesRead = mZs.avail_in;
   1178        buf = mZs.next_in;
   1179        mZs.next_in += mZs.avail_in;
   1180        mZs.avail_in = 0;
   1181      } else {
   1182        *aBytesRead = mZs.avail_in > mBufSize ? mBufSize : mZs.avail_in;
   1183        memcpy(mBuf, mZs.next_in, *aBytesRead);
   1184        mZs.avail_in -= *aBytesRead;
   1185        mZs.next_in += *aBytesRead;
   1186      }
   1187      break;
   1188    case DEFLATED:
   1189      buf = mBuf;
   1190      mZs.next_out = buf;
   1191      mZs.avail_out = mBufSize;
   1192 
   1193      zerr = inflate(&mZs, Z_PARTIAL_FLUSH);
   1194      if (zerr != Z_OK && zerr != Z_STREAM_END) return nullptr;
   1195 
   1196      *aBytesRead = mZs.next_out - buf;
   1197      verifyCRC = (zerr == Z_STREAM_END);
   1198      break;
   1199    default:
   1200      return nullptr;
   1201  }
   1202 
   1203  if (mDoCRC) {
   1204    mCRC = crc32(mCRC, (const unsigned char*)buf, *aBytesRead);
   1205    if (verifyCRC && mCRC != mItem->CRC32()) return nullptr;
   1206  }
   1207  MMAP_FAULT_HANDLER_CATCH(nullptr)
   1208  return buf;
   1209 }
   1210 
   1211 nsZipItemPtr_base::nsZipItemPtr_base(nsZipArchive* aZip,
   1212                                     const nsACString& aEntryName, bool doCRC)
   1213    : mReturnBuf(nullptr), mReadlen(0) {
   1214  // make sure the ziparchive hangs around
   1215  mZipHandle = aZip->GetFD();
   1216 
   1217  nsZipItem* item = aZip->GetItem(aEntryName);
   1218  if (!item) return;
   1219 
   1220  uint32_t size = 0;
   1221  bool compressed = (item->Compression() == DEFLATED);
   1222  if (compressed) {
   1223    size = item->RealSize();
   1224    mAutoBuf = MakeUniqueFallible<uint8_t[]>(size);
   1225    if (!mAutoBuf) {
   1226      return;
   1227    }
   1228  }
   1229 
   1230  nsZipCursor cursor(item, aZip, mAutoBuf.get(), size, doCRC);
   1231  mReturnBuf = cursor.Read(&mReadlen);
   1232  if (!mReturnBuf) {
   1233    return;
   1234  }
   1235 
   1236  if (mReadlen != item->RealSize()) {
   1237    NS_ASSERTION(mReadlen == item->RealSize(), "nsZipCursor underflow");
   1238    mReturnBuf = nullptr;
   1239    return;
   1240  }
   1241 }