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: }