nsresult nsJARInputStream::InitFile(nsJAR *aJar, nsZipItem *item) { nsresult rv = NS_OK; MOZ_ASSERT(aJar, "Argument may not be null"); MOZ_ASSERT(item, "Argument may not be null"); // Mark it as closed, in case something fails in initialisation mMode = MODE_CLOSED; //-- prepare for the compression type switch (item->Compression()) { case STORED: mMode = MODE_COPY; break; case DEFLATED: rv = gZlibInit(&mZs); NS_ENSURE_SUCCESS(rv, rv); mMode = MODE_INFLATE; mInCrc = item->CRC32(); mOutCrc = crc32(0L, Z_NULL, 0); break; #ifdef MOZ_JAR_BROTLI case MOZ_JAR_BROTLI: mBrotliState = BrotliCreateState(nullptr, nullptr, nullptr); mMode = MODE_BROTLI; mInCrc = item->CRC32(); mOutCrc = crc32(0L, Z_NULL, 0); break; #endif default: return NS_ERROR_NOT_IMPLEMENTED; } // Must keep handle to filepointer and mmap structure as long as we need access to the mmapped data mFd = aJar->mZip->GetFD(); mZs.next_in = (Bytef *)aJar->mZip->GetData(item); if (!mZs.next_in) { nsZipArchive::sFileCorruptedReason = "nsJARInputStream: !mZs.next_in"; return NS_ERROR_FILE_CORRUPTED; } mZs.avail_in = item->Size(); mOutSize = item->RealSize(); mZs.total_out = 0; return NS_OK; }
nsresult nsJARInputStream::InitFile(nsZipArchive* aZip, nsZipItem *item, PRFileDesc *fd) { nsresult rv; // Keep the file handle, even on failure mFd = fd; NS_ENSURE_ARG_POINTER(aZip); NS_ENSURE_ARG_POINTER(item); NS_ENSURE_ARG_POINTER(fd); // Mark it as closed, in case something fails in initialisation mClosed = PR_TRUE; // Keep the important bits of nsZipItem only mInSize = item->size; //-- prepare for the compression type switch (item->compression) { case STORED: break; case DEFLATED: mInflate = (InflateStruct *) PR_Malloc(sizeof(InflateStruct)); NS_ENSURE_TRUE(mInflate, NS_ERROR_OUT_OF_MEMORY); rv = gZlibInit(&(mInflate->mZs)); NS_ENSURE_SUCCESS(rv, NS_ERROR_OUT_OF_MEMORY); mInflate->mOutSize = item->realsize; mInflate->mInCrc = item->crc32; mInflate->mOutCrc = crc32(0L, Z_NULL, 0); break; default: return NS_ERROR_NOT_IMPLEMENTED; } //-- Set filepointer to start of item rv = aZip->SeekToItem(item, mFd); NS_ENSURE_SUCCESS(rv, NS_ERROR_FILE_CORRUPTED); // Open for reading mClosed = PR_FALSE; mCurPos = 0; return NS_OK; }
//--------------------------------------------- // nsZipArchive::InflateItem //--------------------------------------------- nsresult nsZipArchive::InflateItem(const nsZipItem* aItem, PRFileDesc* outFD) /* * This function inflates an archive item to disk, to the * file specified by outFD. If outFD is zero, the extracted data is * not written, only checked for CRC, so this is in effect same as 'Test'. */ { PR_ASSERT(aItem); //-- allocate deflation buffers Bytef inbuf[ZIP_BUFLEN]; Bytef outbuf[ZIP_BUFLEN]; //-- set up the inflate z_stream zs; nsresult status = gZlibInit(&zs); if (status != ZIP_OK) return ZIP_ERR_GENERAL; //-- inflate loop zs.next_out = outbuf; zs.avail_out = ZIP_BUFLEN; PRUint32 size = aItem->size; PRUint32 outpos = 0; PRUint32 crc = crc32(0L, Z_NULL, 0); int zerr = Z_OK; while (zerr == Z_OK) { PRBool bRead = PR_FALSE; PRBool bWrote= PR_FALSE; if (zs.avail_in == 0 && zs.total_in < size) { //-- no data to inflate yet still more in file: //-- read another chunk of compressed data PRUint32 chunk = (size-zs.total_in < ZIP_BUFLEN) ? size-zs.total_in : ZIP_BUFLEN; if (PR_Read(mFd, inbuf, chunk) != (READTYPE)chunk) { //-- unexpected end of data status = ZIP_ERR_CORRUPT; break; } zs.next_in = inbuf; zs.avail_in = chunk; bRead = PR_TRUE; } if (zs.avail_out == 0) { //-- write inflated buffer to disk and make space if (outFD && PR_Write(outFD, outbuf, ZIP_BUFLEN) < ZIP_BUFLEN) { //-- Couldn't write all the data (disk full?) status = ZIP_ERR_DISK; break; } outpos = zs.total_out; zs.next_out = outbuf; zs.avail_out = ZIP_BUFLEN; bWrote = PR_TRUE; } if(bRead || bWrote) { Bytef* old_next_out = zs.next_out; zerr = inflate(&zs, Z_PARTIAL_FLUSH); //-- incrementally update crc32 crc = crc32(crc, (const unsigned char*)old_next_out, zs.next_out - old_next_out); } else zerr = Z_STREAM_END; #if defined STANDALONE && defined XP_WIN ProcessWindowsMessages(); #endif } // while //-- verify crc32 if ((status == ZIP_OK) && (crc != aItem->crc32)) { status = ZIP_ERR_CORRUPT; goto cleanup; } //-- write last inflated bit to disk if (zerr == Z_STREAM_END && outpos < zs.total_out) { PRUint32 chunk = zs.total_out - outpos; if (outFD && PR_Write(outFD, outbuf, chunk) < (READTYPE)chunk) status = ZIP_ERR_DISK; } //-- convert zlib error to return value if (status == ZIP_OK && zerr != Z_OK && zerr != Z_STREAM_END) { status = (zerr == Z_MEM_ERROR) ? ZIP_ERR_MEMORY : ZIP_ERR_CORRUPT; } //-- if found no errors make sure we've converted the whole thing // Allow for reading less than the total size if it appears we've // reached the end of the stream without error. It appears Celtx // can produce a .celtx file where an entry appears to be padded // with unnecessary data (size is 316752 bytes, but inflation // stops at 316749 bytes). It's still an error if we read more than // intended, or if the output doesn't match the expected size. PR_ASSERT(status != ZIP_OK || zs.total_in == aItem->size || (zerr == Z_STREAM_END && zs.total_in < aItem->size)); PR_ASSERT(status != ZIP_OK || zs.total_out == aItem->realsize); cleanup: //-- free zlib internal state inflateEnd(&zs); return status; }