Kit.Core/LibExternal/System.IO.Hashing/BinaryPrimitives.cs

86 lines
2.3 KiB
C#

using System;
namespace System.IO.Hashing
{
public static class BinaryPrimitives
{
public static void WriteUInt32LittleEndian(Span<byte> destination, uint value)
{
if (destination.Length < 4)
{
throw new ArgumentOutOfRangeException();
}
destination[3] = (byte)(value >> 24);
destination[2] = (byte)(value >> 16);
destination[1] = (byte)(value >> 8);
destination[0] = (byte)value;
}
}
public sealed partial class Crc32
{
private const uint InitialState = 0xFFFF_FFFFu;
private const int Size = sizeof(uint);
private static readonly uint[] s_crcLookup = GenerateReflectedTable(0xEDB88320u);
private static uint[] GenerateReflectedTable(uint reflectedPolynomial)
{
uint[] table = new uint[256];
for (int i = 0; i < 256; i++)
{
uint val = (uint)i;
for (int j = 0; j < 8; j++)
{
if ((val & 0b0000_0001) == 0)
{
val >>= 1;
}
else
{
val = (val >> 1) ^ reflectedPolynomial;
}
}
table[i] = val;
}
return table;
}
public static bool TryHash(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
{
if (destination.Length < Size)
{
bytesWritten = 0;
return false;
}
bytesWritten = StaticHash(source, destination);
return true;
}
private static int StaticHash(ReadOnlySpan<byte> source, Span<byte> destination)
{
uint crc = InitialState;
crc = Update(crc, source);
BinaryPrimitives.WriteUInt32LittleEndian(destination, ~crc);
return Size;
}
private static uint Update(uint crc, ReadOnlySpan<byte> source)
{
for (int i = 0; i < source.Length; i++)
{
byte idx = (byte)crc;
idx ^= source[i];
crc = s_crcLookup[idx] ^ (crc >> 8);
}
return crc;
}
}
}