Commit 2260d331 authored by Him188's avatar Him188

Support ByteArray

parent 91df7298
...@@ -35,6 +35,7 @@ internal class JceDecoder( ...@@ -35,6 +35,7 @@ internal class JceDecoder(
this.getElementDescriptor(index).isNullable this.getElementDescriptor(index).isNullable
) )
} }
fun SerialDescriptor.getJceTagId(index: Int): Int { fun SerialDescriptor.getJceTagId(index: Int): Int {
return getElementAnnotations(index).filterIsInstance<JceId>().single().id return getElementAnnotations(index).filterIsInstance<JceId>().single().id
} }
...@@ -43,26 +44,32 @@ internal class JceDecoder( ...@@ -43,26 +44,32 @@ internal class JceDecoder(
private val ByteArraySerializer = ByteArraySerializer() private val ByteArraySerializer = ByteArraySerializer()
// TODO: 2020/3/6 can be object // 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 decodeSequentially(): Boolean = true
override fun decodeByteElement(descriptor: SerialDescriptor, index: Int): Byte { 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 { override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
return 0 error("should not be reached")
} }
override fun decodeCollectionSize(descriptor: SerialDescriptor): Int { 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 // TODO: 2020/3/6 can be object
private inner class ListReader() : CompositeDecoder by this { private inner class ListReader : CompositeDecoder by this {
override fun decodeSequentially(): Boolean = false override fun decodeSequentially(): Boolean = true
override fun decodeElementIndex(descriptor: SerialDescriptor): Int { 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 { override fun decodeCollectionSize(descriptor: SerialDescriptor): Int {
...@@ -70,12 +77,24 @@ internal class JceDecoder( ...@@ -70,12 +77,24 @@ internal class JceDecoder(
} }
} }
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 { override fun beginStructure(descriptor: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeDecoder {
println("beginStructure: ${descriptor.serialName}")
if (descriptor == ByteArraySerializer.descriptor) { if (descriptor == ByteArraySerializer.descriptor) {
println("!! ByteArray")
println("decoderTag: $currentTagOrNull")
println("jceHead: " + jce.currentHeadOrNull)
return jce.skipToHeadAndUseIfPossibleOrFail(popTag().id) { return jce.skipToHeadAndUseIfPossibleOrFail(popTag().id) {
println("listHead: $it")
when (it.type) { when (it.type) {
Jce.SIMPLE_LIST -> SimpleByteArrayReader() Jce.SIMPLE_LIST -> SimpleByteArrayReader().also { jce.prepareNextHead() } // 无用的元素类型
Jce.LIST -> ListReader() Jce.LIST -> error(""); //ListReader()
else -> error("type mismatch. Expected SIMPLE_LIST or LIST, got ${it.type} instead") else -> error("type mismatch. Expected SIMPLE_LIST or LIST, got ${it.type} instead")
} }
} }
...@@ -86,22 +105,22 @@ internal class JceDecoder( ...@@ -86,22 +105,22 @@ internal class JceDecoder(
} }
StructureKind.LIST -> ListReader() StructureKind.LIST -> ListReader()
else -> this else -> this@JceDecoder
} }
} }
override fun <T> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T { override fun <T> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T {
println("decodeSerializableValue: ${deserializer.descriptor}") println(
"decodeSerializableValue: ${deserializer.descriptor.toString().substringBefore('(')
.substringAfterLast('.')}"
)
return super.decodeSerializableValue(deserializer) return super.decodeSerializableValue(deserializer)
} }
private var currentIndex = 0
override fun decodeSequentially(): Boolean = false override fun decodeSequentially(): Boolean = false
override fun decodeElementIndex(descriptor: SerialDescriptor): Int { override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
val jceHead = jce.currentHeadOrNull ?: return CompositeDecoder.READ_DONE val jceHead = jce.currentHeadOrNull ?: return CompositeDecoder.READ_DONE
repeat(descriptor.elementsCount){ repeat(descriptor.elementsCount) {
val tag = descriptor.getJceTagId(it) val tag = descriptor.getJceTagId(it)
if (tag == jceHead.tag) { if (tag == jceHead.tag) {
return it return it
...@@ -116,10 +135,6 @@ internal class JceDecoder( ...@@ -116,10 +135,6 @@ internal class JceDecoder(
return super.decodeTaggedNull(tag) return super.decodeTaggedNull(tag)
} }
override fun <T : Any> decodeNullableSerializableValue(deserializer: DeserializationStrategy<T?>): T? {
return super.decodeNullableSerializableValue(deserializer)
}
override fun decodeTaggedValue(tag: JceTag): Any { override fun decodeTaggedValue(tag: JceTag): Any {
println("decodeTaggedValue") println("decodeTaggedValue")
return super.decodeTaggedValue(tag) return super.decodeTaggedValue(tag)
...@@ -149,14 +164,6 @@ internal class JceDecoder( ...@@ -149,14 +164,6 @@ internal class JceDecoder(
override fun decodeTaggedString(tag: JceTag): String = override fun decodeTaggedString(tag: JceTag): String =
jce.skipToHeadAndUseIfPossibleOrFail(tag.id) { jce.readJceStringValue(it) } 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 { override fun decodeTaggedNotNullMark(tag: JceTag): Boolean {
return jce.skipToHeadOrNull(tag.id) != null return jce.skipToHeadOrNull(tag.id) != null
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
package net.mamoe.mirai.qqandroid.io.serialization package net.mamoe.mirai.qqandroid.io.serialization
import io.ktor.utils.io.core.* import io.ktor.utils.io.core.*
import kotlinx.serialization.MissingFieldException
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.qqandroid.io.serialization.jce.JceId 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.JceInput
...@@ -38,20 +39,73 @@ internal const val ZERO_TYPE: Byte = 12 ...@@ -38,20 +39,73 @@ internal const val ZERO_TYPE: Byte = 12
*/ */
@Suppress("INVISIBLE_MEMBER") // bug @Suppress("INVISIBLE_MEMBER") // bug
internal class JceInputTest { internal class JceInputTest {
@Serializable
data class TestSerializableClassA( @Test
@JceId(0) val byte: Byte = 66, fun testSimpleByteArray() {
@JceId(1) val short: Short = 123, @Serializable
@JceId(3) val int: Int = 123456, data class TestSerializableClassA(
@JceId(8) val float: Float = 123f, @JceId(0) val byteArray: ByteArray = byteArrayOf(1, 2, 3),
@JceId(15) val long: Long = 123456789123456789L, @JceId(3) val byteArray2: ByteArray = byteArrayOf(1, 2, 3, 4)
@JceId(16) val double: Double = 123456.0, ) {
@JceId(17) val boolean: Boolean = true, override fun equals(other: Any?): Boolean {
@JceId(11111) val nullable: Int? = null 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 @Test
fun testSerializableClassA() { 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 { val input = buildPacket {
writeJceHead(BYTE, 0) writeJceHead(BYTE, 0)
writeByte(66) writeByte(66)
...@@ -72,6 +126,25 @@ internal class JceInputTest { ...@@ -72,6 +126,25 @@ internal class JceInputTest {
assertEquals(TestSerializableClassA(), JceNew.UTF_8.load(TestSerializableClassA.serializer(), input)) 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 @Test
fun testHeadSkip() { fun testHeadSkip() {
val input = JceInput(buildPacket { val input = JceInput(buildPacket {
......
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