diff --git a/crc32.c b/crc32.c new file mode 100644 index 0000000..15ddda0 --- /dev/null +++ b/crc32.c @@ -0,0 +1,60 @@ +#include +#include +#include + +#ifndef BUFFER +#define BUFFER 4096 +#endif +uint8_t msg[BUFFER]; + +/* CRC-32, eg. ethernet */ +const uint32_t crc32_tbl[] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c +}; + +/* the idea is to act on nybbles instead of bytes to require less CPU cache */ +uint32_t crc32_calc(uint8_t *ptr, int cnt, uint32_t crc) +{ + while (cnt--) { + crc = (crc >> 4) ^ crc32_tbl[(crc & 0xf) ^ (*ptr & 0xf)]; + crc = (crc >> 4) ^ crc32_tbl[(crc & 0xf) ^ (*(ptr++) >> 4)]; + } + return crc; +} + +int main(int argc, char **argv) +{ + int len; + uint32_t v32 = ~0; + FILE *f; + + if (argc == 1) { + freopen(NULL, "rb", stdin); + f = stdin; + } else if (argc == 2) { + f = fopen(argv[1], "rb"); + if (f == NULL) { + perror(argv[1]); + exit(1); + } + } else { + fputs("usage: crc32 [filename]", stderr); + exit(1); + } + + do { + len = fread(msg, 1, BUFFER, f); + if (ferror(f)) { + perror(NULL); + exit(1); + } + v32 = crc32_calc(msg, len, v32); + } while (!feof(f)); + + fclose(f); + + printf("%08lX\n", (unsigned long) ~v32); +}