mirror of
https://github.com/mamoe/mirai.git
synced 2026-09-03 13:13:00 +08:00
Support ByteArray
This commit is contained in:
@@ -35,6 +35,7 @@ internal class JceDecoder(
|
||||
this.getElementDescriptor(index).isNullable
|
||||
)
|
||||
}
|
||||
|
||||
fun SerialDescriptor.getJceTagId(index: Int): Int {
|
||||
return getElementAnnotations(index).filterIsInstance<JceId>().single().id
|
||||
}
|
||||
@@ -43,26 +44,32 @@ internal class JceDecoder(
|
||||
private val ByteArraySerializer = ByteArraySerializer()
|
||||
|
||||
// TODO: 2020/3/6 can be object
|
||||
private inner class SimpleByteArrayReader() : CompositeDecoder by this {
|
||||
private inner class SimpleByteArrayReader : CompositeDecoder by this {
|
||||
override fun decodeSequentially(): Boolean = true
|
||||
override fun decodeByteElement(descriptor: SerialDescriptor, index: Int): Byte {
|
||||
return jce.input.readByte()
|
||||
println("decodeByteElement: $index")
|
||||
return jce.input.readByte().also { println("read: $it") }
|
||||
}
|
||||
|
||||
override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
|
||||
return 0
|
||||
error("should not be reached")
|
||||
}
|
||||
|
||||
override fun decodeCollectionSize(descriptor: SerialDescriptor): Int {
|
||||
return jce.useHead { jce.readJceIntValue(it) }
|
||||
// 不要读下一个 head
|
||||
return jce.currentHead.let { jce.readJceIntValue(it) }.also { println("simpleListSize=$it") }
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 2020/3/6 can be object
|
||||
private inner class ListReader() : CompositeDecoder by this {
|
||||
override fun decodeSequentially(): Boolean = false
|
||||
private inner class ListReader : CompositeDecoder by this {
|
||||
override fun decodeSequentially(): Boolean = true
|
||||
override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
|
||||
return 0
|
||||
error("should not be reached")
|
||||
}
|
||||
|
||||
override fun endStructure(descriptor: SerialDescriptor) {
|
||||
println("endStructure: ${descriptor.serialName}")
|
||||
}
|
||||
|
||||
override fun decodeCollectionSize(descriptor: SerialDescriptor): Int {
|
||||
@@ -70,12 +77,24 @@ internal class JceDecoder(
|
||||
}
|
||||
}
|
||||
|
||||
override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
|
||||
override fun endStructure(descriptor: SerialDescriptor) {
|
||||
if (descriptor == ByteArraySerializer.descriptor) {
|
||||
jce.prepareNextHead() // list 里面没读 head
|
||||
}
|
||||
super.endStructure(descriptor)
|
||||
}
|
||||
|
||||
override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
|
||||
println("beginStructure: ${descriptor.serialName}")
|
||||
if (descriptor == ByteArraySerializer.descriptor) {
|
||||
println("!! ByteArray")
|
||||
println("decoderTag: $currentTagOrNull")
|
||||
println("jceHead: " + jce.currentHeadOrNull)
|
||||
return jce.skipToHeadAndUseIfPossibleOrFail(popTag().id) {
|
||||
println("listHead: $it")
|
||||
when (it.type) {
|
||||
Jce.SIMPLE_LIST -> SimpleByteArrayReader()
|
||||
Jce.LIST -> ListReader()
|
||||
Jce.SIMPLE_LIST -> SimpleByteArrayReader().also { jce.prepareNextHead() } // 无用的元素类型
|
||||
Jce.LIST -> error(""); //ListReader()
|
||||
else -> error("type mismatch. Expected SIMPLE_LIST or LIST, got ${it.type} instead")
|
||||
}
|
||||
}
|
||||
@@ -86,22 +105,22 @@ internal class JceDecoder(
|
||||
}
|
||||
StructureKind.LIST -> ListReader()
|
||||
|
||||
else -> this
|
||||
else -> this@JceDecoder
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T {
|
||||
println("decodeSerializableValue: ${deserializer.descriptor}")
|
||||
println(
|
||||
"decodeSerializableValue: ${deserializer.descriptor.toString().substringBefore('(')
|
||||
.substringAfterLast('.')}"
|
||||
)
|
||||
return super.decodeSerializableValue(deserializer)
|
||||
}
|
||||
|
||||
private var currentIndex = 0
|
||||
|
||||
|
||||
override fun decodeSequentially(): Boolean = false
|
||||
override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
|
||||
val jceHead = jce.currentHeadOrNull ?: return CompositeDecoder.READ_DONE
|
||||
repeat(descriptor.elementsCount){
|
||||
repeat(descriptor.elementsCount) {
|
||||
val tag = descriptor.getJceTagId(it)
|
||||
if (tag == jceHead.tag) {
|
||||
return it
|
||||
@@ -116,10 +135,6 @@ internal class JceDecoder(
|
||||
return super.decodeTaggedNull(tag)
|
||||
}
|
||||
|
||||
override fun <T : Any> decodeNullableSerializableValue(deserializer: DeserializationStrategy<T?>): T? {
|
||||
return super.decodeNullableSerializableValue(deserializer)
|
||||
}
|
||||
|
||||
override fun decodeTaggedValue(tag: JceTag): Any {
|
||||
println("decodeTaggedValue")
|
||||
return super.decodeTaggedValue(tag)
|
||||
@@ -149,14 +164,6 @@ internal class JceDecoder(
|
||||
override fun decodeTaggedString(tag: JceTag): String =
|
||||
jce.skipToHeadAndUseIfPossibleOrFail(tag.id) { jce.readJceStringValue(it) }
|
||||
|
||||
override fun decodeTaggedEnum(tag: JceTag, enumDescription: SerialDescriptor): Int {
|
||||
return super.decodeTaggedEnum(tag, enumDescription)
|
||||
}
|
||||
|
||||
override fun decodeTaggedChar(tag: JceTag): Char {
|
||||
return super.decodeTaggedChar(tag)
|
||||
}
|
||||
|
||||
override fun decodeTaggedNotNullMark(tag: JceTag): Boolean {
|
||||
return jce.skipToHeadOrNull(tag.id) != null
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package net.mamoe.mirai.qqandroid.io.serialization
|
||||
|
||||
import io.ktor.utils.io.core.*
|
||||
import kotlinx.serialization.MissingFieldException
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.qqandroid.io.serialization.jce.JceId
|
||||
import net.mamoe.mirai.qqandroid.io.serialization.jce.JceInput
|
||||
@@ -38,20 +39,73 @@ internal const val ZERO_TYPE: Byte = 12
|
||||
*/
|
||||
@Suppress("INVISIBLE_MEMBER") // bug
|
||||
internal class JceInputTest {
|
||||
@Serializable
|
||||
data class TestSerializableClassA(
|
||||
@JceId(0) val byte: Byte = 66,
|
||||
@JceId(1) val short: Short = 123,
|
||||
@JceId(3) val int: Int = 123456,
|
||||
@JceId(8) val float: Float = 123f,
|
||||
@JceId(15) val long: Long = 123456789123456789L,
|
||||
@JceId(16) val double: Double = 123456.0,
|
||||
@JceId(17) val boolean: Boolean = true,
|
||||
@JceId(11111) val nullable: Int? = null
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testSimpleByteArray() {
|
||||
@Serializable
|
||||
data class TestSerializableClassA(
|
||||
@JceId(0) val byteArray: ByteArray = byteArrayOf(1, 2, 3),
|
||||
@JceId(3) val byteArray2: ByteArray = byteArrayOf(1, 2, 3, 4)
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || this::class != other::class) return false
|
||||
|
||||
other as TestSerializableClassA
|
||||
|
||||
if (!byteArray.contentEquals(other.byteArray)) return false
|
||||
if (!byteArray2.contentEquals(other.byteArray2)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = byteArray.contentHashCode()
|
||||
result = 31 * result + byteArray2.contentHashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
val input = buildPacket {
|
||||
writeJceHead(SIMPLE_LIST, 0)
|
||||
writeJceHead(BYTE, 0)
|
||||
|
||||
writeJceHead(BYTE, 0)
|
||||
byteArrayOf(1, 2, 3).let {
|
||||
writeByte(it.size.toByte())
|
||||
writeFully(it)
|
||||
}
|
||||
|
||||
writeJceHead(SIMPLE_LIST, 3)
|
||||
writeJceHead(BYTE, 0)
|
||||
|
||||
writeJceHead(BYTE, 0)
|
||||
byteArrayOf(1, 2, 3, 4).let {
|
||||
writeByte(it.size.toByte())
|
||||
writeFully(it)
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(TestSerializableClassA(), JceNew.UTF_8.load(TestSerializableClassA.serializer(), input))
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testSerializableClassA() {
|
||||
@Serializable
|
||||
data class TestSerializableClassA(
|
||||
@JceId(0) val byte: Byte = 66,
|
||||
@JceId(1) val short: Short = 123,
|
||||
@JceId(3) val int: Int = 123456,
|
||||
@JceId(8) val float: Float = 123f,
|
||||
@JceId(15) val long: Long = 123456789123456789L,
|
||||
@JceId(16) val double: Double = 123456.0,
|
||||
@JceId(17) val boolean: Boolean = true,
|
||||
@JceId(11111) val nullable: Int? = null,
|
||||
@JceId(111112) val nullable2: Int? = null,
|
||||
@JceId(111113) val optional: Int = 123
|
||||
)
|
||||
|
||||
val input = buildPacket {
|
||||
writeJceHead(BYTE, 0)
|
||||
writeByte(66)
|
||||
@@ -72,6 +126,25 @@ internal class JceInputTest {
|
||||
assertEquals(TestSerializableClassA(), JceNew.UTF_8.load(TestSerializableClassA.serializer(), input))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNoSuchField() {
|
||||
@Serializable
|
||||
data class TestSerializableClassA(
|
||||
@JceId(0) val byte: Byte = 66,
|
||||
@JceId(1) val short: Short = 123,
|
||||
@JceId(3) val int: Int
|
||||
)
|
||||
|
||||
val input = buildPacket {
|
||||
writeJceHead(BYTE, 0)
|
||||
writeByte(66)
|
||||
writeJceHead(SHORT, 1)
|
||||
writeShort(123)
|
||||
}
|
||||
|
||||
assertFailsWith<MissingFieldException> { JceNew.UTF_8.load(TestSerializableClassA.serializer(), input) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHeadSkip() {
|
||||
val input = JceInput(buildPacket {
|
||||
|
||||
Reference in New Issue
Block a user