1*9573673dSchristos // 2*9573673dSchristos // � Copyright Henrik Ravn 2004 3*9573673dSchristos // 4*9573673dSchristos // Use, modification and distribution are subject to the Boost Software License, Version 1.0. 5*9573673dSchristos // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6*9573673dSchristos // 7*9573673dSchristos 8*9573673dSchristos using System; 9*9573673dSchristos using System.Runtime.InteropServices; 10*9573673dSchristos using System.Text; 11*9573673dSchristos 12*9573673dSchristos 13*9573673dSchristos namespace DotZLib 14*9573673dSchristos { 15*9573673dSchristos #region ChecksumGeneratorBase 16*9573673dSchristos /// <summary> 17*9573673dSchristos /// Implements the common functionality needed for all <see cref="ChecksumGenerator"/>s 18*9573673dSchristos /// </summary> 19*9573673dSchristos /// <example></example> 20*9573673dSchristos public abstract class ChecksumGeneratorBase : ChecksumGenerator 21*9573673dSchristos { 22*9573673dSchristos /// <summary> 23*9573673dSchristos /// The value of the current checksum 24*9573673dSchristos /// </summary> 25*9573673dSchristos protected uint _current; 26*9573673dSchristos 27*9573673dSchristos /// <summary> 28*9573673dSchristos /// Initializes a new instance of the checksum generator base - the current checksum is 29*9573673dSchristos /// set to zero 30*9573673dSchristos /// </summary> ChecksumGeneratorBase()31*9573673dSchristos public ChecksumGeneratorBase() 32*9573673dSchristos { 33*9573673dSchristos _current = 0; 34*9573673dSchristos } 35*9573673dSchristos 36*9573673dSchristos /// <summary> 37*9573673dSchristos /// Initializes a new instance of the checksum generator basewith a specified value 38*9573673dSchristos /// </summary> 39*9573673dSchristos /// <param name="initialValue">The value to set the current checksum to</param> ChecksumGeneratorBase(uint initialValue)40*9573673dSchristos public ChecksumGeneratorBase(uint initialValue) 41*9573673dSchristos { 42*9573673dSchristos _current = initialValue; 43*9573673dSchristos } 44*9573673dSchristos 45*9573673dSchristos /// <summary> 46*9573673dSchristos /// Resets the current checksum to zero 47*9573673dSchristos /// </summary> Reset()48*9573673dSchristos public void Reset() { _current = 0; } 49*9573673dSchristos 50*9573673dSchristos /// <summary> 51*9573673dSchristos /// Gets the current checksum value 52*9573673dSchristos /// </summary> 53*9573673dSchristos public uint Value { get { return _current; } } 54*9573673dSchristos 55*9573673dSchristos /// <summary> 56*9573673dSchristos /// Updates the current checksum with part of an array of bytes 57*9573673dSchristos /// </summary> 58*9573673dSchristos /// <param name="data">The data to update the checksum with</param> 59*9573673dSchristos /// <param name="offset">Where in <c>data</c> to start updating</param> 60*9573673dSchristos /// <param name="count">The number of bytes from <c>data</c> to use</param> 61*9573673dSchristos /// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception> 62*9573673dSchristos /// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception> 63*9573673dSchristos /// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception> 64*9573673dSchristos /// <remarks>All the other <c>Update</c> methods are implmeneted in terms of this one. 65*9573673dSchristos /// This is therefore the only method a derived class has to implement</remarks> Update(byte[] data, int offset, int count)66*9573673dSchristos public abstract void Update(byte[] data, int offset, int count); 67*9573673dSchristos 68*9573673dSchristos /// <summary> 69*9573673dSchristos /// Updates the current checksum with an array of bytes. 70*9573673dSchristos /// </summary> 71*9573673dSchristos /// <param name="data">The data to update the checksum with</param> Update(byte[] data)72*9573673dSchristos public void Update(byte[] data) 73*9573673dSchristos { 74*9573673dSchristos Update(data, 0, data.Length); 75*9573673dSchristos } 76*9573673dSchristos 77*9573673dSchristos /// <summary> 78*9573673dSchristos /// Updates the current checksum with the data from a string 79*9573673dSchristos /// </summary> 80*9573673dSchristos /// <param name="data">The string to update the checksum with</param> 81*9573673dSchristos /// <remarks>The characters in the string are converted by the UTF-8 encoding</remarks> Update(string data)82*9573673dSchristos public void Update(string data) 83*9573673dSchristos { 84*9573673dSchristos Update(Encoding.UTF8.GetBytes(data)); 85*9573673dSchristos } 86*9573673dSchristos 87*9573673dSchristos /// <summary> 88*9573673dSchristos /// Updates the current checksum with the data from a string, using a specific encoding 89*9573673dSchristos /// </summary> 90*9573673dSchristos /// <param name="data">The string to update the checksum with</param> 91*9573673dSchristos /// <param name="encoding">The encoding to use</param> Update(string data, Encoding encoding)92*9573673dSchristos public void Update(string data, Encoding encoding) 93*9573673dSchristos { 94*9573673dSchristos Update(encoding.GetBytes(data)); 95*9573673dSchristos } 96*9573673dSchristos 97*9573673dSchristos } 98*9573673dSchristos #endregion 99*9573673dSchristos 100*9573673dSchristos #region CRC32 101*9573673dSchristos /// <summary> 102*9573673dSchristos /// Implements a CRC32 checksum generator 103*9573673dSchristos /// </summary> 104*9573673dSchristos public sealed class CRC32Checksum : ChecksumGeneratorBase 105*9573673dSchristos { 106*9573673dSchristos #region DLL imports 107*9573673dSchristos 108*9573673dSchristos [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] crc32(uint crc, int data, uint length)109*9573673dSchristos private static extern uint crc32(uint crc, int data, uint length); 110*9573673dSchristos 111*9573673dSchristos #endregion 112*9573673dSchristos 113*9573673dSchristos /// <summary> 114*9573673dSchristos /// Initializes a new instance of the CRC32 checksum generator 115*9573673dSchristos /// </summary> CRC32Checksum()116*9573673dSchristos public CRC32Checksum() : base() {} 117*9573673dSchristos 118*9573673dSchristos /// <summary> 119*9573673dSchristos /// Initializes a new instance of the CRC32 checksum generator with a specified value 120*9573673dSchristos /// </summary> 121*9573673dSchristos /// <param name="initialValue">The value to set the current checksum to</param> CRC32Checksum(uint initialValue)122*9573673dSchristos public CRC32Checksum(uint initialValue) : base(initialValue) {} 123*9573673dSchristos 124*9573673dSchristos /// <summary> 125*9573673dSchristos /// Updates the current checksum with part of an array of bytes 126*9573673dSchristos /// </summary> 127*9573673dSchristos /// <param name="data">The data to update the checksum with</param> 128*9573673dSchristos /// <param name="offset">Where in <c>data</c> to start updating</param> 129*9573673dSchristos /// <param name="count">The number of bytes from <c>data</c> to use</param> 130*9573673dSchristos /// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception> 131*9573673dSchristos /// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception> 132*9573673dSchristos /// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception> Update(byte[] data, int offset, int count)133*9573673dSchristos public override void Update(byte[] data, int offset, int count) 134*9573673dSchristos { 135*9573673dSchristos if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); 136*9573673dSchristos if ((offset+count) > data.Length) throw new ArgumentException(); 137*9573673dSchristos GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned); 138*9573673dSchristos try 139*9573673dSchristos { 140*9573673dSchristos _current = crc32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count); 141*9573673dSchristos } 142*9573673dSchristos finally 143*9573673dSchristos { 144*9573673dSchristos hData.Free(); 145*9573673dSchristos } 146*9573673dSchristos } 147*9573673dSchristos 148*9573673dSchristos } 149*9573673dSchristos #endregion 150*9573673dSchristos 151*9573673dSchristos #region Adler 152*9573673dSchristos /// <summary> 153*9573673dSchristos /// Implements a checksum generator that computes the Adler checksum on data 154*9573673dSchristos /// </summary> 155*9573673dSchristos public sealed class AdlerChecksum : ChecksumGeneratorBase 156*9573673dSchristos { 157*9573673dSchristos #region DLL imports 158*9573673dSchristos 159*9573673dSchristos [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] adler32(uint adler, int data, uint length)160*9573673dSchristos private static extern uint adler32(uint adler, int data, uint length); 161*9573673dSchristos 162*9573673dSchristos #endregion 163*9573673dSchristos 164*9573673dSchristos /// <summary> 165*9573673dSchristos /// Initializes a new instance of the Adler checksum generator 166*9573673dSchristos /// </summary> AdlerChecksum()167*9573673dSchristos public AdlerChecksum() : base() {} 168*9573673dSchristos 169*9573673dSchristos /// <summary> 170*9573673dSchristos /// Initializes a new instance of the Adler checksum generator with a specified value 171*9573673dSchristos /// </summary> 172*9573673dSchristos /// <param name="initialValue">The value to set the current checksum to</param> AdlerChecksum(uint initialValue)173*9573673dSchristos public AdlerChecksum(uint initialValue) : base(initialValue) {} 174*9573673dSchristos 175*9573673dSchristos /// <summary> 176*9573673dSchristos /// Updates the current checksum with part of an array of bytes 177*9573673dSchristos /// </summary> 178*9573673dSchristos /// <param name="data">The data to update the checksum with</param> 179*9573673dSchristos /// <param name="offset">Where in <c>data</c> to start updating</param> 180*9573673dSchristos /// <param name="count">The number of bytes from <c>data</c> to use</param> 181*9573673dSchristos /// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception> 182*9573673dSchristos /// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception> 183*9573673dSchristos /// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception> Update(byte[] data, int offset, int count)184*9573673dSchristos public override void Update(byte[] data, int offset, int count) 185*9573673dSchristos { 186*9573673dSchristos if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); 187*9573673dSchristos if ((offset+count) > data.Length) throw new ArgumentException(); 188*9573673dSchristos GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned); 189*9573673dSchristos try 190*9573673dSchristos { 191*9573673dSchristos _current = adler32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count); 192*9573673dSchristos } 193*9573673dSchristos finally 194*9573673dSchristos { 195*9573673dSchristos hData.Free(); 196*9573673dSchristos } 197*9573673dSchristos } 198*9573673dSchristos 199*9573673dSchristos } 200*9573673dSchristos #endregion 201*9573673dSchristos 202*9573673dSchristos }