xref: /netbsd-src/sys/lib/libkern/crc32.c (revision c05f1c0f90c4a4354a13dd07be9d5c43093acfc8)
1*c05f1c0fShe /*	$NetBSD: crc32.c,v 1.4 2009/03/26 22:18:14 he Exp $	*/
236ea3668Sdarran 
336ea3668Sdarran /* crc32.c -- compute the CRC-32 of a data stream
436ea3668Sdarran  *
536ea3668Sdarran  * Adapted from zlib's crc code.
636ea3668Sdarran  *
736ea3668Sdarran  * Copyright (C) 1995-2005 Mark Adler
836ea3668Sdarran  * For conditions of distribution and use, see copyright notice in zlib.h
936ea3668Sdarran  *
1036ea3668Sdarran  * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
1136ea3668Sdarran  * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
1236ea3668Sdarran  * tables for updating the shift register in one step with three exclusive-ors
1336ea3668Sdarran  * instead of four steps with four exclusive-ors.  This results in about a
1436ea3668Sdarran  * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
1536ea3668Sdarran  */
1636ea3668Sdarran 
1736ea3668Sdarran /* @(#) Id */
1836ea3668Sdarran 
1936ea3668Sdarran #include <sys/param.h>
2036ea3668Sdarran #include <machine/endian.h>
2136ea3668Sdarran 
2236ea3668Sdarran typedef uint32_t u4;
2336ea3668Sdarran 
2436ea3668Sdarran /* Definitions for doing the crc four data bytes at a time. */
2536ea3668Sdarran #define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
2636ea3668Sdarran                (((w)&0xff00)<<8)+(((w)&0xff)<<24))
2736ea3668Sdarran 
2836ea3668Sdarran /* ========================================================================
2936ea3668Sdarran  * Tables of CRC-32s of all single-byte values, made by make_crc_table().
3036ea3668Sdarran  */
31a34cd18bStls #include <lib/libkern/libkern.h>
3236ea3668Sdarran #include "crc32.h"
3336ea3668Sdarran 
3436ea3668Sdarran #if BYTE_ORDER == LITTLE_ENDIAN
3536ea3668Sdarran /* ========================================================================= */
3636ea3668Sdarran #define DOLIT4 c ^= *buf4++; \
3736ea3668Sdarran         c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
3836ea3668Sdarran             crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
3936ea3668Sdarran #define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
4036ea3668Sdarran 
4136ea3668Sdarran /* ========================================================================= */
crc32(uint32_t crc,const uint8_t * buf,size_t len)42a34cd18bStls uint32_t crc32(uint32_t crc, const uint8_t *buf, size_t len)
4336ea3668Sdarran {
4436ea3668Sdarran     register u4 c;
4536ea3668Sdarran     register const u4 *buf4;
4636ea3668Sdarran 
4736ea3668Sdarran     if (buf == NULL) return 0UL;
4836ea3668Sdarran 
4936ea3668Sdarran     c = (u4)crc;
5036ea3668Sdarran     c = ~c;
513559a904Stls     while (len && ((uintptr_t)buf & 3)) {
5236ea3668Sdarran         c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
5336ea3668Sdarran         len--;
5436ea3668Sdarran     }
5536ea3668Sdarran 
5636ea3668Sdarran     buf4 = (const u4 *)(const void *)buf;
5736ea3668Sdarran     while (len >= 32) {
5836ea3668Sdarran         DOLIT32;
5936ea3668Sdarran         len -= 32;
6036ea3668Sdarran     }
6136ea3668Sdarran     while (len >= 4) {
6236ea3668Sdarran         DOLIT4;
6336ea3668Sdarran         len -= 4;
6436ea3668Sdarran     }
6536ea3668Sdarran     buf = (const unsigned char *)buf4;
6636ea3668Sdarran 
6736ea3668Sdarran     if (len) do {
6836ea3668Sdarran         c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
6936ea3668Sdarran     } while (--len);
7036ea3668Sdarran     c = ~c;
7136ea3668Sdarran     return (uint32_t)c;
7236ea3668Sdarran }
7336ea3668Sdarran 
7436ea3668Sdarran #else /* BIG_ENDIAN */
7536ea3668Sdarran 
7636ea3668Sdarran /* ========================================================================= */
7736ea3668Sdarran #define DOBIG4 c ^= *++buf4; \
7836ea3668Sdarran         c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
7936ea3668Sdarran             crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
8036ea3668Sdarran #define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
8136ea3668Sdarran 
8236ea3668Sdarran /* ========================================================================= */
crc32(uint32_t crc,const uint8_t * buf,size_t len)83*c05f1c0fShe uint32_t crc32(uint32_t crc, const uint8_t *buf, size_t len)
8436ea3668Sdarran {
8536ea3668Sdarran     register u4 c;
8636ea3668Sdarran     register const u4 *buf4;
8736ea3668Sdarran 
8836ea3668Sdarran     if (buf == NULL) return 0UL;
8936ea3668Sdarran 
9036ea3668Sdarran     c = REV((u4)crc);
9136ea3668Sdarran     c = ~c;
923559a904Stls     while (len && ((uintptr_t)buf & 3)) {
9336ea3668Sdarran         c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
9436ea3668Sdarran         len--;
9536ea3668Sdarran     }
9636ea3668Sdarran 
9736ea3668Sdarran     buf4 = (const u4 *)(const void *)buf;
9836ea3668Sdarran     buf4--;
9936ea3668Sdarran     while (len >= 32) {
10036ea3668Sdarran         DOBIG32;
10136ea3668Sdarran         len -= 32;
10236ea3668Sdarran     }
10336ea3668Sdarran     while (len >= 4) {
10436ea3668Sdarran         DOBIG4;
10536ea3668Sdarran         len -= 4;
10636ea3668Sdarran     }
10736ea3668Sdarran     buf4++;
10836ea3668Sdarran     buf = (const unsigned char *)buf4;
10936ea3668Sdarran 
11036ea3668Sdarran     if (len) do {
11136ea3668Sdarran         c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
11236ea3668Sdarran     } while (--len);
11336ea3668Sdarran     c = ~c;
11436ea3668Sdarran     return (uint32_t)(REV(c));
11536ea3668Sdarran }
11636ea3668Sdarran #endif
117