--- a/modules/libjar/nsJAR.cpp
+++ b/modules/libjar/nsJAR.cpp
@@ -334,17 +334,17 @@ nsJAR::GetInputStreamWithSpec(const nsAC
// addref now so we can call InitFile/InitDirectory()
NS_ENSURE_TRUE(jis, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(*result = jis);
nsresult rv = NS_OK;
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);
}
return rv;
}
//----------------------------------------------
--- a/modules/libjar/nsJARInputStream.cpp
+++ b/modules/libjar/nsJARInputStream.cpp
@@ -54,68 +54,68 @@
NS_IMPL_THREADSAFE_ISUPPORTS1(nsJARInputStream, nsIInputStream)
/*----------------------------------------------------------
* nsJARInputStream implementation
*--------------------------------------------------------*/
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;
}
nsresult
nsJARInputStream::InitDirectory(nsJAR* aJar,
const nsACString& aJarDirSpec,
const char* aDir)
{
NS_ABORT_IF_FALSE(aJar, "Argument may not be null");
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;
nsZipFind *find;
nsresult rv;
// We can get aDir's contents as strings via FindEntries
// with the following pattern (see nsIZipReader.findEntries docs)
// assuming dirName is properly escaped:
@@ -168,80 +168,69 @@ nsJARInputStream::InitDirectory(nsJAR* a
// Sort it
mArray.Sort();
mBuffer.AssignLiteral("300: ");
mBuffer.Append(aJarDirSpec);
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;
}
NS_IMETHODIMP
nsJARInputStream::Available(PRUint32 *_retval)
{
if (mClosed)
return NS_BASE_STREAM_CLOSED;
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;
}
NS_IMETHODIMP
nsJARInputStream::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead)
{
NS_ENSURE_ARG_POINTER(aBuffer);
NS_ENSURE_ARG_POINTER(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
nsJARInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval)
{
// don't have a buffer to read from, so this better not be called!
NS_NOTREACHED("Consumers should be using Read()!");
return NS_ERROR_NOT_IMPLEMENTED;
@@ -252,77 +241,54 @@ nsJARInputStream::IsNonBlocking(PRBool *
{
*aNonBlocking = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsJARInputStream::Close()
{
- PR_FREEIF(mInflate);
- mClosed = PR_TRUE;
- mFd.Close();
+ mClosed = true;
+ mFd = nsnull;
+ mJar = nsnull;
return NS_OK;
}
nsresult
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);
+ mZs.avail_out = PR_MIN(aCount, (mOutSize-oldTotalOut));
+ mZs.next_out = (unsigned char*)aBuffer;
- 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);
- }
-
+ // 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);
return NS_ERROR_FILE_CORRUPTED;
}
}
return NS_OK;
--- a/modules/libjar/nsJARInputStream.h
+++ b/modules/libjar/nsJARInputStream.h
@@ -48,55 +48,49 @@
* Class nsJARInputStream declaration. This class defines the type of the
* object returned by calls to nsJAR::GetInputStream(filename) for the
* purpose of reading a file item out of a JAR file.
*------------------------------------------------------------------------*/
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<nsZipHandle> 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<nsJAR> 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<nsCString> 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<nsJAR> 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<nsCString> 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);
PRUint32 CopyDataToBuffer(char* &aBuffer, PRUint32 &aCount);
};
#endif /* nsJARINPUTSTREAM_h__ */
--- a/modules/libjar/nsZipArchive.cpp
+++ b/modules/libjar/nsZipArchive.cpp
@@ -45,17 +45,16 @@
/*
* This module implements a simple archive extractor for the PKZIP format.
*
* The underlying nsZipArchive is NOT thread-safe. Do not pass references
* or pointers to it across thread boundaries.
*/
-#define ZFILE_CREATE PR_WRONLY | PR_CREATE_FILE
#define READTYPE PRInt32
#include "zlib.h"
#include "nsISupportsUtils.h"
#include "nsRecyclingAllocator.h"
#include "prio.h"
#include "plstr.h"
#include "prlog.h"
#include "stdlib.h"
@@ -168,17 +167,17 @@ static void *
zlibAlloc(void *opaque, uInt items, uInt size)
{
nsRecyclingAllocator *zallocator = (nsRecyclingAllocator *)opaque;
if (zallocator) {
// Bump up x4 allocations
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);
}
static void
zlibFree(void *opaque, void *ptr)
{
@@ -223,49 +222,45 @@ NS_IMPL_THREADSAFE_RELEASE(nsZipHandle)
nsresult nsZipHandle::Init(PRFileDesc *fd, nsZipHandle **ret)
{
PRInt64 size = PR_Available64(fd);
if (size >= PR_INT32_MAX)
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;
handle->mLen = (PRUint32) size;
handle->mFileData = (PRUint8*) PR_MemMap(map, 0, handle->mLen);
handle->AddRef();
*ret = handle;
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);
}
//***********************************************************
// nsZipArchive -- public methods
//***********************************************************
@@ -321,30 +316,28 @@ nsresult nsZipArchive::Test(const char *
//---------------------------------------------
// nsZipArchive::CloseArchive
//---------------------------------------------
nsresult nsZipArchive::CloseArchive()
{
if (mFd) {
PL_FinishArenaPool(&mArena);
+ mFd = NULL;
}
// CAUTION:
// We don't need to delete each of the nsZipItem as the memory for
// the zip item and the filename it holds are both allocated from the Arena.
// Hence, destroying the Arena is like destroying all the memory
// 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;
}
//---------------------------------------------
// nsZipArchive::GetItem
//---------------------------------------------
nsZipItem* nsZipArchive::GetItem(const char * aEntryName)
{
@@ -383,35 +376,27 @@ nsresult nsZipArchive::ExtractFile(nsZip
return ZIP_ERR_PARAM;
if (!mFd)
return ZIP_ERR_GENERAL;
// Directory extraction is handled in nsJAR::Extract,
// 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:
//-- unsupported compression type
rv = ZIP_ERR_UNSUPPORTED;
}
//-- delete the file on errors, or resolve symlink if needed
@@ -602,24 +587,22 @@ nsresult nsZipArchive::BuildFileList()
if (namelen > BR_BUF_SIZE || extralen > BR_BUF_SIZE || commentlen > 2*BR_BUF_SIZE)
return ZIP_ERR_CORRUPT;
nsZipItem* item = CreateZipItem(namelen);
if (!item)
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)
// Check if item is a symlink
item->isSymlink = IsSymlink(central->external_attributes);
#endif
buf += ZIPCENTRAL_SIZE;
@@ -647,17 +630,17 @@ nsresult nsZipArchive::BuildFileList()
//---------------------------------------------
// nsZipArchive::BuildSynthetics
//---------------------------------------------
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.
for (int i = 0; i < ZIP_TABSIZE; ++i)
{
for (nsZipItem* item = mFiles[i]; item != 0; item = item->next)
{
if (item->isSynthetic)
@@ -732,233 +715,157 @@ nsresult nsZipArchive::BuildSynthetics()
diritem->next = mFiles[hash];
mFiles[hash] = diritem;
} /* end processing of dirs in item's name */
}
}
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;
}
//---------------------------------------------
// 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
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;
+ 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;
-
- 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;
+ zs.next_out = outbuf;
+ zs.avail_out = 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;
- }
-
- if (zs.avail_out == 0)
+ zerr = inflate(&zs, Z_PARTIAL_FLUSH);
+ if (zerr != Z_OK && zerr != Z_STREAM_END)
{
- //-- 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 = (zerr == Z_MEM_ERROR) ? ZIP_ERR_MEMORY : ZIP_ERR_CORRUPT;
+ break;
}
+ PRUint32 count = zs.next_out - outbuf;
- 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*)outbuf, count);
- //-- incrementally update crc32
- crc = crc32(crc, (const unsigned char*)old_next_out, zs.next_out - old_next_out);
+ if (outFD && PR_Write(outFD, outbuf, count) < (READTYPE)count)
+ {
+ status = ZIP_ERR_DISK;
+ break;
}
- 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;
}
//------------------------------------------
// nsZipArchive constructor and destructor
//------------------------------------------
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()
{
CloseArchive();
MOZ_COUNT_DTOR(nsZipArchive);
}
--- a/modules/libjar/nsZipArchive.h
+++ b/modules/libjar/nsZipArchive.h
@@ -41,29 +41,26 @@
* ***** END LICENSE BLOCK ***** */
#ifndef nsZipArchive_h_
#define nsZipArchive_h_
#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;
/**
* This file defines some of the basic structures used by libjar to
* read Zip files. It makes use of zlib in order to do the decompression.
*
* A few notes on the classes/structs:
@@ -83,43 +80,39 @@ struct PRFileDesc;
* each nsZipItem represents one file in the archive and all the
* information needed to manipulate it.
*/
struct nsZipItem
{
nsZipItem* next;
PRUint32 headerOffset;
- PRUint32 dataOffset;
PRUint32 size; /* size in original file */
PRUint32 realsize; /* inflated size */
PRUint32 crc32;
/*
* Keep small items together, to avoid overhead.
*/
PRUint16 time;
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.
*
*/
class nsZipArchive
{
friend class nsZipFind;
@@ -185,146 +178,82 @@ public:
* (may be NULL to find all files in archive)
* @param aFind a pointer to a pointer to a structure used
* in FindNext. In the case of an error this
* will be set to NULL.
* @return status code
*/
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 ---
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<nsZipHandle> mFd;
//--- private methods ---
nsZipArchive& operator=(const nsZipArchive& rhs); // prevent assignments
nsZipArchive(const nsZipArchive& rhs); // prevent copies
nsZipItem* CreateZipItem(PRUint16 namelen);
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<nsZipHandle> mFd; // file handle
- PRUint32 mOffset; // current reading offset
- PRUint32 mRemaining; // bytes remaining
+ PRFileMap * mMap; /* nspr datastructure for mmap */
+ nsrefcnt mRefCnt; /* ref count */
};
/**
* nsZipFind
*
* a helper class for nsZipArchive, representing a search
*/
class nsZipFind
{
public:
-
nsZipFind(nsZipArchive* aZip, char* aPattern, PRBool regExp);
~nsZipFind();
nsresult FindNext(const char ** aResult);
private:
nsZipArchive* mArchive;
char* mPattern;