1*9573673dSchristos // 2*9573673dSchristos // � Copyright Henrik Ravn 2004 3*9573673dSchristos // 4*9573673dSchristos // Use, modification and distribution are subject to the Boost Software License, Version 1.0. 5*9573673dSchristos // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6*9573673dSchristos // 7*9573673dSchristos 8*9573673dSchristos using System; 9*9573673dSchristos using System.Runtime.InteropServices; 10*9573673dSchristos 11*9573673dSchristos namespace DotZLib 12*9573673dSchristos { 13*9573673dSchristos /// <summary> 14*9573673dSchristos /// Implements the common functionality needed for all <see cref="Codec"/>s 15*9573673dSchristos /// </summary> 16*9573673dSchristos public abstract class CodecBase : Codec, IDisposable 17*9573673dSchristos { 18*9573673dSchristos 19*9573673dSchristos #region Data members 20*9573673dSchristos 21*9573673dSchristos /// <summary> 22*9573673dSchristos /// Instance of the internal zlib buffer structure that is 23*9573673dSchristos /// passed to all functions in the zlib dll 24*9573673dSchristos /// </summary> 25*9573673dSchristos internal ZStream _ztream = new ZStream(); 26*9573673dSchristos 27*9573673dSchristos /// <summary> 28*9573673dSchristos /// True if the object instance has been disposed, false otherwise 29*9573673dSchristos /// </summary> 30*9573673dSchristos protected bool _isDisposed = false; 31*9573673dSchristos 32*9573673dSchristos /// <summary> 33*9573673dSchristos /// The size of the internal buffers 34*9573673dSchristos /// </summary> 35*9573673dSchristos protected const int kBufferSize = 16384; 36*9573673dSchristos 37*9573673dSchristos private byte[] _outBuffer = new byte[kBufferSize]; 38*9573673dSchristos private byte[] _inBuffer = new byte[kBufferSize]; 39*9573673dSchristos 40*9573673dSchristos private GCHandle _hInput; 41*9573673dSchristos private GCHandle _hOutput; 42*9573673dSchristos 43*9573673dSchristos private uint _checksum = 0; 44*9573673dSchristos 45*9573673dSchristos #endregion 46*9573673dSchristos 47*9573673dSchristos /// <summary> 48*9573673dSchristos /// Initializes a new instance of the <c>CodeBase</c> class. 49*9573673dSchristos /// </summary> CodecBase()50*9573673dSchristos public CodecBase() 51*9573673dSchristos { 52*9573673dSchristos try 53*9573673dSchristos { 54*9573673dSchristos _hInput = GCHandle.Alloc(_inBuffer, GCHandleType.Pinned); 55*9573673dSchristos _hOutput = GCHandle.Alloc(_outBuffer, GCHandleType.Pinned); 56*9573673dSchristos } 57*9573673dSchristos catch (Exception) 58*9573673dSchristos { 59*9573673dSchristos CleanUp(false); 60*9573673dSchristos throw; 61*9573673dSchristos } 62*9573673dSchristos } 63*9573673dSchristos 64*9573673dSchristos 65*9573673dSchristos #region Codec Members 66*9573673dSchristos 67*9573673dSchristos /// <summary> 68*9573673dSchristos /// Occurs when more processed data are available. 69*9573673dSchristos /// </summary> 70*9573673dSchristos public event DataAvailableHandler DataAvailable; 71*9573673dSchristos 72*9573673dSchristos /// <summary> 73*9573673dSchristos /// Fires the <see cref="DataAvailable"/> event 74*9573673dSchristos /// </summary> OnDataAvailable()75*9573673dSchristos protected void OnDataAvailable() 76*9573673dSchristos { 77*9573673dSchristos if (_ztream.total_out > 0) 78*9573673dSchristos { 79*9573673dSchristos if (DataAvailable != null) 80*9573673dSchristos DataAvailable( _outBuffer, 0, (int)_ztream.total_out); 81*9573673dSchristos resetOutput(); 82*9573673dSchristos } 83*9573673dSchristos } 84*9573673dSchristos 85*9573673dSchristos /// <summary> 86*9573673dSchristos /// Adds more data to the codec to be processed. 87*9573673dSchristos /// </summary> 88*9573673dSchristos /// <param name="data">Byte array containing the data to be added to the codec</param> 89*9573673dSchristos /// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks> Add(byte[] data)90*9573673dSchristos public void Add(byte[] data) 91*9573673dSchristos { 92*9573673dSchristos Add(data,0,data.Length); 93*9573673dSchristos } 94*9573673dSchristos 95*9573673dSchristos /// <summary> 96*9573673dSchristos /// Adds more data to the codec to be processed. 97*9573673dSchristos /// </summary> 98*9573673dSchristos /// <param name="data">Byte array containing the data to be added to the codec</param> 99*9573673dSchristos /// <param name="offset">The index of the first byte to add from <c>data</c></param> 100*9573673dSchristos /// <param name="count">The number of bytes to add</param> 101*9573673dSchristos /// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks> 102*9573673dSchristos /// <remarks>This must be implemented by a derived class</remarks> Add(byte[] data, int offset, int count)103*9573673dSchristos public abstract void Add(byte[] data, int offset, int count); 104*9573673dSchristos 105*9573673dSchristos /// <summary> 106*9573673dSchristos /// Finishes up any pending data that needs to be processed and handled. 107*9573673dSchristos /// </summary> 108*9573673dSchristos /// <remarks>This must be implemented by a derived class</remarks> Finish()109*9573673dSchristos public abstract void Finish(); 110*9573673dSchristos 111*9573673dSchristos /// <summary> 112*9573673dSchristos /// Gets the checksum of the data that has been added so far 113*9573673dSchristos /// </summary> 114*9573673dSchristos public uint Checksum { get { return _checksum; } } 115*9573673dSchristos 116*9573673dSchristos #endregion 117*9573673dSchristos 118*9573673dSchristos #region Destructor & IDisposable stuff 119*9573673dSchristos 120*9573673dSchristos /// <summary> 121*9573673dSchristos /// Destroys this instance 122*9573673dSchristos /// </summary> ~CodecBase()123*9573673dSchristos ~CodecBase() 124*9573673dSchristos { 125*9573673dSchristos CleanUp(false); 126*9573673dSchristos } 127*9573673dSchristos 128*9573673dSchristos /// <summary> 129*9573673dSchristos /// Releases any unmanaged resources and calls the <see cref="CleanUp()"/> method of the derived class 130*9573673dSchristos /// </summary> Dispose()131*9573673dSchristos public void Dispose() 132*9573673dSchristos { 133*9573673dSchristos CleanUp(true); 134*9573673dSchristos } 135*9573673dSchristos 136*9573673dSchristos /// <summary> 137*9573673dSchristos /// Performs any codec specific cleanup 138*9573673dSchristos /// </summary> 139*9573673dSchristos /// <remarks>This must be implemented by a derived class</remarks> CleanUp()140*9573673dSchristos protected abstract void CleanUp(); 141*9573673dSchristos 142*9573673dSchristos // performs the release of the handles and calls the dereived CleanUp() CleanUp(bool isDisposing)143*9573673dSchristos private void CleanUp(bool isDisposing) 144*9573673dSchristos { 145*9573673dSchristos if (!_isDisposed) 146*9573673dSchristos { 147*9573673dSchristos CleanUp(); 148*9573673dSchristos if (_hInput.IsAllocated) 149*9573673dSchristos _hInput.Free(); 150*9573673dSchristos if (_hOutput.IsAllocated) 151*9573673dSchristos _hOutput.Free(); 152*9573673dSchristos 153*9573673dSchristos _isDisposed = true; 154*9573673dSchristos } 155*9573673dSchristos } 156*9573673dSchristos 157*9573673dSchristos 158*9573673dSchristos #endregion 159*9573673dSchristos 160*9573673dSchristos #region Helper methods 161*9573673dSchristos 162*9573673dSchristos /// <summary> 163*9573673dSchristos /// Copies a number of bytes to the internal codec buffer - ready for proccesing 164*9573673dSchristos /// </summary> 165*9573673dSchristos /// <param name="data">The byte array that contains the data to copy</param> 166*9573673dSchristos /// <param name="startIndex">The index of the first byte to copy</param> 167*9573673dSchristos /// <param name="count">The number of bytes to copy from <c>data</c></param> copyInput(byte[] data, int startIndex, int count)168*9573673dSchristos protected void copyInput(byte[] data, int startIndex, int count) 169*9573673dSchristos { 170*9573673dSchristos Array.Copy(data, startIndex, _inBuffer,0, count); 171*9573673dSchristos _ztream.next_in = _hInput.AddrOfPinnedObject(); 172*9573673dSchristos _ztream.total_in = 0; 173*9573673dSchristos _ztream.avail_in = (uint)count; 174*9573673dSchristos 175*9573673dSchristos } 176*9573673dSchristos 177*9573673dSchristos /// <summary> 178*9573673dSchristos /// Resets the internal output buffers to a known state - ready for processing 179*9573673dSchristos /// </summary> resetOutput()180*9573673dSchristos protected void resetOutput() 181*9573673dSchristos { 182*9573673dSchristos _ztream.total_out = 0; 183*9573673dSchristos _ztream.avail_out = kBufferSize; 184*9573673dSchristos _ztream.next_out = _hOutput.AddrOfPinnedObject(); 185*9573673dSchristos } 186*9573673dSchristos 187*9573673dSchristos /// <summary> 188*9573673dSchristos /// Updates the running checksum property 189*9573673dSchristos /// </summary> 190*9573673dSchristos /// <param name="newSum">The new checksum value</param> setChecksum(uint newSum)191*9573673dSchristos protected void setChecksum(uint newSum) 192*9573673dSchristos { 193*9573673dSchristos _checksum = newSum; 194*9573673dSchristos } 195*9573673dSchristos #endregion 196*9573673dSchristos 197*9573673dSchristos } 198*9573673dSchristos } 199