Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
michael@0 | 4 | */ |
michael@0 | 5 | |
michael@0 | 6 | #include "StreamFunctions.h" |
michael@0 | 7 | #include "nsZipDataStream.h" |
michael@0 | 8 | #include "nsIStringStream.h" |
michael@0 | 9 | #include "nsISeekableStream.h" |
michael@0 | 10 | #include "nsDeflateConverter.h" |
michael@0 | 11 | #include "nsNetUtil.h" |
michael@0 | 12 | #include "nsComponentManagerUtils.h" |
michael@0 | 13 | #include "nsMemory.h" |
michael@0 | 14 | |
michael@0 | 15 | #define ZIP_METHOD_STORE 0 |
michael@0 | 16 | #define ZIP_METHOD_DEFLATE 8 |
michael@0 | 17 | |
michael@0 | 18 | /** |
michael@0 | 19 | * nsZipDataStream handles the writing an entry's into the zip file. |
michael@0 | 20 | * It is set up to wither write the data as is, or in the event that compression |
michael@0 | 21 | * has been requested to pass it through a stream converter. |
michael@0 | 22 | * Currently only the deflate compression method is supported. |
michael@0 | 23 | * The CRC checksum for the entry's data is also generated here. |
michael@0 | 24 | */ |
michael@0 | 25 | NS_IMPL_ISUPPORTS(nsZipDataStream, nsIStreamListener, |
michael@0 | 26 | nsIRequestObserver) |
michael@0 | 27 | |
michael@0 | 28 | nsresult nsZipDataStream::Init(nsZipWriter *aWriter, |
michael@0 | 29 | nsIOutputStream *aStream, |
michael@0 | 30 | nsZipHeader *aHeader, |
michael@0 | 31 | int32_t aCompression) |
michael@0 | 32 | { |
michael@0 | 33 | mWriter = aWriter; |
michael@0 | 34 | mHeader = aHeader; |
michael@0 | 35 | mStream = aStream; |
michael@0 | 36 | mHeader->mCRC = crc32(0L, Z_NULL, 0); |
michael@0 | 37 | |
michael@0 | 38 | nsresult rv = NS_NewSimpleStreamListener(getter_AddRefs(mOutput), aStream, |
michael@0 | 39 | nullptr); |
michael@0 | 40 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 41 | |
michael@0 | 42 | if (aCompression > 0) { |
michael@0 | 43 | mHeader->mMethod = ZIP_METHOD_DEFLATE; |
michael@0 | 44 | nsCOMPtr<nsIStreamConverter> converter = |
michael@0 | 45 | new nsDeflateConverter(aCompression); |
michael@0 | 46 | NS_ENSURE_TRUE(converter, NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 47 | |
michael@0 | 48 | rv = converter->AsyncConvertData("uncompressed", "rawdeflate", mOutput, |
michael@0 | 49 | nullptr); |
michael@0 | 50 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 51 | |
michael@0 | 52 | mOutput = do_QueryInterface(converter, &rv); |
michael@0 | 53 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 54 | } |
michael@0 | 55 | else { |
michael@0 | 56 | mHeader->mMethod = ZIP_METHOD_STORE; |
michael@0 | 57 | } |
michael@0 | 58 | |
michael@0 | 59 | return NS_OK; |
michael@0 | 60 | } |
michael@0 | 61 | |
michael@0 | 62 | /* void onDataAvailable (in nsIRequest aRequest, in nsISupports aContext, |
michael@0 | 63 | * in nsIInputStream aInputStream, |
michael@0 | 64 | * in unsigned long long aOffset, in unsigned long aCount); */ |
michael@0 | 65 | NS_IMETHODIMP nsZipDataStream::OnDataAvailable(nsIRequest *aRequest, |
michael@0 | 66 | nsISupports *aContext, |
michael@0 | 67 | nsIInputStream *aInputStream, |
michael@0 | 68 | uint64_t aOffset, |
michael@0 | 69 | uint32_t aCount) |
michael@0 | 70 | { |
michael@0 | 71 | if (!mOutput) |
michael@0 | 72 | return NS_ERROR_NOT_INITIALIZED; |
michael@0 | 73 | |
michael@0 | 74 | nsAutoArrayPtr<char> buffer(new char[aCount]); |
michael@0 | 75 | NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 76 | |
michael@0 | 77 | nsresult rv = ZW_ReadData(aInputStream, buffer.get(), aCount); |
michael@0 | 78 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 79 | |
michael@0 | 80 | return ProcessData(aRequest, aContext, buffer.get(), aOffset, aCount); |
michael@0 | 81 | } |
michael@0 | 82 | |
michael@0 | 83 | /* void onStartRequest (in nsIRequest aRequest, in nsISupports aContext); */ |
michael@0 | 84 | NS_IMETHODIMP nsZipDataStream::OnStartRequest(nsIRequest *aRequest, |
michael@0 | 85 | nsISupports *aContext) |
michael@0 | 86 | { |
michael@0 | 87 | if (!mOutput) |
michael@0 | 88 | return NS_ERROR_NOT_INITIALIZED; |
michael@0 | 89 | |
michael@0 | 90 | return mOutput->OnStartRequest(aRequest, aContext); |
michael@0 | 91 | } |
michael@0 | 92 | |
michael@0 | 93 | /* void onStopRequest (in nsIRequest aRequest, in nsISupports aContext, |
michael@0 | 94 | * in nsresult aStatusCode); */ |
michael@0 | 95 | NS_IMETHODIMP nsZipDataStream::OnStopRequest(nsIRequest *aRequest, |
michael@0 | 96 | nsISupports *aContext, |
michael@0 | 97 | nsresult aStatusCode) |
michael@0 | 98 | { |
michael@0 | 99 | if (!mOutput) |
michael@0 | 100 | return NS_ERROR_NOT_INITIALIZED; |
michael@0 | 101 | |
michael@0 | 102 | nsresult rv = mOutput->OnStopRequest(aRequest, aContext, aStatusCode); |
michael@0 | 103 | mOutput = nullptr; |
michael@0 | 104 | if (NS_FAILED(rv)) { |
michael@0 | 105 | mWriter->EntryCompleteCallback(mHeader, rv); |
michael@0 | 106 | } |
michael@0 | 107 | else { |
michael@0 | 108 | rv = CompleteEntry(); |
michael@0 | 109 | rv = mWriter->EntryCompleteCallback(mHeader, rv); |
michael@0 | 110 | } |
michael@0 | 111 | |
michael@0 | 112 | mStream = nullptr; |
michael@0 | 113 | mWriter = nullptr; |
michael@0 | 114 | mHeader = nullptr; |
michael@0 | 115 | |
michael@0 | 116 | return rv; |
michael@0 | 117 | } |
michael@0 | 118 | |
michael@0 | 119 | inline nsresult nsZipDataStream::CompleteEntry() |
michael@0 | 120 | { |
michael@0 | 121 | nsresult rv; |
michael@0 | 122 | nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mStream, &rv); |
michael@0 | 123 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 124 | int64_t pos; |
michael@0 | 125 | rv = seekable->Tell(&pos); |
michael@0 | 126 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 127 | |
michael@0 | 128 | mHeader->mCSize = pos - mHeader->mOffset - mHeader->GetFileHeaderLength(); |
michael@0 | 129 | mHeader->mWriteOnClose = true; |
michael@0 | 130 | return NS_OK; |
michael@0 | 131 | } |
michael@0 | 132 | |
michael@0 | 133 | nsresult nsZipDataStream::ProcessData(nsIRequest *aRequest, |
michael@0 | 134 | nsISupports *aContext, char *aBuffer, |
michael@0 | 135 | uint64_t aOffset, uint32_t aCount) |
michael@0 | 136 | { |
michael@0 | 137 | mHeader->mCRC = crc32(mHeader->mCRC, |
michael@0 | 138 | reinterpret_cast<const unsigned char*>(aBuffer), |
michael@0 | 139 | aCount); |
michael@0 | 140 | |
michael@0 | 141 | nsresult rv; |
michael@0 | 142 | nsCOMPtr<nsIStringInputStream> stream = |
michael@0 | 143 | do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv); |
michael@0 | 144 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 145 | |
michael@0 | 146 | stream->ShareData(aBuffer, aCount); |
michael@0 | 147 | rv = mOutput->OnDataAvailable(aRequest, aContext, stream, aOffset, aCount); |
michael@0 | 148 | mHeader->mUSize += aCount; |
michael@0 | 149 | |
michael@0 | 150 | return rv; |
michael@0 | 151 | } |
michael@0 | 152 | |
michael@0 | 153 | nsresult nsZipDataStream::ReadStream(nsIInputStream *aStream) |
michael@0 | 154 | { |
michael@0 | 155 | if (!mOutput) |
michael@0 | 156 | return NS_ERROR_NOT_INITIALIZED; |
michael@0 | 157 | |
michael@0 | 158 | nsresult rv = OnStartRequest(nullptr, nullptr); |
michael@0 | 159 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 160 | |
michael@0 | 161 | nsAutoArrayPtr<char> buffer(new char[4096]); |
michael@0 | 162 | NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 163 | |
michael@0 | 164 | uint32_t read = 0; |
michael@0 | 165 | uint32_t offset = 0; |
michael@0 | 166 | do |
michael@0 | 167 | { |
michael@0 | 168 | rv = aStream->Read(buffer.get(), 4096, &read); |
michael@0 | 169 | if (NS_FAILED(rv)) { |
michael@0 | 170 | OnStopRequest(nullptr, nullptr, rv); |
michael@0 | 171 | return rv; |
michael@0 | 172 | } |
michael@0 | 173 | |
michael@0 | 174 | if (read > 0) { |
michael@0 | 175 | rv = ProcessData(nullptr, nullptr, buffer.get(), offset, read); |
michael@0 | 176 | if (NS_FAILED(rv)) { |
michael@0 | 177 | OnStopRequest(nullptr, nullptr, rv); |
michael@0 | 178 | return rv; |
michael@0 | 179 | } |
michael@0 | 180 | offset += read; |
michael@0 | 181 | } |
michael@0 | 182 | } while (read > 0); |
michael@0 | 183 | |
michael@0 | 184 | return OnStopRequest(nullptr, nullptr, NS_OK); |
michael@0 | 185 | } |