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