// adler32.cs -- compute the Adler-32 checksum of a data stream // Copyright (C) 1995-2007 Mark Adler // Copyright (C) 2007-2011 by the Authors // For conditions of distribution and use, see copyright notice in License.txt namespace Framework.IO { public static partial class ZLib { private const uint BASE=65521; // largest prime smaller than 65536 private const uint NMAX=5552; // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 // ========================================================================= // Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. // If buf is NULL, this function returns the required initial value for the checksum. // An Adler-32 checksum is almost as reliable as a CRC32 but can be computed much faster. // // Usage example: // uint adler=adler32(0, null, 0); // while(read_buffer(buffer, length)!=EOF) // { // adler=adler32(adler, buffer, length); // } // if(adler!=original_adler) error(); public static uint adler32(uint adler, byte[] buf, uint len) { return adler32(adler, buf, 0, len); } public static uint adler32(uint adler, byte[] buf, uint ind, uint len) { // initial Adler-32 value (deferred check for len==1 speed) if(buf==null) return 1; // split Adler-32 into component sums uint sum2=(adler>>16)&0xffff; adler&=0xffff; //uint ind=0; // index in buf // in case user likes doing a byte at a time, keep it fast if(len==1) { adler+=buf[ind]; if(adler>=BASE) adler-=BASE; sum2+=adler; if(sum2>=BASE) sum2-=BASE; return adler|(sum2<<16); } // in case short lengths are provided, keep it somewhat fast if(len<16) { while(len--!=0) { adler+=buf[ind++]; sum2+=adler; } if(adler>=BASE) adler-=BASE; sum2%=BASE; // only added so many BASE's return adler|(sum2<<16); } // do length NMAX blocks -- requires just one modulo operation while(len>=NMAX) { len-=NMAX; uint n=NMAX/16; // NMAX is divisible by 16 do { // 16 sums unrolled adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; } while(--n!=0); adler%=BASE; sum2%=BASE; } // do remaining bytes (less than NMAX, still just one modulo) if(len!=0) { // avoid modulos if none remaining while(len>=16) { len-=16; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; adler+=buf[ind++]; sum2+=adler; } while(len--!=0) { adler+=buf[ind++]; sum2+=adler; } adler%=BASE; sum2%=BASE; } // return recombined sums return adler|(sum2<<16); } // ========================================================================= // Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 // and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for // each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of // seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. public static uint adler32_combine_(uint adler1, uint adler2, uint len2) { // the derivation of this formula is left as an exercise for the reader uint rem=len2%BASE; uint sum1=adler1&0xffff; uint sum2=(rem*sum1)%BASE; sum1+=(adler2&0xffff)+BASE-1; sum2+=((adler1>>16)&0xffff)+((adler2>>16)&0xffff)+BASE-rem; if(sum1>=BASE) sum1-=BASE; if(sum1>=BASE) sum1-=BASE; if(sum2>=(BASE<<1)) sum2-=(BASE<<1); if(sum2>=BASE) sum2-=BASE; return sum1|(sum2<<16); } // ========================================================================= public static uint adler32_combine(uint adler1, uint adler2, uint len2) { return adler32_combine_(adler1, adler2, len2); } public static uint adler32_combine64(uint adler1, uint adler2, uint len2) { return adler32_combine_(adler1, adler2, len2); } } }