2020-02-09 01:01:36 +08:00
|
|
|
/*
|
2021-04-10 18:43:47 +08:00
|
|
|
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
2020-02-09 01:01:36 +08:00
|
|
|
*
|
2020-11-01 15:07:32 +08:00
|
|
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
|
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
2020-02-09 01:01:36 +08:00
|
|
|
*
|
2020-11-01 15:07:32 +08:00
|
|
|
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
2020-02-09 01:01:36 +08:00
|
|
|
*/
|
|
|
|
|
2020-02-06 13:58:57 +08:00
|
|
|
@file:JvmMultifileClass
|
2020-12-26 20:05:10 +08:00
|
|
|
@file:JvmName("MiraiUtils")
|
2019-10-13 20:19:54 +08:00
|
|
|
|
2020-12-26 20:05:10 +08:00
|
|
|
@file:Suppress("NOTHING_TO_INLINE")
|
2019-10-13 20:19:54 +08:00
|
|
|
|
2020-12-26 20:05:10 +08:00
|
|
|
package net.mamoe.mirai.utils
|
|
|
|
|
|
|
|
import io.ktor.utils.io.charsets.*
|
2020-03-08 00:24:49 +08:00
|
|
|
import kotlinx.io.core.*
|
2021-02-06 22:52:41 +08:00
|
|
|
import java.io.File
|
2020-12-26 20:05:10 +08:00
|
|
|
import kotlin.text.Charsets
|
|
|
|
|
2021-04-16 08:30:05 +08:00
|
|
|
public val EMPTY_BYTE_ARRAY: ByteArray = ByteArray(0)
|
|
|
|
|
2021-04-14 23:23:24 +08:00
|
|
|
public val DECRYPTER_16_ZERO: ByteArray = ByteArray(16)
|
2021-04-16 08:30:05 +08:00
|
|
|
public val KEY_16_ZEROS: ByteArray = ByteArray(16)
|
2019-12-19 17:25:49 +08:00
|
|
|
|
2020-05-02 17:58:22 +08:00
|
|
|
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
2020-12-26 20:05:10 +08:00
|
|
|
public inline fun <R> ByteReadPacket.useBytes(
|
2020-01-29 19:54:09 +08:00
|
|
|
n: Int = remaining.toInt(),//not that safe but adequate
|
|
|
|
block: (data: ByteArray, length: Int) -> R
|
2020-04-08 13:50:48 +08:00
|
|
|
): R = ByteArrayPool.useInstance(n) {
|
2020-01-29 19:54:09 +08:00
|
|
|
this.readFully(it, 0, n)
|
|
|
|
block(it, n)
|
|
|
|
}
|
|
|
|
|
2020-12-26 20:05:10 +08:00
|
|
|
public inline fun ByteReadPacket.readPacketExact(
|
2020-01-31 15:05:02 +08:00
|
|
|
n: Int = remaining.toInt()//not that safe but adequate
|
|
|
|
): ByteReadPacket = this.readBytes(n).toReadPacket()
|
|
|
|
|
2019-10-13 20:19:54 +08:00
|
|
|
|
2020-12-26 20:05:10 +08:00
|
|
|
public typealias TlvMap = MutableMap<Int, ByteArray>
|
2020-01-29 19:17:13 +08:00
|
|
|
|
2020-12-26 20:05:10 +08:00
|
|
|
public inline fun TlvMap.getOrFail(tag: Int): ByteArray {
|
2020-12-26 17:45:30 +08:00
|
|
|
return this[tag] ?: error("cannot find tlv 0x${tag.toUHexString("")}($tag)")
|
2020-01-29 19:17:13 +08:00
|
|
|
}
|
|
|
|
|
2020-12-26 20:05:10 +08:00
|
|
|
public inline fun TlvMap.getOrFail(tag: Int, lazyMessage: (tag: Int) -> String): ByteArray {
|
2020-01-29 19:54:09 +08:00
|
|
|
return this[tag] ?: error(lazyMessage(tag))
|
2020-01-29 19:17:13 +08:00
|
|
|
}
|
|
|
|
|
2020-02-28 19:16:22 +08:00
|
|
|
@Suppress("FunctionName")
|
2020-12-26 20:05:10 +08:00
|
|
|
public inline fun Input._readTLVMap(tagSize: Int = 2, suppressDuplication: Boolean = true): TlvMap =
|
2020-03-01 16:55:33 +08:00
|
|
|
_readTLVMap(true, tagSize, suppressDuplication)
|
2020-01-10 22:49:48 +08:00
|
|
|
|
2020-02-28 19:16:22 +08:00
|
|
|
@Suppress("DuplicatedCode", "FunctionName")
|
2020-12-26 20:05:10 +08:00
|
|
|
public fun Input._readTLVMap(
|
2020-12-26 17:45:30 +08:00
|
|
|
expectingEOF: Boolean = true,
|
|
|
|
tagSize: Int,
|
|
|
|
suppressDuplication: Boolean = true
|
|
|
|
): TlvMap {
|
2020-01-10 22:49:48 +08:00
|
|
|
val map = mutableMapOf<Int, ByteArray>()
|
2020-01-11 15:30:19 +08:00
|
|
|
var key = 0
|
2019-10-13 20:19:54 +08:00
|
|
|
|
2020-12-26 20:05:10 +08:00
|
|
|
while (kotlin.run {
|
2019-11-02 18:29:33 +08:00
|
|
|
try {
|
2020-01-11 15:30:19 +08:00
|
|
|
key = when (tagSize) {
|
|
|
|
1 -> readUByte().toInt()
|
|
|
|
2 -> readUShort().toInt()
|
|
|
|
4 -> readUInt().toInt()
|
2019-11-02 18:29:33 +08:00
|
|
|
else -> error("Unsupported tag size: $tagSize")
|
|
|
|
}
|
2019-12-15 15:53:29 +08:00
|
|
|
} catch (e: Exception) { // java.nio.BufferUnderflowException is not a EOFException...
|
2019-11-02 18:29:33 +08:00
|
|
|
if (expectingEOF) {
|
|
|
|
return map
|
|
|
|
}
|
|
|
|
throw e
|
2019-10-13 20:19:54 +08:00
|
|
|
}
|
2020-01-11 15:30:19 +08:00
|
|
|
key
|
2019-11-02 18:29:33 +08:00
|
|
|
}.toUByte() != UByte.MAX_VALUE) {
|
|
|
|
|
2020-01-11 15:30:19 +08:00
|
|
|
if (map.containsKey(key)) {
|
2020-02-28 19:16:22 +08:00
|
|
|
@Suppress("ControlFlowWithEmptyBody")
|
2020-02-06 13:58:57 +08:00
|
|
|
if (!suppressDuplication) {
|
2020-02-28 19:16:22 +08:00
|
|
|
/*
|
|
|
|
@Suppress("DEPRECATION")
|
|
|
|
MiraiLogger.error(
|
2020-02-06 13:58:57 +08:00
|
|
|
@Suppress("IMPLICIT_CAST_TO_ANY")
|
|
|
|
"""
|
2020-02-28 19:16:22 +08:00
|
|
|
Error readTLVMap:
|
2020-01-11 15:30:19 +08:00
|
|
|
duplicated key ${when (tagSize) {
|
2020-02-06 13:58:57 +08:00
|
|
|
1 -> key.toByte()
|
|
|
|
2 -> key.toShort()
|
|
|
|
4 -> key
|
|
|
|
else -> error("unreachable")
|
|
|
|
}.contentToString()}
|
2020-01-11 15:30:19 +08:00
|
|
|
map=${map.contentToString()}
|
|
|
|
duplicating value=${this.readUShortLVByteArray().toUHexString()}
|
|
|
|
""".trimIndent()
|
2020-02-28 19:16:22 +08:00
|
|
|
)*/
|
2020-02-06 15:32:33 +08:00
|
|
|
} else {
|
|
|
|
this.discardExact(this.readShort().toInt() and 0xffff)
|
2020-02-06 13:58:57 +08:00
|
|
|
}
|
2020-01-11 15:30:19 +08:00
|
|
|
} else {
|
|
|
|
try {
|
2020-02-28 19:16:22 +08:00
|
|
|
map[key] = this.readBytes(readUShort().toInt())
|
2020-01-11 15:30:19 +08:00
|
|
|
} catch (e: Exception) { // BufferUnderflowException, java.io.EOFException
|
|
|
|
// if (expectingEOF) {
|
|
|
|
// return map
|
|
|
|
// }
|
|
|
|
throw e
|
2019-11-20 19:15:11 +08:00
|
|
|
}
|
|
|
|
}
|
2019-10-13 20:19:54 +08:00
|
|
|
}
|
|
|
|
return map
|
|
|
|
}
|
|
|
|
|
2020-12-26 20:05:10 +08:00
|
|
|
public inline fun Input.readString(length: Int, charset: Charset = Charsets.UTF_8): String =
|
2020-03-01 16:55:33 +08:00
|
|
|
String(this.readBytes(length), charset = charset)
|
|
|
|
|
2020-12-26 20:05:10 +08:00
|
|
|
public inline fun Input.readString(length: Long, charset: Charset = Charsets.UTF_8): String =
|
2020-03-01 16:55:33 +08:00
|
|
|
String(this.readBytes(length.toInt()), charset = charset)
|
|
|
|
|
2020-12-26 20:05:10 +08:00
|
|
|
public inline fun Input.readString(length: Short, charset: Charset = Charsets.UTF_8): String =
|
2020-03-01 16:55:33 +08:00
|
|
|
String(this.readBytes(length.toInt()), charset = charset)
|
|
|
|
|
2019-11-27 12:31:30 +08:00
|
|
|
@JvmSynthetic
|
2020-12-26 20:05:10 +08:00
|
|
|
public inline fun Input.readString(length: UShort, charset: Charset = Charsets.UTF_8): String =
|
2020-03-01 16:55:33 +08:00
|
|
|
String(this.readBytes(length.toInt()), charset = charset)
|
2019-11-27 23:14:34 +08:00
|
|
|
|
2020-12-26 20:05:10 +08:00
|
|
|
public inline fun Input.readString(length: Byte, charset: Charset = Charsets.UTF_8): String =
|
2021-02-06 22:52:41 +08:00
|
|
|
String(this.readBytes(length.toInt()), charset = charset)
|
|
|
|
|
2021-04-10 18:43:47 +08:00
|
|
|
public fun Input.readUShortLVString(): String = String(this.readUShortLVByteArray())
|
|
|
|
public fun Input.readUShortLVByteArray(): ByteArray = this.readBytes(this.readUShort().toInt())
|
|
|
|
|
2021-02-06 22:52:41 +08:00
|
|
|
public fun File.createFileIfNotExists() {
|
|
|
|
if (!this.exists()) {
|
|
|
|
this.parentFile.mkdirs()
|
|
|
|
this.createNewFile()
|
|
|
|
}
|
2021-02-10 15:20:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public fun File.resolveCreateFile(relative: String): File = this.resolve(relative).apply { createFileIfNotExists() }
|
|
|
|
public fun File.resolveCreateFile(relative: File): File = this.resolve(relative).apply { createFileIfNotExists() }
|
|
|
|
|
|
|
|
public fun File.resolveMkdir(relative: String): File = this.resolve(relative).apply { mkdirs() }
|
|
|
|
public fun File.resolveMkdir(relative: File): File = this.resolve(relative).apply { mkdirs() }
|