Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/stream support #14

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 45 additions & 2 deletions Crc32.NET.Tests/ImplementationTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.IO;
using System.Linq;
using System.Text;

Expand Down Expand Up @@ -30,7 +31,7 @@ public void ResultConsistency(string text, int offset)
Assert.That(crc2, Is.EqualTo(crc1));
}
#endif

[Test]
public void ResultConsistency2()
{
Expand All @@ -52,7 +53,7 @@ public void ResultConsistencyAsHashAlgorithm()
Console.WriteLine(crc2.ToString("X8"));
Assert.That(crc1, Is.EqualTo(crc2));
}
#endif
#endif

[Test]
public void PartIsWhole()
Expand Down Expand Up @@ -119,5 +120,47 @@ public void Computation_With_Crc_End_Should_Be_Validated(int length)
Assert.That(Crc32Algorithm.IsValidWithCrcAtEnd(buf, 1, length - 2 + 4), Is.False);
}
}

[Test]
public void Compute_With_Stream_Should_Be_Consistent()
{
var buf = new byte[5000];
var r = new Random();
r.NextBytes(buf);

using (var ms = new MemoryStream(buf))
{
Assert.AreEqual(Crc32Algorithm.Compute(buf), Crc32Algorithm.Compute(ms));
}
}

[Test]
public void Compute_And_Write_To_End_With_Stream_Should_Be_Consistent()
{
var buf = new byte[5000];
var r = new Random();
r.NextBytes(buf);

var copyA = new byte[buf.Length + 4];
Array.Copy(buf, copyA, buf.Length);

Crc32Algorithm.ComputeAndWriteToEnd(copyA);

using (var ms = new MemoryStream())
{
ms.Write(buf, 0, buf.Length);
ms.Seek(0, SeekOrigin.Begin);

Crc32Algorithm.ComputeAndWriteToEnd(ms, buf.Length);

ms.Seek(-4, SeekOrigin.End);

for (int i = 0; i < 4; ++i)
{
var index = i + buf.Length;
Assert.AreEqual(copyA[index], ms.ReadByte());
}
}
}
}
}
83 changes: 79 additions & 4 deletions Crc32.NET/Crc32Algorithm.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.IO;
using System.Security.Cryptography;

namespace Force.Crc32
Expand Down Expand Up @@ -107,10 +108,84 @@ public static uint ComputeAndWriteToEnd(byte[] input, int offset, int length)
throw new ArgumentOutOfRangeException("length", "Length of data should be less than array length - 4 bytes of CRC data");
var crc = Append(0, input, offset, length);
var r = offset + length;
input[r] = (byte)crc;
input[r + 1] = (byte)(crc >> 8);
input[r + 2] = (byte)(crc >> 16);
input[r + 3] = (byte)(crc >> 24);
SetCrcBytes(input, r, crc);
return crc;
}

private static void SetCrcBytes(byte[] input, int offset, uint crc)
{
input[offset] = (byte) crc;
input[offset + 1] = (byte) (crc >> 8);
input[offset + 2] = (byte) (crc >> 16);
input[offset + 3] = (byte) (crc >> 24);
}

/// <summary>
/// Computes CRC-32 from input stream.
/// </summary>
/// <param name="input">Input stream with data to be checksummed.</param>
/// <param name="length">Length of the input data in the stream.</param>
/// <returns>CRC-32 of the data in the stream.</returns>
public static uint Compute(Stream input, long length)
{
if (!input.CanRead)
{
throw new ArgumentException("input", "Input stream must be readable");
}

const int bufferLength = 4096;
var buffer = new byte[bufferLength];
uint crc = 0;
var totalRemaining = length;

while (true)
{
var lengthToRead = (int) Math.Min(totalRemaining, bufferLength);

var bytesRead = input.Read(buffer, 0, lengthToRead);
if (bytesRead == 0)
{
break;
}

crc = Append(crc, buffer, 0, bytesRead);
totalRemaining -= bytesRead;
}

return crc;
}

/// <summary>
/// Computes CRC-32 from entire input stream.
/// </summary>
/// <param name="input">Input stream with data to be checksummed.</param>
/// <returns>CRC-32 of the data in the stream.</returns>
public static uint Compute(Stream input)
{
return Compute(input, long.MaxValue);
}

/// <summary>
/// Computes CRC-32 from input stream and writes it at the end.
/// </summary>
/// <param name="input">Input stream with data to be checksummed.</param>
/// <param name="length">Length of the input data in the stream.</param>
/// <returns>CRC-32 of the data in the stream.</returns>
public static uint ComputeAndWriteToEnd(Stream input, long length)
{
if (!input.CanWrite)
{
throw new ArgumentException("input", "Input stream must be writable");
}

var crc = Compute(input, length);

var writeBuffer = new byte[4];

SetCrcBytes(writeBuffer, 0, crc);

input.Write(writeBuffer, 0, writeBuffer.Length);

return crc;
}

Expand Down