Home | History | Annotate | Line # | Download | only in libkern
crc32.c revision 1.4.4.3
      1  1.4.4.3  snj /*	$NetBSD: crc32.c,v 1.4.4.3 2009/05/03 17:31:42 snj Exp $	*/
      2  1.4.4.2  snj 
      3  1.4.4.2  snj /* crc32.c -- compute the CRC-32 of a data stream
      4  1.4.4.2  snj  *
      5  1.4.4.2  snj  * Adapted from zlib's crc code.
      6  1.4.4.2  snj  *
      7  1.4.4.2  snj  * Copyright (C) 1995-2005 Mark Adler
      8  1.4.4.2  snj  * For conditions of distribution and use, see copyright notice in zlib.h
      9  1.4.4.2  snj  *
     10  1.4.4.2  snj  * Thanks to Rodney Brown <rbrown64 (at) csc.com.au> for his contribution of faster
     11  1.4.4.2  snj  * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
     12  1.4.4.2  snj  * tables for updating the shift register in one step with three exclusive-ors
     13  1.4.4.2  snj  * instead of four steps with four exclusive-ors.  This results in about a
     14  1.4.4.2  snj  * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
     15  1.4.4.2  snj  */
     16  1.4.4.2  snj 
     17  1.4.4.2  snj /* @(#) Id */
     18  1.4.4.2  snj 
     19  1.4.4.2  snj #include <sys/param.h>
     20  1.4.4.2  snj #include <machine/endian.h>
     21  1.4.4.2  snj 
     22  1.4.4.2  snj #define z_ptrdiff_t int32_t
     23  1.4.4.2  snj 
     24  1.4.4.2  snj typedef uint32_t u4;
     25  1.4.4.2  snj 
     26  1.4.4.2  snj /* Definitions for doing the crc four data bytes at a time. */
     27  1.4.4.2  snj #define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
     28  1.4.4.2  snj                (((w)&0xff00)<<8)+(((w)&0xff)<<24))
     29  1.4.4.2  snj 
     30  1.4.4.2  snj /* ========================================================================
     31  1.4.4.2  snj  * Tables of CRC-32s of all single-byte values, made by make_crc_table().
     32  1.4.4.2  snj  */
     33  1.4.4.3  snj #include <lib/libkern/libkern.h>
     34  1.4.4.2  snj #include "crc32.h"
     35  1.4.4.2  snj 
     36  1.4.4.2  snj #if BYTE_ORDER == LITTLE_ENDIAN
     37  1.4.4.2  snj /* ========================================================================= */
     38  1.4.4.2  snj #define DOLIT4 c ^= *buf4++; \
     39  1.4.4.2  snj         c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
     40  1.4.4.2  snj             crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
     41  1.4.4.2  snj #define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
     42  1.4.4.2  snj 
     43  1.4.4.2  snj /* ========================================================================= */
     44  1.4.4.3  snj uint32_t crc32(uint32_t crc, const uint8_t *buf, size_t len)
     45  1.4.4.2  snj {
     46  1.4.4.2  snj     register u4 c;
     47  1.4.4.2  snj     register const u4 *buf4;
     48  1.4.4.2  snj 
     49  1.4.4.2  snj     if (buf == NULL) return 0UL;
     50  1.4.4.2  snj 
     51  1.4.4.2  snj     c = (u4)crc;
     52  1.4.4.2  snj     c = ~c;
     53  1.4.4.2  snj     while (len && ((z_ptrdiff_t)buf & 3)) {
     54  1.4.4.2  snj         c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
     55  1.4.4.2  snj         len--;
     56  1.4.4.2  snj     }
     57  1.4.4.2  snj 
     58  1.4.4.2  snj     buf4 = (const u4 *)(const void *)buf;
     59  1.4.4.2  snj     while (len >= 32) {
     60  1.4.4.2  snj         DOLIT32;
     61  1.4.4.2  snj         len -= 32;
     62  1.4.4.2  snj     }
     63  1.4.4.2  snj     while (len >= 4) {
     64  1.4.4.2  snj         DOLIT4;
     65  1.4.4.2  snj         len -= 4;
     66  1.4.4.2  snj     }
     67  1.4.4.2  snj     buf = (const unsigned char *)buf4;
     68  1.4.4.2  snj 
     69  1.4.4.2  snj     if (len) do {
     70  1.4.4.2  snj         c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
     71  1.4.4.2  snj     } while (--len);
     72  1.4.4.2  snj     c = ~c;
     73  1.4.4.2  snj     return (uint32_t)c;
     74  1.4.4.2  snj }
     75  1.4.4.2  snj 
     76  1.4.4.2  snj #else /* BIG_ENDIAN */
     77  1.4.4.2  snj 
     78  1.4.4.2  snj /* ========================================================================= */
     79  1.4.4.2  snj #define DOBIG4 c ^= *++buf4; \
     80  1.4.4.2  snj         c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
     81  1.4.4.2  snj             crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
     82  1.4.4.2  snj #define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
     83  1.4.4.2  snj 
     84  1.4.4.2  snj /* ========================================================================= */
     85  1.4.4.2  snj uint32_t crc32(
     86  1.4.4.2  snj     uint32_t crc,
     87  1.4.4.2  snj     const unsigned char *buf,
     88  1.4.4.2  snj     unsigned len)
     89  1.4.4.2  snj {
     90  1.4.4.2  snj     register u4 c;
     91  1.4.4.2  snj     register const u4 *buf4;
     92  1.4.4.2  snj 
     93  1.4.4.2  snj     if (buf == NULL) return 0UL;
     94  1.4.4.2  snj 
     95  1.4.4.2  snj     c = REV((u4)crc);
     96  1.4.4.2  snj     c = ~c;
     97  1.4.4.2  snj     while (len && ((z_ptrdiff_t)buf & 3)) {
     98  1.4.4.2  snj         c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
     99  1.4.4.2  snj         len--;
    100  1.4.4.2  snj     }
    101  1.4.4.2  snj 
    102  1.4.4.2  snj     buf4 = (const u4 *)(const void *)buf;
    103  1.4.4.2  snj     buf4--;
    104  1.4.4.2  snj     while (len >= 32) {
    105  1.4.4.2  snj         DOBIG32;
    106  1.4.4.2  snj         len -= 32;
    107  1.4.4.2  snj     }
    108  1.4.4.2  snj     while (len >= 4) {
    109  1.4.4.2  snj         DOBIG4;
    110  1.4.4.2  snj         len -= 4;
    111  1.4.4.2  snj     }
    112  1.4.4.2  snj     buf4++;
    113  1.4.4.2  snj     buf = (const unsigned char *)buf4;
    114  1.4.4.2  snj 
    115  1.4.4.2  snj     if (len) do {
    116  1.4.4.2  snj         c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
    117  1.4.4.2  snj     } while (--len);
    118  1.4.4.2  snj     c = ~c;
    119  1.4.4.2  snj     return (uint32_t)(REV(c));
    120  1.4.4.2  snj }
    121  1.4.4.2  snj #endif
    122