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));