|
| 1 | +package space.iseki.bencoding |
| 2 | + |
| 3 | +import kotlinx.serialization.DeserializationStrategy |
| 4 | +import kotlinx.serialization.ExperimentalSerializationApi |
| 5 | +import kotlinx.serialization.descriptors.SerialDescriptor |
| 6 | +import kotlinx.serialization.encoding.CompositeDecoder |
| 7 | +import kotlinx.serialization.encoding.Decoder |
| 8 | +import kotlinx.serialization.modules.EmptySerializersModule |
| 9 | +import kotlinx.serialization.modules.SerializersModule |
| 10 | + |
| 11 | +internal class BencodingDecoderImpl(private val input: I) : DecoderHelper { |
| 12 | + override fun decodeBytes(): ByteArray { |
| 13 | + return input.readText() |
| 14 | + } |
| 15 | + |
| 16 | + override fun decodeNumber(): Long { |
| 17 | + return input.readNumber() |
| 18 | + } |
| 19 | + |
| 20 | + @OptIn(ExperimentalSerializationApi::class) |
| 21 | + override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder { |
| 22 | + return when (val s = input.lookahead()) { |
| 23 | + Symbol.Dict -> { |
| 24 | + input.skip() |
| 25 | + object : CompositeDecoderHelper, DecoderHelper by this { |
| 26 | + override fun decodeElementIndex(descriptor: SerialDescriptor): Int { |
| 27 | + do { |
| 28 | + when (val s = input.lookahead()) { |
| 29 | + Symbol.Text -> { |
| 30 | + val idx = descriptor.getElementIndex(decodeString()) |
| 31 | + if (idx == CompositeDecoder.UNKNOWN_NAME) { |
| 32 | + skipCurrentValue() |
| 33 | + } else { |
| 34 | + return idx |
| 35 | + } |
| 36 | + } |
| 37 | + |
| 38 | + Symbol.End -> return CompositeDecoder.DECODE_DONE |
| 39 | + else -> throw BencodingSerializationException("expect a string(dict key), get $s at ${input.pos}") |
| 40 | + } |
| 41 | + } while (true) |
| 42 | + } |
| 43 | + |
| 44 | + override fun endStructure(descriptor: SerialDescriptor) { |
| 45 | + skipCurrentStructure() |
| 46 | + } |
| 47 | + |
| 48 | + } |
| 49 | + } |
| 50 | + |
| 51 | + Symbol.List -> { |
| 52 | + input.skip() |
| 53 | + object : CompositeDecoderHelper, DecoderHelper by this { |
| 54 | + var i = 0 |
| 55 | + |
| 56 | + override fun decodeElementIndex(descriptor: SerialDescriptor): Int { |
| 57 | + return when (input.lookahead()) { |
| 58 | + Symbol.End -> CompositeDecoder.DECODE_DONE |
| 59 | + Symbol.EOF -> throw BencodingSerializationException("EOF when decode list") |
| 60 | + else -> i++ |
| 61 | + |
| 62 | + } |
| 63 | + } |
| 64 | + |
| 65 | + override fun endStructure(descriptor: SerialDescriptor) { |
| 66 | + skipCurrentStructure() |
| 67 | + } |
| 68 | + } |
| 69 | + } |
| 70 | + |
| 71 | + else -> throw BencodingSerializationException("expect a structured token, get $s at ${input.pos}") |
| 72 | + } |
| 73 | + } |
| 74 | + |
| 75 | + private fun skipCurrentValue() { |
| 76 | + var counter = 0 |
| 77 | + do { |
| 78 | + when (input.lookahead()) { |
| 79 | + Symbol.End -> counter-- |
| 80 | + Symbol.Dict, Symbol.List -> counter++ |
| 81 | + Symbol.EOF -> break |
| 82 | + else -> Unit |
| 83 | + } |
| 84 | + input.skip() |
| 85 | + } while (counter > 0) |
| 86 | + } |
| 87 | + |
| 88 | + private fun skipCurrentStructure() { |
| 89 | + var counter = 1 |
| 90 | + while (counter > 0) { |
| 91 | + when (input.lookahead()) { |
| 92 | + Symbol.End -> counter-- |
| 93 | + Symbol.Dict, Symbol.List -> counter++ |
| 94 | + Symbol.EOF -> break |
| 95 | + else -> Unit |
| 96 | + } |
| 97 | + input.skip() |
| 98 | + } |
| 99 | + } |
| 100 | +} |
| 101 | + |
| 102 | +interface BencodingDecoder { |
| 103 | + fun decodeBytes(): ByteArray |
| 104 | + fun decodeNumber(): Long |
| 105 | +} |
| 106 | + |
| 107 | +private interface DecoderHelper : Decoder, BencodingDecoder { |
| 108 | + override fun decodeBytes(): ByteArray |
| 109 | + override fun decodeNumber(): Long |
| 110 | + |
| 111 | + override val serializersModule: SerializersModule |
| 112 | + get() = EmptySerializersModule() |
| 113 | + |
| 114 | + override fun decodeString(): String = decodeBytes().decodeToString() |
| 115 | + override fun decodeBoolean(): Boolean = decodeString().toBooleanStrict() |
| 116 | + override fun decodeByte(): Byte = decodeNumber().toByte() |
| 117 | + override fun decodeChar(): Char = decodeNumber().toInt().toChar() |
| 118 | + override fun decodeDouble(): Double = decodeNumber().toDouble() |
| 119 | + override fun decodeFloat(): Float = decodeNumber().toFloat() |
| 120 | + override fun decodeInt(): Int = decodeNumber().toInt() |
| 121 | + override fun decodeLong(): Long = decodeNumber() |
| 122 | + override fun decodeShort(): Short = decodeNumber().toShort() |
| 123 | + override fun decodeInline(descriptor: SerialDescriptor): Decoder = this |
| 124 | + |
| 125 | + @ExperimentalSerializationApi |
| 126 | + override fun decodeNull(): Nothing? = throw UnsupportedOperationException("decode null is not supported") |
| 127 | + |
| 128 | + @ExperimentalSerializationApi |
| 129 | + override fun decodeNotNullMark(): Boolean = false |
| 130 | + |
| 131 | + @ExperimentalSerializationApi |
| 132 | + override fun <T : Any> decodeNullableSerializableValue(deserializer: DeserializationStrategy<T?>): T? = |
| 133 | + deserializer.deserialize(this) |
| 134 | + |
| 135 | + override fun <T> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T = |
| 136 | + deserializer.deserialize(this) |
| 137 | + |
| 138 | + override fun decodeEnum(enumDescriptor: SerialDescriptor): Int = |
| 139 | + throw UnsupportedOperationException("decode enum is not supported") |
| 140 | +} |
| 141 | + |
| 142 | +private interface CompositeDecoderHelper : CompositeDecoder, Decoder { |
| 143 | + override fun decodeBooleanElement(descriptor: SerialDescriptor, index: Int): Boolean = decodeBoolean() |
| 144 | + override fun decodeByteElement(descriptor: SerialDescriptor, index: Int): Byte = decodeByte() |
| 145 | + override fun decodeCharElement(descriptor: SerialDescriptor, index: Int): Char = decodeChar() |
| 146 | + override fun decodeDoubleElement(descriptor: SerialDescriptor, index: Int): Double = decodeDouble() |
| 147 | + override fun decodeFloatElement(descriptor: SerialDescriptor, index: Int): Float = decodeFloat() |
| 148 | + override fun decodeInlineElement(descriptor: SerialDescriptor, index: Int): Decoder = decodeInline(descriptor) |
| 149 | + override fun decodeIntElement(descriptor: SerialDescriptor, index: Int): Int = decodeInt() |
| 150 | + override fun decodeLongElement(descriptor: SerialDescriptor, index: Int): Long = decodeLong() |
| 151 | + override fun decodeShortElement(descriptor: SerialDescriptor, index: Int): Short = decodeShort() |
| 152 | + override fun decodeStringElement(descriptor: SerialDescriptor, index: Int): String = decodeString() |
| 153 | + |
| 154 | + @ExperimentalSerializationApi |
| 155 | + override fun <T : Any> decodeNullableSerializableElement( |
| 156 | + descriptor: SerialDescriptor, |
| 157 | + index: Int, |
| 158 | + deserializer: DeserializationStrategy<T?>, |
| 159 | + previousValue: T? |
| 160 | + ): T? = deserializer.deserialize(this) |
| 161 | + |
| 162 | + override fun <T> decodeSerializableElement( |
| 163 | + descriptor: SerialDescriptor, |
| 164 | + index: Int, |
| 165 | + deserializer: DeserializationStrategy<T>, |
| 166 | + previousValue: T? |
| 167 | + ): T = deserializer.deserialize(this) |
| 168 | +} |
| 169 | + |
| 170 | + |
0 commit comments