mirror of
https://github.com/reactos/reactos.git
synced 2024-09-12 05:43:24 +00:00
387 lines
10 KiB
C#
387 lines
10 KiB
C#
// InflaterInputStream.cs
|
|
// Copyright (C) 2001 Mike Krueger
|
|
//
|
|
// This file was translated from java, it was part of the GNU Classpath
|
|
// Copyright (C) 2001 Free Software Foundation, Inc.
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License
|
|
// as published by the Free Software Foundation; either version 2
|
|
// of the License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
//
|
|
// Linking this library statically or dynamically with other modules is
|
|
// making a combined work based on this library. Thus, the terms and
|
|
// conditions of the GNU General Public License cover the whole
|
|
// combination.
|
|
//
|
|
// As a special exception, the copyright holders of this library give you
|
|
// permission to link this library with independent modules to produce an
|
|
// executable, regardless of the license terms of these independent
|
|
// modules, and to copy and distribute the resulting executable under
|
|
// terms of your choice, provided that you also meet, for each linked
|
|
// independent module, the terms and conditions of the license of that
|
|
// module. An independent module is a module which is not derived from
|
|
// or based on this library. If you modify this library, you may extend
|
|
// this exception to your version of the library, but you are not
|
|
// obligated to do so. If you do not wish to do so, delete this
|
|
// exception statement from your version.
|
|
|
|
using System;
|
|
using System.IO;
|
|
|
|
using ICSharpCode.SharpZipLib.Zip.Compression;
|
|
using ICSharpCode.SharpZipLib.Checksums;
|
|
|
|
namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
|
|
{
|
|
|
|
/// <summary>
|
|
/// This filter stream is used to decompress data compressed baseInputStream the "deflate"
|
|
/// format. The "deflate" format is described baseInputStream RFC 1951.
|
|
///
|
|
/// This stream may form the basis for other decompression filters, such
|
|
/// as the <code>GzipInputStream</code>.
|
|
///
|
|
/// author of the original java version : John Leuner
|
|
/// </summary>
|
|
public class InflaterInputStream : Stream
|
|
{
|
|
//Variables
|
|
|
|
/// <summary>
|
|
/// Decompressor for this filter
|
|
/// </summary>
|
|
protected Inflater inf;
|
|
|
|
/// <summary>
|
|
/// Byte array used as a buffer
|
|
/// </summary>
|
|
protected byte[] buf;
|
|
|
|
/// <summary>
|
|
/// Size of buffer
|
|
/// </summary>
|
|
protected int len;
|
|
|
|
//We just use this if we are decoding one byte at a time with the read() call
|
|
private byte[] onebytebuffer = new byte[1];
|
|
|
|
/// <summary>
|
|
/// base stream the inflater depends on.
|
|
/// </summary>
|
|
protected Stream baseInputStream;
|
|
|
|
protected long csize;
|
|
|
|
/// <summary>
|
|
/// I needed to implement the abstract member.
|
|
/// </summary>
|
|
public override bool CanRead {
|
|
get {
|
|
return baseInputStream.CanRead;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// I needed to implement the abstract member.
|
|
/// </summary>
|
|
public override bool CanSeek {
|
|
get {
|
|
return false;
|
|
// return baseInputStream.CanSeek;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// I needed to implement the abstract member.
|
|
/// </summary>
|
|
public override bool CanWrite {
|
|
get {
|
|
return baseInputStream.CanWrite;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// I needed to implement the abstract member.
|
|
/// </summary>
|
|
public override long Length {
|
|
get {
|
|
return len;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// I needed to implement the abstract member.
|
|
/// </summary>
|
|
public override long Position {
|
|
get {
|
|
return baseInputStream.Position;
|
|
}
|
|
set {
|
|
baseInputStream.Position = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Flushes the baseInputStream
|
|
/// </summary>
|
|
public override void Flush()
|
|
{
|
|
baseInputStream.Flush();
|
|
}
|
|
|
|
/// <summary>
|
|
/// I needed to implement the abstract member.
|
|
/// </summary>
|
|
public override long Seek(long offset, SeekOrigin origin)
|
|
{
|
|
throw new NotSupportedException("Seek not supported"); // -jr- 01-Dec-2003
|
|
}
|
|
|
|
/// <summary>
|
|
/// I needed to implement the abstract member.
|
|
/// </summary>
|
|
public override void SetLength(long val)
|
|
{
|
|
baseInputStream.SetLength(val);
|
|
}
|
|
|
|
/// <summary>
|
|
/// I needed to implement the abstract member.
|
|
/// </summary>
|
|
public override void Write(byte[] array, int offset, int count)
|
|
{
|
|
baseInputStream.Write(array, offset, count);
|
|
}
|
|
|
|
/// <summary>
|
|
/// I needed to implement the abstract member.
|
|
/// </summary>
|
|
public override void WriteByte(byte val)
|
|
{
|
|
baseInputStream.WriteByte(val);
|
|
}
|
|
|
|
// -jr- 01-Dec-2003 This may be flawed for some base streams? Depends on implementation of BeginWrite
|
|
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
|
{
|
|
throw new NotSupportedException("Asynch write not currently supported");
|
|
}
|
|
|
|
//Constructors
|
|
|
|
/// <summary>
|
|
/// Create an InflaterInputStream with the default decompresseor
|
|
/// and a default buffer size.
|
|
/// </summary>
|
|
/// <param name = "baseInputStream">
|
|
/// the InputStream to read bytes from
|
|
/// </param>
|
|
public InflaterInputStream(Stream baseInputStream) : this(baseInputStream, new Inflater(), 4096)
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create an InflaterInputStream with the specified decompresseor
|
|
/// and a default buffer size.
|
|
/// </summary>
|
|
/// <param name = "baseInputStream">
|
|
/// the InputStream to read bytes from
|
|
/// </param>
|
|
/// <param name = "inf">
|
|
/// the decompressor used to decompress data read from baseInputStream
|
|
/// </param>
|
|
public InflaterInputStream(Stream baseInputStream, Inflater inf) : this(baseInputStream, inf, 4096)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create an InflaterInputStream with the specified decompresseor
|
|
/// and a specified buffer size.
|
|
/// </summary>
|
|
/// <param name = "baseInputStream">
|
|
/// the InputStream to read bytes from
|
|
/// </param>
|
|
/// <param name = "inf">
|
|
/// the decompressor used to decompress data read from baseInputStream
|
|
/// </param>
|
|
/// <param name = "size">
|
|
/// size of the buffer to use
|
|
/// </param>
|
|
public InflaterInputStream(Stream baseInputStream, Inflater inf, int size)
|
|
{
|
|
this.baseInputStream = baseInputStream;
|
|
this.inf = inf;
|
|
try {
|
|
this.len = (int)baseInputStream.Length;
|
|
} catch (Exception) {
|
|
// the stream may not support .Length
|
|
this.len = 0;
|
|
}
|
|
|
|
if (size <= 0) {
|
|
throw new ArgumentOutOfRangeException("size <= 0");
|
|
}
|
|
|
|
buf = new byte[size]; //Create the buffer
|
|
}
|
|
|
|
//Methods
|
|
|
|
/// <summary>
|
|
/// Returns 0 once the end of the stream (EOF) has been reached.
|
|
/// Otherwise returns 1.
|
|
/// </summary>
|
|
public virtual int Available {
|
|
get {
|
|
return inf.IsFinished ? 0 : 1;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Closes the input stream
|
|
/// </summary>
|
|
public override void Close()
|
|
{
|
|
baseInputStream.Close();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fills the buffer with more data to decompress.
|
|
/// </summary>
|
|
protected void Fill()
|
|
{
|
|
len = baseInputStream.Read(buf, 0, buf.Length);
|
|
// decrypting crypted data
|
|
if (cryptbuffer != null) {
|
|
DecryptBlock(buf, 0, System.Math.Min((int)(csize - inf.TotalIn), buf.Length));
|
|
}
|
|
|
|
if (len <= 0) {
|
|
throw new ApplicationException("Deflated stream ends early.");
|
|
}
|
|
inf.SetInput(buf, 0, len);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads one byte of decompressed data.
|
|
///
|
|
/// The byte is baseInputStream the lower 8 bits of the int.
|
|
/// </summary>
|
|
public override int ReadByte()
|
|
{
|
|
int nread = Read(onebytebuffer, 0, 1); //read one byte
|
|
if (nread > 0) {
|
|
return onebytebuffer[0] & 0xff;
|
|
}
|
|
return -1; // ok
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decompresses data into the byte array
|
|
/// </summary>
|
|
/// <param name ="b">
|
|
/// the array to read and decompress data into
|
|
/// </param>
|
|
/// <param name ="off">
|
|
/// the offset indicating where the data should be placed
|
|
/// </param>
|
|
/// <param name ="len">
|
|
/// the number of bytes to decompress
|
|
/// </param>
|
|
public override int Read(byte[] b, int off, int len)
|
|
{
|
|
for (;;) {
|
|
int count;
|
|
try {
|
|
count = inf.Inflate(b, off, len);
|
|
} catch (Exception e) {
|
|
throw new ZipException(e.ToString());
|
|
}
|
|
|
|
if (count > 0) {
|
|
return count;
|
|
}
|
|
|
|
if (inf.IsNeedingDictionary) {
|
|
throw new ZipException("Need a dictionary");
|
|
} else if (inf.IsFinished) {
|
|
return 0;
|
|
} else if (inf.IsNeedingInput) {
|
|
Fill();
|
|
} else {
|
|
throw new InvalidOperationException("Don't know what to do");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Skip specified number of bytes of uncompressed data
|
|
/// </summary>
|
|
/// <param name ="n">
|
|
/// number of bytes to skip
|
|
/// </param>
|
|
public long Skip(long n)
|
|
{
|
|
if (n < 0) {
|
|
throw new ArgumentOutOfRangeException("n");
|
|
}
|
|
int len = 2048;
|
|
if (n < len) {
|
|
len = (int) n;
|
|
}
|
|
byte[] tmp = new byte[len];
|
|
return (long)baseInputStream.Read(tmp, 0, tmp.Length);
|
|
}
|
|
|
|
#region Encryption stuff
|
|
protected byte[] cryptbuffer = null;
|
|
|
|
uint[] keys = null;
|
|
protected byte DecryptByte()
|
|
{
|
|
uint temp = ((keys[2] & 0xFFFF) | 2);
|
|
return (byte)((temp * (temp ^ 1)) >> 8);
|
|
}
|
|
|
|
protected void DecryptBlock(byte[] buf, int off, int len)
|
|
{
|
|
for (int i = off; i < off + len; ++i) {
|
|
buf[i] ^= DecryptByte();
|
|
UpdateKeys(buf[i]);
|
|
}
|
|
}
|
|
|
|
protected void InitializePassword(string password)
|
|
{
|
|
keys = new uint[] {
|
|
0x12345678,
|
|
0x23456789,
|
|
0x34567890
|
|
};
|
|
for (int i = 0; i < password.Length; ++i) {
|
|
UpdateKeys((byte)password[i]);
|
|
}
|
|
}
|
|
|
|
protected void UpdateKeys(byte ch)
|
|
{
|
|
keys[0] = Crc32.ComputeCrc32(keys[0], ch);
|
|
keys[1] = keys[1] + (byte)keys[0];
|
|
keys[1] = keys[1] * 134775813 + 1;
|
|
keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
|
|
}
|
|
#endregion
|
|
}
|
|
}
|