/** @file crc.c
* @date April 24, 2009
*/
#include "common.h"
#include "crc.h"
static void initialize_table(void);
static u_long reflect(u_long value, size_t count);
/** A flag indicating the table has been initialized. */
static int g_initialized;
/** The table used to compute the checksums. */
static u_long g_table[256];
/* ------------------------------------------------------------------------- */
int crc_file(FILE * file, u_long * result)
{
assert(NULL != file);
assert(NULL != result);
/* Initialize the CRC value, and reset the file pointer. */
*result = crc_init();
RETURN_IF_FALSE(0 == fseek(file, 0, SEEK_SET));
/* Loop over each byte in the file stream. */
for(;;) {
size_t actual;
u_char buffer[10000];
/* Read a block of data. */
actual = fread(buffer, 1, sizeof(buffer), file);
if (0 == actual) {
/* Check for errors if nothing was read. */
RETURN_IF_FALSE(ferror(file) == 0);
RETURN_IF_FALSE(feof(file) != 0);
break;
}
/* Update the CRC. */
*result = crc_update(*result, buffer, actual);
}
/* Store the final checksum result. */
*result = crc_result(*result);
/* Return successfully. */
return EXIT_SUCCESS;
}
/* ------------------------------------------------------------------------- */
u_long crc_init(void)
{
/* Initialize the CRC table if necessary. */
if (g_initialized == 0) {
initialize_table();
g_initialized = 1;
}
/* Return the initial value. */
return 0xffffffff;
}
/* ------------------------------------------------------------------------- */
u_long crc_result(u_long value)
{
/* XOR to get the final value. */
return value ^ 0xffffffff;
}
/* ------------------------------------------------------------------------- */
u_long crc_update(
u_long current,
const void * buffer,
size_t size)
{
const u_char * ptr;
assert(NULL != buffer);
/* Loop over each byte. */
ptr = (u_char *)buffer;
while (size-- > 0) {
/* Update the CRC based on values from the table. */
current = (current >> 8) ^ g_table[(current & 0xff) ^ *ptr++];
}
/* Return the updated CRC value. */
return current;
}
/* ------------------------------------------------------------------------- */
/** Initializes the CRC table. The table is compatible with WinZip CRCs.
*/
static void initialize_table(void)
{
u_long i;
/* Loop over the size of the table. */
for (i = 0; i < 256; i++) {
int j;
/* Initialize the value in the table. */
g_table[i] = reflect(i, 8) << 24;
/* Loop over each bit in the byte. */
for(j = 0; j < 8; j++) {
/* Update the table value based on the CRC table formula. */
g_table[i] <<= 1;
if (0 != (0x80000000 & g_table[i]))
g_table[i] ^= 0x4c11db7;
}
/* Store the final value into the table element. */
g_table[i] = reflect(g_table[i], 32);
}
}
/* ------------------------------------------------------------------------- */
/** Returns the bits in a byte reversed fashion.
*
* @param value The value to reflect.
* @param count The number of bits.
*
* @param The reflected value.
*/
static u_long reflect(u_long value, size_t count)
{
size_t i;
u_long result;
/* Loop over each specified bit. */
result = 0;
for (i = 1; i < (count + 1); i++) {
/* Reverse the value in the result. */
if (0 != (1 & value))
result |= (u_long)1 << (count - i);
/* Advance to the next bit. */
value >>= 1;
}
/* Return the reflected value. */
return result;
}