/** @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; }