1d4afb5ceSopenharmony_ci/* adler32.c -- compute the Adler-32 checksum of a data stream
2d4afb5ceSopenharmony_ci * Copyright (C) 1995-2007 Mark Adler
3d4afb5ceSopenharmony_ci * For conditions of distribution and use, see copyright notice in zlib.h
4d4afb5ceSopenharmony_ci */
5d4afb5ceSopenharmony_ci
6d4afb5ceSopenharmony_ci/* \param (#) $Id$ */
7d4afb5ceSopenharmony_ci
8d4afb5ceSopenharmony_ci#include "zutil.h"
9d4afb5ceSopenharmony_ci
10d4afb5ceSopenharmony_ci#define local static
11d4afb5ceSopenharmony_ci
12d4afb5ceSopenharmony_cilocal uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2);
13d4afb5ceSopenharmony_ci
14d4afb5ceSopenharmony_ci#define BASE 65521UL    /* largest prime smaller than 65536 */
15d4afb5ceSopenharmony_ci#define NMAX 5552
16d4afb5ceSopenharmony_ci/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
17d4afb5ceSopenharmony_ci
18d4afb5ceSopenharmony_ci#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
19d4afb5ceSopenharmony_ci#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
20d4afb5ceSopenharmony_ci#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
21d4afb5ceSopenharmony_ci#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
22d4afb5ceSopenharmony_ci#define DO16(buf)   DO8(buf,0); DO8(buf,8);
23d4afb5ceSopenharmony_ci
24d4afb5ceSopenharmony_ci/* use NO_DIVIDE if your processor does not do division in hardware */
25d4afb5ceSopenharmony_ci#ifdef NO_DIVIDE
26d4afb5ceSopenharmony_ci#  define MOD(a) \
27d4afb5ceSopenharmony_ci    do { \
28d4afb5ceSopenharmony_ci        if (a >= (BASE << 16)) a -= (BASE << 16); \
29d4afb5ceSopenharmony_ci        if (a >= (BASE << 15)) a -= (BASE << 15); \
30d4afb5ceSopenharmony_ci        if (a >= (BASE << 14)) a -= (BASE << 14); \
31d4afb5ceSopenharmony_ci        if (a >= (BASE << 13)) a -= (BASE << 13); \
32d4afb5ceSopenharmony_ci        if (a >= (BASE << 12)) a -= (BASE << 12); \
33d4afb5ceSopenharmony_ci        if (a >= (BASE << 11)) a -= (BASE << 11); \
34d4afb5ceSopenharmony_ci        if (a >= (BASE << 10)) a -= (BASE << 10); \
35d4afb5ceSopenharmony_ci        if (a >= (BASE << 9)) a -= (BASE << 9); \
36d4afb5ceSopenharmony_ci        if (a >= (BASE << 8)) a -= (BASE << 8); \
37d4afb5ceSopenharmony_ci        if (a >= (BASE << 7)) a -= (BASE << 7); \
38d4afb5ceSopenharmony_ci        if (a >= (BASE << 6)) a -= (BASE << 6); \
39d4afb5ceSopenharmony_ci        if (a >= (BASE << 5)) a -= (BASE << 5); \
40d4afb5ceSopenharmony_ci        if (a >= (BASE << 4)) a -= (BASE << 4); \
41d4afb5ceSopenharmony_ci        if (a >= (BASE << 3)) a -= (BASE << 3); \
42d4afb5ceSopenharmony_ci        if (a >= (BASE << 2)) a -= (BASE << 2); \
43d4afb5ceSopenharmony_ci        if (a >= (BASE << 1)) a -= (BASE << 1); \
44d4afb5ceSopenharmony_ci        if (a >= BASE) a -= BASE; \
45d4afb5ceSopenharmony_ci    } while (0)
46d4afb5ceSopenharmony_ci#  define MOD4(a) \
47d4afb5ceSopenharmony_ci    do { \
48d4afb5ceSopenharmony_ci        if (a >= (BASE << 4)) a -= (BASE << 4); \
49d4afb5ceSopenharmony_ci        if (a >= (BASE << 3)) a -= (BASE << 3); \
50d4afb5ceSopenharmony_ci        if (a >= (BASE << 2)) a -= (BASE << 2); \
51d4afb5ceSopenharmony_ci        if (a >= (BASE << 1)) a -= (BASE << 1); \
52d4afb5ceSopenharmony_ci        if (a >= BASE) a -= BASE; \
53d4afb5ceSopenharmony_ci    } while (0)
54d4afb5ceSopenharmony_ci#else
55d4afb5ceSopenharmony_ci#  define MOD(a) a %= BASE
56d4afb5ceSopenharmony_ci#  define MOD4(a) a %= BASE
57d4afb5ceSopenharmony_ci#endif
58d4afb5ceSopenharmony_ci
59d4afb5ceSopenharmony_ci/* ========================================================================= */
60d4afb5ceSopenharmony_ciuLong ZEXPORT adler32(adler, buf, len)
61d4afb5ceSopenharmony_ci    uLong adler;
62d4afb5ceSopenharmony_ci    const Bytef *buf;
63d4afb5ceSopenharmony_ci    uInt len;
64d4afb5ceSopenharmony_ci{
65d4afb5ceSopenharmony_ci    unsigned long sum2;
66d4afb5ceSopenharmony_ci    unsigned n;
67d4afb5ceSopenharmony_ci
68d4afb5ceSopenharmony_ci    /* split Adler-32 into component sums */
69d4afb5ceSopenharmony_ci    sum2 = (adler >> 16) & 0xffff;
70d4afb5ceSopenharmony_ci    adler &= 0xffff;
71d4afb5ceSopenharmony_ci
72d4afb5ceSopenharmony_ci    /* in case user likes doing a byte at a time, keep it fast */
73d4afb5ceSopenharmony_ci    if (len == 1) {
74d4afb5ceSopenharmony_ci        adler += buf[0];
75d4afb5ceSopenharmony_ci        if (adler >= BASE)
76d4afb5ceSopenharmony_ci            adler -= BASE;
77d4afb5ceSopenharmony_ci        sum2 += adler;
78d4afb5ceSopenharmony_ci        if (sum2 >= BASE)
79d4afb5ceSopenharmony_ci            sum2 -= BASE;
80d4afb5ceSopenharmony_ci        return adler | (sum2 << 16);
81d4afb5ceSopenharmony_ci    }
82d4afb5ceSopenharmony_ci
83d4afb5ceSopenharmony_ci    /* initial Adler-32 value (deferred check for len == 1 speed) */
84d4afb5ceSopenharmony_ci    if (buf == Z_NULL)
85d4afb5ceSopenharmony_ci        return 1L;
86d4afb5ceSopenharmony_ci
87d4afb5ceSopenharmony_ci    /* in case short lengths are provided, keep it somewhat fast */
88d4afb5ceSopenharmony_ci    if (len < 16) {
89d4afb5ceSopenharmony_ci        while (len--) {
90d4afb5ceSopenharmony_ci            adler += *buf++;
91d4afb5ceSopenharmony_ci            sum2 += adler;
92d4afb5ceSopenharmony_ci        }
93d4afb5ceSopenharmony_ci        if (adler >= BASE)
94d4afb5ceSopenharmony_ci            adler -= BASE;
95d4afb5ceSopenharmony_ci        MOD4(sum2);             /* only added so many BASE's */
96d4afb5ceSopenharmony_ci        return adler | (sum2 << 16);
97d4afb5ceSopenharmony_ci    }
98d4afb5ceSopenharmony_ci
99d4afb5ceSopenharmony_ci    /* do length NMAX blocks -- requires just one modulo operation */
100d4afb5ceSopenharmony_ci    while (len >= NMAX) {
101d4afb5ceSopenharmony_ci        len -= NMAX;
102d4afb5ceSopenharmony_ci        n = NMAX / 16;          /* NMAX is divisible by 16 */
103d4afb5ceSopenharmony_ci        do {
104d4afb5ceSopenharmony_ci            DO16(buf);          /* 16 sums unrolled */
105d4afb5ceSopenharmony_ci            buf += 16;
106d4afb5ceSopenharmony_ci        } while (--n);
107d4afb5ceSopenharmony_ci        MOD(adler);
108d4afb5ceSopenharmony_ci        MOD(sum2);
109d4afb5ceSopenharmony_ci    }
110d4afb5ceSopenharmony_ci
111d4afb5ceSopenharmony_ci    /* do remaining bytes (less than NMAX, still just one modulo) */
112d4afb5ceSopenharmony_ci    if (len) {                  /* avoid modulos if none remaining */
113d4afb5ceSopenharmony_ci        while (len >= 16) {
114d4afb5ceSopenharmony_ci            len -= 16;
115d4afb5ceSopenharmony_ci            DO16(buf);
116d4afb5ceSopenharmony_ci            buf += 16;
117d4afb5ceSopenharmony_ci        }
118d4afb5ceSopenharmony_ci        while (len--) {
119d4afb5ceSopenharmony_ci            adler += *buf++;
120d4afb5ceSopenharmony_ci            sum2 += adler;
121d4afb5ceSopenharmony_ci        }
122d4afb5ceSopenharmony_ci        MOD(adler);
123d4afb5ceSopenharmony_ci        MOD(sum2);
124d4afb5ceSopenharmony_ci    }
125d4afb5ceSopenharmony_ci
126d4afb5ceSopenharmony_ci    /* return recombined sums */
127d4afb5ceSopenharmony_ci    return adler | (sum2 << 16);
128d4afb5ceSopenharmony_ci}
129d4afb5ceSopenharmony_ci
130d4afb5ceSopenharmony_ci/* ========================================================================= */
131d4afb5ceSopenharmony_cilocal uLong adler32_combine_(adler1, adler2, len2)
132d4afb5ceSopenharmony_ci    uLong adler1;
133d4afb5ceSopenharmony_ci    uLong adler2;
134d4afb5ceSopenharmony_ci    z_off64_t len2;
135d4afb5ceSopenharmony_ci{
136d4afb5ceSopenharmony_ci    unsigned long sum1;
137d4afb5ceSopenharmony_ci    unsigned long sum2;
138d4afb5ceSopenharmony_ci    unsigned rem;
139d4afb5ceSopenharmony_ci
140d4afb5ceSopenharmony_ci    /* the derivation of this formula is left as an exercise for the reader */
141d4afb5ceSopenharmony_ci    rem = (unsigned)(len2 % BASE);
142d4afb5ceSopenharmony_ci    sum1 = adler1 & 0xffff;
143d4afb5ceSopenharmony_ci    sum2 = rem * sum1;
144d4afb5ceSopenharmony_ci    MOD(sum2);
145d4afb5ceSopenharmony_ci    sum1 += (adler2 & 0xffff) + BASE - 1;
146d4afb5ceSopenharmony_ci    sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
147d4afb5ceSopenharmony_ci    if (sum1 >= BASE) sum1 -= BASE;
148d4afb5ceSopenharmony_ci    if (sum1 >= BASE) sum1 -= BASE;
149d4afb5ceSopenharmony_ci    if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
150d4afb5ceSopenharmony_ci    if (sum2 >= BASE) sum2 -= BASE;
151d4afb5ceSopenharmony_ci    return sum1 | (sum2 << 16);
152d4afb5ceSopenharmony_ci}
153d4afb5ceSopenharmony_ci
154d4afb5ceSopenharmony_ci/* ========================================================================= */
155d4afb5ceSopenharmony_ciuLong ZEXPORT adler32_combine(adler1, adler2, len2)
156d4afb5ceSopenharmony_ci    uLong adler1;
157d4afb5ceSopenharmony_ci    uLong adler2;
158d4afb5ceSopenharmony_ci    z_off_t len2;
159d4afb5ceSopenharmony_ci{
160d4afb5ceSopenharmony_ci    return adler32_combine_(adler1, adler2, len2);
161d4afb5ceSopenharmony_ci}
162d4afb5ceSopenharmony_ci
163d4afb5ceSopenharmony_ciuLong ZEXPORT adler32_combine64(adler1, adler2, len2)
164d4afb5ceSopenharmony_ci    uLong adler1;
165d4afb5ceSopenharmony_ci    uLong adler2;
166d4afb5ceSopenharmony_ci    z_off64_t len2;
167d4afb5ceSopenharmony_ci{
168d4afb5ceSopenharmony_ci    return adler32_combine_(adler1, adler2, len2);
169d4afb5ceSopenharmony_ci}
170