// ZlibStream.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2010-January-29 16:35:23>
//
// ------------------------------------------------------------------
//
// This module defines the ZlibStream class, which is similar in idea to
// the System.IO.Compression.DeflateStream and
// System.IO.Compression.GZipStream classes in the .NET BCL.
//
// ------------------------------------------------------------------
using System;
using System.IO;
using System.Text;
namespace SharpCompress.Compressors.Deflate
{
public class ZlibStream : Stream
{
private readonly ZlibBaseStream _baseStream;
private bool _disposed;
public ZlibStream(Stream stream, CompressionMode mode)
: this(stream, mode, CompressionLevel.Default, Encoding.UTF8)
{
}
public ZlibStream(Stream stream, CompressionMode mode, CompressionLevel level)
: this(stream, mode, level, Encoding.UTF8)
{
}
public ZlibStream(Stream stream, CompressionMode mode, CompressionLevel level, Encoding encoding)
{
_baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.ZLIB, encoding);
}
#region Zlib properties
///
/// This property sets the flush behavior on the stream.
/// Sorry, though, not sure exactly how to describe all the various settings.
///
public virtual FlushType FlushMode
{
get => (_baseStream._flushMode);
set
{
if (_disposed)
{
throw new ObjectDisposedException("ZlibStream");
}
_baseStream._flushMode = value;
}
}
///
/// The size of the working buffer for the compression codec.
///
///
///
///
/// The working buffer is used for all stream operations. The default size is
/// 1024 bytes. The minimum size is 128 bytes. You may get better performance
/// with a larger buffer. Then again, you might not. You would have to test
/// it.
///
///
///
/// Set this before the first call to Read() or Write() on the
/// stream. If you try to set it afterwards, it will throw.
///
///
public int BufferSize
{
get => _baseStream._bufferSize;
set
{
if (_disposed)
{
throw new ObjectDisposedException("ZlibStream");
}
if (_baseStream._workingBuffer != null)
{
throw new ZlibException("The working buffer is already set.");
}
if (value < ZlibConstants.WorkingBufferSizeMin)
{
throw new ZlibException(
String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value,
ZlibConstants.WorkingBufferSizeMin));
}
_baseStream._bufferSize = value;
}
}
/// Returns the total number of bytes input so far.
public virtual long TotalIn => _baseStream._z.TotalBytesIn;
/// Returns the total number of bytes output so far.
public virtual long TotalOut => _baseStream._z.TotalBytesOut;
#endregion
#region System.IO.Stream methods
///
/// Indicates whether the stream can be read.
///
///
/// The return value depends on whether the captive stream supports reading.
///
public override bool CanRead
{
get
{
if (_disposed)
{
throw new ObjectDisposedException("ZlibStream");
}
return _baseStream._stream.CanRead;
}
}
///
/// Indicates whether the stream supports Seek operations.
///
///
/// Always returns false.
///
public override bool CanSeek => false;
///
/// Indicates whether the stream can be written.
///
///
/// The return value depends on whether the captive stream supports writing.
///
public override bool CanWrite
{
get
{
if (_disposed)
{
throw new ObjectDisposedException("ZlibStream");
}
return _baseStream._stream.CanWrite;
}
}
///
/// Reading this property always throws a .
///
public override long Length => throw new NotSupportedException();
///
/// The position of the stream pointer.
///
///
///
/// Setting this property always throws a . Reading will return the total bytes
/// written out, if used in writing, or the total bytes read in, if used in
/// reading. The count may refer to compressed bytes or uncompressed bytes,
/// depending on how you've used the stream.
///
public override long Position
{
get
{
if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Writer)
{
return _baseStream._z.TotalBytesOut;
}
if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Reader)
{
return _baseStream._z.TotalBytesIn;
}
return 0;
}
set => throw new NotSupportedException();
}
///
/// Dispose the stream.
///
///
/// This may or may not result in a Close() call on the captive stream.
///
protected override void Dispose(bool disposing)
{
try
{
if (!_disposed)
{
if (disposing)
{
_baseStream?.Dispose();
}
_disposed = true;
}
}
finally
{
base.Dispose(disposing);
}
}
///
/// Flush the stream.
///
public override void Flush()
{
if (_disposed)
{
throw new ObjectDisposedException("ZlibStream");
}
_baseStream.Flush();
}
///
/// Read data from the stream.
///
///
///
///
///
/// If you wish to use the ZlibStream to compress data while reading,
/// you can create a ZlibStream with CompressionMode.Compress,
/// providing an uncompressed data stream. Then call Read() on that
/// ZlibStream, and the data read will be compressed. If you wish to
/// use the ZlibStream to decompress data while reading, you can create
/// a ZlibStream with CompressionMode.Decompress, providing a
/// readable compressed data stream. Then call Read() on that
/// ZlibStream, and the data will be decompressed as it is read.
///
///
///
/// A ZlibStream can be used for Read() or Write(), but
/// not both.
///
///
///
/// The buffer into which the read data should be placed.
/// the offset within that data array to put the first byte read.
/// the number of bytes to read.
public override int Read(byte[] buffer, int offset, int count)
{
if (_disposed)
{
throw new ObjectDisposedException("ZlibStream");
}
return _baseStream.Read(buffer, offset, count);
}
public override int ReadByte()
{
if (_disposed)
{
throw new ObjectDisposedException("ZlibStream");
}
return _baseStream.ReadByte();
}
///
/// Calling this method always throws a .
///
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
///
/// Calling this method always throws a .
///
public override void SetLength(long value)
{
throw new NotSupportedException();
}
///
/// Write data to the stream.
///
///
///
///
///
/// If you wish to use the ZlibStream to compress data while writing,
/// you can create a ZlibStream with CompressionMode.Compress,
/// and a writable output stream. Then call Write() on that
/// ZlibStream, providing uncompressed data as input. The data sent to
/// the output stream will be the compressed form of the data written. If you
/// wish to use the ZlibStream to decompress data while writing, you
/// can create a ZlibStream with CompressionMode.Decompress, and a
/// writable output stream. Then call Write() on that stream,
/// providing previously compressed data. The data sent to the output stream
/// will be the decompressed form of the data written.
///
///
///
/// A ZlibStream can be used for Read() or Write(), but not both.
///
///
/// The buffer holding data to write to the stream.
/// the offset within that data array to find the first byte to write.
/// the number of bytes to write.
public override void Write(byte[] buffer, int offset, int count)
{
if (_disposed)
{
throw new ObjectDisposedException("ZlibStream");
}
_baseStream.Write(buffer, offset, count);
}
public override void WriteByte(byte value)
{
if (_disposed)
{
throw new ObjectDisposedException("ZlibStream");
}
_baseStream.WriteByte(value);
}
#endregion System.IO.Stream methods
}
}