Skip to content

Instantly share code, notes, and snippets.

@omarmiatello
Last active March 27, 2017 21:23
Show Gist options
  • Save omarmiatello/b09d4ba995c8c0881b0921c0e7aa9bdc to your computer and use it in GitHub Desktop.
Save omarmiatello/b09d4ba995c8c0881b0921c0e7aa9bdc to your computer and use it in GitHub Desktop.
Bencode Encoder/Decoder in Kotlin (extended version) - https://en.wikipedia.org/wiki/Bencode
class B(val s:String, var i:Int=0) {
fun r(c:Int)=s.substring(i,i+c).apply{i+=length}
fun u(c:Char)=s.substring(i,s.indexOf(c,i)).apply{i+=length+1}
fun d():Any=when(r(1)[0]){
'e'->Unit;'i'->u('e').toInt()
'l'->ArrayList<Any>().apply{var o=d();while(o!=Unit){add(o);o=d()}}
'd'->HashMap<String,Any>().apply{var o=d();while(o!=Unit){put(o as String,d());o=d()}}
in('0'..'9')->r((s[i-1]+u(':')).toInt())
else->throw IllegalStateException("Char:${s[i-1]}")
}
}
fun Any.e():String=let{o->when(o){
is Int->"i${o}e";is String->"${o.length}:$o"
is List<*>->"l${o.joinToString(""){it!!.e()}}e"
is Map<*,*>->"d${o.map{it.key!!.e()+it.value!!.e()}.joinToString("")}e"
else->throw IllegalStateException()
}}
class Ben(val str: String, var i: Int = 0) {
fun read(count: Int) = str.substring(i, i + count).apply { i += length }
fun readUntil(c: Char) = str.substring(i, str.indexOf(c, i)).apply { i += length + 1 }
fun decode(): Any = when (read(1)[0]) {
'i' -> readUntil('e').toInt()
'l' -> ArrayList<Any>().apply {
var obj = decode()
while (obj != Unit) {
add(obj)
obj = decode()
}
}
'd' -> HashMap<String, Any>().apply {
var obj = decode()
while (obj != Unit) {
put(obj as String, decode())
obj = decode()
}
}
'e' -> Unit
in ('0'..'9') -> read((str[i-1] + readUntil(':')).toInt())
else -> throw IllegalStateException("Char: ${str[i-1]}")
}
companion object {
fun encodeStr(obj: Any): String = when (obj) {
is Int -> "i${obj}e"
is String -> "${obj.length}:$obj"
is List<*> -> "l${obj.joinToString("") { encodeStr(it!!) }}e"
is Map<*, *> -> "d${obj.map { encodeStr(it.key!!) + encodeStr(it.value!!) }.joinToString("")}e"
else -> throw IllegalStateException()
}
}
}
fun String.r(c:Int,i:Int)=substring(i,i+c).let{it to it.length+i}
fun String.u(c:Char,i:Int)=substring(i,indexOf(c,i)).let{it to it.length+i+1}
fun String.d(i:Int=0):Pair<Any,Int> =r(1,i).let{(r,i)->when(r[0]){
'e'->Unit to i;'i'->u('e',i).let{(r,i)->r.toInt() to i}
'l'->ArrayList<Any>().let{var(o,j)=d(i);while(o!=Unit){it.add(o);d(j).let{(o2,j2)->o=o2;j=j2}};it to j}
'd'->HashMap<String,Any>().let{var(k,j)=d(i);while(k!=Unit){d(j).let{(v,z)->it.put(k as String,v);d(z).let{(k1,v1)->k=k1;j=v1}}};it to j}
in('0'..'9')->u(':',i).let{(r,j)->(get(i-1)+r).toInt() to j}.let{(r,i)->r(r,i)}
else->throw IllegalStateException("Char:${get(i-1)}")
}}
fun Any.e():String=let{o->when(o){
is Int->"i${o}e";is String->"${o.length}:$o"
is List<*>->"l${o.joinToString(""){it!!.e()}}e"
is Map<*,*>->"d${o.map{(k,v)->k!!.e()+v!!.e()}.joinToString("")}e"
else->throw IllegalStateException()
}}
fun main(args: Array<String>) {
val n = listOf("i42e", "i0e", "i-42e")
val s = listOf("4:spam", "3:bar", "3:foo")
val l = "l${s[0]}${n[0]}e"
val m = "d${s[1]}${s[0]}${s[2]}${n[0]}e"
(n + s + l + m).forEach {
val ben = Ben(it)
val obj = ben.decode()
val ben2 = Ben.encodeStr(obj)
println("$it -> $obj")
if (ben.str.length != ben.i) throw IllegalStateException("Malformed")
if (it != ben2) throw IllegalStateException("Encoder fail: $it != $ben2")
}
}
fun main(args: Array<String>) {
val n = listOf("i42e", "i0e", "i-42e")
val s = listOf("4:spam", "3:bar", "3:foo")
val l = "l${s[0]}${n[0]}e"
val m = "d${s[1]}${s[0]}${s[2]}${n[0]}e"
(n + s + l + m).forEach {
val (obj,i) = it.d()
val ben2 = obj.e()
println("$it -> $obj")
if (it.length != i) throw IllegalStateException("Malformed")
if (it != ben2) throw IllegalStateException("Encoder fail: $it != $ben2")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment