1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
static uint32_t reflect(uint32_t data, uint8_t len)
{
    uint8_t i;
    uint32_t ret;

    ret = data & 0x01;
    for (i = 1; i < len; i++)
    {
        data >>= 1;
        ret = (ret << 1) | (data & 0x01);
    }
    return ret;
}

uint32_t crc32_generic(const void *src, uint32_t len, const uint32_t polynomial, const bool reflected)
{
    const unsigned char *buf = (const unsigned char *)src;

    uint32_t crc32_lookup[16];
    uint32_t crc32 = 0;
    uint32_t t;
    int8_t i,j;

    /* generate lookup table */
    for (i=0; i<16; i++)
    {
        if (reflected)
            crc32 = (reflect(i,4))<<28;
        else
            crc32 = i;

        for (j=0; j<4; j++)
        {
            if (crc32 & 0x80000000)
                crc32 = (crc32 << 1) ^ polynomial;
            else
                crc32 <<= 1;
        }

        if (reflected)
            crc32_lookup[i] = reflect(crc32,32);
        else
            crc32_lookup[i] = crc32;
    }

    crc32 = 0;
    while (len--)
    {
        if (reflected)
        {
            t = crc32 ^ *buf;
            crc32 = crc32_lookup[t & 0x0f] ^ (crc32 >> 4);

            t = crc32 ^ (*buf>>4);
            crc32 = crc32_lookup[t & 0x0f] ^ (crc32 >> 4);
        }
        else
        {
            t = (crc32 >> 28) ^ (*buf >> 4);
            crc32 = crc32_lookup[t & 0x0f] ^ (crc32 << 4);

            t = (crc32 >> 28) ^ *buf;
            crc32 = crc32_lookup[t & 0x0f] ^ (crc32 << 4);
        }

        buf++;
    }

    return crc32;
}