| // |
| // © Copyright Henrik Ravn 2004 |
| // |
| // Use, modification and distribution are subject to the Boost Software License, Version 1.0. |
| // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| // |
| |
| using System; |
| using System.Runtime.InteropServices; |
| |
| namespace DotZLib |
| { |
| /// <summary> |
| /// Implements the common functionality needed for all <see cref="Codec"/>s |
| /// </summary> |
| public abstract class CodecBase : Codec, IDisposable |
| { |
| |
| #region Data members |
| |
| /// <summary> |
| /// Instance of the internal zlib buffer structure that is |
| /// passed to all functions in the zlib dll |
| /// </summary> |
| internal ZStream _ztream = new ZStream(); |
| |
| /// <summary> |
| /// True if the object instance has been disposed, false otherwise |
| /// </summary> |
| protected bool _isDisposed = false; |
| |
| /// <summary> |
| /// The size of the internal buffers |
| /// </summary> |
| protected const int kBufferSize = 16384; |
| |
| private byte[] _outBuffer = new byte[kBufferSize]; |
| private byte[] _inBuffer = new byte[kBufferSize]; |
| |
| private GCHandle _hInput; |
| private GCHandle _hOutput; |
| |
| private uint _checksum = 0; |
| |
| #endregion |
| |
| /// <summary> |
| /// Initializes a new instance of the <c>CodeBase</c> class. |
| /// </summary> |
| public CodecBase() |
| { |
| try |
| { |
| _hInput = GCHandle.Alloc(_inBuffer, GCHandleType.Pinned); |
| _hOutput = GCHandle.Alloc(_outBuffer, GCHandleType.Pinned); |
| } |
| catch (Exception) |
| { |
| CleanUp(false); |
| throw; |
| } |
| } |
| |
| |
| #region Codec Members |
| |
| /// <summary> |
| /// Occurs when more processed data are available. |
| /// </summary> |
| public event DataAvailableHandler DataAvailable; |
| |
| /// <summary> |
| /// Fires the <see cref="DataAvailable"/> event |
| /// </summary> |
| protected void OnDataAvailable() |
| { |
| if (_ztream.total_out > 0) |
| { |
| if (DataAvailable != null) |
| DataAvailable( _outBuffer, 0, (int)_ztream.total_out); |
| resetOutput(); |
| } |
| } |
| |
| /// <summary> |
| /// Adds more data to the codec to be processed. |
| /// </summary> |
| /// <param name="data">Byte array containing the data to be added to the codec</param> |
| /// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks> |
| public void Add(byte[] data) |
| { |
| Add(data,0,data.Length); |
| } |
| |
| /// <summary> |
| /// Adds more data to the codec to be processed. |
| /// </summary> |
| /// <param name="data">Byte array containing the data to be added to the codec</param> |
| /// <param name="offset">The index of the first byte to add from <c>data</c></param> |
| /// <param name="count">The number of bytes to add</param> |
| /// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks> |
| /// <remarks>This must be implemented by a derived class</remarks> |
| public abstract void Add(byte[] data, int offset, int count); |
| |
| /// <summary> |
| /// Finishes up any pending data that needs to be processed and handled. |
| /// </summary> |
| /// <remarks>This must be implemented by a derived class</remarks> |
| public abstract void Finish(); |
| |
| /// <summary> |
| /// Gets the checksum of the data that has been added so far |
| /// </summary> |
| public uint Checksum { get { return _checksum; } } |
| |
| #endregion |
| |
| #region Destructor & IDisposable stuff |
| |
| /// <summary> |
| /// Destroys this instance |
| /// </summary> |
| ~CodecBase() |
| { |
| CleanUp(false); |
| } |
| |
| /// <summary> |
| /// Releases any unmanaged resources and calls the <see cref="CleanUp()"/> method of the derived class |
| /// </summary> |
| public void Dispose() |
| { |
| CleanUp(true); |
| } |
| |
| /// <summary> |
| /// Performs any codec specific cleanup |
| /// </summary> |
| /// <remarks>This must be implemented by a derived class</remarks> |
| protected abstract void CleanUp(); |
| |
| // performs the release of the handles and calls the derived CleanUp() |
| private void CleanUp(bool isDisposing) |
| { |
| if (!_isDisposed) |
| { |
| CleanUp(); |
| if (_hInput.IsAllocated) |
| _hInput.Free(); |
| if (_hOutput.IsAllocated) |
| _hOutput.Free(); |
| |
| _isDisposed = true; |
| } |
| } |
| |
| |
| #endregion |
| |
| #region Helper methods |
| |
| /// <summary> |
| /// Copies a number of bytes to the internal codec buffer - ready for processing |
| /// </summary> |
| /// <param name="data">The byte array that contains the data to copy</param> |
| /// <param name="startIndex">The index of the first byte to copy</param> |
| /// <param name="count">The number of bytes to copy from <c>data</c></param> |
| protected void copyInput(byte[] data, int startIndex, int count) |
| { |
| Array.Copy(data, startIndex, _inBuffer,0, count); |
| _ztream.next_in = _hInput.AddrOfPinnedObject(); |
| _ztream.total_in = 0; |
| _ztream.avail_in = (uint)count; |
| |
| } |
| |
| /// <summary> |
| /// Resets the internal output buffers to a known state - ready for processing |
| /// </summary> |
| protected void resetOutput() |
| { |
| _ztream.total_out = 0; |
| _ztream.avail_out = kBufferSize; |
| _ztream.next_out = _hOutput.AddrOfPinnedObject(); |
| } |
| |
| /// <summary> |
| /// Updates the running checksum property |
| /// </summary> |
| /// <param name="newSum">The new checksum value</param> |
| protected void setChecksum(uint newSum) |
| { |
| _checksum = newSum; |
| } |
| #endregion |
| |
| } |
| } |