xref: /third_party/zlib/adler32.c (revision 275793ea)
1275793eaSopenharmony_ci/* adler32.c -- compute the Adler-32 checksum of a data stream
2275793eaSopenharmony_ci * Copyright (C) 1995-2011, 2016 Mark Adler
3275793eaSopenharmony_ci * For conditions of distribution and use, see copyright notice in zlib.h
4275793eaSopenharmony_ci */
5275793eaSopenharmony_ci
6275793eaSopenharmony_ci/* @(#) $Id$ */
7275793eaSopenharmony_ci
8275793eaSopenharmony_ci#include "zutil.h"
9275793eaSopenharmony_ci
10275793eaSopenharmony_ci#define BASE 65521U     /* largest prime smaller than 65536 */
11275793eaSopenharmony_ci#define NMAX 5552
12275793eaSopenharmony_ci/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
13275793eaSopenharmony_ci
14275793eaSopenharmony_ci#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
15275793eaSopenharmony_ci#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
16275793eaSopenharmony_ci#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
17275793eaSopenharmony_ci#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
18275793eaSopenharmony_ci#define DO16(buf)   DO8(buf,0); DO8(buf,8);
19275793eaSopenharmony_ci
20275793eaSopenharmony_ci/* use NO_DIVIDE if your processor does not do division in hardware --
21275793eaSopenharmony_ci   try it both ways to see which is faster */
22275793eaSopenharmony_ci#ifdef NO_DIVIDE
23275793eaSopenharmony_ci/* note that this assumes BASE is 65521, where 65536 % 65521 == 15
24275793eaSopenharmony_ci   (thank you to John Reiser for pointing this out) */
25275793eaSopenharmony_ci#  define CHOP(a) \
26275793eaSopenharmony_ci    do { \
27275793eaSopenharmony_ci        unsigned long tmp = a >> 16; \
28275793eaSopenharmony_ci        a &= 0xffffUL; \
29275793eaSopenharmony_ci        a += (tmp << 4) - tmp; \
30275793eaSopenharmony_ci    } while (0)
31275793eaSopenharmony_ci#  define MOD28(a) \
32275793eaSopenharmony_ci    do { \
33275793eaSopenharmony_ci        CHOP(a); \
34275793eaSopenharmony_ci        if (a >= BASE) a -= BASE; \
35275793eaSopenharmony_ci    } while (0)
36275793eaSopenharmony_ci#  define MOD(a) \
37275793eaSopenharmony_ci    do { \
38275793eaSopenharmony_ci        CHOP(a); \
39275793eaSopenharmony_ci        MOD28(a); \
40275793eaSopenharmony_ci    } while (0)
41275793eaSopenharmony_ci#  define MOD63(a) \
42275793eaSopenharmony_ci    do { /* this assumes a is not negative */ \
43275793eaSopenharmony_ci        z_off64_t tmp = a >> 32; \
44275793eaSopenharmony_ci        a &= 0xffffffffL; \
45275793eaSopenharmony_ci        a += (tmp << 8) - (tmp << 5) + tmp; \
46275793eaSopenharmony_ci        tmp = a >> 16; \
47275793eaSopenharmony_ci        a &= 0xffffL; \
48275793eaSopenharmony_ci        a += (tmp << 4) - tmp; \
49275793eaSopenharmony_ci        tmp = a >> 16; \
50275793eaSopenharmony_ci        a &= 0xffffL; \
51275793eaSopenharmony_ci        a += (tmp << 4) - tmp; \
52275793eaSopenharmony_ci        if (a >= BASE) a -= BASE; \
53275793eaSopenharmony_ci    } while (0)
54275793eaSopenharmony_ci#else
55275793eaSopenharmony_ci#  define MOD(a) a %= BASE
56275793eaSopenharmony_ci#  define MOD28(a) a %= BASE
57275793eaSopenharmony_ci#  define MOD63(a) a %= BASE
58275793eaSopenharmony_ci#endif
59275793eaSopenharmony_ci
60275793eaSopenharmony_ci/* ========================================================================= */
61275793eaSopenharmony_ciuLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len)
62275793eaSopenharmony_ci{
63275793eaSopenharmony_ci    unsigned long sum2;
64275793eaSopenharmony_ci    unsigned n;
65275793eaSopenharmony_ci
66275793eaSopenharmony_ci    /* split Adler-32 into component sums */
67275793eaSopenharmony_ci    sum2 = (adler >> 16) & 0xffff;
68275793eaSopenharmony_ci    adler &= 0xffff;
69275793eaSopenharmony_ci
70275793eaSopenharmony_ci    /* in case user likes doing a byte at a time, keep it fast */
71275793eaSopenharmony_ci    if (len == 1) {
72275793eaSopenharmony_ci        adler += buf[0];
73275793eaSopenharmony_ci        if (adler >= BASE)
74275793eaSopenharmony_ci            adler -= BASE;
75275793eaSopenharmony_ci        sum2 += adler;
76275793eaSopenharmony_ci        if (sum2 >= BASE)
77275793eaSopenharmony_ci            sum2 -= BASE;
78275793eaSopenharmony_ci        return adler | (sum2 << 16);
79275793eaSopenharmony_ci    }
80275793eaSopenharmony_ci
81275793eaSopenharmony_ci    /* initial Adler-32 value (deferred check for len == 1 speed) */
82275793eaSopenharmony_ci    if (buf == Z_NULL)
83275793eaSopenharmony_ci        return 1L;
84275793eaSopenharmony_ci
85275793eaSopenharmony_ci    /* in case short lengths are provided, keep it somewhat fast */
86275793eaSopenharmony_ci    if (len < 16) {
87275793eaSopenharmony_ci        while (len--) {
88275793eaSopenharmony_ci            adler += *buf++;
89275793eaSopenharmony_ci            sum2 += adler;
90275793eaSopenharmony_ci        }
91275793eaSopenharmony_ci        if (adler >= BASE)
92275793eaSopenharmony_ci            adler -= BASE;
93275793eaSopenharmony_ci        MOD28(sum2);            /* only added so many BASE's */
94275793eaSopenharmony_ci        return adler | (sum2 << 16);
95275793eaSopenharmony_ci    }
96275793eaSopenharmony_ci
97275793eaSopenharmony_ci    /* do length NMAX blocks -- requires just one modulo operation */
98275793eaSopenharmony_ci    while (len >= NMAX) {
99275793eaSopenharmony_ci        len -= NMAX;
100275793eaSopenharmony_ci        n = NMAX / 16;          /* NMAX is divisible by 16 */
101275793eaSopenharmony_ci        do {
102275793eaSopenharmony_ci            DO16(buf);          /* 16 sums unrolled */
103275793eaSopenharmony_ci            buf += 16;
104275793eaSopenharmony_ci        } while (--n);
105275793eaSopenharmony_ci        MOD(adler);
106275793eaSopenharmony_ci        MOD(sum2);
107275793eaSopenharmony_ci    }
108275793eaSopenharmony_ci
109275793eaSopenharmony_ci    /* do remaining bytes (less than NMAX, still just one modulo) */
110275793eaSopenharmony_ci    if (len) {                  /* avoid modulos if none remaining */
111275793eaSopenharmony_ci        while (len >= 16) {
112275793eaSopenharmony_ci            len -= 16;
113275793eaSopenharmony_ci            DO16(buf);
114275793eaSopenharmony_ci            buf += 16;
115275793eaSopenharmony_ci        }
116275793eaSopenharmony_ci        while (len--) {
117275793eaSopenharmony_ci            adler += *buf++;
118275793eaSopenharmony_ci            sum2 += adler;
119275793eaSopenharmony_ci        }
120275793eaSopenharmony_ci        MOD(adler);
121275793eaSopenharmony_ci        MOD(sum2);
122275793eaSopenharmony_ci    }
123275793eaSopenharmony_ci
124275793eaSopenharmony_ci    /* return recombined sums */
125275793eaSopenharmony_ci    return adler | (sum2 << 16);
126275793eaSopenharmony_ci}
127275793eaSopenharmony_ci
128275793eaSopenharmony_ci/* ========================================================================= */
129275793eaSopenharmony_ciuLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len)
130275793eaSopenharmony_ci{
131275793eaSopenharmony_ci    return adler32_z(adler, buf, len);
132275793eaSopenharmony_ci}
133275793eaSopenharmony_ci
134275793eaSopenharmony_ci/* ========================================================================= */
135275793eaSopenharmony_cilocal uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2)
136275793eaSopenharmony_ci{
137275793eaSopenharmony_ci    unsigned long sum1;
138275793eaSopenharmony_ci    unsigned long sum2;
139275793eaSopenharmony_ci    unsigned rem;
140275793eaSopenharmony_ci
141275793eaSopenharmony_ci    /* for negative len, return invalid adler32 as a clue for debugging */
142275793eaSopenharmony_ci    if (len2 < 0)
143275793eaSopenharmony_ci        return 0xffffffffUL;
144275793eaSopenharmony_ci
145275793eaSopenharmony_ci    /* the derivation of this formula is left as an exercise for the reader */
146275793eaSopenharmony_ci    MOD63(len2);                /* assumes len2 >= 0 */
147275793eaSopenharmony_ci    rem = (unsigned)len2;
148275793eaSopenharmony_ci    sum1 = adler1 & 0xffff;
149275793eaSopenharmony_ci    sum2 = rem * sum1;
150275793eaSopenharmony_ci    MOD(sum2);
151275793eaSopenharmony_ci    sum1 += (adler2 & 0xffff) + BASE - 1;
152275793eaSopenharmony_ci    sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
153275793eaSopenharmony_ci    if (sum1 >= BASE) sum1 -= BASE;
154275793eaSopenharmony_ci    if (sum1 >= BASE) sum1 -= BASE;
155275793eaSopenharmony_ci    if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1);
156275793eaSopenharmony_ci    if (sum2 >= BASE) sum2 -= BASE;
157275793eaSopenharmony_ci    return sum1 | (sum2 << 16);
158275793eaSopenharmony_ci}
159275793eaSopenharmony_ci
160275793eaSopenharmony_ci/* ========================================================================= */
161275793eaSopenharmony_ciuLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2)
162275793eaSopenharmony_ci{
163275793eaSopenharmony_ci    return adler32_combine_(adler1, adler2, len2);
164275793eaSopenharmony_ci}
165275793eaSopenharmony_ci
166275793eaSopenharmony_ciuLong ZEXPORT adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2)
167275793eaSopenharmony_ci{
168275793eaSopenharmony_ci    return adler32_combine_(adler1, adler2, len2);
169275793eaSopenharmony_ci}
170