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