/src/mozilla-central/modules/libjar/zipwriter/nsDeflateConverter.cpp
Line | Count | Source (jump to first uncovered line) |
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 "nsDeflateConverter.h" |
8 | | #include "nsStringStream.h" |
9 | | #include "nsIInputStreamPump.h" |
10 | | #include "nsComponentManagerUtils.h" |
11 | | #include "nsMemory.h" |
12 | | #include "plstr.h" |
13 | | #include "mozilla/UniquePtr.h" |
14 | | |
15 | 0 | #define ZLIB_TYPE "deflate" |
16 | 0 | #define GZIP_TYPE "gzip" |
17 | 0 | #define X_GZIP_TYPE "x-gzip" |
18 | | |
19 | | using namespace mozilla; |
20 | | |
21 | | /** |
22 | | * nsDeflateConverter is a stream converter applies the deflate compression |
23 | | * method to the data. |
24 | | */ |
25 | | NS_IMPL_ISUPPORTS(nsDeflateConverter, nsIStreamConverter, |
26 | | nsIStreamListener, |
27 | | nsIRequestObserver) |
28 | | |
29 | | nsresult nsDeflateConverter::Init() |
30 | 0 | { |
31 | 0 | int zerr; |
32 | 0 |
|
33 | 0 | mOffset = 0; |
34 | 0 |
|
35 | 0 | mZstream.zalloc = Z_NULL; |
36 | 0 | mZstream.zfree = Z_NULL; |
37 | 0 | mZstream.opaque = Z_NULL; |
38 | 0 |
|
39 | 0 | int32_t window = MAX_WBITS; |
40 | 0 | switch (mWrapMode) { |
41 | 0 | case WRAP_NONE: |
42 | 0 | window = -window; |
43 | 0 | break; |
44 | 0 | case WRAP_GZIP: |
45 | 0 | window += 16; |
46 | 0 | break; |
47 | 0 | default: |
48 | 0 | break; |
49 | 0 | } |
50 | 0 | |
51 | 0 | zerr = deflateInit2(&mZstream, mLevel, Z_DEFLATED, window, 8, |
52 | 0 | Z_DEFAULT_STRATEGY); |
53 | 0 | if (zerr != Z_OK) return NS_ERROR_OUT_OF_MEMORY; |
54 | 0 | |
55 | 0 | mZstream.next_out = mWriteBuffer; |
56 | 0 | mZstream.avail_out = sizeof(mWriteBuffer); |
57 | 0 |
|
58 | 0 | // mark the input buffer as empty. |
59 | 0 | mZstream.avail_in = 0; |
60 | 0 | mZstream.next_in = Z_NULL; |
61 | 0 |
|
62 | 0 | return NS_OK; |
63 | 0 | } |
64 | | |
65 | | NS_IMETHODIMP nsDeflateConverter::Convert(nsIInputStream *aFromStream, |
66 | | const char *aFromType, |
67 | | const char *aToType, |
68 | | nsISupports *aCtxt, |
69 | | nsIInputStream **_retval) |
70 | 0 | { |
71 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
72 | 0 | } |
73 | | |
74 | | NS_IMETHODIMP nsDeflateConverter::AsyncConvertData(const char *aFromType, |
75 | | const char *aToType, |
76 | | nsIStreamListener *aListener, |
77 | | nsISupports *aCtxt) |
78 | 0 | { |
79 | 0 | if (mListener) |
80 | 0 | return NS_ERROR_ALREADY_INITIALIZED; |
81 | 0 | |
82 | 0 | NS_ENSURE_ARG_POINTER(aListener); |
83 | 0 |
|
84 | 0 | if (!PL_strncasecmp(aToType, ZLIB_TYPE, sizeof(ZLIB_TYPE)-1)) |
85 | 0 | mWrapMode = WRAP_ZLIB; |
86 | 0 | else if (!PL_strcasecmp(aToType, GZIP_TYPE) || |
87 | 0 | !PL_strcasecmp(aToType, X_GZIP_TYPE)) |
88 | 0 | mWrapMode = WRAP_GZIP; |
89 | 0 | else |
90 | 0 | mWrapMode = WRAP_NONE; |
91 | 0 |
|
92 | 0 | nsresult rv = Init(); |
93 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
94 | 0 |
|
95 | 0 | mListener = aListener; |
96 | 0 | mContext = aCtxt; |
97 | 0 | return rv; |
98 | 0 | } |
99 | | |
100 | | NS_IMETHODIMP nsDeflateConverter::OnDataAvailable(nsIRequest *aRequest, |
101 | | nsISupports *aContext, |
102 | | nsIInputStream *aInputStream, |
103 | | uint64_t aOffset, |
104 | | uint32_t aCount) |
105 | 0 | { |
106 | 0 | if (!mListener) |
107 | 0 | return NS_ERROR_NOT_INITIALIZED; |
108 | 0 | |
109 | 0 | auto buffer = MakeUnique<char[]>(aCount); |
110 | 0 | NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY); |
111 | 0 |
|
112 | 0 | nsresult rv = ZW_ReadData(aInputStream, buffer.get(), aCount); |
113 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
114 | 0 |
|
115 | 0 | // make sure we aren't reading too much |
116 | 0 | mZstream.avail_in = aCount; |
117 | 0 | mZstream.next_in = (unsigned char*)buffer.get(); |
118 | 0 |
|
119 | 0 | int zerr = Z_OK; |
120 | 0 | // deflate loop |
121 | 0 | while (mZstream.avail_in > 0 && zerr == Z_OK) { |
122 | 0 | zerr = deflate(&mZstream, Z_NO_FLUSH); |
123 | 0 |
|
124 | 0 | while (mZstream.avail_out == 0) { |
125 | 0 | // buffer is full, push the data out to the listener |
126 | 0 | rv = PushAvailableData(aRequest, aContext); |
127 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
128 | 0 | zerr = deflate(&mZstream, Z_NO_FLUSH); |
129 | 0 | } |
130 | 0 | } |
131 | 0 |
|
132 | 0 | return NS_OK; |
133 | 0 | } |
134 | | |
135 | | NS_IMETHODIMP nsDeflateConverter::OnStartRequest(nsIRequest *aRequest, |
136 | | nsISupports *aContext) |
137 | 0 | { |
138 | 0 | if (!mListener) |
139 | 0 | return NS_ERROR_NOT_INITIALIZED; |
140 | 0 | |
141 | 0 | return mListener->OnStartRequest(aRequest, mContext); |
142 | 0 | } |
143 | | |
144 | | NS_IMETHODIMP nsDeflateConverter::OnStopRequest(nsIRequest *aRequest, |
145 | | nsISupports *aContext, |
146 | | nsresult aStatusCode) |
147 | 0 | { |
148 | 0 | if (!mListener) |
149 | 0 | return NS_ERROR_NOT_INITIALIZED; |
150 | 0 | |
151 | 0 | nsresult rv; |
152 | 0 |
|
153 | 0 | int zerr; |
154 | 0 | do { |
155 | 0 | zerr = deflate(&mZstream, Z_FINISH); |
156 | 0 | rv = PushAvailableData(aRequest, aContext); |
157 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
158 | 0 | } while (zerr == Z_OK); |
159 | 0 |
|
160 | 0 | deflateEnd(&mZstream); |
161 | 0 |
|
162 | 0 | return mListener->OnStopRequest(aRequest, mContext, aStatusCode); |
163 | 0 | } |
164 | | |
165 | | nsresult nsDeflateConverter::PushAvailableData(nsIRequest *aRequest, |
166 | | nsISupports *aContext) |
167 | 0 | { |
168 | 0 | uint32_t bytesToWrite = sizeof(mWriteBuffer) - mZstream.avail_out; |
169 | 0 | // We don't need to do anything if there isn't any data |
170 | 0 | if (bytesToWrite == 0) |
171 | 0 | return NS_OK; |
172 | 0 | |
173 | 0 | MOZ_ASSERT(bytesToWrite <= INT32_MAX); |
174 | 0 | nsCOMPtr<nsIInputStream> stream; |
175 | 0 | nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), |
176 | 0 | (char*)mWriteBuffer, bytesToWrite); |
177 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
178 | 0 |
|
179 | 0 | rv = mListener->OnDataAvailable(aRequest, mContext, stream, mOffset, |
180 | 0 | bytesToWrite); |
181 | 0 |
|
182 | 0 | // now set the state for 'deflate' |
183 | 0 | mZstream.next_out = mWriteBuffer; |
184 | 0 | mZstream.avail_out = sizeof(mWriteBuffer); |
185 | 0 |
|
186 | 0 | mOffset += bytesToWrite; |
187 | 0 | return rv; |
188 | 0 | } |