Commit 90b83afc authored by Him188's avatar Him188

Fix #165, use fast conversion, add tests

parent d3db5f1c
...@@ -173,7 +173,8 @@ internal fun MsgComm.Msg.toMessageChain(): MessageChain { ...@@ -173,7 +173,8 @@ internal fun MsgComm.Msg.toMessageChain(): MessageChain {
}.cleanupRubbishMessageElements() }.cleanupRubbishMessageElements()
} }
// These two functions are not identical, dont combine. // These two functions have difference method signature, don't combine.
@OptIn(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class) @OptIn(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class)
internal fun ImMsgBody.SourceMsg.toMessageChain(): MessageChain { internal fun ImMsgBody.SourceMsg.toMessageChain(): MessageChain {
val elements = this.elems!! val elements = this.elems!!
...@@ -218,6 +219,7 @@ internal inline fun <reified R> Iterable<*>.firstIsInstance(): R { ...@@ -218,6 +219,7 @@ internal inline fun <reified R> Iterable<*>.firstIsInstance(): R {
@OptIn(MiraiInternalAPI::class, LowLevelAPI::class) @OptIn(MiraiInternalAPI::class, LowLevelAPI::class)
internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MessageChainBuilder) { internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MessageChainBuilder) {
// (this._miraiContentToString())
this.forEach { this.forEach {
when { when {
it.srcMsg != null -> message.add(QuoteReply(MessageSourceFromServer(it.srcMsg))) it.srcMsg != null -> message.add(QuoteReply(MessageSourceFromServer(it.srcMsg)))
...@@ -277,7 +279,7 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MessageChainBuilde ...@@ -277,7 +279,7 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MessageChainBuilde
} }
} }
else -> { else -> {
println(it._miraiContentToString()) // println(it._miraiContentToString())
} }
} }
} }
......
...@@ -21,7 +21,6 @@ import net.mamoe.mirai.BotImpl ...@@ -21,7 +21,6 @@ import net.mamoe.mirai.BotImpl
import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.io.chunkedHexToBytes
import kotlin.js.JsName import kotlin.js.JsName
import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
...@@ -52,9 +51,9 @@ interface Image : Message, MessageContent { ...@@ -52,9 +51,9 @@ interface Image : Message, MessageContent {
@Suppress("FunctionName") @Suppress("FunctionName")
@JsName("newImage") @JsName("newImage")
@JvmName("newImage") @JvmName("newImage")
fun Image(imageId: String): Image = when (imageId.length) { fun Image(imageId: String): Image = when {
54, 37 -> OfflineFriendImage(imageId) // /f8f1ab55-bf8e-4236-b55e-955848d7069f imageId.startsWith('/') -> OfflineFriendImage(imageId) // /f8f1ab55-bf8e-4236-b55e-955848d7069f
42 -> OfflineGroupImage(imageId) // {01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.png imageId.length == 42 || imageId.startsWith('{') && imageId.endsWith('}') -> OfflineGroupImage(imageId) // {01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.png
else -> throw IllegalArgumentException("Bad imageId, expecting length=37 or 42, got ${imageId.length}") else -> throw IllegalArgumentException("Bad imageId, expecting length=37 or 42, got ${imageId.length}")
} }
...@@ -272,21 +271,71 @@ abstract class OnlineFriendImage : FriendImage(), OnlineImage ...@@ -272,21 +271,71 @@ abstract class OnlineFriendImage : FriendImage(), OnlineImage
private val EMPTY_BYTE_ARRAY = ByteArray(0) private val EMPTY_BYTE_ARRAY = ByteArray(0)
private fun calculateImageMd5ByImageId(imageId: String): ByteArray {
return if (imageId.startsWith('/')) { // /000000000-3814297509-BFB7027B9354B8F899A062061D74E206
imageId private val FRIEND_IMAGE_ID_REGEX_1 = Regex("""/[0-9]*-[0-9]*-[0-9a-zA-Z]{32}""")
.drop(1)
.replace("-", "") // /f8f1ab55-bf8e-4236-b55e-955848d7069f
.take(16 * 2) private val FRIEND_IMAGE_ID_REGEX_2 = Regex("""/.{8}-(.{4}-){3}.{12}""")
.chunkedHexToBytes()
} else { // {01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.png
imageId private val GROUP_IMAGE_ID_REGEX = Regex("""\{.{8}-(.{4}-){3}.{12}}\..*""")
.substringAfter('{')
.substringBefore('}') @Suppress("NOTHING_TO_INLINE") // no stack waste
.replace("-", "") internal inline fun Char.hexDigitToByte(): Int {
.take(16 * 2) return when (this) {
.chunkedHexToBytes() in '0'..'9' -> this - '0'
in 'A'..'F' -> 10 + (this - 'A')
in 'a'..'f' -> 10 + (this - 'a')
else -> throw IllegalArgumentException("illegal hex digit: $this")
} }
} }
internal fun String.skipToSecondHyphen(): Int {
var count = 0
this.forEachIndexed { index, c ->
if (c == '-' && ++count == 2) return index
}
error("cannot find two hyphens")
}
internal fun String.imageIdToMd5(offset: Int): ByteArray {
val result = ByteArray(16)
var cur = 0
var hasCurrent = false
var lastChar: Char = 0.toChar()
for (index in offset..this.lastIndex) {
val char = this[index]
if (char == '-') continue
if (hasCurrent) {
result[cur++] = (lastChar.hexDigitToByte().shl(4) or char.hexDigitToByte()).toByte()
if (cur == 16) return result
hasCurrent = false
} else {
lastChar = char
hasCurrent = true
}
}
error("No enough chars")
}
@OptIn(ExperimentalStdlibApi::class)
internal fun calculateImageMd5ByImageId(imageId: String): ByteArray {
return when {
imageId.matches(FRIEND_IMAGE_ID_REGEX_1) -> imageId.imageIdToMd5(imageId.skipToSecondHyphen() + 1)
imageId.matches(FRIEND_IMAGE_ID_REGEX_2) ->
imageId.imageIdToMd5(1)
imageId.matches(GROUP_IMAGE_ID_REGEX) -> {
imageId.imageIdToMd5(1)
}
else -> error(
"illegal imageId: $imageId. " +
"ImageId must matches Regex `${FRIEND_IMAGE_ID_REGEX_1.pattern}`, " +
"`${FRIEND_IMAGE_ID_REGEX_2.pattern}` or " +
"`${GROUP_IMAGE_ID_REGEX.pattern}`"
)
}
}
// endregion // endregion
\ No newline at end of file
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 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.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.message.data
import net.mamoe.mirai.utils.io.autoHexToBytes
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
internal class ImageTest {
@Test
fun testHexDigitToByte() {
assertEquals(0xf, 'f'.hexDigitToByte())
assertEquals(0x1, '1'.hexDigitToByte())
assertEquals(0x0, '0'.hexDigitToByte())
assertFailsWith<IllegalArgumentException> {
'g'.hexDigitToByte()
}
}
@Test
fun testCalculateImageMd5ByImageId() {
assertEquals(
"01E9451B-70ED-EAE3-B37C-101F1EEBF5B5".filterNot { it == '-' }.autoHexToBytes().contentToString(),
calculateImageMd5ByImageId("{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.png").contentToString()
)
assertEquals(
"f8f1ab55-bf8e-4236-b55e-955848d7069f".filterNot { it == '-' }.autoHexToBytes().contentToString(),
calculateImageMd5ByImageId("/f8f1ab55-bf8e-4236-b55e-955848d7069f").contentToString()
)
assertEquals(
"BFB7027B9354B8F899A062061D74E206".filterNot { it == '-' }.autoHexToBytes().contentToString(),
calculateImageMd5ByImageId("/000000000-3814297509-BFB7027B9354B8F899A062061D74E206").contentToString()
)
}
// `/f8f1ab55-bf8e-4236-b55e-955848d7069f` 或 `/000000000-3814297509-BFB7027B9354B8F899A062061D74E206`
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment