Coverage Report

Created: 2026-02-14 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/alembic/lib/Alembic/Util/SpookyV2.cpp
Line
Count
Source
1
//-*****************************************************************************
2
//
3
// Copyright (c) 2013,
4
//  Sony Pictures Imageworks Inc. and
5
//  Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd.
6
//
7
// All rights reserved.
8
//
9
// Redistribution and use in source and binary forms, with or without
10
// modification, are permitted provided that the following conditions are
11
// met:
12
// *       Redistributions of source code must retain the above copyright
13
// notice, this list of conditions and the following disclaimer.
14
// *       Redistributions in binary form must reproduce the above
15
// copyright notice, this list of conditions and the following disclaimer
16
// in the documentation and/or other materials provided with the
17
// distribution.
18
// *       Neither the name of Industrial Light & Magic nor the names of
19
// its contributors may be used to endorse or promote products derived
20
// from this software without specific prior written permission.
21
//
22
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
//
34
//-*****************************************************************************
35
36
37
// Spooky Hash
38
// A 128-bit noncryptographic hash, for checksums and table lookup
39
// By Bob Jenkins.  Public domain.
40
//   Oct 31 2010: published framework, disclaimer ShortHash isn't right
41
//   Nov 7 2010: disabled ShortHash
42
//   Oct 31 2011: replace End, ShortMix, ShortEnd, enable ShortHash again
43
//   April 10 2012: buffer overflow on platforms without unaligned reads
44
//   July 12 2012: was passing out variables in final to in/out in short
45
//   July 30 2012: I reintroduced the buffer overflow
46
//   August 5 2012: SpookyV2: d = should be d += in short hash, and remove extra mix from long hash
47
48
#include <memory.h>
49
#include "SpookyV2.h"
50
51
0
#define ALLOW_UNALIGNED_READS 1
52
53
namespace Alembic {
54
namespace Util {
55
namespace ALEMBIC_VERSION_NS {
56
57
//
58
// short hash ... it could be used on any message,
59
// but it's used by Spooky just for short messages.
60
//
61
void SpookyHash::Short(
62
    const void *message,
63
    size_t length,
64
    uint64_t *hash1,
65
    uint64_t *hash2)
66
0
{
67
0
    uint64_t buf[2*sc_numVars];
68
0
    union
69
0
    {
70
0
        const uint8_t *p8;
71
0
        uint32_t *p32;
72
0
        uint64_t *p64;
73
0
        size_t i;
74
0
    } u;
75
76
0
    u.p8 = (const uint8_t *)message;
77
78
0
    if (!ALLOW_UNALIGNED_READS && (u.i & 0x7))
79
0
    {
80
0
        memcpy(buf, message, length);
81
0
        u.p64 = buf;
82
0
    }
83
84
0
    size_t remainder = length%32;
85
0
    uint64_t a=*hash1;
86
0
    uint64_t b=*hash2;
87
0
    uint64_t c=sc_const;
88
0
    uint64_t d=sc_const;
89
90
0
    if (length > 15)
91
0
    {
92
0
        const uint64_t *end = u.p64 + (length/32)*4;
93
94
        // handle all complete sets of 32 bytes
95
0
        for (; u.p64 < end; u.p64 += 4)
96
0
        {
97
0
            c += u.p64[0];
98
0
            d += u.p64[1];
99
0
            ShortMix(a,b,c,d);
100
0
            a += u.p64[2];
101
0
            b += u.p64[3];
102
0
        }
103
104
        //Handle the case of 16+ remaining bytes.
105
0
        if (remainder >= 16)
106
0
        {
107
0
            c += u.p64[0];
108
0
            d += u.p64[1];
109
0
            ShortMix(a,b,c,d);
110
0
            u.p64 += 2;
111
0
            remainder -= 16;
112
0
        }
113
0
    }
114
115
    // Handle the last 0..15 bytes, and its length
116
0
    d += ((uint64_t)length) << 56;
117
0
    switch (remainder)
118
0
    {
119
0
    case 15:
120
0
    d += ((uint64_t)u.p8[14]) << 48;
121
0
    case 14:
122
0
        d += ((uint64_t)u.p8[13]) << 40;
123
0
    case 13:
124
0
        d += ((uint64_t)u.p8[12]) << 32;
125
0
    case 12:
126
0
        d += u.p32[2];
127
0
        c += u.p64[0];
128
0
        break;
129
0
    case 11:
130
0
        d += ((uint64_t)u.p8[10]) << 16;
131
0
    case 10:
132
0
        d += ((uint64_t)u.p8[9]) << 8;
133
0
    case 9:
134
0
        d += (uint64_t)u.p8[8];
135
0
    case 8:
136
0
        c += u.p64[0];
137
0
        break;
138
0
    case 7:
139
0
        c += ((uint64_t)u.p8[6]) << 48;
140
0
    case 6:
141
0
        c += ((uint64_t)u.p8[5]) << 40;
142
0
    case 5:
143
0
        c += ((uint64_t)u.p8[4]) << 32;
144
0
    case 4:
145
0
        c += u.p32[0];
146
0
        break;
147
0
    case 3:
148
0
        c += ((uint64_t)u.p8[2]) << 16;
149
0
    case 2:
150
0
        c += ((uint64_t)u.p8[1]) << 8;
151
0
    case 1:
152
0
        c += (uint64_t)u.p8[0];
153
0
        break;
154
0
    case 0:
155
0
        c += sc_const;
156
0
        d += sc_const;
157
0
    }
158
0
    ShortEnd(a,b,c,d);
159
0
    *hash1 = a;
160
0
    *hash2 = b;
161
0
}
162
163
164
165
166
// do the whole hash in one call
167
void SpookyHash::Hash128(
168
    const void *message,
169
    size_t length,
170
    uint64_t *hash1,
171
    uint64_t *hash2)
172
0
{
173
0
    if (length < sc_bufSize)
174
0
    {
175
0
        Short(message, length, hash1, hash2);
176
0
        return;
177
0
    }
178
179
0
    uint64_t h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
180
0
    uint64_t buf[sc_numVars];
181
0
    uint64_t *end;
182
0
    union
183
0
    {
184
0
        const uint8_t *p8;
185
0
        uint64_t *p64;
186
0
        size_t i;
187
0
    } u;
188
0
    size_t remainder;
189
190
0
    h0=h3=h6=h9  = *hash1;
191
0
    h1=h4=h7=h10 = *hash2;
192
0
    h2=h5=h8=h11 = sc_const;
193
194
0
    u.p8 = (const uint8_t *)message;
195
0
    end = u.p64 + (length/sc_blockSize)*sc_numVars;
196
197
    // handle all whole sc_blockSize blocks of bytes
198
0
    if (ALLOW_UNALIGNED_READS || ((u.i & 0x7) == 0))
199
0
    {
200
0
        while (u.p64 < end)
201
0
        {
202
0
            Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
203
0
            u.p64 += sc_numVars;
204
0
        }
205
0
    }
206
0
    else
207
0
    {
208
0
        while (u.p64 < end)
209
0
        {
210
0
            memcpy(buf, u.p64, sc_blockSize);
211
0
            Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
212
0
            u.p64 += sc_numVars;
213
0
        }
214
0
    }
215
216
    // handle the last partial block of sc_blockSize bytes
217
0
    remainder = (length - ((const uint8_t *)end-(const uint8_t *)message));
218
0
    memcpy(buf, end, remainder);
219
0
    memset(((uint8_t *)buf)+remainder, 0, sc_blockSize-remainder);
220
0
    ((uint8_t *)buf)[sc_blockSize-1] = remainder;
221
222
    // do some final mixing
223
0
    End(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
224
0
    *hash1 = h0;
225
0
    *hash2 = h1;
226
0
}
227
228
229
230
// init spooky state
231
void SpookyHash::Init(uint64_t seed1, uint64_t seed2)
232
0
{
233
0
    m_length = 0;
234
0
    m_remainder = 0;
235
0
    m_state[0] = seed1;
236
0
    m_state[1] = seed2;
237
0
}
238
239
240
// add a message fragment to the state
241
void SpookyHash::Update(const void *message, size_t length)
242
0
{
243
0
    uint64_t h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
244
0
    size_t newLength = length + m_remainder;
245
0
    uint8_t  remainder;
246
0
    union
247
0
    {
248
0
        const uint8_t *p8;
249
0
        uint64_t *p64;
250
0
        size_t i;
251
0
    } u;
252
0
    const uint64_t *end;
253
254
    // Is this message fragment too short?  If it is, stuff it away.
255
0
    if (newLength < sc_bufSize)
256
0
    {
257
0
        memcpy(&((uint8_t *)m_data)[m_remainder], message, length);
258
0
        m_length = length + m_length;
259
0
        m_remainder = (uint8_t)newLength;
260
0
        return;
261
0
    }
262
263
    // init the variables
264
0
    if (m_length < sc_bufSize)
265
0
    {
266
0
        h0=h3=h6=h9  = m_state[0];
267
0
        h1=h4=h7=h10 = m_state[1];
268
0
        h2=h5=h8=h11 = sc_const;
269
0
    }
270
0
    else
271
0
    {
272
0
        h0 = m_state[0];
273
0
        h1 = m_state[1];
274
0
        h2 = m_state[2];
275
0
        h3 = m_state[3];
276
0
        h4 = m_state[4];
277
0
        h5 = m_state[5];
278
0
        h6 = m_state[6];
279
0
        h7 = m_state[7];
280
0
        h8 = m_state[8];
281
0
        h9 = m_state[9];
282
0
        h10 = m_state[10];
283
0
        h11 = m_state[11];
284
0
    }
285
0
    m_length = length + m_length;
286
287
    // if we've got anything stuffed away, use it now
288
0
    if (m_remainder)
289
0
    {
290
0
        uint8_t prefix = sc_bufSize-m_remainder;
291
0
        memcpy(&(((uint8_t *)m_data)[m_remainder]), message, prefix);
292
0
        u.p64 = m_data;
293
0
        Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
294
0
        Mix(&u.p64[sc_numVars], h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
295
0
        u.p8 = ((const uint8_t *)message) + prefix;
296
0
        length -= prefix;
297
0
    }
298
0
    else
299
0
    {
300
0
        u.p8 = (const uint8_t *)message;
301
0
    }
302
303
    // handle all whole blocks of sc_blockSize bytes
304
0
    end = u.p64 + (length/sc_blockSize)*sc_numVars;
305
0
    remainder = (uint8_t)(length-((const uint8_t *)end-u.p8));
306
0
    if (ALLOW_UNALIGNED_READS || (u.i & 0x7) == 0)
307
0
    {
308
0
        while (u.p64 < end)
309
0
        {
310
0
            Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
311
0
            u.p64 += sc_numVars;
312
0
        }
313
0
    }
314
0
    else
315
0
    {
316
0
        while (u.p64 < end)
317
0
        {
318
0
            memcpy(m_data, u.p8, sc_blockSize);
319
0
            Mix(m_data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
320
0
            u.p64 += sc_numVars;
321
0
        }
322
0
    }
323
324
    // stuff away the last few bytes
325
0
    m_remainder = remainder;
326
0
    memcpy(m_data, end, remainder);
327
328
    // stuff away the variables
329
0
    m_state[0] = h0;
330
0
    m_state[1] = h1;
331
0
    m_state[2] = h2;
332
0
    m_state[3] = h3;
333
0
    m_state[4] = h4;
334
0
    m_state[5] = h5;
335
0
    m_state[6] = h6;
336
0
    m_state[7] = h7;
337
0
    m_state[8] = h8;
338
0
    m_state[9] = h9;
339
0
    m_state[10] = h10;
340
0
    m_state[11] = h11;
341
0
}
342
343
344
// report the hash for the concatenation of all message fragments so far
345
void SpookyHash::Final(uint64_t *hash1, uint64_t *hash2)
346
0
{
347
    // init the variables
348
0
    if (m_length < sc_bufSize)
349
0
    {
350
0
        *hash1 = m_state[0];
351
0
        *hash2 = m_state[1];
352
0
        Short( m_data, m_length, hash1, hash2);
353
0
        return;
354
0
    }
355
356
0
    const uint64_t *data = (const uint64_t *)m_data;
357
0
    uint8_t remainder = m_remainder;
358
359
0
    uint64_t h0 = m_state[0];
360
0
    uint64_t h1 = m_state[1];
361
0
    uint64_t h2 = m_state[2];
362
0
    uint64_t h3 = m_state[3];
363
0
    uint64_t h4 = m_state[4];
364
0
    uint64_t h5 = m_state[5];
365
0
    uint64_t h6 = m_state[6];
366
0
    uint64_t h7 = m_state[7];
367
0
    uint64_t h8 = m_state[8];
368
0
    uint64_t h9 = m_state[9];
369
0
    uint64_t h10 = m_state[10];
370
0
    uint64_t h11 = m_state[11];
371
372
0
    if (remainder >= sc_blockSize)
373
0
    {
374
        // m_data can contain two blocks; handle any whole first block
375
0
        Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
376
0
        data += sc_numVars;
377
0
        remainder -= sc_blockSize;
378
0
    }
379
380
    // mix in the last partial block, and the length mod sc_blockSize
381
0
    memset(&((uint8_t *)data)[remainder], 0, (sc_blockSize-remainder));
382
383
0
    ((uint8_t *)data)[sc_blockSize-1] = remainder;
384
385
    // do some final mixing
386
0
    End(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
387
388
0
    *hash1 = h0;
389
0
    *hash2 = h1;
390
0
}
391
392
} // End namespace ALEMBIC_VERSION_NS
393
} // End namespace Util
394
} // End namespace Alembic