crc.c

/** @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;
}
Valid HTML 4.01 Valid CSS