Last active
November 23, 2020 09:37
-
-
Save ktprograms/c6a180216b719b7ac4c8798a26bb74a8 to your computer and use it in GitHub Desktop.
Kotlin Base85 (Ascii85) encoder/decoder. Doesn't add the <~ and ~> at the start and end.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import kotlin.math.pow | |
object Base85 { | |
// Data class to represent the 5 output values of the base85 / ascii85 encoding | |
private data class Block(val a: UInt, val b: UInt, val c: UInt, val d: UInt, val e: UInt) | |
// Encode a ByteArray to a Base85 / Ascii85 String | |
fun encode(arr: ByteArray): String { | |
var final = "" | |
for (x in arr.indices step 4) { | |
val uInt = arr uIntAt x | |
val block = getBlock(uInt) | |
final = final add block | |
} | |
return final | |
} | |
// Decode a Base85 / Ascii85 String to a ByteArray | |
fun decode(str: String): ByteArray { | |
var final = ByteArray(0) | |
for (i in str.indices step 5) { | |
val c0 = str[i].toInt() - 33 | |
val c1 = str[i + 1].toInt() - 33 | |
val c2 = str[i + 2].toInt() - 33 | |
val c3 = str[i + 3].toInt() - 33 | |
val c4 = str[i + 4].toInt() - 33 | |
val v = (c0 * (85.0).pow(4)) + (c1 * (85.0).pow(3)) + (c2 * (85.0).pow(2)) + (c3 * 85.0) + c4 | |
val vStr = v.toLong().to32bitString() | |
for (j in 0..3) { | |
final += Integer.parseInt(vStr.substring(j * 8, (j + 1) * 8), 2).toByte() | |
} | |
} | |
return final | |
} | |
// Functions used for encoding / decoding | |
private infix fun ByteArray.uIntAt(i: Int) = | |
((this[i].toUInt() and 0xFFu) shl 24) or | |
((this[i + 1].toUInt() and 0xFFu) shl 16) or | |
((this[i + 2].toUInt() and 0xFFu) shl 8) or | |
(this[i + 3].toUInt() and 0xFFu) | |
private fun getBlock(uInt: UInt): Block { | |
var n = uInt | |
val base = 85 | |
val uBase = base.toUInt() | |
val add = 33 | |
val uAdd = add.toUInt() | |
val e = n.rem(uBase).plus(uAdd) | |
n = n.div(uBase) | |
val d = n.rem(uBase).plus(uAdd) | |
n = n.div(uBase) | |
val c = n.rem(uBase).plus(uAdd) | |
n = n.div(uBase) | |
val b = n.rem(uBase).plus(uAdd) | |
n = n.div(uBase) | |
val a = n.rem(uBase).plus(uAdd) | |
return Block(a, b, c, d, e) | |
} | |
private infix fun String.add(block: Block): String { | |
var str = this | |
str += block.a.toInt().toChar() | |
str += block.b.toInt().toChar() | |
str += block.c.toInt().toChar() | |
str += block.d.toInt().toChar() | |
str += block.e.toInt().toChar() | |
return str | |
} | |
private fun Long.to32bitString(): String = | |
java.lang.Long.toBinaryString(this).padStart(Int.SIZE_BITS, '0') | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment