2023-12-06 17:43:39 -05:00
|
|
|
|
//
|
|
|
|
|
// <20> Copyright Henrik Ravn 2004
|
|
|
|
|
//
|
|
|
|
|
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
|
|
|
|
|
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DotZLib
|
|
|
|
|
{
|
|
|
|
|
#region ChecksumGeneratorBase
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Implements the common functionality needed for all <see cref="ChecksumGenerator"/>s
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <example></example>
|
|
|
|
|
public abstract class ChecksumGeneratorBase : ChecksumGenerator
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The value of the current checksum
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected uint _current;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes a new instance of the checksum generator base - the current checksum is
|
|
|
|
|
/// set to zero
|
|
|
|
|
/// </summary>
|
|
|
|
|
public ChecksumGeneratorBase()
|
|
|
|
|
{
|
|
|
|
|
_current = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2024-06-17 19:04:36 -04:00
|
|
|
|
/// Initializes a new instance of the checksum generator base with a specified value
|
2023-12-06 17:43:39 -05:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="initialValue">The value to set the current checksum to</param>
|
|
|
|
|
public ChecksumGeneratorBase(uint initialValue)
|
|
|
|
|
{
|
|
|
|
|
_current = initialValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Resets the current checksum to zero
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Reset() { _current = 0; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the current checksum value
|
|
|
|
|
/// </summary>
|
|
|
|
|
public uint Value { get { return _current; } }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Updates the current checksum with part of an array of bytes
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">The data to update the checksum with</param>
|
|
|
|
|
/// <param name="offset">Where in <c>data</c> to start updating</param>
|
|
|
|
|
/// <param name="count">The number of bytes from <c>data</c> to use</param>
|
|
|
|
|
/// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception>
|
|
|
|
|
/// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception>
|
|
|
|
|
/// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception>
|
|
|
|
|
/// <remarks>All the other <c>Update</c> methods are implemented in terms of this one.
|
|
|
|
|
/// This is therefore the only method a derived class has to implement</remarks>
|
|
|
|
|
public abstract void Update(byte[] data, int offset, int count);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Updates the current checksum with an array of bytes.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">The data to update the checksum with</param>
|
|
|
|
|
public void Update(byte[] data)
|
|
|
|
|
{
|
|
|
|
|
Update(data, 0, data.Length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Updates the current checksum with the data from a string
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">The string to update the checksum with</param>
|
|
|
|
|
/// <remarks>The characters in the string are converted by the UTF-8 encoding</remarks>
|
|
|
|
|
public void Update(string data)
|
|
|
|
|
{
|
|
|
|
|
Update(Encoding.UTF8.GetBytes(data));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Updates the current checksum with the data from a string, using a specific encoding
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">The string to update the checksum with</param>
|
|
|
|
|
/// <param name="encoding">The encoding to use</param>
|
|
|
|
|
public void Update(string data, Encoding encoding)
|
|
|
|
|
{
|
|
|
|
|
Update(encoding.GetBytes(data));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region CRC32
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Implements a CRC32 checksum generator
|
|
|
|
|
/// </summary>
|
|
|
|
|
public sealed class CRC32Checksum : ChecksumGeneratorBase
|
|
|
|
|
{
|
|
|
|
|
#region DLL imports
|
|
|
|
|
|
|
|
|
|
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
|
|
|
|
|
private static extern uint crc32(uint crc, int data, uint length);
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes a new instance of the CRC32 checksum generator
|
|
|
|
|
/// </summary>
|
|
|
|
|
public CRC32Checksum() : base() {}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes a new instance of the CRC32 checksum generator with a specified value
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="initialValue">The value to set the current checksum to</param>
|
|
|
|
|
public CRC32Checksum(uint initialValue) : base(initialValue) {}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Updates the current checksum with part of an array of bytes
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">The data to update the checksum with</param>
|
|
|
|
|
/// <param name="offset">Where in <c>data</c> to start updating</param>
|
|
|
|
|
/// <param name="count">The number of bytes from <c>data</c> to use</param>
|
|
|
|
|
/// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception>
|
|
|
|
|
/// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception>
|
|
|
|
|
/// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception>
|
|
|
|
|
public override void Update(byte[] data, int offset, int count)
|
|
|
|
|
{
|
|
|
|
|
if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
|
|
|
|
|
if ((offset+count) > data.Length) throw new ArgumentException();
|
|
|
|
|
GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned);
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_current = crc32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count);
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
hData.Free();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Adler
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Implements a checksum generator that computes the Adler checksum on data
|
|
|
|
|
/// </summary>
|
|
|
|
|
public sealed class AdlerChecksum : ChecksumGeneratorBase
|
|
|
|
|
{
|
|
|
|
|
#region DLL imports
|
|
|
|
|
|
|
|
|
|
[DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
|
|
|
|
|
private static extern uint adler32(uint adler, int data, uint length);
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes a new instance of the Adler checksum generator
|
|
|
|
|
/// </summary>
|
|
|
|
|
public AdlerChecksum() : base() {}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes a new instance of the Adler checksum generator with a specified value
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="initialValue">The value to set the current checksum to</param>
|
|
|
|
|
public AdlerChecksum(uint initialValue) : base(initialValue) {}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Updates the current checksum with part of an array of bytes
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">The data to update the checksum with</param>
|
|
|
|
|
/// <param name="offset">Where in <c>data</c> to start updating</param>
|
|
|
|
|
/// <param name="count">The number of bytes from <c>data</c> to use</param>
|
|
|
|
|
/// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception>
|
|
|
|
|
/// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception>
|
|
|
|
|
/// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception>
|
|
|
|
|
public override void Update(byte[] data, int offset, int count)
|
|
|
|
|
{
|
|
|
|
|
if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
|
|
|
|
|
if ((offset+count) > data.Length) throw new ArgumentException();
|
|
|
|
|
GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned);
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_current = adler32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count);
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
hData.Free();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
}
|