Может ли кто-нибудь помочь мне преобразовать этот код C# в 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;
}
Это позволяет вычислять CRC32 первых length байтов bytes.
Я пробовал разные подходы к работе с неподписанными типами данных, но не могу заставить его вернуть правильный CRC.
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
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
}
Но этот код генерирует исключение IndexOutOfBoundsException, потому что top оказывается равным -1.
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)
}
}
Я добавил свою попытку, а также модульный тест, который зеленый при запуске с кодом С#.
Попробуйте toUByte() вместо toByte() в calcCrc32(), также применяя к результату bytes[i]. Вы проверили, что ваша таблица верна?
В заключение!! Спасибо!! Я мог бы поклясться, что уже испробовал все комбинации Uxxx и не-Uxxx. Я опубликую правильную версию в качестве ответа через несколько дней. Если вы хотите кредит, не стесняйтесь сделать это. Просто нужно было добавить val uBytes = bytes.toUByteArray(), адаптировать использование bytes и перейти на toUBytes(), как вы упомянули.





В JDK есть встроенный класс, позволяющий вычислить CRC32 заданного значения: https://docs.oracle.com/javase/8/docs/api/java/util/zip/CRC32.html
Вы можете воспользоваться совместимостью Kotlin с Java для вычисления контрольной суммы CRC32 заданного значения:
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
Спасибо! Я уже нашел этот класс. Аппаратное обеспечение, которое мы используем, имеет несколько особых требований к вычислению контрольной суммы. Это причина, по которой нам нужно использовать приведенную выше логику, которая, как доказано, генерирует «правильную» контрольную сумму для нашего оборудования в C#. Вот почему я прошу больше о дословном переводе моего кода, чем о помощи в создании нормальной контрольной суммы.
Попробуйте toUByte() вместо toByte() в calcCrc32(), также применив его к результату bytes[i].
private fun calcCrc32(bytes: ByteArray, length: Int): UInt {
var checksum: UInt = 0xFFFFFFFFu
val uBytes = bytes.toUByteArray()
for (i in 0 until length) {
var top = (checksum shr 24).toUByte()
top = top xor uBytes[i]
checksum = checksum shl 8 xor crcTable[top.toInt()]
}
return checksum
}
Где ваша попытка кода Kotlin?