Import TechBot
[reactos.git] / irc / TechBot / Compression / Streams / InflaterInputStream.cs
1 // InflaterInputStream.cs
2 // Copyright (C) 2001 Mike Krueger
3 //
4 // This file was translated from java, it was part of the GNU Classpath
5 // Copyright (C) 2001 Free Software Foundation, Inc.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 //
21 // Linking this library statically or dynamically with other modules is
22 // making a combined work based on this library. Thus, the terms and
23 // conditions of the GNU General Public License cover the whole
24 // combination.
25 //
26 // As a special exception, the copyright holders of this library give you
27 // permission to link this library with independent modules to produce an
28 // executable, regardless of the license terms of these independent
29 // modules, and to copy and distribute the resulting executable under
30 // terms of your choice, provided that you also meet, for each linked
31 // independent module, the terms and conditions of the license of that
32 // module. An independent module is a module which is not derived from
33 // or based on this library. If you modify this library, you may extend
34 // this exception to your version of the library, but you are not
35 // obligated to do so. If you do not wish to do so, delete this
36 // exception statement from your version.
37
38 using System;
39 using System.IO;
40
41 using ICSharpCode.SharpZipLib.Zip.Compression;
42 using ICSharpCode.SharpZipLib.Checksums;
43
44 namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
45 {
46
47 /// <summary>
48 /// This filter stream is used to decompress data compressed baseInputStream the "deflate"
49 /// format. The "deflate" format is described baseInputStream RFC 1951.
50 ///
51 /// This stream may form the basis for other decompression filters, such
52 /// as the <code>GzipInputStream</code>.
53 ///
54 /// author of the original java version : John Leuner
55 /// </summary>
56 public class InflaterInputStream : Stream
57 {
58 //Variables
59
60 /// <summary>
61 /// Decompressor for this filter
62 /// </summary>
63 protected Inflater inf;
64
65 /// <summary>
66 /// Byte array used as a buffer
67 /// </summary>
68 protected byte[] buf;
69
70 /// <summary>
71 /// Size of buffer
72 /// </summary>
73 protected int len;
74
75 //We just use this if we are decoding one byte at a time with the read() call
76 private byte[] onebytebuffer = new byte[1];
77
78 /// <summary>
79 /// base stream the inflater depends on.
80 /// </summary>
81 protected Stream baseInputStream;
82
83 protected long csize;
84
85 /// <summary>
86 /// I needed to implement the abstract member.
87 /// </summary>
88 public override bool CanRead {
89 get {
90 return baseInputStream.CanRead;
91 }
92 }
93
94 /// <summary>
95 /// I needed to implement the abstract member.
96 /// </summary>
97 public override bool CanSeek {
98 get {
99 return false;
100 // return baseInputStream.CanSeek;
101 }
102 }
103
104 /// <summary>
105 /// I needed to implement the abstract member.
106 /// </summary>
107 public override bool CanWrite {
108 get {
109 return baseInputStream.CanWrite;
110 }
111 }
112
113 /// <summary>
114 /// I needed to implement the abstract member.
115 /// </summary>
116 public override long Length {
117 get {
118 return len;
119 }
120 }
121
122 /// <summary>
123 /// I needed to implement the abstract member.
124 /// </summary>
125 public override long Position {
126 get {
127 return baseInputStream.Position;
128 }
129 set {
130 baseInputStream.Position = value;
131 }
132 }
133
134 /// <summary>
135 /// Flushes the baseInputStream
136 /// </summary>
137 public override void Flush()
138 {
139 baseInputStream.Flush();
140 }
141
142 /// <summary>
143 /// I needed to implement the abstract member.
144 /// </summary>
145 public override long Seek(long offset, SeekOrigin origin)
146 {
147 throw new NotSupportedException("Seek not supported"); // -jr- 01-Dec-2003
148 }
149
150 /// <summary>
151 /// I needed to implement the abstract member.
152 /// </summary>
153 public override void SetLength(long val)
154 {
155 baseInputStream.SetLength(val);
156 }
157
158 /// <summary>
159 /// I needed to implement the abstract member.
160 /// </summary>
161 public override void Write(byte[] array, int offset, int count)
162 {
163 baseInputStream.Write(array, offset, count);
164 }
165
166 /// <summary>
167 /// I needed to implement the abstract member.
168 /// </summary>
169 public override void WriteByte(byte val)
170 {
171 baseInputStream.WriteByte(val);
172 }
173
174 // -jr- 01-Dec-2003 This may be flawed for some base streams? Depends on implementation of BeginWrite
175 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
176 {
177 throw new NotSupportedException("Asynch write not currently supported");
178 }
179
180 //Constructors
181
182 /// <summary>
183 /// Create an InflaterInputStream with the default decompresseor
184 /// and a default buffer size.
185 /// </summary>
186 /// <param name = "baseInputStream">
187 /// the InputStream to read bytes from
188 /// </param>
189 public InflaterInputStream(Stream baseInputStream) : this(baseInputStream, new Inflater(), 4096)
190 {
191
192 }
193
194 /// <summary>
195 /// Create an InflaterInputStream with the specified decompresseor
196 /// and a default buffer size.
197 /// </summary>
198 /// <param name = "baseInputStream">
199 /// the InputStream to read bytes from
200 /// </param>
201 /// <param name = "inf">
202 /// the decompressor used to decompress data read from baseInputStream
203 /// </param>
204 public InflaterInputStream(Stream baseInputStream, Inflater inf) : this(baseInputStream, inf, 4096)
205 {
206 }
207
208 /// <summary>
209 /// Create an InflaterInputStream with the specified decompresseor
210 /// and a specified buffer size.
211 /// </summary>
212 /// <param name = "baseInputStream">
213 /// the InputStream to read bytes from
214 /// </param>
215 /// <param name = "inf">
216 /// the decompressor used to decompress data read from baseInputStream
217 /// </param>
218 /// <param name = "size">
219 /// size of the buffer to use
220 /// </param>
221 public InflaterInputStream(Stream baseInputStream, Inflater inf, int size)
222 {
223 this.baseInputStream = baseInputStream;
224 this.inf = inf;
225 try {
226 this.len = (int)baseInputStream.Length;
227 } catch (Exception) {
228 // the stream may not support .Length
229 this.len = 0;
230 }
231
232 if (size <= 0) {
233 throw new ArgumentOutOfRangeException("size <= 0");
234 }
235
236 buf = new byte[size]; //Create the buffer
237 }
238
239 //Methods
240
241 /// <summary>
242 /// Returns 0 once the end of the stream (EOF) has been reached.
243 /// Otherwise returns 1.
244 /// </summary>
245 public virtual int Available {
246 get {
247 return inf.IsFinished ? 0 : 1;
248 }
249 }
250
251 /// <summary>
252 /// Closes the input stream
253 /// </summary>
254 public override void Close()
255 {
256 baseInputStream.Close();
257 }
258
259 /// <summary>
260 /// Fills the buffer with more data to decompress.
261 /// </summary>
262 protected void Fill()
263 {
264 len = baseInputStream.Read(buf, 0, buf.Length);
265 // decrypting crypted data
266 if (cryptbuffer != null) {
267 DecryptBlock(buf, 0, System.Math.Min((int)(csize - inf.TotalIn), buf.Length));
268 }
269
270 if (len <= 0) {
271 throw new ApplicationException("Deflated stream ends early.");
272 }
273 inf.SetInput(buf, 0, len);
274 }
275
276 /// <summary>
277 /// Reads one byte of decompressed data.
278 ///
279 /// The byte is baseInputStream the lower 8 bits of the int.
280 /// </summary>
281 public override int ReadByte()
282 {
283 int nread = Read(onebytebuffer, 0, 1); //read one byte
284 if (nread > 0) {
285 return onebytebuffer[0] & 0xff;
286 }
287 return -1; // ok
288 }
289
290 /// <summary>
291 /// Decompresses data into the byte array
292 /// </summary>
293 /// <param name ="b">
294 /// the array to read and decompress data into
295 /// </param>
296 /// <param name ="off">
297 /// the offset indicating where the data should be placed
298 /// </param>
299 /// <param name ="len">
300 /// the number of bytes to decompress
301 /// </param>
302 public override int Read(byte[] b, int off, int len)
303 {
304 for (;;) {
305 int count;
306 try {
307 count = inf.Inflate(b, off, len);
308 } catch (Exception e) {
309 throw new ZipException(e.ToString());
310 }
311
312 if (count > 0) {
313 return count;
314 }
315
316 if (inf.IsNeedingDictionary) {
317 throw new ZipException("Need a dictionary");
318 } else if (inf.IsFinished) {
319 return 0;
320 } else if (inf.IsNeedingInput) {
321 Fill();
322 } else {
323 throw new InvalidOperationException("Don't know what to do");
324 }
325 }
326 }
327
328 /// <summary>
329 /// Skip specified number of bytes of uncompressed data
330 /// </summary>
331 /// <param name ="n">
332 /// number of bytes to skip
333 /// </param>
334 public long Skip(long n)
335 {
336 if (n < 0) {
337 throw new ArgumentOutOfRangeException("n");
338 }
339 int len = 2048;
340 if (n < len) {
341 len = (int) n;
342 }
343 byte[] tmp = new byte[len];
344 return (long)baseInputStream.Read(tmp, 0, tmp.Length);
345 }
346
347 #region Encryption stuff
348 protected byte[] cryptbuffer = null;
349
350 uint[] keys = null;
351 protected byte DecryptByte()
352 {
353 uint temp = ((keys[2] & 0xFFFF) | 2);
354 return (byte)((temp * (temp ^ 1)) >> 8);
355 }
356
357 protected void DecryptBlock(byte[] buf, int off, int len)
358 {
359 for (int i = off; i < off + len; ++i) {
360 buf[i] ^= DecryptByte();
361 UpdateKeys(buf[i]);
362 }
363 }
364
365 protected void InitializePassword(string password)
366 {
367 keys = new uint[] {
368 0x12345678,
369 0x23456789,
370 0x34567890
371 };
372 for (int i = 0; i < password.Length; ++i) {
373 UpdateKeys((byte)password[i]);
374 }
375 }
376
377 protected void UpdateKeys(byte ch)
378 {
379 keys[0] = Crc32.ComputeCrc32(keys[0], ch);
380 keys[1] = keys[1] + (byte)keys[0];
381 keys[1] = keys[1] * 134775813 + 1;
382 keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
383 }
384 #endregion
385 }
386 }