From e4c3a0f45f4b6f630a21d5ee63f921de8c26ebc1 Mon Sep 17 00:00:00 2001 From: Infendro Date: Mon, 10 Nov 2025 13:51:21 +0100 Subject: [PATCH] implement padding, support UByteArray --- .../com/infendro/bytearray/ByteArray.kt | 148 ++++++++++++++++++ .../com/infendro/bytearray/ByteOrder.kt | 16 ++ .../com/infendro/bytearray/Collection.kt | 74 ++++++++- .../kotlin/com/infendro/bytearray/Int.kt | 38 +---- .../kotlin/com/infendro/bytearray/Long.kt | 38 +---- .../com/infendro/bytearray/UByteArray.kt | 145 +++++++++++++++++ .../kotlin/com/infendro/bytearray/UInt.kt | 38 +---- .../kotlin/com/infendro/bytearray/ULong.kt | 38 +---- .../com/infendro/bytearray/operation.kt | 35 ----- 9 files changed, 404 insertions(+), 166 deletions(-) create mode 100644 src/commonMain/kotlin/com/infendro/bytearray/ByteArray.kt create mode 100644 src/commonMain/kotlin/com/infendro/bytearray/UByteArray.kt delete mode 100644 src/commonMain/kotlin/com/infendro/bytearray/operation.kt diff --git a/src/commonMain/kotlin/com/infendro/bytearray/ByteArray.kt b/src/commonMain/kotlin/com/infendro/bytearray/ByteArray.kt new file mode 100644 index 0000000..7947d7f --- /dev/null +++ b/src/commonMain/kotlin/com/infendro/bytearray/ByteArray.kt @@ -0,0 +1,148 @@ +package com.infendro.bytearray + +import com.infendro.bytearray.ByteOrder.BIG_ENDIAN +import kotlin.experimental.and +import kotlin.experimental.or +import kotlin.experimental.xor + +infix fun ByteArray.and( + that: ByteArray, +): ByteArray { + if (this.size != that.size) throw Exception() + + return ByteArray(size) { i -> + this[i] and that[i] + } +} + +infix fun ByteArray.or( + that: ByteArray, +): ByteArray { + if (this.size != that.size) throw Exception() + + return ByteArray(size) { i -> + this[i] or that[i] + } +} + +infix fun ByteArray.xor( + that: ByteArray, +): ByteArray { + if (this.size != that.size) throw Exception() + + return ByteArray(size) { i -> + this[i] xor that[i] + } +} + +fun ByteArray.padStart( + length: Int, + padByte: Byte, +): ByteArray { + return buildList { + repeat(length - size) { + add(padByte) + } + addAll(this) + }.toByteArray() +} + +fun ByteArray.padEnd( + length: Int, + padByte: Byte, +): ByteArray { + return buildList { + repeat(length - size) { + add(padByte) + } + addAll(this) + }.toByteArray() +} + +fun ByteArray.toInt( + order: ByteOrder = BIG_ENDIAN, +): Int { + if (size != 4) throw Exception() + + val bytes = order.normalize(this) + return bytes.fold(0) { acc, byte -> + (acc shl 8) or (byte.toInt() and 0xFF) + } +} + +fun ByteArray.toIntArray( + order: ByteOrder = BIG_ENDIAN, +): IntArray { + if (size % 4 != 0) throw Exception() + + return toList() + .chunked(4) + .map { it.toInt(order) } + .toIntArray() +} + +fun ByteArray.toLong( + order: ByteOrder = BIG_ENDIAN, +): Long { + if (size != 8) throw Exception() + + val bytes = order.normalize(this) + return bytes.fold(0L) { acc, byte -> + (acc shl 8) or (byte.toLong() and 0xFFL) + } +} + +fun ByteArray.toLongArray( + order: ByteOrder = BIG_ENDIAN, +): LongArray { + if (size % 8 != 0) throw Exception() + + return toList() + .chunked(8) + .map { it.toLong(order) } + .toLongArray() +} + +fun ByteArray.toUInt( + order: ByteOrder = BIG_ENDIAN, +): UInt { + if (size != 4) throw Exception() + + val bytes = order.normalize(this) + return bytes.fold(0U) { acc, byte -> + (acc shl 8) or (byte.toUInt() and 0xFFU) + } +} + +fun ByteArray.toUIntArray( + order: ByteOrder = BIG_ENDIAN, +): UIntArray { + if (size % 4 != 0) throw Exception() + + return toList() + .chunked(4) + .map { it.toUInt(order) } + .toUIntArray() +} + +fun ByteArray.toULong( + order: ByteOrder = BIG_ENDIAN, +): ULong { + if (size != 8) throw Exception() + + val bytes = order.normalize(this) + return bytes.fold(0UL) { acc, byte -> + (acc shl 8) or (byte.toULong() and 0xFFUL) + } +} + +fun ByteArray.toULongArray( + order: ByteOrder = BIG_ENDIAN, +): ULongArray { + if (size % 8 != 0) throw Exception() + + return toList() + .chunked(8) + .map { it.toULong(order) } + .toULongArray() +} diff --git a/src/commonMain/kotlin/com/infendro/bytearray/ByteOrder.kt b/src/commonMain/kotlin/com/infendro/bytearray/ByteOrder.kt index 3a0a175..f13d085 100644 --- a/src/commonMain/kotlin/com/infendro/bytearray/ByteOrder.kt +++ b/src/commonMain/kotlin/com/infendro/bytearray/ByteOrder.kt @@ -7,6 +7,12 @@ enum class ByteOrder { ): ByteArray { return bytes } + + override fun normalize( + bytes: UByteArray, + ): UByteArray { + return bytes + } }, LITTLE_ENDIAN { override fun normalize( @@ -14,9 +20,19 @@ enum class ByteOrder { ): ByteArray { return bytes.reversedArray() } + + override fun normalize( + bytes: UByteArray, + ): UByteArray { + return bytes.reversedArray() + } }; internal abstract fun normalize( bytes: ByteArray, ): ByteArray + + internal abstract fun normalize( + bytes: UByteArray, + ): UByteArray } diff --git a/src/commonMain/kotlin/com/infendro/bytearray/Collection.kt b/src/commonMain/kotlin/com/infendro/bytearray/Collection.kt index 9b11c09..893eacb 100644 --- a/src/commonMain/kotlin/com/infendro/bytearray/Collection.kt +++ b/src/commonMain/kotlin/com/infendro/bytearray/Collection.kt @@ -1,7 +1,75 @@ package com.infendro.bytearray +import com.infendro.bytearray.ByteOrder.BIG_ENDIAN + fun MutableCollection.addAll( bytes: ByteArray, -): Boolean { - return addAll(bytes.toList()) -} +) = addAll(bytes.toList()) + +fun MutableCollection.addAll( + bytes: UByteArray, +) = addAll(bytes.toList()) + +fun Collection.toInt( + order: ByteOrder = BIG_ENDIAN, +) = toByteArray().toInt(order) + +fun Collection.toInt( + order: ByteOrder = BIG_ENDIAN, +) = toUByteArray().toInt(order) + +fun Collection.toIntArray( + order: ByteOrder = BIG_ENDIAN, +) = toByteArray().toIntArray(order) + +fun Collection.toIntArray( + order: ByteOrder = BIG_ENDIAN, +) = toUByteArray().toIntArray(order) + +fun Collection.toLong( + order: ByteOrder = BIG_ENDIAN, +) = toByteArray().toLong(order) + +fun Collection.toLong( + order: ByteOrder = BIG_ENDIAN, +) = toUByteArray().toLong(order) + +fun Collection.toLongArray( + order: ByteOrder = BIG_ENDIAN, +) = toByteArray().toLongArray(order) + +fun Collection.toLongArray( + order: ByteOrder = BIG_ENDIAN, +) = toUByteArray().toLongArray(order) + +fun Collection.toUInt( + order: ByteOrder = BIG_ENDIAN, +) = toByteArray().toUInt(order) + +fun Collection.toUInt( + order: ByteOrder = BIG_ENDIAN, +) = toUByteArray().toUInt(order) + +fun Collection.toUIntArray( + order: ByteOrder = BIG_ENDIAN, +) = toByteArray().toUIntArray(order) + +fun Collection.toUIntArray( + order: ByteOrder = BIG_ENDIAN, +) = toUByteArray().toUIntArray(order) + +fun Collection.toULong( + order: ByteOrder = BIG_ENDIAN, +) = toByteArray().toULong(order) + +fun Collection.toULong( + order: ByteOrder = BIG_ENDIAN, +) = toUByteArray().toULong(order) + +fun Collection.toULongArray( + order: ByteOrder = BIG_ENDIAN, +) = toByteArray().toULongArray(order) + +fun Collection.toULongArray( + order: ByteOrder = BIG_ENDIAN, +) = toUByteArray().toULongArray(order) diff --git a/src/commonMain/kotlin/com/infendro/bytearray/Int.kt b/src/commonMain/kotlin/com/infendro/bytearray/Int.kt index fffdf4d..394a2f7 100644 --- a/src/commonMain/kotlin/com/infendro/bytearray/Int.kt +++ b/src/commonMain/kotlin/com/infendro/bytearray/Int.kt @@ -12,38 +12,12 @@ fun Int.toByteArray( return order.normalize(bytes) } -fun ByteArray.toInt( +fun Int.toUByteArray( order: ByteOrder = BIG_ENDIAN, -): Int { - if (size != 4) throw Exception() - - val bytes = order.normalize(this) - return bytes.fold(0) { acc, byte -> - (acc shl 8) or (byte.toInt() and 0xFF) +): UByteArray { + val bytes = UByteArray(4) { i -> + val offset = (3 - i) * 8 + (this ushr offset).toUByte() } -} - -fun Collection.toInt( - order: ByteOrder = BIG_ENDIAN, -): Int { - return toByteArray() - .toInt(order) -} - -fun ByteArray.toIntArray( - order: ByteOrder = BIG_ENDIAN, -): IntArray { - if (size % 4 != 0) throw Exception() - - return toList() - .chunked(4) - .map { it.toInt(order) } - .toIntArray() -} - -fun Collection.toIntArray( - order: ByteOrder = BIG_ENDIAN, -): IntArray { - return toByteArray() - .toIntArray(order) + return order.normalize(bytes) } diff --git a/src/commonMain/kotlin/com/infendro/bytearray/Long.kt b/src/commonMain/kotlin/com/infendro/bytearray/Long.kt index 5cbd8a2..873edef 100644 --- a/src/commonMain/kotlin/com/infendro/bytearray/Long.kt +++ b/src/commonMain/kotlin/com/infendro/bytearray/Long.kt @@ -12,38 +12,12 @@ fun Long.toByteArray( return order.normalize(bytes) } -fun ByteArray.toLong( +fun Long.toUByteArray( order: ByteOrder = BIG_ENDIAN, -): Long { - if (size != 8) throw Exception() - - val bytes = order.normalize(this) - return bytes.fold(0L) { acc, byte -> - (acc shl 8) or (byte.toLong() and 0xFFL) +): UByteArray { + val bytes = UByteArray(8) { i -> + val offset = (7 - i) * 8 + (this ushr offset).toUByte() } -} - -fun Collection.toLong( - order: ByteOrder = BIG_ENDIAN, -): Long { - return toByteArray() - .toLong(order) -} - -fun ByteArray.toLongArray( - order: ByteOrder = BIG_ENDIAN, -): LongArray { - if (size % 8 != 0) throw Exception() - - return toList() - .chunked(8) - .map { it.toLong(order) } - .toLongArray() -} - -fun Collection.toLongArray( - order: ByteOrder = BIG_ENDIAN, -): LongArray { - return toByteArray() - .toLongArray(order) + return order.normalize(bytes) } diff --git a/src/commonMain/kotlin/com/infendro/bytearray/UByteArray.kt b/src/commonMain/kotlin/com/infendro/bytearray/UByteArray.kt new file mode 100644 index 0000000..82acab0 --- /dev/null +++ b/src/commonMain/kotlin/com/infendro/bytearray/UByteArray.kt @@ -0,0 +1,145 @@ +package com.infendro.bytearray + +import com.infendro.bytearray.ByteOrder.BIG_ENDIAN + +infix fun UByteArray.and( + that: UByteArray, +): UByteArray { + if (this.size != that.size) throw Exception() + + return UByteArray(size) { i -> + this[i] and that[i] + } +} + +infix fun UByteArray.or( + that: UByteArray, +): UByteArray { + if (this.size != that.size) throw Exception() + + return UByteArray(size) { i -> + this[i] or that[i] + } +} + +infix fun UByteArray.xor( + that: UByteArray, +): UByteArray { + if (this.size != that.size) throw Exception() + + return UByteArray(size) { i -> + this[i] xor that[i] + } +} + +fun UByteArray.padStart( + length: Int, + padByte: UByte, +): UByteArray { + return buildList { + repeat(length - size) { + add(padByte) + } + addAll(this) + }.toUByteArray() +} + +fun UByteArray.padEnd( + length: Int, + padByte: UByte, +): UByteArray { + return buildList { + repeat(length - size) { + add(padByte) + } + addAll(this) + }.toUByteArray() +} + +fun UByteArray.toInt( + order: ByteOrder = BIG_ENDIAN, +): Int { + if (size != 4) throw Exception() + + val bytes = order.normalize(this) + return bytes.fold(0) { acc, byte -> + (acc shl 8) or (byte.toInt() and 0xFF) + } +} + +fun UByteArray.toIntArray( + order: ByteOrder = BIG_ENDIAN, +): IntArray { + if (size % 4 != 0) throw Exception() + + return toList() + .chunked(4) + .map { it.toInt(order) } + .toIntArray() +} + +fun UByteArray.toLong( + order: ByteOrder = BIG_ENDIAN, +): Long { + if (size != 8) throw Exception() + + val bytes = order.normalize(this) + return bytes.fold(0L) { acc, byte -> + (acc shl 8) or (byte.toLong() and 0xFFL) + } +} + +fun UByteArray.toLongArray( + order: ByteOrder = BIG_ENDIAN, +): LongArray { + if (size % 8 != 0) throw Exception() + + return toList() + .chunked(8) + .map { it.toLong(order) } + .toLongArray() +} + +fun UByteArray.toUInt( + order: ByteOrder = BIG_ENDIAN, +): UInt { + if (size != 4) throw Exception() + + val bytes = order.normalize(this) + return bytes.fold(0U) { acc, byte -> + (acc shl 8) or (byte.toUInt() and 0xFFU) + } +} + +fun UByteArray.toUIntArray( + order: ByteOrder = BIG_ENDIAN, +): UIntArray { + if (size % 4 != 0) throw Exception() + + return toList() + .chunked(4) + .map { it.toUInt(order) } + .toUIntArray() +} + +fun UByteArray.toULong( + order: ByteOrder = BIG_ENDIAN, +): ULong { + if (size != 8) throw Exception() + + val bytes = order.normalize(this) + return bytes.fold(0UL) { acc, byte -> + (acc shl 8) or (byte.toULong() and 0xFFUL) + } +} + +fun UByteArray.toULongArray( + order: ByteOrder = BIG_ENDIAN, +): ULongArray { + if (size % 8 != 0) throw Exception() + + return toList() + .chunked(8) + .map { it.toULong(order) } + .toULongArray() +} diff --git a/src/commonMain/kotlin/com/infendro/bytearray/UInt.kt b/src/commonMain/kotlin/com/infendro/bytearray/UInt.kt index 9f6884b..371971c 100644 --- a/src/commonMain/kotlin/com/infendro/bytearray/UInt.kt +++ b/src/commonMain/kotlin/com/infendro/bytearray/UInt.kt @@ -12,38 +12,12 @@ fun UInt.toByteArray( return order.normalize(bytes) } -fun ByteArray.toUInt( +fun UInt.toUByteArray( order: ByteOrder = BIG_ENDIAN, -): UInt { - if (size != 4) throw Exception() - - val bytes = order.normalize(this) - return bytes.fold(0U) { acc, byte -> - (acc shl 8) or (byte.toUInt() and 0xFFU) +): UByteArray { + val bytes = UByteArray(4) { i -> + val offset = (3 - i) * 8 + (this shr offset).toUByte() } -} - -fun Collection.toUInt( - order: ByteOrder = BIG_ENDIAN, -): UInt { - return toByteArray() - .toUInt(order) -} - -fun ByteArray.toUIntArray( - order: ByteOrder = BIG_ENDIAN, -): UIntArray { - if (size % 4 != 0) throw Exception() - - return toList() - .chunked(4) - .map { it.toUInt(order) } - .toUIntArray() -} - -fun Collection.toUIntArray( - order: ByteOrder = BIG_ENDIAN, -): UIntArray { - return toByteArray() - .toUIntArray(order) + return order.normalize(bytes) } diff --git a/src/commonMain/kotlin/com/infendro/bytearray/ULong.kt b/src/commonMain/kotlin/com/infendro/bytearray/ULong.kt index bb49fd2..ba77ef7 100644 --- a/src/commonMain/kotlin/com/infendro/bytearray/ULong.kt +++ b/src/commonMain/kotlin/com/infendro/bytearray/ULong.kt @@ -12,38 +12,12 @@ fun ULong.toByteArray( return order.normalize(bytes) } -fun ByteArray.toULong( +fun ULong.toUByteArray( order: ByteOrder = BIG_ENDIAN, -): ULong { - if (size != 8) throw Exception() - - val bytes = order.normalize(this) - return bytes.fold(0UL) { acc, byte -> - (acc shl 8) or (byte.toULong() and 0xFFUL) +): UByteArray { + val bytes = UByteArray(8) { i -> + val offset = (7 - i) * 8 + (this shr offset).toUByte() } -} - -fun Collection.toULong( - order: ByteOrder = BIG_ENDIAN, -): ULong { - return toByteArray() - .toULong(order) -} - -fun ByteArray.toULongArray( - order: ByteOrder = BIG_ENDIAN, -): ULongArray { - if (size % 8 != 0) throw Exception() - - return toList() - .chunked(8) - .map { it.toULong(order) } - .toULongArray() -} - -fun Collection.toULongArray( - order: ByteOrder = BIG_ENDIAN, -): ULongArray { - return toByteArray() - .toULongArray(order) + return order.normalize(bytes) } diff --git a/src/commonMain/kotlin/com/infendro/bytearray/operation.kt b/src/commonMain/kotlin/com/infendro/bytearray/operation.kt deleted file mode 100644 index 0e0301f..0000000 --- a/src/commonMain/kotlin/com/infendro/bytearray/operation.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.infendro.bytearray - -import kotlin.experimental.and -import kotlin.experimental.or -import kotlin.experimental.xor - -infix fun ByteArray.and( - that: ByteArray, -): ByteArray { - if (this.size != that.size) throw Exception() - - return ByteArray(size) { i -> - this[i] and that[i] - } -} - -infix fun ByteArray.or( - that: ByteArray, -): ByteArray { - if (this.size != that.size) throw Exception() - - return ByteArray(size) { i -> - this[i] or that[i] - } -} - -infix fun ByteArray.xor( - that: ByteArray, -): ByteArray { - if (this.size != that.size) throw Exception() - - return ByteArray(size) { i -> - this[i] xor that[i] - } -}