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>
CodecBase()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>
OnDataAvailable()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>
Add(byte[] data)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>
Add(byte[] data, int offset, int count)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>
Finish()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>
~CodecBase()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>
Dispose()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>
CleanUp()140         protected abstract void CleanUp();
141 
142         // performs the release of the handles and calls the dereived CleanUp()
CleanUp(bool isDisposing)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>
copyInput(byte[] data, int startIndex, int count)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>
resetOutput()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>
setChecksum(uint newSum)191         protected void setChecksum(uint newSum)
192         {
193             _checksum = newSum;
194         }
195         #endregion
196 
197     }
198 }
199