/*
* adler32.c : routines for handling Adler-32 checksums
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
#include
#include
#include "private/svn_adler32.h"
/**
* An Adler-32 implementation per RFC1950.
*
* "The Adler-32 algorithm is much faster than the CRC32 algorithm yet
* still provides an extremely low probability of undetected errors"
*/
/*
* 65521 is the largest prime less than 65536.
* "That 65521 is prime is important to avoid a possible large class of
* two-byte errors that leave the check unchanged."
*/
#define ADLER_MOD_BASE 65521
/*
* Start with CHECKSUM and update the checksum by processing a chunk
* of DATA sized LEN.
*/
apr_uint32_t
svn__adler32(apr_uint32_t checksum, const char *data, apr_off_t len)
{
/* The actual limit can be set somewhat higher but should
* not be lower because the SIMD code would not be used
* in that case.
*
* However, it must be lower than 5552 to make sure our local
* implementation does not suffer from overflows.
*/
if (len >= 80)
{
/* Larger buffers can be efficiently handled by Marc Adler's
* optimized code. Also, new zlib versions will come with
* SIMD code for x86 and x64.
*/
return (apr_uint32_t)adler32(checksum,
(const Bytef *)data,
(uInt)len);
}
else
{
const unsigned char *input = (const unsigned char *)data;
apr_uint32_t s1 = checksum & 0xFFFF;
apr_uint32_t s2 = checksum >> 16;
apr_uint32_t b;
/* Some loop unrolling
* (approx. one clock tick per byte + 2 ticks loop overhead)
*/
for (; len >= 8; len -= 8, input += 8)
{
s1 += input[0]; s2 += s1;
s1 += input[1]; s2 += s1;
s1 += input[2]; s2 += s1;
s1 += input[3]; s2 += s1;
s1 += input[4]; s2 += s1;
s1 += input[5]; s2 += s1;
s1 += input[6]; s2 += s1;
s1 += input[7]; s2 += s1;
}
/* Adler-32 calculation as a simple two ticks per iteration loop.
*/
while (len--)
{
b = *input++;
s1 += b;
s2 += s1;
}
return ((s2 % ADLER_MOD_BASE) << 16) | (s1 % ADLER_MOD_BASE);
}
}