namespace ImageProcessor.Formats
{
using System;
using System.IO;
//using ICSharpCode.SharpZipLib;
//using ICSharpCode.SharpZipLib.Zip;
//using ICSharpCode.SharpZipLib.Zip.Compression;
///
/// This filter stream is used to decompress data compressed using the "deflate"
/// format. The "deflate" format is described in RFC 1951.
///
/// This stream may form the basis for other decompression filters, such
/// as the GZipInputStream.
///
/// Author of the original java version : John Leuner.
///
public class InflaterInputStream : Stream
{
#region Constructors
///
/// Create an InflaterInputStream with the default decompressor
/// and a default buffer size of 4KB.
///
///
/// The InputStream to read bytes from
///
public InflaterInputStream(Stream baseInputStream)
: this(baseInputStream, new Inflater(), 4096)
{
}
///
/// Create an InflaterInputStream with the specified decompressor
/// and a default buffer size of 4KB.
///
///
/// The source of input data
///
///
/// The decompressor used to decompress data read from baseInputStream
///
public InflaterInputStream(Stream baseInputStream, Inflater inf)
: this(baseInputStream, inf, 4096)
{
}
///
/// Create an InflaterInputStream with the specified decompressor and the specified buffer size.
///
///
/// The InputStream to read bytes from
///
///
/// The decompressor to use
///
///
/// Size of the buffer to use
///
public InflaterInputStream(Stream baseInputStream, Inflater inflater, int bufferSize)
{
if (baseInputStream == null)
{
throw new ArgumentNullException("baseInputStream");
}
if (inflater == null)
{
throw new ArgumentNullException("inflater");
}
if (bufferSize <= 0)
{
throw new ArgumentOutOfRangeException("bufferSize");
}
this.baseInputStream = baseInputStream;
this.inf = inflater;
inputBuffer = new InflaterInputBuffer(baseInputStream, bufferSize);
}
#endregion
///
/// Get/set flag indicating ownership of underlying stream.
/// When the flag is true will close the underlying stream also.
///
///
/// The default value is true.
///
public bool IsStreamOwner
{
get { return isStreamOwner; }
set { isStreamOwner = value; }
}
///
/// Skip specified number of bytes of uncompressed data
///
///
/// Number of bytes to skip
///
///
/// The number of bytes skipped, zero if the end of
/// stream has been reached
///
///
/// The number of bytes to skip is less than or equal to zero.
///
public long Skip(long count)
{
if (count <= 0)
{
throw new ArgumentOutOfRangeException("count");
}
// v0.80 Skip by seeking if underlying stream supports it...
if (baseInputStream.CanSeek)
{
baseInputStream.Seek(count, SeekOrigin.Current);
return count;
}
else
{
int length = 2048;
if (count < length)
{
length = (int)count;
}
byte[] tmp = new byte[length];
int readCount = 1;
long toSkip = count;
while ((toSkip > 0) && (readCount > 0))
{
if (toSkip < length)
{
length = (int)toSkip;
}
readCount = baseInputStream.Read(tmp, 0, length);
toSkip -= readCount;
}
return count - toSkip;
}
}
///
/// Clear any cryptographic state.
///
protected void StopDecrypting()
{
#if !NETCF_1_0 && !NOCRYPTO
inputBuffer.CryptoTransform = null;
#endif
}
///
/// Returns 0 once the end of the stream (EOF) has been reached.
/// Otherwise returns 1.
///
public virtual int Available
{
get
{
return inf.IsFinished ? 0 : 1;
}
}
///
/// Fills the buffer with more data to decompress.
///
///
/// Stream ends early
///
protected void Fill()
{
// Protect against redundant calls
if (inputBuffer.Available <= 0)
{
inputBuffer.Fill();
if (inputBuffer.Available <= 0)
{
throw new ImageFormatException("Unexpected EOF");
}
}
inputBuffer.SetInflaterInput(inf);
}
#region Stream Overrides
///
/// Gets a value indicating whether the current stream supports reading
///
public override bool CanRead
{
get
{
return baseInputStream.CanRead;
}
}
///
/// Gets a value of false indicating seeking is not supported for this stream.
///
public override bool CanSeek
{
get
{
return false;
}
}
///
/// Gets a value of false indicating that this stream is not writeable.
///
public override bool CanWrite
{
get
{
return false;
}
}
///
/// A value representing the length of the stream in bytes.
///
public override long Length
{
get
{
return inputBuffer.RawLength;
}
}
///
/// The current position within the stream.
/// Throws a NotSupportedException when attempting to set the position
///
/// Attempting to set the position
public override long Position
{
get
{
return baseInputStream.Position;
}
set
{
throw new NotSupportedException("InflaterInputStream Position not supported");
}
}
///
/// Flushes the baseInputStream
///
public override void Flush()
{
baseInputStream.Flush();
}
///
/// Sets the position within the current stream
/// Always throws a NotSupportedException
///
/// The relative offset to seek to.
/// The defining where to seek from.
/// The new position in the stream.
/// Any access
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException("Seek not supported");
}
///
/// Set the length of the current stream
/// Always throws a NotSupportedException
///
/// The new length value for the stream.
/// Any access
public override void SetLength(long value)
{
throw new NotSupportedException("InflaterInputStream SetLength not supported");
}
///
/// Writes a sequence of bytes to stream and advances the current position
/// This method always throws a NotSupportedException
///
/// Thew buffer containing data to write.
/// The offset of the first byte to write.
/// The number of bytes to write.
/// Any access
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException("InflaterInputStream Write not supported");
}
///
/// Writes one byte to the current stream and advances the current position
/// Always throws a NotSupportedException
///
/// The byte to write.
/// Any access
public override void WriteByte(byte value)
{
throw new NotSupportedException("InflaterInputStream WriteByte not supported");
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing && !isClosed)
{
isClosed = true;
if (isStreamOwner)
{
baseInputStream.Dispose();
}
}
}
///
/// Reads decompressed data into the provided buffer byte array
///
///
/// The array to read and decompress data into
///
///
/// The offset indicating where the data should be placed
///
///
/// The number of bytes to decompress
///
/// The number of bytes read. Zero signals the end of stream
///
/// Inflater needs a dictionary
///
public override int Read(byte[] buffer, int offset, int count)
{
if (inf.IsNeedingDictionary)
{
throw new ImageFormatException("Need a dictionary");
}
int remainingBytes = count;
while (true)
{
int bytesRead = inf.Inflate(buffer, offset, remainingBytes);
offset += bytesRead;
remainingBytes -= bytesRead;
if (remainingBytes == 0 || inf.IsFinished)
{
break;
}
if (inf.IsNeedingInput)
{
Fill();
}
else if (bytesRead == 0)
{
throw new ImageFormatException("Dont know what to do");
}
}
return count - remainingBytes;
}
#endregion
#region Instance Fields
///
/// Decompressor for this stream
///
protected Inflater inf;
///
/// Input buffer for this stream.
///
protected InflaterInputBuffer inputBuffer;
///
/// Base stream the inflater reads from.
///
private Stream baseInputStream;
///
/// The compressed size
///
protected long csize;
///
/// Flag indicating wether this instance has been closed or not.
///
bool isClosed;
///
/// Flag indicating wether this instance is designated the stream owner.
/// When closing if this flag is true the underlying stream is closed.
///
bool isStreamOwner = true;
#endregion
}
}