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 }