diff --git a/buildSrc/src/main/kotlin/HmppConfigure.kt b/buildSrc/src/main/kotlin/HmppConfigure.kt index 1aa70c98b..35c2903c7 100644 --- a/buildSrc/src/main/kotlin/HmppConfigure.kt +++ b/buildSrc/src/main/kotlin/HmppConfigure.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget +import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType import java.io.File private val miraiPlatform = Attribute.of( @@ -133,7 +134,8 @@ private fun Project.configureNativeInterop( nativeTargets: MutableList<KotlinNativeTarget> ) { if (nativeInteropDir.exists() && nativeInteropDir.isDirectory && nativeInteropDir.resolve("build.rs").exists()) { - val crateName = project.name.replace("-", "_") + val crateName = project.name.replace("-", "_") + "_i" + val kotlinDylibName = project.name.replace("-", "_") val headerName = "$crateName.h" val rustLibDir = nativeInteropDir.resolve("target/debug/") @@ -149,10 +151,16 @@ private fun Project.configureNativeInterop( sharedLib { linkerOpts("-v") linkerOpts("-L${rustLibDir.absolutePath.replace("\\", "/")}") -// linkerOpts("-lmyrust") - linkerOpts("-Wl,-undefined,dynamic_lookup") // resolve symbols in runtime +// linkerOpts("-lmirai_core_utils_i") + linkerOpts("-undefined", "dynamic_lookup") baseName = project.name } + getTest(NativeBuildType.DEBUG).apply { + linkerOpts("-v") + linkerOpts("-L${rustLibDir.absolutePath.replace("\\", "/")}") + linkerOpts("-lmirai_core_utils_i") +// linkerOpts("-undefined", "dynamic_lookup") + } } } @@ -190,7 +198,7 @@ private fun Project.configureNativeInterop( val bindgen = tasks.register("bindgen${compilationName.titlecase()}") { group = "mirai" val bindingsPath = nativeInteropDir.resolve("src/bindings.rs") - val headerFile = buildDir.resolve("bin/native/debugShared/lib${crateName}_api.h") + val headerFile = buildDir.resolve("bin/native/debugShared/lib${kotlinDylibName}_api.h") inputs.files(headerFile) outputs.file(bindingsPath) mustRunAfter(tasks.findByName("linkDebugSharedNative")) @@ -239,7 +247,7 @@ private fun Project.configureNativeInterop( "build", "--color", "always", "--all", - "--", "--color", "always", "2>&1" +// "--", "--color", "always", "2>&1" ) } } diff --git a/mirai-core-utils/src/commonMain/kotlin/MiraiPlatformUtils.kt b/mirai-core-utils/src/commonMain/kotlin/ByteArrayOp.kt similarity index 51% rename from mirai-core-utils/src/commonMain/kotlin/MiraiPlatformUtils.kt rename to mirai-core-utils/src/commonMain/kotlin/ByteArrayOp.kt index a30105971..5c7fc7aaa 100644 --- a/mirai-core-utils/src/commonMain/kotlin/MiraiPlatformUtils.kt +++ b/mirai-core-utils/src/commonMain/kotlin/ByteArrayOp.kt @@ -7,28 +7,15 @@ * https://github.com/mamoe/mirai/blob/dev/LICENSE */ -@file:JvmMultifileClass -@file:JvmName("MiraiUtils") +@file:JvmName("ByteArrayOpKt_common") package net.mamoe.mirai.utils import io.ktor.utils.io.core.* -import io.ktor.utils.io.core.Closeable -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmName public expect val DEFAULT_BUFFER_SIZE: Int -public expect fun ByteArray.unzip(offset: Int = 0, length: Int = size - offset): ByteArray - - -/** - * Localhost 解析 - */ -public expect fun localIpAddress(): String - public fun String.md5(): ByteArray = toByteArray().md5() public expect fun ByteArray.md5(offset: Int = 0, length: Int = size - offset): ByteArray @@ -37,24 +24,8 @@ public fun String.sha1(): ByteArray = toByteArray().sha1() public expect fun ByteArray.sha1(offset: Int = 0, length: Int = size - offset): ByteArray +public expect fun ByteArray.gzip(offset: Int = 0, length: Int = size - offset): ByteArray public expect fun ByteArray.ungzip(offset: Int = 0, length: Int = size - offset): ByteArray -public expect fun ByteArray.gzip(offset: Int = 0, length: Int = size - offset): ByteArray - -public expect fun ByteArray.zip(offset: Int = 0, length: Int = size - offset): ByteArray - -public expect fun availableProcessors(): Int - -public inline fun <C : Closeable, R> C.withUse(block: C.() -> R): R { - contract { - callsInPlace(block, InvocationKind.EXACTLY_ONCE) - } - return use(block) -} - -public inline fun <I : Closeable, O : Closeable, R> I.withOut(output: O, block: I.(output: O) -> R): R { - contract { - callsInPlace(block, InvocationKind.EXACTLY_ONCE) - } - return use { output.use { block(this, output) } } -} +public expect fun ByteArray.inflate(offset: Int = 0, length: Int = size - offset): ByteArray +public expect fun ByteArray.deflate(offset: Int = 0, length: Int = size - offset): ByteArray diff --git a/mirai-core-utils/src/commonMain/kotlin/IO.kt b/mirai-core-utils/src/commonMain/kotlin/IO.kt index 5a1aa83dc..39838bfc6 100644 --- a/mirai-core-utils/src/commonMain/kotlin/IO.kt +++ b/mirai-core-utils/src/commonMain/kotlin/IO.kt @@ -18,6 +18,8 @@ import io.ktor.utils.io.* import io.ktor.utils.io.charsets.* import io.ktor.utils.io.core.* import io.ktor.utils.io.core.internal.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmName import kotlin.jvm.JvmSynthetic @@ -27,6 +29,20 @@ public val EMPTY_BYTE_ARRAY: ByteArray = ByteArray(0) public val DECRYPTER_16_ZERO: ByteArray = ByteArray(16) public val KEY_16_ZEROS: ByteArray = ByteArray(16) +public inline fun <C : Closeable, R> C.withUse(block: C.() -> R): R { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return use(block) +} + +public inline fun <I : Closeable, O : Closeable, R> I.withOut(output: O, block: I.(output: O) -> R): R { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return use { output.use { block(this, output) } } +} + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") public inline fun <R> ByteReadPacket.useBytes( n: Int = remaining.toInt(),//not that safe but adequate diff --git a/mirai-core-utils/src/commonMain/kotlin/StandardUtils.kt b/mirai-core-utils/src/commonMain/kotlin/StandardUtils.kt index 9fa068f22..d2e17363e 100644 --- a/mirai-core-utils/src/commonMain/kotlin/StandardUtils.kt +++ b/mirai-core-utils/src/commonMain/kotlin/StandardUtils.kt @@ -166,4 +166,12 @@ public inline fun <reified T> isSameType(thisObject: T, other: Any?): Boolean { if (other == null) return false if (other !is T) return false return isSameClass(thisObject, other) -} \ No newline at end of file +} + +public expect fun availableProcessors(): Int + + +/** + * Localhost 解析 + */ +public expect fun localIpAddress(): String diff --git a/mirai-core-utils/src/jvmBaseMain/kotlin/Crypto.kt b/mirai-core-utils/src/jvmBaseMain/kotlin/Crypto.kt index 6d726bbb4..c248c3b7b 100644 --- a/mirai-core-utils/src/jvmBaseMain/kotlin/Crypto.kt +++ b/mirai-core-utils/src/jvmBaseMain/kotlin/Crypto.kt @@ -12,11 +12,9 @@ package net.mamoe.mirai.utils -import io.ktor.utils.io.core.* import java.io.ByteArrayOutputStream import java.io.InputStream import java.io.OutputStream -import java.net.Inet4Address import java.security.MessageDigest import java.util.zip.Deflater import java.util.zip.GZIPInputStream @@ -25,7 +23,7 @@ import java.util.zip.Inflater public actual val DEFAULT_BUFFER_SIZE: Int get() = kotlin.io.DEFAULT_BUFFER_SIZE -public actual fun ByteArray.unzip(offset: Int, length: Int): ByteArray { +public actual fun ByteArray.inflate(offset: Int, length: Int): ByteArray { checkOffsetAndLength(offset, length) if (length == 0) return ByteArray(0) @@ -44,10 +42,6 @@ public actual fun ByteArray.unzip(offset: Int, length: Int): ByteArray { } } -public actual fun localIpAddress(): String = runCatching { - Inet4Address.getLocalHost().hostAddress -}.getOrElse { "192.168.1.123" } - public fun InputStream.md5(): ByteArray { return digest("md5") } @@ -104,7 +98,7 @@ public actual fun ByteArray.gzip(offset: Int, length: Int): ByteArray { } @JvmOverloads -public actual fun ByteArray.zip(offset: Int, length: Int): ByteArray { +public actual fun ByteArray.deflate(offset: Int, length: Int): ByteArray { checkOffsetAndLength(offset, length) if (length == 0) return ByteArray(0) @@ -117,4 +111,3 @@ public actual fun ByteArray.zip(offset: Int, length: Int): ByteArray { } } -public actual fun availableProcessors(): Int = Runtime.getRuntime().availableProcessors() \ No newline at end of file diff --git a/mirai-core-utils/src/jvmBaseMain/kotlin/StandardUtils.kt b/mirai-core-utils/src/jvmBaseMain/kotlin/StandardUtils.kt index b7c9fba81..b2941a4ec 100644 --- a/mirai-core-utils/src/jvmBaseMain/kotlin/StandardUtils.kt +++ b/mirai-core-utils/src/jvmBaseMain/kotlin/StandardUtils.kt @@ -9,6 +9,14 @@ package net.mamoe.mirai.utils +import java.net.Inet4Address + internal actual fun isSameClassPlatform(object1: Any, object2: Any): Boolean { return object1.javaClass == object2.javaClass -} \ No newline at end of file +} + +public actual fun localIpAddress(): String = runCatching { + Inet4Address.getLocalHost().hostAddress +}.getOrElse { "192.168.1.123" } + +public actual fun availableProcessors(): Int = Runtime.getRuntime().availableProcessors() \ No newline at end of file diff --git a/mirai-core-utils/src/nativeMain/kotlin/ByteArrayOp.kt b/mirai-core-utils/src/nativeMain/kotlin/ByteArrayOp.kt new file mode 100644 index 000000000..0282bd04b --- /dev/null +++ b/mirai-core-utils/src/nativeMain/kotlin/ByteArrayOp.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2019-2022 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/dev/LICENSE + */ + +@file:Suppress("RedundantVisibilityModifier") + +package net.mamoe.mirai.utils + +import interop.* +import kotlinx.cinterop.* +import platform.posix.free +import platform.posix.uint8_tVar + + +public actual val DEFAULT_BUFFER_SIZE: Int get() = 8192 + +public actual fun ByteArray.md5(offset: Int, length: Int): ByteArray = callImpl(::mirai_crypto_md5, offset, length) +public actual fun ByteArray.sha1(offset: Int, length: Int): ByteArray = callImpl(::mirai_crypto_sha1, offset, length) + +public actual fun ByteArray.gzip(offset: Int, length: Int): ByteArray = callImpl(::mirai_crypto_gzip, offset, length) +public actual fun ByteArray.ungzip(offset: Int, length: Int): ByteArray = + callImpl(::mirai_crypto_ungzip, offset, length) + +public actual fun ByteArray.deflate(offset: Int, length: Int): ByteArray = + callImpl(::mirai_crypto_deflate, offset, length) + +public actual fun ByteArray.inflate(offset: Int, length: Int): ByteArray = + callImpl(::mirai_crypto_inflate, offset, length) + + +private fun ByteArray.callImpl( + fn: (CValuesRef<uint8_tVar>, UInt, CValuesRef<SizedByteArray>) -> Boolean, + offset: Int, + length: Int +): ByteArray { + checkOffsetAndLength(offset, length) + + memScoped { + val r = alloc<SizedByteArray>() + if (!fn(toCValues().ptr.reinterpret<uint8_tVar>().plus(offset)!!, length.toUInt(), r.ptr)) { + throw IllegalStateException("Failed platform implementation call") + } + try { + return r.arr?.readBytes(r.size.toInt())!! + } finally { + free(r.arr) + } + } +} diff --git a/mirai-core-utils/src/nativeMain/kotlin/Crypto.kt b/mirai-core-utils/src/nativeMain/kotlin/Crypto.kt deleted file mode 100644 index b4442d122..000000000 --- a/mirai-core-utils/src/nativeMain/kotlin/Crypto.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2019-2022 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/dev/LICENSE - */ - -@file:Suppress("RedundantVisibilityModifier") - -package net.mamoe.mirai.utils - - -public actual fun ByteArray.unzip(offset: Int, length: Int): ByteArray { - TODO("Not yet implemented") -} - -public actual fun localIpAddress(): String = "192.168.1.123" - - -public actual fun ByteArray.md5(offset: Int, length: Int): ByteArray { - TODO("Not yet implemented") -} - -public actual val DEFAULT_BUFFER_SIZE: Int get() = 8192 - -public actual fun ByteArray.sha1(offset: Int, length: Int): ByteArray { - TODO("Not yet implemented") -} - -public actual fun ByteArray.ungzip(offset: Int, length: Int): ByteArray { - TODO("Not yet implemented") -} - -public actual fun ByteArray.gzip(offset: Int, length: Int): ByteArray { - TODO("Not yet implemented") -} - -public actual fun ByteArray.zip(offset: Int, length: Int): ByteArray { - TODO("Not yet implemented") -} - -public actual fun availableProcessors(): Int { - TODO("Not yet implemented") -} \ No newline at end of file diff --git a/mirai-core-utils/src/nativeMain/kotlin/isSameClassPlatform.kt b/mirai-core-utils/src/nativeMain/kotlin/NativeOps.kt similarity index 76% rename from mirai-core-utils/src/nativeMain/kotlin/isSameClassPlatform.kt rename to mirai-core-utils/src/nativeMain/kotlin/NativeOps.kt index d26e10b80..e9ee487b5 100644 --- a/mirai-core-utils/src/nativeMain/kotlin/isSameClassPlatform.kt +++ b/mirai-core-utils/src/nativeMain/kotlin/NativeOps.kt @@ -9,6 +9,6 @@ package net.mamoe.mirai.utils -internal actual fun isSameClassPlatform(object1: Any, object2: Any): Boolean { - return object1::class == object2::class +public fun symbolNotFound(name: String): Nothing { + throw IllegalStateException("Symbol '$name' not found.") } \ No newline at end of file diff --git a/mirai-core-utils/src/nativeMain/kotlin/StandardUtils.kt b/mirai-core-utils/src/nativeMain/kotlin/StandardUtils.kt new file mode 100644 index 000000000..9a77a7d0d --- /dev/null +++ b/mirai-core-utils/src/nativeMain/kotlin/StandardUtils.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2019-2022 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/dev/LICENSE + */ + +package net.mamoe.mirai.utils + +import platform.posix._SC_NPROCESSORS_ONLN +import platform.posix.sysconf + + +public actual fun localIpAddress(): String = "192.168.1.123" + +public actual fun availableProcessors(): Int = sysconf(_SC_NPROCESSORS_ONLN).toInt() + +internal actual fun isSameClassPlatform(object1: Any, object2: Any): Boolean { + return object1::class == object2::class +} \ No newline at end of file diff --git a/mirai-core-utils/src/nativeMainInterop/.gitignore b/mirai-core-utils/src/nativeMainInterop/.gitignore new file mode 100644 index 000000000..683119ebf --- /dev/null +++ b/mirai-core-utils/src/nativeMainInterop/.gitignore @@ -0,0 +1,8 @@ +/target +Cargo.lock +myrust.h + +*.iml + +src/bindings.rs +/*.h \ No newline at end of file diff --git a/mirai-core-utils/src/nativeMainInterop/Cargo.toml b/mirai-core-utils/src/nativeMainInterop/Cargo.toml new file mode 100644 index 000000000..1165bb458 --- /dev/null +++ b/mirai-core-utils/src/nativeMainInterop/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "mirai_core_utils_i" +version = "0.1.0" + +[dependencies] +md5 = "0.7.0" +sha1 = "0.10.1" +flate2 = "1.0.23" +libc = "0.2.126" + +[lib] +name = "mirai_core_utils_i" +crate-type = ["cdylib"] # Creates dynamic lib +# crate-type = ["staticlib"] # Creates static lib + +[build-dependencies] +bindgen = "0.53.1" +cbindgen = "0.20.0" diff --git a/mirai-core-utils/src/nativeMainInterop/build.rs b/mirai-core-utils/src/nativeMainInterop/build.rs new file mode 100644 index 000000000..669efe88f --- /dev/null +++ b/mirai-core-utils/src/nativeMainInterop/build.rs @@ -0,0 +1,32 @@ +/* + * Copyright 2019-2022 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/dev/LICENSE + */ + +extern crate bindgen; +extern crate cbindgen; + +use std::env; +use std::path::PathBuf; + +use cbindgen::Config; +use cbindgen::Language::C; + +fn main() { + // let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + + // cbindgen::Builder::new() + // .with_crate(crate_dir) + // .with_language(C) + // .generate() + // .expect("Unable to generate bindings") + // .write_to_file("nativeInterop.h"); + + + println!("cargo:rustc-link-search=../../build/bin/native/debugShared"); + println!("cargo:rustc-link-lib=mirai_core_utils"); +} \ No newline at end of file diff --git a/mirai-core-utils/src/nativeMainInterop/cbindgen.toml b/mirai-core-utils/src/nativeMainInterop/cbindgen.toml new file mode 100644 index 000000000..4aa4b4903 --- /dev/null +++ b/mirai-core-utils/src/nativeMainInterop/cbindgen.toml @@ -0,0 +1,10 @@ +# This is a template cbindgen.toml file with all of the default values. +# Some values are commented out because their absence is the real default. +# +# See https://github.com/eqrion/cbindgen/blob/master/docs.md#cbindgentoml +# for detailed documentation of every option here. + + + +language = "C" + diff --git a/mirai-core-utils/src/nativeMainInterop/interop.def b/mirai-core-utils/src/nativeMainInterop/interop.def new file mode 100644 index 000000000..e69de29bb diff --git a/mirai-core-utils/src/nativeMainInterop/src/crypto.rs b/mirai-core-utils/src/nativeMainInterop/src/crypto.rs new file mode 100644 index 000000000..6efd52b6e --- /dev/null +++ b/mirai-core-utils/src/nativeMainInterop/src/crypto.rs @@ -0,0 +1,125 @@ +/* + * Copyright 2019-2022 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/dev/LICENSE + */ + +use std::io::{BufReader, Read, Write}; + +use flate2::Compression; +use flate2::write::{DeflateDecoder, DeflateEncoder, GzDecoder, GzEncoder, ZlibDecoder, ZlibEncoder}; +use libc::{malloc, read, size_t}; +use sha1::{Digest, Sha1}; +use sha1::digest::{Output, OutputSizeUser}; +use sha1::digest::generic_array::GenericArray; + +#[no_mangle] +#[repr(C)] +pub struct SizedByteArray { + arr: *mut u8, + size: u32, +} + +#[no_mangle] +pub unsafe extern "C" fn mirai_crypto_md5(data: *const u8, len: u32, ret: &mut SizedByteArray) -> bool { + let data = unsafe { std::slice::from_raw_parts(data, len as usize) }; + let result = md5::compute(data); + let size = 16; + let mut memory = malloc(size).cast(); + memory.copy_from(result.as_ptr(), size); + + ret.arr = memory; + ret.size = size as u32; + return true; +} + +#[no_mangle] +pub unsafe extern "C" fn mirai_crypto_sha1(data: *const u8, len: u32, ret: &mut SizedByteArray) -> bool { + let data = unsafe { std::slice::from_raw_parts(data, len as usize) }; + let mut hasher = Sha1::new(); + hasher.update(data); + let result = hasher.finalize(); + let size = 16; + let mut memory = malloc(size).cast(); + memory.copy_from(result.as_ptr(), size); + + ret.arr = memory; + ret.size = size as u32; + return true; +} + + +#[no_mangle] +pub unsafe extern "C" fn mirai_crypto_gzip(data: *const u8, len: u32, ret: &mut SizedByteArray) -> bool { + let data = unsafe { std::slice::from_raw_parts(data, len as usize) }; + let mut encoder = GzEncoder::new(Vec::new(), Compression::default()); + + let result = encoder.write_all(data).and_then(|_| { encoder.finish() }); + if result.is_err() { return false; } + let result = result.unwrap(); + + let size = result.len(); + let mut memory = malloc(size).cast(); + memory.copy_from(result.as_ptr(), size); + + ret.arr = memory; + ret.size = size as u32; + return true; +} + +#[no_mangle] +pub unsafe extern "C" fn mirai_crypto_ungzip(data: *const u8, len: u32, ret: &mut SizedByteArray) -> bool { + let data = unsafe { std::slice::from_raw_parts(data, len as usize) }; + let mut encoder = GzDecoder::new(Vec::new()); + + let result = encoder.write_all(data).and_then(|_| { encoder.finish() }); + if result.is_err() { return false; } + let result = result.unwrap(); + + let size = result.len(); + let mut memory = malloc(size).cast(); + memory.copy_from(result.as_ptr(), size); + + ret.arr = memory; + ret.size = size as u32; + return true; +} + +#[no_mangle] +pub unsafe extern "C" fn mirai_crypto_deflate(data: *const u8, len: u32, ret: &mut SizedByteArray) -> bool { + let data = unsafe { std::slice::from_raw_parts(data, len as usize) }; + let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default()); + + let result = encoder.write_all(data).and_then(|_| { encoder.finish() }); + if result.is_err() { return false; } + let result = result.unwrap(); + + let size = result.len(); + let mut memory = malloc(size).cast(); + memory.copy_from(result.as_ptr(), size); + + ret.arr = memory; + ret.size = size as u32; + return true; +} + +#[no_mangle] +pub unsafe extern "C" fn mirai_crypto_inflate(data: *const u8, len: u32, ret: &mut SizedByteArray) -> bool { + let data = unsafe { std::slice::from_raw_parts(data, len as usize) }; + let mut encoder = ZlibDecoder::new(Vec::new()); + + let result = encoder.write_all(data).and_then(|_| { encoder.finish() }); + if result.is_err() { return false; } + let result = result.unwrap(); + + let size = result.len(); + let mut memory = malloc(size).cast(); + memory.copy_from(result.as_ptr(), size); + + ret.arr = memory; + ret.size = size as u32; + return true; +} diff --git a/mirai-core-utils/src/nativeMainInterop/src/lib.rs b/mirai-core-utils/src/nativeMainInterop/src/lib.rs new file mode 100644 index 000000000..1bdaa485f --- /dev/null +++ b/mirai-core-utils/src/nativeMainInterop/src/lib.rs @@ -0,0 +1,17 @@ +/* + * Copyright 2019-2022 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/dev/LICENSE + */ + +extern crate flate2; +extern crate libc; +extern crate sha1; + +/// cbindgen:ignore +mod bindings; +mod crypto; + diff --git a/mirai-core-utils/src/nativeTest/kotlin/CryptoTest.kt b/mirai-core-utils/src/nativeTest/kotlin/CryptoTest.kt new file mode 100644 index 000000000..a979a9fe3 --- /dev/null +++ b/mirai-core-utils/src/nativeTest/kotlin/CryptoTest.kt @@ -0,0 +1,110 @@ +/* + * Copyright 2019-2022 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/dev/LICENSE + */ + +package net.mamoe.mirai.utils + +import io.ktor.utils.io.core.* +import kotlin.random.Random +import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class CryptoTest { + + @Test + fun testAvailableProcessors() { + val processors = availableProcessors() + assertTrue(processors.toString()) { processors > 0 } + } + + @Test + fun testMd5() { + val str = getRandomString(10, Random(1)) + println(str) + val hash = str.md5() + assertContentEquals( + "30 3B 36 B3 42 00 39 E2 EC 18 22 79 10 32 05 48".hexToBytes(), + hash, + message = hash.toUHexString() + ) + } + + @Test + fun testMd5WithOffset() { + val str = getRandomString(10, Random(1)) + println(str) + val hash = (byteArrayOf(1) + str.toByteArray()).md5(1) + assertContentEquals( + "30 3B 36 B3 42 00 39 E2 EC 18 22 79 10 32 05 48".hexToBytes(), + hash, + message = hash.toUHexString() + ) + } + + @Test + fun testSha1() { + val str = getRandomString(10, Random(1)) + println(str) + val hash = str.sha1() + assertContentEquals( + "54 98 CD 62 6C DE E3 9B 96 D4 34 5E 13 51 48 BB".hexToBytes(), + hash, + message = hash.toUHexString() + ) + } + + @Test + fun testDeflate() { + val str = "qGnJ1RrFC9" + println(str) + val hash = str.toByteArray().deflate() + assertContentEquals( + "78 9C 2B 74 CF F3 32 0C 2A 72 73 B6 04 00 12 82 03 28".hexToBytes(), + hash, + message = hash.toUHexString() + ) + } + + @Test + fun testInflate() { + val result = + "78 9C 2B 74 CF F3 32 0C 2A 72 73 B6 04 00 12 82 03 28".hexToBytes() + .inflate().decodeToString() + assertEquals( + "qGnJ1RrFC9", + result, + message = result + ) + } + + @Test + fun testGzip() { + val str = "qGnJ1RrFC9" + println(str) + val hash = str.toByteArray().gzip() + assertContentEquals( + "1F 8B 08 00 00 00 00 00 00 FF 2B 74 CF F3 32 0C 2A 72 73 B6 04 00 A8 35 6D D9 0A 00 00 00".hexToBytes(), + hash, + message = hash.toUHexString() + ) + } + + @Test + fun testUnGzip() { + val result = + "1F 8B 08 00 00 00 00 00 00 FF 2B 74 CF F3 32 0C 2A 72 73 B6 04 00 A8 35 6D D9 0A 00 00 00".hexToBytes() + .ungzip().decodeToString() + assertEquals( + "qGnJ1RrFC9", + result, + message = result + ) + } +} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/RichMessageProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/RichMessageProtocol.kt index 756e64800..6e46357e3 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/RichMessageProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/RichMessageProtocol.kt @@ -23,10 +23,10 @@ import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext.Co import net.mamoe.mirai.internal.message.runWithBugReport import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.message.data.* +import net.mamoe.mirai.utils.deflate import net.mamoe.mirai.utils.hexToBytes +import net.mamoe.mirai.utils.inflate import net.mamoe.mirai.utils.toUHexString -import net.mamoe.mirai.utils.unzip -import net.mamoe.mirai.utils.zip /** * Handles: @@ -50,7 +50,7 @@ internal class RichMessageProtocol : MessageProtocol() { private class Encoder : MessageEncoder<RichMessage> { override suspend fun MessageEncoderContext.process(data: RichMessage) { markAsConsumed() - val content = data.content.toByteArray().zip() + val content = data.content.toByteArray().deflate() var longTextResId: String? = null when (data) { is ForwardMessageInternal -> { @@ -127,7 +127,7 @@ internal class RichMessageProtocol : MessageProtocol() { { "resId=" + lightApp.msgResid + "data=" + lightApp.data.toUHexString() }) { when (lightApp.data[0].toInt()) { 0 -> lightApp.data.decodeToString(startIndex = 1) - 1 -> lightApp.data.unzip(1).decodeToString() + 1 -> lightApp.data.inflate(1).decodeToString() else -> error("unknown compression flag=${lightApp.data[0]}") } } @@ -146,7 +146,7 @@ internal class RichMessageProtocol : MessageProtocol() { val content = runWithBugReport("解析 richMsg", { richMsg.template1.toUHexString() }) { when (richMsg.template1[0].toInt()) { 0 -> richMsg.template1.decodeToString(startIndex = 1) - 1 -> richMsg.template1.unzip(1).decodeToString() + 1 -> richMsg.template1.inflate(1).decodeToString() else -> error("unknown compression flag=${richMsg.template1[0]}") } } diff --git a/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt b/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt index e2431cb4e..82b2b76a1 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt @@ -221,7 +221,7 @@ internal class PacketCodecImpl : PacketCodec { 1 -> { input.discardExact(4) input.useBytes { data, length -> - data.unzip(0, length).let { + data.inflate(0, length).let { val size = it.toInt() if (size == it.size || size == it.size + 4) { it.toReadPacket(offset = 4) diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/Msg.kt b/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/Msg.kt index 8bb3dc211..758ddb9ca 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/Msg.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/Msg.kt @@ -20,8 +20,8 @@ import net.mamoe.mirai.internal.utils.io.ProtoBuf import net.mamoe.mirai.internal.utils.io.serialization.loadAs import net.mamoe.mirai.internal.utils.structureToStringIfAvailable import net.mamoe.mirai.utils.EMPTY_BYTE_ARRAY +import net.mamoe.mirai.utils.inflate import net.mamoe.mirai.utils.isSameType -import net.mamoe.mirai.utils.unzip import kotlin.jvm.JvmField @Serializable @@ -558,7 +558,7 @@ internal class ImMsgBody : ProtoBuf { return when (byteArray[0].toInt()) { 0 -> byteArrayOf(0) + byteArray.decodeToString(startIndex = 1).toByteArray() - 1 -> byteArrayOf(0) + byteArray.unzip(offset = 1).decodeToString().toByteArray() + 1 -> byteArrayOf(0) + byteArray.inflate(offset = 1).decodeToString().toByteArray() else -> error("unknown compression flag=${byteArray[0]}") } } diff --git a/mirai-core/src/commonTest/kotlin/PlatformUtilsTest.kt b/mirai-core/src/commonTest/kotlin/PlatformUtilsTest.kt index b8e4a40c7..d719783f9 100644 --- a/mirai-core/src/commonTest/kotlin/PlatformUtilsTest.kt +++ b/mirai-core/src/commonTest/kotlin/PlatformUtilsTest.kt @@ -11,10 +11,10 @@ package net.mamoe.mirai.internal import io.ktor.utils.io.core.* import net.mamoe.mirai.internal.test.AbstractTest +import net.mamoe.mirai.utils.deflate import net.mamoe.mirai.utils.gzip +import net.mamoe.mirai.utils.inflate import net.mamoe.mirai.utils.ungzip -import net.mamoe.mirai.utils.unzip -import net.mamoe.mirai.utils.zip import kotlin.test.Test import kotlin.test.assertEquals @@ -22,7 +22,7 @@ internal class PlatformUtilsTest : AbstractTest() { @Test fun testZip() { - assertEquals("test", "test".toByteArray().zip().unzip().decodeToString()) + assertEquals("test", "test".toByteArray().deflate().inflate().decodeToString()) } @Test