1 /**
2 Adler-32 implementation. This module conforms to the APIs defined in std.digest.digest.
3 */
4 module digestx.adler;
5 
6 
7 public import std.digest.digest;
8 
9 
10 struct Adler32
11 {
12 	/// Initializes the digest calculation.
13 	void start() @safe pure nothrow @nogc
14 	{
15 		_a = 1;
16 		_b = 0;
17 		_tlen = moduloInterval;
18 	}
19 
20 	/// Feeds the digest with data.
21 	void put(scope const(ubyte)[] data...) @trusted pure nothrow @nogc
22 	{
23 		foreach (immutable ubyte i; data)
24 		{
25 			_a += i;
26 			_b += _a;
27 
28 			--_tlen;
29 			if (_tlen == 0)
30 			{
31 				_a %= 65521;
32 				_b %= 65521;
33 				_tlen = moduloInterval;
34 			}
35 		}
36 
37 		if (_tlen != moduloInterval)
38 		{
39 			_a %= 65521;
40 			_b %= 65521;
41 		}
42 	}
43 
44 	/// Returns the finished Adler-32 digest. This also calls start to reset the internal state.
45 	ubyte[4] finish() @trusted pure nothrow @nogc
46 	{
47 		import std.bitmanip : nativeToBigEndian;
48 
49 		auto a = _a, b = _b;
50 
51 		start();
52 
53 		static if (__VERSION__ < 2067)
54 		{
55 			// Phobos bug: std.bitmanip.nativeToBigEndian is not annotated with @nogc
56 			return (cast(ubyte[4] function(uint) @safe pure nothrow @nogc)&nativeToBigEndian!uint)
57 				((b << 16) | a);
58 		}
59 		else
60 		{
61 			return nativeToBigEndian((b << 16) | a);
62 		}
63 	}
64 
65 private:
66 
67 	uint _a = void, _b = void;
68 	uint _tlen = void;
69 
70 	enum moduloInterval = 5552;
71 }
72 
73 //Convenience alias for $(D digest) function in std.digest.digest using the Adler32 implementation.
74 auto adler32Of(T...)(T data)
75 {
76 	return digest!(Adler32, T)(data);
77 }
78 
79 /// OOP API for Adler32.
80 alias Adler32Digest = WrapperDigest!Adler32;
81 
82 ///
83 unittest
84 {
85 	Adler32 adler;
86 	adler.start();
87 	adler.put(cast(ubyte[])"abc");
88 	assert(adler.finish() == x"024d0127");
89 	adler.start();
90 	adler.put(cast(ubyte[])"def");
91 	assert(adler.finish() == x"025F0130");
92 
93 	assert(adler32Of("abc") == x"024d0127");
94 }
95 
96 @safe pure nothrow @nogc
97 unittest
98 {
99 	static assert(isDigest!Adler32);
100 
101 	assert(adler32Of("abc") == x"024d0127");
102 	assert(adler32Of("abcdefghijklmnopqrstuvwxyz") == x"90860B20");
103 }
104 
105 pure nothrow @nogc
106 unittest
107 {
108 	import std.range : repeat;
109 	assert(adler32Of(repeat('a', 1000000)) == x"15D870F9");
110 }
111 
112 ///
113 unittest
114 {
115 	auto adler = new Adler32Digest;
116 	assert(adler.digest("abc") == x"024d0127");
117 }