mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 566686 - Provide a decompression API in nsZipArchive, patch mostly by taras, r=alfredkayser
--HG-- extra : rebase_source : 0e45fb4b4a78fbd4337ef7f95ee338b58f50e29f
This commit is contained in:
parent
76a20dbcfd
commit
ec14bb00fe
@ -346,22 +346,22 @@ nsresult nsZipArchive::ExtractFile(nsZipItem *item, const char *outname,
|
||||
// so the item to be extracted should never be a directory
|
||||
PR_ASSERT(!item->IsDirectory());
|
||||
|
||||
Bytef outbuf[ZIP_BUFLEN];
|
||||
|
||||
nsZipCursor cursor(item, this, outbuf, ZIP_BUFLEN, true);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
//-- extract the file using the appropriate method
|
||||
switch(item->Compression())
|
||||
{
|
||||
case STORED:
|
||||
rv = CopyItemToDisk(item, aFd);
|
||||
while (true) {
|
||||
PRUint32 count = 0;
|
||||
PRUint8* buf = cursor.Read(&count);
|
||||
if (!buf)
|
||||
rv = NS_ERROR_FILE_CORRUPTED;
|
||||
else if (count == 0)
|
||||
break;
|
||||
|
||||
case DEFLATED:
|
||||
rv = InflateItem(item, aFd);
|
||||
break;
|
||||
|
||||
default:
|
||||
//-- unsupported compression type
|
||||
rv = NS_ERROR_NOT_IMPLEMENTED;
|
||||
if (aFd && PR_Write(aFd, buf, count) < (READTYPE)count)
|
||||
rv = NS_ERROR_FILE_DISK_FULL;
|
||||
}
|
||||
|
||||
//-- delete the file on errors, or resolve symlink if needed
|
||||
@ -697,97 +697,6 @@ PRUint8* nsZipArchive::GetData(nsZipItem* aItem)
|
||||
return data + offset;
|
||||
}
|
||||
|
||||
//---------------------------------------------
|
||||
// nsZipArchive::CopyItemToDisk
|
||||
//---------------------------------------------
|
||||
nsresult
|
||||
nsZipArchive::CopyItemToDisk(nsZipItem *item, PRFileDesc* outFD)
|
||||
{
|
||||
PR_ASSERT(item);
|
||||
|
||||
//-- get to the start of file's data
|
||||
const PRUint8* itemData = GetData(item);
|
||||
if (!itemData)
|
||||
return NS_ERROR_FILE_CORRUPTED;
|
||||
|
||||
if (outFD && PR_Write(outFD, itemData, item->Size()) < (READTYPE)item->Size())
|
||||
{
|
||||
//-- Couldn't write all the data (disk full?)
|
||||
return NS_ERROR_FILE_DISK_FULL;
|
||||
}
|
||||
|
||||
//-- Calculate crc
|
||||
PRUint32 crc = crc32(0L, (const unsigned char*)itemData, item->Size());
|
||||
//-- verify crc32
|
||||
if (crc != item->CRC32())
|
||||
return NS_ERROR_FILE_CORRUPTED;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------
|
||||
// nsZipArchive::InflateItem
|
||||
//---------------------------------------------
|
||||
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(item);
|
||||
//-- allocate deflation buffers
|
||||
Bytef outbuf[ZIP_BUFLEN];
|
||||
|
||||
//-- set up the inflate
|
||||
z_stream zs;
|
||||
nsresult status = gZlibInit(&zs);
|
||||
if (status != NS_OK)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
//-- inflate loop
|
||||
zs.avail_in = item->Size();
|
||||
zs.next_in = (Bytef*)GetData(item);
|
||||
if (!zs.next_in)
|
||||
return NS_ERROR_FILE_CORRUPTED;
|
||||
|
||||
PRUint32 crc = crc32(0L, Z_NULL, 0);
|
||||
int zerr = Z_OK;
|
||||
while (zerr == Z_OK)
|
||||
{
|
||||
zs.next_out = outbuf;
|
||||
zs.avail_out = ZIP_BUFLEN;
|
||||
|
||||
zerr = inflate(&zs, Z_PARTIAL_FLUSH);
|
||||
if (zerr != Z_OK && zerr != Z_STREAM_END)
|
||||
{
|
||||
status = (zerr == Z_MEM_ERROR) ? NS_ERROR_OUT_OF_MEMORY : NS_ERROR_FILE_CORRUPTED;
|
||||
break;
|
||||
}
|
||||
PRUint32 count = zs.next_out - outbuf;
|
||||
|
||||
//-- incrementally update crc32
|
||||
crc = crc32(crc, (const unsigned char*)outbuf, count);
|
||||
|
||||
if (outFD && PR_Write(outFD, outbuf, count) < (READTYPE)count)
|
||||
{
|
||||
status = NS_ERROR_FILE_DISK_FULL;
|
||||
break;
|
||||
}
|
||||
} // while
|
||||
|
||||
//-- free zlib internal state
|
||||
inflateEnd(&zs);
|
||||
|
||||
//-- verify crc32
|
||||
if ((status == NS_OK) && (crc != item->CRC32()))
|
||||
{
|
||||
status = NS_ERROR_FILE_CORRUPTED;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
// nsZipArchive constructor and destructor
|
||||
//------------------------------------------
|
||||
@ -1004,3 +913,94 @@ bool nsZipItem::IsSymlink()
|
||||
}
|
||||
#endif
|
||||
|
||||
nsZipCursor::nsZipCursor(nsZipItem *item, nsZipArchive *aZip, PRUint8* aBuf, PRUint32 aBufSize, bool doCRC) :
|
||||
mItem(item),
|
||||
mBuf(aBuf),
|
||||
mBufSize(aBufSize),
|
||||
mDoCRC(doCRC)
|
||||
{
|
||||
if (mItem->Compression() == DEFLATED) {
|
||||
nsresult status = gZlibInit(&mZs);
|
||||
NS_ASSERTION(status == NS_OK, "Zlib failed to initialize");
|
||||
NS_ASSERTION(aBuf, "Must pass in a buffer for DEFLATED nsZipItem");
|
||||
}
|
||||
|
||||
mZs.avail_in = item->Size();
|
||||
mZs.next_in = (Bytef*)aZip->GetData(item);
|
||||
|
||||
if (doCRC)
|
||||
mCRC = crc32(0L, Z_NULL, 0);
|
||||
}
|
||||
|
||||
nsZipCursor::~nsZipCursor()
|
||||
{
|
||||
if (mItem->Compression() == DEFLATED) {
|
||||
inflateEnd(&mZs);
|
||||
}
|
||||
}
|
||||
|
||||
PRUint8* nsZipCursor::Read(PRUint32 *aBytesRead) {
|
||||
int zerr;
|
||||
PRUint8 *buf = nsnull;
|
||||
bool verifyCRC = true;
|
||||
|
||||
if (!mZs.next_in)
|
||||
return nsnull;
|
||||
|
||||
switch (mItem->Compression()) {
|
||||
case STORED:
|
||||
*aBytesRead = mZs.avail_in;
|
||||
buf = mZs.next_in;
|
||||
mZs.next_in += mZs.avail_in;
|
||||
mZs.avail_in = 0;
|
||||
break;
|
||||
case DEFLATED:
|
||||
buf = mBuf;
|
||||
mZs.next_out = buf;
|
||||
mZs.avail_out = mBufSize;
|
||||
|
||||
zerr = inflate(&mZs, Z_PARTIAL_FLUSH);
|
||||
if (zerr != Z_OK && zerr != Z_STREAM_END)
|
||||
return nsnull;
|
||||
|
||||
*aBytesRead = mZs.next_out - buf;
|
||||
verifyCRC = (zerr == Z_STREAM_END);
|
||||
break;
|
||||
default:
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (mDoCRC) {
|
||||
mCRC = crc32(mCRC, (const unsigned char*)buf, *aBytesRead);
|
||||
if (verifyCRC && mCRC != mItem->CRC32())
|
||||
return nsnull;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
nsZipItemPtr_base::nsZipItemPtr_base(nsZipArchive *aZip, const char * aEntryName, bool doCRC) :
|
||||
mReturnBuf(nsnull)
|
||||
{
|
||||
// make sure the ziparchive hangs around
|
||||
mZipHandle = aZip->GetFD();
|
||||
|
||||
nsZipItem* item = aZip->GetItem(aEntryName);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
PRUint32 size = 0;
|
||||
if (item->Compression() == DEFLATED) {
|
||||
size = item->RealSize();
|
||||
mAutoBuf = new PRUint8[size];
|
||||
}
|
||||
|
||||
nsZipCursor cursor(item, aZip, mAutoBuf, size, doCRC);
|
||||
mReturnBuf = cursor.Read(&mReadlen);
|
||||
if (!mReturnBuf)
|
||||
return;
|
||||
|
||||
if (mReadlen != item->RealSize()) {
|
||||
NS_ASSERTION(mReadlen == item->RealSize(), "nsZipCursor underflow");
|
||||
mReturnBuf = nsnull;
|
||||
}
|
||||
}
|
||||
|
@ -214,9 +214,6 @@ private:
|
||||
nsZipItem* CreateZipItem();
|
||||
nsresult BuildFileList();
|
||||
nsresult BuildSynthetics();
|
||||
|
||||
nsresult CopyItemToDisk(nsZipItem* item, PRFileDesc* outFD);
|
||||
nsresult InflateItem(nsZipItem* item, PRFileDesc* outFD);
|
||||
};
|
||||
|
||||
class nsZipHandle {
|
||||
@ -265,6 +262,88 @@ private:
|
||||
nsZipFind(const nsZipFind& rhs);
|
||||
};
|
||||
|
||||
/**
|
||||
* nsZipCursor -- a low-level class for reading the individual items in a zip.
|
||||
*/
|
||||
class nsZipCursor {
|
||||
public:
|
||||
/**
|
||||
* Initializes the cursor
|
||||
*
|
||||
* @param aItem Item of interest
|
||||
* @param aZip Archive
|
||||
* @param aBuf Buffer used for decompression.
|
||||
* This determines the maximum Read() size in the compressed case.
|
||||
* @param aBufSize Buffer size
|
||||
* @param doCRC When set to true Read() will check crc
|
||||
*/
|
||||
nsZipCursor(nsZipItem *aItem, nsZipArchive *aZip, PRUint8* aBuf = NULL, PRUint32 aBufSize = 0, bool doCRC = false);
|
||||
|
||||
~nsZipCursor();
|
||||
|
||||
/**
|
||||
* Performs reads. In the compressed case it uses aBuf(passed in constructor), for stored files
|
||||
* it returns a zero-copy buffer.
|
||||
*
|
||||
* @param aBytesRead Outparam for number of bytes read.
|
||||
* @return data read or NULL if item is corrupted.
|
||||
*/
|
||||
PRUint8* Read(PRUint32 *aBytesRead);
|
||||
|
||||
private:
|
||||
nsZipItem *mItem;
|
||||
PRUint8 *mBuf;
|
||||
PRUint32 mBufSize;
|
||||
z_stream mZs;
|
||||
PRUint32 mCRC;
|
||||
bool mDoCRC;
|
||||
};
|
||||
|
||||
/**
|
||||
* nsZipItemPtr - a RAII convenience class for reading the individual items in a zip.
|
||||
* It reads whole files and does zero-copy IO for stored files. A buffer is allocated
|
||||
* for decompression.
|
||||
* Do not use when the file may be very large.
|
||||
*/
|
||||
class nsZipItemPtr_base {
|
||||
public:
|
||||
/**
|
||||
* Initializes the reader
|
||||
*
|
||||
* @param aZip Archive
|
||||
* @param aEntryName Archive membername
|
||||
* @param doCRC When set to true Read() will check crc
|
||||
*/
|
||||
nsZipItemPtr_base(nsZipArchive *aZip, const char *aEntryName, bool doCRC);
|
||||
|
||||
PRUint32 Length() const {
|
||||
return mReadlen;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsRefPtr<nsZipHandle> mZipHandle;
|
||||
nsAutoArrayPtr<PRUint8> mAutoBuf;
|
||||
PRUint8 *mReturnBuf;
|
||||
PRUint32 mReadlen;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class nsZipItemPtr : public nsZipItemPtr_base {
|
||||
public:
|
||||
nsZipItemPtr(nsZipArchive *aZip, const char *aEntryName, bool doCRC = false) : nsZipItemPtr_base(aZip, aEntryName, doCRC) { }
|
||||
/**
|
||||
* @return buffer containing the whole zip member or NULL on error.
|
||||
* The returned buffer is owned by nsZipItemReader.
|
||||
*/
|
||||
const T* Buffer() const {
|
||||
return (const T*)mReturnBuf;
|
||||
}
|
||||
|
||||
operator const T*() const {
|
||||
return Buffer();
|
||||
}
|
||||
};
|
||||
|
||||
nsresult gZlibInit(z_stream *zs);
|
||||
|
||||
#endif /* nsZipArchive_h_ */
|
||||
|
12
modules/libjar/test/unit/test_uncompressed.js
Normal file
12
modules/libjar/test/unit/test_uncompressed.js
Normal file
@ -0,0 +1,12 @@
|
||||
// Make sure uncompressed files pass crc
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
function run_test() {
|
||||
var file = do_get_file("data/uncompressed.zip");
|
||||
var zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
zipReader.open(file);
|
||||
zipReader.test("hello");
|
||||
zipReader.close();
|
||||
}
|
Loading…
Reference in New Issue
Block a user