2 * fnv1a.c : routines to create checksums derived from FNV-1a
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
24 #define APR_WANT_BYTEFUNC
29 #include "private/svn_subr_private.h"
33 * See http://www.isthe.com/chongo/tech/comp/fnv/ for more info on FNV-1
36 /* FNV-1 32 bit constants taken from
37 * http://www.isthe.com/chongo/tech/comp/fnv/
39 #define FNV1_PRIME_32 0x01000193
40 #define FNV1_BASE_32 2166136261U
42 /* FNV-1a core implementation returning a 32 bit checksum over the first
43 * LEN bytes in INPUT. HASH is the checksum over preceding data (if any).
46 fnv1a_32(apr_uint32_t hash, const void *input, apr_size_t len)
48 const unsigned char *data = input;
49 const unsigned char *end = data + len;
51 for (; data != end; ++data)
54 hash *= FNV1_PRIME_32;
60 /* Number of interleaved FVN-1a checksums we calculate for the modified
65 /* FNV-1a core implementation updating 4 interleaved checksums in HASHES
66 * over the first LEN bytes in INPUT. This will only process multiples
67 * of 4 and return the number of bytes processed. LEN - ReturnValue < 4.
70 fnv1a_32x4(apr_uint32_t hashes[SCALING], const void *input, apr_size_t len)
72 /* calculate SCALING interleaved FNV-1a hashes while the input
74 const unsigned char *data = input;
75 const unsigned char *end = data + len;
76 for (; data + SCALING <= end; data += SCALING)
79 hashes[0] *= FNV1_PRIME_32;
81 hashes[1] *= FNV1_PRIME_32;
83 hashes[2] *= FNV1_PRIME_32;
85 hashes[3] *= FNV1_PRIME_32;
88 return data - (const unsigned char *)input;
91 /* Combine interleaved HASHES plus LEN bytes from INPUT into a single
92 * 32 bit hash value and return that. LEN must be < 4.
95 finalize_fnv1a_32x4(apr_uint32_t hashes[SCALING],
99 char final_data[sizeof(apr_uint32_t) * SCALING + SCALING - 1];
101 assert(len < SCALING);
103 for (i = 0; i < SCALING; ++i)
104 hashes[i] = htonl(hashes[i]);
106 /* run FNV-1a over the interleaved checksums plus the remaining
107 (odd-lotted) input data */
108 memcpy(final_data, hashes, sizeof(apr_uint32_t) * SCALING);
110 memcpy(final_data + sizeof(apr_uint32_t) * SCALING, input, len);
112 return fnv1a_32(FNV1_BASE_32,
114 sizeof(apr_uint32_t) * SCALING + len);
118 svn__fnv1a_32(const void *input, apr_size_t len)
120 return fnv1a_32(FNV1_BASE_32, input, len);
124 svn__fnv1a_32x4(const void *input, apr_size_t len)
126 apr_uint32_t hashes[SCALING]
127 = { FNV1_BASE_32, FNV1_BASE_32, FNV1_BASE_32, FNV1_BASE_32 };
128 apr_size_t processed = fnv1a_32x4(hashes, input, len);
130 return finalize_fnv1a_32x4(hashes,
131 (const char *)input + processed,
136 svn__fnv1a_32x4_raw(apr_uint32_t hashes[4],
140 apr_size_t processed;
143 for (i = 0; i < SCALING; ++i)
144 hashes[i] = FNV1_BASE_32;
146 /* Process full 16 byte chunks. */
147 processed = fnv1a_32x4(hashes, input, len);
149 /* Fold the remainder (if any) into the first hash. */
150 hashes[0] = fnv1a_32(hashes[0], (const char *)input + processed,
154 struct svn_fnv1a_32__context_t
159 svn_fnv1a_32__context_t *
160 svn_fnv1a_32__context_create(apr_pool_t *pool)
162 svn_fnv1a_32__context_t *context = apr_palloc(pool, sizeof(*context));
163 context->hash = FNV1_BASE_32;
169 svn_fnv1a_32__update(svn_fnv1a_32__context_t *context,
173 context->hash = fnv1a_32(context->hash, data, len);
177 svn_fnv1a_32__finalize(svn_fnv1a_32__context_t *context)
179 return context->hash;
183 struct svn_fnv1a_32x4__context_t
185 apr_uint32_t hashes[SCALING];
187 char buffer[SCALING];
190 svn_fnv1a_32x4__context_t *
191 svn_fnv1a_32x4__context_create(apr_pool_t *pool)
193 svn_fnv1a_32x4__context_t *context = apr_palloc(pool, sizeof(*context));
195 context->hashes[0] = FNV1_BASE_32;
196 context->hashes[1] = FNV1_BASE_32;
197 context->hashes[2] = FNV1_BASE_32;
198 context->hashes[3] = FNV1_BASE_32;
200 context->buffered = 0;
206 svn_fnv1a_32x4__update(svn_fnv1a_32x4__context_t *context,
210 apr_size_t processed;
212 if (context->buffered)
214 apr_size_t to_copy = SCALING - context->buffered;
217 memcpy(context->buffer + context->buffered, data, len);
218 context->buffered += len;
222 memcpy(context->buffer + context->buffered, data, to_copy);
223 data = (const char *)data + to_copy;
226 fnv1a_32x4(context->hashes, context->buffer, SCALING);
227 context->buffered = 0;
230 processed = fnv1a_32x4(context->hashes, data, len);
231 if (processed != len)
233 context->buffered = len - processed;
234 memcpy(context->buffer,
235 (const char*)data + processed,
241 svn_fnv1a_32x4__finalize(svn_fnv1a_32x4__context_t *context)
243 return finalize_fnv1a_32x4(context->hashes,