Fix shadowed struct elements

This commit is contained in:
Him188 2020-03-19 14:52:59 +08:00
parent 4c6e427d12
commit 948658c9ec
3 changed files with 81 additions and 69 deletions

View File

@ -181,9 +181,9 @@ internal class JceDecoder(
companion object { companion object {
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
val debuggingMode: Boolean by lazy { false } var debuggingMode: Boolean = false
private var structureHierarchy: Int = 0 var structureHierarchy: Int = 0
inline fun println(value: () -> String) { inline fun println(value: () -> String) {
if (debuggingMode) { if (debuggingMode) {
@ -258,7 +258,10 @@ internal class JceDecoder(
override fun decodeSequentially(): Boolean = false override fun decodeSequentially(): Boolean = false
override fun decodeElementIndex(descriptor: SerialDescriptor): Int { override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
var jceHead = jce.currentHeadOrNull ?: return CompositeDecoder.READ_DONE var jceHead = jce.currentHeadOrNull ?: kotlin.run {
println("decodeElementIndex: currentHead == null")
return CompositeDecoder.READ_DONE
}
println { "decodeElementIndex: ${jce.currentHead}" } println { "decodeElementIndex: ${jce.currentHead}" }
while (!jce.input.endOfInput) { while (!jce.input.endOfInput) {

View File

@ -116,53 +116,58 @@ internal class JceInput(
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
@PublishedApi @PublishedApi
internal fun skipField(type: Byte): Unit = when (type) { internal fun skipField(type: Byte): Unit {
JceDecoder.println { "skipping ${JceHead.findJceTypeName(type)}" }
when (type) {
Jce.BYTE -> this.input.discardExact(1) Jce.BYTE -> this.input.discardExact(1)
Jce.SHORT -> this.input.discardExact(2) Jce.SHORT -> this.input.discardExact(2)
Jce.INT -> this.input.discardExact(4) Jce.INT -> println("readInt=" + this.input.readInt())
Jce.LONG -> this.input.discardExact(8) Jce.LONG -> this.input.discardExact(8)
Jce.FLOAT -> this.input.discardExact(4) Jce.FLOAT -> this.input.discardExact(4)
Jce.DOUBLE -> this.input.discardExact(8) Jce.DOUBLE -> this.input.discardExact(8)
Jce.STRING1 -> this.input.discardExact(this.input.readUByte().toInt()) Jce.STRING1 -> this.input.discardExact(this.input.readUByte().toInt())
Jce.STRING4 -> this.input.discardExact(this.input.readInt()) Jce.STRING4 -> this.input.discardExact(this.input.readInt())
Jce.MAP -> { // map Jce.MAP -> { // map
//println("skip map!") JceDecoder.structureHierarchy++
nextHead() var count: Int = 0
nextHead() // avoid shadowing, don't remove
repeat(skipToHeadAndUseIfPossibleOrFail(0, message = { "tag 0 not found when skipping map" }) { repeat(skipToHeadAndUseIfPossibleOrFail(0, message = { "tag 0 not found when skipping map" }) {
readJceIntValue(it) readJceIntValue(it).also { count = it * 2 }
} * 2) { } * 2) {
val currentHead = currentHead
prepareNextHead()
skipField(currentHead.type) skipField(currentHead.type)
if (it != count - 1) { // don't read last head
nextHead()
} }
} }
JceDecoder.structureHierarchy--
}
Jce.LIST -> { // list Jce.LIST -> { // list
JceDecoder.println {"skip list!"} JceDecoder.structureHierarchy++
nextHead() var count: Int = 0
repeat(skipToHeadAndUseIfPossibleOrFail(0, message = { "tag 0 not found when skipping list" }) { nextHead() // avoid shadowing, don't remove
readJceIntValue(it) repeat(skipToHeadAndUseIfPossibleOrFail(0, message = { "tag 0 not found when skipping list" }) { head ->
readJceIntValue(head).also { count = it }
}) { }) {
val currentHead = currentHead
prepareNextHead()
skipField(currentHead.type) skipField(currentHead.type)
if (it != count - 1) { // don't read last head
nextHead()
} }
} }
JceDecoder.structureHierarchy--
}
Jce.STRUCT_BEGIN -> { Jce.STRUCT_BEGIN -> {
JceDecoder.println {"skip struct!"} JceDecoder.structureHierarchy++
fun skipToStructEnd() {
var head: JceHead var head: JceHead
do { do {
head = nextHead() head = nextHead()
skipField(head.type) skipField(head.type)
} while (head.type != Jce.STRUCT_END) } while (head.type != Jce.STRUCT_END)
} JceDecoder.structureHierarchy--
skipToStructEnd()
} }
Jce.STRUCT_END, Jce.ZERO_TYPE -> { Jce.STRUCT_END, Jce.ZERO_TYPE -> {
Unit
} }
Jce.SIMPLE_LIST -> { Jce.SIMPLE_LIST -> {
JceDecoder.println { "skip simple list!" } JceDecoder.structureHierarchy++
var head = nextHead() var head = nextHead()
check(head.type == Jce.BYTE) { "bad simple list element type: " + head.type } 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}" } check(head.tag == 0) { "simple list element tag must be 0, but was ${head.tag}" }
@ -170,9 +175,11 @@ internal class JceInput(
head = nextHead() head = nextHead()
check(head.tag == 0) { "tag for size for simple list must be 0, but was ${head.tag}" } check(head.tag == 0) { "tag for size for simple list must be 0, but was ${head.tag}" }
this.input.discardExact(readJceIntValue(head)) this.input.discardExact(readJceIntValue(head))
JceDecoder.structureHierarchy--
} }
else -> error("invalid type: $type") else -> error("invalid type: $type")
} }
}
// region readers // region readers
fun readJceIntValue(head: JceHead): Int { fun readJceIntValue(head: JceHead): Int {

View File

@ -8,10 +8,7 @@ import kotlinx.io.core.writeFully
import kotlinx.serialization.MissingFieldException import kotlinx.serialization.MissingFieldException
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.qqandroid.io.JceStruct import net.mamoe.mirai.qqandroid.io.JceStruct
import net.mamoe.mirai.qqandroid.io.serialization.jce.Jce import net.mamoe.mirai.qqandroid.io.serialization.jce.*
import net.mamoe.mirai.qqandroid.io.serialization.jce.JceId
import net.mamoe.mirai.qqandroid.io.serialization.jce.JceInput
import net.mamoe.mirai.qqandroid.io.serialization.jce.writeJceHead
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFailsWith import kotlin.test.assertFailsWith
@ -42,6 +39,9 @@ internal const val ZERO_TYPE: Byte = 12
*/ */
@Suppress("INVISIBLE_MEMBER") // bug @Suppress("INVISIBLE_MEMBER") // bug
internal class JceInputTest { internal class JceInputTest {
init {
JceDecoder.debuggingMode = true
}
@Test @Test
fun testIntToStructMap() { fun testIntToStructMap() {
@ -109,8 +109,9 @@ internal class JceInputTest {
val input = buildPacket { val input = buildPacket {
writeJceHead(MAP, 0) // TestSerializableClassB writeJceHead(MAP, 0) // TestSerializableClassB
writeJceHead(BYTE, 0) writeJceHead(BYTE, 0)
writeByte(1) writeByte(1);
{
writeJceHead(STRUCT_BEGIN, 0); writeJceHead(STRUCT_BEGIN, 0);
{ {
writeJceHead(INT, 0) writeJceHead(INT, 0)
@ -134,6 +135,7 @@ internal class JceInputTest {
writeInt(123123) writeInt(123123)
}() }()
writeJceHead(STRUCT_END, 0) writeJceHead(STRUCT_END, 0)
}()
writeJceHead(STRING1, 1) writeJceHead(STRING1, 1)
writeByte(1) writeByte(1)