1 // DeflaterOutputStream.cs
2 // Copyright (C) 2001 Mike Krueger
4 // This file was translated from java, it was part of the GNU Classpath
5 // Copyright (C) 2001 Free Software Foundation, Inc.
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.
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.
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.
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
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.
40 using ICSharpCode.SharpZipLib.Checksums;
41 using ICSharpCode.SharpZipLib.Zip.Compression;
43 namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
47 /// This is a special FilterOutputStream deflating the bytes that are
48 /// written through it. It uses the Deflater for deflating.
50 /// authors of the original java version : Tom Tromey, Jochen Hoenicke
52 public class DeflaterOutputStream : Stream
55 /// This buffer is used temporarily to retrieve the bytes from the
56 /// deflater and write them to the underlying output stream.
61 /// The deflater which is used to deflate the stream.
63 protected Deflater def;
66 /// base stream the deflater depends on.
68 protected Stream baseOutputStream;
71 /// I needed to implement the abstract member.
73 public override bool CanRead {
75 return baseOutputStream.CanRead;
80 /// I needed to implement the abstract member.
82 public override bool CanSeek {
85 // return baseOutputStream.CanSeek;
90 /// I needed to implement the abstract member.
92 public override bool CanWrite {
94 return baseOutputStream.CanWrite;
99 /// I needed to implement the abstract member.
101 public override long Length {
103 return baseOutputStream.Length;
108 /// I needed to implement the abstract member.
110 public override long Position {
112 return baseOutputStream.Position;
115 baseOutputStream.Position = value;
120 /// I needed to implement the abstract member.
122 public override long Seek(long offset, SeekOrigin origin)
124 throw new NotSupportedException("Seek not supported"); // -jr- 01-Dec-2003
125 // return baseOutputStream.Seek(offset, origin);
129 /// I needed to implement the abstract member.
131 public override void SetLength(long val)
133 baseOutputStream.SetLength(val);
137 /// I needed to implement the abstract member.
139 public override int ReadByte()
141 return baseOutputStream.ReadByte();
145 /// I needed to implement the abstract member.
147 public override int Read(byte[] b, int off, int len)
149 return baseOutputStream.Read(b, off, len);
152 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
154 throw new NotSupportedException("Asynch read not currently supported");
158 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
160 throw new NotSupportedException("Asynch write not currently supported");
164 /// Deflates everything in the def's input buffers. This will call
165 /// <code>def.deflate()</code> until all bytes from the input buffers
168 protected void Deflate()
170 while (!def.IsNeedingInput) {
171 int len = def.Deflate(buf, 0, buf.Length);
173 // System.err.println("DOS deflated " + len + " baseOutputStream of " + buf.length);
177 baseOutputStream.Write(buf, 0, len);
180 if (!def.IsNeedingInput) {
181 throw new ApplicationException("Can't deflate all input?");
186 /// Creates a new DeflaterOutputStream with a default Deflater and default buffer size.
188 /// <param name="baseOutputStream">
189 /// the output stream where deflated output should be written.
191 public DeflaterOutputStream(Stream baseOutputStream) : this(baseOutputStream, new Deflater(), 512)
196 /// Creates a new DeflaterOutputStream with the given Deflater and
197 /// default buffer size.
199 /// <param name="baseOutputStream">
200 /// the output stream where deflated output should be written.
202 /// <param name="defl">
203 /// the underlying deflater.
205 public DeflaterOutputStream(Stream baseOutputStream, Deflater defl) :this(baseOutputStream, defl, 512)
210 /// Creates a new DeflaterOutputStream with the given Deflater and
213 /// <param name="baseOutputStream">
214 /// the output stream where deflated output should be written.
216 /// <param name="defl">
217 /// the underlying deflater.
219 /// <param name="bufsize">
222 /// <exception cref="System.InvalidOperationException">
223 /// if bufsize isn't positive.
225 public DeflaterOutputStream(Stream baseOutputStream, Deflater defl, int bufsize)
227 this.baseOutputStream = baseOutputStream;
229 throw new InvalidOperationException("bufsize <= 0");
231 buf = new byte[bufsize];
236 /// Flushes the stream by calling flush() on the deflater and then
237 /// on the underlying stream. This ensures that all bytes are
240 public override void Flush()
244 baseOutputStream.Flush();
248 /// Finishes the stream by calling finish() on the deflater.
250 public virtual void Finish()
253 while (!def.IsFinished) {
254 int len = def.Deflate(buf, 0, buf.Length);
259 // kidnthrain encryption alteration
260 if (this.Password != null) {
261 // plain data has been deflated. Now encrypt result
262 this.EncryptBlock(buf, 0, len);
265 baseOutputStream.Write(buf, 0, len);
267 if (!def.IsFinished) {
268 throw new ApplicationException("Can't deflate all input?");
270 baseOutputStream.Flush();
274 /// Calls finish () and closes the stream.
276 public override void Close()
279 baseOutputStream.Close();
283 /// Writes a single byte to the compressed output stream.
285 /// <param name="bval">
288 public override void WriteByte(byte bval)
290 byte[] b = new byte[1];
296 /// Writes a len bytes from an array to the compressed stream.
298 /// <param name="buf">
301 /// <param name="off">
302 /// the offset into the byte array where to start.
304 /// <param name="len">
305 /// the number of bytes to write.
307 public override void Write(byte[] buf, int off, int len)
309 // System.err.println("DOS with off " + off + " and len " + len);
310 def.SetInput(buf, off, len);
315 string password = null;
318 public string Password {
328 //The beauty of xor-ing bits is that
330 //and enc ^ key = plain
331 //accordingly, this is the exact same as the decrypt byte
332 //function in InflaterInputStream
333 protected byte EncryptByte()
335 uint temp = ((keys[2] & 0xFFFF) | 2);
336 return (byte)((temp * (temp ^ 1)) >> 8);
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
346 protected void EncryptBlock(byte[] buf, int off, int len)
348 for (int i = off; i < off + len; ++i) {
349 byte oldbyte = buf[i];
350 buf[i] ^= EncryptByte();
356 /// Initializes our encryption keys using a given password
358 protected void InitializePassword(string password) {
365 for (int i = 0; i < password.Length; ++i) {
366 UpdateKeys((byte)password[i]);
370 protected void UpdateKeys(byte ch)
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));