summaryrefslogtreecommitdiff
path: root/adler32.c
diff options
context:
space:
mode:
Diffstat (limited to 'adler32.c')
-rw-r--r--adler32.c115
1 files changed, 84 insertions, 31 deletions
diff --git a/adler32.c b/adler32.c
index 94f1021..007ba26 100644
--- a/adler32.c
+++ b/adler32.c
@@ -12,12 +12,13 @@
12#define NMAX 5552 12#define NMAX 5552
13/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ 13/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
14 14
15#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} 15#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
16#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); 16#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
17#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); 17#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
18#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); 18#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
19#define DO16(buf) DO8(buf,0); DO8(buf,8); 19#define DO16(buf) DO8(buf,0); DO8(buf,8);
20 20
21/* use NO_DIVIDE if your processor does not do division in hardware */
21#ifdef NO_DIVIDE 22#ifdef NO_DIVIDE
22# define MOD(a) \ 23# define MOD(a) \
23 do { \ 24 do { \
@@ -39,8 +40,17 @@
39 if (a >= (BASE << 1)) a -= (BASE << 1); \ 40 if (a >= (BASE << 1)) a -= (BASE << 1); \
40 if (a >= BASE) a -= BASE; \ 41 if (a >= BASE) a -= BASE; \
41 } while (0) 42 } while (0)
43# define MOD4(a) \
44 do { \
45 if (a >= (BASE << 4)) a -= (BASE << 4); \
46 if (a >= (BASE << 3)) a -= (BASE << 3); \
47 if (a >= (BASE << 2)) a -= (BASE << 2); \
48 if (a >= (BASE << 1)) a -= (BASE << 1); \
49 if (a >= BASE) a -= BASE; \
50 } while (0)
42#else 51#else
43# define MOD(a) a %= BASE 52# define MOD(a) a %= BASE
53# define MOD4(a) a %= BASE
44#endif 54#endif
45 55
46/* ========================================================================= */ 56/* ========================================================================= */
@@ -49,48 +59,91 @@ uLong ZEXPORT adler32(adler, buf, len)
49 const Bytef *buf; 59 const Bytef *buf;
50 uInt len; 60 uInt len;
51{ 61{
52 unsigned long s1 = adler & 0xffff; 62 unsigned long sum2;
53 unsigned long s2 = (adler >> 16) & 0xffff; 63 unsigned n;
54 int k; 64
65 /* split Adler-32 into component sums */
66 sum2 = (adler >> 16) & 0xffff;
67 adler &= 0xffff;
68
69 /* in case user likes doing a byte at a time, keep it fast */
70 if (len == 1) {
71 adler += buf[0];
72 if (adler >= BASE)
73 adler -= BASE;
74 sum2 += adler;
75 if (sum2 >= BASE)
76 sum2 -= BASE;
77 return adler | (sum2 << 16);
78 }
55 79
56 if (buf == Z_NULL) return 1L; 80 /* initial Adler-32 value (deferred check for len == 1 speed) */
81 if (buf == Z_NULL)
82 return 1L;
57 83
58 while (len > 0) { 84 /* in case short lengths are provided, keep it somewhat fast */
59 k = len < NMAX ? (int)len : NMAX; 85 if (len < 16) {
60 len -= k; 86 while (len--) {
61 while (k >= 16) { 87 adler += *buf++;
88 sum2 += adler;
89 }
90 if (adler >= BASE)
91 adler -= BASE;
92 MOD4(sum2); /* only added so many BASE's */
93 return adler | (sum2 << 16);
94 }
95
96 /* do length NMAX blocks -- requires just one modulo operation */
97 while (len >= NMAX) {
98 len -= NMAX;
99 n = NMAX / 16; /* NMAX is divisible by 16 */
100 do {
101 DO16(buf); /* 16 sums unrolled */
102 buf += 16;
103 } while (--n);
104 MOD(adler);
105 MOD(sum2);
106 }
107
108 /* do remaining bytes (less than NMAX, still just one modulo) */
109 if (len) { /* avoid modulos if none remaining */
110 while (len >= 16) {
111 len -= 16;
62 DO16(buf); 112 DO16(buf);
63 buf += 16; 113 buf += 16;
64 k -= 16;
65 } 114 }
66 if (k != 0) do { 115 while (len--) {
67 s1 += *buf++; 116 adler += *buf++;
68 s2 += s1; 117 sum2 += adler;
69 } while (--k); 118 }
70 MOD(s1); 119 MOD(adler);
71 MOD(s2); 120 MOD(sum2);
72 } 121 }
73 return (s2 << 16) | s1; 122
123 /* return recombined sums */
124 return adler | (sum2 << 16);
74} 125}
75 126
76/* ========================================================================= */ 127/* ========================================================================= */
77uLong ZEXPORT adler32_combine(adler1, adler2, len2) 128uLong ZEXPORT adler32_combine(adler1, adler2, len2)
78 uLong adler1; 129 uLong adler1;
79 uLong adler2; 130 uLong adler2;
80 uLong len2; 131 z_off_t len2;
81{ 132{
82 unsigned long s1; 133 unsigned long sum1;
83 unsigned long s2; 134 unsigned long sum2;
135 unsigned rem;
84 136
85 len2 %= BASE; 137 /* the derivation of this formula is left as an exercise for the reader */
86 s1 = adler1 & 0xffff; 138 rem = (unsigned)(len2 % BASE);
87 s2 = len2 * s1; 139 sum1 = adler1 & 0xffff;
88 MOD(s2); 140 sum2 = rem * sum1;
89 s1 += (adler2 & 0xffff) + BASE - 1; 141 MOD(sum2);
90 s2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - len2; 142 sum1 += (adler2 & 0xffff) + BASE - 1;
91 if (s1 > BASE) s1 -= BASE; 143 sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
92 if (s1 > BASE) s1 -= BASE; 144 if (sum1 > BASE) sum1 -= BASE;
93 if (s2 > (BASE << 1)) s2 -= (BASE << 1); 145 if (sum1 > BASE) sum1 -= BASE;
94 if (s2 > BASE) s2 -= BASE; 146 if (sum2 > (BASE << 1)) sum2 -= (BASE << 1);
95 return (s2 << 16) | s1; 147 if (sum2 > BASE) sum2 -= BASE;
148 return sum1 | (sum2 << 16);
96} 149}