summaryrefslogtreecommitdiffstats
path: root/modules/libjar/zipwriter/nsDeflateConverter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/libjar/zipwriter/nsDeflateConverter.cpp')
-rw-r--r--modules/libjar/zipwriter/nsDeflateConverter.cpp178
1 files changed, 178 insertions, 0 deletions
diff --git a/modules/libjar/zipwriter/nsDeflateConverter.cpp b/modules/libjar/zipwriter/nsDeflateConverter.cpp
new file mode 100644
index 0000000000..32dc3c7ebf
--- /dev/null
+++ b/modules/libjar/zipwriter/nsDeflateConverter.cpp
@@ -0,0 +1,178 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "StreamFunctions.h"
+#include "nsDeflateConverter.h"
+#include "nsStringStream.h"
+#include "nsComponentManagerUtils.h"
+#include "nsMemory.h"
+#include "plstr.h"
+#include "mozilla/UniquePtr.h"
+
+#define ZLIB_TYPE "deflate"
+#define GZIP_TYPE "gzip"
+#define X_GZIP_TYPE "x-gzip"
+
+using namespace mozilla;
+
+/**
+ * nsDeflateConverter is a stream converter applies the deflate compression
+ * method to the data.
+ */
+NS_IMPL_ISUPPORTS(nsDeflateConverter, nsIStreamConverter, nsIStreamListener,
+ nsIRequestObserver)
+
+nsresult nsDeflateConverter::Init() {
+ int zerr;
+
+ mOffset = 0;
+
+ mZstream.zalloc = Z_NULL;
+ mZstream.zfree = Z_NULL;
+ mZstream.opaque = Z_NULL;
+
+ int32_t window = MAX_WBITS;
+ switch (mWrapMode) {
+ case WRAP_NONE:
+ window = -window;
+ break;
+ case WRAP_GZIP:
+ window += 16;
+ break;
+ default:
+ break;
+ }
+
+ zerr = deflateInit2(&mZstream, mLevel, Z_DEFLATED, window, 8,
+ Z_DEFAULT_STRATEGY);
+ if (zerr != Z_OK) return NS_ERROR_OUT_OF_MEMORY;
+
+ mZstream.next_out = mWriteBuffer;
+ mZstream.avail_out = sizeof(mWriteBuffer);
+
+ // mark the input buffer as empty.
+ mZstream.avail_in = 0;
+ mZstream.next_in = Z_NULL;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsDeflateConverter::Convert(nsIInputStream* aFromStream,
+ const char* aFromType,
+ const char* aToType,
+ nsISupports* aCtxt,
+ nsIInputStream** _retval) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP nsDeflateConverter::AsyncConvertData(const char* aFromType,
+ const char* aToType,
+ nsIStreamListener* aListener,
+ nsISupports* aCtxt) {
+ if (mListener) return NS_ERROR_ALREADY_INITIALIZED;
+
+ NS_ENSURE_ARG_POINTER(aListener);
+
+ if (!PL_strncasecmp(aToType, ZLIB_TYPE, sizeof(ZLIB_TYPE) - 1))
+ mWrapMode = WRAP_ZLIB;
+ else if (!PL_strcasecmp(aToType, GZIP_TYPE) ||
+ !PL_strcasecmp(aToType, X_GZIP_TYPE))
+ mWrapMode = WRAP_GZIP;
+ else
+ mWrapMode = WRAP_NONE;
+
+ nsresult rv = Init();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mListener = aListener;
+ mContext = aCtxt;
+ return rv;
+}
+
+NS_IMETHODIMP
+nsDeflateConverter::GetConvertedType(const nsACString& aFromType,
+ nsIChannel* aChannel,
+ nsACString& aToType) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP nsDeflateConverter::OnDataAvailable(nsIRequest* aRequest,
+ nsIInputStream* aInputStream,
+ uint64_t aOffset,
+ uint32_t aCount) {
+ if (!mListener) return NS_ERROR_NOT_INITIALIZED;
+
+ auto buffer = MakeUnique<char[]>(aCount);
+ NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY);
+
+ nsresult rv = ZW_ReadData(aInputStream, buffer.get(), aCount);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // make sure we aren't reading too much
+ mZstream.avail_in = aCount;
+ mZstream.next_in = (unsigned char*)buffer.get();
+
+ int zerr = Z_OK;
+ // deflate loop
+ while (mZstream.avail_in > 0 && zerr == Z_OK) {
+ zerr = deflate(&mZstream, Z_NO_FLUSH);
+
+ while (mZstream.avail_out == 0) {
+ // buffer is full, push the data out to the listener
+ rv = PushAvailableData(aRequest, nullptr);
+ NS_ENSURE_SUCCESS(rv, rv);
+ zerr = deflate(&mZstream, Z_NO_FLUSH);
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsDeflateConverter::OnStartRequest(nsIRequest* aRequest) {
+ if (!mListener) return NS_ERROR_NOT_INITIALIZED;
+
+ return mListener->OnStartRequest(aRequest);
+}
+
+NS_IMETHODIMP nsDeflateConverter::OnStopRequest(nsIRequest* aRequest,
+ nsresult aStatusCode) {
+ if (!mListener) return NS_ERROR_NOT_INITIALIZED;
+
+ nsresult rv;
+
+ int zerr;
+ do {
+ zerr = deflate(&mZstream, Z_FINISH);
+ rv = PushAvailableData(aRequest, nullptr);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } while (zerr == Z_OK);
+
+ deflateEnd(&mZstream);
+
+ return mListener->OnStopRequest(aRequest, aStatusCode);
+}
+
+nsresult nsDeflateConverter::PushAvailableData(nsIRequest* aRequest,
+ nsISupports* aContext) {
+ uint32_t bytesToWrite = sizeof(mWriteBuffer) - mZstream.avail_out;
+ // We don't need to do anything if there isn't any data
+ if (bytesToWrite == 0) return NS_OK;
+
+ MOZ_ASSERT(bytesToWrite <= INT32_MAX);
+ nsCOMPtr<nsIInputStream> stream;
+ nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream),
+ Span((char*)mWriteBuffer, bytesToWrite),
+ NS_ASSIGNMENT_DEPEND);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = mListener->OnDataAvailable(aRequest, stream, mOffset, bytesToWrite);
+
+ // now set the state for 'deflate'
+ mZstream.next_out = mWriteBuffer;
+ mZstream.avail_out = sizeof(mWriteBuffer);
+
+ mOffset += bytesToWrite;
+ return rv;
+}