Вычислить CRC32 в Kotlin (преобразовать код C# в Kotlin)

Может ли кто-нибудь помочь мне преобразовать этот код 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.

Это было самое близкое, что я получил

Создание таблицы 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

Преобразование метода C# в 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
}

Но этот код генерирует исключение 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)

    }

}

Где ваша попытка кода Kotlin?

Mark Adler 05.10.2022 20:11

Я добавил свою попытку, а также модульный тест, который зеленый при запуске с кодом С#.

muetzenflo 06.10.2022 09:39

Попробуйте toUByte() вместо toByte() в calcCrc32(), также применяя к результату bytes[i]. Вы проверили, что ваша таблица верна?

Mark Adler 06.10.2022 10:32

В заключение!! Спасибо!! Я мог бы поклясться, что уже испробовал все комбинации Uxxx и не-Uxxx. Я опубликую правильную версию в качестве ответа через несколько дней. Если вы хотите кредит, не стесняйтесь сделать это. Просто нужно было добавить val uBytes = bytes.toUByteArray(), адаптировать использование bytes и перейти на toUBytes(), как вы упомянули.

muetzenflo 06.10.2022 14:13
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
207
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

В 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#. Вот почему я прошу больше о дословном переводе моего кода, чем о помощи в создании нормальной контрольной суммы.

muetzenflo 05.10.2022 15:02
Ответ принят как подходящий

Попробуйте 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
}

Другие вопросы по теме