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