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