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