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