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