diff --git a/Crc32.NET.Tests/ImplementationTest.cs b/Crc32.NET.Tests/ImplementationTest.cs
index 7bfe6da..d543d90 100644
--- a/Crc32.NET.Tests/ImplementationTest.cs
+++ b/Crc32.NET.Tests/ImplementationTest.cs
@@ -1,4 +1,5 @@
using System;
+using System.IO;
using System.Linq;
using System.Text;
@@ -30,7 +31,7 @@ public void ResultConsistency(string text, int offset)
Assert.That(crc2, Is.EqualTo(crc1));
}
#endif
-
+
[Test]
public void ResultConsistency2()
{
@@ -52,7 +53,7 @@ public void ResultConsistencyAsHashAlgorithm()
Console.WriteLine(crc2.ToString("X8"));
Assert.That(crc1, Is.EqualTo(crc2));
}
-#endif
+#endif
[Test]
public void PartIsWhole()
@@ -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());
+ }
+ }
+ }
}
}
diff --git a/Crc32.NET/Crc32Algorithm.cs b/Crc32.NET/Crc32Algorithm.cs
index ccacd03..c911202 100644
--- a/Crc32.NET/Crc32Algorithm.cs
+++ b/Crc32.NET/Crc32Algorithm.cs
@@ -1,4 +1,5 @@
using System;
+using System.IO;
using System.Security.Cryptography;
namespace Force.Crc32
@@ -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);
+ }
+
+ ///
+ /// Computes CRC-32 from input stream.
+ ///
+ /// Input stream with data to be checksummed.
+ /// Length of the input data in the stream.
+ /// CRC-32 of the data in the stream.
+ 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;
+ }
+
+ ///
+ /// Computes CRC-32 from entire input stream.
+ ///
+ /// Input stream with data to be checksummed.
+ /// CRC-32 of the data in the stream.
+ public static uint Compute(Stream input)
+ {
+ return Compute(input, long.MaxValue);
+ }
+
+ ///
+ /// Computes CRC-32 from input stream and writes it at the end.
+ ///
+ /// Input stream with data to be checksummed.
+ /// Length of the input data in the stream.
+ /// CRC-32 of the data in the stream.
+ 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;
}