Skip to content

Commit 76f6708

Browse files
committed
add input stream
1 parent bda9081 commit 76f6708

File tree

5 files changed

+163
-0
lines changed

5 files changed

+163
-0
lines changed

MurmurHash.Specs/HashVerifier.cs

+36
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,41 @@ public static uint ComputeVerificationHashOutputStream(int bits, Func<Stream, ui
5252
return BitConverter.ToUInt32(algorithm.Hash, 0);
5353
}
5454
}
55+
56+
public static uint ComputeVerificationHashInputStream(int bits, Func<Stream, uint, MurmurInputStream> streamFactory)
57+
{
58+
int bytes = bits / 8;
59+
60+
byte[] key = new byte[256];
61+
byte[] hashes = new byte[bytes * 256];
62+
63+
for (int i = 0; i < 256; i++)
64+
{
65+
key[i] = (byte)i;
66+
using (var memory = new MemoryStream())
67+
using (var source = streamFactory(memory, (uint)(256 - i)))
68+
{
69+
memory.Write(key, 0, i);
70+
memory.Position = 0L;
71+
72+
var buffer = new byte[i];
73+
source.Read(buffer, 0, i);
74+
75+
Array.Copy(source.Hash, 0, hashes, i * bytes, bytes);
76+
}
77+
}
78+
79+
using (var memory = new MemoryStream())
80+
using (var source = streamFactory(memory, 0))
81+
{
82+
memory.Write(hashes, 0, hashes.Length);
83+
memory.Position = 0L;
84+
85+
var buffer = new byte[hashes.Length];
86+
source.Read(hashes, 0, hashes.Length);
87+
88+
return BitConverter.ToUInt32(source.Hash, 0);
89+
}
90+
}
5591
}
5692
}

MurmurHash.Specs/Murmur128Specs.cs

+40
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ class given_a_managed_x64_algorithm_output_stream
2727
It should_have_computed_correct_hash = () => VerificationHash.ShouldEqual(Expectation.Result);
2828
}
2929

30+
[Subject("Murmur128")]
31+
class given_a_managed_x64_algorithm_input_stream
32+
{
33+
protected static readonly HashExpection Expectation = new HashExpection(128, 0x6384BA69);
34+
protected static uint VerificationHash;
35+
Establish context = () => VerificationHash = 0;
36+
Because of = () => VerificationHash = HashVerifier.ComputeVerificationHashInputStream(Expectation.Bits, (stream, seed) => new MurmurInputStream(stream, seed, true, AlgorithmType.Murmur128, AlgorithmPreference.X64));
37+
It should_have_computed_correct_hash = () => VerificationHash.ShouldEqual(Expectation.Result);
38+
}
39+
3040
[Subject("Murmur128")]
3141
class given_an_unmanaged_x64_algorithm
3242
{
@@ -47,6 +57,16 @@ class given_an_unmanaged_x64_algorithm_output_stream
4757
It should_have_computed_correct_hash = () => VerificationHash.ShouldEqual(Expectation.Result);
4858
}
4959

60+
[Subject("Murmur128")]
61+
class given_an_unmanaged_x64_algorithm_input_stream
62+
{
63+
protected static readonly HashExpection Expectation = new HashExpection(128, 0x6384BA69);
64+
protected static uint VerificationHash;
65+
Establish context = () => VerificationHash = 0;
66+
Because of = () => VerificationHash = HashVerifier.ComputeVerificationHashInputStream(Expectation.Bits, (stream, seed) => new MurmurInputStream(stream, seed, false, AlgorithmType.Murmur128, AlgorithmPreference.X64));
67+
It should_have_computed_correct_hash = () => VerificationHash.ShouldEqual(Expectation.Result);
68+
}
69+
5070
[Subject("Murmur128")]
5171
class given_a_managed_x86_algorithm
5272
{
@@ -67,6 +87,16 @@ class given_a_managed_x86_algorithm_output_stream
6787
It should_have_computed_correct_hash = () => VerificationHash.ShouldEqual(Expectation.Result);
6888
}
6989

90+
[Subject("Murmur128")]
91+
class given_a_managed_x86_algorithm_input_stream
92+
{
93+
protected static readonly HashExpection Expectation = new HashExpection(128, 0xB3ECE62A);
94+
protected static uint VerificationHash;
95+
Establish context = () => VerificationHash = 0;
96+
Because of = () => VerificationHash = HashVerifier.ComputeVerificationHashInputStream(Expectation.Bits, (stream, seed) => new MurmurInputStream(stream, seed, true, AlgorithmType.Murmur128, AlgorithmPreference.X86));
97+
It should_have_computed_correct_hash = () => VerificationHash.ShouldEqual(Expectation.Result);
98+
}
99+
70100
[Subject("Murmur128")]
71101
class given_an_unmanaged_x86_algorithm
72102
{
@@ -87,6 +117,16 @@ class given_an_unmanaged_x86_algorithm_output_stream
87117
It should_have_computed_correct_hash = () => VerificationHash.ShouldEqual(Expectation.Result);
88118
}
89119

120+
[Subject("Murmur128")]
121+
class given_an_unmanaged_x86_algorithm_input_stream
122+
{
123+
protected static readonly HashExpection Expectation = new HashExpection(128, 0xB3ECE62A);
124+
protected static uint VerificationHash;
125+
Establish context = () => VerificationHash = 0;
126+
Because of = () => VerificationHash = HashVerifier.ComputeVerificationHashInputStream(Expectation.Bits, (stream, seed) => new MurmurInputStream(stream, seed, false, AlgorithmType.Murmur128, AlgorithmPreference.X86));
127+
It should_have_computed_correct_hash = () => VerificationHash.ShouldEqual(Expectation.Result);
128+
}
129+
90130
[Subject("Murmur128")]
91131
class given_a_managed_and_unmanaged_algorithm
92132
{

MurmurHash.Specs/Murmur32Specs.cs

+22
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ class given_a_managed_algorithm_output_stream
2828
It should_have_created_a_valid_hash = () => VerificationHash.ShouldEqual(Expectation.Result);
2929
}
3030

31+
[Subject("Murmur32")]
32+
class given_a_managed_algorithm_input_stream
33+
{
34+
protected static readonly HashExpection Expectation = new HashExpection(32, 0xB0F57EE3);
35+
protected static uint VerificationHash;
36+
37+
Establish context = () => VerificationHash = 0;
38+
Because of = () => VerificationHash = HashVerifier.ComputeVerificationHashInputStream(Expectation.Bits, (stream, seed) => new MurmurInputStream(stream, seed, true, AlgorithmType.Murmur32));
39+
It should_have_created_a_valid_hash = () => VerificationHash.ShouldEqual(Expectation.Result);
40+
}
41+
3142
[Subject("Murmur32")]
3243
class given_an_unmanaged_algorithm
3344
{
@@ -50,6 +61,17 @@ class given_an_unmanaged_algorithm_output_stream
5061
It should_have_created_a_valid_hash = () => VerificationHash.ShouldEqual(Expectation.Result);
5162
}
5263

64+
[Subject("Murmur32")]
65+
class given_an_unmanaged_algorithm_input_stream
66+
{
67+
protected static readonly HashExpection Expectation = new HashExpection(32, 0xB0F57EE3);
68+
protected static uint VerificationHash;
69+
70+
Establish context = () => VerificationHash = 0;
71+
Because of = () => VerificationHash = HashVerifier.ComputeVerificationHashInputStream(Expectation.Bits, (stream, seed) => new MurmurInputStream(stream, seed, false, AlgorithmType.Murmur32));
72+
It should_have_created_a_valid_hash = () => VerificationHash.ShouldEqual(Expectation.Result);
73+
}
74+
5375
[Subject("Murmur32")]
5476
class given_a_managed_and_unmanaged_algorithm
5577
{

MurmurHash/MurmurHash.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
<Compile Include="Murmur128.cs" />
5151
<Compile Include="Murmur32.cs" />
5252
<Compile Include="MurmurHash.cs" />
53+
<Compile Include="MurmurInputStream.cs" />
5354
<Compile Include="MurmurOutputStream.cs" />
5455
<Compile Include="Properties\AssemblyInfo.cs" />
5556
<Compile Include="Managed\Murmur128ManagedX86.cs" />

MurmurHash/MurmurInputStream.cs

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System;
2+
using System.IO;
3+
using System.Security.Cryptography;
4+
5+
namespace Murmur
6+
{
7+
public class MurmurInputStream : Stream
8+
{
9+
static readonly byte[] DEFAULT_FINAL_TRANFORM = new byte[0];
10+
11+
readonly Stream UnderlyingStream;
12+
readonly HashAlgorithm Algorithm;
13+
public MurmurInputStream(Stream underlyingStream, uint seed = 0, bool managed = true, AlgorithmType type = AlgorithmType.Murmur128, AlgorithmPreference preference = AlgorithmPreference.Auto)
14+
{
15+
UnderlyingStream = underlyingStream;
16+
Algorithm = type == AlgorithmType.Murmur32
17+
? (HashAlgorithm)MurmurHash.Create32(seed, managed)
18+
: (HashAlgorithm)MurmurHash.Create128(seed, managed, preference);
19+
}
20+
21+
public byte[] Hash { get { Algorithm.TransformFinalBlock(DEFAULT_FINAL_TRANFORM, 0, 0); return Algorithm.Hash; } }
22+
public override bool CanRead { get { return true; } }
23+
public override bool CanSeek { get { return false; } }
24+
public override bool CanWrite { get { return false; } }
25+
public override long Length { get { return UnderlyingStream.Length; } }
26+
public override long Position { get { return UnderlyingStream.Position; } set { throw new NotSupportedException(); } }
27+
28+
public override void Flush()
29+
{
30+
UnderlyingStream.Flush();
31+
}
32+
33+
public override int Read(byte[] buffer, int offset, int count)
34+
{
35+
var result = UnderlyingStream.Read(buffer, offset, count);
36+
Algorithm.TransformBlock(buffer, offset, result, null, 0);
37+
38+
return result;
39+
}
40+
41+
public override long Seek(long offset, SeekOrigin origin)
42+
{
43+
throw new NotSupportedException("This stream does not support seeking, it is forward-only.");
44+
}
45+
46+
public override void SetLength(long value)
47+
{
48+
UnderlyingStream.SetLength(value);
49+
}
50+
51+
public override void Write(byte[] buffer, int offset, int count)
52+
{
53+
throw new NotSupportedException("This stream does not support writing, it is read-only.");
54+
}
55+
56+
protected override void Dispose(bool disposing)
57+
{
58+
if (disposing)
59+
Algorithm.Dispose();
60+
61+
base.Dispose(disposing);
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)