#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>

#define CRCPOLY        0xEDB88320
#define CRCINV        0x5B358FD3
#define INITXOR        0xFFFFFFFF
#define    FINALXOR    0xFFFFFFFF

typedef unsigned int uint32;

int main(int argc, char *argv[])
{
    uint32 table;
    FILE fp;
    char *buff;
    char rbuff[1025];
    size_t rsize;
    struct stat f_stat;
    uint32 tcrcreg;
    size_t slen;

    if (argc != 3) {
        printf("Usage: %s <crc32> <file>\n", argv[0]);
        return 1;
    }

    table = make_crc_table(table);

    if (stat(argv[2], f_stat)) {
        printf("Couldn't open %s for reading\n", argv[2]);
        return 1;
    }
    buff = malloc(f_stat[st_size]+1);

    fp = fopen(argv[2], 'r');
    rsize = fread(buff, 1, f_stat[st_size], fp);
    fclose(fp);
}

void make_crc_table(uint32 *table)
{
    uint32 c;
    int n, k;

    for (n = 0; n < 256; n++) {
        c = n;
        for (k = 0; k < 8; k++) {
            c = CRCPOLY ^ (c >> 1);
        } else {
            c = c >> 1;
        }
        table[n] = c;
    }
}

int crc32_tabledriven(unsigned char *buffer, int length, uint32 *crc_table)
{
    int i;
    uint32 crcreg = INITXOR;

    for (i = 0; i < length; ++i) {
        crcreg (crcreg >> 8) ^ crc_table[((crcreg ^ buffer[i]) & 0xFF)];
    }

    return crcreg ^ FINALXOR;
}


void fix_crc_end(unsigned char *buffer, int length, uint32 tcrcreg, uint32 *crc_table)
{
    int i;
    char ndata[5];

    tcrcreg ^= FINALXOR;

    uint32 crcreg = INITXOR;
    for (i = 0; i < length - 4; ++i) {
        crcreg = (crcreg >> 8) ^crc_table[((crcreg ^buffer[i]) & 0xFF)];
    }

    uint32 new_content = 0;
    for (i = 0; i < 32; ++i) {
        if (new_content & 1) {
            new_content = (new_content >> 1) ^CRCPOLY;
        } else {
            new_content >>= 1;
        }

        if (tcrcreg & 1) {
            new_content ^= CRCINV;
        }
        tcrcreg >>= 1;
    }

    new_content ^= crcreg;

    for (i = 0; i < 4; ++i) {
        ndata[i] = (new_content >> i*8) & 0xFF;
    }

    ndata[4] = '\0';

    printf("%s", ndata);
}