285 lines
12 KiB
Kotlin
285 lines
12 KiB
Kotlin
package burp
|
|
|
|
import com.ensarsarajcic.kotlinx.serialization.msgpack.exceptions.MsgPackSerializationException
|
|
import com.ensarsarajcic.kotlinx.serialization.msgpack.extensions.DynamicMsgPackExtensionSerializer
|
|
import com.ensarsarajcic.kotlinx.serialization.msgpack.internal.MsgPackTypeDecoder
|
|
import kotlinx.serialization.ExperimentalSerializationApi
|
|
import kotlinx.serialization.InternalSerializationApi
|
|
import kotlinx.serialization.KSerializer
|
|
import kotlinx.serialization.builtins.*
|
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
|
import kotlinx.serialization.descriptors.SerialKind
|
|
import kotlinx.serialization.descriptors.buildSerialDescriptor
|
|
import kotlinx.serialization.encoding.Decoder
|
|
import kotlinx.serialization.encoding.Encoder
|
|
import kotlinx.serialization.serializer
|
|
|
|
internal object MsgPackType {
|
|
internal object Boolean {
|
|
operator fun invoke(value: kotlin.Boolean) = if (value) TRUE else FALSE
|
|
const val TRUE = 0xc3.toByte()
|
|
const val FALSE = 0xc2.toByte()
|
|
}
|
|
|
|
internal interface Mask<T> {
|
|
operator fun invoke(value: T) = maskValue(value)
|
|
fun maskValue(value: T): T
|
|
fun test(value: T): kotlin.Boolean
|
|
fun unMaskValue(value: T): T = maskValue(value)
|
|
}
|
|
|
|
internal object Int {
|
|
const val INT8 = 0xd0.toByte()
|
|
const val INT16 = 0xd1.toByte()
|
|
const val INT32 = 0xd2.toByte()
|
|
const val INT64 = 0xd3.toByte()
|
|
const val UINT8 = 0xcc.toByte()
|
|
const val UINT16 = 0xcd.toByte()
|
|
const val UINT32 = 0xce.toByte()
|
|
const val UINT64 = 0xcf.toByte()
|
|
|
|
val POSITIVE_FIXNUM_MASK = object : Mask<Byte> {
|
|
private val mask = 0b01111111
|
|
override fun maskValue(value: Byte): Byte = (mask and value.toInt()).toByte()
|
|
override fun test(value: Byte): kotlin.Boolean = (mask or value.toInt()) == mask
|
|
}
|
|
val NEGATIVE_FIXNUM_MASK = object : Mask<Byte> {
|
|
private val mask = 0b11100000
|
|
override fun maskValue(value: Byte): Byte = (mask or value.toInt()).toByte()
|
|
override fun test(value: Byte): kotlin.Boolean = (mask and value.toInt()) == mask
|
|
override fun unMaskValue(value: Byte): Byte = (mask xor value.toInt()).toByte()
|
|
}
|
|
const val MIN_NEGATIVE_SINGLE_BYTE = -32
|
|
const val MIN_NEGATIVE_BYTE = -127
|
|
const val MAX_UBYTE = 255
|
|
const val MAX_USHORT = 65535
|
|
const val MAX_UINT = 4294967295
|
|
const val MAX_ULONG = -1 // Can't do it without unsigned types or BigInteger
|
|
|
|
fun isByte(byte: Byte) = byte == INT8 || byte == UINT8
|
|
fun isShort(byte: Byte) = byte == INT16 || byte == UINT16
|
|
fun isInt(byte: Byte) = byte == INT32 || byte == UINT32
|
|
fun isLong(byte: Byte) = byte == INT64 || byte == UINT64
|
|
}
|
|
|
|
internal object Float {
|
|
const val FLOAT = 0xca.toByte()
|
|
const val DOUBLE = 0xcb.toByte()
|
|
}
|
|
|
|
internal object String {
|
|
fun isString(value: Byte): kotlin.Boolean {
|
|
return FIXSTR_SIZE_MASK.test(value) || value == STR8 || value == STR16 || value == STR32
|
|
}
|
|
|
|
private const val STR8 = 0xd9.toByte()
|
|
private const val STR16 = 0xda.toByte()
|
|
private const val STR32 = 0xdb.toByte()
|
|
|
|
private val FIXSTR_SIZE_MASK = object : Mask<Byte> {
|
|
private val maskResult = 0b10100000
|
|
private val mask = 0b11100000
|
|
override fun maskValue(value: Byte): Byte = (maskResult or value.toInt()).toByte()
|
|
override fun test(value: Byte): kotlin.Boolean = (mask and value.toInt()) == maskResult
|
|
override fun unMaskValue(value: Byte): Byte = (maskResult xor value.toInt()).toByte()
|
|
}
|
|
const val MAX_FIXSTR_LENGTH = 31
|
|
const val MAX_STR8_LENGTH = Int.MAX_UBYTE
|
|
const val MAX_STR16_LENGTH = Int.MAX_USHORT
|
|
const val MAX_STR32_LENGTH = Int.MAX_UINT
|
|
}
|
|
|
|
internal object Bin {
|
|
fun isBinary(value: Byte): kotlin.Boolean {
|
|
return value == BIN8 || value == BIN16 || value == BIN32
|
|
}
|
|
|
|
private const val BIN8 = 0xc4.toByte()
|
|
private const val BIN16 = 0xc5.toByte()
|
|
private const val BIN32 = 0xc6.toByte()
|
|
|
|
const val MAX_BIN8_LENGTH = Int.MAX_UBYTE
|
|
const val MAX_BIN16_LENGTH = Int.MAX_USHORT
|
|
const val MAX_BIN32_LENGTH = Int.MAX_UINT
|
|
}
|
|
|
|
internal object Array {
|
|
fun isArray(value: Byte): kotlin.Boolean {
|
|
return FIXARRAY_SIZE_MASK.test(value) || value == ARRAY16 || value == ARRAY32
|
|
}
|
|
|
|
private const val ARRAY16 = 0xdc.toByte()
|
|
private const val ARRAY32 = 0xdd.toByte()
|
|
|
|
private val FIXARRAY_SIZE_MASK = object : Mask<Byte> {
|
|
private val maskResult = 0b10010000
|
|
private val mask = 0b11110000
|
|
override fun maskValue(value: Byte): Byte = (maskResult or value.toInt()).toByte()
|
|
override fun test(value: Byte): kotlin.Boolean = (mask and value.toInt()) == maskResult
|
|
override fun unMaskValue(value: Byte): Byte = (maskResult xor value.toInt()).toByte()
|
|
}
|
|
const val MAX_FIXARRAY_SIZE = 15
|
|
const val MAX_ARRAY16_LENGTH = Int.MAX_USHORT
|
|
const val MAX_ARRAY32_LENGTH = Int.MAX_UINT
|
|
}
|
|
|
|
internal object Map {
|
|
fun isMap(value: Byte): kotlin.Boolean {
|
|
return FIXMAP_SIZE_MASK.test(value) || value == MAP16 || value == MAP32
|
|
}
|
|
|
|
private const val MAP16 = 0xde.toByte()
|
|
private const val MAP32 = 0xdf.toByte()
|
|
|
|
private val FIXMAP_SIZE_MASK = object : Mask<Byte> {
|
|
private val maskResult = 0b10000000
|
|
private val mask = 0b11110000
|
|
override fun maskValue(value: Byte): Byte = (maskResult or value.toInt()).toByte()
|
|
override fun test(value: Byte): kotlin.Boolean = (mask and value.toInt()) == maskResult
|
|
override fun unMaskValue(value: Byte): Byte = (maskResult xor value.toInt()).toByte()
|
|
}
|
|
const val MAX_FIXMAP_SIZE = 15
|
|
const val MAX_MAP16_LENGTH = Int.MAX_USHORT
|
|
const val MAX_MAP32_LENGTH = Int.MAX_UINT
|
|
}
|
|
|
|
internal object Ext {
|
|
fun isExt(value: Byte): kotlin.Boolean {
|
|
return TYPES.contains(value)
|
|
}
|
|
|
|
private const val FIXEXT1 = 0xd4.toByte()
|
|
private const val FIXEXT2 = 0xd5.toByte()
|
|
private const val FIXEXT4 = 0xd6.toByte()
|
|
private const val FIXEXT8 = 0xd7.toByte()
|
|
private const val FIXEXT16 = 0xd8.toByte()
|
|
private const val EXT8 = 0xc7.toByte()
|
|
private const val EXT16 = 0xc8.toByte()
|
|
private const val EXT32 = 0xc9.toByte()
|
|
|
|
private val SIZES = hashMapOf(
|
|
FIXEXT1 to 1, FIXEXT2 to 2, FIXEXT4 to 4, FIXEXT8 to 8, FIXEXT16 to 16
|
|
)
|
|
|
|
val SIZE_SIZE = hashMapOf(
|
|
EXT8 to 1, EXT16 to 2, EXT32 to 4
|
|
)
|
|
|
|
private val TYPES = SIZES.keys + listOf(EXT8, EXT16, EXT32)
|
|
|
|
const val MAX_EXT8_LENGTH = Int.MAX_UBYTE
|
|
const val MAX_EXT16_LENGTH = Int.MAX_USHORT
|
|
const val MAX_EXT32_LENGTH = Int.MAX_UINT
|
|
}
|
|
|
|
const val NULL = 0xc0.toByte()
|
|
}
|
|
|
|
open class MsgPackSerializer(
|
|
private val nullableSerializer: MsgPackNullableSerializer = MsgPackNullableSerializer
|
|
) : KSerializer<Any> {
|
|
companion object Default : MsgPackSerializer(MsgPackNullableSerializer)
|
|
|
|
final override fun deserialize(decoder: Decoder): Any {
|
|
return nullableSerializer.deserialize(decoder)!!
|
|
}
|
|
|
|
@OptIn(InternalSerializationApi::class, ExperimentalSerializationApi::class)
|
|
final override val descriptor: SerialDescriptor = buildSerialDescriptor("MsgPackDynamic", SerialKind.CONTEXTUAL)
|
|
|
|
final override fun serialize(encoder: Encoder, value: Any) {
|
|
nullableSerializer.serialize(encoder, value)
|
|
}
|
|
}
|
|
|
|
open class MsgPackNullableSerializer(
|
|
private val dynamicMsgPackExtensionSerializer: DynamicMsgPackExtensionSerializer = DynamicMsgPackExtensionSerializer
|
|
) : KSerializer<Any?> {
|
|
companion object Default : MsgPackNullableSerializer(DynamicMsgPackExtensionSerializer)
|
|
|
|
@OptIn(ExperimentalSerializationApi::class)
|
|
final override fun deserialize(decoder: Decoder): Any? {
|
|
if (decoder !is MsgPackTypeDecoder) throw MsgPackSerializationException.dynamicSerializationError("Unsupported decoder: $decoder")
|
|
val type = decoder.peekNextType()
|
|
return when {
|
|
type == MsgPackType.NULL -> decoder.decodeNull()
|
|
type == MsgPackType.Boolean.FALSE || type == MsgPackType.Boolean.TRUE -> decoder.decodeBoolean()
|
|
MsgPackType.Int.POSITIVE_FIXNUM_MASK.test(type) || MsgPackType.Int.NEGATIVE_FIXNUM_MASK.test(type) || type == MsgPackType.Int.INT8 -> decoder.decodeByte()
|
|
|
|
type == MsgPackType.Int.INT16 || type == MsgPackType.Int.UINT8 -> {
|
|
val result = decoder.decodeShort()
|
|
if (type == MsgPackType.Int.UINT8 && result <= Byte.MAX_VALUE && result >= Byte.MIN_VALUE) {
|
|
result.toByte()
|
|
} else {
|
|
result
|
|
}
|
|
}
|
|
|
|
type == MsgPackType.Int.INT32 || type == MsgPackType.Int.UINT16 -> {
|
|
val result = decoder.decodeInt()
|
|
if (type == MsgPackType.Int.UINT16 && result <= Short.MAX_VALUE && result >= Short.MIN_VALUE) {
|
|
result.toShort()
|
|
} else {
|
|
result
|
|
}
|
|
}
|
|
|
|
type == MsgPackType.Int.INT64 || type == MsgPackType.Int.UINT32 || type == MsgPackType.Int.UINT64 -> {
|
|
val result = decoder.decodeLong()
|
|
if (type == MsgPackType.Int.UINT32 && result <= Int.MAX_VALUE && result >= Int.MIN_VALUE) {
|
|
result.toInt()
|
|
} else {
|
|
result
|
|
}
|
|
}
|
|
|
|
type == MsgPackType.Float.FLOAT -> decoder.decodeFloat()
|
|
type == MsgPackType.Float.DOUBLE -> decoder.decodeDouble()
|
|
MsgPackType.String.isString(type) -> decoder.decodeString()
|
|
MsgPackType.Bin.isBinary(type) -> decoder.decodeSerializableValue(ByteArraySerializer())
|
|
MsgPackType.Array.isArray(type) -> ListSerializer(this).deserialize(decoder)
|
|
MsgPackType.Map.isMap(type) -> MapSerializer(this, this).deserialize(decoder)
|
|
MsgPackType.Ext.isExt(type) -> dynamicMsgPackExtensionSerializer.deserialize(decoder)
|
|
else -> throw MsgPackSerializationException.dynamicSerializationError("Missing decoder for type: $type")
|
|
}
|
|
}
|
|
|
|
@OptIn(InternalSerializationApi::class, ExperimentalSerializationApi::class)
|
|
final override val descriptor: SerialDescriptor =
|
|
buildSerialDescriptor("MsgPackNullableDynamic", SerialKind.CONTEXTUAL)
|
|
|
|
@OptIn(InternalSerializationApi::class, ExperimentalSerializationApi::class)
|
|
final override fun serialize(encoder: Encoder, value: Any?) {
|
|
if (value == null) {
|
|
encoder.encodeNull()
|
|
return
|
|
}
|
|
when (value::class) {
|
|
Boolean::class -> encoder.encodeBoolean(value as Boolean)
|
|
Byte::class -> encoder.encodeByte(value as Byte)
|
|
Short::class -> encoder.encodeShort(value as Short)
|
|
Int::class -> encoder.encodeInt(value as Int)
|
|
Long::class -> encoder.encodeLong(value as Long)
|
|
Float::class -> encoder.encodeFloat(value as Float)
|
|
Double::class -> encoder.encodeDouble(value as Double)
|
|
String::class -> encoder.encodeString(value as String)
|
|
ByteArray::class -> encoder.encodeSerializableValue(ByteArraySerializer(), value as ByteArray)
|
|
else -> {
|
|
when (value) {
|
|
is Map<*, *> -> MapSerializer(this, this).serialize(encoder, value as Map<Any?, Any?>)
|
|
is Array<*> -> ArraySerializer(this).serialize(encoder, value.map { it }.toTypedArray())
|
|
is List<*> -> ListSerializer(this).serialize(encoder, value.map { it })
|
|
is Map.Entry<*, *> -> MapEntrySerializer(this, this).serialize(encoder, value)
|
|
else -> {
|
|
if (dynamicMsgPackExtensionSerializer.canSerialize(value)) {
|
|
dynamicMsgPackExtensionSerializer.serialize(encoder, value)
|
|
} else {
|
|
encoder.encodeSerializableValue(value::class.serializer() as KSerializer<Any>, value)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|