19e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* adler32.c -- compute the Adler-32 checksum of a data stream 2ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes * Copyright (C) 1995-2011 Mark Adler 39e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project * For conditions of distribution and use, see copyright notice in zlib.h 49e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project */ 59e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project 69e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* @(#) $Id$ */ 79e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project 8381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#include "zutil.h" 9381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 10381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#define local static 11381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 12ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hugheslocal uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); 139e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project 14ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#define BASE 65521 /* largest prime smaller than 65536 */ 159e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#define NMAX 5552 169e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ 179e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project 189e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} 199e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); 209e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); 219e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); 229e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#define DO16(buf) DO8(buf,0); DO8(buf,8); 239e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project 24ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes/* use NO_DIVIDE if your processor does not do division in hardware -- 25ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes try it both ways to see which is faster */ 269e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#ifdef NO_DIVIDE 27ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 28ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes (thank you to John Reiser for pointing this out) */ 29ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define CHOP(a) \ 30ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes do { \ 31ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes unsigned long tmp = a >> 16; \ 32ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes a &= 0xffffUL; \ 33ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes a += (tmp << 4) - tmp; \ 34ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes } while (0) 35ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define MOD28(a) \ 369e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project do { \ 37ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes CHOP(a); \ 389e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project if (a >= BASE) a -= BASE; \ 399e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project } while (0) 40ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define MOD(a) \ 419e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project do { \ 42ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes CHOP(a); \ 43ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes MOD28(a); \ 44ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes } while (0) 45ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define MOD63(a) \ 46ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes do { /* this assumes a is not negative */ \ 47ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes z_off64_t tmp = a >> 32; \ 48ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes a &= 0xffffffffL; \ 49ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes a += (tmp << 8) - (tmp << 5) + tmp; \ 50ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes tmp = a >> 16; \ 51ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes a &= 0xffffL; \ 52ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes a += (tmp << 4) - tmp; \ 53ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes tmp = a >> 16; \ 54ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes a &= 0xffffL; \ 55ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes a += (tmp << 4) - tmp; \ 569e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project if (a >= BASE) a -= BASE; \ 579e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project } while (0) 589e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#else 599e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project# define MOD(a) a %= BASE 60ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define MOD28(a) a %= BASE 61ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define MOD63(a) a %= BASE 629e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#endif 639e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project 649e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* ========================================================================= */ 659e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source ProjectuLong ZEXPORT adler32(adler, buf, len) 669e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project uLong adler; 679e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project const Bytef *buf; 689e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project uInt len; 699e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project{ 709e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project unsigned long sum2; 719e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project unsigned n; 729e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project 739e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project /* split Adler-32 into component sums */ 749e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project sum2 = (adler >> 16) & 0xffff; 759e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project adler &= 0xffff; 769e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project 779e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project /* in case user likes doing a byte at a time, keep it fast */ 789e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project if (len == 1) { 799e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project adler += buf[0]; 809e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project if (adler >= BASE) 819e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project adler -= BASE; 829e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project sum2 += adler; 839e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project if (sum2 >= BASE) 849e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project sum2 -= BASE; 859e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project return adler | (sum2 << 16); 869e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project } 879e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project 889e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project /* initial Adler-32 value (deferred check for len == 1 speed) */ 899e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project if (buf == Z_NULL) 909e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project return 1L; 919e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project 929e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project /* in case short lengths are provided, keep it somewhat fast */ 939e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project if (len < 16) { 949e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project while (len--) { 959e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project adler += *buf++; 969e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project sum2 += adler; 979e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project } 989e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project if (adler >= BASE) 999e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project adler -= BASE; 100ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes MOD28(sum2); /* only added so many BASE's */ 1019e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project return adler | (sum2 << 16); 1029e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project } 1039e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project 1049e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project /* do length NMAX blocks -- requires just one modulo operation */ 1059e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project while (len >= NMAX) { 1069e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project len -= NMAX; 1079e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project n = NMAX / 16; /* NMAX is divisible by 16 */ 1089e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project do { 1099e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project DO16(buf); /* 16 sums unrolled */ 1109e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project buf += 16; 1119e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project } while (--n); 1129e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project MOD(adler); 1139e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project MOD(sum2); 1149e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project } 1159e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project 1169e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project /* do remaining bytes (less than NMAX, still just one modulo) */ 1179e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project if (len) { /* avoid modulos if none remaining */ 1189e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project while (len >= 16) { 1199e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project len -= 16; 1209e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project DO16(buf); 1219e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project buf += 16; 1229e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project } 1239e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project while (len--) { 1249e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project adler += *buf++; 1259e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project sum2 += adler; 1269e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project } 1279e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project MOD(adler); 1289e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project MOD(sum2); 1299e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project } 1309e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project 1319e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project /* return recombined sums */ 1329e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project return adler | (sum2 << 16); 1339e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project} 1349e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project 1359e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* ========================================================================= */ 136381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheslocal uLong adler32_combine_(adler1, adler2, len2) 1379e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project uLong adler1; 1389e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project uLong adler2; 139381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes z_off64_t len2; 1409e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project{ 1419e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project unsigned long sum1; 1429e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project unsigned long sum2; 1439e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project unsigned rem; 1449e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project 145ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes /* for negative len, return invalid adler32 as a clue for debugging */ 146ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes if (len2 < 0) 147ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes return 0xffffffffUL; 148ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 1499e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project /* the derivation of this formula is left as an exercise for the reader */ 150ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes MOD63(len2); /* assumes len2 >= 0 */ 151ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes rem = (unsigned)len2; 1529e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project sum1 = adler1 & 0xffff; 1539e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project sum2 = rem * sum1; 1549e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project MOD(sum2); 1559e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project sum1 += (adler2 & 0xffff) + BASE - 1; 1569e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; 157381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes if (sum1 >= BASE) sum1 -= BASE; 158381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes if (sum1 >= BASE) sum1 -= BASE; 159381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1); 160381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes if (sum2 >= BASE) sum2 -= BASE; 1619e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project return sum1 | (sum2 << 16); 1629e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project} 163381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 164381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* ========================================================================= */ 165381716e9396b55b1adb8235b020c37344f60ab07Elliott HughesuLong ZEXPORT adler32_combine(adler1, adler2, len2) 166381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes uLong adler1; 167381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes uLong adler2; 168381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes z_off_t len2; 169381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes{ 170381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes return adler32_combine_(adler1, adler2, len2); 171381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes} 172381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 173381716e9396b55b1adb8235b020c37344f60ab07Elliott HughesuLong ZEXPORT adler32_combine64(adler1, adler2, len2) 174381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes uLong adler1; 175381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes uLong adler2; 176381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes z_off64_t len2; 177381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes{ 178381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes return adler32_combine_(adler1, adler2, len2); 179381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes} 180