blob: 63d641ae91ef7b39424d27d62c6c4df9a0ec5870 [file] [log] [blame]
/*
* 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.
*/
namespace DotPulsar.Internal
{
using System.Buffers;
public static class Crc32C
{
private const uint _generator = 0x82F63B78u;
private static readonly uint[] _lookup;
static Crc32C()
{
_lookup = new uint[16 * 256];
for (uint i = 0; i < 256; i++)
{
var entry = i;
for (var j = 0; j < 16; j++)
{
for (var k = 0; k < 8; k++)
entry = (entry & 1) == 1 ? _generator ^ (entry >> 1) : entry >> 1;
_lookup[j * 256 + i] = entry;
}
}
}
public static uint Calculate(ReadOnlySequence<byte> sequence)
{
var block = new uint[16];
var checksum = uint.MaxValue;
var remaningBytes = sequence.Length;
var readingBlock = remaningBytes >= 16;
var offset = 15;
foreach (var memory in sequence)
{
var span = memory.Span;
for (var i = 0; i < span.Length; ++i)
{
var currentByte = span[i];
if (!readingBlock)
{
checksum = _lookup[(byte) (checksum ^ currentByte)] ^ (checksum >> 8);
continue;
}
var offSetBase = offset * 256;
if (offset > 11)
block[offset] = _lookup[offSetBase + ((byte) (checksum >> (8 * (15 - offset))) ^ currentByte)];
else
block[offset] = _lookup[offSetBase + currentByte];
--remaningBytes;
if (offset == 0)
{
offset = 15;
readingBlock = remaningBytes >= 16;
checksum = 0;
for (var j = 0; j < block.Length; ++j)
checksum ^= block[j];
}
else
{
--offset;
}
}
}
return checksum ^ uint.MaxValue;
}
}
}