summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--modules/libjar/nsJARInputStream.cpp55
-rw-r--r--modules/libjar/nsJARInputStream.h16
-rw-r--r--modules/libjar/nsZipArchive.cpp38
-rw-r--r--modules/libjar/nsZipArchive.h2
-rw-r--r--modules/libjar/zipstruct.h3
5 files changed, 101 insertions, 13 deletions
diff --git a/modules/libjar/nsJARInputStream.cpp b/modules/libjar/nsJARInputStream.cpp
index 086c21ab4..a1f6c1d56 100644
--- a/modules/libjar/nsJARInputStream.cpp
+++ b/modules/libjar/nsJARInputStream.cpp
@@ -7,6 +7,7 @@
#include "nsJARInputStream.h"
#include "zipstruct.h" // defines ZIP compression codes
+#include "brotli/decode.h"
#include "nsZipArchive.h"
#include "nsEscape.h"
@@ -51,6 +52,13 @@ nsJARInputStream::InitFile(nsJAR *aJar, nsZipItem *item)
mOutCrc = crc32(0L, Z_NULL, 0);
break;
+ case MOZ_JAR_BROTLI:
+ mBrotliState = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
+ mMode = MODE_BROTLI;
+ mInCrc = item->CRC32();
+ mOutCrc = crc32(0L, Z_NULL, 0);
+ break;
+
default:
return NS_ERROR_NOT_IMPLEMENTED;
}
@@ -166,6 +174,7 @@ nsJARInputStream::Available(uint64_t *_retval)
break;
case MODE_INFLATE:
+ case MODE_BROTLI:
case MODE_COPY:
*_retval = mOutSize - mZs.total_out;
break;
@@ -195,6 +204,7 @@ MOZ_WIN_MEM_TRY_BEGIN
return ReadDirectory(aBuffer, aCount, aBytesRead);
case MODE_INFLATE:
+ case MODE_BROTLI:
if (mZs.total_out < mOutSize) {
rv = ContinueInflate(aBuffer, aCount, aBytesRead);
}
@@ -246,6 +256,9 @@ nsJARInputStream::Close()
if (mMode == MODE_INFLATE) {
inflateEnd(&mZs);
}
+ if (mMode == MODE_BROTLI) {
+ BrotliDecoderDestroyInstance(mBrotliState);
+ }
mMode = MODE_CLOSED;
mFd = nullptr;
return NS_OK;
@@ -255,6 +268,8 @@ nsresult
nsJARInputStream::ContinueInflate(char* aBuffer, uint32_t aCount,
uint32_t* aBytesRead)
{
+ bool finished = false;
+
// No need to check the args, ::Read did that, but assert them at least
NS_ASSERTION(aBuffer,"aBuffer parameter must not be null");
NS_ASSERTION(aBytesRead,"aBytesRead parameter must not be null");
@@ -266,11 +281,35 @@ nsJARInputStream::ContinueInflate(char* aBuffer, uint32_t aCount,
mZs.avail_out = std::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)) {
- nsZipArchive::sFileCorruptedReason = "nsJARInputStream: error while inflating";
- return NS_ERROR_FILE_CORRUPTED;
+ if (mMode == MODE_INFLATE) {
+ // now inflate
+ int zerr = inflate(&mZs, Z_SYNC_FLUSH);
+ if ((zerr != Z_OK) && (zerr != Z_STREAM_END)) {
+ nsZipArchive::sFileCorruptedReason = "nsJARInputStream: error while inflating";
+ return NS_ERROR_FILE_CORRUPTED;
+ }
+ finished = (zerr == Z_STREAM_END);
+ } else {
+ MOZ_ASSERT(mMode == MODE_BROTLI);
+ /* The brotli library wants size_t, but z_stream only contains
+ * unsigned int for avail_* and unsigned long for total_*.
+ * So use temporary stack values. */
+ size_t avail_in = mZs.avail_in;
+ size_t avail_out = mZs.avail_out;
+ size_t total_out = mZs.total_out;
+ BrotliDecoderResult result = BrotliDecoderDecompressStream(
+ mBrotliState,
+ &avail_in, const_cast<const unsigned char**>(&mZs.next_in),
+ &avail_out, &mZs.next_out, &total_out);
+ /* We don't need to update avail_out, it's not used outside this
+ * function. */
+ mZs.total_out = total_out;
+ mZs.avail_in = avail_in;
+ if (result == BROTLI_DECODER_RESULT_ERROR) {
+ nsZipArchive::sFileCorruptedReason = "nsJARInputStream: brotli decompression error";
+ return NS_ERROR_FILE_CORRUPTED;
+ }
+ finished = (result == BROTLI_DECODER_RESULT_SUCCESS);
}
*aBytesRead = (mZs.total_out - oldTotalOut);
@@ -280,8 +319,10 @@ nsJARInputStream::ContinueInflate(char* aBuffer, uint32_t aCount,
// be aggressive about ending the inflation
// for some reason we don't always get Z_STREAM_END
- if (zerr == Z_STREAM_END || mZs.total_out == mOutSize) {
- inflateEnd(&mZs);
+ if (finished || mZs.total_out == mOutSize) {
+ if (mMode == MODE_INFLATE) {
+ inflateEnd(&mZs);
+ }
// stop returning valid data as soon as we know we have a bad CRC
if (mOutCrc != mInCrc) {
diff --git a/modules/libjar/nsJARInputStream.h b/modules/libjar/nsJARInputStream.h
index 1c396aa10..60c3d763e 100644
--- a/modules/libjar/nsJARInputStream.h
+++ b/modules/libjar/nsJARInputStream.h
@@ -12,6 +12,8 @@
#include "nsTArray.h"
#include "mozilla/Attributes.h"
+struct BrotliDecoderStateStruct;
+
/*-------------------------------------------------------------------------
* Class nsJARInputStream declaration. This class defines the type of the
* object returned by calls to nsJAR::GetInputStream(filename) for the
@@ -20,9 +22,15 @@
class nsJARInputStream final : public nsIInputStream
{
public:
- nsJARInputStream() :
- mOutSize(0), mInCrc(0), mOutCrc(0), mNameLen(0),
- mCurPos(0), mArrPos(0), mMode(MODE_NOTINITED)
+ nsJARInputStream()
+ : mOutSize(0)
+ , mInCrc(0)
+ , mOutCrc(0)
+ , mBrotliState(nullptr)
+ , mNameLen(0)
+ , mCurPos(0)
+ , mArrPos(0)
+ , mMode(MODE_NOTINITED)
{
memset(&mZs, 0, sizeof(z_stream));
}
@@ -45,6 +53,7 @@ class nsJARInputStream final : public nsIInputStream
uint32_t mInCrc; // CRC as provided by the zipentry
uint32_t mOutCrc; // CRC as calculated by me
z_stream mZs; // zip data structure
+ BrotliDecoderStateStruct* mBrotliState; // Brotli decoder state
/* For directory reading */
RefPtr<nsJAR> mJar; // string reference to zipreader
@@ -59,6 +68,7 @@ class nsJARInputStream final : public nsIInputStream
MODE_CLOSED,
MODE_DIRECTORY,
MODE_INFLATE,
+ MODE_BROTLI,
MODE_COPY
} JISMode;
diff --git a/modules/libjar/nsZipArchive.cpp b/modules/libjar/nsZipArchive.cpp
index 2f12af5f0..b28fddc18 100644
--- a/modules/libjar/nsZipArchive.cpp
+++ b/modules/libjar/nsZipArchive.cpp
@@ -4,7 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
- * This module implements a simple archive extractor for the PKZIP format.
+ * This module implements a simple archive extractor.
*
* The underlying nsZipArchive is NOT thread-safe. Do not pass references
* or pointers to it across thread boundaries.
@@ -17,6 +17,7 @@
#define READTYPE int32_t
#include "zlib.h"
+#include "brotli/decode.h"
#include "nsISupportsUtils.h"
#include "prio.h"
#include "plstr.h"
@@ -1186,6 +1187,7 @@ nsZipCursor::nsZipCursor(nsZipItem *item, nsZipArchive *aZip, uint8_t* aBuf,
: mItem(item)
, mBuf(aBuf)
, mBufSize(aBufSize)
+ , mBrotliState(nullptr)
, mCRC(0)
, mDoCRC(doCRC)
{
@@ -1200,6 +1202,10 @@ nsZipCursor::nsZipCursor(nsZipItem *item, nsZipArchive *aZip, uint8_t* aBuf,
mZs.avail_in = item->Size();
mZs.next_in = (Bytef*)aZip->GetData(item);
+
+ if (mItem->Compression() == MOZ_JAR_BROTLI) {
+ mBrotliState = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
+ }
if (doCRC)
mCRC = crc32(0L, Z_NULL, 0);
@@ -1210,6 +1216,9 @@ nsZipCursor::~nsZipCursor()
if (mItem->Compression() == DEFLATED) {
inflateEnd(&mZs);
}
+ if (mItem->Compression() == MOZ_JAR_BROTLI) {
+ BrotliDecoderDestroyInstance(mBrotliState);
+ }
}
uint8_t* nsZipCursor::ReadOrCopy(uint32_t *aBytesRead, bool aCopy) {
@@ -1246,6 +1255,29 @@ MOZ_WIN_MEM_TRY_BEGIN
*aBytesRead = mZs.next_out - buf;
verifyCRC = (zerr == Z_STREAM_END);
break;
+ case MOZ_JAR_BROTLI: {
+ buf = mBuf;
+ mZs.next_out = buf;
+ /* The brotli library wants size_t, but z_stream only contains
+ * unsigned int for avail_*. So use temporary stack values. */
+ size_t avail_out = mBufSize;
+ size_t avail_in = mZs.avail_in;
+ BrotliDecoderResult result = BrotliDecoderDecompressStream(
+ mBrotliState,
+ &avail_in, const_cast<const unsigned char**>(&mZs.next_in),
+ &avail_out, &mZs.next_out, nullptr);
+ /* We don't need to update avail_out, it's not used outside this
+ * function. */
+ mZs.avail_in = avail_in;
+
+ if (result == BROTLI_DECODER_RESULT_ERROR) {
+ return nullptr;
+ }
+
+ *aBytesRead = mZs.next_out - buf;
+ verifyCRC = (result == BROTLI_DECODER_RESULT_SUCCESS);
+ break;
+ }
default:
return nullptr;
}
@@ -1272,7 +1304,9 @@ nsZipItemPtr_base::nsZipItemPtr_base(nsZipArchive *aZip,
return;
uint32_t size = 0;
- if (item->Compression() == DEFLATED) {
+ bool compressed = (item->Compression() == DEFLATED) ||
+ (item->Compression() == MOZ_JAR_BROTLI);
+ if (compressed) {
size = item->RealSize();
mAutoBuf = MakeUniqueFallible<uint8_t[]>(size);
if (!mAutoBuf) {
diff --git a/modules/libjar/nsZipArchive.h b/modules/libjar/nsZipArchive.h
index 2de679032..6b758c9fd 100644
--- a/modules/libjar/nsZipArchive.h
+++ b/modules/libjar/nsZipArchive.h
@@ -37,6 +37,7 @@
class nsZipFind;
struct PRFileDesc;
+struct BrotliDecoderStateStruct;
/**
* This file defines some of the basic structures used by libjar to
@@ -314,6 +315,7 @@ private:
uint8_t *mBuf;
uint32_t mBufSize;
z_stream mZs;
+ BrotliDecoderStateStruct* mBrotliState;
uint32_t mCRC;
bool mDoCRC;
};
diff --git a/modules/libjar/zipstruct.h b/modules/libjar/zipstruct.h
index f06afe14e..f7393128a 100644
--- a/modules/libjar/zipstruct.h
+++ b/modules/libjar/zipstruct.h
@@ -102,6 +102,7 @@ typedef struct ZipEnd_
#define TOKENIZED 7
#define DEFLATED 8
#define UNSUPPORTED 0xFF
-
+/* non-standard extension */
+#define MOZ_JAR_BROTLI 0x81
#endif /* _zipstruct_h */