mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-03 15:32:25 +08:00
Fix unresolved KDoc reference
This commit is contained in:
parent
ee7d3a7e1a
commit
20ea49b090
@ -174,7 +174,7 @@ inline class Image(inline val id: ImageId) : Message {
|
|||||||
* 对于好友, [value] 类似于 `/01ee6426-5ff1-4cf0-8278-e8634d2909ef`, 由服务器返回.
|
* 对于好友, [value] 类似于 `/01ee6426-5ff1-4cf0-8278-e8634d2909ef`, 由服务器返回.
|
||||||
*
|
*
|
||||||
* @see ExternalImage.groupImageId 群图片的 [ImageId] 获取
|
* @see ExternalImage.groupImageId 群图片的 [ImageId] 获取
|
||||||
* @see FriendImageIdRequestPacket.Response.imageId 好友图片的 [ImageId] 获取
|
* @see FriendImageIdRequestPacket.Response.RequireUpload.imageId 好友图片的 [ImageId] 获取
|
||||||
*/
|
*/
|
||||||
inline class ImageId(inline val value: String)
|
inline class ImageId(inline val value: String)
|
||||||
|
|
||||||
|
@ -5,7 +5,9 @@ import kotlinx.io.core.IoBuffer
|
|||||||
import kotlinx.io.pool.useInstance
|
import kotlinx.io.pool.useInstance
|
||||||
import net.mamoe.mirai.network.protocol.tim.packet.Decrypter
|
import net.mamoe.mirai.network.protocol.tim.packet.Decrypter
|
||||||
import net.mamoe.mirai.network.protocol.tim.packet.DecrypterByteArray
|
import net.mamoe.mirai.network.protocol.tim.packet.DecrypterByteArray
|
||||||
import net.mamoe.mirai.utils.io.*
|
import net.mamoe.mirai.utils.io.ByteArrayPool
|
||||||
|
import net.mamoe.mirai.utils.io.toByteArray
|
||||||
|
import net.mamoe.mirai.utils.io.toUHexString
|
||||||
import kotlin.experimental.and
|
import kotlin.experimental.and
|
||||||
import kotlin.experimental.xor
|
import kotlin.experimental.xor
|
||||||
import kotlin.jvm.JvmStatic
|
import kotlin.jvm.JvmStatic
|
||||||
@ -30,15 +32,6 @@ fun ByteArray.encryptBy(key: ByteArray, length: Int = this.size): ByteArray = TE
|
|||||||
|
|
||||||
fun ByteArray.encryptBy(key: DecrypterByteArray, length: Int = this.size): ByteArray = TEA.encrypt(this, key.value, sourceLength = length)
|
fun ByteArray.encryptBy(key: DecrypterByteArray, length: Int = this.size): ByteArray = TEA.encrypt(this, key.value, sourceLength = length)
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过 [String.hexToBytes] 将 [keyHex] 转为 [ByteArray] 后用它解密 [this].
|
|
||||||
* 将会使用 [HexCache]
|
|
||||||
*
|
|
||||||
* @param keyHex 长度至少为 16 bytes
|
|
||||||
* @throws DecryptionFailedException 解密错误时
|
|
||||||
*/
|
|
||||||
fun ByteArray.encryptBy(keyHex: String, length: Int = this.size): ByteArray = encryptBy(keyHex.hexToBytes(withCache = true), length = length)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在 [ByteArrayPool] 缓存 [this], 然后使用 [key] 加密.
|
* 在 [ByteArrayPool] 缓存 [this], 然后使用 [key] 加密.
|
||||||
*
|
*
|
||||||
@ -83,15 +76,6 @@ fun ByteArray.decryptBy(key: IoBuffer, length: Int = this.size): ByteArray {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过 [String.hexToBytes] 将 [keyHex] 转为 [ByteArray] 后用它解密 [this]
|
|
||||||
* 将会使用 [HexCache]
|
|
||||||
*
|
|
||||||
* @param keyHex 长度至少为 16 bytes
|
|
||||||
* @throws DecryptionFailedException 解密错误时
|
|
||||||
*/
|
|
||||||
fun ByteArray.decryptBy(keyHex: String, length: Int = this.size): ByteArray = decryptBy(keyHex.hexToBytes(withCache = true), length = length)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在 [ByteArrayPool] 缓存 [this], 然后使用 [key] 解密.
|
* 在 [ByteArrayPool] 缓存 [this], 然后使用 [key] 解密.
|
||||||
*
|
*
|
||||||
@ -106,16 +90,6 @@ fun IoBuffer.decryptBy(key: ByteArray, offset: Int = 0, length: Int = readRemain
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 在 [ByteArrayPool] 缓存 [this], 然后使用 [keyHex] 解密.
|
|
||||||
*
|
|
||||||
* @param keyHex 长度至少为 16
|
|
||||||
* @throws DecryptionFailedException 解密错误时
|
|
||||||
*/
|
|
||||||
fun IoBuffer.decryptBy(keyHex: String, offset: Int = 0, length: Int = readRemaining - offset): ByteArray =
|
|
||||||
decryptBy(keyHex.hexToBytes(withCache = true), offset = offset, length = length)
|
|
||||||
|
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region ByteReadPacket extension
|
// region ByteReadPacket extension
|
||||||
@ -126,8 +100,6 @@ fun ByteReadPacket.decryptBy(key: IoBuffer): ByteReadPacket = decryptAsByteArray
|
|||||||
|
|
||||||
fun ByteReadPacket.decryptBy(key: Decrypter): ByteReadPacket = key.decrypt(this)
|
fun ByteReadPacket.decryptBy(key: Decrypter): ByteReadPacket = key.decrypt(this)
|
||||||
|
|
||||||
fun ByteReadPacket.decryptBy(keyHex: String): ByteReadPacket = decryptBy(keyHex.hexToBytes())
|
|
||||||
|
|
||||||
inline fun <R> ByteReadPacket.decryptAsByteArray(key: ByteArray, consumer: (ByteArray) -> R): R =
|
inline fun <R> ByteReadPacket.decryptAsByteArray(key: ByteArray, consumer: (ByteArray) -> R): R =
|
||||||
ByteArrayPool.useInstance {
|
ByteArrayPool.useInstance {
|
||||||
val length = remaining.toInt()
|
val length = remaining.toInt()
|
||||||
@ -135,9 +107,6 @@ inline fun <R> ByteReadPacket.decryptAsByteArray(key: ByteArray, consumer: (Byte
|
|||||||
consumer(it.decryptBy(key, length))
|
consumer(it.decryptBy(key, length))
|
||||||
}.also { close() }
|
}.also { close() }
|
||||||
|
|
||||||
inline fun <R> ByteReadPacket.decryptAsByteArray(keyHex: String, consumer: (ByteArray) -> R): R =
|
|
||||||
this.decryptAsByteArray(keyHex.hexToBytes(), consumer)
|
|
||||||
|
|
||||||
inline fun <R> ByteReadPacket.decryptAsByteArray(key: IoBuffer, consumer: (ByteArray) -> R): R =
|
inline fun <R> ByteReadPacket.decryptAsByteArray(key: IoBuffer, consumer: (ByteArray) -> R): R =
|
||||||
ByteArrayPool.useInstance {
|
ByteArrayPool.useInstance {
|
||||||
val length = remaining.toInt()
|
val length = remaining.toInt()
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
@file:Suppress("ObjectPropertyName", "MayBeConstant", "NonAsciiCharacters", "SpellCheckingInspection", "unused")
|
@file:Suppress("ObjectPropertyName", "MayBeConstant", "NonAsciiCharacters", "SpellCheckingInspection", "unused")
|
||||||
|
|
||||||
package net.mamoe.mirai.utils.io
|
package net.mamoe.mirai.utils.internal
|
||||||
|
|
||||||
import kotlinx.io.core.toByteArray
|
import kotlinx.io.core.toByteArray
|
||||||
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||||
|
import net.mamoe.mirai.utils.io.toUHexString
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 匹配已知 hex 常量并格式化后打印到控制台.
|
* 匹配已知 hex 常量并格式化后打印到控制台.
|
||||||
@ -19,7 +20,7 @@ internal fun String.printColorize(ignoreUntilFirstConst: Boolean): String = with
|
|||||||
*
|
*
|
||||||
* 低效率, 仅调试使用.
|
* 低效率, 仅调试使用.
|
||||||
*/
|
*/
|
||||||
internal fun printCompareHex(hex1s: String, hex2s: String): String = with(HexComparator) { compare(hex1s, hex2s) }
|
fun printCompareHex(hex1s: String, hex2s: String): String = with(HexComparator) { compare(hex1s.toUpperCase(), hex2s.toUpperCase()) }
|
||||||
|
|
||||||
data class NamedHexElement(
|
data class NamedHexElement(
|
||||||
val name: String,
|
val name: String,
|
||||||
@ -35,8 +36,8 @@ private fun LinkedHashSet<NamedHexElement>.initConstFileds() {
|
|||||||
TIMProtocol,
|
TIMProtocol,
|
||||||
PacketIds
|
PacketIds
|
||||||
).forEach { obj ->
|
).forEach { obj ->
|
||||||
obj::class.members.filterIsInstance<KProperty<*>>().forEach { property ->
|
obj::class.members.filterIsInstance<KProperty0<*>>().forEach { property ->
|
||||||
add(NamedHexElement(property.name, property.getter.call().toString()))
|
property.get()?.let { add(NamedHexElement(property.name, it.toString())) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,9 +108,14 @@ private object HexComparator {
|
|||||||
private class Match internal constructor(val range: IntRange, val constName: String)
|
private class Match internal constructor(val range: IntRange, val constName: String)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
TIMProtocol::class.members.filterIsInstance<KProperty<*>>().forEach {
|
CONST_FIELDS.forEach { (name, value) ->
|
||||||
for (match in match(hex, it.getter.call().toString())) {
|
for (match in match(hex, value)) {
|
||||||
matches.add(Match(match, it.getter.call().toString()))
|
matches.add(Match(match, name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TIMProtocol::class.members.filterIsInstance<KProperty0<*>>().mapNotNull { it()?.toString() }.forEach {
|
||||||
|
for (match in match(hex, it)) {
|
||||||
|
matches.add(Match(match, it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,10 +124,10 @@ private object HexComparator {
|
|||||||
val CONST_FIELDS: Set<NamedHexElement> = linkedSetOf<NamedHexElement>().apply { initConstFileds() }
|
val CONST_FIELDS: Set<NamedHexElement> = linkedSetOf<NamedHexElement>().apply { initConstFileds() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun match(hex: String, field: String): Set<IntRange> {
|
private fun match(hex: String, value: String): Set<IntRange> {
|
||||||
val constValue: String
|
val constValue: String
|
||||||
try {
|
try {
|
||||||
constValue = field.trim { it <= ' ' }
|
constValue = value.trim { it <= ' ' }
|
||||||
if (constValue.length / 3 <= 3) {//Minimum numbers of const hex bytes
|
if (constValue.length / 3 <= 3) {//Minimum numbers of const hex bytes
|
||||||
return linkedSetOf()
|
return linkedSetOf()
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package net.mamoe.mirai.utils.io
|
|||||||
import kotlinx.io.core.*
|
import kotlinx.io.core.*
|
||||||
import net.mamoe.mirai.utils.DefaultLogger
|
import net.mamoe.mirai.utils.DefaultLogger
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
|
import net.mamoe.mirai.utils.internal.printColorize
|
||||||
|
import net.mamoe.mirai.utils.internal.printCompareHex
|
||||||
|
|
||||||
|
|
||||||
internal object DebugLogger : MiraiLogger by DefaultLogger("Packet Debug")
|
internal object DebugLogger : MiraiLogger by DefaultLogger("Packet Debug")
|
||||||
@ -62,7 +64,7 @@ internal fun BytePacketBuilder.debugPrintThis(name: String = "") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun String.printStringFromHex() {
|
internal fun String.printStringFromHex() {
|
||||||
println(this.hexToBytes().stringOfWitch())
|
println(this.hexToBytes().encodeToString())
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ByteArray.printColorizedHex(name: String = "", ignoreUntilFirstConst: Boolean = false, compareTo: String? = null) {
|
internal fun ByteArray.printColorizedHex(name: String = "", ignoreUntilFirstConst: Boolean = false, compareTo: String? = null) {
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
package net.mamoe.mirai.utils.io
|
package net.mamoe.mirai.utils.io
|
||||||
|
|
||||||
import kotlinx.io.core.*
|
import kotlinx.io.core.*
|
||||||
|
import kotlinx.io.pool.useInstance
|
||||||
|
import kotlin.jvm.JvmName
|
||||||
|
|
||||||
|
|
||||||
fun ByteReadPacket.readRemainingBytes(
|
fun ByteReadPacket.readRemainingBytes(
|
||||||
@ -23,8 +25,12 @@ fun Input.readIP(): String = buildString(4 + 3) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Input.readUVarIntLVString(): String = String(this.readUVarIntByteArray())
|
||||||
|
|
||||||
fun Input.readUShortLVString(): String = String(this.readUShortLVByteArray())
|
fun Input.readUShortLVString(): String = String(this.readUShortLVByteArray())
|
||||||
|
|
||||||
|
fun Input.readUVarIntByteArray(): ByteArray = this.readBytes(this.readUVarInt().toInt())
|
||||||
|
|
||||||
fun Input.readUShortLVByteArray(): ByteArray = this.readBytes(this.readUShort().toInt())
|
fun Input.readUShortLVByteArray(): ByteArray = this.readBytes(this.readUShort().toInt())
|
||||||
|
|
||||||
private inline fun <R> inline(block: () -> R): R = block()
|
private inline fun <R> inline(block: () -> R): R = block()
|
||||||
@ -63,7 +69,33 @@ fun Input.readTLVMap(expectingEOF: Boolean = false, tagSize: Int = 1): MutableMa
|
|||||||
fun Map<*, ByteArray>.printTLVMap(name: String) =
|
fun Map<*, ByteArray>.printTLVMap(name: String) =
|
||||||
debugPrintln("TLVMap $name= " + this.mapValues { (_, value) -> value.toUHexString() })
|
debugPrintln("TLVMap $name= " + this.mapValues { (_, value) -> value.toUHexString() })
|
||||||
|
|
||||||
fun Input.readString(length: Number): String = String(this.readBytes(length.toInt()))
|
fun Input.readString(length: Int): String = String(this.readBytes(length))
|
||||||
|
fun Input.readString(length: Long): String = String(this.readBytes(length.toInt()))
|
||||||
|
fun Input.readString(length: Short): String = String(this.readBytes(length.toInt()))
|
||||||
|
fun Input.readString(length: UShort): String = String(this.readBytes(length.toInt()))
|
||||||
|
fun Input.readString(length: Byte): String = String(this.readBytes(length.toInt()))
|
||||||
|
|
||||||
|
fun Input.readStringUntil(stopSignalExclude: UByte, expectingEOF: Boolean = false): String = readStringUntil(stopSignalExclude.toByte(), expectingEOF)
|
||||||
|
|
||||||
|
// TODO 应标记 JvmSynthetic 但 kotlin 有bug
|
||||||
|
@JvmName("readStringUntil0")
|
||||||
|
fun Input.readStringUntil(stopSignalExclude: Byte, expectingEOF: Boolean = false): String {
|
||||||
|
ByteArrayPool.useInstance {
|
||||||
|
var count = 0
|
||||||
|
|
||||||
|
val buffer = byteArrayOf(1)
|
||||||
|
while (readAvailable(buffer, 1) == 1) {
|
||||||
|
if (buffer[0] == stopSignalExclude) {
|
||||||
|
return buffer.encodeToString()
|
||||||
|
}
|
||||||
|
it[count++] = buffer[0]
|
||||||
|
}
|
||||||
|
if (!expectingEOF) {
|
||||||
|
throw EOFException("Early EOF")
|
||||||
|
}
|
||||||
|
return buffer.encodeToString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private const val TRUE_BYTE_VALUE: Byte = 1
|
private const val TRUE_BYTE_VALUE: Byte = 1
|
||||||
fun Input.readBoolean(): Boolean = this.readByte() == TRUE_BYTE_VALUE
|
fun Input.readBoolean(): Boolean = this.readByte() == TRUE_BYTE_VALUE
|
||||||
|
@ -29,38 +29,33 @@ fun BytePacketBuilder.writeShortLVByteArray(byteArray: ByteArray) {
|
|||||||
this.writeFully(byteArray)
|
this.writeFully(byteArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun BytePacketBuilder.writeShortLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long)? = null, builder: BytePacketBuilder.() -> Unit) =
|
fun BytePacketBuilder.writeShortLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long)? = null, builder: BytePacketBuilder.() -> Unit) =
|
||||||
with(BytePacketBuilder().apply(builder).build()) {
|
BytePacketBuilder().apply(builder).build().use {
|
||||||
if (tag != null) {
|
if (tag != null) writeUByte(tag)
|
||||||
writeUByte(tag)
|
writeUShort((lengthOffset?.invoke(it.remaining) ?: it.remaining).coerceAtMostOrFail(0xFFFFL).toUShort())
|
||||||
}
|
writePacket(it)
|
||||||
writeUShort((lengthOffset?.invoke(remaining) ?: remaining).coerceAtMostOrFail(0xFFFFL).toUShort())
|
|
||||||
writePacket(this)
|
|
||||||
this.release()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun BytePacketBuilder.writeUVarintLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long)? = null, builder: BytePacketBuilder.() -> Unit) =
|
fun BytePacketBuilder.writeUVarIntLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long)? = null, builder: BytePacketBuilder.() -> Unit) =
|
||||||
with(BytePacketBuilder().apply(builder).build()) {
|
BytePacketBuilder().apply(builder).build().use {
|
||||||
if (tag != null) {
|
if (tag != null) writeUByte(tag)
|
||||||
writeUByte(tag)
|
writeUVarInt((lengthOffset?.invoke(it.remaining) ?: it.remaining).coerceAtMostOrFail(0xFFFFL))
|
||||||
}
|
writePacket(it)
|
||||||
writeUVarInt((lengthOffset?.invoke(remaining) ?: remaining).coerceAtMostOrFail(0xFFFFL))
|
|
||||||
writePacket(this)
|
|
||||||
this.release()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
fun BytePacketBuilder.writeShortLVString(str: String) = writeShortLVByteArray(str.toByteArray())
|
||||||
fun BytePacketBuilder.writeShortLVString(str: String) = this.writeShortLVByteArray(str.toByteArray())
|
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
fun BytePacketBuilder.writeLVHex(hex: String) = this.writeShortLVByteArray(hex.hexToBytes())
|
|
||||||
|
|
||||||
fun BytePacketBuilder.writeIP(ip: String) = writeFully(ip.trim().split(".").map { it.toUByte() }.toUByteArray())
|
fun BytePacketBuilder.writeIP(ip: String) = writeFully(ip.trim().split(".").map { it.toUByte() }.toUByteArray())
|
||||||
|
|
||||||
fun BytePacketBuilder.writeTime() = this.writeInt(currentTime.toInt())
|
fun BytePacketBuilder.writeTime() = this.writeInt(currentTime.toInt())
|
||||||
|
|
||||||
fun BytePacketBuilder.writeHex(uHex: String) = this.writeFully(uHex.hexToUBytes())
|
fun BytePacketBuilder.writeHex(uHex: String) {
|
||||||
|
uHex.split(" ").forEach {
|
||||||
|
if (it.isNotBlank()) {
|
||||||
|
writeUByte(it.toUByte(16))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun BytePacketBuilder.writeTLV(tag: UByte, values: UByteArray) {
|
fun BytePacketBuilder.writeTLV(tag: UByte, values: UByteArray) {
|
||||||
writeUByte(tag)
|
writeUByte(tag)
|
||||||
@ -81,6 +76,11 @@ fun BytePacketBuilder.writeTHex(tag: UByte, uHex: String) {
|
|||||||
|
|
||||||
fun BytePacketBuilder.writeTV(tagValue: UShort) = writeUShort(tagValue)
|
fun BytePacketBuilder.writeTV(tagValue: UShort) = writeUShort(tagValue)
|
||||||
|
|
||||||
|
fun BytePacketBuilder.writeTV(tag: UByte, value: UByte) {
|
||||||
|
writeUByte(tag)
|
||||||
|
writeUByte(value)
|
||||||
|
}
|
||||||
|
|
||||||
fun BytePacketBuilder.writeTUbyte(tag: UByte, value: UByte) {
|
fun BytePacketBuilder.writeTUbyte(tag: UByte, value: UByte) {
|
||||||
this.writeUByte(tag)
|
this.writeUByte(tag)
|
||||||
this.writeUByte(value)
|
this.writeUByte(value)
|
||||||
@ -124,7 +124,7 @@ fun BytePacketBuilder.writeTLV0006(qq: UInt, password: String, loginTime: Int, l
|
|||||||
writeRandom(4)
|
writeRandom(4)
|
||||||
writeHex("00 02")
|
writeHex("00 02")
|
||||||
writeQQ(qq)
|
writeQQ(qq)
|
||||||
writeHex(TIMProtocol.constantData2)
|
writeFully(TIMProtocol.constantData2)
|
||||||
writeHex("00 00 01")
|
writeHex("00 00 01")
|
||||||
|
|
||||||
writeFully(firstMD5)
|
writeFully(firstMD5)
|
||||||
@ -151,5 +151,5 @@ fun BytePacketBuilder.writeDeviceName(random: Boolean) {
|
|||||||
}
|
}
|
||||||
this.writeShort((deviceName.length + 2).toShort())
|
this.writeShort((deviceName.length + 2).toShort())
|
||||||
this.writeShort(deviceName.length.toShort())
|
this.writeShort(deviceName.length.toShort())
|
||||||
this.writeStringUtf8(deviceName)//TODO TEST?
|
this.writeStringUtf8(deviceName)
|
||||||
}
|
}
|
@ -5,7 +5,6 @@ package net.mamoe.mirai.utils.io
|
|||||||
import kotlinx.io.core.IoBuffer
|
import kotlinx.io.core.IoBuffer
|
||||||
import kotlinx.io.core.writeFully
|
import kotlinx.io.core.writeFully
|
||||||
import kotlinx.io.pool.ObjectPool
|
import kotlinx.io.pool.ObjectPool
|
||||||
import kotlin.jvm.Synchronized
|
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
import kotlin.random.nextInt
|
import kotlin.random.nextInt
|
||||||
|
|
||||||
@ -75,9 +74,8 @@ fun Byte.toUHexString(): String = this.toUByte().toString(16).toUpperCase().let
|
|||||||
/**
|
/**
|
||||||
* 将无符号 Hex 转为 [ByteArray], 有根据 hex 的 [hashCode] 建立的缓存.
|
* 将无符号 Hex 转为 [ByteArray], 有根据 hex 的 [hashCode] 建立的缓存.
|
||||||
*/
|
*/
|
||||||
fun String.hexToBytes(withCache: Boolean = true): ByteArray =
|
fun String.hexToBytes(): ByteArray =
|
||||||
if (withCache) HexCache.getCacheOrConvert(this)
|
this.split(" ")
|
||||||
else this.split(" ")
|
|
||||||
.filterNot { it.isEmpty() }
|
.filterNot { it.isEmpty() }
|
||||||
.map { s -> s.toUByte(16).toByte() }
|
.map { s -> s.toUByte(16).toByte() }
|
||||||
.toByteArray()
|
.toByteArray()
|
||||||
@ -85,9 +83,8 @@ fun String.hexToBytes(withCache: Boolean = true): ByteArray =
|
|||||||
/**
|
/**
|
||||||
* 将无符号 Hex 转为 [UByteArray], 有根据 hex 的 [hashCode] 建立的缓存.
|
* 将无符号 Hex 转为 [UByteArray], 有根据 hex 的 [hashCode] 建立的缓存.
|
||||||
*/
|
*/
|
||||||
fun String.hexToUBytes(withCache: Boolean = true): UByteArray =
|
fun String.hexToUBytes(): UByteArray =
|
||||||
if (withCache) HexCache.getUCacheOrConvert(this)
|
this.split(" ")
|
||||||
else this.split(" ")
|
|
||||||
.filterNot { it.isEmpty() }
|
.filterNot { it.isEmpty() }
|
||||||
.map { s -> s.toUByte(16) }
|
.map { s -> s.toUByte(16) }
|
||||||
.toUByteArray()
|
.toUByteArray()
|
||||||
@ -130,37 +127,3 @@ fun ByteArray.toUInt(): UInt =
|
|||||||
* 注意回收 ([ObjectPool.recycle])
|
* 注意回收 ([ObjectPool.recycle])
|
||||||
*/
|
*/
|
||||||
fun ByteArray.toIoBuffer(): IoBuffer = IoBuffer.Pool.borrow().let { it.writeFully(this); it }
|
fun ByteArray.toIoBuffer(): IoBuffer = IoBuffer.Pool.borrow().let { it.writeFully(this); it }
|
||||||
|
|
||||||
/**
|
|
||||||
* Hex 转换 [ByteArray] 和 [UByteArray] 缓存.
|
|
||||||
* 为 [net.mamoe.mirai.network.protocol.tim.TIMProtocol] 的 hex 常量使用
|
|
||||||
*/
|
|
||||||
internal object HexCache {
|
|
||||||
private val hexToByteArrayCacheMap: MutableMap<Int, ByteArray> = mutableMapOf()
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
internal fun getCacheOrConvert(hex: String): ByteArray = hex.hashCode().let { id ->
|
|
||||||
if (hexToByteArrayCacheMap.containsKey(id)) {
|
|
||||||
return hexToByteArrayCacheMap[id]!!
|
|
||||||
} else {
|
|
||||||
hex.hexToBytes(withCache = false).let {
|
|
||||||
hexToByteArrayCacheMap[id] = it
|
|
||||||
return it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val hexToUByteArrayCacheMap: MutableMap<Int, UByteArray> = mutableMapOf()
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
internal fun getUCacheOrConvert(hex: String): UByteArray = hex.hashCode().let { id ->
|
|
||||||
if (hexToUByteArrayCacheMap.containsKey(id)) {
|
|
||||||
return hexToUByteArrayCacheMap[id]!!
|
|
||||||
} else {
|
|
||||||
hex.hexToUBytes(withCache = false).let {
|
|
||||||
hexToUByteArrayCacheMap[id] = it
|
|
||||||
return it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +1,13 @@
|
|||||||
@file:JvmName("Varint")
|
@file:JvmName("Varint")
|
||||||
@file:Suppress("EXPERIMENTAL_API_USAGE")
|
@file:Suppress("EXPERIMENTAL_API_USAGE")
|
||||||
|
|
||||||
package net.mamoe.mirai.utils
|
package net.mamoe.mirai.utils.io
|
||||||
|
|
||||||
import kotlinx.io.core.BytePacketBuilder
|
import kotlinx.io.core.Input
|
||||||
import kotlinx.io.core.ByteReadPacket
|
import kotlinx.io.core.Output
|
||||||
import kotlin.experimental.or
|
import kotlin.experimental.or
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
|
import kotlin.jvm.JvmSynthetic
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tool class for VarInt or VarLong operations.
|
* Tool class for VarInt or VarLong operations.
|
||||||
@ -17,70 +18,72 @@ import kotlin.jvm.JvmName
|
|||||||
* @author lmlstarqaq of Nukkit Project
|
* @author lmlstarqaq of Nukkit Project
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fun encodeZigZag32(signedInt: Int): Long {
|
internal fun encodeZigZag32(signedInt: Int): Long {
|
||||||
return (signedInt shl 1 xor (signedInt shr 31)).toLong()
|
return (signedInt shl 1 xor (signedInt shr 31)).toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmSynthetic
|
||||||
//@JvmSynthetic
|
internal fun decodeZigZag32(uint: UInt): Int {
|
||||||
fun decodeZigZag32(uint: UInt): Int {
|
|
||||||
return decodeZigZag32(uint.toLong())
|
return decodeZigZag32(uint.toLong())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun decodeZigZag32(uint: Long): Int {
|
internal fun decodeZigZag32(uint: Long): Int {
|
||||||
return (uint shr 1).toInt() xor -(uint and 1).toInt()
|
return (uint shr 1).toInt() xor -(uint and 1).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun encodeZigZag64(signedLong: Long): Long {
|
internal fun encodeZigZag64(signedLong: Long): Long {
|
||||||
return signedLong shl 1 xor (signedLong shr 63)
|
return signedLong shl 1 xor (signedLong shr 63)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun decodeZigZag64(signedLong: Long): Long {
|
internal fun decodeZigZag64(signedLong: Long): Long {
|
||||||
return signedLong.ushr(1) xor -(signedLong and 1)
|
return signedLong.ushr(1) xor -(signedLong and 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun ByteReadPacket.readVarInt(): Int {
|
fun Input.readVarInt(): Int {
|
||||||
return decodeZigZag32(this.readUnsignedVarInt())
|
return decodeZigZag32(this.readUVarInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun ByteReadPacket.readUnsignedVarInt(): UInt {
|
@JvmSynthetic
|
||||||
|
fun Input.readUVarInt(): UInt {
|
||||||
return read(this, 5).toUInt()
|
return read(this, 5).toUInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun ByteReadPacket.readVarLong(): Long {
|
fun Input.readVarLong(): Long {
|
||||||
return decodeZigZag64(readUnsignedVarLong().toLong())
|
return decodeZigZag64(readUVarLong().toLong())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun ByteReadPacket.readUnsignedVarLong(): ULong {
|
@JvmSynthetic
|
||||||
|
fun Input.readUVarLong(): ULong {
|
||||||
return read(this, 10).toULong()
|
return read(this, 10).toULong()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun BytePacketBuilder.writeVarInt(signedInt: Int) {
|
fun Output.writeVarInt(signedInt: Int) {
|
||||||
this.writeUVarInt(encodeZigZag32(signedInt))
|
this.writeUVarInt(encodeZigZag32(signedInt))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun BytePacketBuilder.writeUVarInt(uint: UInt) {
|
@JvmSynthetic
|
||||||
|
fun Output.writeUVarInt(uint: UInt) {
|
||||||
return writeUVarInt(uint.toLong())
|
return writeUVarInt(uint.toLong())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun BytePacketBuilder.writeUVarInt(uint: Long) {
|
fun Output.writeUVarInt(uint: Long) {
|
||||||
this.write0(uint)
|
this.write0(uint)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun BytePacketBuilder.writeVarLong(signedLong: Long) {
|
fun Output.writeVarLong(signedLong: Long) {
|
||||||
this.writeUVarLong(encodeZigZag64(signedLong))
|
this.writeUVarLong(encodeZigZag64(signedLong))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun BytePacketBuilder.writeUVarLong(ulong: Long) {
|
fun Output.writeUVarLong(ulong: Long) {
|
||||||
this.write0(ulong)
|
this.write0(ulong)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun BytePacketBuilder.write0(long: Long) {
|
private fun Output.write0(long: Long) {
|
||||||
var value = long
|
var value = long
|
||||||
do {
|
do {
|
||||||
var temp = (value and 127).toByte()
|
var temp = (value and 127).toByte()
|
||||||
@ -92,7 +95,7 @@ private fun BytePacketBuilder.write0(long: Long) {
|
|||||||
} while (value != 0L)
|
} while (value != 0L)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun read(stream: ByteReadPacket, maxSize: Int): Long {
|
private fun read(stream: Input, maxSize: Int): Long {
|
||||||
var value: Long = 0
|
var value: Long = 0
|
||||||
var size = 0
|
var size = 0
|
||||||
var b = stream.readByte().toInt()
|
var b = stream.readByte().toInt()
|
||||||
|
Loading…
Reference in New Issue
Block a user