diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceInput.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceInput.kt index 2910b341d..a2bcd2a0b 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceInput.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceInput.kt @@ -3,6 +3,8 @@ package net.mamoe.mirai.qqandroid.io import kotlinx.io.charsets.Charset import kotlinx.io.core.* import kotlinx.io.pool.ObjectPool +import kotlinx.serialization.DeserializationStrategy +import net.mamoe.mirai.qqandroid.io.serialization.Jce import net.mamoe.mirai.qqandroid.network.protocol.jce.RequestPacket import net.mamoe.mirai.utils.io.DebugLogger import net.mamoe.mirai.utils.io.readIoBuffer @@ -18,12 +20,16 @@ inline class JceHead(private val value: Long) { override fun toString(): String { return "JceHead(tag=$tag, type=$type)" - } + }Z } -fun ByteArray.readJceStruct(factory: JceStruct.Factory, tag: Int = 0, charset: Charset = CharsetUTF8): J { +fun ByteArray.readJceStruct( + deserializer: DeserializationStrategy, + tag: Int = 0, + charset: Charset = CharsetUTF8 +): J { this.asJceInput(charset).use { - return it.readJceStruct(factory, tag) + return Jce.byCharSet(charset).load(deserializer, this.) } } @@ -55,7 +61,10 @@ fun ByteReadPacket.readJceRequestBufferMapVersion3ToJceStruct(fa fun ByteReadPacket.readJceRequestBufferMapVersion2(charset: Charset = CharsetUTF8): Map { this.use { discardExact(8) - val request = this.asJceInput(charset).use { RequestPacket.newInstanceFrom(it) } + val request = this.asJceInput(charset).use { + Jce + RequestPacket.serializer() + } val map = request.sBuffer.asJceInput(charset).withUse { readNestedMap(0) } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceStruct.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceStruct.kt index 452731941..ffff1fbe9 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceStruct.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceStruct.kt @@ -1,10 +1,5 @@ package net.mamoe.mirai.qqandroid.io -abstract class JceStruct { - abstract fun writeTo(builder: JceOutput) +interface JceStruct { - interface Factory { - fun newInstanceFrom(input: JceInput): T - - } } \ No newline at end of file diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/JceEncoder.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/JceEncoder.kt index 0de297c38..b206cfef6 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/JceEncoder.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/JceEncoder.kt @@ -10,6 +10,7 @@ import kotlinx.serialization.* import kotlinx.serialization.internal.* import kotlinx.serialization.modules.EmptyModule import kotlinx.serialization.modules.SerialModule +import net.mamoe.mirai.qqandroid.io.CharsetUTF8 import net.mamoe.mirai.qqandroid.io.JceEncodeException import net.mamoe.mirai.qqandroid.io.JceStruct import kotlin.reflect.KClass @@ -321,6 +322,14 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo val UTF8 = Jce(JceCharset.UTF8) val GBK = Jce(JceCharset.GBK) + public fun byCharSet(c: Charset): Jce { + return if (c === CharsetUTF8) { + UTF8 + } else { + GBK + } + } + internal const val BYTE: Int = 0 internal const val DOUBLE: Int = 5 internal const val FLOAT: Int = 4 diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/jce/RequestPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/jce/RequestPacket.kt index 20cbc50fb..8c3717588 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/jce/RequestPacket.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/jce/RequestPacket.kt @@ -1,78 +1,22 @@ package net.mamoe.mirai.qqandroid.network.protocol.jce -import net.mamoe.mirai.qqandroid.io.JceInput -import net.mamoe.mirai.qqandroid.io.JceOutput +import kotlinx.serialization.SerialId +import kotlinx.serialization.Serializable import net.mamoe.mirai.qqandroid.io.JceStruct -import net.mamoe.mirai.utils.cryptor.contentToString +import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY private val EMPTY_MAP = mapOf() -class RequestPacket() : JceStruct() { - lateinit var sBuffer: ByteArray - var cPacketType: Byte = 0 - var iMessageType: Int = 0 - var iRequestId: Int = 0 - var iTimeout: Int = 0 - var iVersion: Short = 3 - var context: Map = EMPTY_MAP - var sFuncName: String = "" - var sServantName: String = "" - var status: Map = EMPTY_MAP - - constructor( - sBuffer: ByteArray, - cPacketType: Byte = 0, - iMessageType: Int = 0, - iRequestId: Int = 0, - iTimeout: Int = 0, - iVersion: Short = 3, - context: Map = EMPTY_MAP, - sFuncName: String = "", - sServantName: String = "", - status: Map = EMPTY_MAP - ) : this() { - this.sBuffer = sBuffer - this.cPacketType = cPacketType - this.iMessageType = iMessageType - this.iRequestId = iRequestId - this.iTimeout = iTimeout - this.iVersion = iVersion - this.context = context - this.sFuncName = sFuncName - this.sServantName = sServantName - this.status = status - } - - companion object : Factory { - override fun newInstanceFrom(input: JceInput): RequestPacket { - val iVersion = input.readShort(1) - val cPacketType = input.readByte(2) - val iMessageType = input.readInt(3) - val iRequestId = input.readInt(4) - val sServantName = input.readString(5) - val sFuncName = input.readString(6) - val sBuffer = input.readByteArray(7) - val iTimeout = input.readInt(8) - val context = input.readMap("", "", 9) - val status = input.readMap("", "", 10) - return RequestPacket(sBuffer, cPacketType, iMessageType, iRequestId, iTimeout, iVersion, context, sFuncName, sServantName, status) - } - } - - override fun writeTo(builder: JceOutput) { - builder.write(this.iVersion, 1) - builder.write(this.cPacketType, 2) - builder.write(this.iMessageType, 3) - builder.write(this.iRequestId, 4) - builder.write(this.sServantName, 5) - builder.write(this.sFuncName, 6) - builder.write(this.sBuffer, 7) - builder.write(this.iTimeout, 8) - builder.write(this.context, 9) - builder.write(this.status, 10) - } - - override fun toString(): String { - return this.contentToString() - } -} \ No newline at end of file +@Serializable +class RequestPacket( + @SerialId(1) val iVersion: Short = 3, + @SerialId(2) val cPacketType: Byte = 0, + @SerialId(3) val iMessageType: Int = 0, + @SerialId(4) val iRequestId: Int = 0, + @SerialId(5) val sServantName: String = "", + @SerialId(6) val sFuncName: String = "", + @SerialId(7) val sBuffer: ByteArray = EMPTY_BYTE_ARRAY, + @SerialId(8) val iTimeout: Int = 0, + @SerialId(9) val context: Map = EMPTY_MAP, + @SerialId(10) val status: Map = EMPTY_MAP +) : JceStruct \ No newline at end of file diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/PushNotifyPack.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/PushNotifyPack.kt index 0f706f0a7..88c6a5d03 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/PushNotifyPack.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/PushNotifyPack.kt @@ -1,164 +1,70 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data +import kotlinx.serialization.SerialId +import kotlinx.serialization.Serializable import net.mamoe.mirai.data.Packet -import net.mamoe.mirai.qqandroid.io.JceInput -import net.mamoe.mirai.qqandroid.io.JceOutput import net.mamoe.mirai.qqandroid.io.JceStruct import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY -class RequestPushNotify( - val uin: Long, - val ctype: Byte, - val strService: String, - val strCmd: String, - val vNotifyCookie: ByteArray, - val usMsgType: Int, - val wUserActive: Int, - val wGeneralFlag: Int, - val bindedUin: Long, - val stMsgInfo: MsgInfo, - val msgCtrlBuf: String, - val serverBuf: ByteArray, - val pingFlag: Long, - val svrip: Int -) : Packet, JceStruct() { - override fun writeTo(builder: JceOutput) { - //not needed - } +@Serializable +internal class RequestPushNotify( + @SerialId(0) val uin: Long = 0L, + @SerialId(1) val ctype: Byte = 0, + @SerialId(2) val strService: String?, + @SerialId(3) val strCmd: String?, + @SerialId(4) val vNotifyCookie: ByteArray = EMPTY_BYTE_ARRAY, + @SerialId(5) val usMsgType: Int?, + @SerialId(6) val wUserActive: Int?, + @SerialId(7) val wGeneralFlag: Int?, + @SerialId(8) val bindedUin: Long?, + @SerialId(9) val stMsgInfo: MsgInfo?, + @SerialId(10) val msgCtrlBuf: String?, + @SerialId(11) val serverBuf: ByteArray?, + @SerialId(12) val pingFlag: Long?, + @SerialId(13) val svrip: Int? +) : JceStruct, Packet - companion object : Factory { - override fun newInstanceFrom(input: JceInput): RequestPushNotify { - return RequestPushNotify( - input.read(0L, 0), - input.read(0.toByte(), 1), - input.readString(2), - input.readString(3), - input.read(EMPTY_BYTE_ARRAY, 4), - input.read(0, 5), - input.read(0, 6), - input.read(0, 7), - input.read(0L, 8), - input.readJceStruct(MsgInfo, 9), - input.readString(10), - input.readByteArray(11), - input.readLong(12), - input.readInt(13) - ) - } - } +@Serializable +internal class MsgInfo( + @SerialId(0) val lFromUin: Long = 0L, + @SerialId(1) val uMsgTime: Long = 0L, + @SerialId(2) val shMsgType: Short?, + @SerialId(3) val shMsgSeq: Short?, + @SerialId(4) val strMsg: String?, + @SerialId(5) val uRealMsgTime: Int?, + @SerialId(6) val vMsg: ByteArray?, + @SerialId(7) val uAppShareID: Long?, + @SerialId(8) val vMsgCookies: ByteArray = EMPTY_BYTE_ARRAY, + @SerialId(9) val vAppShareCookie: ByteArray = EMPTY_BYTE_ARRAY, + @SerialId(10) val lMsgUid: Long?, + @SerialId(11) val lLastChangeTime: Long?, + @SerialId(12) val vCPicInfo: List?, + @SerialId(13) val stShareData: ShareData?, + @SerialId(14) val lFromInstId: Long?, + @SerialId(15) val vRemarkOfSender: ByteArray?, + @SerialId(16) val strFromMobile: String?, + @SerialId(17) val strFromName: String?, + @SerialId(18) val vNickName: List?, + @SerialId(19) val stC2CTmpMsgHead: TempMsgHead? +) : JceStruct -} - -class MsgInfo( - val lFromUin: Long, - val uMsgTime: Long, - val shMsgType: Short, - val shMsgSeq: Short, - val strMsg: String, - val uRealMsgTime: Int, - val vMsg: ByteArray, - val uAppShareID: Long, - val vMsgCookies: ByteArray, - val vAppShareCookie: ByteArray, - val lMsgUid: Long, - val lLastChangeTime: Long, - val vCPicInfo: List, - val stShareData: ShareData, - val lFromInstId: Long, - val vRemarkOfSender: ByteArray, - val strFromMobile: String, - val strFromName: String, - val vNickName: List, - val stC2CTmpMsgHead: TempMsgHead? -) : JceStruct() { - companion object : Factory { - override fun newInstanceFrom(input: JceInput): MsgInfo = with(input) { - return MsgInfo( - readLong(0), - readLong(1), - readShort(2), - readShort(3), - readString(4), - readInt(5), - readByteArray(6), - readLong(7), - readByteArray(8), - readByteArray(9), - readLong(10), - readLong(11), - readJceStructList(CPicInfo, 12), - readJceStruct(ShareData, 13), - readLong(14), - readByteArray(15), - readString(16), - readString(17), - readList(18), - readJceStructOrNull(TempMsgHead, 19) - ) - } - - } - - override fun writeTo(builder: JceOutput) { - // not needed - } -} +@Serializable class ShareData( - val pkgname: String = "", - val msgtail: String = "", - val picurl: String = "", - val url: String = "" -) : JceStruct() { - companion object : Factory { - override fun newInstanceFrom(input: JceInput): ShareData { - return ShareData( - input.readString(0), - input.readString(1), - input.readString(2), - input.readString(3) - ) - } - } - - override fun writeTo(builder: JceOutput) { - // not needed - } -} + @SerialId(0) val pkgname: String = "", + @SerialId(1) val msgtail: String = "", + @SerialId(2) val picurl: String = "", + @SerialId(3) val url: String = "" +) : JceStruct +@Serializable class TempMsgHead( - val c2c_type: Int, - val serviceType: Int -) : JceStruct() { - override fun writeTo(builder: JceOutput) { - - } - - companion object : Factory { - override fun newInstanceFrom(input: JceInput): TempMsgHead { - return TempMsgHead( - input.readInt(0), - input.readInt(1) - ) - } - } -} + @SerialId(0) val c2c_type: Int = 0, + @SerialId(1) val serviceType: Int = 0 +) : JceStruct +@Serializable class CPicInfo( - val vPath: ByteArray, - val vHost: ByteArray? -) : JceStruct() { - override fun writeTo(builder: JceOutput) { - - } - - companion object : Factory { - override fun newInstanceFrom(input: JceInput): CPicInfo { - return CPicInfo( - input.readByteArray(0), - input.readByteArray(1) - ) - } - } - -} + @SerialId(0) val vPath: ByteArray = EMPTY_BYTE_ARRAY, + @SerialId(1) val vHost: ByteArray = EMPTY_BYTE_ARRAY +) : JceStruct \ No newline at end of file