blob: 3bcf15a105552f923a1031fb37245268891952de (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
package net.taler.wallet.kotlin
class EncodingException : Exception("Invalid encoding")
object Base32Crockford {
private fun ByteArray.getIntAt(index: Int): Int {
val x = this[index].toInt()
return if (x >= 0) x else (x + 256)
}
private var encTable = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
fun encode(data: ByteArray): String {
val sb = StringBuilder()
val size = data.size
var bitBuf = 0
var numBits = 0
var pos = 0
while (pos < size || numBits > 0) {
if (pos < size && numBits < 5) {
val d = data.getIntAt(pos++)
bitBuf = (bitBuf shl 8) or d
numBits += 8
}
if (numBits < 5) {
// zero-padding
bitBuf = bitBuf shl (5 - numBits)
numBits = 5
}
val v = bitBuf.ushr(numBits - 5) and 31
sb.append(encTable[v])
numBits -= 5
}
return sb.toString()
}
fun decode(encoded: String): ByteArray {
val size = encoded.length
var bitpos = 0
var bitbuf = 0
var readPosition = 0
var writePosition = 0
val out = ByteArray(calculateDecodedDataLength(size))
while (readPosition < size || bitpos > 0) {
//println("at position $readPosition with bitpos $bitpos")
if (readPosition < size) {
val v = getValue(encoded[readPosition++])
bitbuf = (bitbuf shl 5) or v
bitpos += 5
}
while (bitpos >= 8) {
val d = (bitbuf ushr (bitpos - 8)) and 0xFF
out[writePosition] = d.toByte()
writePosition++
bitpos -= 8
}
if (readPosition == size && bitpos > 0) {
bitbuf = (bitbuf shl (8 - bitpos)) and 0xFF
bitpos = if (bitbuf == 0) 0 else 8
}
}
return out
}
private fun getValue(chr: Char): Int {
var a = chr
when (a) {
'O', 'o' -> a = '0'
'i', 'I', 'l', 'L' -> a = '1'
'u', 'U' -> a = 'V'
}
if (a in '0'..'9')
return a - '0'
if (a in 'a'..'z')
a = a.toUpperCase()
var dec = 0
if (a in 'A'..'Z') {
if ('I' < a) dec++
if ('L' < a) dec++
if ('O' < a) dec++
if ('U' < a) dec++
return a - 'A' + 10 - dec
}
throw EncodingException()
}
/**
* Compute the length of the resulting string when encoding data of the given size
* in bytes.
*
* @param dataSize size of the data to encode in bytes
* @return size of the string that would result from encoding
*/
private fun calculateEncodedStringLength(dataSize: Int): Int {
return (dataSize * 8 + 4) / 5
}
/**
* Compute the length of the resulting data in bytes when decoding a (valid) string of the
* given size.
*
* @param stringSize size of the string to decode
* @return size of the resulting data in bytes
*/
fun calculateDecodedDataLength(stringSize: Int): Int {
return stringSize * 5 / 8
}
}
|