[DDK]
[reactos.git] / irc / TechBot / Compression / Streams / DeflaterOutputStream.cs
1 // DeflaterOutputStream.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 using ICSharpCode.SharpZipLib.Checksums;
41 using ICSharpCode.SharpZipLib.Zip.Compression;
42
43 namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
44 {
45
46 /// <summary>
47 /// This is a special FilterOutputStream deflating the bytes that are
48 /// written through it. It uses the Deflater for deflating.
49 ///
50 /// authors of the original java version : Tom Tromey, Jochen Hoenicke
51 /// </summary>
52 public class DeflaterOutputStream : Stream
53 {
54 /// <summary>
55 /// This buffer is used temporarily to retrieve the bytes from the
56 /// deflater and write them to the underlying output stream.
57 /// </summary>
58 protected byte[] buf;
59
60 /// <summary>
61 /// The deflater which is used to deflate the stream.
62 /// </summary>
63 protected Deflater def;
64
65 /// <summary>
66 /// base stream the deflater depends on.
67 /// </summary>
68 protected Stream baseOutputStream;
69
70 /// <summary>
71 /// I needed to implement the abstract member.
72 /// </summary>
73 public override bool CanRead {
74 get {
75 return baseOutputStream.CanRead;
76 }
77 }
78
79 /// <summary>
80 /// I needed to implement the abstract member.
81 /// </summary>
82 public override bool CanSeek {
83 get {
84 return false;
85 // return baseOutputStream.CanSeek;
86 }
87 }
88
89 /// <summary>
90 /// I needed to implement the abstract member.
91 /// </summary>
92 public override bool CanWrite {
93 get {
94 return baseOutputStream.CanWrite;
95 }
96 }
97
98 /// <summary>
99 /// I needed to implement the abstract member.
100 /// </summary>
101 public override long Length {
102 get {
103 return baseOutputStream.Length;
104 }
105 }
106
107 /// <summary>
108 /// I needed to implement the abstract member.
109 /// </summary>
110 public override long Position {
111 get {
112 return baseOutputStream.Position;
113 }
114 set {
115 baseOutputStream.Position = value;
116 }
117 }
118
119 /// <summary>
120 /// I needed to implement the abstract member.
121 /// </summary>
122 public override long Seek(long offset, SeekOrigin origin)
123 {
124 throw new NotSupportedException("Seek not supported"); // -jr- 01-Dec-2003
125 // return baseOutputStream.Seek(offset, origin);
126 }
127
128 /// <summary>
129 /// I needed to implement the abstract member.
130 /// </summary>
131 public override void SetLength(long val)
132 {
133 baseOutputStream.SetLength(val);
134 }
135
136 /// <summary>
137 /// I needed to implement the abstract member.
138 /// </summary>
139 public override int ReadByte()
140 {
141 return baseOutputStream.ReadByte();
142 }
143
144 /// <summary>
145 /// I needed to implement the abstract member.
146 /// </summary>
147 public override int Read(byte[] b, int off, int len)
148 {
149 return baseOutputStream.Read(b, off, len);
150 }
151 // -jr- 01-Dec-2003
152 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
153 {
154 throw new NotSupportedException("Asynch read not currently supported");
155 }
156
157 // -jr- 01-Dec-2003
158 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
159 {
160 throw new NotSupportedException("Asynch write not currently supported");
161 }
162
163 /// <summary>
164 /// Deflates everything in the def's input buffers. This will call
165 /// <code>def.deflate()</code> until all bytes from the input buffers
166 /// are processed.
167 /// </summary>
168 protected void Deflate()
169 {
170 while (!def.IsNeedingInput) {
171 int len = def.Deflate(buf, 0, buf.Length);
172
173 // System.err.println("DOS deflated " + len + " baseOutputStream of " + buf.length);
174 if (len <= 0) {
175 break;
176 }
177 baseOutputStream.Write(buf, 0, len);
178 }
179
180 if (!def.IsNeedingInput) {
181 throw new ApplicationException("Can't deflate all input?");
182 }
183 }
184
185 /// <summary>
186 /// Creates a new DeflaterOutputStream with a default Deflater and default buffer size.
187 /// </summary>
188 /// <param name="baseOutputStream">
189 /// the output stream where deflated output should be written.
190 /// </param>
191 public DeflaterOutputStream(Stream baseOutputStream) : this(baseOutputStream, new Deflater(), 512)
192 {
193 }
194
195 /// <summary>
196 /// Creates a new DeflaterOutputStream with the given Deflater and
197 /// default buffer size.
198 /// </summary>
199 /// <param name="baseOutputStream">
200 /// the output stream where deflated output should be written.
201 /// </param>
202 /// <param name="defl">
203 /// the underlying deflater.
204 /// </param>
205 public DeflaterOutputStream(Stream baseOutputStream, Deflater defl) :this(baseOutputStream, defl, 512)
206 {
207 }
208
209 /// <summary>
210 /// Creates a new DeflaterOutputStream with the given Deflater and
211 /// buffer size.
212 /// </summary>
213 /// <param name="baseOutputStream">
214 /// the output stream where deflated output should be written.
215 /// </param>
216 /// <param name="defl">
217 /// the underlying deflater.
218 /// </param>
219 /// <param name="bufsize">
220 /// the buffer size.
221 /// </param>
222 /// <exception cref="System.InvalidOperationException">
223 /// if bufsize isn't positive.
224 /// </exception>
225 public DeflaterOutputStream(Stream baseOutputStream, Deflater defl, int bufsize)
226 {
227 this.baseOutputStream = baseOutputStream;
228 if (bufsize <= 0) {
229 throw new InvalidOperationException("bufsize <= 0");
230 }
231 buf = new byte[bufsize];
232 def = defl;
233 }
234
235 /// <summary>
236 /// Flushes the stream by calling flush() on the deflater and then
237 /// on the underlying stream. This ensures that all bytes are
238 /// flushed.
239 /// </summary>
240 public override void Flush()
241 {
242 def.Flush();
243 Deflate();
244 baseOutputStream.Flush();
245 }
246
247 /// <summary>
248 /// Finishes the stream by calling finish() on the deflater.
249 /// </summary>
250 public virtual void Finish()
251 {
252 def.Finish();
253 while (!def.IsFinished) {
254 int len = def.Deflate(buf, 0, buf.Length);
255 if (len <= 0) {
256 break;
257 }
258
259 // kidnthrain encryption alteration
260 if (this.Password != null) {
261 // plain data has been deflated. Now encrypt result
262 this.EncryptBlock(buf, 0, len);
263 }
264
265 baseOutputStream.Write(buf, 0, len);
266 }
267 if (!def.IsFinished) {
268 throw new ApplicationException("Can't deflate all input?");
269 }
270 baseOutputStream.Flush();
271 }
272
273 /// <summary>
274 /// Calls finish () and closes the stream.
275 /// </summary>
276 public override void Close()
277 {
278 Finish();
279 baseOutputStream.Close();
280 }
281
282 /// <summary>
283 /// Writes a single byte to the compressed output stream.
284 /// </summary>
285 /// <param name="bval">
286 /// the byte value.
287 /// </param>
288 public override void WriteByte(byte bval)
289 {
290 byte[] b = new byte[1];
291 b[0] = (byte) bval;
292 Write(b, 0, 1);
293 }
294
295 /// <summary>
296 /// Writes a len bytes from an array to the compressed stream.
297 /// </summary>
298 /// <param name="buf">
299 /// the byte array.
300 /// </param>
301 /// <param name="off">
302 /// the offset into the byte array where to start.
303 /// </param>
304 /// <param name="len">
305 /// the number of bytes to write.
306 /// </param>
307 public override void Write(byte[] buf, int off, int len)
308 {
309 // System.err.println("DOS with off " + off + " and len " + len);
310 def.SetInput(buf, off, len);
311 Deflate();
312 }
313
314 #region Encryption
315 string password = null;
316 uint[] keys = null;
317
318 public string Password {
319 get {
320 return password;
321 }
322 set {
323 password = value;
324 }
325 }
326
327
328 //The beauty of xor-ing bits is that
329 //plain ^ key = enc
330 //and enc ^ key = plain
331 //accordingly, this is the exact same as the decrypt byte
332 //function in InflaterInputStream
333 protected byte EncryptByte()
334 {
335 uint temp = ((keys[2] & 0xFFFF) | 2);
336 return (byte)((temp * (temp ^ 1)) >> 8);
337 }
338
339
340 /// <summary>
341 /// Takes a buffer of data and uses the keys
342 /// that have been previously initialized from a
343 /// password and then updated via a random encryption header
344 /// to encrypt that data
345 /// </summary>
346 protected void EncryptBlock(byte[] buf, int off, int len)
347 {
348 for (int i = off; i < off + len; ++i) {
349 byte oldbyte = buf[i];
350 buf[i] ^= EncryptByte();
351 UpdateKeys(oldbyte);
352 }
353 }
354
355 /// <summary>
356 /// Initializes our encryption keys using a given password
357 /// </summary>
358 protected void InitializePassword(string password) {
359 keys = new uint[] {
360 0x12345678,
361 0x23456789,
362 0x34567890
363 };
364
365 for (int i = 0; i < password.Length; ++i) {
366 UpdateKeys((byte)password[i]);
367 }
368 }
369
370 protected void UpdateKeys(byte ch)
371 {
372 keys[0] = Crc32.ComputeCrc32(keys[0], ch);
373 keys[1] = keys[1] + (byte)keys[0];
374 keys[1] = keys[1] * 134775813 + 1;
375 keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
376 }
377 #endregion
378 }
379 }