1275793eaSopenharmony_ci//
2275793eaSopenharmony_ci// � Copyright Henrik Ravn 2004
3275793eaSopenharmony_ci//
4275793eaSopenharmony_ci// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
5275793eaSopenharmony_ci// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6275793eaSopenharmony_ci//
7275793eaSopenharmony_ci
8275793eaSopenharmony_ciusing System;
9275793eaSopenharmony_ciusing System.Runtime.InteropServices;
10275793eaSopenharmony_ci
11275793eaSopenharmony_cinamespace DotZLib
12275793eaSopenharmony_ci{
13275793eaSopenharmony_ci	/// <summary>
14275793eaSopenharmony_ci	/// Implements the common functionality needed for all <see cref="Codec"/>s
15275793eaSopenharmony_ci	/// </summary>
16275793eaSopenharmony_ci	public abstract class CodecBase : Codec, IDisposable
17275793eaSopenharmony_ci	{
18275793eaSopenharmony_ci
19275793eaSopenharmony_ci        #region Data members
20275793eaSopenharmony_ci
21275793eaSopenharmony_ci        /// <summary>
22275793eaSopenharmony_ci        /// Instance of the internal zlib buffer structure that is
23275793eaSopenharmony_ci        /// passed to all functions in the zlib dll
24275793eaSopenharmony_ci        /// </summary>
25275793eaSopenharmony_ci        internal ZStream _ztream = new ZStream();
26275793eaSopenharmony_ci
27275793eaSopenharmony_ci        /// <summary>
28275793eaSopenharmony_ci        /// True if the object instance has been disposed, false otherwise
29275793eaSopenharmony_ci        /// </summary>
30275793eaSopenharmony_ci        protected bool _isDisposed = false;
31275793eaSopenharmony_ci
32275793eaSopenharmony_ci        /// <summary>
33275793eaSopenharmony_ci        /// The size of the internal buffers
34275793eaSopenharmony_ci        /// </summary>
35275793eaSopenharmony_ci        protected const int kBufferSize = 16384;
36275793eaSopenharmony_ci
37275793eaSopenharmony_ci        private byte[] _outBuffer = new byte[kBufferSize];
38275793eaSopenharmony_ci        private byte[] _inBuffer = new byte[kBufferSize];
39275793eaSopenharmony_ci
40275793eaSopenharmony_ci        private GCHandle _hInput;
41275793eaSopenharmony_ci        private GCHandle _hOutput;
42275793eaSopenharmony_ci
43275793eaSopenharmony_ci        private uint _checksum = 0;
44275793eaSopenharmony_ci
45275793eaSopenharmony_ci        #endregion
46275793eaSopenharmony_ci
47275793eaSopenharmony_ci        /// <summary>
48275793eaSopenharmony_ci        /// Initializes a new instance of the <c>CodeBase</c> class.
49275793eaSopenharmony_ci        /// </summary>
50275793eaSopenharmony_ci		public CodecBase()
51275793eaSopenharmony_ci		{
52275793eaSopenharmony_ci            try
53275793eaSopenharmony_ci            {
54275793eaSopenharmony_ci                _hInput = GCHandle.Alloc(_inBuffer, GCHandleType.Pinned);
55275793eaSopenharmony_ci                _hOutput = GCHandle.Alloc(_outBuffer, GCHandleType.Pinned);
56275793eaSopenharmony_ci            }
57275793eaSopenharmony_ci            catch (Exception)
58275793eaSopenharmony_ci            {
59275793eaSopenharmony_ci                CleanUp(false);
60275793eaSopenharmony_ci                throw;
61275793eaSopenharmony_ci            }
62275793eaSopenharmony_ci        }
63275793eaSopenharmony_ci
64275793eaSopenharmony_ci
65275793eaSopenharmony_ci        #region Codec Members
66275793eaSopenharmony_ci
67275793eaSopenharmony_ci        /// <summary>
68275793eaSopenharmony_ci        /// Occurs when more processed data are available.
69275793eaSopenharmony_ci        /// </summary>
70275793eaSopenharmony_ci        public event DataAvailableHandler DataAvailable;
71275793eaSopenharmony_ci
72275793eaSopenharmony_ci        /// <summary>
73275793eaSopenharmony_ci        /// Fires the <see cref="DataAvailable"/> event
74275793eaSopenharmony_ci        /// </summary>
75275793eaSopenharmony_ci        protected void OnDataAvailable()
76275793eaSopenharmony_ci        {
77275793eaSopenharmony_ci            if (_ztream.total_out > 0)
78275793eaSopenharmony_ci            {
79275793eaSopenharmony_ci                if (DataAvailable != null)
80275793eaSopenharmony_ci                    DataAvailable( _outBuffer, 0, (int)_ztream.total_out);
81275793eaSopenharmony_ci                resetOutput();
82275793eaSopenharmony_ci            }
83275793eaSopenharmony_ci        }
84275793eaSopenharmony_ci
85275793eaSopenharmony_ci        /// <summary>
86275793eaSopenharmony_ci        /// Adds more data to the codec to be processed.
87275793eaSopenharmony_ci        /// </summary>
88275793eaSopenharmony_ci        /// <param name="data">Byte array containing the data to be added to the codec</param>
89275793eaSopenharmony_ci        /// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
90275793eaSopenharmony_ci        public void Add(byte[] data)
91275793eaSopenharmony_ci        {
92275793eaSopenharmony_ci            Add(data,0,data.Length);
93275793eaSopenharmony_ci        }
94275793eaSopenharmony_ci
95275793eaSopenharmony_ci        /// <summary>
96275793eaSopenharmony_ci        /// Adds more data to the codec to be processed.
97275793eaSopenharmony_ci        /// </summary>
98275793eaSopenharmony_ci        /// <param name="data">Byte array containing the data to be added to the codec</param>
99275793eaSopenharmony_ci        /// <param name="offset">The index of the first byte to add from <c>data</c></param>
100275793eaSopenharmony_ci        /// <param name="count">The number of bytes to add</param>
101275793eaSopenharmony_ci        /// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
102275793eaSopenharmony_ci        /// <remarks>This must be implemented by a derived class</remarks>
103275793eaSopenharmony_ci        public abstract void Add(byte[] data, int offset, int count);
104275793eaSopenharmony_ci
105275793eaSopenharmony_ci        /// <summary>
106275793eaSopenharmony_ci        /// Finishes up any pending data that needs to be processed and handled.
107275793eaSopenharmony_ci        /// </summary>
108275793eaSopenharmony_ci        /// <remarks>This must be implemented by a derived class</remarks>
109275793eaSopenharmony_ci        public abstract void Finish();
110275793eaSopenharmony_ci
111275793eaSopenharmony_ci        /// <summary>
112275793eaSopenharmony_ci        /// Gets the checksum of the data that has been added so far
113275793eaSopenharmony_ci        /// </summary>
114275793eaSopenharmony_ci        public uint Checksum { get { return _checksum; } }
115275793eaSopenharmony_ci
116275793eaSopenharmony_ci        #endregion
117275793eaSopenharmony_ci
118275793eaSopenharmony_ci        #region Destructor & IDisposable stuff
119275793eaSopenharmony_ci
120275793eaSopenharmony_ci        /// <summary>
121275793eaSopenharmony_ci        /// Destroys this instance
122275793eaSopenharmony_ci        /// </summary>
123275793eaSopenharmony_ci        ~CodecBase()
124275793eaSopenharmony_ci        {
125275793eaSopenharmony_ci            CleanUp(false);
126275793eaSopenharmony_ci        }
127275793eaSopenharmony_ci
128275793eaSopenharmony_ci        /// <summary>
129275793eaSopenharmony_ci        /// Releases any unmanaged resources and calls the <see cref="CleanUp()"/> method of the derived class
130275793eaSopenharmony_ci        /// </summary>
131275793eaSopenharmony_ci        public void Dispose()
132275793eaSopenharmony_ci        {
133275793eaSopenharmony_ci            CleanUp(true);
134275793eaSopenharmony_ci        }
135275793eaSopenharmony_ci
136275793eaSopenharmony_ci        /// <summary>
137275793eaSopenharmony_ci        /// Performs any codec specific cleanup
138275793eaSopenharmony_ci        /// </summary>
139275793eaSopenharmony_ci        /// <remarks>This must be implemented by a derived class</remarks>
140275793eaSopenharmony_ci        protected abstract void CleanUp();
141275793eaSopenharmony_ci
142275793eaSopenharmony_ci        // performs the release of the handles and calls the derived CleanUp()
143275793eaSopenharmony_ci        private void CleanUp(bool isDisposing)
144275793eaSopenharmony_ci        {
145275793eaSopenharmony_ci            if (!_isDisposed)
146275793eaSopenharmony_ci            {
147275793eaSopenharmony_ci                CleanUp();
148275793eaSopenharmony_ci                if (_hInput.IsAllocated)
149275793eaSopenharmony_ci                    _hInput.Free();
150275793eaSopenharmony_ci                if (_hOutput.IsAllocated)
151275793eaSopenharmony_ci                    _hOutput.Free();
152275793eaSopenharmony_ci
153275793eaSopenharmony_ci                _isDisposed = true;
154275793eaSopenharmony_ci            }
155275793eaSopenharmony_ci        }
156275793eaSopenharmony_ci
157275793eaSopenharmony_ci
158275793eaSopenharmony_ci        #endregion
159275793eaSopenharmony_ci
160275793eaSopenharmony_ci        #region Helper methods
161275793eaSopenharmony_ci
162275793eaSopenharmony_ci        /// <summary>
163275793eaSopenharmony_ci        /// Copies a number of bytes to the internal codec buffer - ready for processing
164275793eaSopenharmony_ci        /// </summary>
165275793eaSopenharmony_ci        /// <param name="data">The byte array that contains the data to copy</param>
166275793eaSopenharmony_ci        /// <param name="startIndex">The index of the first byte to copy</param>
167275793eaSopenharmony_ci        /// <param name="count">The number of bytes to copy from <c>data</c></param>
168275793eaSopenharmony_ci        protected void copyInput(byte[] data, int startIndex, int count)
169275793eaSopenharmony_ci        {
170275793eaSopenharmony_ci            Array.Copy(data, startIndex, _inBuffer,0, count);
171275793eaSopenharmony_ci            _ztream.next_in = _hInput.AddrOfPinnedObject();
172275793eaSopenharmony_ci            _ztream.total_in = 0;
173275793eaSopenharmony_ci            _ztream.avail_in = (uint)count;
174275793eaSopenharmony_ci
175275793eaSopenharmony_ci        }
176275793eaSopenharmony_ci
177275793eaSopenharmony_ci        /// <summary>
178275793eaSopenharmony_ci        /// Resets the internal output buffers to a known state - ready for processing
179275793eaSopenharmony_ci        /// </summary>
180275793eaSopenharmony_ci        protected void resetOutput()
181275793eaSopenharmony_ci        {
182275793eaSopenharmony_ci            _ztream.total_out = 0;
183275793eaSopenharmony_ci            _ztream.avail_out = kBufferSize;
184275793eaSopenharmony_ci            _ztream.next_out = _hOutput.AddrOfPinnedObject();
185275793eaSopenharmony_ci        }
186275793eaSopenharmony_ci
187275793eaSopenharmony_ci        /// <summary>
188275793eaSopenharmony_ci        /// Updates the running checksum property
189275793eaSopenharmony_ci        /// </summary>
190275793eaSopenharmony_ci        /// <param name="newSum">The new checksum value</param>
191275793eaSopenharmony_ci        protected void setChecksum(uint newSum)
192275793eaSopenharmony_ci        {
193275793eaSopenharmony_ci            _checksum = newSum;
194275793eaSopenharmony_ci        }
195275793eaSopenharmony_ci        #endregion
196275793eaSopenharmony_ci
197275793eaSopenharmony_ci    }
198275793eaSopenharmony_ci}
199