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