diff --git a/.gitea/workflows/main.yaml b/.gitea/workflows/main.yaml deleted file mode 100644 index 4885477..0000000 --- a/.gitea/workflows/main.yaml +++ /dev/null @@ -1,36 +0,0 @@ -on: - push: - branches: - - main - -env: - INFENDRO__TOKEN: ${{ secrets.TOKEN }} - -jobs: - publish: - runs-on: linux - steps: - - uses: actions/checkout@v4 - - - uses: actions/cache/restore@v4 - with: - key: gradle - path: | - ~/.gradle/caches/ - ~/.gradle/wrapper/ - ~/.konan/ - - - uses: actions/setup-java@v4 - with: - java-version: '24' - distribution: 'temurin' - - - run: ./gradlew publish - - - uses: actions/cache/save@v4 - with: - key: gradle - path: | - ~/.gradle/caches/ - ~/.gradle/wrapper/ - ~/.konan/ diff --git a/.gitea/workflows/publish.yaml b/.gitea/workflows/publish.yaml new file mode 100644 index 0000000..dad1306 --- /dev/null +++ b/.gitea/workflows/publish.yaml @@ -0,0 +1,47 @@ +on: + push: + branches: [ main ] + +jobs: + publish: + runs-on: linux + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + java-version: '24' + distribution: 'temurin' + + - name: Cache Gradle + uses: actions/cache@v4 + with: + key: gradle-${{ hashFiles('**/libs.versions.toml') }} + restore-keys: gradle + path: | + ~/.gradle/caches/ + ~/.gradle/wrapper/ + + - name: Cache Konan + uses: actions/cache@v4 + with: + key: konan-${{ hashFiles('**/libs.versions.toml') }} + restore-keys: konan + path: | + ~/.konan/ + + - name: Cache Node + uses: actions/cache@v4 + with: + key: node-${{ hashFiles('**/libs.versions.toml') }} + restore-keys: node + path: | + ~/.gradle/nodejs + ~/.gradle/yarn + + - name: Publish + run: ./gradlew publish + env: + INFENDRO__TOKEN: ${{ secrets.TOKEN }} diff --git a/.gitea/workflows/test.yaml b/.gitea/workflows/test.yaml new file mode 100644 index 0000000..bce9e35 --- /dev/null +++ b/.gitea/workflows/test.yaml @@ -0,0 +1,28 @@ +on: + pull_request: + branches: [ main ] + +jobs: + test: + runs-on: linux + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + java-version: '24' + distribution: 'temurin' + + - name: Cache Gradle + uses: actions/cache@v4 + with: + key: gradle-${{ hashFiles('**/libs.versions.toml') }} + restore-keys: gradle + path: | + ~/.gradle/caches/ + ~/.gradle/wrapper/ + + - name: Test + run: ./gradlew jvmTest diff --git a/README.md b/README.md index 18d1c5f..6828ec2 100644 --- a/README.md +++ b/README.md @@ -5,18 +5,15 @@ Supported encodings: - Base2 (binary) - Base8 (octal) -- Base16 (hexadecimal) +- Base10 (decimal) +- Base16 (hexadecimal, uppercase/lowercase) - Base32 -- Base64 - -## Targets - -| Target | Status | -|------------------|---------------| -| JVM | Supported | -| JavaScript | Supported | -| Native (Linux) | Supported | -| Native (Windows) | Not Supported | +- Base36 +- Base45 +- Base56 +- Base58 +- Base62 +- Base64 (standard/URL) ## Installation @@ -28,24 +25,20 @@ repositories { } dependencies { - implementation("com.infendro:encoding:1.2.0") + implementation("com.infendro:encoding:1.3.0") } ``` ## Usage ```kotlin -import com.infendro.encoding.Base16 - fun main() { // the string to encode - val test = "Hello World!" - .encodeToByteArray().asUByteArray() + val test = "Hello World!".encodeToByteArray() // encode the string with the desired encoding - val encoded = Base16.encode(test) - .asByteArray().decodeToString() + val encoded = Base16.encode(test).decodeToString() - println(encoded) // 48656c6c6f20576f726c6421 + println(encoded) // 48656C6C6F20576F726C6421 } ``` diff --git a/build.gradle.kts b/build.gradle.kts index 8e65a48..cbb9453 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,11 @@ +@file:OptIn(ExperimentalWasmDsl::class) + import com.infendro.plugin.infendro import com.infendro.plugin.token +import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl group = "com.infendro" -version = "1.2.0" +version = "1.3.0" plugins { alias(libs.plugins.infendro) @@ -12,10 +15,14 @@ plugins { kotlin { jvm() - js { - nodejs() - } linuxX64() + linuxArm64() + mingwX64() + macosX64() + macosArm64() + js { nodejs() } + wasmJs { nodejs() } + wasmWasi { nodejs() } repositories { mavenCentral() @@ -26,10 +33,6 @@ kotlin { implementation(libs.test) } } - - compilerOptions { - freeCompilerArgs.add("-opt-in=kotlin.ExperimentalUnsignedTypes") - } } publishing.repositories { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 10d43ce..9194c62 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] infendro = "1.0.0" -kotlin = "2.2.21" +kotlin = "2.3.0" [plugins] infendro = { id = "com.infendro.plugin", version.ref = "infendro" } diff --git a/src/commonMain/kotlin/com/infendro/encoding/Base10.kt b/src/commonMain/kotlin/com/infendro/encoding/Base10.kt new file mode 100644 index 0000000..eab2713 --- /dev/null +++ b/src/commonMain/kotlin/com/infendro/encoding/Base10.kt @@ -0,0 +1,5 @@ +package com.infendro.encoding + +private val alphabet = "0123456789".encodeToByteArray() + +object Base10 : Encoding by NumericEncoding(alphabet) diff --git a/src/commonMain/kotlin/com/infendro/encoding/Base16.kt b/src/commonMain/kotlin/com/infendro/encoding/Base16.kt index 4c23230..6530b7c 100644 --- a/src/commonMain/kotlin/com/infendro/encoding/Base16.kt +++ b/src/commonMain/kotlin/com/infendro/encoding/Base16.kt @@ -1,16 +1,10 @@ package com.infendro.encoding -object Base16 : Encoding() { - private val CHARACTERS = ubyteArrayOf( - 0x30U, 0x31U, 0x32U, 0x33U, 0x34U, 0x35U, 0x36U, 0x37U, - 0x38U, 0x39U, 0x61U, 0x62U, 0x63U, 0x64U, 0x65U, 0x66U, - ) +private val uppercase = "0123456789ABCDEF".encodeToByteArray() +private val lowercase = "0123456789abcdef".encodeToByteArray() - override fun encode( - bytes: UByteArray, - ) = encode(bytes, CHARACTERS) +object Base16 : Encoding by StreamEncoding(uppercase) { + val UPPERCASE = this - override fun decode( - bytes: UByteArray, - ) = decode(bytes, CHARACTERS) + object LOWERCASE : Encoding by StreamEncoding(lowercase) } diff --git a/src/commonMain/kotlin/com/infendro/encoding/Base2.kt b/src/commonMain/kotlin/com/infendro/encoding/Base2.kt index a6de71b..ec8db94 100644 --- a/src/commonMain/kotlin/com/infendro/encoding/Base2.kt +++ b/src/commonMain/kotlin/com/infendro/encoding/Base2.kt @@ -1,15 +1,5 @@ package com.infendro.encoding -object Base2 : Encoding() { - private val CHARACTERS = ubyteArrayOf( - 0x30U, 0x31U, - ) +private val alphabet = "01".encodeToByteArray() - override fun encode( - bytes: UByteArray, - ) = encode(bytes, CHARACTERS) - - override fun decode( - bytes: UByteArray, - ) = decode(bytes, CHARACTERS) -} +object Base2 : Encoding by StreamEncoding(alphabet) diff --git a/src/commonMain/kotlin/com/infendro/encoding/Base32.kt b/src/commonMain/kotlin/com/infendro/encoding/Base32.kt index 007471f..b89a8cb 100644 --- a/src/commonMain/kotlin/com/infendro/encoding/Base32.kt +++ b/src/commonMain/kotlin/com/infendro/encoding/Base32.kt @@ -1,19 +1,6 @@ package com.infendro.encoding -object Base32 : Encoding() { - private val CHARACTERS = ubyteArrayOf( - 0x41U, 0x42U, 0x43U, 0x44U, 0x45U, 0x46U, 0x47U, 0x48U, - 0x49U, 0x4aU, 0x4bU, 0x4cU, 0x4dU, 0x4eU, 0x4fU, 0x50U, - 0x51U, 0x52U, 0x53U, 0x54U, 0x55U, 0x56U, 0x57U, 0x58U, - 0x59U, 0x5aU, 0x32U, 0x33U, 0x34U, 0x35U, 0x36U, 0x37U, - ) - private const val PADDING: UByte = 0x3dU +private val alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".encodeToByteArray() +private const val padding = '='.code.toByte() - override fun encode( - bytes: UByteArray, - ) = encode(bytes, CHARACTERS, PADDING) - - override fun decode( - bytes: UByteArray, - ) = decode(bytes, CHARACTERS, PADDING) -} +object Base32 : Encoding by StreamEncoding(alphabet, padding) diff --git a/src/commonMain/kotlin/com/infendro/encoding/Base36.kt b/src/commonMain/kotlin/com/infendro/encoding/Base36.kt new file mode 100644 index 0000000..421b3cc --- /dev/null +++ b/src/commonMain/kotlin/com/infendro/encoding/Base36.kt @@ -0,0 +1,5 @@ +package com.infendro.encoding + +private val alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".encodeToByteArray() + +object Base36 : Encoding by NumericEncoding(alphabet) diff --git a/src/commonMain/kotlin/com/infendro/encoding/Base45.kt b/src/commonMain/kotlin/com/infendro/encoding/Base45.kt new file mode 100644 index 0000000..c24808a --- /dev/null +++ b/src/commonMain/kotlin/com/infendro/encoding/Base45.kt @@ -0,0 +1,51 @@ +package com.infendro.encoding + +import com.infendro.encoding.exception.IllegalByteException + +object Base45 : Encoding { + private val alphabet: ByteArray = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".encodeToByteArray() + private val base: Int = alphabet.size + + override fun encode(bytes: ByteArray): ByteArray { + val result = mutableListOf() + + for (i in bytes.indices step 2) { + val remaining = minOf(bytes.size - i, 2) + + var value = 0 + for (j in 0..() + + for (i in bytes.indices step 3) { + val remaining = minOf(bytes.size - i, 3) + + var value = 0 + for (j in (0..() - - var buffer = 0U - var bits = 0 - - for (byte in bytes) { - buffer = (buffer shl 8) + byte - bits += 8 - - while (bits >= length) { - val offset = bits - length - val index = (buffer shr offset).toInt() - buffer = buffer and (mask shl offset).inv() - bits -= length - - encoded.add(characters[index]) - } - } - if (bits > 0) { - buffer = buffer shl (length - bits) - val index = buffer.toInt() - encoded.add(characters[index]) - } - - if (padding != null) { - val block = lcm(length, 8) / length - while (encoded.size % block != 0) { - encoded.add(padding) - } - } - - return encoded.toUByteArray() - } - - protected fun decode( - bytes: UByteArray, - characters: UByteArray, - padding: UByte? = null, - ): UByteArray { - val length = log2(characters.size).toInt() - val mask = 0xffU - - val decoded = mutableListOf() - - var buffer = 0U - var bits = 0 - - for (byte in bytes) { - if (byte == padding) break - - val index = characters.indexOf(byte) - if (index == -1) throw Exception() - - buffer = (buffer shl length) + index.toUByte() - bits += length - - if (bits >= 8) { - val offset = bits - 8 - val character = (buffer shr offset).toUByte() - buffer = buffer and (mask shl offset).inv() - bits -= 8 - - decoded.add(character) - } - } - - return decoded.toUByteArray() - } +interface Encoding { + fun encode(bytes: ByteArray): ByteArray + fun decode(bytes: ByteArray): ByteArray } diff --git a/src/commonMain/kotlin/com/infendro/encoding/NumericEncoding.kt b/src/commonMain/kotlin/com/infendro/encoding/NumericEncoding.kt new file mode 100644 index 0000000..36e9555 --- /dev/null +++ b/src/commonMain/kotlin/com/infendro/encoding/NumericEncoding.kt @@ -0,0 +1,39 @@ +package com.infendro.encoding + +import com.infendro.encoding.exception.IllegalByteException +import com.infendro.encoding.util.BigInt + +class NumericEncoding internal constructor( + private val alphabet: ByteArray, +) : Encoding { + private val base: Int = alphabet.size + + override fun encode(bytes: ByteArray): ByteArray { + if (bytes.isEmpty()) return byteArrayOf() + + val result = mutableListOf() + + var x = BigInt.from(bytes) + while (!x.isZero()) { + val (quotient, remainder) = x.divRem(base) + x = quotient + result += alphabet[remainder] + } + + return result.asReversed().toByteArray() + } + + override fun decode(bytes: ByteArray): ByteArray { + if (bytes.isEmpty()) return byteArrayOf() + + var value = BigInt.zero + for (i in 0.. (bytes.size * 8).divCeil(bits) + else -> (bytes.size * 8).divCeil(bits).align(block) + } + val encoded = ByteArray(size) + var i = 0 + + var buffer = 0 + var bufferBits = 0 + for (byte in bytes) { + buffer = (buffer shl 8) or (byte.toInt() and 0xFF) + bufferBits += 8 + + while (bufferBits >= bits) { + val index = (buffer shr (bufferBits - bits)) and mask + bufferBits -= bits + encoded[i++] = alphabet[index] + } + } + if (bufferBits > 0) { + val index = (buffer shl (bits - bufferBits)) and mask + encoded[i++] = alphabet[index] + } + + while (i < encoded.size) { + encoded[i++] = padding!! + } + + return encoded + } + + override fun decode(bytes: ByteArray): ByteArray { + val end = when (padding) { + null -> bytes.size + else -> when (val index = bytes.indexOf(padding)) { + -1 -> bytes.size + else -> index + } + } + val size = end * bits / 8 + val decoded = ByteArray(size) + var i = 0 + + var buffer = 0 + var bufferBits = 0 + for (b in 0..= 8) { + val byte = (buffer shr (bufferBits - 8)) and 0xFF + bufferBits -= 8 + decoded[i++] = byte.toByte() + } + } + + return decoded + } +} diff --git a/src/commonMain/kotlin/com/infendro/encoding/exception/DecodeException.kt b/src/commonMain/kotlin/com/infendro/encoding/exception/DecodeException.kt new file mode 100644 index 0000000..f81ba30 --- /dev/null +++ b/src/commonMain/kotlin/com/infendro/encoding/exception/DecodeException.kt @@ -0,0 +1,5 @@ +package com.infendro.encoding.exception + +abstract class DecodeException : Exception() { + abstract override val message: String +} diff --git a/src/commonMain/kotlin/com/infendro/encoding/exception/IllegalByteException.kt b/src/commonMain/kotlin/com/infendro/encoding/exception/IllegalByteException.kt new file mode 100644 index 0000000..5650bf6 --- /dev/null +++ b/src/commonMain/kotlin/com/infendro/encoding/exception/IllegalByteException.kt @@ -0,0 +1,12 @@ +package com.infendro.encoding.exception + +class IllegalByteException( + val byte: Byte, +) : DecodeException() { + override val message: String + get() { + val hex = "0x${byte.toHexString().padStart(2, '0')}" + val char = "'${byte.toInt().toChar()}'" + return "Illegal byte $hex ($char)." + } +} diff --git a/src/commonMain/kotlin/com/infendro/encoding/util/BigInt.kt b/src/commonMain/kotlin/com/infendro/encoding/util/BigInt.kt new file mode 100644 index 0000000..14c8d39 --- /dev/null +++ b/src/commonMain/kotlin/com/infendro/encoding/util/BigInt.kt @@ -0,0 +1,73 @@ +package com.infendro.encoding.util + +internal class BigInt private constructor( + val words: IntArray, +) { + init { + require(words.isNotEmpty()) + } + + fun isZero(): Boolean = words.all { it == 0 } + + fun timesAdd(multiplier: Int, addend: Int): BigInt { + val product = IntArray(words.size) + var carry = addend + + for (i in words.indices) { + val current = (words[i].toLong() and 0xFFFFFFFFL) * multiplier + carry + product[i] = current.toInt() + carry = (current ushr 32).toInt() + } + + when { + carry > 0 -> { + val expanded = product.copyOf(product.size + 1) + expanded[product.size] = carry + return BigInt(expanded) + } + else -> return BigInt(product) + } + } + + fun divRem(divisor: Int): Pair { + val quotient = IntArray(words.size) + var remainder = 0 + + for (i in words.indices.reversed()) { + val current = (remainder.toLong() shl 32) or (words[i].toLong() and 0xFFFFFFFFL) + quotient[i] = (current / divisor.toLong()).toInt() + remainder = (current % divisor.toLong()).toInt() + } + + when { + quotient.size > 1 && quotient.last() == 0 -> { + val contracted = quotient.copyOfRange(0, quotient.size - 1) + return Pair(BigInt(contracted), remainder) + } + else -> return Pair(BigInt(quotient), remainder) + } + } + + fun toByteArray(): ByteArray { + val bytes = ByteArray((words.size * 4) - words.last().countLeadingZeroBytes()) + for (i in bytes.indices) { + val (wi, bi) = (bytes.lastIndex - i).divRem(4) + bytes[i] = (words[wi] ushr (bi * 8)).toByte() + } + return bytes + } + + companion object { + val zero: BigInt + get() = BigInt(intArrayOf(0)) + + fun from(bytes: ByteArray): BigInt { + val words = IntArray(bytes.size.divCeil(4)) + for (i in bytes.indices) { + val (wi, bi) = (bytes.lastIndex - i).divRem(4) + words[wi] = words[wi] or ((bytes[i].toInt() and 0xFF) shl (bi * 8)) + } + return BigInt(words) + } + } +} diff --git a/src/commonMain/kotlin/com/infendro/encoding/util/Int.kt b/src/commonMain/kotlin/com/infendro/encoding/util/Int.kt new file mode 100644 index 0000000..67cfc57 --- /dev/null +++ b/src/commonMain/kotlin/com/infendro/encoding/util/Int.kt @@ -0,0 +1,7 @@ +package com.infendro.encoding.util + +fun Int.divRem(divisor: Int): Pair = + Pair(this / divisor, this % divisor) + +fun Int.countLeadingZeroBytes(): Int = + countLeadingZeroBits() / 8 diff --git a/src/commonMain/kotlin/com/infendro/encoding/util/Math.kt b/src/commonMain/kotlin/com/infendro/encoding/util/Math.kt index ca08e48..a5ea675 100644 --- a/src/commonMain/kotlin/com/infendro/encoding/util/Math.kt +++ b/src/commonMain/kotlin/com/infendro/encoding/util/Math.kt @@ -2,14 +2,16 @@ package com.infendro.encoding.util import kotlin.math.log2 -internal fun log2( - value: Int, -) = log2(value.toDouble()) +internal fun Int.divCeil(n: Int): Int = + (this + n - 1) / n -internal fun gcd( - a: Int, - b: Int, -): Int { +internal fun Int.align(n: Int): Int = + divCeil(n) * n + +internal fun log2(value: Int): Double = + log2(value.toDouble()) + +internal fun gcd(a: Int, b: Int): Int { var x = a var y = b while (y != 0) { @@ -20,9 +22,6 @@ internal fun gcd( return x } -internal fun lcm( - a: Int, - b: Int, -): Int { +internal fun lcm(a: Int, b: Int): Int { return (a * b) / gcd(a, b) } diff --git a/src/commonTest/kotlin/com/infendro/encoding/Base10.kt b/src/commonTest/kotlin/com/infendro/encoding/Base10.kt new file mode 100644 index 0000000..017b8f7 --- /dev/null +++ b/src/commonTest/kotlin/com/infendro/encoding/Base10.kt @@ -0,0 +1,36 @@ +package com.infendro.encoding + +import kotlin.test.Test +import kotlin.test.assertContentEquals + +class `Base10 Test` { + val encoding: Encoding + get() = Base10 + + val original = "Hello World!".encodeToByteArray() + val encoded = "22405534230753928650781647905".encodeToByteArray() + + @Test + fun `encode empty`() { + val actual = encoding.encode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun `decode empty`() { + val actual = encoding.decode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun encode() { + val actual = encoding.encode(original) + assertContentEquals(encoded, actual) + } + + @Test + fun decode() { + val actual = encoding.decode(encoded) + assertContentEquals(original, actual) + } +} diff --git a/src/commonTest/kotlin/com/infendro/encoding/Base16.kt b/src/commonTest/kotlin/com/infendro/encoding/Base16.kt index 63d7c4b..380e5c9 100644 --- a/src/commonTest/kotlin/com/infendro/encoding/Base16.kt +++ b/src/commonTest/kotlin/com/infendro/encoding/Base16.kt @@ -7,27 +7,30 @@ class `Base16 Test` { val encoding: Encoding get() = Base16 - val `Hello World!` = ubyteArrayOf( - 0x48U, 0x65U, 0x6cU, 0x6cU, - 0x6fU, 0x20U, 0x57U, 0x6fU, - 0x72U, 0x6cU, 0x64U, 0x21U, - ) + val original = "Hello World!".encodeToByteArray() + val encoded = "48656C6C6F20576F726C6421".encodeToByteArray() @Test - fun `encode empty ByteArray`() { - val expected = ubyteArrayOf() - val actual = encoding.encode(ubyteArrayOf()) - assertContentEquals(expected, actual) + fun `encode empty`() { + val actual = encoding.encode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) } @Test - fun `encode "Hello World!"`() { - val expected = ubyteArrayOf( - 0x34U, 0x38U, 0x36U, 0x35U, 0x36U, 0x63U, 0x36U, 0x63U, - 0x36U, 0x66U, 0x32U, 0x30U, 0x35U, 0x37U, 0x36U, 0x66U, - 0x37U, 0x32U, 0x36U, 0x63U, 0x36U, 0x34U, 0x32U, 0x31U, - ) - val actual = encoding.encode(`Hello World!`) - assertContentEquals(expected, actual) + fun `decode empty`() { + val actual = encoding.decode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun encode() { + val actual = encoding.encode(original) + assertContentEquals(encoded, actual) + } + + @Test + fun decode() { + val actual = encoding.decode(encoded) + assertContentEquals(original, actual) } } diff --git a/src/commonTest/kotlin/com/infendro/encoding/Base2.kt b/src/commonTest/kotlin/com/infendro/encoding/Base2.kt index b4fa689..f4235a6 100644 --- a/src/commonTest/kotlin/com/infendro/encoding/Base2.kt +++ b/src/commonTest/kotlin/com/infendro/encoding/Base2.kt @@ -7,36 +7,30 @@ class `Base2 Test` { val encoding: Encoding get() = Base2 - val `Hello World!` = ubyteArrayOf( - 0x48U, 0x65U, 0x6cU, 0x6cU, - 0x6fU, 0x20U, 0x57U, 0x6fU, - 0x72U, 0x6cU, 0x64U, 0x21U, - ) + val original = "Hello World!".encodeToByteArray() + val encoded = "010010000110010101101100011011000110111100100000010101110110111101110010011011000110010000100001".encodeToByteArray() @Test - fun `encode empty ByteArray`() { - val expected = ubyteArrayOf() - val actual = encoding.encode(ubyteArrayOf()) - assertContentEquals(expected, actual) + fun `encode empty`() { + val actual = encoding.encode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) } @Test - fun `encode "Hello World!"`() { - val expected = ubyteArrayOf( - 0x30U, 0x31U, 0x30U, 0x30U, 0x31U, 0x30U, 0x30U, 0x30U, - 0x30U, 0x31U, 0x31U, 0x30U, 0x30U, 0x31U, 0x30U, 0x31U, - 0x30U, 0x31U, 0x31U, 0x30U, 0x31U, 0x31U, 0x30U, 0x30U, - 0x30U, 0x31U, 0x31U, 0x30U, 0x31U, 0x31U, 0x30U, 0x30U, - 0x30U, 0x31U, 0x31U, 0x30U, 0x31U, 0x31U, 0x31U, 0x31U, - 0x30U, 0x30U, 0x31U, 0x30U, 0x30U, 0x30U, 0x30U, 0x30U, - 0x30U, 0x31U, 0x30U, 0x31U, 0x30U, 0x31U, 0x31U, 0x31U, - 0x30U, 0x31U, 0x31U, 0x30U, 0x31U, 0x31U, 0x31U, 0x31U, - 0x30U, 0x31U, 0x31U, 0x31U, 0x30U, 0x30U, 0x31U, 0x30U, - 0x30U, 0x31U, 0x31U, 0x30U, 0x31U, 0x31U, 0x30U, 0x30U, - 0x30U, 0x31U, 0x31U, 0x30U, 0x30U, 0x31U, 0x30U, 0x30U, - 0x30U, 0x30U, 0x31U, 0x30U, 0x30U, 0x30U, 0x30U, 0x31U, - ) - val actual = encoding.encode(`Hello World!`) - assertContentEquals(expected, actual) + fun `decode empty`() { + val actual = encoding.decode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun encode() { + val actual = encoding.encode(original) + assertContentEquals(encoded, actual) + } + + @Test + fun decode() { + val actual = encoding.decode(encoded) + assertContentEquals(original, actual) } } diff --git a/src/commonTest/kotlin/com/infendro/encoding/Base32.kt b/src/commonTest/kotlin/com/infendro/encoding/Base32.kt index 76362c2..5a10dfc 100644 --- a/src/commonTest/kotlin/com/infendro/encoding/Base32.kt +++ b/src/commonTest/kotlin/com/infendro/encoding/Base32.kt @@ -7,27 +7,30 @@ class `Base32 Test` { val encoding: Encoding get() = Base32 - val `Hello World!` = ubyteArrayOf( - 0x48U, 0x65U, 0x6cU, 0x6cU, - 0x6fU, 0x20U, 0x57U, 0x6fU, - 0x72U, 0x6cU, 0x64U, 0x21U, - ) + val original = "Hello World!".encodeToByteArray() + val encoded = "JBSWY3DPEBLW64TMMQQQ====".encodeToByteArray() @Test - fun `encode empty ByteArray`() { - val expected = ubyteArrayOf() - val actual = encoding.encode(ubyteArrayOf()) - assertContentEquals(expected, actual) + fun `encode empty`() { + val actual = encoding.encode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) } @Test - fun `encode "Hello World!"`() { - val expected = ubyteArrayOf( - 0x4aU, 0x42U, 0x53U, 0x57U, 0x59U, 0x33U, 0x44U, 0x50U, - 0x45U, 0x42U, 0x4cU, 0x57U, 0x36U, 0x34U, 0x54U, 0x4dU, - 0x4dU, 0x51U, 0x51U, 0x51U, 0x3dU, 0x3dU, 0x3dU, 0x3dU, - ) - val actual = encoding.encode(`Hello World!`) - assertContentEquals(expected, actual) + fun `decode empty`() { + val actual = encoding.decode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun encode() { + val actual = encoding.encode(original) + assertContentEquals(encoded, actual) + } + + @Test + fun decode() { + val actual = encoding.decode(encoded) + assertContentEquals(original, actual) } } diff --git a/src/commonTest/kotlin/com/infendro/encoding/Base36.kt b/src/commonTest/kotlin/com/infendro/encoding/Base36.kt new file mode 100644 index 0000000..3dc916b --- /dev/null +++ b/src/commonTest/kotlin/com/infendro/encoding/Base36.kt @@ -0,0 +1,36 @@ +package com.infendro.encoding + +import kotlin.test.Test +import kotlin.test.assertContentEquals + +class `Base36 Test` { + val encoding: Encoding + get() = Base36 + + val original = "Hello World!".encodeToByteArray() + val encoded = "2678LX5GVMSV1DRO9B5".encodeToByteArray() + + @Test + fun `encode empty`() { + val actual = encoding.encode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun `decode empty`() { + val actual = encoding.decode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun encode() { + val actual = encoding.encode(original) + assertContentEquals(encoded, actual) + } + + @Test + fun decode() { + val actual = encoding.decode(encoded) + assertContentEquals(original, actual) + } +} diff --git a/src/commonTest/kotlin/com/infendro/encoding/Base45.kt b/src/commonTest/kotlin/com/infendro/encoding/Base45.kt new file mode 100644 index 0000000..b1f91aa --- /dev/null +++ b/src/commonTest/kotlin/com/infendro/encoding/Base45.kt @@ -0,0 +1,36 @@ +package com.infendro.encoding + +import kotlin.test.Test +import kotlin.test.assertContentEquals + +class `Base45 Test` { + val encoding: Encoding + get() = Base45 + + val original = "Hello World!".encodeToByteArray() + val encoded = "%69 VD82EI2B.KESTC".encodeToByteArray() + + @Test + fun `encode empty`() { + val actual = encoding.encode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun `decode empty`() { + val actual = encoding.decode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun encode() { + val actual = encoding.encode(original) + assertContentEquals(encoded, actual) + } + + @Test + fun decode() { + val actual = encoding.decode(encoded) + assertContentEquals(original, actual) + } +} diff --git a/src/commonTest/kotlin/com/infendro/encoding/Base56.kt b/src/commonTest/kotlin/com/infendro/encoding/Base56.kt new file mode 100644 index 0000000..9147642 --- /dev/null +++ b/src/commonTest/kotlin/com/infendro/encoding/Base56.kt @@ -0,0 +1,36 @@ +package com.infendro.encoding + +import kotlin.test.Test +import kotlin.test.assertContentEquals + +class `Base56 Test` { + val encoding: Encoding + get() = Base56 + + val original = "Hello World!".encodeToByteArray() + val encoded = "4Q9SNpVv4JrdwvjKj".encodeToByteArray() + + @Test + fun `encode empty`() { + val actual = encoding.encode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun `decode empty`() { + val actual = encoding.decode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun encode() { + val actual = encoding.encode(original) + assertContentEquals(encoded, actual) + } + + @Test + fun decode() { + val actual = encoding.decode(encoded) + assertContentEquals(original, actual) + } +} diff --git a/src/commonTest/kotlin/com/infendro/encoding/Base58.kt b/src/commonTest/kotlin/com/infendro/encoding/Base58.kt new file mode 100644 index 0000000..5a8e82e --- /dev/null +++ b/src/commonTest/kotlin/com/infendro/encoding/Base58.kt @@ -0,0 +1,36 @@ +package com.infendro.encoding + +import kotlin.test.Test +import kotlin.test.assertContentEquals + +class `Base58 Test` { + val encoding: Encoding + get() = Base58 + + val original = "Hello World!".encodeToByteArray() + val encoded = "2NEpo7TZRRrLZSi2U".encodeToByteArray() + + @Test + fun `encode empty`() { + val actual = encoding.encode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun `decode empty`() { + val actual = encoding.decode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun encode() { + val actual = encoding.encode(original) + assertContentEquals(encoded, actual) + } + + @Test + fun decode() { + val actual = encoding.decode(encoded) + assertContentEquals(original, actual) + } +} diff --git a/src/commonTest/kotlin/com/infendro/encoding/Base62.kt b/src/commonTest/kotlin/com/infendro/encoding/Base62.kt new file mode 100644 index 0000000..fa67355 --- /dev/null +++ b/src/commonTest/kotlin/com/infendro/encoding/Base62.kt @@ -0,0 +1,36 @@ +package com.infendro.encoding + +import kotlin.test.Test +import kotlin.test.assertContentEquals + +class `Base62 Test` { + val encoding: Encoding + get() = Base62 + + val original = "Hello World!".encodeToByteArray() + val encoded = "T8dgcjRGkZ3aysdN".encodeToByteArray() + + @Test + fun `encode empty`() { + val actual = encoding.encode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun `decode empty`() { + val actual = encoding.decode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun encode() { + val actual = encoding.encode(original) + assertContentEquals(encoded, actual) + } + + @Test + fun decode() { + val actual = encoding.decode(encoded) + assertContentEquals(original, actual) + } +} diff --git a/src/commonTest/kotlin/com/infendro/encoding/Base64.kt b/src/commonTest/kotlin/com/infendro/encoding/Base64.kt index 169591d..3ac84ef 100644 --- a/src/commonTest/kotlin/com/infendro/encoding/Base64.kt +++ b/src/commonTest/kotlin/com/infendro/encoding/Base64.kt @@ -7,26 +7,30 @@ class `Base64 Test` { val encoding: Encoding get() = Base64 - val `Hello World!` = ubyteArrayOf( - 0x48U, 0x65U, 0x6cU, 0x6cU, - 0x6fU, 0x20U, 0x57U, 0x6fU, - 0x72U, 0x6cU, 0x64U, 0x21U, - ) + val original = "Hello World!".encodeToByteArray() + val encoded = "SGVsbG8gV29ybGQh".encodeToByteArray() @Test - fun `encode empty ByteArray`() { - val expected = ubyteArrayOf() - val actual = encoding.encode(ubyteArrayOf()) - assertContentEquals(expected, actual) + fun `encode empty`() { + val actual = encoding.encode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) } @Test - fun `encode "Hello World!"`() { - val expected = ubyteArrayOf( - 0x53U, 0x47U, 0x56U, 0x73U, 0x62U, 0x47U, 0x38U, 0x67U, - 0x56U, 0x32U, 0x39U, 0x79U, 0x62U, 0x47U, 0x51U, 0x68U, - ) - val actual = encoding.encode(`Hello World!`) - assertContentEquals(expected, actual) + fun `decode empty`() { + val actual = encoding.decode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun encode() { + val actual = encoding.encode(original) + assertContentEquals(encoded, actual) + } + + @Test + fun decode() { + val actual = encoding.decode(encoded) + assertContentEquals(original, actual) } } diff --git a/src/commonTest/kotlin/com/infendro/encoding/Base8.kt b/src/commonTest/kotlin/com/infendro/encoding/Base8.kt index ce16791..3f16e9d 100644 --- a/src/commonTest/kotlin/com/infendro/encoding/Base8.kt +++ b/src/commonTest/kotlin/com/infendro/encoding/Base8.kt @@ -7,28 +7,30 @@ class `Base8 Test` { val encoding: Encoding get() = Base8 - val `Hello World!` = ubyteArrayOf( - 0x48U, 0x65U, 0x6cU, 0x6cU, - 0x6fU, 0x20U, 0x57U, 0x6fU, - 0x72U, 0x6cU, 0x64U, 0x21U, - ) + val original = "Hello World!".encodeToByteArray() + val encoded = "22062554330674402566756233062041".encodeToByteArray() @Test - fun `encode empty ByteArray`() { - val expected = ubyteArrayOf() - val actual = encoding.encode(ubyteArrayOf()) - assertContentEquals(expected, actual) + fun `encode empty`() { + val actual = encoding.encode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) } @Test - fun `encode "Hello World!"`() { - val expected = ubyteArrayOf( - 0x32U, 0x32U, 0x30U, 0x36U, 0x32U, 0x35U, 0x35U, 0x34U, - 0x33U, 0x33U, 0x30U, 0x36U, 0x37U, 0x34U, 0x34U, 0x30U, - 0x32U, 0x35U, 0x36U, 0x36U, 0x37U, 0x35U, 0x36U, 0x32U, - 0x33U, 0x33U, 0x30U, 0x36U, 0x32U, 0x30U, 0x34U, 0x31U, - ) - val actual = encoding.encode(`Hello World!`) - assertContentEquals(expected, actual) + fun `decode empty`() { + val actual = encoding.decode(byteArrayOf()) + assertContentEquals(byteArrayOf(), actual) + } + + @Test + fun encode() { + val actual = encoding.encode(original) + assertContentEquals(encoded, actual) + } + + @Test + fun decode() { + val actual = encoding.decode(encoded) + assertContentEquals(original, actual) } }