mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-09 09:50:16 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
92f7ca4dbd
@ -12,8 +12,7 @@ import kotlinx.serialization.modules.EmptyModule
|
|||||||
import kotlinx.serialization.modules.SerialModule
|
import kotlinx.serialization.modules.SerialModule
|
||||||
import net.mamoe.mirai.qqandroid.io.CharsetUTF8
|
import net.mamoe.mirai.qqandroid.io.CharsetUTF8
|
||||||
import net.mamoe.mirai.qqandroid.io.JceEncodeException
|
import net.mamoe.mirai.qqandroid.io.JceEncodeException
|
||||||
import net.mamoe.mirai.qqandroid.io.JceOutput
|
import net.mamoe.mirai.qqandroid.io.JceStruct
|
||||||
import net.mamoe.mirai.utils.io.toUHexString
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
fun <T> ByteArray.loadAs(deserializer: DeserializationStrategy<T>, c: Charset): T {
|
fun <T> ByteArray.loadAs(deserializer: DeserializationStrategy<T>, c: Charset): T {
|
||||||
@ -68,17 +67,16 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
|
|||||||
defaultStringCharset: JceCharset,
|
defaultStringCharset: JceCharset,
|
||||||
private val count: Int,
|
private val count: Int,
|
||||||
private val tag: JceDesc,
|
private val tag: JceDesc,
|
||||||
private val parentEncoder: JceEncoder,
|
private val parentEncoder: JceEncoder
|
||||||
private val stream: ByteArrayOutputStream = ByteArrayOutputStream()
|
) : JceEncoder(defaultStringCharset, ByteArrayOutputStream()) {
|
||||||
) : JceEncoder(defaultStringCharset, stream) {
|
|
||||||
override fun SerialDescriptor.getTag(index: Int): JceDesc {
|
override fun SerialDescriptor.getTag(index: Int): JceDesc {
|
||||||
return JceDesc(0, getCharset(index))
|
return JceDesc(0, getCharset(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun endEncode(desc: SerialDescriptor) {
|
override fun endEncode(desc: SerialDescriptor) {
|
||||||
parentEncoder.writeHead(JceOutput.LIST, this.tag.id)
|
parentEncoder.writeHead(LIST, this.tag.id)
|
||||||
parentEncoder.encodeTaggedInt(JceDesc.STUB_FOR_PRIMITIVE_NUMBERS_GBK, count)
|
parentEncoder.encodeTaggedInt(JceDesc.STUB_FOR_PRIMITIVE_NUMBERS_GBK, count)
|
||||||
parentEncoder.output.write(stream.toByteArray())
|
parentEncoder.output.write(this.output.toByteArray())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,28 +87,35 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
|
|||||||
private val stream: ByteArrayOutputStream = ByteArrayOutputStream()
|
private val stream: ByteArrayOutputStream = ByteArrayOutputStream()
|
||||||
) : JceEncoder(defaultStringCharset, stream) {
|
) : JceEncoder(defaultStringCharset, stream) {
|
||||||
override fun endEncode(desc: SerialDescriptor) {
|
override fun endEncode(desc: SerialDescriptor) {
|
||||||
parentEncoder.writeHead(JceOutput.STRUCT_BEGIN, this.tag.id)
|
parentEncoder.writeHead(STRUCT_BEGIN, this.tag.id)
|
||||||
parentEncoder.output.write(stream.toByteArray())
|
parentEncoder.output.write(stream.toByteArray())
|
||||||
parentEncoder.writeHead(JceOutput.STRUCT_END, 0)
|
parentEncoder.writeHead(STRUCT_END, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class JceMapWriter(
|
private inner class JceMapWriter(
|
||||||
defaultStringCharset: JceCharset,
|
defaultStringCharset: JceCharset,
|
||||||
private val count: Int,
|
output: ByteArrayOutputStream
|
||||||
private val tag: JceDesc,
|
) : JceEncoder(defaultStringCharset, output) {
|
||||||
private val parentEncoder: JceEncoder
|
|
||||||
) : JceEncoder(defaultStringCharset, ByteArrayOutputStream()) {
|
|
||||||
override fun SerialDescriptor.getTag(index: Int): JceDesc {
|
override fun SerialDescriptor.getTag(index: Int): JceDesc {
|
||||||
return if (index % 2 == 0) JceDesc(0, getCharset(index))
|
return if (index % 2 == 0) JceDesc(0, getCharset(index))
|
||||||
else JceDesc(1, getCharset(index))
|
else JceDesc(1, getCharset(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
override fun endEncode(desc: SerialDescriptor) {
|
override fun endEncode(desc: SerialDescriptor) {
|
||||||
parentEncoder.writeHead(JceOutput.MAP, this.tag.id)
|
parentEncoder.writeHead(MAP, this.tag.id)
|
||||||
parentEncoder.encodeTaggedInt(JceDesc.STUB_FOR_PRIMITIVE_NUMBERS_GBK, count)
|
parentEncoder.encodeTaggedInt(JceDesc.STUB_FOR_PRIMITIVE_NUMBERS_GBK, count)
|
||||||
println(this.output.toByteArray().toUHexString())
|
println(this.output.toByteArray().toUHexString())
|
||||||
parentEncoder.output.write(this.output.toByteArray())
|
parentEncoder.output.write(this.output.toByteArray())
|
||||||
|
}*/
|
||||||
|
|
||||||
|
override fun beginCollection(desc: SerialDescriptor, collectionSize: Int, vararg typeParams: KSerializer<*>): CompositeEncoder {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeEncoder {
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,31 +147,27 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
|
|||||||
override fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeEncoder = when (desc.kind) {
|
override fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): CompositeEncoder = when (desc.kind) {
|
||||||
StructureKind.LIST -> this
|
StructureKind.LIST -> this
|
||||||
StructureKind.MAP -> this
|
StructureKind.MAP -> this
|
||||||
StructureKind.CLASS, UnionKind.OBJECT -> {
|
StructureKind.CLASS, UnionKind.OBJECT -> this
|
||||||
val currentTag = currentTagOrNull
|
is PolymorphicKind -> this
|
||||||
if (currentTag == null) {
|
|
||||||
this
|
|
||||||
} else {
|
|
||||||
JceStructWriter(defaultStringCharset, currentTag, this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is PolymorphicKind -> error("unsupported: PolymorphicKind")
|
|
||||||
else -> throw SerializationException("Primitives are not supported at top-level")
|
else -> throw SerializationException("Primitives are not supported at top-level")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST", "NAME_SHADOWING")
|
@Suppress("UNCHECKED_CAST", "NAME_SHADOWING")
|
||||||
override fun <T> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T) = when (serializer.descriptor) {
|
override fun <T> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T) = when (serializer.descriptor) {
|
||||||
// encode maps as collection of map entries, not merged collection of key-values
|
|
||||||
is MapLikeDescriptor -> {
|
is MapLikeDescriptor -> {
|
||||||
|
println("hello")
|
||||||
val entries = (value as Map<*, *>).entries
|
val entries = (value as Map<*, *>).entries
|
||||||
val serializer = (serializer as MapLikeSerializer<Any?, Any?, T, *>)
|
val serializer = (serializer as MapLikeSerializer<Any?, Any?, T, *>)
|
||||||
val mapEntrySerial = MapEntrySerializer(serializer.keySerializer, serializer.valueSerializer)
|
val mapEntrySerial = MapEntrySerializer(serializer.keySerializer, serializer.valueSerializer)
|
||||||
HashSetSerializer(mapEntrySerial).serialize(JceMapWriter(charset, entries.size, popTag(), this), entries)
|
|
||||||
|
this.writeHead(MAP, currentTag.id)
|
||||||
|
this.encodeTaggedInt(JceDesc.STUB_FOR_PRIMITIVE_NUMBERS_GBK, entries.count())
|
||||||
|
HashSetSerializer(mapEntrySerial).serialize(JceMapWriter(charset, this.output), entries)
|
||||||
}
|
}
|
||||||
ByteArraySerializer.descriptor -> encodeTaggedByteArray(popTag(), value as ByteArray)
|
ByteArraySerializer.descriptor -> encodeTaggedByteArray(popTag(), value as ByteArray)
|
||||||
is PrimitiveArrayDescriptor -> {
|
is PrimitiveArrayDescriptor -> {
|
||||||
if (value is ByteArray) {
|
if (value is ByteArray) {
|
||||||
this.encodeTaggedByteArray(currentTag, value)
|
this.encodeTaggedByteArray( popTag(), value)
|
||||||
} else{
|
} else{
|
||||||
serializer.serialize(
|
serializer.serialize(
|
||||||
ListWriter(charset, when(value){
|
ListWriter(charset, when(value){
|
||||||
@ -177,24 +178,34 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
|
|||||||
is DoubleArray -> value.size
|
is DoubleArray -> value.size
|
||||||
is CharArray -> value.size
|
is CharArray -> value.size
|
||||||
else -> error("unknown array type: ${value.getClassName()}")
|
else -> error("unknown array type: ${value.getClassName()}")
|
||||||
}, currentTag, this),
|
}, popTag(), this),
|
||||||
value
|
value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is ArrayClassDesc-> {
|
is ArrayClassDesc-> {
|
||||||
serializer.serialize(
|
serializer.serialize(
|
||||||
ListWriter(charset, (value as Array<*>).size, currentTag, this),
|
ListWriter(charset, (value as Array<*>).size, popTag(), this),
|
||||||
value
|
value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is ListLikeDescriptor -> {
|
is ListLikeDescriptor -> {
|
||||||
serializer.serialize(
|
serializer.serialize(
|
||||||
ListWriter(charset, (value as Collection<*>).size, currentTag, this),
|
ListWriter(charset, (value as Collection<*>).size, popTag(), this),
|
||||||
value
|
value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> serializer.serialize(this, value)
|
else -> {
|
||||||
|
if (value is JceStruct) {
|
||||||
|
if (currentTagOrNull == null) {
|
||||||
|
serializer.serialize(this, value)
|
||||||
|
} else {
|
||||||
|
this.writeHead(STRUCT_BEGIN, currentTag.id)
|
||||||
|
serializer.serialize(this, value)
|
||||||
|
this.writeHead(STRUCT_END, 0)
|
||||||
|
}
|
||||||
|
} else serializer.serialize(this, value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun encodeTaggedByte(tag: JceDesc, value: Byte) {
|
override fun encodeTaggedByte(tag: JceDesc, value: Byte) {
|
||||||
@ -263,8 +274,8 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun encodeTaggedByteArray(tag: JceDesc, bytes: ByteArray) {
|
fun encodeTaggedByteArray(tag: JceDesc, bytes: ByteArray) {
|
||||||
writeHead(JceOutput.SIMPLE_LIST, tag.id)
|
writeHead(SIMPLE_LIST, tag.id)
|
||||||
writeHead(JceOutput.BYTE, 0)
|
writeHead(BYTE, 0)
|
||||||
encodeTaggedInt(JceDesc.STUB_FOR_PRIMITIVE_NUMBERS_GBK, bytes.size)
|
encodeTaggedInt(JceDesc.STUB_FOR_PRIMITIVE_NUMBERS_GBK, bytes.size)
|
||||||
output.write(bytes)
|
output.write(bytes)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,9 @@ package net.mamoe.mirai.qqandroid.io.serialization
|
|||||||
import kotlinx.io.core.readBytes
|
import kotlinx.io.core.readBytes
|
||||||
import kotlinx.serialization.SerialId
|
import kotlinx.serialization.SerialId
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import net.mamoe.mirai.qqandroid.io.CharsetUTF8
|
||||||
|
import net.mamoe.mirai.qqandroid.io.JceOutput
|
||||||
|
import net.mamoe.mirai.qqandroid.io.JceStruct
|
||||||
import net.mamoe.mirai.qqandroid.io.buildJcePacket
|
import net.mamoe.mirai.qqandroid.io.buildJcePacket
|
||||||
import net.mamoe.mirai.utils.io.toUHexString
|
import net.mamoe.mirai.utils.io.toUHexString
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
@ -20,7 +23,17 @@ class JceEncoderTest {
|
|||||||
@SerialId(4) val long: Long = 123,
|
@SerialId(4) val long: Long = 123,
|
||||||
@SerialId(5) val float: Float = 123f,
|
@SerialId(5) val float: Float = 123f,
|
||||||
@SerialId(6) val double: Double = 123.0
|
@SerialId(6) val double: Double = 123.0
|
||||||
)
|
) : JceStruct() {
|
||||||
|
override fun writeTo(builder: JceOutput) = builder.run {
|
||||||
|
writeString("123", 0)
|
||||||
|
writeByte(123, 1)
|
||||||
|
writeShort(123, 2)
|
||||||
|
writeInt(123, 3)
|
||||||
|
writeLong(123, 4)
|
||||||
|
writeFloat(123f, 5)
|
||||||
|
writeDouble(123.0, 6)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testEncoder() {
|
fun testEncoder() {
|
||||||
@ -44,12 +57,13 @@ class JceEncoderTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testEncoder2() {
|
fun testEncoder2() {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
buildJcePacket {
|
buildJcePacket(stringCharset = CharsetUTF8) {
|
||||||
writeFully(byteArrayOf(1, 2, 3), 7)
|
writeFully(byteArrayOf(1, 2, 3), 7)
|
||||||
writeCollection(listOf(1, 2, 3), 8)
|
writeCollection(listOf(1, 2, 3), 8)
|
||||||
writeMap(mapOf("哈哈" to "嘿嘿"), 9)
|
writeMap(mapOf("哈哈" to "嘿嘿"), 9)
|
||||||
|
writeJceStruct(TestSimpleJceStruct(), 10)
|
||||||
}.readBytes().toUHexString(),
|
}.readBytes().toUHexString(),
|
||||||
Jce.GBK.dump(
|
Jce.UTF8.dump(
|
||||||
TestComplexJceStruct.serializer(),
|
TestComplexJceStruct.serializer(),
|
||||||
TestComplexJceStruct()
|
TestComplexJceStruct()
|
||||||
).toUHexString()
|
).toUHexString()
|
||||||
@ -60,6 +74,7 @@ class JceEncoderTest {
|
|||||||
class TestComplexJceStruct(
|
class TestComplexJceStruct(
|
||||||
@SerialId(7) val byteArray: ByteArray = byteArrayOf(1, 2, 3),
|
@SerialId(7) val byteArray: ByteArray = byteArrayOf(1, 2, 3),
|
||||||
@SerialId(8) val byteList: List<Byte> = listOf(1, 2, 3),
|
@SerialId(8) val byteList: List<Byte> = listOf(1, 2, 3),
|
||||||
@SerialId(9) val map: Map<String, String> = mapOf("哈哈" to "嘿嘿")
|
@SerialId(9) val map: Map<String, String> = mapOf("哈哈" to "嘿嘿"),
|
||||||
|
@SerialId(10) val nestedJceStruct: TestSimpleJceStruct = TestSimpleJceStruct()
|
||||||
)
|
)
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user