1/* crc32.c -- compute the CRC-32 of a data stream
2 * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016, 2018 Mark Adler
3 * For conditions of distribution and use, see copyright notice in zlib.h
4 *
5 * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
6 * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
7 * tables for updating the shift register in one step with three exclusive-ors
8 * instead of four steps with four exclusive-ors. This results in about a
9 * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
10 */
11
12#include "zbuild.h"
13#include "zendian.h"
14#include <inttypes.h>
15#include "deflate.h"
16#include "functable.h"
17#include "crc32_tbl.h"
18
19/* =========================================================================
20 * This function can be used by asm versions of crc32()
21 */
22const uint32_t * Z_EXPORT PREFIX(get_crc_table)(void) {
23 return (const uint32_t *)crc_table;
24}
25
26#ifdef ZLIB_COMPAT
27unsigned long Z_EXPORT PREFIX(crc32_z)(unsigned long crc, const unsigned char *buf, size_t len) {
28 if (buf == NULL) return 0;
29
30 return (unsigned long)functable.crc32((uint32_t)crc, buf, len);
31}
32#else
33uint32_t Z_EXPORT PREFIX(crc32_z)(uint32_t crc, const unsigned char *buf, size_t len) {
34 if (buf == NULL) return 0;
35
36 return functable.crc32(crc, buf, len);
37}
38#endif
39/* ========================================================================= */
40#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
41#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
42#define DO4 DO1; DO1; DO1; DO1
43
44/* ========================================================================= */
45Z_INTERNAL uint32_t crc32_generic(uint32_t crc, const unsigned char *buf, uint64_t len) {
46 crc = crc ^ 0xffffffff;
47
48#ifdef UNROLL_MORE
49 while (len >= 8) {
50 DO8;
51 len -= 8;
52 }
53#else
54 while (len >= 4) {
55 DO4;
56 len -= 4;
57 }
58#endif
59
60 if (len) do {
61 DO1;
62 } while (--len);
63 return crc ^ 0xffffffff;
64}
65
66#ifdef ZLIB_COMPAT
67unsigned long Z_EXPORT PREFIX(crc32)(unsigned long crc, const unsigned char *buf, unsigned int len) {
68 return (unsigned long)PREFIX(crc32_z)(crc: (uint32_t)crc, buf, len);
69}
70#else
71uint32_t Z_EXPORT PREFIX(crc32)(uint32_t crc, const unsigned char *buf, uint32_t len) {
72 return PREFIX(crc32_z)(crc, buf, len);
73}
74#endif
75
76/*
77 This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit
78 integer pointer type. This violates the strict aliasing rule, where a
79 compiler can assume, for optimization purposes, that two pointers to
80 fundamentally different types won't ever point to the same memory. This can
81 manifest as a problem only if one of the pointers is written to. This code
82 only reads from those pointers. So long as this code remains isolated in
83 this compilation unit, there won't be a problem. For this reason, this code
84 should not be copied and pasted into a compilation unit in which other code
85 writes to the buffer that is passed to these routines.
86 */
87
88/* ========================================================================= */
89#if BYTE_ORDER == LITTLE_ENDIAN
90#define DOLIT4 c ^= *buf4++; \
91 c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
92 crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
93#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
94
95/* ========================================================================= */
96Z_INTERNAL uint32_t crc32_little(uint32_t crc, const unsigned char *buf, uint64_t len) {
97 Z_REGISTER uint32_t c;
98 Z_REGISTER const uint32_t *buf4;
99
100 c = crc;
101 c = ~c;
102 while (len && ((ptrdiff_t)buf & 3)) {
103 c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
104 len--;
105 }
106
107 buf4 = (const uint32_t *)(const void *)buf;
108
109#ifdef UNROLL_MORE
110 while (len >= 32) {
111 DOLIT32;
112 len -= 32;
113 }
114#endif
115
116 while (len >= 4) {
117 DOLIT4;
118 len -= 4;
119 }
120 buf = (const unsigned char *)buf4;
121
122 if (len) do {
123 c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
124 } while (--len);
125 c = ~c;
126 return c;
127}
128#endif /* BYTE_ORDER == LITTLE_ENDIAN */
129
130/* ========================================================================= */
131#if BYTE_ORDER == BIG_ENDIAN
132#define DOBIG4 c ^= *buf4++; \
133 c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
134 crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
135#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
136
137/* ========================================================================= */
138Z_INTERNAL uint32_t crc32_big(uint32_t crc, const unsigned char *buf, uint64_t len) {
139 Z_REGISTER uint32_t c;
140 Z_REGISTER const uint32_t *buf4;
141
142 c = ZSWAP32(crc);
143 c = ~c;
144 while (len && ((ptrdiff_t)buf & 3)) {
145 c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
146 len--;
147 }
148
149 buf4 = (const uint32_t *)(const void *)buf;
150
151#ifdef UNROLL_MORE
152 while (len >= 32) {
153 DOBIG32;
154 len -= 32;
155 }
156#endif
157
158 while (len >= 4) {
159 DOBIG4;
160 len -= 4;
161 }
162 buf = (const unsigned char *)buf4;
163
164 if (len) do {
165 c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
166 } while (--len);
167 c = ~c;
168 return ZSWAP32(c);
169}
170#endif /* BYTE_ORDER == BIG_ENDIAN */
171
172#ifdef X86_PCLMULQDQ_CRC
173#include "arch/x86/x86.h"
174#include "arch/x86/crc_folding.h"
175
176Z_INTERNAL void crc_finalize(deflate_state *const s) {
177 if (x86_cpu_has_pclmulqdq)
178 s->strm->adler = crc_fold_512to32(s);
179}
180#endif
181
182Z_INTERNAL void crc_reset(deflate_state *const s) {
183#ifdef X86_PCLMULQDQ_CRC
184 x86_check_features();
185 if (x86_cpu_has_pclmulqdq) {
186 crc_fold_init(s);
187 return;
188 }
189#endif
190 s->strm->adler = PREFIX(crc32)(crc: 0L, NULL, len: 0);
191}
192
193Z_INTERNAL void copy_with_crc(PREFIX3(stream) *strm, unsigned char *dst, unsigned long size) {
194#ifdef X86_PCLMULQDQ_CRC
195 if (x86_cpu_has_pclmulqdq) {
196 crc_fold_copy(strm->state, dst, strm->next_in, size);
197 return;
198 }
199#endif
200 memcpy(dest: dst, src: strm->next_in, n: size);
201 strm->adler = PREFIX(crc32)(crc: strm->adler, buf: dst, len: size);
202}
203