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