Nas Nas - 1 month ago 7
C# Question

Calculate checksum return wrong value in android

Hi am converting c# application to android and am calculating checksum from byte array as same as in c#. But it return wrong value below byte array. Anyone please help on this.Thank you.

C# byte array:

[41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132, 41, 132]

c# code:

public static uint CalculateChecksum(byte[] buffer, int offset, int length)
{
uint cs = 0;
for (int i = offset; i < offset + length & i < buffer.Length; i += 2)
{
ushort s = BitConverter.ToUInt16(buffer, i);
cs += s;
}

return cs;
}


value getting 4736620 converting this value to byte array gives [108,70,72,0]

Android byte array

[41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124, 41, -124]

Android code:

public static long checkSum(byte[] buffer, int offset, int length) {
long cs = 0;
for (int i = offset; i < offset + length & i < buffer.length; i += 2) {

ByteBuffer bb = ByteBuffer.allocate(2);
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.put(buffer[i]);
bb.put(buffer[i+1]);
long shortVal = bb.getShort(0);

cs += shortVal;
}
return cs;
}


value getting -4438420 converting this value to byte array

ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt((int) value).array();


gives [108,70,-68,-1]

What am doing wrongly? Why its return different value?
Please help me. Thank you.

Answer

The contents of the byte array differs (for example, the second position was different in C# than in Android). So from my point of view, it is OK that the code returns different checksums.

Edit: The contents of the array indeed differ. One consists of signed bytesm the other one of unsigned bytes. This is a difference (even though the bit representation may be the same) and has nothing to do with big endian vs. little endian. The problem you are facing is because in the Java version, you are again using signed shorts, whereas the C# version used unsigned shorts. There, the sign makes the computation wrong by a term that is a multiple of 2^16. In fact, if you were using signed int16 in C#, you would also get the same result as in the Android solution.

The simple solution is therefore to request an integer from the byte buffer, not a short, since the latter is signed. Alternatively, you could add 2^16 in case that the short is negative (which a ushort can never be):

public static long checkSum(byte[] buffer, int offset, int length) {
    long cs = 0;
    for (int i = offset; i < offset + length & i < buffer.length; i += 2) {

        ByteBuffer bb = ByteBuffer.allocate(2);
        bb.order(ByteOrder.LITTLE_ENDIAN);
        bb.put(buffer[i]);
        bb.put(buffer[i+1]);
        long shortVal = bb.getShort(0);
        if (shortVal < 0) { shortVal += (1 << 16); }
        cs += shortVal;
    }
    return cs;
}