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 {
}.cleanupRubbishMessageElements()
}
// These two functions are not identical, dont combine.
// These two functions have difference method signature, don't combine.
@OptIn(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class)
internal fun ImMsgBody.SourceMsg.toMessageChain(): MessageChain {
val elements = this.elems!!
......@@ -218,6 +219,7 @@ internal inline fun <reified R> Iterable<*>.firstIsInstance(): R {
@OptIn(MiraiInternalAPI::class, LowLevelAPI::class)
internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MessageChainBuilder) {
// (this._miraiContentToString())
this.forEach {
when {
it.srcMsg != null -> message.add(QuoteReply(MessageSourceFromServer(it.srcMsg)))
......@@ -277,7 +279,7 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MessageChainBuilde
}
}
else -> {
println(it._miraiContentToString())
// println(it._miraiContentToString())
}
}
}
......
......@@ -21,7 +21,6 @@ import net.mamoe.mirai.BotImpl
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.io.chunkedHexToBytes
import kotlin.js.JsName
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
......@@ -52,9 +51,9 @@ interface Image : Message, MessageContent {
@Suppress("FunctionName")
@JsName("newImage")
@JvmName("newImage")
fun Image(imageId: String): Image = when (imageId.length) {
54, 37 -> OfflineFriendImage(imageId) // /f8f1ab55-bf8e-4236-b55e-955848d7069f
42 -> OfflineGroupImage(imageId) // {01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.png
fun Image(imageId: String): Image = when {
imageId.startsWith('/') -> OfflineFriendImage(imageId) // /f8f1ab55-bf8e-4236-b55e-955848d7069f
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}")
}
......@@ -272,21 +271,71 @@ abstract class OnlineFriendImage : FriendImage(), OnlineImage
private val EMPTY_BYTE_ARRAY = ByteArray(0)
private fun calculateImageMd5ByImageId(imageId: String): ByteArray {
return if (imageId.startsWith('/')) {
imageId
.drop(1)
.replace("-", "")
.take(16 * 2)
.chunkedHexToBytes()
// /000000000-3814297509-BFB7027B9354B8F899A062061D74E206
private val FRIEND_IMAGE_ID_REGEX_1 = Regex("""/[0-9]*-[0-9]*-[0-9a-zA-Z]{32}""")
// /f8f1ab55-bf8e-4236-b55e-955848d7069f
private val FRIEND_IMAGE_ID_REGEX_2 = Regex("""/.{8}-(.{4}-){3}.{12}""")
// {01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.png
private val GROUP_IMAGE_ID_REGEX = Regex("""\{.{8}-(.{4}-){3}.{12}}\..*""")
@Suppress("NOTHING_TO_INLINE") // no stack waste
internal inline fun Char.hexDigitToByte(): Int {
return when (this) {
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 {
imageId
.substringAfter('{')
.substringBefore('}')
.replace("-", "")
.take(16 * 2)
.chunkedHexToBytes()
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
\ 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