162 lines
3.6 KiB
C
162 lines
3.6 KiB
C
/* crc32.h - 32-bit cyclic redundancy check calcuations
|
|
Copyright (C) 2012 Connor Olding
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef CRC32_H_
|
|
#define CRC32_H_
|
|
|
|
#include <stdlib.h>
|
|
|
|
/* interface */
|
|
|
|
typedef unsigned long uint32;
|
|
|
|
void crc_cycle(uint32 *remainder, char c);
|
|
uint32 crc_reflect(uint32 input);
|
|
|
|
void crc_set_big_endian();
|
|
void crc_set_little_endian();
|
|
void crc_set_polynomial(uint32 p);
|
|
|
|
/* implementation */
|
|
|
|
static char crc_big_endian = 0;
|
|
static const int crc_table_size = 0x100;
|
|
static uint32* crc_be_table = NULL; /* big endian */
|
|
static uint32* crc_le_table = NULL; /* little endian */
|
|
static uint32 crc_polynomial = 0x04C11DB7;
|
|
|
|
uint32 crc_reflect(uint32 input)
|
|
{
|
|
uint32 reflected = 0;
|
|
unsigned int i;
|
|
for (i = 0; i < sizeof(uint32) * 8; i++) {
|
|
reflected <<= 1;
|
|
reflected |= input & 1;
|
|
input >>= 1;
|
|
}
|
|
return reflected;
|
|
}
|
|
|
|
static uint32* crc_alloc(size_t size)
|
|
{
|
|
uint32* p = (uint32*) malloc(size * sizeof(uint32));
|
|
if (p == NULL)
|
|
exit(1);
|
|
return p;
|
|
}
|
|
|
|
static void crc_allocate_tables_once()
|
|
{
|
|
static char allocated = 0;
|
|
if (crc_big_endian && !(allocated & 1)) {
|
|
crc_be_table = crc_alloc(crc_table_size);
|
|
allocated |= 1;
|
|
} else if (!crc_big_endian && !(allocated & 2)) {
|
|
crc_le_table = crc_alloc(crc_table_size);
|
|
allocated |= 2;
|
|
}
|
|
}
|
|
|
|
static void crc_fill_big_endian_table()
|
|
{
|
|
const uint32 least_significant_bit = 1 << 31;
|
|
int c, i;
|
|
|
|
crc_allocate_tables_once();
|
|
|
|
for (c = 0; c < crc_table_size; c++) {
|
|
crc_be_table[c] = c << 24;
|
|
for (i = 0; i < 8; i++) {
|
|
if (crc_be_table[c] & least_significant_bit) {
|
|
crc_be_table[c] <<= 1;
|
|
crc_be_table[c] ^= crc_polynomial;
|
|
} else {
|
|
crc_be_table[c] <<= 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void crc_fill_little_endian_table()
|
|
{
|
|
const uint32 least_significant_bit = 1;
|
|
const uint32 reflected_polynomial = crc_reflect(crc_polynomial);
|
|
int c, i;
|
|
|
|
crc_allocate_tables_once();
|
|
/* printf("p: %08X\n", (int)reflected_polynomial); */
|
|
|
|
for (c = 0; c < crc_table_size; c++) {
|
|
crc_le_table[c] = c;
|
|
for (i = 0; i < 8; i++) {
|
|
if (crc_le_table[c] & least_significant_bit) {
|
|
crc_le_table[c] >>= 1;
|
|
crc_le_table[c] ^= reflected_polynomial;
|
|
} else {
|
|
crc_le_table[c] >>= 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void crc_fill_tables_once()
|
|
{
|
|
static char filled = 0;
|
|
if (crc_big_endian && !(filled & 1)) {
|
|
crc_fill_big_endian_table();
|
|
filled |= 1;
|
|
} else if (!crc_big_endian && !(filled & 2)) {
|
|
crc_fill_little_endian_table();
|
|
filled |= 2;
|
|
}
|
|
}
|
|
|
|
void crc_set_big_endian()
|
|
{
|
|
crc_big_endian = 1;
|
|
}
|
|
|
|
void crc_set_little_endian()
|
|
{
|
|
crc_big_endian = 0;
|
|
}
|
|
|
|
void crc_set_polynomial(uint32 p)
|
|
{
|
|
crc_polynomial = p;
|
|
}
|
|
|
|
void crc_cycle(uint32 *remainder, char c)
|
|
{
|
|
crc_fill_tables_once();
|
|
if (crc_big_endian) {
|
|
const uint32 newByte = crc_be_table[
|
|
((*remainder) >> 24) ^ c];
|
|
/* printf("%08X00 ^ %08X =\n",
|
|
(int)(*remainder), (int)newByte); */
|
|
*remainder = ((*remainder) << 8) ^ newByte;
|
|
} else {
|
|
const uint32 newByte = crc_le_table[
|
|
((*remainder) ^ c) & 0xFF];
|
|
/* printf(" %08X ^ %08X =\n",
|
|
(int)((*remainder) >> 8), (int)newByte); */
|
|
*remainder = ((*remainder) >> 8) ^ newByte;
|
|
}
|
|
}
|
|
|
|
#endif
|