1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is Zip Writer Component.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * Dave Townsend <dtownsend@oxymoronical.com>.
18 : *
19 : * Portions created by the Initial Developer are Copyright (C) 2007
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Lan Qiang <jameslan@gmail.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK *****
38 : */
39 :
40 : #include "StreamFunctions.h"
41 : #include "nsDeflateConverter.h"
42 : #include "nsIStringStream.h"
43 : #include "nsIInputStreamPump.h"
44 : #include "nsComponentManagerUtils.h"
45 : #include "nsMemory.h"
46 : #include "nsAutoPtr.h"
47 : #include "plstr.h"
48 :
49 : #define ZLIB_TYPE "deflate"
50 : #define GZIP_TYPE "gzip"
51 : #define X_GZIP_TYPE "x-gzip"
52 :
53 : /**
54 : * nsDeflateConverter is a stream converter applies the deflate compression
55 : * method to the data.
56 : */
57 46471 : NS_IMPL_ISUPPORTS3(nsDeflateConverter, nsIStreamConverter,
58 : nsIStreamListener,
59 : nsIRequestObserver)
60 :
61 5152 : nsresult nsDeflateConverter::Init()
62 : {
63 : int zerr;
64 :
65 5152 : mOffset = 0;
66 :
67 5152 : mZstream.zalloc = Z_NULL;
68 5152 : mZstream.zfree = Z_NULL;
69 5152 : mZstream.opaque = Z_NULL;
70 :
71 5152 : PRInt32 window = MAX_WBITS;
72 5152 : switch (mWrapMode) {
73 : case WRAP_NONE:
74 5146 : window = -window;
75 5146 : break;
76 : case WRAP_GZIP:
77 5 : window += 16;
78 5 : break;
79 : default:
80 1 : break;
81 : }
82 :
83 5152 : zerr = deflateInit2(&mZstream, mLevel, Z_DEFLATED, window, 8,
84 5152 : Z_DEFAULT_STRATEGY);
85 5152 : if (zerr != Z_OK) return NS_ERROR_OUT_OF_MEMORY;
86 :
87 5152 : mZstream.next_out = mWriteBuffer;
88 5152 : mZstream.avail_out = sizeof(mWriteBuffer);
89 :
90 : // mark the input buffer as empty.
91 5152 : mZstream.avail_in = 0;
92 5152 : mZstream.next_in = Z_NULL;
93 :
94 5152 : return NS_OK;
95 : }
96 :
97 : /* nsIInputStream convert (in nsIInputStream aFromStream, in string aFromType
98 : * in string aToType, in nsISupports aCtxt); */
99 0 : NS_IMETHODIMP nsDeflateConverter::Convert(nsIInputStream *aFromStream,
100 : const char *aFromType,
101 : const char *aToType,
102 : nsISupports *aCtxt,
103 : nsIInputStream **_retval)
104 : {
105 0 : return NS_ERROR_NOT_IMPLEMENTED;
106 : }
107 :
108 : /* void asyncConvertData (in string aFromType, in string aToType,
109 : * in nsIStreamListener aListener,
110 : * in nsISupports aCtxt); */
111 5152 : NS_IMETHODIMP nsDeflateConverter::AsyncConvertData(const char *aFromType,
112 : const char *aToType,
113 : nsIStreamListener *aListener,
114 : nsISupports *aCtxt)
115 : {
116 5152 : if (mListener)
117 0 : return NS_ERROR_ALREADY_INITIALIZED;
118 :
119 5152 : NS_ENSURE_ARG_POINTER(aListener);
120 :
121 5152 : if (!PL_strncasecmp(aToType, ZLIB_TYPE, sizeof(ZLIB_TYPE)-1))
122 1 : mWrapMode = WRAP_ZLIB;
123 10297 : else if (!PL_strcasecmp(aToType, GZIP_TYPE) ||
124 5146 : !PL_strcasecmp(aToType, X_GZIP_TYPE))
125 5 : mWrapMode = WRAP_GZIP;
126 : else
127 5146 : mWrapMode = WRAP_NONE;
128 :
129 5152 : nsresult rv = Init();
130 5152 : NS_ENSURE_SUCCESS(rv, rv);
131 :
132 5152 : mListener = aListener;
133 5152 : mContext = aCtxt;
134 5152 : return rv;
135 : }
136 :
137 : /* void onDataAvailable (in nsIRequest aRequest, in nsISupports aContext,
138 : * in nsIInputStream aInputStream,
139 : * in unsigned long aOffset, in unsigned long aCount); */
140 161711 : NS_IMETHODIMP nsDeflateConverter::OnDataAvailable(nsIRequest *aRequest,
141 : nsISupports *aContext,
142 : nsIInputStream *aInputStream,
143 : PRUint32 aOffset,
144 : PRUint32 aCount)
145 : {
146 161711 : if (!mListener)
147 0 : return NS_ERROR_NOT_INITIALIZED;
148 :
149 485133 : nsAutoArrayPtr<char> buffer(new char[aCount]);
150 161711 : NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY);
151 :
152 161711 : nsresult rv = ZW_ReadData(aInputStream, buffer.get(), aCount);
153 161711 : NS_ENSURE_SUCCESS(rv, rv);
154 :
155 : // make sure we aren't reading too much
156 161711 : mZstream.avail_in = aCount;
157 161711 : mZstream.next_in = (unsigned char*)buffer.get();
158 :
159 161711 : int zerr = Z_OK;
160 : // deflate loop
161 485133 : while (mZstream.avail_in > 0 && zerr == Z_OK) {
162 161711 : zerr = deflate(&mZstream, Z_NO_FLUSH);
163 :
164 341402 : while (mZstream.avail_out == 0) {
165 : // buffer is full, push the data out to the listener
166 17980 : rv = PushAvailableData(aRequest, aContext);
167 17980 : NS_ENSURE_SUCCESS(rv, rv);
168 17980 : zerr = deflate(&mZstream, Z_NO_FLUSH);
169 : }
170 : }
171 :
172 161711 : return NS_OK;
173 : }
174 :
175 : /* void onStartRequest (in nsIRequest aRequest, in nsISupports aContext); */
176 5152 : NS_IMETHODIMP nsDeflateConverter::OnStartRequest(nsIRequest *aRequest,
177 : nsISupports *aContext)
178 : {
179 5152 : if (!mListener)
180 0 : return NS_ERROR_NOT_INITIALIZED;
181 :
182 5152 : return mListener->OnStartRequest(aRequest, mContext);
183 : }
184 :
185 : /* void onStopRequest (in nsIRequest aRequest, in nsISupports aContext,
186 : * in nsresult aStatusCode); */
187 5152 : NS_IMETHODIMP nsDeflateConverter::OnStopRequest(nsIRequest *aRequest,
188 : nsISupports *aContext,
189 : nsresult aStatusCode)
190 : {
191 5152 : if (!mListener)
192 0 : return NS_ERROR_NOT_INITIALIZED;
193 :
194 : nsresult rv;
195 :
196 : int zerr;
197 15010 : do {
198 15010 : zerr = deflate(&mZstream, Z_FINISH);
199 15010 : rv = PushAvailableData(aRequest, aContext);
200 15010 : NS_ENSURE_SUCCESS(rv, rv);
201 : } while (zerr == Z_OK);
202 :
203 5152 : deflateEnd(&mZstream);
204 :
205 5152 : return mListener->OnStopRequest(aRequest, mContext, aStatusCode);
206 : }
207 :
208 32990 : nsresult nsDeflateConverter::PushAvailableData(nsIRequest *aRequest,
209 : nsISupports *aContext)
210 : {
211 32990 : PRUint32 bytesToWrite = sizeof(mWriteBuffer) - mZstream.avail_out;
212 : // We don't need to do anything if there isn't any data
213 32990 : if (bytesToWrite == 0)
214 1 : return NS_OK;
215 :
216 : nsresult rv;
217 : nsCOMPtr<nsIStringInputStream> stream =
218 65978 : do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
219 32989 : NS_ENSURE_SUCCESS(rv, rv);
220 :
221 32989 : stream->ShareData((char*)mWriteBuffer, bytesToWrite);
222 32989 : rv = mListener->OnDataAvailable(aRequest, mContext, stream, mOffset,
223 32989 : bytesToWrite);
224 :
225 : // now set the state for 'deflate'
226 32989 : mZstream.next_out = mWriteBuffer;
227 32989 : mZstream.avail_out = sizeof(mWriteBuffer);
228 :
229 32989 : mOffset += bytesToWrite;
230 32989 : return rv;
231 : }
|