diff -r 000000000000 -r 6474c204b198 modules/libjar/zipwriter/src/nsZipDataStream.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/libjar/zipwriter/src/nsZipDataStream.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,185 @@ +/* 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 "nsZipDataStream.h" +#include "nsIStringStream.h" +#include "nsISeekableStream.h" +#include "nsDeflateConverter.h" +#include "nsNetUtil.h" +#include "nsComponentManagerUtils.h" +#include "nsMemory.h" + +#define ZIP_METHOD_STORE 0 +#define ZIP_METHOD_DEFLATE 8 + +/** + * nsZipDataStream handles the writing an entry's into the zip file. + * It is set up to wither write the data as is, or in the event that compression + * has been requested to pass it through a stream converter. + * Currently only the deflate compression method is supported. + * The CRC checksum for the entry's data is also generated here. + */ +NS_IMPL_ISUPPORTS(nsZipDataStream, nsIStreamListener, + nsIRequestObserver) + +nsresult nsZipDataStream::Init(nsZipWriter *aWriter, + nsIOutputStream *aStream, + nsZipHeader *aHeader, + int32_t aCompression) +{ + mWriter = aWriter; + mHeader = aHeader; + mStream = aStream; + mHeader->mCRC = crc32(0L, Z_NULL, 0); + + nsresult rv = NS_NewSimpleStreamListener(getter_AddRefs(mOutput), aStream, + nullptr); + NS_ENSURE_SUCCESS(rv, rv); + + if (aCompression > 0) { + mHeader->mMethod = ZIP_METHOD_DEFLATE; + nsCOMPtr converter = + new nsDeflateConverter(aCompression); + NS_ENSURE_TRUE(converter, NS_ERROR_OUT_OF_MEMORY); + + rv = converter->AsyncConvertData("uncompressed", "rawdeflate", mOutput, + nullptr); + NS_ENSURE_SUCCESS(rv, rv); + + mOutput = do_QueryInterface(converter, &rv); + NS_ENSURE_SUCCESS(rv, rv); + } + else { + mHeader->mMethod = ZIP_METHOD_STORE; + } + + return NS_OK; +} + +/* void onDataAvailable (in nsIRequest aRequest, in nsISupports aContext, + * in nsIInputStream aInputStream, + * in unsigned long long aOffset, in unsigned long aCount); */ +NS_IMETHODIMP nsZipDataStream::OnDataAvailable(nsIRequest *aRequest, + nsISupports *aContext, + nsIInputStream *aInputStream, + uint64_t aOffset, + uint32_t aCount) +{ + if (!mOutput) + return NS_ERROR_NOT_INITIALIZED; + + nsAutoArrayPtr 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); + + return ProcessData(aRequest, aContext, buffer.get(), aOffset, aCount); +} + +/* void onStartRequest (in nsIRequest aRequest, in nsISupports aContext); */ +NS_IMETHODIMP nsZipDataStream::OnStartRequest(nsIRequest *aRequest, + nsISupports *aContext) +{ + if (!mOutput) + return NS_ERROR_NOT_INITIALIZED; + + return mOutput->OnStartRequest(aRequest, aContext); +} + +/* void onStopRequest (in nsIRequest aRequest, in nsISupports aContext, + * in nsresult aStatusCode); */ +NS_IMETHODIMP nsZipDataStream::OnStopRequest(nsIRequest *aRequest, + nsISupports *aContext, + nsresult aStatusCode) +{ + if (!mOutput) + return NS_ERROR_NOT_INITIALIZED; + + nsresult rv = mOutput->OnStopRequest(aRequest, aContext, aStatusCode); + mOutput = nullptr; + if (NS_FAILED(rv)) { + mWriter->EntryCompleteCallback(mHeader, rv); + } + else { + rv = CompleteEntry(); + rv = mWriter->EntryCompleteCallback(mHeader, rv); + } + + mStream = nullptr; + mWriter = nullptr; + mHeader = nullptr; + + return rv; +} + +inline nsresult nsZipDataStream::CompleteEntry() +{ + nsresult rv; + nsCOMPtr seekable = do_QueryInterface(mStream, &rv); + NS_ENSURE_SUCCESS(rv, rv); + int64_t pos; + rv = seekable->Tell(&pos); + NS_ENSURE_SUCCESS(rv, rv); + + mHeader->mCSize = pos - mHeader->mOffset - mHeader->GetFileHeaderLength(); + mHeader->mWriteOnClose = true; + return NS_OK; +} + +nsresult nsZipDataStream::ProcessData(nsIRequest *aRequest, + nsISupports *aContext, char *aBuffer, + uint64_t aOffset, uint32_t aCount) +{ + mHeader->mCRC = crc32(mHeader->mCRC, + reinterpret_cast(aBuffer), + aCount); + + nsresult rv; + nsCOMPtr stream = + do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + stream->ShareData(aBuffer, aCount); + rv = mOutput->OnDataAvailable(aRequest, aContext, stream, aOffset, aCount); + mHeader->mUSize += aCount; + + return rv; +} + +nsresult nsZipDataStream::ReadStream(nsIInputStream *aStream) +{ + if (!mOutput) + return NS_ERROR_NOT_INITIALIZED; + + nsresult rv = OnStartRequest(nullptr, nullptr); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoArrayPtr buffer(new char[4096]); + NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY); + + uint32_t read = 0; + uint32_t offset = 0; + do + { + rv = aStream->Read(buffer.get(), 4096, &read); + if (NS_FAILED(rv)) { + OnStopRequest(nullptr, nullptr, rv); + return rv; + } + + if (read > 0) { + rv = ProcessData(nullptr, nullptr, buffer.get(), offset, read); + if (NS_FAILED(rv)) { + OnStopRequest(nullptr, nullptr, rv); + return rv; + } + offset += read; + } + } while (read > 0); + + return OnStopRequest(nullptr, nullptr, NS_OK); +}