using Renci.SshNet.Security; using System.IO; using System; namespace Renci.SshNet.Compression { /// /// Represents base class for compression algorithm implementation /// public abstract class Compressor : Algorithm, IDisposable { private readonly ZlibStream _compressor; private readonly ZlibStream _decompressor; private MemoryStream _compressorStream; private MemoryStream _decompressorStream; /// /// Gets or sets a value indicating whether compression is active. /// /// /// true if compression is active; otherwise, false. /// protected bool IsActive { get; set; } /// /// Gets the session. /// protected Session Session { get; private set; } /// /// Initializes a new instance of the class. /// protected Compressor() { _compressorStream = new MemoryStream(); _decompressorStream = new MemoryStream(); _compressor = new ZlibStream(_compressorStream, CompressionMode.Compress); _decompressor = new ZlibStream(_decompressorStream, CompressionMode.Decompress); } /// /// Initializes the algorithm /// /// The session. public virtual void Init(Session session) { Session = session; } /// /// Compresses the specified data. /// /// Data to compress. /// Compressed data public virtual byte[] Compress(byte[] data) { return Compress(data, 0, data.Length); } /// /// Compresses the specified data. /// /// Data to compress. /// The zero-based byte offset in at which to begin reading the data to compress. /// The number of bytes to be compressed. /// /// The compressed data. /// public virtual byte[] Compress(byte[] data, int offset, int length) { if (!IsActive) { if (offset == 0 && length == data.Length) return data; var buffer = new byte[length]; Buffer.BlockCopy(data, offset, buffer, 0, length); return buffer; } _compressorStream.SetLength(0); _compressor.Write(data, offset, length); return _compressorStream.ToArray(); } /// /// Decompresses the specified data. /// /// Compressed data. /// /// The decompressed data. /// public virtual byte[] Decompress(byte[] data) { return Decompress(data, 0, data.Length); } /// /// Decompresses the specified data. /// /// Compressed data. /// The zero-based byte offset in at which to begin reading the data to decompress. /// The number of bytes to be read from the compressed data. /// /// The decompressed data. /// public virtual byte[] Decompress(byte[] data, int offset, int length) { if (!IsActive) { if (offset == 0 && length == data.Length) return data; var buffer = new byte[length]; Buffer.BlockCopy(data, offset, buffer, 0, length); return buffer; } _decompressorStream.SetLength(0); _decompressor.Write(data, offset, length); return _decompressorStream.ToArray(); } #region IDisposable Members private bool _isDisposed; /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged ResourceMessages. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Releases unmanaged and - optionally - managed resources /// /// true to release both managed and unmanaged resources; false to release only unmanaged ResourceMessages. protected virtual void Dispose(bool disposing) { // Check to see if Dispose has already been called. if (!_isDisposed) { // If disposing equals true, dispose all managed // and unmanaged ResourceMessages. if (disposing) { // Dispose managed ResourceMessages. if (_compressorStream != null) { _compressorStream.Dispose(); _compressorStream = null; } if (_decompressorStream != null) { _decompressorStream.Dispose(); _decompressorStream = null; } } // Note disposing has been done. _isDisposed = true; } } /// /// Releases unmanaged resources and performs other cleanup operations before the /// is reclaimed by garbage collection. /// ~Compressor() { // Do not re-create Dispose clean-up code here. // Calling Dispose(false) is optimal in terms of // readability and maintainability. Dispose(false); } #endregion } }