Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* |
2 | * Compute the Adler-32 checksum of a data stream. |
||
3 | * This is a modified version based on adler32.c from the zlib library. |
||
4 | * |
||
5 | * Copyright (C) 1995 Mark Adler |
||
6 | * |
||
7 | * This software is provided 'as-is', without any express or implied |
||
8 | * warranty. In no event will the authors be held liable for any damages |
||
9 | * arising from the use of this software. |
||
10 | * |
||
11 | * Permission is granted to anyone to use this software for any purpose, |
||
12 | * including commercial applications, and to alter it and redistribute it |
||
13 | * freely, subject to the following restrictions: |
||
14 | * |
||
15 | * 1. The origin of this software must not be misrepresented; you must not |
||
16 | * claim that you wrote the original software. If you use this software |
||
17 | * in a product, an acknowledgment in the product documentation would be |
||
18 | * appreciated but is not required. |
||
19 | * 2. Altered source versions must be plainly marked as such, and must not be |
||
20 | * misrepresented as being the original software. |
||
21 | * 3. This notice may not be removed or altered from any source distribution. |
||
22 | */ |
||
23 | |||
24 | #include "config.h" |
||
25 | #include "adler32.h" |
||
26 | #include "common.h" |
||
27 | #include "intreadwrite.h" |
||
28 | |||
29 | #define BASE 65521L /* largest prime smaller than 65536 */ |
||
30 | |||
31 | #define DO1(buf) { s1 += *buf++; s2 += s1; } |
||
32 | #define DO4(buf) DO1(buf); DO1(buf); DO1(buf); DO1(buf); |
||
33 | #define DO16(buf) DO4(buf); DO4(buf); DO4(buf); DO4(buf); |
||
34 | |||
35 | unsigned long av_adler32_update(unsigned long adler, const uint8_t * buf, |
||
36 | unsigned int len) |
||
37 | { |
||
38 | unsigned long s1 = adler & 0xffff; |
||
39 | unsigned long s2 = adler >> 16; |
||
40 | |||
41 | while (len > 0) { |
||
42 | #if HAVE_FAST_64BIT && HAVE_FAST_UNALIGNED && !CONFIG_SMALL |
||
43 | unsigned len2 = FFMIN((len-1) & ~7, 23*8); |
||
44 | if (len2) { |
||
45 | uint64_t a1= 0; |
||
46 | uint64_t a2= 0; |
||
47 | uint64_t b1= 0; |
||
48 | uint64_t b2= 0; |
||
49 | len -= len2; |
||
50 | s2 += s1*len2; |
||
51 | while (len2 >= 8) { |
||
52 | uint64_t v = AV_RN64(buf); |
||
53 | a2 += a1; |
||
54 | b2 += b1; |
||
55 | a1 += v &0x00FF00FF00FF00FF; |
||
56 | b1 += (v>>8)&0x00FF00FF00FF00FF; |
||
57 | len2 -= 8; |
||
58 | buf+=8; |
||
59 | } |
||
60 | |||
61 | //We combine the 8 interleaved adler32 checksums without overflows |
||
62 | //Decreasing the number of iterations would allow below code to be |
||
63 | //simplified but would likely be slower due to the fewer iterations |
||
64 | //of the inner loop |
||
65 | s1 += ((a1+b1)*0x1000100010001)>>48; |
||
66 | s2 += ((((a2&0xFFFF0000FFFF)+(b2&0xFFFF0000FFFF)+((a2>>16)&0xFFFF0000FFFF)+((b2>>16)&0xFFFF0000FFFF))*0x800000008)>>32) |
||
67 | #if HAVE_BIGENDIAN |
||
68 | + 2*((b1*0x1000200030004)>>48) |
||
69 | + ((a1*0x1000100010001)>>48) |
||
70 | + 2*((a1*0x0000100020003)>>48); |
||
71 | #else |
||
72 | + 2*((a1*0x4000300020001)>>48) |
||
73 | + ((b1*0x1000100010001)>>48) |
||
74 | + 2*((b1*0x3000200010000)>>48); |
||
75 | #endif |
||
76 | } |
||
77 | #else |
||
78 | while (len > 4 && s2 < (1U << 31)) { |
||
79 | DO4(buf); |
||
80 | len -= 4; |
||
81 | } |
||
82 | #endif |
||
83 | DO1(buf); len--; |
||
84 | s1 %= BASE; |
||
85 | s2 %= BASE; |
||
86 | } |
||
87 | return (s2 << 16) | s1; |
||
88 | } |
||
89 | |||
90 | #ifdef TEST |
||
91 | // LCOV_EXCL_START |
||
92 | #include |
||
93 | #include "log.h" |
||
94 | #include "timer.h" |
||
95 | #define LEN 7001 |
||
96 | |||
97 | static volatile int checksum; |
||
98 | |||
99 | int main(int argc, char **argv) |
||
100 | { |
||
101 | int i; |
||
102 | char data[LEN]; |
||
103 | |||
104 | av_log_set_level(AV_LOG_DEBUG); |
||
105 | |||
106 | for (i = 0; i < LEN; i++) |
||
107 | data[i] = ((i * i) >> 3) + 123 * i; |
||
108 | |||
109 | if (argc > 1 && !strcmp(argv[1], "-t")) { |
||
110 | for (i = 0; i < 1000; i++) { |
||
111 | START_TIMER; |
||
112 | checksum = av_adler32_update(1, data, LEN); |
||
113 | STOP_TIMER("adler"); |
||
114 | } |
||
115 | } else { |
||
116 | checksum = av_adler32_update(1, data, LEN); |
||
117 | } |
||
118 | |||
119 | av_log(NULL, AV_LOG_DEBUG, "%X (expected 50E6E508)\n", checksum); |
||
120 | return checksum == 0x50e6e508 ? 0 : 1; |
||
121 | } |
||
122 | // LCOV_EXCL_STOP |
||
123 | #endif>>><>><>> |