226 lines
7.6 KiB
C++
226 lines
7.6 KiB
C++
/* ***** 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 Zip Writer Component.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Dave Townsend <dtownsend@oxymoronical.com>.
|
|
*
|
|
* Portions created by the Initial Developer are Copyright (C) 2007
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Lan Qiang <jameslan@gmail.com>
|
|
*
|
|
* 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 *****
|
|
*/
|
|
|
|
#include "StreamFunctions.h"
|
|
#include "nsDeflateConverter.h"
|
|
#include "nsIStringStream.h"
|
|
#include "nsIInputStreamPump.h"
|
|
#include "nsComponentManagerUtils.h"
|
|
#include "nsMemory.h"
|
|
#include "nsAutoPtr.h"
|
|
#include "plstr.h"
|
|
|
|
#define ZLIB_TYPE "deflate"
|
|
#define GZIP_TYPE "gzip"
|
|
#define X_GZIP_TYPE "x-gzip"
|
|
|
|
/**
|
|
* nsDeflateConverter is a stream converter applies the deflate compression
|
|
* method to the data.
|
|
*/
|
|
NS_IMPL_ISUPPORTS3(nsDeflateConverter, nsIStreamConverter,
|
|
nsIStreamListener,
|
|
nsIRequestObserver)
|
|
|
|
nsresult nsDeflateConverter::Init()
|
|
{
|
|
int zerr;
|
|
|
|
mOffset = 0;
|
|
|
|
mZstream.zalloc = Z_NULL;
|
|
mZstream.zfree = Z_NULL;
|
|
mZstream.opaque = Z_NULL;
|
|
|
|
PRInt32 window = MAX_WBITS;
|
|
switch (mWrapMode) {
|
|
case WRAP_NONE:
|
|
window = -window;
|
|
break;
|
|
case WRAP_GZIP:
|
|
window += 16;
|
|
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;
|
|
}
|
|
|
|
/* nsIInputStream convert (in nsIInputStream aFromStream, in string aFromType
|
|
* in string aToType, in nsISupports aCtxt); */
|
|
NS_IMETHODIMP nsDeflateConverter::Convert(nsIInputStream *aFromStream,
|
|
const char *aFromType,
|
|
const char *aToType,
|
|
nsISupports *aCtxt,
|
|
nsIInputStream **_retval)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/* void asyncConvertData (in string aFromType, in string aToType,
|
|
* in nsIStreamListener aListener,
|
|
* in nsISupports aCtxt); */
|
|
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(aFromType, GZIP_TYPE) ||
|
|
!PL_strcasecmp(aFromType, X_GZIP_TYPE))
|
|
mWrapMode = WRAP_GZIP;
|
|
else
|
|
mWrapMode = WRAP_NONE;
|
|
|
|
nsresult rv = Init();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
mListener = aListener;
|
|
mContext = aCtxt;
|
|
return rv;
|
|
}
|
|
|
|
/* void onDataAvailable (in nsIRequest aRequest, in nsISupports aContext,
|
|
* in nsIInputStream aInputStream,
|
|
* in unsigned long aOffset, in unsigned long aCount); */
|
|
NS_IMETHODIMP nsDeflateConverter::OnDataAvailable(nsIRequest *aRequest,
|
|
nsISupports *aContext,
|
|
nsIInputStream *aInputStream,
|
|
PRUint32 aOffset,
|
|
PRUint32 aCount)
|
|
{
|
|
if (!mListener)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsAutoArrayPtr<char> buffer(new 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, aContext);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
zerr = deflate(&mZstream, Z_NO_FLUSH);
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
/* void onStartRequest (in nsIRequest aRequest, in nsISupports aContext); */
|
|
NS_IMETHODIMP nsDeflateConverter::OnStartRequest(nsIRequest *aRequest,
|
|
nsISupports *aContext)
|
|
{
|
|
if (!mListener)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
return mListener->OnStartRequest(aRequest, mContext);
|
|
}
|
|
|
|
/* void onStopRequest (in nsIRequest aRequest, in nsISupports aContext,
|
|
* in nsresult aStatusCode); */
|
|
NS_IMETHODIMP nsDeflateConverter::OnStopRequest(nsIRequest *aRequest,
|
|
nsISupports *aContext,
|
|
nsresult aStatusCode)
|
|
{
|
|
if (!mListener)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsresult rv;
|
|
|
|
int zerr;
|
|
do {
|
|
zerr = deflate(&mZstream, Z_FINISH);
|
|
rv = PushAvailableData(aRequest, aContext);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
} while (zerr == Z_OK);
|
|
|
|
deflateEnd(&mZstream);
|
|
|
|
return mListener->OnStopRequest(aRequest, mContext, aStatusCode);
|
|
}
|
|
|
|
nsresult nsDeflateConverter::PushAvailableData(nsIRequest *aRequest,
|
|
nsISupports *aContext)
|
|
{
|
|
nsresult rv;
|
|
nsCOMPtr<nsIStringInputStream> stream =
|
|
do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
PRUint32 bytesToWrite = ZIP_BUFLEN - mZstream.avail_out;
|
|
stream->ShareData((char*)mWriteBuffer, bytesToWrite);
|
|
rv = mListener->OnDataAvailable(aRequest, mContext, stream, mOffset,
|
|
bytesToWrite);
|
|
|
|
// now set the state for 'deflate'
|
|
mZstream.next_out = mWriteBuffer;
|
|
mZstream.avail_out = sizeof(mWriteBuffer);
|
|
|
|
mOffset += bytesToWrite;
|
|
return rv;
|
|
}
|