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 }