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