#region Copyright 2013-2014 by Roger Knapp, Licensed under the Apache License, Version 2.0
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
namespace CSharpTest.Net.IO
{
/// Provides a simple CRC64 checksum for a set of bytes using algorithm (CRC-64/XZ)
[System.Diagnostics.DebuggerDisplay("{Value:X8}")]
public struct Crc64 : IEquatable, IEquatable
{
static readonly ulong[] Table;
static Crc64()
{
Table = new ulong[256];
for (uint i = 0; i < 256; i++)
{
ulong crc = i;
for (uint j = 0; j < 8; j++)
crc = (crc >> 1) ^ (((crc & 1) == 1) ? 0xC96C5795D7870F42 : 0);
//Note: table ordinal and value inverted to omit -1 start and end operation
Table[~i & 0x0ff] = ~crc;
}
}
ulong _crc64;
/// Resumes the computation of a CRC64 value
public Crc64(long crc)
{ _crc64 = unchecked((ulong)crc); }
/// Initailizes the Crc64 value to the checksum of the string as a series of 16-bit values
public Crc64(string text)
{ _crc64 = 0; Add(text); }
/// Initailizes the Crc64 value to the checksum of the bytes provided
public Crc64(byte[] bytes)
{ _crc64 = 0; Add(bytes, 0, bytes.Length); }
/// Returns the computed CRC64 value as a Hex string
public override string ToString() { return String.Format("{0:X16}", Value); }
/// Returns the computed CRC64 value
public long Value { get { return unchecked((long)_crc64); } }
/// Adds a byte to the checksum
public void Add(byte b)
{
_crc64 = (((~_crc64 >> 8) & 0x00FFFFFFFFFFFFFF) ^ Table[(_crc64 ^ b) & 0x0ff]);
}
/// Adds a byte to the checksum
public static Crc64 operator +(Crc64 chksum, byte b)
{
chksum.Add(b);
return chksum;
}
/// Adds an entire array of bytes to the checksum
public void Add(byte[] bytes)
{ Add(bytes, 0, Check.NotNull(bytes).Length); }
/// Adds a range from an array of bytes to the checksum
public void Add(byte[] bytes, int start, int length)
{
Check.NotNull(bytes);
int end = start + length;
unchecked
{
for (int i = start; i < end; i++)
_crc64 = (((~_crc64 >> 8) & 0x00FFFFFFFFFFFFFF) ^ Table[(_crc64 ^ bytes[i]) & 0x0ff]);
}
}
/// Adds an entire array of bytes to the checksum
public static Crc64 operator +(Crc64 chksum, byte[] bytes)
{
chksum.Add(bytes, 0, bytes.Length);
return chksum;
}
/// Adds a string to the checksum as a series of 16-bit values (big endian)
public void Add(string text)
{
unchecked
{
foreach (char ch in Check.NotNull(text))
{
_crc64 = (((~_crc64 >> 8) & 0x00FFFFFFFFFFFFFF) ^ Table[((int) _crc64 ^ ((byte) ch >> 8)) & 0x0ff]);
_crc64 = (((~_crc64 >> 8) & 0x00FFFFFFFFFFFFFF) ^ Table[(_crc64 ^ ((byte) ch)) & 0x0ff]);
}
}
}
/// Adds a string to the checksum as a series of 16-bit values
public static Crc64 operator +(Crc64 chksum, string text)
{
chksum.Add(text);
return chksum;
}
/// Extracts the correct hash code
public override int GetHashCode() { return (int)(Value ^ (Value >> 32)); }
/// Returns true if the other object is equal to this one
public override bool Equals(object obj)
{
return
(obj is Crc64 && _crc64 == ((Crc64)obj)._crc64) ||
(obj is long && Value == ((long)obj));
}
/// Returns true if the other object is equal to this one
public bool Equals(Crc64 other) { return _crc64 == other._crc64; }
/// Returns true if the CRC64 provided is equal to this one
public bool Equals(long crc64) { return Value == crc64; }
/// Compares the two objects for equality
public static bool operator ==(Crc64 x, Crc64 y) { return x._crc64 == y._crc64; }
/// Compares the two objects for equality
public static bool operator !=(Crc64 x, Crc64 y) { return x._crc64 != y._crc64; }
/// Compares the two objects for equality
public static bool operator ==(Crc64 x, long y) { return x.Value == y; }
/// Compares the two objects for equality
public static bool operator !=(Crc64 x, long y) { return x.Value != y; }
}
}