xref: /plan9/sys/src/cmd/gs/zlib/crc32.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* crc32.c -- compute the CRC-32 of a data stream
2*593dc095SDavid du Colombier  * Copyright (C) 1995-2003 Mark Adler
37dd7cddfSDavid du Colombier  * For conditions of distribution and use, see copyright notice in zlib.h
4*593dc095SDavid du Colombier  *
5*593dc095SDavid du Colombier  * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
6*593dc095SDavid du Colombier  * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
7*593dc095SDavid du Colombier  * tables for updating the shift register in one step with three exclusive-ors
8*593dc095SDavid du Colombier  * instead of four steps with four exclusive-ors.  This results about a factor
9*593dc095SDavid du Colombier  * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
107dd7cddfSDavid du Colombier  */
117dd7cddfSDavid du Colombier 
12*593dc095SDavid du Colombier /* @(#) $Id: crc32.c,v 1.1.1.1 2005/04/24 21:39:37 giles Exp $ */
137dd7cddfSDavid du Colombier 
14*593dc095SDavid du Colombier /*
15*593dc095SDavid du Colombier   Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
16*593dc095SDavid du Colombier   protection on the static variables used to control the first-use generation
17*593dc095SDavid du Colombier   of the crc tables.  Therefore, if you #define DYNAMIC_CRC_TABLE, you should
18*593dc095SDavid du Colombier   first call get_crc_table() to initialize the tables before allowing more than
19*593dc095SDavid du Colombier   one thread to use crc32().
20*593dc095SDavid du Colombier  */
21*593dc095SDavid du Colombier 
22*593dc095SDavid du Colombier #ifdef MAKECRCH
23*593dc095SDavid du Colombier #  include <stdio.h>
24*593dc095SDavid du Colombier #  ifndef DYNAMIC_CRC_TABLE
25*593dc095SDavid du Colombier #    define DYNAMIC_CRC_TABLE
26*593dc095SDavid du Colombier #  endif /* !DYNAMIC_CRC_TABLE */
27*593dc095SDavid du Colombier #endif /* MAKECRCH */
28*593dc095SDavid du Colombier 
29*593dc095SDavid du Colombier #include "zutil.h"      /* for STDC and FAR definitions */
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier #define local static
327dd7cddfSDavid du Colombier 
33*593dc095SDavid du Colombier /* Find a four-byte integer type for crc32_little() and crc32_big(). */
34*593dc095SDavid du Colombier #ifndef NOBYFOUR
35*593dc095SDavid du Colombier #  ifdef STDC           /* need ANSI C limits.h to determine sizes */
36*593dc095SDavid du Colombier #    include <limits.h>
37*593dc095SDavid du Colombier #    define BYFOUR
38*593dc095SDavid du Colombier #    if (UINT_MAX == 0xffffffffUL)
39*593dc095SDavid du Colombier        typedef unsigned int u4;
40*593dc095SDavid du Colombier #    else
41*593dc095SDavid du Colombier #      if (ULONG_MAX == 0xffffffffUL)
42*593dc095SDavid du Colombier          typedef unsigned long u4;
43*593dc095SDavid du Colombier #      else
44*593dc095SDavid du Colombier #        if (USHRT_MAX == 0xffffffffUL)
45*593dc095SDavid du Colombier            typedef unsigned short u4;
46*593dc095SDavid du Colombier #        else
47*593dc095SDavid du Colombier #          undef BYFOUR     /* can't find a four-byte integer type! */
48*593dc095SDavid du Colombier #        endif
49*593dc095SDavid du Colombier #      endif
50*593dc095SDavid du Colombier #    endif
51*593dc095SDavid du Colombier #  endif /* STDC */
52*593dc095SDavid du Colombier #endif /* !NOBYFOUR */
53*593dc095SDavid du Colombier 
54*593dc095SDavid du Colombier /* Definitions for doing the crc four data bytes at a time. */
55*593dc095SDavid du Colombier #ifdef BYFOUR
56*593dc095SDavid du Colombier #  define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
57*593dc095SDavid du Colombier                 (((w)&0xff00)<<8)+(((w)&0xff)<<24))
58*593dc095SDavid du Colombier    local unsigned long crc32_little OF((unsigned long,
59*593dc095SDavid du Colombier                         const unsigned char FAR *, unsigned));
60*593dc095SDavid du Colombier    local unsigned long crc32_big OF((unsigned long,
61*593dc095SDavid du Colombier                         const unsigned char FAR *, unsigned));
62*593dc095SDavid du Colombier #  define TBLS 8
63*593dc095SDavid du Colombier #else
64*593dc095SDavid du Colombier #  define TBLS 1
65*593dc095SDavid du Colombier #endif /* BYFOUR */
66*593dc095SDavid du Colombier 
677dd7cddfSDavid du Colombier #ifdef DYNAMIC_CRC_TABLE
687dd7cddfSDavid du Colombier 
69*593dc095SDavid du Colombier local volatile int crc_table_empty = 1;
70*593dc095SDavid du Colombier local unsigned long FAR crc_table[TBLS][256];
717dd7cddfSDavid du Colombier local void make_crc_table OF((void));
72*593dc095SDavid du Colombier #ifdef MAKECRCH
73*593dc095SDavid du Colombier    local void write_table OF((FILE *, const unsigned long FAR *));
74*593dc095SDavid du Colombier #endif /* MAKECRCH */
757dd7cddfSDavid du Colombier 
767dd7cddfSDavid du Colombier /*
77*593dc095SDavid du Colombier   Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
787dd7cddfSDavid du Colombier   x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
797dd7cddfSDavid du Colombier 
807dd7cddfSDavid du Colombier   Polynomials over GF(2) are represented in binary, one bit per coefficient,
817dd7cddfSDavid du Colombier   with the lowest powers in the most significant bit.  Then adding polynomials
827dd7cddfSDavid du Colombier   is just exclusive-or, and multiplying a polynomial by x is a right shift by
837dd7cddfSDavid du Colombier   one.  If we call the above polynomial p, and represent a byte as the
847dd7cddfSDavid du Colombier   polynomial q, also with the lowest power in the most significant bit (so the
857dd7cddfSDavid du Colombier   byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
867dd7cddfSDavid du Colombier   where a mod b means the remainder after dividing a by b.
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier   This calculation is done using the shift-register method of multiplying and
897dd7cddfSDavid du Colombier   taking the remainder.  The register is initialized to zero, and for each
907dd7cddfSDavid du Colombier   incoming bit, x^32 is added mod p to the register if the bit is a one (where
917dd7cddfSDavid du Colombier   x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
927dd7cddfSDavid du Colombier   x (which is shifting right by one and adding x^32 mod p if the bit shifted
937dd7cddfSDavid du Colombier   out is a one).  We start with the highest power (least significant bit) of
947dd7cddfSDavid du Colombier   q and repeat for all eight bits of q.
957dd7cddfSDavid du Colombier 
96*593dc095SDavid du Colombier   The first table is simply the CRC of all possible eight bit values.  This is
97*593dc095SDavid du Colombier   all the information needed to generate CRCs on data a byte at a time for all
98*593dc095SDavid du Colombier   combinations of CRC register values and incoming bytes.  The remaining tables
99*593dc095SDavid du Colombier   allow for word-at-a-time CRC calculation for both big-endian and little-
100*593dc095SDavid du Colombier   endian machines, where a word is four bytes.
1017dd7cddfSDavid du Colombier */
make_crc_table()1027dd7cddfSDavid du Colombier local void make_crc_table()
1037dd7cddfSDavid du Colombier {
104*593dc095SDavid du Colombier     unsigned long c;
1057dd7cddfSDavid du Colombier     int n, k;
106*593dc095SDavid du Colombier     unsigned long poly;                 /* polynomial exclusive-or pattern */
1077dd7cddfSDavid du Colombier     /* terms of polynomial defining this crc (except x^32): */
108*593dc095SDavid du Colombier     static volatile int first = 1;      /* flag to limit concurrent making */
109*593dc095SDavid du Colombier     static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
1107dd7cddfSDavid du Colombier 
111*593dc095SDavid du Colombier     /* See if another task is already doing this (not thread-safe, but better
112*593dc095SDavid du Colombier        than nothing -- significantly reduces duration of vulnerability in
113*593dc095SDavid du Colombier        case the advice about DYNAMIC_CRC_TABLE is ignored) */
114*593dc095SDavid du Colombier     if (first) {
115*593dc095SDavid du Colombier         first = 0;
1167dd7cddfSDavid du Colombier 
117*593dc095SDavid du Colombier         /* make exclusive-or pattern from polynomial (0xedb88320UL) */
118*593dc095SDavid du Colombier         poly = 0UL;
119*593dc095SDavid du Colombier         for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
120*593dc095SDavid du Colombier             poly |= 1UL << (31 - p[n]);
121*593dc095SDavid du Colombier 
122*593dc095SDavid du Colombier         /* generate a crc for every 8-bit value */
123*593dc095SDavid du Colombier         for (n = 0; n < 256; n++) {
124*593dc095SDavid du Colombier             c = (unsigned long)n;
1257dd7cddfSDavid du Colombier             for (k = 0; k < 8; k++)
1267dd7cddfSDavid du Colombier                 c = c & 1 ? poly ^ (c >> 1) : c >> 1;
127*593dc095SDavid du Colombier             crc_table[0][n] = c;
1287dd7cddfSDavid du Colombier         }
129*593dc095SDavid du Colombier 
130*593dc095SDavid du Colombier #ifdef BYFOUR
131*593dc095SDavid du Colombier         /* generate crc for each value followed by one, two, and three zeros,
132*593dc095SDavid du Colombier            and then the byte reversal of those as well as the first table */
133*593dc095SDavid du Colombier         for (n = 0; n < 256; n++) {
134*593dc095SDavid du Colombier             c = crc_table[0][n];
135*593dc095SDavid du Colombier             crc_table[4][n] = REV(c);
136*593dc095SDavid du Colombier             for (k = 1; k < 4; k++) {
137*593dc095SDavid du Colombier                 c = crc_table[0][c & 0xff] ^ (c >> 8);
138*593dc095SDavid du Colombier                 crc_table[k][n] = c;
139*593dc095SDavid du Colombier                 crc_table[k + 4][n] = REV(c);
140*593dc095SDavid du Colombier             }
141*593dc095SDavid du Colombier         }
142*593dc095SDavid du Colombier #endif /* BYFOUR */
143*593dc095SDavid du Colombier 
1447dd7cddfSDavid du Colombier         crc_table_empty = 0;
1457dd7cddfSDavid du Colombier     }
146*593dc095SDavid du Colombier     else {      /* not first */
147*593dc095SDavid du Colombier         /* wait for the other guy to finish (not efficient, but rare) */
148*593dc095SDavid du Colombier         while (crc_table_empty)
149*593dc095SDavid du Colombier             ;
150*593dc095SDavid du Colombier     }
151*593dc095SDavid du Colombier 
152*593dc095SDavid du Colombier #ifdef MAKECRCH
153*593dc095SDavid du Colombier     /* write out CRC tables to crc32.h */
154*593dc095SDavid du Colombier     {
155*593dc095SDavid du Colombier         FILE *out;
156*593dc095SDavid du Colombier 
157*593dc095SDavid du Colombier         out = fopen("crc32.h", "w");
158*593dc095SDavid du Colombier         if (out == NULL) return;
159*593dc095SDavid du Colombier         fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
160*593dc095SDavid du Colombier         fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
161*593dc095SDavid du Colombier         fprintf(out, "local const unsigned long FAR ");
162*593dc095SDavid du Colombier         fprintf(out, "crc_table[TBLS][256] =\n{\n  {\n");
163*593dc095SDavid du Colombier         write_table(out, crc_table[0]);
164*593dc095SDavid du Colombier #  ifdef BYFOUR
165*593dc095SDavid du Colombier         fprintf(out, "#ifdef BYFOUR\n");
166*593dc095SDavid du Colombier         for (k = 1; k < 8; k++) {
167*593dc095SDavid du Colombier             fprintf(out, "  },\n  {\n");
168*593dc095SDavid du Colombier             write_table(out, crc_table[k]);
169*593dc095SDavid du Colombier         }
170*593dc095SDavid du Colombier         fprintf(out, "#endif\n");
171*593dc095SDavid du Colombier #  endif /* BYFOUR */
172*593dc095SDavid du Colombier         fprintf(out, "  }\n};\n");
173*593dc095SDavid du Colombier         fclose(out);
174*593dc095SDavid du Colombier     }
175*593dc095SDavid du Colombier #endif /* MAKECRCH */
176*593dc095SDavid du Colombier }
177*593dc095SDavid du Colombier 
178*593dc095SDavid du Colombier #ifdef MAKECRCH
write_table(out,table)179*593dc095SDavid du Colombier local void write_table(out, table)
180*593dc095SDavid du Colombier     FILE *out;
181*593dc095SDavid du Colombier     const unsigned long FAR *table;
182*593dc095SDavid du Colombier {
183*593dc095SDavid du Colombier     int n;
184*593dc095SDavid du Colombier 
185*593dc095SDavid du Colombier     for (n = 0; n < 256; n++)
186*593dc095SDavid du Colombier         fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : "    ", table[n],
187*593dc095SDavid du Colombier                 n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
188*593dc095SDavid du Colombier }
189*593dc095SDavid du Colombier #endif /* MAKECRCH */
190*593dc095SDavid du Colombier 
191*593dc095SDavid du Colombier #else /* !DYNAMIC_CRC_TABLE */
1927dd7cddfSDavid du Colombier /* ========================================================================
193*593dc095SDavid du Colombier  * Tables of CRC-32s of all single-byte values, made by make_crc_table().
1947dd7cddfSDavid du Colombier  */
195*593dc095SDavid du Colombier #include "crc32.h"
196*593dc095SDavid du Colombier #endif /* DYNAMIC_CRC_TABLE */
1977dd7cddfSDavid du Colombier 
1987dd7cddfSDavid du Colombier /* =========================================================================
1997dd7cddfSDavid du Colombier  * This function can be used by asm versions of crc32()
2007dd7cddfSDavid du Colombier  */
get_crc_table()201*593dc095SDavid du Colombier const unsigned long FAR * ZEXPORT get_crc_table()
2027dd7cddfSDavid du Colombier {
2037dd7cddfSDavid du Colombier #ifdef DYNAMIC_CRC_TABLE
2047dd7cddfSDavid du Colombier     if (crc_table_empty)
2057dd7cddfSDavid du Colombier         make_crc_table();
206*593dc095SDavid du Colombier #endif /* DYNAMIC_CRC_TABLE */
207*593dc095SDavid du Colombier     return (const unsigned long FAR *)crc_table;
208*593dc095SDavid du Colombier }
209*593dc095SDavid du Colombier 
210*593dc095SDavid du Colombier /* ========================================================================= */
211*593dc095SDavid du Colombier #define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
212*593dc095SDavid du Colombier #define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
213*593dc095SDavid du Colombier 
214*593dc095SDavid du Colombier /* ========================================================================= */
crc32(crc,buf,len)215*593dc095SDavid du Colombier unsigned long ZEXPORT crc32(crc, buf, len)
216*593dc095SDavid du Colombier     unsigned long crc;
217*593dc095SDavid du Colombier     const unsigned char FAR *buf;
218*593dc095SDavid du Colombier     unsigned len;
2197dd7cddfSDavid du Colombier {
220*593dc095SDavid du Colombier     if (buf == Z_NULL) return 0UL;
221*593dc095SDavid du Colombier 
222*593dc095SDavid du Colombier #ifdef DYNAMIC_CRC_TABLE
223*593dc095SDavid du Colombier     if (crc_table_empty)
224*593dc095SDavid du Colombier         make_crc_table();
225*593dc095SDavid du Colombier #endif /* DYNAMIC_CRC_TABLE */
226*593dc095SDavid du Colombier 
227*593dc095SDavid du Colombier #ifdef BYFOUR
228*593dc095SDavid du Colombier     if (sizeof(void *) == sizeof(ptrdiff_t)) {
229*593dc095SDavid du Colombier         u4 endian;
230*593dc095SDavid du Colombier 
231*593dc095SDavid du Colombier         endian = 1;
232*593dc095SDavid du Colombier         if (*((unsigned char *)(&endian)))
233*593dc095SDavid du Colombier             return crc32_little(crc, buf, len);
234*593dc095SDavid du Colombier         else
235*593dc095SDavid du Colombier             return crc32_big(crc, buf, len);
236*593dc095SDavid du Colombier     }
237*593dc095SDavid du Colombier #endif /* BYFOUR */
238*593dc095SDavid du Colombier     crc = crc ^ 0xffffffffUL;
239*593dc095SDavid du Colombier     while (len >= 8) {
240*593dc095SDavid du Colombier         DO8;
2417dd7cddfSDavid du Colombier         len -= 8;
2427dd7cddfSDavid du Colombier     }
2437dd7cddfSDavid du Colombier     if (len) do {
244*593dc095SDavid du Colombier         DO1;
2457dd7cddfSDavid du Colombier     } while (--len);
246*593dc095SDavid du Colombier     return crc ^ 0xffffffffUL;
2477dd7cddfSDavid du Colombier }
248*593dc095SDavid du Colombier 
249*593dc095SDavid du Colombier #ifdef BYFOUR
250*593dc095SDavid du Colombier 
251*593dc095SDavid du Colombier /* ========================================================================= */
252*593dc095SDavid du Colombier #define DOLIT4 c ^= *buf4++; \
253*593dc095SDavid du Colombier         c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
254*593dc095SDavid du Colombier             crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
255*593dc095SDavid du Colombier #define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
256*593dc095SDavid du Colombier 
257*593dc095SDavid du Colombier /* ========================================================================= */
crc32_little(crc,buf,len)258*593dc095SDavid du Colombier local unsigned long crc32_little(crc, buf, len)
259*593dc095SDavid du Colombier     unsigned long crc;
260*593dc095SDavid du Colombier     const unsigned char FAR *buf;
261*593dc095SDavid du Colombier     unsigned len;
262*593dc095SDavid du Colombier {
263*593dc095SDavid du Colombier     register u4 c;
264*593dc095SDavid du Colombier     register const u4 FAR *buf4;
265*593dc095SDavid du Colombier 
266*593dc095SDavid du Colombier     c = (u4)crc;
267*593dc095SDavid du Colombier     c = ~c;
268*593dc095SDavid du Colombier     while (len && ((ptrdiff_t)buf & 3)) {
269*593dc095SDavid du Colombier         c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
270*593dc095SDavid du Colombier         len--;
271*593dc095SDavid du Colombier     }
272*593dc095SDavid du Colombier 
273*593dc095SDavid du Colombier     buf4 = (const u4 FAR *)buf;
274*593dc095SDavid du Colombier     while (len >= 32) {
275*593dc095SDavid du Colombier         DOLIT32;
276*593dc095SDavid du Colombier         len -= 32;
277*593dc095SDavid du Colombier     }
278*593dc095SDavid du Colombier     while (len >= 4) {
279*593dc095SDavid du Colombier         DOLIT4;
280*593dc095SDavid du Colombier         len -= 4;
281*593dc095SDavid du Colombier     }
282*593dc095SDavid du Colombier     buf = (const unsigned char FAR *)buf4;
283*593dc095SDavid du Colombier 
284*593dc095SDavid du Colombier     if (len) do {
285*593dc095SDavid du Colombier         c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
286*593dc095SDavid du Colombier     } while (--len);
287*593dc095SDavid du Colombier     c = ~c;
288*593dc095SDavid du Colombier     return (unsigned long)c;
289*593dc095SDavid du Colombier }
290*593dc095SDavid du Colombier 
291*593dc095SDavid du Colombier /* ========================================================================= */
292*593dc095SDavid du Colombier #define DOBIG4 c ^= *++buf4; \
293*593dc095SDavid du Colombier         c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
294*593dc095SDavid du Colombier             crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
295*593dc095SDavid du Colombier #define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
296*593dc095SDavid du Colombier 
297*593dc095SDavid du Colombier /* ========================================================================= */
crc32_big(crc,buf,len)298*593dc095SDavid du Colombier local unsigned long crc32_big(crc, buf, len)
299*593dc095SDavid du Colombier     unsigned long crc;
300*593dc095SDavid du Colombier     const unsigned char FAR *buf;
301*593dc095SDavid du Colombier     unsigned len;
302*593dc095SDavid du Colombier {
303*593dc095SDavid du Colombier     register u4 c;
304*593dc095SDavid du Colombier     register const u4 FAR *buf4;
305*593dc095SDavid du Colombier 
306*593dc095SDavid du Colombier     c = REV((u4)crc);
307*593dc095SDavid du Colombier     c = ~c;
308*593dc095SDavid du Colombier     while (len && ((ptrdiff_t)buf & 3)) {
309*593dc095SDavid du Colombier         c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
310*593dc095SDavid du Colombier         len--;
311*593dc095SDavid du Colombier     }
312*593dc095SDavid du Colombier 
313*593dc095SDavid du Colombier     buf4 = (const u4 FAR *)buf;
314*593dc095SDavid du Colombier     buf4--;
315*593dc095SDavid du Colombier     while (len >= 32) {
316*593dc095SDavid du Colombier         DOBIG32;
317*593dc095SDavid du Colombier         len -= 32;
318*593dc095SDavid du Colombier     }
319*593dc095SDavid du Colombier     while (len >= 4) {
320*593dc095SDavid du Colombier         DOBIG4;
321*593dc095SDavid du Colombier         len -= 4;
322*593dc095SDavid du Colombier     }
323*593dc095SDavid du Colombier     buf4++;
324*593dc095SDavid du Colombier     buf = (const unsigned char FAR *)buf4;
325*593dc095SDavid du Colombier 
326*593dc095SDavid du Colombier     if (len) do {
327*593dc095SDavid du Colombier         c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
328*593dc095SDavid du Colombier     } while (--len);
329*593dc095SDavid du Colombier     c = ~c;
330*593dc095SDavid du Colombier     return (unsigned long)(REV(c));
331*593dc095SDavid du Colombier }
332*593dc095SDavid du Colombier 
333*593dc095SDavid du Colombier #endif /* BYFOUR */
334