1.3.0 release #7
@@ -3,4 +3,4 @@ package com.infendro.encoding
|
|||||||
private val alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".encodeToByteArray()
|
private val alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".encodeToByteArray()
|
||||||
private const val padding = '='.code.toByte()
|
private const val padding = '='.code.toByte()
|
||||||
|
|
||||||
object Base32 : Encoding by StreamEncoding(alphabet, padding)
|
object Base32 : Encoding by PaddedStreamEncoding(alphabet, padding)
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ package com.infendro.encoding
|
|||||||
private val alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".encodeToByteArray()
|
private val alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".encodeToByteArray()
|
||||||
private const val padding = '='.code.toByte()
|
private const val padding = '='.code.toByte()
|
||||||
|
|
||||||
object Base64 : Encoding by StreamEncoding(alphabet, padding)
|
object Base64 : Encoding by PaddedStreamEncoding(alphabet, padding)
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ package com.infendro.encoding
|
|||||||
|
|
||||||
import com.infendro.encoding.exception.IllegalByteException
|
import com.infendro.encoding.exception.IllegalByteException
|
||||||
import com.infendro.encoding.util.BigInt
|
import com.infendro.encoding.util.BigInt
|
||||||
import com.infendro.encoding.util.log2
|
|
||||||
import kotlin.math.ceil
|
|
||||||
|
|
||||||
class NumericEncoding internal constructor(
|
class NumericEncoding internal constructor(
|
||||||
override val alphabet: ByteArray,
|
override val alphabet: ByteArray,
|
||||||
@@ -11,18 +9,16 @@ class NumericEncoding internal constructor(
|
|||||||
override fun encode(bytes: ByteArray): ByteArray {
|
override fun encode(bytes: ByteArray): ByteArray {
|
||||||
if (bytes.isEmpty()) return byteArrayOf()
|
if (bytes.isEmpty()) return byteArrayOf()
|
||||||
|
|
||||||
val size = ceil(bytes.size * 8 / log2(base)).toInt()
|
val result = mutableListOf<Byte>()
|
||||||
val result = ByteArray(size)
|
|
||||||
|
|
||||||
var i = result.size
|
|
||||||
var x = BigInt.from(bytes)
|
var x = BigInt.from(bytes)
|
||||||
while (!x.isZero()) {
|
while (!x.isZero()) {
|
||||||
val (quotient, remainder) = x.divRem(base)
|
val (quotient, remainder) = x.divRem(base)
|
||||||
x = quotient
|
x = quotient
|
||||||
result[--i] = alphabet[remainder]
|
result += alphabet[remainder]
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.copyOfRange(i, result.size)
|
return result.asReversed().toByteArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun decode(bytes: ByteArray): ByteArray {
|
override fun decode(bytes: ByteArray): ByteArray {
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package com.infendro.encoding
|
||||||
|
|
||||||
|
import com.infendro.encoding.exception.IllegalByteException
|
||||||
|
import com.infendro.encoding.util.align
|
||||||
|
import com.infendro.encoding.util.divCeil
|
||||||
|
import com.infendro.encoding.util.lcm
|
||||||
|
import com.infendro.encoding.util.log2
|
||||||
|
|
||||||
|
class PaddedStreamEncoding internal constructor(
|
||||||
|
override val alphabet: ByteArray,
|
||||||
|
private val padding: Byte,
|
||||||
|
) : Encoding {
|
||||||
|
override fun encode(bytes: ByteArray): ByteArray {
|
||||||
|
val bits = log2(base).toInt()
|
||||||
|
|
||||||
|
val block = lcm(bits, 8) / bits
|
||||||
|
val size = (bytes.size * 8).divCeil(bits).align(block)
|
||||||
|
val result = ByteArray(size)
|
||||||
|
|
||||||
|
var r = 0
|
||||||
|
var buffer = 0
|
||||||
|
var bufferBits = 0
|
||||||
|
for (i in bytes.indices) {
|
||||||
|
buffer = (buffer shl 8) + bytes[i]
|
||||||
|
bufferBits += 8
|
||||||
|
|
||||||
|
while (bufferBits >= bits) {
|
||||||
|
val offset = bufferBits - bits
|
||||||
|
val index = (buffer ushr offset)
|
||||||
|
buffer = buffer and ((base - 1) shl offset).inv()
|
||||||
|
bufferBits -= bits
|
||||||
|
|
||||||
|
result[r++] = alphabet[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bufferBits > 0) {
|
||||||
|
val index = buffer shl (bits - bufferBits)
|
||||||
|
result[r++] = alphabet[index]
|
||||||
|
}
|
||||||
|
while (r < result.size) {
|
||||||
|
result[r++] = padding
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun decode(bytes: ByteArray): ByteArray {
|
||||||
|
val bits = log2(base).toInt()
|
||||||
|
|
||||||
|
val end = bytes.indexOf(padding).takeIf { it != -1 } ?: bytes.size
|
||||||
|
val size = end * bits / 8
|
||||||
|
val result = ByteArray(size)
|
||||||
|
|
||||||
|
var r = 0
|
||||||
|
var buffer = 0
|
||||||
|
var bufferBits = 0
|
||||||
|
for (i in 0..<end) {
|
||||||
|
val byte = bytes[i]
|
||||||
|
|
||||||
|
val value = alphabet.indexOf(byte)
|
||||||
|
if (value == -1) throw IllegalByteException(byte)
|
||||||
|
|
||||||
|
buffer = (buffer shl bits) + value.toByte()
|
||||||
|
bufferBits += bits
|
||||||
|
|
||||||
|
if (bufferBits >= 8) {
|
||||||
|
val offset = bufferBits - 8
|
||||||
|
val character = (buffer ushr offset).toByte()
|
||||||
|
buffer = buffer and (0xFF shl offset).inv()
|
||||||
|
bufferBits -= 8
|
||||||
|
|
||||||
|
result[r++] = character
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,30 +1,17 @@
|
|||||||
package com.infendro.encoding
|
package com.infendro.encoding
|
||||||
|
|
||||||
import com.infendro.encoding.exception.IllegalByteException
|
import com.infendro.encoding.exception.IllegalByteException
|
||||||
import com.infendro.encoding.util.align
|
|
||||||
import com.infendro.encoding.util.divCeil
|
import com.infendro.encoding.util.divCeil
|
||||||
import com.infendro.encoding.util.lcm
|
|
||||||
import com.infendro.encoding.util.log2
|
import com.infendro.encoding.util.log2
|
||||||
|
|
||||||
class StreamEncoding internal constructor(
|
class StreamEncoding internal constructor(
|
||||||
override val alphabet: ByteArray,
|
override val alphabet: ByteArray,
|
||||||
private val padding: Byte? = null,
|
|
||||||
) : Encoding {
|
) : Encoding {
|
||||||
init {
|
|
||||||
require(base and (base - 1) == 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun encode(bytes: ByteArray): ByteArray {
|
override fun encode(bytes: ByteArray): ByteArray {
|
||||||
val bits = log2(base).toInt()
|
val bits = log2(base).toInt()
|
||||||
|
|
||||||
val size = (bytes.size * 8).divCeil(bits)
|
val size = (bytes.size * 8).divCeil(bits)
|
||||||
val encodedSize = when (padding) {
|
val result = ByteArray(size)
|
||||||
null -> size
|
|
||||||
else -> {
|
|
||||||
val block = lcm(bits, 8) / bits
|
|
||||||
size.align(block)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val result = ByteArray(encodedSize)
|
|
||||||
|
|
||||||
var r = 0
|
var r = 0
|
||||||
var buffer = 0
|
var buffer = 0
|
||||||
@@ -43,15 +30,8 @@ class StreamEncoding internal constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bufferBits > 0) {
|
if (bufferBits > 0) {
|
||||||
buffer = buffer shl (bits - bufferBits)
|
val index = buffer shl (bits - bufferBits)
|
||||||
val index = buffer
|
result[r] = alphabet[index]
|
||||||
result[r++] = alphabet[index]
|
|
||||||
}
|
|
||||||
|
|
||||||
if (padding != null) {
|
|
||||||
while (r < result.size) {
|
|
||||||
result[r++] = padding
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@@ -59,24 +39,20 @@ class StreamEncoding internal constructor(
|
|||||||
|
|
||||||
override fun decode(bytes: ByteArray): ByteArray {
|
override fun decode(bytes: ByteArray): ByteArray {
|
||||||
val bits = log2(base).toInt()
|
val bits = log2(base).toInt()
|
||||||
val index = padding?.let { bytes.indexOf(it) } ?: -1
|
|
||||||
val decodedSize = when (index) {
|
val size = bytes.size * bits / 8
|
||||||
-1 -> bytes.size * bits / 8
|
val result = ByteArray(size)
|
||||||
else -> index * bits / 8
|
|
||||||
}
|
|
||||||
val result = ByteArray(decodedSize)
|
|
||||||
|
|
||||||
var r = 0
|
var r = 0
|
||||||
var buffer = 0
|
var buffer = 0
|
||||||
var bufferBits = 0
|
var bufferBits = 0
|
||||||
for (i in bytes.indices) {
|
for (i in bytes.indices) {
|
||||||
val byte = bytes[i]
|
val byte = bytes[i]
|
||||||
if (byte == padding) break
|
|
||||||
|
|
||||||
val index = alphabet.indexOf(byte)
|
val value = alphabet.indexOf(byte)
|
||||||
if (index == -1) throw IllegalByteException(byte)
|
if (value == -1) throw IllegalByteException(byte)
|
||||||
|
|
||||||
buffer = (buffer shl bits) + index.toByte()
|
buffer = (buffer shl bits) + value.toByte()
|
||||||
bufferBits += bits
|
bufferBits += bits
|
||||||
|
|
||||||
if (bufferBits >= 8) {
|
if (bufferBits >= 8) {
|
||||||
|
|||||||
Reference in New Issue
Block a user