Commit 24983d8b authored by Him188's avatar Him188

Throws EOFException rather than IllegalStateException

parent 115ccec9
...@@ -45,28 +45,28 @@ private class JceDecoder( ...@@ -45,28 +45,28 @@ private class JceDecoder(
} }
override fun decodeTaggedInt(tag: JceTag): Int = override fun decodeTaggedInt(tag: JceTag): Int =
jce.skipToTagAndUseIfPossibleOrFail(tag.id) { jce.readJceIntValue(it) } jce.skipToHeadAndUseIfPossibleOrFail(tag.id) { jce.readJceIntValue(it) }
override fun decodeTaggedByte(tag: JceTag): Byte = override fun decodeTaggedByte(tag: JceTag): Byte =
jce.skipToTagAndUseIfPossibleOrFail(tag.id) { jce.readJceByteValue(it) } jce.skipToHeadAndUseIfPossibleOrFail(tag.id) { jce.readJceByteValue(it) }
override fun decodeTaggedBoolean(tag: JceTag): Boolean = override fun decodeTaggedBoolean(tag: JceTag): Boolean =
jce.skipToTagAndUseIfPossibleOrFail(tag.id) { jce.readJceBooleanValue(it) } jce.skipToHeadAndUseIfPossibleOrFail(tag.id) { jce.readJceBooleanValue(it) }
override fun decodeTaggedFloat(tag: JceTag): Float = override fun decodeTaggedFloat(tag: JceTag): Float =
jce.skipToTagAndUseIfPossibleOrFail(tag.id) { jce.readJceFloatValue(it) } jce.skipToHeadAndUseIfPossibleOrFail(tag.id) { jce.readJceFloatValue(it) }
override fun decodeTaggedDouble(tag: JceTag): Double = override fun decodeTaggedDouble(tag: JceTag): Double =
jce.skipToTagAndUseIfPossibleOrFail(tag.id) { jce.readJceDoubleValue(it) } jce.skipToHeadAndUseIfPossibleOrFail(tag.id) { jce.readJceDoubleValue(it) }
override fun decodeTaggedShort(tag: JceTag): Short = override fun decodeTaggedShort(tag: JceTag): Short =
jce.skipToTagAndUseIfPossibleOrFail(tag.id) { jce.readJceShortValue(it) } jce.skipToHeadAndUseIfPossibleOrFail(tag.id) { jce.readJceShortValue(it) }
override fun decodeTaggedLong(tag: JceTag): Long = override fun decodeTaggedLong(tag: JceTag): Long =
jce.skipToTagAndUseIfPossibleOrFail(tag.id) { jce.readJceLongValue(it) } jce.skipToHeadAndUseIfPossibleOrFail(tag.id) { jce.readJceLongValue(it) }
override fun decodeTaggedString(tag: JceTag): String = override fun decodeTaggedString(tag: JceTag): String =
jce.skipToTagAndUseIfPossibleOrFail(tag.id) { jce.readJceStringValue(it) } jce.skipToHeadAndUseIfPossibleOrFail(tag.id) { jce.readJceStringValue(it) }
override fun decodeTaggedEnum(tag: JceTag, enumDescription: SerialDescriptor): Int { override fun decodeTaggedEnum(tag: JceTag, enumDescription: SerialDescriptor): Int {
return super.decodeTaggedEnum(tag, enumDescription) return super.decodeTaggedEnum(tag, enumDescription)
......
...@@ -23,7 +23,7 @@ class JceInput( ...@@ -23,7 +23,7 @@ class JceInput(
) { ) {
private var _head: JceHead? = null private var _head: JceHead? = null
val currentHead: JceHead get() = _head ?: error("No current JceHead available") val currentHead: JceHead get() = _head ?: throw EOFException("No current JceHead available")
val currentHeadOrNull: JceHead? get() = _head val currentHeadOrNull: JceHead? get() = _head
init { init {
...@@ -40,7 +40,9 @@ class JceInput( ...@@ -40,7 +40,9 @@ class JceInput(
} }
fun nextHead(): JceHead { fun nextHead(): JceHead {
check(prepareNextHead()) { "No more JceHead available" } if (!prepareNextHead()) {
throw EOFException("No more JceHead available")
}
return currentHead return currentHead
} }
...@@ -51,13 +53,13 @@ class JceInput( ...@@ -51,13 +53,13 @@ class JceInput(
@Suppress("FunctionName") @Suppress("FunctionName")
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
private fun readNextHeadButDoNotAssignTo_Head(): JceHead? { private fun readNextHeadButDoNotAssignTo_Head(): JceHead? {
if (input.endOfInput) {
return null
}
val var2 = input.readUByte() val var2 = input.readUByte()
val type = var2 and 15u val type = var2 and 15u
var tag = var2.toUInt() shr 4 var tag = var2.toUInt() shr 4
if (tag == 15u) { if (tag == 15u) {
if (input.endOfInput) {
return null
}
tag = input.readUByte().toUInt() tag = input.readUByte().toUInt()
} }
return JceHead( return JceHead(
...@@ -77,19 +79,19 @@ class JceInput( ...@@ -77,19 +79,19 @@ class JceInput(
/** /**
* 跳过 [JceHead] 和对应的数据值, 直到找到 [tag], 否则返回 `null` * 跳过 [JceHead] 和对应的数据值, 直到找到 [tag], 否则返回 `null`
*/ */
inline fun <R> skipToTagAndUseIfPossibleOrNull(tag: Int, crossinline block: (JceHead) -> R): R? { inline fun <R> skipToHeadAndUseIfPossibleOrNull(tag: Int, crossinline block: (JceHead) -> R): R? {
return skipToHeadOrNull(tag)?.let(block).also { prepareNextHead() } return skipToHeadOrNull(tag)?.let(block).also { prepareNextHead() }
} }
/** /**
* 跳过 [JceHead] 和对应的数据值, 直到找到 [tag], 否则抛出异常 * 跳过 [JceHead] 和对应的数据值, 直到找到 [tag], 否则抛出异常
*/ */
inline fun <R : Any> skipToTagAndUseIfPossibleOrFail( inline fun <R : Any> skipToHeadAndUseIfPossibleOrFail(
tag: Int, tag: Int,
crossinline message: () -> String = { "tag not found: $tag" }, crossinline message: () -> String = { "tag not found: $tag" },
crossinline block: (JceHead) -> R crossinline block: (JceHead) -> R
): R { ): R {
return checkNotNull<R>(skipToTagAndUseIfPossibleOrNull(tag, block), message) return checkNotNull<R>(skipToHeadAndUseIfPossibleOrNull(tag, block), message)
} }
tailrec fun skipToHeadOrNull(tag: Int): JceHead? { tailrec fun skipToHeadOrNull(tag: Int): JceHead? {
...@@ -125,14 +127,14 @@ class JceInput( ...@@ -125,14 +127,14 @@ class JceInput(
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
repeat(skipToTagAndUseIfPossibleOrFail(0) { repeat(skipToHeadAndUseIfPossibleOrFail(0) {
readJceIntValue(it) readJceIntValue(it)
} * 2) { } * 2) {
useHead { skipField(it.type) } useHead { skipField(it.type) }
} }
} }
Jce.LIST -> { // list Jce.LIST -> { // list
repeat(skipToTagAndUseIfPossibleOrFail(0) { repeat(skipToHeadAndUseIfPossibleOrFail(0) {
readJceIntValue(it) readJceIntValue(it)
}) { }) {
useHead { skipField(it.type) } useHead { skipField(it.type) }
...@@ -155,7 +157,7 @@ class JceInput( ...@@ -155,7 +157,7 @@ class JceInput(
val head = nextHead() val head = nextHead()
check(head.type.toInt() == 0) { "skipField with invalid type, type value: " + type + ", " + head.type } check(head.type.toInt() == 0) { "skipField with invalid type, type value: " + type + ", " + head.type }
this.input.discardExact( this.input.discardExact(
skipToTagAndUseIfPossibleOrFail(0) { skipToHeadAndUseIfPossibleOrFail(0) {
readJceIntValue(it) readJceIntValue(it)
} }
) )
...@@ -232,6 +234,6 @@ class JceInput( ...@@ -232,6 +234,6 @@ class JceInput(
} }
fun readJceBooleanValue(head: JceHead): Boolean { fun readJceBooleanValue(head: JceHead): Boolean {
return readJceByteValue(head) == 0.toByte() return readJceByteValue(head) == 1.toByte()
} }
} }
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
package net.mamoe.mirai.qqandroid.io.serialization.jce package net.mamoe.mirai.qqandroid.io.serialization.jce
import io.ktor.utils.io.core.Output
import kotlinx.serialization.SerialInfo import kotlinx.serialization.SerialInfo
import net.mamoe.mirai.qqandroid.io.serialization.Jce import net.mamoe.mirai.qqandroid.io.serialization.Jce
...@@ -24,12 +25,27 @@ annotation class JceId(val id: Int) ...@@ -24,12 +25,27 @@ annotation class JceId(val id: Int)
* *
* 保留这个结构, 为将来增加功能的兼容性. * 保留这个结构, 为将来增加功能的兼容性.
*/ */
@PublishedApi
internal data class JceTag( internal data class JceTag(
val id: Int, val id: Int,
val isNullable: Boolean val isNullable: Boolean
) )
@PublishedApi
internal fun Output.writeJceHead(type: Byte, tag: Int) {
if (tag < 15) {
writeByte(((tag shl 4) or type.toInt()).toByte())
return
}
if (tag < 256) {
writeByte((type.toInt() or 0xF0).toByte())
writeByte(tag.toByte())
return
}
error("tag is too large: $tag")
}
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
inline class JceHead(private val value: Long) { inline class JceHead(private val value: Long) {
constructor(tag: Int, type: Byte) : this(tag.toLong().shl(32) or type.toLong()) constructor(tag: Int, type: Byte) : this(tag.toLong().shl(32) or type.toLong())
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment