mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 504864 - mmap io for JARs; r=benjamin
This commit is contained in:
parent
7b5cd072e9
commit
ed2f94b3a5
@ -122,7 +122,6 @@ nsJAR::nsJAR(): mManifestData(nsnull, nsnull, DeleteManifestEntry, nsnull, 10),
|
|||||||
mReleaseTime(PR_INTERVAL_NO_TIMEOUT),
|
mReleaseTime(PR_INTERVAL_NO_TIMEOUT),
|
||||||
mCache(nsnull),
|
mCache(nsnull),
|
||||||
mLock(nsnull),
|
mLock(nsnull),
|
||||||
mMtime(0),
|
|
||||||
mTotalItemsInManifest(0)
|
mTotalItemsInManifest(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -167,8 +166,6 @@ nsJAR::Open(nsIFile* zipFile)
|
|||||||
if (mLock) return NS_ERROR_FAILURE; // Already open!
|
if (mLock) return NS_ERROR_FAILURE; // Already open!
|
||||||
|
|
||||||
mZipFile = zipFile;
|
mZipFile = zipFile;
|
||||||
nsresult rv = zipFile->GetLastModifiedTime(&mMtime);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
mLock = PR_NewLock();
|
mLock = PR_NewLock();
|
||||||
NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY);
|
NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY);
|
||||||
@ -176,7 +173,7 @@ nsJAR::Open(nsIFile* zipFile)
|
|||||||
PRFileDesc *fd = OpenFile();
|
PRFileDesc *fd = OpenFile();
|
||||||
NS_ENSURE_TRUE(fd, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(fd, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
rv = mZip.OpenArchive(fd);
|
nsresult rv = mZip.OpenArchive(fd);
|
||||||
if (NS_FAILED(rv)) Close();
|
if (NS_FAILED(rv)) Close();
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
@ -340,19 +337,9 @@ nsJAR::GetInputStreamWithSpec(const nsACString& aJarDirSpec,
|
|||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
if (!item || item->isDirectory) {
|
if (!item || item->isDirectory) {
|
||||||
rv = jis->InitDirectory(&mZip, aJarDirSpec, aEntryName);
|
rv = jis->InitDirectory(this, aJarDirSpec, aEntryName);
|
||||||
} else {
|
} else {
|
||||||
// Open jarfile, to get its own filedescriptor for the stream
|
rv = jis->InitFile(mZip.GetFD(item), item);
|
||||||
// XXX The file may have been overwritten, so |item| might not be
|
|
||||||
// valid. We really want to work from inode rather than file name.
|
|
||||||
PRFileDesc *fd = nsnull;
|
|
||||||
fd = OpenFile();
|
|
||||||
if (fd) {
|
|
||||||
rv = jis->InitFile(&mZip, item, fd);
|
|
||||||
// |jis| now owns |fd|
|
|
||||||
} else {
|
|
||||||
rv = NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
NS_RELEASE(*result);
|
NS_RELEASE(*result);
|
||||||
@ -1113,13 +1100,9 @@ nsZipReaderCache::GetZip(nsIFile* zipFile, nsIZipReader* *result)
|
|||||||
rv = zipFile->GetNativePath(path);
|
rv = zipFile->GetNativePath(path);
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
PRInt64 Mtime;
|
|
||||||
rv = zipFile->GetLastModifiedTime(&Mtime);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
nsCStringKey key(path);
|
nsCStringKey key(path);
|
||||||
nsJAR* zip = static_cast<nsJAR*>(static_cast<nsIZipReader*>(mZips.Get(&key))); // AddRefs
|
nsJAR* zip = static_cast<nsJAR*>(static_cast<nsIZipReader*>(mZips.Get(&key))); // AddRefs
|
||||||
if (zip && Mtime == zip->GetMtime()) {
|
if (zip) {
|
||||||
#ifdef ZIP_CACHE_HIT_RATE
|
#ifdef ZIP_CACHE_HIT_RATE
|
||||||
mZipCacheHits++;
|
mZipCacheHits++;
|
||||||
#endif
|
#endif
|
||||||
|
@ -133,10 +133,6 @@ class nsJAR : public nsIZipReader, public nsIJAR
|
|||||||
mCache = cache;
|
mCache = cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRInt64 GetMtime() {
|
|
||||||
return mMtime;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//-- Private data members
|
//-- Private data members
|
||||||
nsCOMPtr<nsIFile> mZipFile; // The zip/jar file on disk
|
nsCOMPtr<nsIFile> mZipFile; // The zip/jar file on disk
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Mitch Stoltz <mstoltz@netscape.com>
|
* Mitch Stoltz <mstoltz@netscape.com>
|
||||||
|
* Taras Glek <tglek@mozilla.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
@ -45,6 +46,7 @@
|
|||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
#include "nsEscape.h"
|
#include "nsEscape.h"
|
||||||
#include "nsIFile.h"
|
#include "nsIFile.h"
|
||||||
|
#include "nsDebug.h"
|
||||||
|
|
||||||
/*---------------------------------------------
|
/*---------------------------------------------
|
||||||
* nsISupports implementation
|
* nsISupports implementation
|
||||||
@ -57,20 +59,14 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(nsJARInputStream, nsIInputStream)
|
|||||||
*--------------------------------------------------------*/
|
*--------------------------------------------------------*/
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsJARInputStream::InitFile(nsZipArchive* aZip, nsZipItem *item, PRFileDesc *fd)
|
nsJARInputStream::InitFile(nsZipHandle *aFd, nsZipItem *item)
|
||||||
{
|
{
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
NS_ABORT_IF_FALSE(aFd, "Argument may not be null");
|
||||||
// Keep the file handle, even on failure
|
NS_ABORT_IF_FALSE(item, "Argument may not be null");
|
||||||
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
|
// Mark it as closed, in case something fails in initialisation
|
||||||
mClosed = PR_TRUE;
|
mClosed = PR_TRUE;
|
||||||
|
|
||||||
// Keep the important bits of nsZipItem only
|
// Keep the important bits of nsZipItem only
|
||||||
mInSize = item->size;
|
mInSize = item->size;
|
||||||
|
|
||||||
@ -96,8 +92,7 @@ nsJARInputStream::InitFile(nsZipArchive* aZip, nsZipItem *item, PRFileDesc *fd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//-- Set filepointer to start of item
|
//-- Set filepointer to start of item
|
||||||
rv = aZip->SeekToItem(item, mFd);
|
mFd.Open(aFd, item->dataOffset, item->size);
|
||||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_FILE_CORRUPTED);
|
|
||||||
|
|
||||||
// Open for reading
|
// Open for reading
|
||||||
mClosed = PR_FALSE;
|
mClosed = PR_FALSE;
|
||||||
@ -106,19 +101,19 @@ nsJARInputStream::InitFile(nsZipArchive* aZip, nsZipItem *item, PRFileDesc *fd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsJARInputStream::InitDirectory(nsZipArchive* aZip,
|
nsJARInputStream::InitDirectory(nsJAR* aJar,
|
||||||
const nsACString& aJarDirSpec,
|
const nsACString& aJarDirSpec,
|
||||||
const char* aDir)
|
const char* aDir)
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG_POINTER(aZip);
|
NS_ABORT_IF_FALSE(aJar, "Argument may not be null");
|
||||||
NS_ENSURE_ARG_POINTER(aDir);
|
NS_ABORT_IF_FALSE(aDir, "Argument may not be null");
|
||||||
|
|
||||||
// Mark it as closed, in case something fails in initialisation
|
// Mark it as closed, in case something fails in initialisation
|
||||||
mClosed = PR_TRUE;
|
mClosed = PR_TRUE;
|
||||||
mDirectory = PR_TRUE;
|
mDirectory = PR_TRUE;
|
||||||
|
|
||||||
// Keep the zipReader for getting the actual zipItems
|
// Keep the zipReader for getting the actual zipItems
|
||||||
mZip = aZip;
|
mJar = aJar;
|
||||||
nsZipFind *find;
|
nsZipFind *find;
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
// We can get aDir's contents as strings via FindEntries
|
// We can get aDir's contents as strings via FindEntries
|
||||||
@ -156,7 +151,7 @@ nsJARInputStream::InitDirectory(nsZipArchive* aZip,
|
|||||||
}
|
}
|
||||||
nsCAutoString pattern = escDirName + NS_LITERAL_CSTRING("?*~") +
|
nsCAutoString pattern = escDirName + NS_LITERAL_CSTRING("?*~") +
|
||||||
escDirName + NS_LITERAL_CSTRING("?*/?*");
|
escDirName + NS_LITERAL_CSTRING("?*/?*");
|
||||||
rv = aZip->FindInit(pattern.get(), &find);
|
rv = mJar->mZip.FindInit(pattern.get(), &find);
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -220,27 +215,25 @@ nsJARInputStream::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead)
|
|||||||
PRInt32 bytesRead = 0;
|
PRInt32 bytesRead = 0;
|
||||||
aCount = PR_MIN(aCount, mInSize - mCurPos);
|
aCount = PR_MIN(aCount, mInSize - mCurPos);
|
||||||
if (aCount) {
|
if (aCount) {
|
||||||
bytesRead = PR_Read(mFd, aBuffer, aCount);
|
bytesRead = mFd.Read(aBuffer, aCount);
|
||||||
if (bytesRead < 0)
|
if (bytesRead < 0)
|
||||||
return NS_ERROR_FILE_CORRUPTED;
|
return NS_ERROR_FILE_CORRUPTED;
|
||||||
mCurPos += bytesRead;
|
mCurPos += bytesRead;
|
||||||
if (bytesRead != aCount) {
|
if ((PRUint32)bytesRead != aCount) {
|
||||||
// file is truncated or was lying about size, we're done
|
// file is truncated or was lying about size, we're done
|
||||||
PR_Close(mFd);
|
Close();
|
||||||
mFd = nsnull;
|
|
||||||
return NS_ERROR_FILE_CORRUPTED;
|
return NS_ERROR_FILE_CORRUPTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*aBytesRead = bytesRead;
|
*aBytesRead = bytesRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
// be aggressive about closing!
|
// be aggressive about closing!
|
||||||
// note that sometimes, we will close mFd before we've finished
|
// note that sometimes, we will close mFd before we've finished
|
||||||
// deflating - this is because zlib buffers the input
|
// deflating - this is because zlib buffers the input
|
||||||
// So, don't free the ReadBuf/InflateStruct yet.
|
// So, don't free the ReadBuf/InflateStruct yet.
|
||||||
if (mCurPos >= mInSize && mFd) {
|
// It is ok to close the fd multiple times (also in nsJARInputStream::Close())
|
||||||
PR_Close(mFd);
|
if (mCurPos >= mInSize) {
|
||||||
mFd = nsnull;
|
mFd.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
@ -265,11 +258,8 @@ NS_IMETHODIMP
|
|||||||
nsJARInputStream::Close()
|
nsJARInputStream::Close()
|
||||||
{
|
{
|
||||||
PR_FREEIF(mInflate);
|
PR_FREEIF(mInflate);
|
||||||
if (mFd) {
|
|
||||||
PR_Close(mFd);
|
|
||||||
mFd = nsnull;
|
|
||||||
}
|
|
||||||
mClosed = PR_TRUE;
|
mClosed = PR_TRUE;
|
||||||
|
mFd.Close();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,8 +287,7 @@ nsJARInputStream::ContinueInflate(char* aBuffer, PRUint32 aCount,
|
|||||||
// time to fill the buffer!
|
// time to fill the buffer!
|
||||||
PRUint32 bytesToRead = PR_MIN(mInSize - mCurPos, ZIP_BUFLEN);
|
PRUint32 bytesToRead = PR_MIN(mInSize - mCurPos, ZIP_BUFLEN);
|
||||||
|
|
||||||
NS_ASSERTION(mFd, "File handle missing");
|
PRInt32 bytesRead = mFd.Read(mInflate->mReadBuf, bytesToRead);
|
||||||
PRInt32 bytesRead = PR_Read(mFd, mInflate->mReadBuf, bytesToRead);
|
|
||||||
if (bytesRead < 0) {
|
if (bytesRead < 0) {
|
||||||
zerr = Z_ERRNO;
|
zerr = Z_ERRNO;
|
||||||
break;
|
break;
|
||||||
@ -362,7 +351,7 @@ nsJARInputStream::ReadDirectory(char* aBuffer, PRUint32 aCount, PRUint32 *aBytes
|
|||||||
|
|
||||||
const char * entryName = mArray[mArrPos].get();
|
const char * entryName = mArray[mArrPos].get();
|
||||||
PRUint32 entryNameLen = mArray[mArrPos].Length();
|
PRUint32 entryNameLen = mArray[mArrPos].Length();
|
||||||
nsZipItem* ze = mZip->GetItem(entryName);
|
nsZipItem* ze = mJar->mZip.GetItem(entryName);
|
||||||
NS_ENSURE_TRUE(ze, NS_ERROR_FILE_TARGET_DOES_NOT_EXIST);
|
NS_ENSURE_TRUE(ze, NS_ERROR_FILE_TARGET_DOES_NOT_EXIST);
|
||||||
|
|
||||||
// Last Modified Time
|
// Last Modified Time
|
||||||
|
@ -53,23 +53,24 @@ class nsJARInputStream : public nsIInputStream
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
nsJARInputStream() :
|
nsJARInputStream() :
|
||||||
mFd(nsnull), mInSize(0), mCurPos(0),
|
mInSize(0), mCurPos(0), mInflate(nsnull), mDirectory(0), mClosed(PR_FALSE)
|
||||||
mInflate(nsnull), mDirectory(0), mClosed(PR_FALSE) { }
|
{ }
|
||||||
|
|
||||||
~nsJARInputStream() { Close(); }
|
~nsJARInputStream() {
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
NS_DECL_NSIINPUTSTREAM
|
NS_DECL_NSIINPUTSTREAM
|
||||||
|
|
||||||
// takes ownership of |fd|, even on failure
|
// takes ownership of |fd|, even on failure
|
||||||
nsresult InitFile(nsZipArchive* aZip, nsZipItem *item, PRFileDesc *fd);
|
nsresult InitFile(nsZipHandle *aFd, nsZipItem *item);
|
||||||
|
|
||||||
nsresult InitDirectory(nsZipArchive* aZip,
|
nsresult InitDirectory(nsJAR *aJar,
|
||||||
const nsACString& aJarDirSpec,
|
const nsACString& aJarDirSpec,
|
||||||
const char* aDir);
|
const char* aDir);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PRFileDesc* mFd; // My own file handle, for reading
|
|
||||||
PRUint32 mInSize; // Size in original file
|
PRUint32 mInSize; // Size in original file
|
||||||
PRUint32 mCurPos; // Current position in input
|
PRUint32 mCurPos; // Current position in input
|
||||||
|
|
||||||
@ -83,14 +84,14 @@ class nsJARInputStream : public nsIInputStream
|
|||||||
struct InflateStruct * mInflate;
|
struct InflateStruct * mInflate;
|
||||||
|
|
||||||
/* For directory reading */
|
/* For directory reading */
|
||||||
nsZipArchive* mZip; // the zipReader
|
nsRefPtr<nsJAR> mJar; // string reference to zipreader
|
||||||
PRUint32 mNameLen; // length of dirname
|
PRUint32 mNameLen; // length of dirname
|
||||||
nsCAutoString mBuffer; // storage for generated text of stream
|
nsCAutoString mBuffer; // storage for generated text of stream
|
||||||
PRUint32 mArrPos; // current position within mArray
|
PRUint32 mArrPos; // current position within mArray
|
||||||
nsTArray<nsCString> mArray; // array of names in (zip) directory
|
nsTArray<nsCString> mArray; // array of names in (zip) directory
|
||||||
|
PRPackedBool mDirectory; // is this a directory?
|
||||||
PRPackedBool mDirectory;
|
PRPackedBool mClosed; // Whether the stream is closed
|
||||||
PRPackedBool mClosed; // Whether the stream is closed
|
nsSeekableZipHandle mFd; // handle for reading
|
||||||
|
|
||||||
nsresult ContinueInflate(char* aBuf, PRUint32 aCount, PRUint32* aBytesRead);
|
nsresult ContinueInflate(char* aBuf, PRUint32 aCount, PRUint32* aBytesRead);
|
||||||
nsresult ReadDirectory(char* aBuf, PRUint32 aCount, PRUint32* aBytesRead);
|
nsresult ReadDirectory(char* aBuf, PRUint32 aCount, PRUint32* aBytesRead);
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
* Mitch Stoltz <mstoltz@netscape.com>
|
* Mitch Stoltz <mstoltz@netscape.com>
|
||||||
* Jeroen Dobbelaere <jeroen.dobbelaere@acunia.com>
|
* Jeroen Dobbelaere <jeroen.dobbelaere@acunia.com>
|
||||||
* Jeff Walden <jwalden+code@mit.edu>
|
* Jeff Walden <jwalden+code@mit.edu>
|
||||||
|
* Taras Glek <tglek@mozilla.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
@ -49,17 +50,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "nsWildCard.h"
|
|
||||||
#include "nscore.h"
|
|
||||||
#include "prmem.h"
|
|
||||||
#include "prio.h"
|
|
||||||
#include "plstr.h"
|
|
||||||
#include "prlog.h"
|
|
||||||
#define ZFILE_CREATE PR_WRONLY | PR_CREATE_FILE
|
#define ZFILE_CREATE PR_WRONLY | PR_CREATE_FILE
|
||||||
#define READTYPE PRInt32
|
#define READTYPE PRInt32
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
#include "nsISupportsUtils.h"
|
#include "nsISupportsUtils.h"
|
||||||
#include "nsRecyclingAllocator.h"
|
#include "nsRecyclingAllocator.h"
|
||||||
|
#include "prio.h"
|
||||||
|
#include "plstr.h"
|
||||||
|
#include "prlog.h"
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "nsWildCard.h"
|
||||||
|
#include "zipfile.h"
|
||||||
|
#include "zipstruct.h"
|
||||||
|
#include "nsZipArchive.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Globals
|
* Globals
|
||||||
@ -205,6 +208,60 @@ nsresult gZlibInit(z_stream *zs)
|
|||||||
return ZIP_OK;
|
return ZIP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsZipHandle::nsZipHandle()
|
||||||
|
: mFd(nsnull)
|
||||||
|
, mFileData(nsnull)
|
||||||
|
, mLen(0)
|
||||||
|
, mMap(nsnull)
|
||||||
|
, mRefCnt(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_THREADSAFE_ADDREF(nsZipHandle)
|
||||||
|
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)
|
||||||
|
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);
|
||||||
|
*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) {
|
||||||
|
PR_MemUnmap(mFileData, mLen);
|
||||||
|
PR_CloseFileMap(mMap);
|
||||||
|
PR_Close(mFd);
|
||||||
|
mFd = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//***********************************************************
|
//***********************************************************
|
||||||
// nsZipArchive -- public methods
|
// nsZipArchive -- public methods
|
||||||
//***********************************************************
|
//***********************************************************
|
||||||
@ -215,15 +272,13 @@ nsresult gZlibInit(z_stream *zs)
|
|||||||
//---------------------------------------------
|
//---------------------------------------------
|
||||||
nsresult nsZipArchive::OpenArchive(PRFileDesc * fd)
|
nsresult nsZipArchive::OpenArchive(PRFileDesc * fd)
|
||||||
{
|
{
|
||||||
if (!fd)
|
nsresult rv = nsZipHandle::Init(fd, getter_AddRefs(mFd));
|
||||||
return ZIP_ERR_PARAM;
|
if (NS_FAILED(rv))
|
||||||
|
return rv;
|
||||||
|
|
||||||
// Initialize our arena
|
// Initialize our arena
|
||||||
PL_INIT_ARENA_POOL(&mArena, "ZipArena", ZIP_ARENABLOCKSIZE);
|
PL_INIT_ARENA_POOL(&mArena, "ZipArena", ZIP_ARENABLOCKSIZE);
|
||||||
|
|
||||||
//-- Keep the filedescriptor for further reading...
|
|
||||||
mFd = fd;
|
|
||||||
|
|
||||||
//-- get table of contents for archive
|
//-- get table of contents for archive
|
||||||
return BuildFileList();
|
return BuildFileList();
|
||||||
}
|
}
|
||||||
@ -280,10 +335,7 @@ nsresult nsZipArchive::CloseArchive()
|
|||||||
for (int i = 0; i < ZIP_TABSIZE; i++) {
|
for (int i = 0; i < ZIP_TABSIZE; i++) {
|
||||||
mFiles[i] = 0;
|
mFiles[i] = 0;
|
||||||
}
|
}
|
||||||
if (mFd) {
|
mFd = NULL;
|
||||||
PR_Close(mFd);
|
|
||||||
mFd = 0;
|
|
||||||
}
|
|
||||||
mBuiltSynthetics = PR_FALSE;
|
mBuiltSynthetics = PR_FALSE;
|
||||||
return ZIP_OK;
|
return ZIP_OK;
|
||||||
}
|
}
|
||||||
@ -334,7 +386,11 @@ nsresult nsZipArchive::ExtractFile(nsZipItem *item, const char *outname,
|
|||||||
PR_ASSERT(!item->isDirectory);
|
PR_ASSERT(!item->isDirectory);
|
||||||
|
|
||||||
//-- move to the start of file's data
|
//-- move to the start of file's data
|
||||||
if (SeekToItem(item, mFd) != ZIP_OK)
|
if (MaybeReadItem(item) != ZIP_OK)
|
||||||
|
return ZIP_ERR_CORRUPT;
|
||||||
|
|
||||||
|
nsSeekableZipHandle fd;
|
||||||
|
if (!fd.Open(mFd.get(), item->headerOffset, item->size))
|
||||||
return ZIP_ERR_CORRUPT;
|
return ZIP_ERR_CORRUPT;
|
||||||
|
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
@ -343,11 +399,11 @@ nsresult nsZipArchive::ExtractFile(nsZipItem *item, const char *outname,
|
|||||||
switch(item->compression)
|
switch(item->compression)
|
||||||
{
|
{
|
||||||
case STORED:
|
case STORED:
|
||||||
rv = CopyItemToDisk(item->size, item->crc32, aFd);
|
rv = CopyItemToDisk(item->size, item->crc32, fd, aFd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DEFLATED:
|
case DEFLATED:
|
||||||
rv = InflateItem(item, aFd);
|
rv = InflateItem(item, fd, aFd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -509,29 +565,22 @@ nsZipItem* nsZipArchive::CreateZipItem(PRUint16 namelen)
|
|||||||
//---------------------------------------------
|
//---------------------------------------------
|
||||||
nsresult nsZipArchive::BuildFileList()
|
nsresult nsZipArchive::BuildFileList()
|
||||||
{
|
{
|
||||||
PRUint8 buf[4*BR_BUF_SIZE];
|
PRUint8 *buf;
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
// locate the central directory via the End record
|
// locate the central directory via the End record
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
//-- get archive size using end pos
|
//-- get archive size using end pos
|
||||||
PRInt32 pos = PR_Seek(mFd, 0, PR_SEEK_END);
|
PRInt32 pos = (PRInt32) mFd->mLen;
|
||||||
if (pos <= 0)
|
|
||||||
return ZIP_ERR_CORRUPT;
|
|
||||||
|
|
||||||
PRBool bEndsigFound = PR_FALSE;
|
PRInt32 central = -1;
|
||||||
while (!bEndsigFound)
|
while (central == -1)
|
||||||
{
|
{
|
||||||
//-- read backwards in 1K-sized chunks (unless file is less than 1K)
|
//-- read backwards in 1K-sized chunks (unless file is less than 1K)
|
||||||
PRInt32 bufsize = pos > BR_BUF_SIZE ? BR_BUF_SIZE : pos;
|
PRInt32 bufsize = pos > BR_BUF_SIZE ? BR_BUF_SIZE : pos;
|
||||||
pos -= bufsize;
|
pos -= bufsize;
|
||||||
|
|
||||||
if (!ZIP_Seek(mFd, pos, PR_SEEK_SET))
|
buf = mFd->mFileData + pos;
|
||||||
return ZIP_ERR_CORRUPT;
|
|
||||||
|
|
||||||
if (PR_Read(mFd, buf, bufsize) != (READTYPE)bufsize)
|
|
||||||
return ZIP_ERR_CORRUPT;
|
|
||||||
|
|
||||||
//-- scan for ENDSIG
|
//-- scan for ENDSIG
|
||||||
PRUint8 *endp = buf + bufsize;
|
PRUint8 *endp = buf + bufsize;
|
||||||
@ -540,16 +589,12 @@ nsresult nsZipArchive::BuildFileList()
|
|||||||
if (xtolong(endp) == ENDSIG)
|
if (xtolong(endp) == ENDSIG)
|
||||||
{
|
{
|
||||||
//-- Seek to start of central directory
|
//-- Seek to start of central directory
|
||||||
PRInt32 central = xtolong(((ZipEnd *) endp)->offset_central_dir);
|
central = xtolong(((ZipEnd *) endp)->offset_central_dir);
|
||||||
if (!ZIP_Seek(mFd, central, PR_SEEK_SET))
|
|
||||||
return ZIP_ERR_CORRUPT;
|
|
||||||
|
|
||||||
bEndsigFound = PR_TRUE;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bEndsigFound)
|
if (central != -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (pos <= 0)
|
if (pos <= 0)
|
||||||
@ -566,7 +611,8 @@ nsresult nsZipArchive::BuildFileList()
|
|||||||
//-------------------------------------------------------
|
//-------------------------------------------------------
|
||||||
// read the central directory headers
|
// read the central directory headers
|
||||||
//-------------------------------------------------------
|
//-------------------------------------------------------
|
||||||
PRInt32 byteCount = PR_Read(mFd, &buf, sizeof(buf));
|
PRInt32 byteCount = mFd->mLen - central;
|
||||||
|
buf = mFd->mFileData + central;
|
||||||
pos = 0;
|
pos = 0;
|
||||||
PRUint32 sig = xtolong(buf);
|
PRUint32 sig = xtolong(buf);
|
||||||
while (sig == CENTRALSIG) {
|
while (sig == CENTRALSIG) {
|
||||||
@ -613,31 +659,11 @@ nsresult nsZipArchive::BuildFileList()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
pos += ZIPCENTRAL_SIZE;
|
pos += ZIPCENTRAL_SIZE;
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// Make sure that remainder of this record (name, comments, extra)
|
|
||||||
// and the next ZipCentral is all in the buffer
|
|
||||||
//-------------------------------------------------------
|
|
||||||
PRInt32 leftover = byteCount - pos;
|
|
||||||
if (leftover < (namelen + extralen + commentlen + ZIPCENTRAL_SIZE)) {
|
|
||||||
//-- not enough data left to process at top of loop.
|
|
||||||
//-- move leftover and read more
|
|
||||||
memcpy(buf, buf+pos, leftover);
|
|
||||||
byteCount = leftover + PR_Read(mFd, buf+leftover, sizeof(buf)-leftover);
|
|
||||||
pos = 0;
|
|
||||||
|
|
||||||
if (byteCount < (namelen + extralen + commentlen + sizeof(sig))) {
|
|
||||||
// truncated file
|
|
||||||
return ZIP_ERR_CORRUPT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
//-------------------------------------------------------
|
||||||
// get the item name
|
// get the item name
|
||||||
//-------------------------------------------------------
|
//-------------------------------------------------------
|
||||||
memcpy(item->name, buf+pos, namelen);
|
memcpy(item->name, buf+pos, namelen);
|
||||||
item->name[namelen] = 0;
|
item->name[namelen] = 0;
|
||||||
|
|
||||||
//-- an item whose name ends with '/' is a directory
|
//-- an item whose name ends with '/' is a directory
|
||||||
item->isDirectory = ('/' == item->name[namelen - 1]);
|
item->isDirectory = ('/' == item->name[namelen - 1]);
|
||||||
|
|
||||||
@ -758,11 +784,17 @@ nsresult nsZipArchive::BuildSynthetics()
|
|||||||
return ZIP_OK;
|
return ZIP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsZipHandle* nsZipArchive::GetFD(nsZipItem* aItem)
|
||||||
|
{
|
||||||
|
if (!mFd || !MaybeReadItem(aItem))
|
||||||
|
return NULL;
|
||||||
|
return mFd.get();
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------
|
//---------------------------------------------
|
||||||
// nsZipArchive::SeekToItem
|
// nsZipArchive::MaybeReadItem
|
||||||
//---------------------------------------------
|
//---------------------------------------------
|
||||||
nsresult nsZipArchive::SeekToItem(nsZipItem* aItem, PRFileDesc* aFd)
|
bool nsZipArchive::MaybeReadItem(nsZipItem* aItem)
|
||||||
{
|
{
|
||||||
PR_ASSERT (aItem);
|
PR_ASSERT (aItem);
|
||||||
|
|
||||||
@ -775,36 +807,33 @@ nsresult nsZipArchive::SeekToItem(nsZipItem* aItem, PRFileDesc* aFd)
|
|||||||
//-- NOTE: extralen is different in central header and local header
|
//-- NOTE: extralen is different in central header and local header
|
||||||
//-- for archives created using the Unix "zip" utility. To set
|
//-- for archives created using the Unix "zip" utility. To set
|
||||||
//-- the offset accurately we need the _local_ extralen.
|
//-- the offset accurately we need the _local_ extralen.
|
||||||
if (!ZIP_Seek(aFd, aItem->headerOffset, PR_SEEK_SET))
|
if (!mFd || !mFd->mLen > aItem->headerOffset + ZIPLOCAL_SIZE)
|
||||||
return ZIP_ERR_CORRUPT;
|
return false;
|
||||||
|
|
||||||
ZipLocal Local;
|
ZipLocal *Local = (ZipLocal*)(mFd->mFileData + aItem->headerOffset);
|
||||||
if ((PR_Read(aFd, (char*)&Local, ZIPLOCAL_SIZE) != (READTYPE) ZIPLOCAL_SIZE) ||
|
//check limits here
|
||||||
(xtolong(Local.signature) != LOCALSIG))
|
if ((xtolong(Local->signature) != LOCALSIG))
|
||||||
{
|
{
|
||||||
//-- read error or local header not found
|
//-- read error or local header not found
|
||||||
return ZIP_ERR_CORRUPT;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
aItem->dataOffset = aItem->headerOffset +
|
aItem->dataOffset = aItem->headerOffset +
|
||||||
ZIPLOCAL_SIZE +
|
ZIPLOCAL_SIZE +
|
||||||
xtoint(Local.filename_len) +
|
xtoint(Local->filename_len) +
|
||||||
xtoint(Local.extrafield_len);
|
xtoint(Local->extrafield_len);
|
||||||
aItem->hasDataOffset = PR_TRUE;
|
aItem->hasDataOffset = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-- move to start of file in archive
|
return true;
|
||||||
if (!ZIP_Seek(aFd, aItem->dataOffset, PR_SEEK_SET))
|
|
||||||
return ZIP_ERR_CORRUPT;
|
|
||||||
|
|
||||||
return ZIP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------
|
//---------------------------------------------
|
||||||
// nsZipArchive::CopyItemToDisk
|
// nsZipArchive::CopyItemToDisk
|
||||||
//---------------------------------------------
|
//---------------------------------------------
|
||||||
nsresult
|
nsresult
|
||||||
nsZipArchive::CopyItemToDisk(PRUint32 itemSize, PRUint32 itemCrc, PRFileDesc* outFD)
|
nsZipArchive::CopyItemToDisk(PRUint32 itemSize, PRUint32 itemCrc,
|
||||||
|
nsSeekableZipHandle &fd, PRFileDesc* outFD)
|
||||||
/*
|
/*
|
||||||
* This function copies an archive item to disk, to the
|
* This function copies an archive item to disk, to the
|
||||||
* file specified by outFD. If outFD is zero, the extracted data is
|
* file specified by outFD. If outFD is zero, the extracted data is
|
||||||
@ -822,7 +851,7 @@ nsZipArchive::CopyItemToDisk(PRUint32 itemSize, PRUint32 itemCrc, PRFileDesc* ou
|
|||||||
{
|
{
|
||||||
chunk = (itemSize - pos < ZIP_BUFLEN) ? (itemSize - pos) : ZIP_BUFLEN;
|
chunk = (itemSize - pos < ZIP_BUFLEN) ? (itemSize - pos) : ZIP_BUFLEN;
|
||||||
|
|
||||||
if (PR_Read(mFd, buf, chunk) != (READTYPE)chunk)
|
if (fd.Read(buf, chunk) != (READTYPE)chunk)
|
||||||
{
|
{
|
||||||
//-- unexpected end of data in archive
|
//-- unexpected end of data in archive
|
||||||
return ZIP_ERR_CORRUPT;
|
return ZIP_ERR_CORRUPT;
|
||||||
@ -849,7 +878,7 @@ nsZipArchive::CopyItemToDisk(PRUint32 itemSize, PRUint32 itemCrc, PRFileDesc* ou
|
|||||||
//---------------------------------------------
|
//---------------------------------------------
|
||||||
// nsZipArchive::InflateItem
|
// nsZipArchive::InflateItem
|
||||||
//---------------------------------------------
|
//---------------------------------------------
|
||||||
nsresult nsZipArchive::InflateItem(const nsZipItem* aItem, PRFileDesc* outFD)
|
nsresult nsZipArchive::InflateItem(const nsZipItem* aItem, nsSeekableZipHandle &fd, PRFileDesc* outFD)
|
||||||
/*
|
/*
|
||||||
* This function inflates an archive item to disk, to the
|
* This function inflates an archive item to disk, to the
|
||||||
* file specified by outFD. If outFD is zero, the extracted data is
|
* file specified by outFD. If outFD is zero, the extracted data is
|
||||||
@ -887,7 +916,7 @@ nsresult nsZipArchive::InflateItem(const nsZipItem* aItem, PRFileDesc* outFD)
|
|||||||
//-- read another chunk of compressed data
|
//-- read another chunk of compressed data
|
||||||
PRUint32 chunk = (size-zs.total_in < ZIP_BUFLEN) ? size-zs.total_in : ZIP_BUFLEN;
|
PRUint32 chunk = (size-zs.total_in < ZIP_BUFLEN) ? size-zs.total_in : ZIP_BUFLEN;
|
||||||
|
|
||||||
if (PR_Read(mFd, inbuf, chunk) != (READTYPE)chunk)
|
if (fd.Read(inbuf, chunk) != (READTYPE)chunk)
|
||||||
{
|
{
|
||||||
//-- unexpected end of data
|
//-- unexpected end of data
|
||||||
status = ZIP_ERR_CORRUPT;
|
status = ZIP_ERR_CORRUPT;
|
||||||
@ -966,8 +995,7 @@ cleanup:
|
|||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
|
|
||||||
nsZipArchive::nsZipArchive() :
|
nsZipArchive::nsZipArchive() :
|
||||||
mFd(0),
|
mBuiltSynthetics(PR_FALSE)
|
||||||
mBuiltSynthetics(PR_FALSE)
|
|
||||||
{
|
{
|
||||||
MOZ_COUNT_CTOR(nsZipArchive);
|
MOZ_COUNT_CTOR(nsZipArchive);
|
||||||
|
|
||||||
@ -1075,4 +1103,3 @@ static PRBool IsSymlink(unsigned char *ll)
|
|||||||
return ((xtoint(ll+2) & S_IFMT) == S_IFLNK);
|
return ((xtoint(ll+2) & S_IFMT) == S_IFLNK);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
* Daniel Veditz <dveditz@netscape.com>
|
* Daniel Veditz <dveditz@netscape.com>
|
||||||
* Samir Gehani <sgehani@netscape.com>
|
* Samir Gehani <sgehani@netscape.com>
|
||||||
* Mitch Stoltz <mstoltz@netscape.com>
|
* Mitch Stoltz <mstoltz@netscape.com>
|
||||||
|
* Taras Glek <tglek@mozilla.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
@ -53,6 +54,7 @@
|
|||||||
#define ZIP_Seek(fd,p,m) (PR_Seek((fd),((PROffset32)p),(m))==((PROffset32)p))
|
#define ZIP_Seek(fd,p,m) (PR_Seek((fd),((PROffset32)p),(m))==((PROffset32)p))
|
||||||
|
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
|
#include "nsAutoPtr.h"
|
||||||
|
|
||||||
class nsZipFind;
|
class nsZipFind;
|
||||||
class nsZipReadState;
|
class nsZipReadState;
|
||||||
@ -111,6 +113,8 @@ struct nsZipItem
|
|||||||
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.
|
* nsZipArchive -- a class for reading the PKZIP file format.
|
||||||
*
|
*
|
||||||
@ -186,12 +190,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
PRInt32 FindInit(const char * aPattern, nsZipFind** aFind);
|
PRInt32 FindInit(const char * aPattern, nsZipFind** aFind);
|
||||||
|
|
||||||
/**
|
/* Gets an undependent handle to the jar
|
||||||
* Moves the filepointer aFd to the start of data of the aItem.
|
* Also ensures that aItem is fully filled
|
||||||
* @param aItem Pointer to nsZipItem
|
|
||||||
* @param aFd The filepointer to move
|
|
||||||
*/
|
*/
|
||||||
nsresult SeekToItem(nsZipItem* aItem, PRFileDesc* aFd);
|
nsZipHandle* GetFD(nsZipItem* aItem);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//--- private members ---
|
//--- private members ---
|
||||||
@ -199,12 +201,18 @@ private:
|
|||||||
nsZipItem* mFiles[ZIP_TABSIZE];
|
nsZipItem* mFiles[ZIP_TABSIZE];
|
||||||
PLArenaPool mArena;
|
PLArenaPool mArena;
|
||||||
|
|
||||||
// Used for central directory reading, and for Test and Extract
|
/**
|
||||||
PRFileDesc *mFd;
|
* 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
|
// Whether we synthesized the directory entries
|
||||||
PRPackedBool mBuiltSynthetics;
|
PRPackedBool mBuiltSynthetics;
|
||||||
|
|
||||||
|
// file handle
|
||||||
|
nsRefPtr<nsZipHandle> mFd;
|
||||||
//--- private methods ---
|
//--- private methods ---
|
||||||
|
|
||||||
nsZipArchive& operator=(const nsZipArchive& rhs); // prevent assignments
|
nsZipArchive& operator=(const nsZipArchive& rhs); // prevent assignments
|
||||||
@ -214,8 +222,92 @@ private:
|
|||||||
nsresult BuildFileList();
|
nsresult BuildFileList();
|
||||||
nsresult BuildSynthetics();
|
nsresult BuildSynthetics();
|
||||||
|
|
||||||
nsresult CopyItemToDisk(PRUint32 size, PRUint32 crc, PRFileDesc* outFD);
|
nsresult CopyItemToDisk(PRUint32 size, PRUint32 crc, nsSeekableZipHandle &fd, PRFileDesc* outFD);
|
||||||
nsresult InflateItem(const nsZipItem* aItem, PRFileDesc* outFD);
|
nsresult InflateItem(const nsZipItem* aItem, nsSeekableZipHandle &fd, 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);
|
||||||
|
|
||||||
|
nsrefcnt AddRef(void);
|
||||||
|
nsrefcnt Release(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,66 @@
|
|||||||
|
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is mozilla.org code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Taras Glek <tglek@mozilla.com>
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
function wrapInputStream(input)
|
||||||
|
{
|
||||||
|
var nsIScriptableInputStream = Components.interfaces.nsIScriptableInputStream;
|
||||||
|
var factory = Components.classes["@mozilla.org/scriptableinputstream;1"];
|
||||||
|
var wrapper = factory.createInstance(nsIScriptableInputStream);
|
||||||
|
wrapper.init(input);
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that files can be read from after closing zipreader
|
||||||
|
function run_test() {
|
||||||
|
const Cc = Components.classes;
|
||||||
|
const Ci = Components.interfaces;
|
||||||
|
|
||||||
|
// the build script have created the zip we can test on in the current dir.
|
||||||
|
var file = do_get_file("data/test_bug333423.zip");
|
||||||
|
|
||||||
|
var zipreader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||||
|
createInstance(Ci.nsIZipReader);
|
||||||
|
zipreader.open(file);
|
||||||
|
var entries = zipreader.findEntries(null);
|
||||||
|
var stream = wrapInputStream(zipreader.getInputStream("modules/libjar/test/Makefile.in"))
|
||||||
|
var dirstream= wrapInputStream(zipreader.getInputStream("modules/libjar/test/"))
|
||||||
|
zipreader.close();
|
||||||
|
zipreader = null;
|
||||||
|
Components.utils.forceGC();
|
||||||
|
do_check_true(stream.read(1024).length > 0);
|
||||||
|
do_check_true(dirstream.read(100).length > 0);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user