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