From 522ac8b839d4c214858d8a82ebce56f9bcd36dde Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 8 Oct 2019 16:32:52 +0800 Subject: [PATCH] Improved message parsing --- .../kotlin/net/mamoe/mirai/message/FaceID.kt | 309 +++++++++--------- .../net/mamoe/mirai/message/defaults/Face.kt | 8 +- .../net/mamoe/mirai/message/defaults/Image.kt | 8 +- .../mirai/message/defaults/MessageChain.kt | 70 ++++ .../mamoe/mirai/message/defaults/PlainText.kt | 2 +- .../mirai/network/protocol/tim/TIMProtocol.kt | 2 + .../protocol/tim/packet/ServerEvent.kt | 69 +--- .../action/ClientSendFriendMessagePacket.kt | 21 +- .../kotlin/net/mamoe/mirai/utils/Varint.kt | 1 - 9 files changed, 254 insertions(+), 236 deletions(-) diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/FaceID.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/FaceID.kt index c84411b2a..7cf822298 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/FaceID.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/FaceID.kt @@ -1,174 +1,167 @@ -package net.mamoe.mirai.message; +package net.mamoe.mirai.message /** * @author LamGC * @author Him188moe */ -public enum FaceID { +@Suppress("EnumEntryName", "unused", "SpellCheckingInspection") +enum class FaceID constructor(val id: Int) { unknown(0xff), - - Face_jingya(0), - Face_piezui(1), - Face_se(2), - Face_fadai(3), - Face_deyi(4), - Face_liulei(5), - Face_haixiu(6), - Face_bizui(7), - Face_shui(8), - Face_daku(9), - Face_ganga(10), - Face_fanu(11), - Face_tiaopi(12), - Face_ciya(13), - Face_weixiao(14), - Face_nanguo(15), - Face_ku(16), - Face_zhuakuang(18), - Face_tu(19), - Face_touxiao(20), - Face_keai(21), - Face_baiyan(22), - Face_aoman(23), - Face_ji_e(24), - Face_kun(25), - Face_jingkong(26), - Face_liuhan(27), - Face_hanxiao(28), - Face_dabing(29), - Face_fendou(30), - Face_zhouma(31), - Face_yiwen(32), - Face_yun(34), - Face_zhemo(35), - Face_shuai(36), - Face_kulou(37), - Face_qiaoda(38), - Face_zaijian(39), - Face_fadou(41), - Face_aiqing(42), - Face_tiaotiao(43), - Face_zhutou(46), - Face_yongbao(49), - Face_dan_gao(53), - Face_shandian(54), - Face_zhadan(55), - Face_dao(56), - Face_zuqiu(57), - Face_bianbian(59), - Face_kafei(60), - Face_fan(61), - Face_meigui(63), - Face_diaoxie(64), - Face_aixin(66), - Face_xinsui(67), - Face_liwu(69), - Face_taiyang(74), - Face_yueliang(75), - Face_qiang(76), - Face_ruo(77), - Face_woshou(78), - Face_shengli(79), - Face_feiwen(85), - Face_naohuo(86), - Face_xigua(89), - Face_lenghan(96), - Face_cahan(97), - Face_koubi(98), - Face_guzhang(99), - Face_qiudale(100), - Face_huaixiao(101), - Face_zuohengheng(102), - Face_youhengheng(103), - Face_haqian(104), - Face_bishi(105), - Face_weiqu(106), - Face_kuaikule(107), - Face_yinxian(108), - Face_qinqin(109), - Face_xia(110), - Face_kelian(111), - Face_caidao(112), - Face_pijiu(113), - Face_lanqiu(114), - Face_pingpang(115), - Face_shiai(116), - Face_piaochong(117), - Face_baoquan(118), - Face_gouyin(119), - Face_quantou(120), - Face_chajin(121), - Face_aini(122), - Face_bu(123), - Face_hao(124), - Face_zhuanquan(125), - Face_ketou(126), - Face_huitou(127), - Face_tiaosheng(128), - Face_huishou(129), - Face_jidong(130), - Face_jiewu(131), - Face_xianwen(132), - Face_zuotaiji(133), - Face_youtaiji(134), - Face_shuangxi(136), - Face_bianpao(137), - Face_denglong(138), - Face_facai(139), - Face_K_ge(140), - Face_gouwu(141), - Face_youjian(142), - Face_shuai_qi(143), - Face_hecai(144), - Face_qidao(145), - Face_baojin(146), - Face_bangbangtang(147), - Face_he_nai(148), - Face_xiamian(149), - Face_xiangjiao(150), - Face_feiji(151), - Face_kaiche(152), - Face_gaotiezuochetou(153), - Face_chexiang(154), - Face_gaotieyouchetou(155), - Face_duoyun(156), - Face_xiayu(157), - Face_chaopiao(158), - Face_xiongmao(159), - Face_dengpao(160), - Face_fengche(161), - Face_naozhong(162), - Face_dasan(163), - Face_caiqiu(164), - Face_zuanjie(165), - Face_shafa(166), - Face_zhijin(167), - Face_yao(168), - Face_shouqiang(169), - Face_qingwa(170), - // TODO: 2019/9/1 添加更多表情 + jingya(0), + piezui(1), + se(2), + fadai(3), + deyi(4), + liulei(5), + haixiu(6), + bizui(7), + shui(8), + daku(9), + ganga(10), + fanu(11), + tiaopi(12), + ciya(13), + weixiao(14), + nanguo(15), + ku(16), + zhuakuang(18), + tu(19), + touxiao(20), + keai(21), + baiyan(22), + aoman(23), + ji_e(24), + kun(25), + jingkong(26), + liuhan(27), + hanxiao(28), + dabing(29), + fendou(30), + zhouma(31), + yiwen(32), + yun(34), + zhemo(35), + shuai(36), + kulou(37), + qiaoda(38), + zaijian(39), + fadou(41), + aiqing(42), + tiaotiao(43), + zhutou(46), + yongbao(49), + dan_gao(53), + shandian(54), + zhadan(55), + dao(56), + zuqiu(57), + bianbian(59), + kafei(60), + fan(61), + meigui(63), + diaoxie(64), + aixin(66), + xinsui(67), + liwu(69), + taiyang(74), + yueliang(75), + qiang(76), + ruo(77), + woshou(78), + shengli(79), + feiwen(85), + naohuo(86), + xigua(89), + lenghan(96), + cahan(97), + koubi(98), + guzhang(99), + qiudale(100), + huaixiao(101), + zuohengheng(102), + youhengheng(103), + haqian(104), + bishi(105), + weiqu(106), + kuaikule(107), + yinxian(108), + qinqin(109), + xia(110), + kelian(111), + caidao(112), + pijiu(113), + lanqiu(114), + pingpang(115), + shiai(116), + piaochong(117), + baoquan(118), + gouyin(119), + quantou(120), + chajin(121), + aini(122), + bu(123), + hao(124), + zhuanquan(125), + ketou(126), + huitou(127), + tiaosheng(128), + huishou(129), + jidong(130), + jiewu(131), + xianwen(132), + zuotaiji(133), + youtaiji(134), + shuangxi(136), + bianpao(137), + denglong(138), + facai(139), + K_ge(140), + gouwu(141), + youjian(142), + shuai_qi(143), + hecai(144), + qidao(145), + baojin(146), + bangbangtang(147), + he_nai(148), + xiamian(149), + xiangjiao(150), + feiji(151), + kaiche(152), + gaotiezuochetou(153), + chexiang(154), + gaotieyouchetou(155), + duoyun(156), + xiayu(157), + chaopiao(158), + xiongmao(159), + dengpao(160), + fengche(161), + naozhong(162), + dasan(163), + caiqiu(164), + zuanjie(165), + shafa(166), + zhijin(167), + yao(168), + shouqiang(169), + qingwa(170); - ; - - private final int id; - - FaceID(int id) { - this.id = id; + override fun toString(): String { + return "$name($id)" } - public int getId() { - return id; - } + companion object { - public static FaceID ofId(int id) { - for (FaceID value : FaceID.values()) { - if (value.id == id) { - return value; + fun ofId(id: Int): FaceID { + for (value in values()) { + if (value.id == id) { + return value + } } + return unknown } - return FaceID.unknown; } - } diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/defaults/Face.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/defaults/Face.kt index 2d251de68..0b5eecf33 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/defaults/Face.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/defaults/Face.kt @@ -20,7 +20,11 @@ class Face(val id: FaceID) : Message() { override val type: MessageKey = Key override fun toStringImpl(): String { - return String.format("[face%d]", id.id) + return "[face${id.id}]" + } + + override fun toObjectString(): String { + return "Face[$id]" } override fun toByteArray(): ByteArray = dataEncode { section -> @@ -48,7 +52,7 @@ class Face(val id: FaceID) : Message() { override operator fun contains(sub: String): Boolean = false - internal object PacketHelper { + object PacketHelper { fun ofByteArray(data: ByteArray): Face = dataDecode(data) { //00 01 AF 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 F0 //00 01 0C 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 4D diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/defaults/Image.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/defaults/Image.kt index 79edadf32..459349e7b 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/defaults/Image.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/defaults/Image.kt @@ -22,7 +22,11 @@ open class Image(val imageId: String) : Message() { override val type: MessageKey = Key override fun toStringImpl(): String { - return imageId + return "[$imageId]" + } + + override fun toObjectString(): String { + return "Image[$imageId]" } override fun toByteArray(): ByteArray = dataEncode { section -> @@ -55,7 +59,7 @@ open class Image(val imageId: String) : Message() { override operator fun contains(sub: String): Boolean = false //No string can be contained in a image - internal object PacketHelper { + object PacketHelper { @JvmStatic fun ofByteArray0x06(data: ByteArray): Image = dataDecode(data) { it.skip(1) diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/defaults/MessageChain.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/defaults/MessageChain.kt index 2943513de..8e7be7c4b 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/defaults/MessageChain.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/defaults/MessageChain.kt @@ -2,7 +2,12 @@ package net.mamoe.mirai.message.defaults import net.mamoe.mirai.message.Message import net.mamoe.mirai.message.MessageKey +import net.mamoe.mirai.network.protocol.tim.packet.readLVByteArray +import net.mamoe.mirai.network.protocol.tim.packet.readNBytes +import net.mamoe.mirai.utils.dataDecode import net.mamoe.mirai.utils.dataEncode +import net.mamoe.mirai.utils.toUHexString +import java.io.DataInputStream import java.util.* import java.util.stream.Collectors import java.util.stream.Stream @@ -95,4 +100,69 @@ class MessageChain : Message { operator fun component1(): Message = this.list[0] operator fun component2(): Message = this.list[1] operator fun component3(): Message = this.list[2] + + object PacketHelper { + @JvmStatic + fun ofByteArray(byteArray: ByteArray): MessageChain = dataDecode(byteArray) { + it.readMessageChain() + } + } } + +fun DataInputStream.readMessage(): Message? { + val messageType = this.readByte().toInt() + val sectionLength = this.readShort().toLong()//sectionLength: short + val sectionData = this.readNBytes(sectionLength) + return when (messageType) { + 0x01 -> PlainText.PacketHelper.ofByteArray(sectionData) + 0x02 -> Face.PacketHelper.ofByteArray(sectionData) + 0x03 -> Image.PacketHelper.ofByteArray0x03(sectionData) + 0x06 -> Image.PacketHelper.ofByteArray0x06(sectionData) + + + 0x19 -> {//长文本 + val value = readLVByteArray() + //todo 未知压缩算法 + PlainText(String(value)) + + // PlainText(String(GZip.uncompress( value))) + } + + + 0x14 -> {//长文本 + val value = readLVByteArray() + println(value.size) + println(value.toUHexString()) + //todo 未知压缩算法 + this.skip(7)//几个TLV + return PlainText(String(value)) + } + + 0x0E -> { + //null + null + } + + else -> { + println("未知的messageType=0x${messageType.toByte().toUHexString()}") + println("后文=${this.readAllBytes().toUHexString()}") + null + } + } + +} + +fun DataInputStream.readMessageChain(): MessageChain { + val chain = MessageChain() + var got: Message? = null + do { + if (got != null) { + chain.concat(got) + } + if (this.available() == 0) { + return chain + } + got = this.readMessage() + } while (got != null) + return chain +} \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/defaults/PlainText.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/defaults/PlainText.kt index c5bb3e759..86748f93e 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/defaults/PlainText.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/defaults/PlainText.kt @@ -38,7 +38,7 @@ class PlainText(private val text: String) : Message() { override operator fun contains(sub: String): Boolean = this.toString().contains(sub) - internal object PacketHelper { + object PacketHelper { @JvmStatic fun ofByteArray(data: ByteArray): PlainText = dataDecode(data) { it.skip(1) diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/TIMProtocol.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/TIMProtocol.kt index 6d02ff12f..84c23956c 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/TIMProtocol.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/TIMProtocol.kt @@ -39,6 +39,7 @@ object TIMProtocol { */ const val fixVer2 = "02 00 00 00 01 01 01 00 00 68 20" // 02 38 03 00 CD 48 68 3E 03 3F A2 02 00 00 00 + // 02 00 00 00 01 2E 01 00 00 69 35 /** * 0825data1 */ @@ -105,6 +106,7 @@ object TIMProtocol { * length=15 */ const val messageConst1 = "00 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91" + // TIM最新 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 private val hexToByteArrayCacheMap: MutableMap = mutableMapOf() diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/packet/ServerEvent.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/packet/ServerEvent.kt index fd3a7dcfa..16f9dd36c 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/packet/ServerEvent.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/packet/ServerEvent.kt @@ -2,11 +2,8 @@ package net.mamoe.mirai.network.protocol.tim.packet -import net.mamoe.mirai.message.Message -import net.mamoe.mirai.message.defaults.Face -import net.mamoe.mirai.message.defaults.Image import net.mamoe.mirai.message.defaults.MessageChain -import net.mamoe.mirai.message.defaults.PlainText +import net.mamoe.mirai.message.defaults.readMessageChain import net.mamoe.mirai.network.protocol.tim.TIMProtocol import net.mamoe.mirai.utils.dataDecode import net.mamoe.mirai.utils.hexToBytes @@ -49,7 +46,7 @@ abstract class ServerEventPacket(input: DataInputStream, val packetId: ByteArray @PacketId("00 17") class Encrypted(input: DataInputStream, private val packetId: ByteArray) : ServerPacket(input) { - fun decrypt(sessionKey: ByteArray): Raw = Raw(decryptBy(sessionKey), packetId).setId(this.idHex) + fun decrypt(sessionKey: ByteArray): Raw = Raw(this.decryptBy(sessionKey), packetId).setId(this.idHex) } } @@ -135,7 +132,7 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray, this.input.goto(108) this.input.readLVByteArray() input.skip(2)//2个0x00 - message = input.readSections() + message = input.readMessageChain() val map = input.readTLVMap(true) if (map.containsKey(18)) { @@ -262,7 +259,7 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray input.goto(93 + l1) input.readLVByteArray()//font input.skip(2)//2个0x00 - message = input.readSections() + message = input.readMessageChain() val map: Map = input.readTLVMap(true).withDefault { byteArrayOf() } println(map.getValue(18)) @@ -278,64 +275,6 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray } } -private fun DataInputStream.readSection(): Message? { - val messageType = this.readByte().toInt() - val sectionLength = this.readShort().toLong()//sectionLength: short - val sectionData = this.readNBytes(sectionLength) - return when (messageType) { - 0x01 -> PlainText.PacketHelper.ofByteArray(sectionData) - 0x02 -> Face.PacketHelper.ofByteArray(sectionData) - 0x03 -> Image.PacketHelper.ofByteArray0x03(sectionData) - 0x06 -> Image.PacketHelper.ofByteArray0x06(sectionData) - - - 0x19 -> {//长文本 - val value = readLVByteArray() - //todo 未知压缩算法 - PlainText(String(value)) - - // PlainText(String(GZip.uncompress( value))) - } - - - 0x14 -> {//长文本 - val value = readLVByteArray() - println(value.size) - println(value.toUHexString()) - //todo 未知压缩算法 - this.skip(7)//几个TLV - return PlainText(String(value)) - } - - 0x0E -> { - //null - null - } - - else -> { - println("未知的messageType=0x${messageType.toByte().toUHexString()}") - println("后文=${this.readAllBytes().toUHexString()}") - null - } - } - -} - -private fun DataInputStream.readSections(): MessageChain { - val chain = MessageChain() - var got: Message? = null - do { - if (got != null) { - chain.concat(got) - } - if (this.available() == 0) { - return chain - } - got = this.readSection() - } while (got != null) - return chain -} - /* 牛逼 (10404 diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/packet/action/ClientSendFriendMessagePacket.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/packet/action/ClientSendFriendMessagePacket.kt index d54e1330b..fbfcc095e 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/packet/action/ClientSendFriendMessagePacket.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/protocol/tim/packet/action/ClientSendFriendMessagePacket.kt @@ -34,11 +34,22 @@ class ClientSendFriendMessagePacket( writeRandom(2) writeTime() writeHex("00 00" + - "00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00") - //01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 + "00 00 00 00") + + //消息过多要分包发送 + //如果只有一个 + writeByte(0x01) + writeByte(0)//第几个包 + writeByte(0) + //如果大于一个, + //writeByte(0x02)//数量 + //writeByte(0)//第几个包 + //writeByte(0x91)//why? + + writeHex("00 01 4D 53 47 00 00 00 00 00") writeTime() writeRandom(4) - writeHex("00 00 00 00 09 00 86") + writeHex("00 00 00 00 09 00 86")//TIM最新 0C 00 86 writeHex(TIMProtocol.messageConst1)//... 85 E9 BB 91 writeZero(2) @@ -56,9 +67,5 @@ class ClientSendFriendMessagePacket( } } - -fun main() { - -} @PacketId("00 CD") class ServerSendFriendMessageResponsePacket(input: DataInputStream) : ServerPacket(input) \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/Varint.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/Varint.kt index 289749a18..ddf9c6818 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/Varint.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/Varint.kt @@ -69,7 +69,6 @@ fun DataOutputStream.writeVarInt(signedInt: Int) { this.writeUVarInt(encodeZigZag32(signedInt)) } - @Throws(IOException::class) fun DataOutputStream.writeUVarInt(uint: UInt) { return writeUVarInt(uint.toLong())