Fix deserializing

This commit is contained in:
Him188 2020-03-19 14:05:32 +08:00
parent f48e27d743
commit 320bb1b76f
4 changed files with 107 additions and 27 deletions

View File

@ -35,8 +35,8 @@ internal class JceDecoder(
}
private fun SerialDescriptor.getJceTagId(index: Int): Int {
//println("getTag: ${getElementName(index)}")
return getElementAnnotations(index).filterIsInstance<JceId>().singleOrNull()?.id
// higher performance, don't use filterIsInstance
return (getElementAnnotations(index).first { it is JceId } as? JceId)?.id
?: error("missing @JceId for ${getElementName(index)} in ${this.serialName}")
}
@ -119,11 +119,15 @@ internal class JceDecoder(
this@JceDecoder.endStructure(descriptor)
}
private var state: Boolean = true
override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
this@JceDecoder.pushTag(if (jce.currentHead.tag == 0) JceTagMapEntryKey else JceTagMapEntryValue)
state = !state
println { "MapReader.beginStructure: ${jce.currentHead}" }
this@JceDecoder.pushTag(
when (jce.currentHead.tag) {
0 -> JceTagMapEntryKey
1 -> JceTagMapEntryValue
else -> error("illegal map entry head: ${jce.currentHead.tag}")
}
)
return this@JceDecoder.beginStructure(descriptor, *typeParams)
}
@ -140,7 +144,7 @@ internal class JceDecoder(
override fun decodeString(): String = jce.useHead { jce.readJceStringValue(it) }
override fun decodeCollectionSize(descriptor: SerialDescriptor): Int {
//println("decodeCollectionSize in MapReader: ${descriptor.serialName}")
println { "decodeCollectionSize in MapReader: ${descriptor.serialName}" }
// 不读下一个 head
return jce.useHead { jce.readJceIntValue(it) }
}
@ -148,7 +152,8 @@ internal class JceDecoder(
override fun endStructure(descriptor: SerialDescriptor) {
//println("endStructure: $descriptor")
structureHierarchy--
println { "endStructure: ${descriptor.serialName}" }
if (currentTagOrNull?.isSimpleByteArray == true) {
jce.prepareNextHead() // read to next head
}
@ -173,9 +178,31 @@ internal class JceDecoder(
}
}
companion object {
@Suppress("MemberVisibilityCanBePrivate")
val debuggingMode: Boolean by lazy { false }
private var structureHierarchy: Int = 0
inline fun println(value: () -> String) {
if (debuggingMode) {
kotlin.io.println(" ".repeat(structureHierarchy) + value())
}
}
@Suppress("NOTHING_TO_INLINE")
inline fun println(value: Any? = "") {
if (debuggingMode) {
kotlin.io.println(" ".repeat(structureHierarchy) + value)
}
}
}
override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
//println()
//println("beginStructure: ${descriptor.serialName}")
println()
println { "beginStructure: ${descriptor.serialName}" }
structureHierarchy++
return when (descriptor.kind) {
is PrimitiveKind -> this@JceDecoder
@ -198,7 +225,7 @@ internal class JceDecoder(
when (it.type) {
Jce.SIMPLE_LIST -> {
currentTag.isSimpleByteArray = true
jce.prepareNextHead() // 无用的元素类型
jce.nextHead() // 无用的元素类型
SimpleByteArrayReader
}
Jce.LIST -> ListReader
@ -232,23 +259,29 @@ internal class JceDecoder(
override fun decodeSequentially(): Boolean = false
override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
var jceHead = jce.currentHeadOrNull ?: return CompositeDecoder.READ_DONE
if (jceHead.type == Jce.STRUCT_END) {
return CompositeDecoder.READ_DONE
}
while (!jce.input.endOfInput){
println { "decodeElementIndex: ${jce.currentHead}" }
while (!jce.input.endOfInput) {
if (jceHead.type == Jce.STRUCT_END) {
println { "decodeElementIndex: ${jce.currentHead}" }
return CompositeDecoder.READ_DONE
}
repeat(descriptor.elementsCount) {
val tag = descriptor.getJceTagId(it)
if (tag == jceHead.tag) {
println { "name=" + descriptor.getElementName(it) }
return it
}
}
jce.skipField(jceHead.type)
if (!jce.prepareNextHead()) {
println { "decodeElementIndex EOF" }
break
}
jceHead = jce.currentHead
println { "next! $jceHead" }
}
return CompositeDecoder.READ_DONE // optional support

View File

@ -126,6 +126,7 @@ internal class JceInput(
Jce.STRING1 -> this.input.discardExact(this.input.readUByte().toInt())
Jce.STRING4 -> this.input.discardExact(this.input.readInt())
Jce.MAP -> { // map
//println("skip map!")
nextHead()
repeat(skipToHeadAndUseIfPossibleOrFail(0, message = { "tag 0 not found when skipping map" }) {
readJceIntValue(it)
@ -136,6 +137,7 @@ internal class JceInput(
}
}
Jce.LIST -> { // list
JceDecoder.println {"skip list!"}
nextHead()
repeat(skipToHeadAndUseIfPossibleOrFail(0, message = { "tag 0 not found when skipping list" }) {
readJceIntValue(it)
@ -146,26 +148,28 @@ internal class JceInput(
}
}
Jce.STRUCT_BEGIN -> {
JceDecoder.println {"skip struct!"}
fun skipToStructEnd() {
var head: JceHead
do {
head = nextHead()
skipField(head.type)
} while (head.type.toInt() != 11)
} while (head.type != Jce.STRUCT_END)
}
skipToStructEnd()
}
Jce.STRUCT_END, Jce.ZERO_TYPE -> {
Unit
}
Jce.SIMPLE_LIST -> {
val head = nextHead()
check(head.type.toInt() == 0) { "skipField with invalid type, type value: " + type + ", " + head.type }
this.input.discardExact(
skipToHeadAndUseIfPossibleOrFail(0) {
readJceIntValue(it)
}
)
JceDecoder.println { "skip simple list!" }
var head = nextHead()
check(head.type == Jce.BYTE) { "bad simple list element type: " + head.type }
check(head.tag == 0) { "simple list element tag must be 0, but was ${head.tag}" }
head = nextHead()
check(head.tag == 0) { "tag for size for simple list must be 0, but was ${head.tag}" }
this.input.discardExact(readJceIntValue(head))
}
else -> error("invalid type: $type")
}

View File

@ -114,7 +114,7 @@ internal class FriendInfo(
@JceId(16) val vecIMGroupID: ByteArray? = null,
@JceId(17) val vecMSFGroupID: ByteArray? = null,
@JceId(18) val iTermType: Int? = null,
@JceId(19) val oVipInfo: VipBaseInfo? = null,
@JceId(19) val oVipInfo: VipBaseInfo? = null, //? bad
@JceId(20) val network: Byte? = null,
@JceId(21) val vecRing: ByteArray? = null,
@JceId(22) val uAbiFlag: Long? = null,
@ -156,12 +156,12 @@ internal class FriendInfo(
@Serializable
internal class VipBaseInfo(
@JceId(0) val mOpenInfo: Map<Int, VipOpenInfo>
@JceId(0) val mOpenInfo: Map<Int, VipOpenInfo>? = null // 原本是 0
) : JceStruct
@Serializable
internal class VipOpenInfo(
@JceId(0) val open: Boolean,
@JceId(0) val open: Boolean? = false,
@JceId(1) val iVipType: Int = -1,
@JceId(2) val iVipLevel: Int = -1,
@JceId(3) val iVipFlag: Int? = null,

View File

@ -7,6 +7,7 @@ import kotlinx.io.core.toByteArray
import kotlinx.io.core.writeFully
import kotlinx.serialization.MissingFieldException
import kotlinx.serialization.Serializable
import net.mamoe.mirai.qqandroid.io.JceStruct
import net.mamoe.mirai.qqandroid.io.serialization.jce.Jce
import net.mamoe.mirai.qqandroid.io.serialization.jce.JceId
import net.mamoe.mirai.qqandroid.io.serialization.jce.JceInput
@ -42,6 +43,48 @@ internal const val ZERO_TYPE: Byte = 12
@Suppress("INVISIBLE_MEMBER") // bug
internal class JceInputTest {
@Test
fun testIntToStructMap() {
@Serializable
data class VipOpenInfo(
@JceId(0) val open: Boolean? = false,
@JceId(1) val iVipType: Int = -1,
@JceId(2) val iVipLevel: Int = -1,
@JceId(3) val iVipFlag: Int? = null,
@JceId(4) val nameplateId: Long? = null
) : JceStruct
@Serializable
data class VipBaseInfo(
@JceId(0) val mOpenInfo: Map<Int, VipOpenInfo>? = null
) : JceStruct
@Serializable
data class FriendInfo(
@JceId(0) val friendUin: Long,
@JceId(14) val nick: String = "",
@JceId(19) val oVipInfo: VipBaseInfo? = null, //? bad
@JceId(20) val network: Byte? = null
) : JceStruct
val value = FriendInfo(
friendUin = 123,
nick = "h",
oVipInfo = VipBaseInfo(
mapOf(
1 to VipOpenInfo(true, -1),
999999999 to VipOpenInfo(true, -1)
)
),
network = 1
)
assertEquals(
value.toString(),
Jce.UTF_8.load(FriendInfo.serializer(), value.toByteArray(FriendInfo.serializer())).toString()
)
}
@Test
fun testSkippingMap() {
@Serializable