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