Could someone help me out with converting this C# code to Kotlin?
public static UInt32 CalcCrc32(byte[] bytes, int length)
{
// GLB_u32CalcCrc32OverBytes
UInt32 Checksum = 0xFFFFFFFF;
for (int i = 0; i < length; i )
{
byte top = (byte)(Checksum >> 24);
top ^= bytes[i];
Checksum = (Checksum << 8) ^ crc_table[top];
}
return Checksum;
}
It allows the CRC32 caluclation of the first length
bytes of bytes
.
I have tried different approaches to deal with the unsigned datatypes, but I cannot get it to return the correct CRC.
This was the closest I got
Generating the crc table (taken from this repo)
private val crcTable = (0 until 256).map {
crc32(it.toUByte(), 0x04C11DB7.toUInt())
}
private fun crc32(input: UByte, polynomial: UInt): UInt {
val bigEndianInput = input.toBigEndianUInt()
return (0 until 8).fold(bigEndianInput) { result, _ ->
val isMostSignificantBitOne = result and 0x80000000.toUInt() != 0.toUInt()
val shiftedResult = result shl 1
when (isMostSignificantBitOne) {
true -> shiftedResult xor polynomial
false -> shiftedResult
}
}
}
private fun UByte.toBigEndianUInt(): UInt = this.toUInt() shl 24
Converting the C# method to Kotlin
private fun calcCrc32(bytes: ByteArray, length: Int): UInt {
var checksum : UInt = 0xFFFFFFFFu
for (i in 0 until length) {
var top = (checksum shr 24).toByte()
top = top xor bytes[i]
checksum = checksum shl 8 xor crcTable[top.toInt()]
}
return checksum
}
But this code throws an IndexOutOfBoundsException, because top
ends up being -1.
Unit Test
import com.google.common.truth.Truth.assertThat
import com.proregia.pump.common.CrcUtil
import org.junit.Test
class CrcUtilTest {
@Test
fun crc16_correctByteArray_returnsCorrectCrc16() {
val data = byteArrayOf(
0xe8.toByte(),
0x03.toByte(),
0x00.toByte(),
0x00.toByte(),
0x3c.toByte(),
0x00.toByte(),
0x00.toByte(),
0x00.toByte(),
0x90.toByte(),
0x01.toByte(),
0x00.toByte(),
0x00.toByte(),
0x02.toByte(),
0x00.toByte(),
0x00.toByte()
)
CrcUtil.updateCrc16(data)
assertThat(data[13]).isEqualTo(0xAD)
assertThat(data[14]).isEqualTo(0xC1)
}
}
CodePudding user response:
The JDK has a built-in class that allows you to compute the CRC32 of a given value: https://docs.oracle.com/javase/8/docs/api/java/util/zip/CRC32.html
You can take advantage of Kotlin's interoperability with Java to compute the CRC32 checksum of a given value:
import java.util.zip.CRC32
fun calculateCRC32(value: ByteArray): Long {
val crc32Calculator = CRC32()
crc32Calculator.update(value)
return crc32Calculator.value
}
println(calculateCRC32("Some text".toByteArray())) // prints 3444260633
CodePudding user response:
Try toUByte()
instead of toByte()
in calcCrc32()
, also applying it to the result of bytes[i]
.