/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│ │vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 1995-2016 Mark Adler │ │ Copyright 2017 The Chromium Authors │ │ Use of this source code is governed by the BSD-style licenses that can │ │ be found in the third_party/zlib/LICENSE file. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/dce.h" #include "libc/nexgen32e/x86feature.h" #include "third_party/zlib/internal.h" #include "third_party/zlib/zutil.h" asm(".ident\t\"\\n\\n\ zlib (zlib License)\\n\ Copyright 1995-2017 Jean-loup Gailly and Mark Adler\""); asm(".include \"libc/disclaimer.inc\""); #define BASE 65521U /* largest prime smaller than 65536 */ #define NMAX 5552 /* largest n such that 255n(n+1)/2+(n+1)(BASE-1)<=2^32-1 */ #define DO1(buf, i) \ { \ adler += (buf)[i]; \ sum2 += adler; \ } #define DO2(buf, i) \ DO1(buf, i); \ DO1(buf, i + 1); #define DO4(buf, i) \ DO2(buf, i); \ DO2(buf, i + 2); #define DO8(buf, i) \ DO4(buf, i); \ DO4(buf, i + 4); #define DO16(buf) \ DO8(buf, 0); \ DO8(buf, 8); /* use NO_DIVIDE if your processor does not do division in hardware -- try it both ways to see which is faster */ #ifdef NO_DIVIDE /* note that this assumes BASE is 65521, where 65536 % 65521 == 15 (thank you to John Reiser for pointing this out) */ #define CHOP(a) \ do { \ unsigned long tmp = a >> 16; \ a &= 0xffffUL; \ a += (tmp << 4) - tmp; \ } while (0) #define MOD28(a) \ do { \ CHOP(a); \ if (a >= BASE) a -= BASE; \ } while (0) #define MOD(a) \ do { \ CHOP(a); \ MOD28(a); \ } while (0) #define MOD63(a) \ do { /* this assumes a is not negative */ \ int64_t tmp = a >> 32; \ a &= 0xffffffffL; \ a += (tmp << 8) - (tmp << 5) + tmp; \ tmp = a >> 16; \ a &= 0xffffL; \ a += (tmp << 4) - tmp; \ tmp = a >> 16; \ a &= 0xffffL; \ a += (tmp << 4) - tmp; \ if (a >= BASE) a -= BASE; \ } while (0) #else #define MOD(a) a %= BASE #define MOD28(a) a %= BASE #define MOD63(a) a %= BASE #endif uLong adler32_z(uLong adler, const Bytef *buf, size_t len) { return adler32(adler, buf, len); } uLong adler32(uLong adler, const Bytef *buf, uInt len) { unsigned long sum2; unsigned n; if (!IsTiny() && X86_HAVE(SSSE3) && buf && len >= 64) { return adler32_simd_(adler, buf, len); } /* split Adler-32 into component sums */ sum2 = (adler >> 16) & 0xffff; adler &= 0xffff; /* in case user likes doing a byte at a time, keep it fast */ if (len == 1) { adler += buf[0]; if (adler >= BASE) adler -= BASE; sum2 += adler; if (sum2 >= BASE) sum2 -= BASE; return adler | (sum2 << 16); } /* initial Adler-32 value (deferred check for len == 1 speed) */ if (buf == Z_NULL) return 1L; /* in case short lengths are provided, keep it somewhat fast */ if (len < 16) { while (len--) { adler += *buf++; sum2 += adler; } if (adler >= BASE) adler -= BASE; MOD28(sum2); /* only added so many BASE's */ return adler | (sum2 << 16); } /* do length NMAX blocks -- requires just one modulo operation */ while (len >= NMAX) { len -= NMAX; n = NMAX / 16; /* NMAX is divisible by 16 */ do { DO16(buf); /* 16 sums unrolled */ buf += 16; } while (--n); MOD(adler); MOD(sum2); } /* do remaining bytes (less than NMAX, still just one modulo) */ if (len) { /* avoid modulos if none remaining */ while (len >= 16) { len -= 16; DO16(buf); buf += 16; } while (len--) { adler += *buf++; sum2 += adler; } MOD(adler); MOD(sum2); } /* return recombined sums */ return adler | (sum2 << 16); } uLong adler32_combine(uLong adler1, uLong adler2, int64_t len2) { unsigned long sum1; unsigned long sum2; unsigned rem; /* for negative len, return invalid adler32 as a clue for debugging */ if (len2 < 0) return 0xffffffffUL; /* the derivation of this formula is left as an exercise for the reader */ MOD63(len2); /* assumes len2 >= 0 */ rem = (unsigned)len2; sum1 = adler1 & 0xffff; sum2 = rem * sum1; MOD(sum2); sum1 += (adler2 & 0xffff) + BASE - 1; sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; if (sum1 >= BASE) sum1 -= BASE; if (sum1 >= BASE) sum1 -= BASE; if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); if (sum2 >= BASE) sum2 -= BASE; return sum1 | (sum2 << 16); }