diff --git a/modules/libjar/nsJAR.cpp b/modules/libjar/nsJAR.cpp index 6d013281fb0..5168b31c282 100644 --- a/modules/libjar/nsJAR.cpp +++ b/modules/libjar/nsJAR.cpp @@ -339,7 +339,7 @@ nsJAR::GetInputStreamWithSpec(const nsACString& aJarDirSpec, if (!item || item->isDirectory) { rv = jis->InitDirectory(this, aJarDirSpec, aEntryName); } else { - rv = jis->InitFile(mZip.GetFD(item), item); + rv = jis->InitFile(this, item); } if (NS_FAILED(rv)) { NS_RELEASE(*result); diff --git a/modules/libjar/nsJARInputStream.cpp b/modules/libjar/nsJARInputStream.cpp index 50b392da4c7..b5d1d384d89 100644 --- a/modules/libjar/nsJARInputStream.cpp +++ b/modules/libjar/nsJARInputStream.cpp @@ -59,43 +59,42 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(nsJARInputStream, nsIInputStream) *--------------------------------------------------------*/ nsresult -nsJARInputStream::InitFile(nsZipHandle *aFd, nsZipItem *item) +nsJARInputStream::InitFile(nsJAR *aJar, nsZipItem *item) { - nsresult rv; - NS_ABORT_IF_FALSE(aFd, "Argument may not be null"); + nsresult rv = NS_OK; + NS_ABORT_IF_FALSE(aJar, "Argument may not be null"); NS_ABORT_IF_FALSE(item, "Argument may not be null"); // Mark it as closed, in case something fails in initialisation - mClosed = PR_TRUE; - // Keep the important bits of nsZipItem only - mInSize = item->size; - + mClosed = true; //-- prepare for the compression type switch (item->compression) { case STORED: + mCompressed = false; break; case DEFLATED: - mInflate = (InflateStruct *) PR_Malloc(sizeof(InflateStruct)); - NS_ENSURE_TRUE(mInflate, NS_ERROR_OUT_OF_MEMORY); - - rv = gZlibInit(&(mInflate->mZs)); + mCompressed = true; + rv = gZlibInit(&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); + mOutSize = item->realsize; + mInCrc = item->crc32; + mOutCrc = crc32(0L, Z_NULL, 0); break; default: return NS_ERROR_NOT_IMPLEMENTED; } - //-- Set filepointer to start of item - mFd.Open(aFd, item->dataOffset, item->size); - + // 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 = aJar->mZip.GetData(item); + mZs.avail_in = item->size; + mOutSize = item->realsize; + mDirectory = false; // Open for reading - mClosed = PR_FALSE; + mClosed = false; mCurPos = 0; return NS_OK; } @@ -109,8 +108,9 @@ nsJARInputStream::InitDirectory(nsJAR* aJar, NS_ABORT_IF_FALSE(aDir, "Argument may not be null"); // Mark it as closed, in case something fails in initialisation - mClosed = PR_TRUE; - mDirectory = PR_TRUE; + mClosed = true; + mDirectory = true; + mCompressed = false; // Keep the zipReader for getting the actual zipItems mJar = aJar; @@ -173,7 +173,7 @@ nsJARInputStream::InitDirectory(nsJAR* aJar, mBuffer.AppendLiteral("\n200: filename content-length last-modified file-type\n"); // Open for reading - mClosed = PR_FALSE; + mClosed = false; mCurPos = 0; mArrPos = 0; return NS_OK; @@ -187,10 +187,10 @@ nsJARInputStream::Available(PRUint32 *_retval) if (mDirectory) *_retval = mBuffer.Length(); - else if (mInflate) - *_retval = mInflate->mOutSize - mInflate->mZs.total_out; + else if (mCompressed) + *_retval = mOutSize - mZs.total_out; else - *_retval = mInSize - mCurPos; + *_retval = mOutSize - mCurPos; return NS_OK; } @@ -202,41 +202,30 @@ nsJARInputStream::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead) *aBytesRead = 0; - nsresult rv = NS_OK; if (mClosed) - return rv; + return NS_OK; if (mDirectory) { - rv = ReadDirectory(aBuffer, aCount, aBytesRead); - } else { - if (mInflate) { - rv = ContinueInflate(aBuffer, aCount, aBytesRead); - } else { - PRInt32 bytesRead = 0; - aCount = PR_MIN(aCount, mInSize - mCurPos); - if (aCount) { - bytesRead = mFd.Read(aBuffer, aCount); - if (bytesRead < 0) - return NS_ERROR_FILE_CORRUPTED; - mCurPos += bytesRead; - if ((PRUint32)bytesRead != aCount) { - // file is truncated or was lying about size, we're done - Close(); - return NS_ERROR_FILE_CORRUPTED; - } - } - *aBytesRead = bytesRead; - } + return ReadDirectory(aBuffer, aCount, aBytesRead); + } + if (mCompressed) { + return ContinueInflate(aBuffer, aCount, aBytesRead); + } + if (mFd) { + PRUint32 count = PR_MIN(aCount, mOutSize - mCurPos); + memcpy(aBuffer, mZs.next_in + mCurPos, count); + mCurPos += count; + *aBytesRead = count; // be aggressive about closing! // note that sometimes, we will close mFd before we've finished // deflating - this is because zlib buffers the input // So, don't free the ReadBuf/InflateStruct yet. // It is ok to close the fd multiple times (also in nsJARInputStream::Close()) - if (mCurPos >= mInSize) { - mFd.Close(); + if (mCurPos >= mZs.avail_in) { + mFd = nsnull; } } - return rv; + return NS_OK; } NS_IMETHODIMP @@ -257,9 +246,9 @@ nsJARInputStream::IsNonBlocking(PRBool *aNonBlocking) NS_IMETHODIMP nsJARInputStream::Close() { - PR_FREEIF(mInflate); - mClosed = PR_TRUE; - mFd.Close(); + mClosed = true; + mFd = nsnull; + mJar = nsnull; return NS_OK; } @@ -268,56 +257,33 @@ nsJARInputStream::ContinueInflate(char* aBuffer, PRUint32 aCount, PRUint32* aBytesRead) { // No need to check the args, ::Read did that, but assert them at least - NS_ASSERTION(mInflate,"inflate data structure missing"); NS_ASSERTION(aBuffer,"aBuffer parameter must not be null"); NS_ASSERTION(aBytesRead,"aBytesRead parameter must not be null"); // Keep old total_out count - const PRUint32 oldTotalOut = mInflate->mZs.total_out; + const PRUint32 oldTotalOut = mZs.total_out; // make sure we aren't reading too much - mInflate->mZs.avail_out = (mInflate->mOutSize-oldTotalOut > aCount) ? aCount : mInflate->mOutSize-oldTotalOut; - mInflate->mZs.next_out = (unsigned char*)aBuffer; - - int zerr = Z_OK; - //-- inflate loop - while (mInflate->mZs.avail_out > 0 && zerr == Z_OK) { - - if (mInflate->mZs.avail_in == 0 && mCurPos < mInSize) { - // time to fill the buffer! - PRUint32 bytesToRead = PR_MIN(mInSize - mCurPos, ZIP_BUFLEN); - - PRInt32 bytesRead = mFd.Read(mInflate->mReadBuf, bytesToRead); - if (bytesRead < 0) { - zerr = Z_ERRNO; - break; - } - mCurPos += bytesRead; - - // now set the state for 'inflate' - mInflate->mZs.next_in = mInflate->mReadBuf; - mInflate->mZs.avail_in = bytesRead; - } - - // now inflate - zerr = inflate(&(mInflate->mZs), Z_SYNC_FLUSH); - } + mZs.avail_out = PR_MIN(aCount, (mOutSize-oldTotalOut)); + mZs.next_out = (unsigned char*)aBuffer; + // now inflate + int zerr = inflate(&mZs, Z_SYNC_FLUSH); if ((zerr != Z_OK) && (zerr != Z_STREAM_END)) return NS_ERROR_FILE_CORRUPTED; - *aBytesRead = (mInflate->mZs.total_out - oldTotalOut); + *aBytesRead = (mZs.total_out - oldTotalOut); // Calculate the CRC on the output - mInflate->mOutCrc = crc32(mInflate->mOutCrc, (unsigned char*)aBuffer, *aBytesRead); + mOutCrc = crc32(mOutCrc, (unsigned char*)aBuffer, *aBytesRead); // be aggressive about ending the inflation // for some reason we don't always get Z_STREAM_END - if (zerr == Z_STREAM_END || mInflate->mZs.total_out == mInflate->mOutSize) { - inflateEnd(&(mInflate->mZs)); + if (zerr == Z_STREAM_END || mZs.total_out == mOutSize) { + inflateEnd(&mZs); // stop returning valid data as soon as we know we have a bad CRC - if (mInflate->mOutCrc != mInflate->mInCrc) { + if (mOutCrc != mInCrc) { // asserting because while this rarely happens, you definitely // want to catch it in debug builds! NS_NOTREACHED(0); diff --git a/modules/libjar/nsJARInputStream.h b/modules/libjar/nsJARInputStream.h index d626e96f4de..bd0b0646fca 100644 --- a/modules/libjar/nsJARInputStream.h +++ b/modules/libjar/nsJARInputStream.h @@ -53,45 +53,39 @@ class nsJARInputStream : public nsIInputStream { public: nsJARInputStream() : - mInSize(0), mCurPos(0), mInflate(nsnull), mDirectory(0), mClosed(PR_FALSE) - { } + mCurPos(0), mCompressed(false), mDirectory(false), mClosed(true) + { } - ~nsJARInputStream() { - Close(); - } + ~nsJARInputStream() { Close(); } NS_DECL_ISUPPORTS NS_DECL_NSIINPUTSTREAM // takes ownership of |fd|, even on failure - nsresult InitFile(nsZipHandle *aFd, nsZipItem *item); + nsresult InitFile(nsJAR *aJar, nsZipItem *item); nsresult InitDirectory(nsJAR *aJar, const nsACString& aJarDirSpec, const char* aDir); private: - PRUint32 mInSize; // Size in original file - PRUint32 mCurPos; // Current position in input - - struct InflateStruct { - PRUint32 mOutSize; // inflated size - PRUint32 mInCrc; // CRC as provided by the zipentry - PRUint32 mOutCrc; // CRC as calculated by me - z_stream mZs; // zip data structure - unsigned char mReadBuf[ZIP_BUFLEN]; // Readbuffer to inflate from - }; - struct InflateStruct * mInflate; + nsRefPtr mFd; // handle for reading + PRUint32 mCurPos; // Current position in input + PRUint32 mOutSize; // inflated size + PRUint32 mInCrc; // CRC as provided by the zipentry + PRUint32 mOutCrc; // CRC as calculated by me + z_stream mZs; // zip data structure /* For directory reading */ - nsRefPtr mJar; // string reference to zipreader - PRUint32 mNameLen; // length of dirname - nsCAutoString mBuffer; // storage for generated text of stream - PRUint32 mArrPos; // current position within mArray - nsTArray mArray; // array of names in (zip) directory - PRPackedBool mDirectory; // is this a directory? - PRPackedBool mClosed; // Whether the stream is closed - nsSeekableZipHandle mFd; // handle for reading + nsRefPtr mJar; // string reference to zipreader + PRUint32 mNameLen; // length of dirname + nsCString mBuffer; // storage for generated text of stream + PRUint32 mArrPos; // current position within mArray + nsTArray mArray; // array of names in (zip) directory + + bool mCompressed; // is this compressed? + bool mDirectory; // is this a directory? + bool mClosed; // Whether the stream is closed nsresult ContinueInflate(char* aBuf, PRUint32 aCount, PRUint32* aBytesRead); nsresult ReadDirectory(char* aBuf, PRUint32 aCount, PRUint32* aBytesRead); diff --git a/modules/libjar/nsZipArchive.cpp b/modules/libjar/nsZipArchive.cpp index d277fe1bf09..8049b63312d 100644 --- a/modules/libjar/nsZipArchive.cpp +++ b/modules/libjar/nsZipArchive.cpp @@ -50,7 +50,6 @@ */ -#define ZFILE_CREATE PR_WRONLY | PR_CREATE_FILE #define READTYPE PRInt32 #include "zlib.h" #include "nsISupportsUtils.h" @@ -173,7 +172,7 @@ zlibAlloc(void *opaque, uInt items, uInt size) PRUint32 realitems = items; if (size == 4 && items < BY4ALLOC_ITEMS) realitems = BY4ALLOC_ITEMS; - return zallocator->Calloc(realitems, size); + return zallocator->Calloc(realitems, size); } else return calloc(items, size); @@ -228,13 +227,14 @@ nsresult nsZipHandle::Init(PRFileDesc *fd, nsZipHandle **ret) return NS_ERROR_FILE_TOO_BIG; PRFileMap *map = PR_CreateFileMap(fd, size, PR_PROT_READONLY); - if (!map) return NS_ERROR_FAILURE; nsZipHandle *handle = new nsZipHandle(); - if (!handle) + if (!handle) { + PR_CloseFileMap(map); return NS_ERROR_OUT_OF_MEMORY; + } handle->mFd = fd; handle->mMap = map; @@ -245,22 +245,17 @@ nsresult nsZipHandle::Init(PRFileDesc *fd, nsZipHandle **ret) return NS_OK; } -PRInt32 nsZipHandle::Read(PRUint32 aPosition, void *aBuffer, PRUint32 aCount) -{ - if (mLen < 0 || aPosition+aCount > (PRUint32) mLen) - return -1; - PRInt32 count = PR_MIN(aCount, mLen - aPosition); - memcpy(aBuffer, mFileData + aPosition, count); - return count; -} - nsZipHandle::~nsZipHandle() { - if (mFd) { + if (mFileData) { PR_MemUnmap(mFileData, mLen); PR_CloseFileMap(mMap); + mFileData = nsnull; + mMap = nsnull; + } + if (mFd) { PR_Close(mFd); - mFd = 0; + mFd = nsnull; } MOZ_COUNT_DTOR(nsZipHandle); } @@ -326,6 +321,7 @@ nsresult nsZipArchive::CloseArchive() { if (mFd) { PL_FinishArenaPool(&mArena); + mFd = NULL; } // CAUTION: @@ -335,11 +331,8 @@ nsresult nsZipArchive::CloseArchive() // for all the nsZipItem in one shot. But if the ~nsZipItem is doing // anything more than cleaning up memory, we should start calling it. // Let us also cleanup the mFiles table for re-use on the next 'open' call - for (int i = 0; i < ZIP_TABSIZE; i++) { - mFiles[i] = 0; - } - mFd = NULL; - mBuiltSynthetics = PR_FALSE; + memset(mFiles, 0, sizeof(mFiles)); + mBuiltSynthetics = false; return ZIP_OK; } @@ -388,25 +381,17 @@ nsresult nsZipArchive::ExtractFile(nsZipItem *item, const char *outname, // so the item to be extracted should never be a directory PR_ASSERT(!item->isDirectory); - //-- move to the start of file's data - if (!MaybeReadItem(item)) - return ZIP_ERR_CORRUPT; - - nsSeekableZipHandle fd; - if (!fd.Open(mFd.get(), item->dataOffset, item->size)) - return ZIP_ERR_CORRUPT; - nsresult rv; //-- extract the file using the appropriate method switch(item->compression) { case STORED: - rv = CopyItemToDisk(item->size, item->crc32, fd, aFd); + rv = CopyItemToDisk(item, aFd); break; case DEFLATED: - rv = InflateItem(item, fd, aFd); + rv = InflateItem(item, aFd); break; default: @@ -607,14 +592,12 @@ nsresult nsZipArchive::BuildFileList() return ZIP_ERR_MEMORY; item->headerOffset = xtolong(central->localhdr_offset); - item->dataOffset = 0; item->size = xtolong(central->size); item->realsize = xtolong(central->orglen); item->crc32 = xtolong(central->crc32); item->time = xtoint(central->time); item->date = xtoint(central->date); item->isSynthetic = PR_FALSE; - item->hasDataOffset = PR_FALSE; item->compression = PR_MIN(xtoint(central->method), UNSUPPORTED); item->mode = ExtractMode(central->external_attributes); #if defined(XP_UNIX) || defined(XP_BEOS) @@ -652,7 +635,7 @@ nsresult nsZipArchive::BuildSynthetics() { if (mBuiltSynthetics) return ZIP_OK; - mBuiltSynthetics = PR_TRUE; + mBuiltSynthetics = true; // Create synthetic entries for any missing directories. // Do this when all ziptable has scanned to prevent double entries. @@ -737,91 +720,68 @@ nsresult nsZipArchive::BuildSynthetics() return ZIP_OK; } -nsZipHandle* nsZipArchive::GetFD(nsZipItem* aItem) +nsZipHandle* nsZipArchive::GetFD() { - if (!mFd || !MaybeReadItem(aItem)) + if (!mFd) return NULL; return mFd.get(); } //--------------------------------------------- -// nsZipArchive::MaybeReadItem +// nsZipArchive::GetData //--------------------------------------------- -bool nsZipArchive::MaybeReadItem(nsZipItem* aItem) +PRUint8* nsZipArchive::GetData(nsZipItem* aItem) { PR_ASSERT (aItem); - //-- the first time an item is used we need to calculate its offset - if (!aItem->hasDataOffset) - { - //-- read local header to get variable length values and calculate - //-- the real data offset - //-- - //-- NOTE: extralen is different in central header and local header - //-- for archives created using the Unix "zip" utility. To set - //-- the offset accurately we need the _local_ extralen. - if (!mFd || !mFd->mLen > aItem->headerOffset + ZIPLOCAL_SIZE) - return false; + //-- read local header to get variable length values and calculate + //-- the real data offset + if (aItem->headerOffset + ZIPLOCAL_SIZE > mFd->mLen) + return nsnull; - ZipLocal *Local = (ZipLocal*)(mFd->mFileData + aItem->headerOffset); - //check limits here - if ((xtolong(Local->signature) != LOCALSIG)) - { - //-- read error or local header not found - return false; - } + // -- check signature before using the structure, in case the zip file is corrupt + ZipLocal* Local = (ZipLocal*)(mFd->mFileData + aItem->headerOffset); + if ((xtolong(Local->signature) != LOCALSIG)) + return nsnull; - aItem->dataOffset = aItem->headerOffset + + //-- NOTE: extralen is different in central header and local header + //-- for archives created using the Unix "zip" utility. To set + //-- the offset accurately we need the _local_ extralen. + PRUint32 dataOffset = aItem->headerOffset + ZIPLOCAL_SIZE + xtoint(Local->filename_len) + xtoint(Local->extrafield_len); - aItem->hasDataOffset = PR_TRUE; - } - return true; + // -- check if there is enough source data in the file + if (dataOffset + aItem->size > mFd->mLen) + return nsnull; + + return mFd->mFileData + dataOffset; } //--------------------------------------------- // nsZipArchive::CopyItemToDisk //--------------------------------------------- nsresult -nsZipArchive::CopyItemToDisk(PRUint32 itemSize, PRUint32 itemCrc, - nsSeekableZipHandle &fd, PRFileDesc* outFD) -/* - * This function copies 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'. - */ +nsZipArchive::CopyItemToDisk(nsZipItem *item, PRFileDesc* outFD) { - PRUint32 chunk, pos, crc; - char buf[ZIP_BUFLEN]; + PR_ASSERT(item); - //-- initialize crc - crc = crc32(0L, Z_NULL, 0); + //-- get to the start of file's data + const PRUint8* itemData = GetData(item); + if (!itemData) + return ZIP_ERR_CORRUPT; - //-- copy chunks until file is done - for (pos = 0; pos < itemSize; pos += chunk) + if (outFD && PR_Write(outFD, itemData, item->size) < (READTYPE)item->size) { - chunk = (itemSize - pos < ZIP_BUFLEN) ? (itemSize - pos) : ZIP_BUFLEN; - - if (fd.Read(buf, chunk) != (READTYPE)chunk) - { - //-- unexpected end of data in archive - return ZIP_ERR_CORRUPT; - } - - //-- incrementally update crc32 - crc = crc32(crc, (const unsigned char*)buf, chunk); - - if (outFD && PR_Write(outFD, buf, chunk) < (READTYPE)chunk) - { - //-- Couldn't write all the data (disk full?) - return ZIP_ERR_DISK; - } + //-- Couldn't write all the data (disk full?) + return ZIP_ERR_DISK; } + //-- Calculate crc + PRUint32 crc = crc32(0L, (const unsigned char*)itemData, item->size); //-- verify crc32 - if (crc != itemCrc) + if (crc != item->crc32) return ZIP_ERR_CORRUPT; return ZIP_OK; @@ -831,17 +791,15 @@ nsZipArchive::CopyItemToDisk(PRUint32 itemSize, PRUint32 itemCrc, //--------------------------------------------- // nsZipArchive::InflateItem //--------------------------------------------- -nsresult nsZipArchive::InflateItem(const nsZipItem* aItem, nsSeekableZipHandle &fd, PRFileDesc* outFD) +nsresult nsZipArchive::InflateItem(nsZipItem * item, 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); - + PR_ASSERT(item); //-- allocate deflation buffers - Bytef inbuf[ZIP_BUFLEN]; Bytef outbuf[ZIP_BUFLEN]; //-- set up the inflate @@ -851,95 +809,44 @@ nsresult nsZipArchive::InflateItem(const nsZipItem* aItem, nsSeekableZipHandle & return ZIP_ERR_GENERAL; //-- inflate loop - zs.next_out = outbuf; - zs.avail_out = ZIP_BUFLEN; + zs.avail_in = item->size; + zs.next_in = (Bytef*)GetData(item); + if (!zs.next_in) + return ZIP_ERR_CORRUPT; - PRUint32 size = aItem->size; - PRUint32 outpos = 0; PRUint32 crc = crc32(0L, Z_NULL, 0); - int zerr = Z_OK; + int zerr = Z_OK; while (zerr == Z_OK) { - PRBool bRead = PR_FALSE; - PRBool bWrote= PR_FALSE; + zs.next_out = outbuf; + zs.avail_out = ZIP_BUFLEN; - if (zs.avail_in == 0 && zs.total_in < size) + zerr = inflate(&zs, Z_PARTIAL_FLUSH); + if (zerr != Z_OK && zerr != Z_STREAM_END) { - //-- 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 (fd.Read(inbuf, chunk) != (READTYPE)chunk) - { - //-- unexpected end of data - status = ZIP_ERR_CORRUPT; - break; - } - - zs.next_in = inbuf; - zs.avail_in = chunk; - bRead = PR_TRUE; + status = (zerr == Z_MEM_ERROR) ? ZIP_ERR_MEMORY : ZIP_ERR_CORRUPT; + break; } + PRUint32 count = zs.next_out - outbuf; - if (zs.avail_out == 0) + //-- incrementally update crc32 + crc = crc32(crc, (const unsigned char*)outbuf, count); + + if (outFD && PR_Write(outFD, outbuf, count) < (READTYPE)count) { - //-- 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; + status = ZIP_ERR_DISK; + break; } - - 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; - } // 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 - PR_ASSERT(status != ZIP_OK || zs.total_in == aItem->size); - PR_ASSERT(status != ZIP_OK || zs.total_out == aItem->realsize); - -cleanup: //-- free zlib internal state inflateEnd(&zs); + //-- verify crc32 + if ((status == ZIP_OK) && (crc != item->crc32)) + { + status = ZIP_ERR_CORRUPT; + } return status; } @@ -948,12 +855,12 @@ cleanup: //------------------------------------------ nsZipArchive::nsZipArchive() : - mBuiltSynthetics(PR_FALSE) + mBuiltSynthetics(false) { MOZ_COUNT_CTOR(nsZipArchive); // initialize the table to NULL - memset(mFiles, 0, sizeof mFiles); + memset(mFiles, 0, sizeof(mFiles)); } nsZipArchive::~nsZipArchive() diff --git a/modules/libjar/nsZipArchive.h b/modules/libjar/nsZipArchive.h index a5c54040faf..bbb0d5a877f 100644 --- a/modules/libjar/nsZipArchive.h +++ b/modules/libjar/nsZipArchive.h @@ -46,19 +46,16 @@ #define ZIP_MAGIC 0x5A49505FL /* "ZIP_" */ #define ZIPFIND_MAGIC 0x5A495046L /* "ZIPF" */ #define ZIP_TABSIZE 256 -// Keep this odd. The -1 is significant. -#define ZIP_BUFLEN (4 * 1024 - 1) +/* We really want to be a (multiple of) 4K for optimal file IO */ +#define ZIP_BUFLEN (4*1024) /* Used as output buffer when deflating items to a file */ #define PL_ARENA_CONST_ALIGN_MASK 7 #include "plarena.h" -#define ZIP_Seek(fd,p,m) (PR_Seek((fd),((PROffset32)p),(m))==((PROffset32)p)) #include "zlib.h" #include "nsAutoPtr.h" class nsZipFind; -class nsZipReadState; -class nsZipItemMetadata; struct PRFileDesc; @@ -88,7 +85,6 @@ struct nsZipItem nsZipItem* next; PRUint32 headerOffset; - PRUint32 dataOffset; PRUint32 size; /* size in original file */ PRUint32 realsize; /* inflated size */ PRUint32 crc32; @@ -100,21 +96,18 @@ struct nsZipItem PRUint16 date; PRUint16 mode; PRUint8 compression; - PRPackedBool hasDataOffset : 1; - PRPackedBool isDirectory : 1; - PRPackedBool isSynthetic : 1; /* whether item is an actual zip entry or was - generated as part of a real entry's path, - e.g. foo/ in a zip containing only foo/a.txt - and no foo/ entry is synthetic */ + bool isDirectory; + bool isSynthetic; /* whether item is an actual zip entry or was + generated as part of a real entry's path */ #if defined(XP_UNIX) || defined(XP_BEOS) - PRPackedBool isSymlink : 1; + bool isSymlink; #endif - char name[1]; // actually, bigger than 1 + char name[1]; /* actually, bigger than 1 */ }; class nsZipHandle; -class nsSeekableZipHandle; + /** * nsZipArchive -- a class for reading the PKZIP file format. * @@ -190,10 +183,17 @@ public: */ PRInt32 FindInit(const char * aPattern, nsZipFind** aFind); - /* Gets an undependent handle to the jar - * Also ensures that aItem is fully filled + /* + * Gets an undependent handle to the mapped file. */ - nsZipHandle* GetFD(nsZipItem* aItem); + nsZipHandle* GetFD(); + + /** + * Get pointer to the data of the item. + * @param aItem Pointer to nsZipItem + * reutrns null when zip file is corrupt. + */ + PRUint8* GetData(nsZipItem* aItem); private: //--- private members --- @@ -201,15 +201,8 @@ private: nsZipItem* mFiles[ZIP_TABSIZE]; PLArenaPool mArena; - /** - * Fills in nsZipItem fields that were not filled in by BuildFileList - * @param aItem Pointer to nsZipItem - * returns true if the item was filled in successfully - */ - bool MaybeReadItem(nsZipItem* aItem); - // Whether we synthesized the directory entries - PRPackedBool mBuiltSynthetics; + bool mBuiltSynthetics; // file handle nsRefPtr mFd; @@ -222,92 +215,29 @@ private: nsresult BuildFileList(); nsresult BuildSynthetics(); - nsresult CopyItemToDisk(PRUint32 size, PRUint32 crc, nsSeekableZipHandle &fd, PRFileDesc* outFD); - nsresult InflateItem(const nsZipItem* aItem, nsSeekableZipHandle &fd, PRFileDesc* outFD); + nsresult CopyItemToDisk(nsZipItem* item, PRFileDesc* outFD); + nsresult InflateItem(nsZipItem* item, PRFileDesc* outFD); }; class nsZipHandle { friend class nsZipArchive; -friend class nsSeekableZipHandle; public: static nsresult Init(PRFileDesc *fd, nsZipHandle **ret NS_OUTPARAM); - /** - * Reads data at a certain point - * @param aPosition seek ofset - * @param aBuffer buffer - * @param aCount number of bytes to read */ - PRInt32 Read(PRUint32 aPosition, void *aBuffer, PRUint32 aCount); - NS_METHOD_(nsrefcnt) AddRef(void); NS_METHOD_(nsrefcnt) Release(void); protected: - PRFileDesc *mFd; // OS file-descriptor - PRUint8 *mFileData; // pointer to mmaped file - PRUint32 mLen; // length of file and memory mapped area + PRFileDesc * mFd; /* OS file-descriptor */ + PRUint8 * mFileData; /* pointer to mmaped file */ + PRUint32 mLen; /* length of file and memory mapped area */ private: nsZipHandle(); ~nsZipHandle(); - PRFileMap *mMap; // nspr datastructure for mmap - nsrefcnt mRefCnt; // ref count -}; - - -/** nsSeekableZipHandle acts as a container for nsZipHandle, - emulates sequential file io */ -class nsSeekableZipHandle { - // stick nsZipItem in here -public: - nsSeekableZipHandle() - : mOffset(0) - , mRemaining(0) - { - } - - /** Initializes nsSeekableZipHandle with - * @param aOffset byte offset of the file to start reading at - * @param length of this descriptor - */ - bool Open(nsZipHandle *aHandle, PRUint32 aOffset, PRUint32 aLength) { - NS_ABORT_IF_FALSE (aHandle, "Argument must not be NULL"); - if (aOffset > aHandle->mLen) - return false; - mFd = aHandle; - mOffset = aOffset; - mRemaining = aLength; - return true; - } - - /** Releases the file handle. It is safe to call multiple times. */ - void Close() - { - mFd = NULL; - } - - /** - * Reads data at a certain point - * @param aBuffer input buffer - * @param aCount number of bytes to read */ - PRInt32 Read(void *aBuffer, PRUint32 aCount) - { - if (!mFd.get()) - return -1; - aCount = PR_MIN(mRemaining, aCount); - PRInt32 ret = mFd->Read(mOffset, aBuffer, aCount); - if (ret > 0) { - mOffset += ret; - mRemaining -= ret; - } - return ret; - } - -private: - nsRefPtr mFd; // file handle - PRUint32 mOffset; // current reading offset - PRUint32 mRemaining; // bytes remaining + PRFileMap * mMap; /* nspr datastructure for mmap */ + nsrefcnt mRefCnt; /* ref count */ }; @@ -319,7 +249,6 @@ private: class nsZipFind { public: - nsZipFind(nsZipArchive* aZip, char* aPattern, PRBool regExp); ~nsZipFind();