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