mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-08 17:20:11 +08:00
zip support
This commit is contained in:
parent
b50f3e4d16
commit
6a8e6b93a0
@ -14,9 +14,9 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.login.data.RequestPacke
|
||||
import net.mamoe.mirai.utils.DefaultLogger
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.cryptor.adjustToPublicKey
|
||||
import net.mamoe.mirai.utils.cryptor.contentToString
|
||||
import net.mamoe.mirai.utils.cryptor.decryptBy
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.utils.unzip
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.jvm.JvmName
|
||||
@ -126,6 +126,8 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
|
||||
}?.let {
|
||||
// 处理内层真实的包
|
||||
if (it.packetFactory == null) {
|
||||
PacketLogger.warning("找不到 PacketFactory")
|
||||
PacketLogger.verbose("传递给 PacketFactory 的数据 = ${it.data.useBytes { data, length -> data.toUHexString(length = length) }}")
|
||||
return
|
||||
}
|
||||
|
||||
@ -147,7 +149,6 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
|
||||
PacketLogger.error("任何key都无法解密: ${data.take(size).toUHexString()}")
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -183,7 +184,7 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
|
||||
private fun parseSsoFrame(bot: QQAndroidBot, input: ByteReadPacket): IncomingPacket {
|
||||
val commandName: String
|
||||
val ssoSequenceId: Int
|
||||
|
||||
val dataCompressed: Int
|
||||
// head
|
||||
input.readIoBuffer(input.readInt() - 4).withUse {
|
||||
ssoSequenceId = readInt()
|
||||
@ -196,26 +197,25 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
|
||||
val unknown = readBytes(readInt() - 4)
|
||||
if (unknown.toInt() != 0x02B05B8B) DebugLogger.debug("got new unknown: ${unknown.toUHexString()}")
|
||||
|
||||
readInt().let {
|
||||
if (it != 0) {
|
||||
DebugLogger.debug("!! 得到一个原本是 0, 现在是 ${it.contentToString()}")
|
||||
if (it == 1){
|
||||
PacketLogger.info("无法处理的数据 = ${input.readBytes().toUHexString()}")
|
||||
return IncomingPacket(null, ssoSequenceId, input)
|
||||
}
|
||||
}
|
||||
dataCompressed = readInt()
|
||||
}
|
||||
|
||||
val packet = when (dataCompressed) {
|
||||
0 -> input
|
||||
1 -> {
|
||||
input.discardExact(4)
|
||||
input.useBytes { data, length ->
|
||||
data.unzip(length = length)
|
||||
}.toReadPacket()
|
||||
}
|
||||
else -> error("unknown dataCompressed flag: $dataCompressed")
|
||||
}
|
||||
|
||||
// body
|
||||
val packetFactory = findPacketFactory(commandName)
|
||||
|
||||
bot.logger.verbose(commandName)
|
||||
if (packetFactory == null) {
|
||||
bot.logger.warning("找不到包 PacketFactory")
|
||||
PacketLogger.verbose("传递给 PacketFactory 的数据 = ${input.readBytes().toUHexString()}")
|
||||
}
|
||||
return IncomingPacket(packetFactory, ssoSequenceId, input)
|
||||
bot.logger.info("Received: $commandName")
|
||||
return IncomingPacket(packetFactory, ssoSequenceId, packet)
|
||||
}
|
||||
|
||||
private suspend fun <T : Packet> ByteReadPacket.parseOicqResponse(
|
||||
@ -224,14 +224,13 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
|
||||
ssoSequenceId: Int,
|
||||
consumer: PacketConsumer<T>
|
||||
) {
|
||||
val qq: Long
|
||||
readIoBuffer(readInt() - 4).withUse {
|
||||
check(readByte().toInt() == 2)
|
||||
this.discardExact(2) // 27 + 2 + body.size
|
||||
this.discardExact(2) // const, =8001
|
||||
this.readUShort() // commandId
|
||||
this.readShort() // const, =0x0001
|
||||
qq = this.readUInt().toLong()
|
||||
this.readUInt().toLong() // qq
|
||||
val encryptionMethod = this.readUShort().toInt()
|
||||
|
||||
this.discardExact(1) // const = 0
|
||||
|
@ -6,8 +6,9 @@ import net.mamoe.mirai.data.Packet
|
||||
import net.mamoe.mirai.qqandroid.io.JceStruct
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
|
||||
|
||||
@Suppress("ArrayInDataClass")
|
||||
@Serializable
|
||||
internal class RequestPushNotify(
|
||||
internal data class RequestPushNotify(
|
||||
@SerialId(0) val uin: Long = 0L,
|
||||
@SerialId(1) val ctype: Byte = 0,
|
||||
@SerialId(2) val strService: String?,
|
||||
|
@ -5,6 +5,8 @@ import io.ktor.client.engine.cio.CIO
|
||||
import io.ktor.util.KtorExperimentalAPI
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import kotlinx.io.pool.useInstance
|
||||
import net.mamoe.mirai.utils.io.ByteArrayPool
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.DataInput
|
||||
import java.io.EOFException
|
||||
@ -83,17 +85,23 @@ actual fun crc32(key: ByteArray): Int = CRC32().apply { update(key) }.value.toIn
|
||||
*/
|
||||
actual fun solveIpAddress(hostname: String): String = InetAddress.getByName(hostname).hostAddress
|
||||
|
||||
actual fun ByteArray.unzip(): ByteArray {
|
||||
actual fun ByteArray.unzip(offset: Int, length: Int): ByteArray {
|
||||
this.checkOffsetAndLength(offset, length)
|
||||
if (length == 0) return ByteArray(0)
|
||||
|
||||
val inflater = Inflater()
|
||||
inflater.reset()
|
||||
val output = ByteArrayOutputStream()
|
||||
inflater.setInput(this)
|
||||
val buffer = ByteArray(128)
|
||||
while (!inflater.finished()) {
|
||||
output.write(buffer, 0, inflater.inflate(buffer))
|
||||
ByteArrayOutputStream().use { output ->
|
||||
inflater.setInput(this, offset, length)
|
||||
ByteArrayPool.useInstance {
|
||||
while (!inflater.finished()) {
|
||||
output.write(it, 0, inflater.inflate(it))
|
||||
}
|
||||
}
|
||||
|
||||
inflater.end()
|
||||
return output.toByteArray()
|
||||
}
|
||||
inflater.end()
|
||||
return output.toByteArray()
|
||||
}
|
||||
|
||||
actual fun newCoroutineDispatcher(threadCount: Int): CoroutineDispatcher {
|
||||
|
@ -24,7 +24,10 @@ expect val deviceName: String
|
||||
*/
|
||||
expect fun crc32(key: ByteArray): Int
|
||||
|
||||
expect fun ByteArray.unzip(): ByteArray
|
||||
/**
|
||||
* 解 zip 压缩
|
||||
*/
|
||||
expect fun ByteArray.unzip(offset: Int = 0, length: Int = this.size - offset): ByteArray
|
||||
|
||||
/**
|
||||
* MD5 算法
|
||||
@ -48,4 +51,10 @@ expect fun localIpAddress(): String
|
||||
*/
|
||||
expect val Http: HttpClient
|
||||
|
||||
expect fun newCoroutineDispatcher(threadCount: Int): CoroutineDispatcher
|
||||
expect fun newCoroutineDispatcher(threadCount: Int): CoroutineDispatcher
|
||||
|
||||
internal fun ByteArray.checkOffsetAndLength(offset: Int, length: Int){
|
||||
require(offset >= 0) { "offset shouldn't be negative: $offset" }
|
||||
require(length >= 0) { "length shouldn't be negative: $length" }
|
||||
require(offset + length <= this.size) { "offset ($offset) + length ($length) > array.size (${this.size})" }
|
||||
}
|
@ -38,6 +38,14 @@ fun ByteReadPacket.transferTo(outputStream: OutputStream) {
|
||||
}
|
||||
}
|
||||
|
||||
fun <R> ByteReadPacket.useBytes(
|
||||
n: Int = remaining.toInt(),//not that safe but adequate
|
||||
block: (data: ByteArray, length: Int) -> R
|
||||
): R = ByteArrayPool.useInstance {
|
||||
this.readFully(it, 0, n)
|
||||
block(it, n)
|
||||
}
|
||||
|
||||
fun ByteReadPacket.readRemainingBytes(
|
||||
n: Int = remaining.toInt()//not that safe but adequate
|
||||
): ByteArray = ByteArray(n).also { readAvailable(it, 0, n) }
|
||||
@ -79,11 +87,11 @@ private inline fun <R> inline(block: () -> R): R = block()
|
||||
typealias TlvMap = MutableMap<Int, ByteArray>
|
||||
|
||||
fun TlvMap.getOrFail(tag: Int): ByteArray {
|
||||
return this[tag]?: error("cannot find tlv 0x${tag.toUHexString("")}($tag)")
|
||||
return this[tag] ?: error("cannot find tlv 0x${tag.toUHexString("")}($tag)")
|
||||
}
|
||||
|
||||
inline fun TlvMap.getOrFail(tag: Int, lazyMessage: (tag: Int) -> String): ByteArray {
|
||||
return this[tag]?: error(lazyMessage(tag))
|
||||
return this[tag] ?: error(lazyMessage(tag))
|
||||
}
|
||||
|
||||
fun Input.readTLVMap(tagSize: Int = 2): TlvMap = readTLVMap(true, tagSize)
|
||||
|
@ -7,8 +7,10 @@ import io.ktor.client.engine.cio.CIO
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import kotlinx.io.core.copyTo
|
||||
import kotlinx.io.pool.useInstance
|
||||
import kotlinx.io.streams.asInput
|
||||
import kotlinx.io.streams.asOutput
|
||||
import net.mamoe.mirai.utils.io.ByteArrayPool
|
||||
import java.io.*
|
||||
import java.net.InetAddress
|
||||
import java.security.MessageDigest
|
||||
@ -56,18 +58,23 @@ actual fun localIpAddress(): String = InetAddress.getLocalHost().hostAddress
|
||||
|
||||
actual val Http: HttpClient get() = HttpClient(CIO)
|
||||
|
||||
actual fun ByteArray.unzip(): ByteArray {
|
||||
actual fun ByteArray.unzip(offset: Int, length: Int): ByteArray {
|
||||
this.checkOffsetAndLength(offset, length)
|
||||
if (length == 0) return ByteArray(0)
|
||||
|
||||
val inflater = Inflater()
|
||||
inflater.reset()
|
||||
val input = this
|
||||
val output = ByteArrayOutputStream()
|
||||
inflater.setInput(input)
|
||||
val buffer = ByteArray(128)
|
||||
while (!inflater.finished()) {
|
||||
output.write(buffer, 0, inflater.inflate(buffer))
|
||||
ByteArrayOutputStream().use { output ->
|
||||
inflater.setInput(this, offset, length)
|
||||
ByteArrayPool.useInstance {
|
||||
while (!inflater.finished()) {
|
||||
output.write(it, 0, inflater.inflate(it))
|
||||
}
|
||||
}
|
||||
|
||||
inflater.end()
|
||||
return output.toByteArray()
|
||||
}
|
||||
inflater.end()
|
||||
return output.toByteArray()
|
||||
}
|
||||
|
||||
actual fun newCoroutineDispatcher(threadCount: Int): CoroutineDispatcher {
|
||||
|
Loading…
Reference in New Issue
Block a user