Improved message parsing

This commit is contained in:
Him188 2019-10-08 16:32:52 +08:00
parent c6373ec727
commit 522ac8b839
9 changed files with 254 additions and 236 deletions

View File

@ -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;
}
}

View File

@ -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

View File

@ -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)

View File

@ -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
}

View File

@ -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)

View File

@ -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<Int, ByteArray> = mutableMapOf()

View File

@ -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<Int, ByteArray> = 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

View File

@ -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)

View File

@ -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())