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