1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/modules/libjar/zipwriter/src/nsDeflateConverter.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,198 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.7 + */ 1.8 + 1.9 +#include "StreamFunctions.h" 1.10 +#include "nsDeflateConverter.h" 1.11 +#include "nsIStringStream.h" 1.12 +#include "nsIInputStreamPump.h" 1.13 +#include "nsComponentManagerUtils.h" 1.14 +#include "nsMemory.h" 1.15 +#include "nsAutoPtr.h" 1.16 +#include "plstr.h" 1.17 + 1.18 +#define ZLIB_TYPE "deflate" 1.19 +#define GZIP_TYPE "gzip" 1.20 +#define X_GZIP_TYPE "x-gzip" 1.21 + 1.22 +/** 1.23 + * nsDeflateConverter is a stream converter applies the deflate compression 1.24 + * method to the data. 1.25 + */ 1.26 +NS_IMPL_ISUPPORTS(nsDeflateConverter, nsIStreamConverter, 1.27 + nsIStreamListener, 1.28 + nsIRequestObserver) 1.29 + 1.30 +nsresult nsDeflateConverter::Init() 1.31 +{ 1.32 + int zerr; 1.33 + 1.34 + mOffset = 0; 1.35 + 1.36 + mZstream.zalloc = Z_NULL; 1.37 + mZstream.zfree = Z_NULL; 1.38 + mZstream.opaque = Z_NULL; 1.39 + 1.40 + int32_t window = MAX_WBITS; 1.41 + switch (mWrapMode) { 1.42 + case WRAP_NONE: 1.43 + window = -window; 1.44 + break; 1.45 + case WRAP_GZIP: 1.46 + window += 16; 1.47 + break; 1.48 + default: 1.49 + break; 1.50 + } 1.51 + 1.52 + zerr = deflateInit2(&mZstream, mLevel, Z_DEFLATED, window, 8, 1.53 + Z_DEFAULT_STRATEGY); 1.54 + if (zerr != Z_OK) return NS_ERROR_OUT_OF_MEMORY; 1.55 + 1.56 + mZstream.next_out = mWriteBuffer; 1.57 + mZstream.avail_out = sizeof(mWriteBuffer); 1.58 + 1.59 + // mark the input buffer as empty. 1.60 + mZstream.avail_in = 0; 1.61 + mZstream.next_in = Z_NULL; 1.62 + 1.63 + return NS_OK; 1.64 +} 1.65 + 1.66 +/* nsIInputStream convert (in nsIInputStream aFromStream, in string aFromType 1.67 + * in string aToType, in nsISupports aCtxt); */ 1.68 +NS_IMETHODIMP nsDeflateConverter::Convert(nsIInputStream *aFromStream, 1.69 + const char *aFromType, 1.70 + const char *aToType, 1.71 + nsISupports *aCtxt, 1.72 + nsIInputStream **_retval) 1.73 +{ 1.74 + return NS_ERROR_NOT_IMPLEMENTED; 1.75 +} 1.76 + 1.77 +/* void asyncConvertData (in string aFromType, in string aToType, 1.78 + * in nsIStreamListener aListener, 1.79 + * in nsISupports aCtxt); */ 1.80 +NS_IMETHODIMP nsDeflateConverter::AsyncConvertData(const char *aFromType, 1.81 + const char *aToType, 1.82 + nsIStreamListener *aListener, 1.83 + nsISupports *aCtxt) 1.84 +{ 1.85 + if (mListener) 1.86 + return NS_ERROR_ALREADY_INITIALIZED; 1.87 + 1.88 + NS_ENSURE_ARG_POINTER(aListener); 1.89 + 1.90 + if (!PL_strncasecmp(aToType, ZLIB_TYPE, sizeof(ZLIB_TYPE)-1)) 1.91 + mWrapMode = WRAP_ZLIB; 1.92 + else if (!PL_strcasecmp(aToType, GZIP_TYPE) || 1.93 + !PL_strcasecmp(aToType, X_GZIP_TYPE)) 1.94 + mWrapMode = WRAP_GZIP; 1.95 + else 1.96 + mWrapMode = WRAP_NONE; 1.97 + 1.98 + nsresult rv = Init(); 1.99 + NS_ENSURE_SUCCESS(rv, rv); 1.100 + 1.101 + mListener = aListener; 1.102 + mContext = aCtxt; 1.103 + return rv; 1.104 +} 1.105 + 1.106 +/* void onDataAvailable (in nsIRequest aRequest, in nsISupports aContext, 1.107 + * in nsIInputStream aInputStream, 1.108 + * in unsigned long long aOffset, 1.109 + * in unsigned long aCount); */ 1.110 +NS_IMETHODIMP nsDeflateConverter::OnDataAvailable(nsIRequest *aRequest, 1.111 + nsISupports *aContext, 1.112 + nsIInputStream *aInputStream, 1.113 + uint64_t aOffset, 1.114 + uint32_t aCount) 1.115 +{ 1.116 + if (!mListener) 1.117 + return NS_ERROR_NOT_INITIALIZED; 1.118 + 1.119 + nsAutoArrayPtr<char> buffer(new char[aCount]); 1.120 + NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY); 1.121 + 1.122 + nsresult rv = ZW_ReadData(aInputStream, buffer.get(), aCount); 1.123 + NS_ENSURE_SUCCESS(rv, rv); 1.124 + 1.125 + // make sure we aren't reading too much 1.126 + mZstream.avail_in = aCount; 1.127 + mZstream.next_in = (unsigned char*)buffer.get(); 1.128 + 1.129 + int zerr = Z_OK; 1.130 + // deflate loop 1.131 + while (mZstream.avail_in > 0 && zerr == Z_OK) { 1.132 + zerr = deflate(&mZstream, Z_NO_FLUSH); 1.133 + 1.134 + while (mZstream.avail_out == 0) { 1.135 + // buffer is full, push the data out to the listener 1.136 + rv = PushAvailableData(aRequest, aContext); 1.137 + NS_ENSURE_SUCCESS(rv, rv); 1.138 + zerr = deflate(&mZstream, Z_NO_FLUSH); 1.139 + } 1.140 + } 1.141 + 1.142 + return NS_OK; 1.143 +} 1.144 + 1.145 +/* void onStartRequest (in nsIRequest aRequest, in nsISupports aContext); */ 1.146 +NS_IMETHODIMP nsDeflateConverter::OnStartRequest(nsIRequest *aRequest, 1.147 + nsISupports *aContext) 1.148 +{ 1.149 + if (!mListener) 1.150 + return NS_ERROR_NOT_INITIALIZED; 1.151 + 1.152 + return mListener->OnStartRequest(aRequest, mContext); 1.153 +} 1.154 + 1.155 +/* void onStopRequest (in nsIRequest aRequest, in nsISupports aContext, 1.156 + * in nsresult aStatusCode); */ 1.157 +NS_IMETHODIMP nsDeflateConverter::OnStopRequest(nsIRequest *aRequest, 1.158 + nsISupports *aContext, 1.159 + nsresult aStatusCode) 1.160 +{ 1.161 + if (!mListener) 1.162 + return NS_ERROR_NOT_INITIALIZED; 1.163 + 1.164 + nsresult rv; 1.165 + 1.166 + int zerr; 1.167 + do { 1.168 + zerr = deflate(&mZstream, Z_FINISH); 1.169 + rv = PushAvailableData(aRequest, aContext); 1.170 + NS_ENSURE_SUCCESS(rv, rv); 1.171 + } while (zerr == Z_OK); 1.172 + 1.173 + deflateEnd(&mZstream); 1.174 + 1.175 + return mListener->OnStopRequest(aRequest, mContext, aStatusCode); 1.176 +} 1.177 + 1.178 +nsresult nsDeflateConverter::PushAvailableData(nsIRequest *aRequest, 1.179 + nsISupports *aContext) 1.180 +{ 1.181 + uint32_t bytesToWrite = sizeof(mWriteBuffer) - mZstream.avail_out; 1.182 + // We don't need to do anything if there isn't any data 1.183 + if (bytesToWrite == 0) 1.184 + return NS_OK; 1.185 + 1.186 + nsresult rv; 1.187 + nsCOMPtr<nsIStringInputStream> stream = 1.188 + do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv); 1.189 + NS_ENSURE_SUCCESS(rv, rv); 1.190 + 1.191 + stream->ShareData((char*)mWriteBuffer, bytesToWrite); 1.192 + rv = mListener->OnDataAvailable(aRequest, mContext, stream, mOffset, 1.193 + bytesToWrite); 1.194 + 1.195 + // now set the state for 'deflate' 1.196 + mZstream.next_out = mWriteBuffer; 1.197 + mZstream.avail_out = sizeof(mWriteBuffer); 1.198 + 1.199 + mOffset += bytesToWrite; 1.200 + return rv; 1.201 +}