burp-blazor/src/main/kotlin/MsgPackSerializer.kt

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)
}
}
}
}
}
}
}