CodecBase.cs revision 9e38dfa2f95fce609707a0941f10af9a785288de
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt//
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// � Copyright Henrik Ravn 2004
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt//
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt//
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtusing System;
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtusing System.Runtime.InteropServices;
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnamespace DotZLib
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/// <summary>
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/// Implements the common functionality needed for all <see cref="Codec"/>s
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/// </summary>
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	public abstract class CodecBase : Codec, IDisposable
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        #region Data members
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <summary>
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// Instance of the internal zlib buffer structure that is
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// passed to all functions in the zlib dll
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// </summary>
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        internal ZStream _ztream = new ZStream();
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <summary>
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// True if the object instance has been disposed, false otherwise
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// </summary>
301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt        protected bool _isDisposed = false;
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <summary>
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// The size of the internal buffers
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// </summary>
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        protected const int kBufferSize = 16384;
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        private byte[] _outBuffer = new byte[kBufferSize];
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        private byte[] _inBuffer = new byte[kBufferSize];
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        private GCHandle _hInput;
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        private GCHandle _hOutput;
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        private uint _checksum = 0;
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        #endregion
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <summary>
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// Initializes a new instance of the <c>CodeBase</c> class.
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// </summary>
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		public CodecBase()
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		{
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            try
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            {
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                _hInput = GCHandle.Alloc(_inBuffer, GCHandleType.Pinned);
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                _hOutput = GCHandle.Alloc(_outBuffer, GCHandleType.Pinned);
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            }
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            catch (Exception)
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            {
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                CleanUp(false);
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                throw;
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            }
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        #region Codec Members
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <summary>
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// Occurs when more processed data are available.
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// </summary>
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public event DataAvailableHandler DataAvailable;
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <summary>
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// Fires the <see cref="DataAvailable"/> event
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// </summary>
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        protected void OnDataAvailable()
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        {
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (_ztream.total_out > 0)
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            {
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                if (DataAvailable != null)
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                    DataAvailable( _outBuffer, 0, (int)_ztream.total_out);
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                resetOutput();
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            }
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <summary>
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// Adds more data to the codec to be processed.
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// </summary>
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <param name="data">Byte array containing the data to be added to the codec</param>
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public void Add(byte[] data)
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        {
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            Add(data,0,data.Length);
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <summary>
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// Adds more data to the codec to be processed.
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// </summary>
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <param name="data">Byte array containing the data to be added to the codec</param>
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <param name="offset">The index of the first byte to add from <c>data</c></param>
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <param name="count">The number of bytes to add</param>
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <remarks>This must be implemented by a derived class</remarks>
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public abstract void Add(byte[] data, int offset, int count);
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <summary>
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// Finishes up any pending data that needs to be processed and handled.
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// </summary>
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <remarks>This must be implemented by a derived class</remarks>
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public abstract void Finish();
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <summary>
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// Gets the checksum of the data that has been added so far
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// </summary>
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public uint Checksum { get { return _checksum; } }
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        #endregion
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        #region Destructor & IDisposable stuff
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <summary>
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// Destroys this instance
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// </summary>
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        ~CodecBase()
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        {
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            CleanUp(false);
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <summary>
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// Releases any unmanaged resources and calls the <see cref="CleanUp()"/> method of the derived class
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// </summary>
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        public void Dispose()
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        {
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            CleanUp(true);
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <summary>
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// Performs any codec specific cleanup
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// </summary>
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <remarks>This must be implemented by a derived class</remarks>
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        protected abstract void CleanUp();
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        // performs the release of the handles and calls the dereived CleanUp()
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        private void CleanUp(bool isDisposing)
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        {
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            if (!_isDisposed)
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            {
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                CleanUp();
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                if (_hInput.IsAllocated)
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                    _hInput.Free();
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                if (_hOutput.IsAllocated)
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                    _hOutput.Free();
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                _isDisposed = true;
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            }
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        #endregion
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        #region Helper methods
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <summary>
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// Copies a number of bytes to the internal codec buffer - ready for proccesing
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// </summary>
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <param name="data">The byte array that contains the data to copy</param>
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <param name="startIndex">The index of the first byte to copy</param>
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <param name="count">The number of bytes to copy from <c>data</c></param>
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        protected void copyInput(byte[] data, int startIndex, int count)
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        {
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            Array.Copy(data, startIndex, _inBuffer,0, count);
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            _ztream.next_in = _hInput.AddrOfPinnedObject();
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            _ztream.total_in = 0;
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            _ztream.avail_in = (uint)count;
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <summary>
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// Resets the internal output buffers to a known state - ready for processing
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// </summary>
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        protected void resetOutput()
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        {
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            _ztream.total_out = 0;
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            _ztream.avail_out = kBufferSize;
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            _ztream.next_out = _hOutput.AddrOfPinnedObject();
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <summary>
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// Updates the running checksum property
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// </summary>
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        /// <param name="newSum">The new checksum value</param>
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        protected void setChecksum(uint newSum)
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        {
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            _checksum = newSum;
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        #endregion
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt