1 /** 2 Adler-32 implementation. This module conforms to the APIs defined in std.digest. 3 */ 4 module nxt.digest.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() pure nothrow @safe @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 _a += i; 24 _b += _a; 25 26 --_tlen; 27 if (_tlen == 0) { 28 _a %= 65521; 29 _b %= 65521; 30 _tlen = moduloInterval; 31 } 32 } 33 34 if (_tlen != moduloInterval) { 35 _a %= 65521; 36 _b %= 65521; 37 } 38 } 39 40 /// Returns the finished Adler-32 digest. This also calls start to reset the internal state. 41 ubyte[4] finish() @trusted pure nothrow @nogc 42 { 43 import std.bitmanip : nativeToBigEndian; 44 auto a = _a, b = _b; 45 start(); 46 return nativeToBigEndian((b << 16) | a); 47 } 48 49 private: 50 51 uint _a = void, _b = void; 52 uint _tlen = void; 53 54 enum moduloInterval = 5552; 55 } 56 57 /// 58 unittest { 59 Adler32 adler; 60 adler.start(); 61 adler.put(cast(ubyte[]) "abc"); 62 assert(adler.finish() == hexString!"024d0127"); 63 adler.start(); 64 adler.put(cast(ubyte[]) "def"); 65 assert(adler.finish() == hexString!"025F0130"); 66 } 67 68 /// Convenience alias for $(D digest) function in std.digest using the Adler32 implementation. 69 auto adler32Of(T...)(T data) { 70 return digest!(Adler32, T)(data); 71 } 72 73 /// OOP API for Adler32. 74 alias Adler32Digest = WrapperDigest!Adler32; 75 76 /// 77 unittest { 78 auto adler = new Adler32Digest; 79 assert(adler.digest("abc") == hexString!"024d0127"); 80 } 81 82 pure nothrow @safe @nogc unittest { 83 static assert(isDigest!Adler32); 84 85 assert(adler32Of("abc") == hexString!"024d0127"); 86 assert(adler32Of("abcdefghijklmnopqrstuvwxyz") == hexString!"90860B20"); 87 } 88 89 version (unittest) { 90 import std.conv : hexString; 91 }