Java equivalent for C CRC16

1.1k views Asked by At

I need to convert C CRC16 method to Java. The problem is I'm not that good with C and Bytes operations.

C code:

static const unsigned short crc16_table[256] =
{
 0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,
 ...  /* Removed for brevity */
 0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040
};

unsigned short crc16 (const void *data, unsigned data_size)
{
 if (!data || !data_size)
 return 0;
 unsigned short crc = 0;
 unsigned char* buf = (unsigned char*)data;
 while (data_size--)
 crc = (crc >> 8) ^ crc16_table[(unsigned char)crc ^ *buf++];
 return crc;
}

And that's my attempt to convert it. Not sure if that's correct.

private static int[] table = {
    0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,0xC601,0x06C0,0x0780,0xC741,
    ...    // Removed for brevity
    0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,0x8201,0x42C0,0x4380,0x8341, 0x4100,0x81C1,0x8081,0x4040
};

public static int getCode (String[] data){
    if (data.length == 0) {
        return 0;
    }
    int crc = 0;
    for (String item : data) {
        byte[] bytes = item.getBytes();
        for (byte b : bytes) {
            crc = (crc >>> 8) ^ table[(crc ^ b) & 0xff]; //this confuses me
        }
    }
    return crc;
}

Question: Is my porting to Java correct?


EDIT:

Modified crc16 working method (thanks to great answers):

public static int getCode(String data) {
    if (data == null || data.equals("")) {
        return 0;
    }
    int crc = 0x0000;
    byte[] bytes = data.getBytes();
    for (byte b : bytes) {
        crc = (crc >>> 8) ^ table[(crc ^ b) & 0xff];
    }
    return crc;
}

This returns Decimal value. And CRC16 code needs to be Hexadecimal. I used this method to convert to base 16. Do it with received crc like dec2m(crc, 16):

static String dec2m(int N, int m) {
    String s = "";
    for (int n = N; n > 0; n /= m) {
        int r = n % m;
        s = r < 10 ? r + s : (char) ('A' - 10 + r) + s;
    }
    return s;
}

For testing your results you could use this site (Thanks to @greenaps)

2

There are 2 answers

7
greenapps On BEST ANSWER

Your translated the c code function call crc16 (const void *data, unsigned data_size) wrong.

public static int getCode (String[] data)

should be

public static int getCode (String data)

Moreover you can also see in the Wialon pdf that you need a getCode (String) and not a getCode(String[]).

Converting the received String to a byte array stands.

7
Serge Ballesta On

What you wrote looks good as said by Mohit Jain. But your function does thing differently than original C one : you take an array of String, while C code takes a void *, and a length in bytes. So if you use your conversion function to validate a string containing non ASCII characters between an UTF-8 and a Latin1 platform, it will give different result, because with Latin1, "éè" will give the 2 bytes 0xe9, 0xe8, while with UTF-8, you will get 4 bytes : 0xc3, 0xa9, 0xc3, 0xa8 => your CRC function will give different results.

IMHO, you should stick to original code and only compute a CRC for a byte array. You could force always same charset (say UTF-8 for example), but it will still be hard to compare your results with the C implementation, and you would loose the ability to compute the CRC of a raw byte array (binary data).

Anyway, the only way to make sure that your implementation gives same results than original C one, is to take an arbitrary byte string (all bytes from 0 to 255 for example), pass it to the C routine on one side and to you java one on the other side and compare both CRCs.