Compare commits

..

4 Commits

Author SHA1 Message Date
3c3ebfa894 Add file size 2026-06-09 10:55:19 +08:00
81df6cc2df Update msg_tool to v0.4.0-alpha.2 and simplify audio type detection 2026-06-09 10:26:36 +08:00
b8a921022b Fix bug 2026-04-14 18:04:18 +08:00
f213fc6d8b Add cache and bug fix 2026-04-14 17:39:56 +08:00
3 changed files with 344 additions and 158 deletions

145
src-tauri/Cargo.lock generated
View File

@@ -126,6 +126,18 @@ version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]]
name = "argon2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
dependencies = [
"base64ct",
"blake2",
"cpufeatures 0.2.17",
"password-hash",
]
[[package]]
name = "arrayvec"
version = "0.7.6"
@@ -321,6 +333,12 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64ct"
version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
[[package]]
name = "bit-set"
version = "0.8.0"
@@ -351,6 +369,15 @@ dependencies = [
"serde_core",
]
[[package]]
name = "blake2"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
dependencies = [
"digest 0.10.7",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
@@ -593,9 +620,9 @@ dependencies = [
[[package]]
name = "cedarwood"
version = "0.4.6"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d910bedd62c24733263d0bed247460853c9d22e8956bd4cd964302095e04e90"
checksum = "c0524a528a6a0288df1863c3c20fe92c301875b4941e7b6c4b394ab08c5a4c55"
dependencies = [
"smallvec",
]
@@ -646,6 +673,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures 0.3.0",
"rand_core 0.10.0",
]
@@ -657,8 +685,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
"serde",
"wasm-bindgen",
"windows-link 0.2.1",
]
@@ -668,6 +698,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea"
dependencies = [
"block-buffer 0.12.0",
"crypto-common 0.2.1",
"inout",
]
@@ -1219,6 +1250,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer 0.10.4",
"crypto-common 0.1.7",
"subtle",
]
[[package]]
@@ -1564,9 +1596,9 @@ dependencies = [
[[package]]
name = "fancy-regex"
version = "0.17.0"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8"
checksum = "e1e1dacd0d2082dfcf1351c4bdd566bbe89a2b263235a2b50058f1e130a47277"
dependencies = [
"bit-set",
"regex-automata",
@@ -1575,9 +1607,9 @@ dependencies = [
[[package]]
name = "fastcdc"
version = "3.2.1"
version = "4.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf51ceb43e96afbfe4dd5c6f6082af5dfd60e220820b8123792d61963f2ce6bc"
checksum = "77af40d8a8dadb92dc178569a5f5edb5f3056e98255c2de48ab5d59a52892e0c"
[[package]]
name = "fastrand"
@@ -2725,19 +2757,20 @@ dependencies = [
[[package]]
name = "jieba-macros"
version = "0.8.1"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "348294e44ee7e3c42685da656490f8febc7359632544019621588902216da95c"
checksum = "46adade69b634535a8f495cf87710ed893cff53e1dbc9dd750c2ab81c5defb82"
dependencies = [
"phf_codegen 0.13.1",
]
[[package]]
name = "jieba-rs"
version = "0.8.1"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "766bd7012aa5ba49411ebdf4e93bddd59b182d2918e085d58dec5bb9b54b7105"
checksum = "11b53580aaa8ec8b713da271da434f8947409242c537a9ab3f7b76bdbb19e8a9"
dependencies = [
"bytecount",
"cedarwood",
"include-flate",
"jieba-macros",
@@ -2840,6 +2873,16 @@ dependencies = [
"serde_json",
]
[[package]]
name = "keccak"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aa"
dependencies = [
"cfg-if",
"cpufeatures 0.3.0",
]
[[package]]
name = "keyboard-types"
version = "0.7.0"
@@ -3176,16 +3219,20 @@ dependencies = [
[[package]]
name = "msg_tool"
version = "0.3.1"
version = "0.4.0-alpha.2"
dependencies = [
"adler",
"aes",
"anyhow",
"argon2",
"base64 0.22.1",
"blake2",
"block_compression",
"byteorder",
"bytes",
"cbc",
"chacha20",
"chrono",
"clap 4.6.0",
"crc32fast",
"crossbeam",
@@ -3197,6 +3244,7 @@ dependencies = [
"fancy-regex",
"fastcdc",
"flate2",
"hex",
"include-flate",
"int-enum",
"jieba-rs",
@@ -3217,6 +3265,7 @@ dependencies = [
"parse-size",
"pelite",
"png 0.18.1",
"qoi",
"rand 0.10.1",
"rust-ini",
"serde",
@@ -3224,6 +3273,9 @@ dependencies = [
"serde_yaml_ng",
"sha1",
"sha2 0.11.0",
"sha3",
"shake",
"siphasher 1.0.2",
"stylua",
"tendril 0.5.0",
"unicode-segmentation",
@@ -3232,13 +3284,16 @@ dependencies = [
"webp",
"windows-sys 0.61.2",
"xml5ever",
"xxhash-rust",
"zopfli",
"zstd",
]
[[package]]
name = "msg_tool_build"
version = "0.3.1"
version = "0.4.0-alpha.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8386042ba7f224865098b365961d45df240b4f43ac6c8e279d16616ae25188ae"
dependencies = [
"json",
"zstd",
@@ -3246,7 +3301,9 @@ dependencies = [
[[package]]
name = "msg_tool_macro"
version = "0.3.0"
version = "0.4.0-alpha.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "177ed201ff17ef103ad65d1f5a679d105e463a4e36e61a977978bdb97b5d04bc"
dependencies = [
"quote",
"syn 2.0.117",
@@ -3254,7 +3311,7 @@ dependencies = [
[[package]]
name = "msg_tool_xp3data"
version = "0.3.1"
version = "0.4.0-alpha.2"
dependencies = [
"msg_tool_build",
"zstd",
@@ -3648,6 +3705,17 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "487f2ccd1e17ce8c1bfab3a65c89525af41cfad4c8659021a1e9a2aacd73b89b"
[[package]]
name = "password-hash"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
dependencies = [
"base64ct",
"rand_core 0.6.4",
"subtle",
]
[[package]]
name = "paste"
version = "1.0.15"
@@ -4096,6 +4164,15 @@ version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d"
[[package]]
name = "qoi"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
dependencies = [
"bytemuck",
]
[[package]]
name = "quick-error"
version = "2.0.1"
@@ -4730,6 +4807,28 @@ dependencies = [
"digest 0.11.2",
]
[[package]]
name = "sha3"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc9bad02c26382724b2d2692c6f179285e4b54eeecd7968f52a50059c3c11759"
dependencies = [
"digest 0.11.2",
"keccak",
"sponge-cursor",
]
[[package]]
name = "shake"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09057cb2149ad4cbd2da1e26b351f9a4c354219421229c69c3063e6f61947c4a"
dependencies = [
"digest 0.11.2",
"keccak",
"sponge-cursor",
]
[[package]]
name = "shlex"
version = "1.3.0"
@@ -4854,6 +4953,12 @@ dependencies = [
"system-deps",
]
[[package]]
name = "sponge-cursor"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a0219bd7d979d58245a4f41f695e1ac9f8befdffadd7f61f1bae9e39abc6620"
[[package]]
name = "stable_deref_trait"
version = "1.2.1"
@@ -4948,6 +5053,12 @@ dependencies = [
"toml 0.8.2",
]
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "swift-rs"
version = "1.0.7"
@@ -6809,6 +6920,12 @@ dependencies = [
"markup5ever 0.38.0",
]
[[package]]
name = "xxhash-rust"
version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3"
[[package]]
name = "yoke"
version = "0.8.2"

View File

@@ -1,15 +1,18 @@
use anyhow::Result;
use msg_tool::ext::io::MutexWrapper;
use msg_tool::ext::mutex::*;
use msg_tool::scripts::base::ReadSeek;
use msg_tool::scripts::{BUILDER, ScriptBuilder};
use msg_tool::types::{ExtraConfig, ImageOutputType, ScriptType};
use msg_tool::scripts::{BUILDER, Script, ScriptBuilder};
use msg_tool::types::{ExtraConfig, ImageOutputType, PngCompressionLevel, ScriptType};
use msg_tool::utils::img::*;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;
use std::io::{BufReader, Read};
use std::path::Path;
use std::sync::Mutex;
use std::sync::{Arc, Mutex};
use tauri::{AppHandle, Manager};
use tauri::ipc::Response;
const PNG_SIGNATURE: &[u8] = b"\x89PNG\r\n\x1a\n";
@@ -17,12 +20,172 @@ lazy_static::lazy_static! {
static ref ENTRY_TYPE_CACHE: Mutex<BTreeMap<ScriptType, EntryType>> = Mutex::new(BTreeMap::new());
}
struct CacheEntry<'a> {
archive: Box<dyn Script + Send + Sync + 'a>,
path: String,
option: FileOptions,
}
impl<'a> CacheEntry<'a> {
fn new(
mut reader: Box<dyn ReadSeek + Send + Sync + 'a>,
filename: &str,
option: FileOptions,
script_type: Option<ScriptType>,
) -> Result<Self> {
let (entry_type, msg_tool_type) = if let Some(typ) = script_type {
(query_entry_type(&typ), Some(typ.clone()))
} else {
let mut buffer = [0; 1024];
let n = reader.read(&mut buffer)?;
reader.rewind()?;
detect_file_type(filename, &buffer[..n])
};
if entry_type != EntryType::Archive {
return Err(anyhow::anyhow!("不是归档文件"));
}
let script_type = msg_tool_type.ok_or_else(|| anyhow::anyhow!("无法识别的归档格式"))?;
let builder = BUILDER
.iter()
.find(|b| b.script_type() == &script_type)
.ok_or_else(|| anyhow::anyhow!("不支持的归档格式"))?;
let extra_config = option.to_extra_config();
let encoding = builder.default_encoding();
let archive_encoding = builder.default_archive_encoding().unwrap_or(encoding);
let archive = builder.build_script_from_reader(
reader,
filename,
encoding,
archive_encoding,
&extra_config,
None,
)?;
Ok(CacheEntry {
archive,
path: filename.to_string(),
option,
})
}
}
struct CacheManager {
file: Option<Arc<Mutex<BufReader<File>>>>,
cache: Option<CacheEntry<'static>>,
}
impl CacheManager {
fn list_archive(
&mut self,
path: &str,
option: Option<&Vec<FileOptions>>,
) -> Result<Vec<Entry>> {
let paths = path.split("|").collect::<Vec<_>>();
let cache = self.get_entry(path, option)?;
if paths.len() == 1 {
let mut result = Vec::new();
let mut index = 0;
for entry in cache.archive.iter_archive_filename()? {
let name = entry?;
let mut entry = cache.archive.open_file(index)?;
let file_size = entry.size();
index += 1;
let (entry_type, msg_tool_type) = if let Some(typ) = entry.script_type() {
(query_entry_type(&typ), Some(typ.clone()))
} else {
let mut buffer = [0; 1024];
let n = entry.read(&mut buffer)?;
detect_file_type(&name, &buffer[..n])
};
// 扁平结构,不区分文件夹,前端根据路径解析出文件夹结构
result.push(Entry {
name,
is_dir: false,
entry_type,
msg_tool_type,
size: file_size,
});
}
Ok(result)
} else {
let filename = path.split("|").nth(1).unwrap();
let mut entry = cache.archive.open_file_by_name(filename, false)?;
let typ = entry.script_type().map(|t| t.clone());
let entry = entry.to_data()?;
let path = path.splitn(2, "|").nth(1).unwrap();
list_archive_directory_in_archive(path, entry, filename, option, typ, 1)
}
}
fn preview_image(&mut self, path: &str, option: Option<&Vec<FileOptions>>) -> Result<Vec<u8>> {
let cache = self.get_entry(path, option)?;
let paths = path.split("|").collect::<Vec<_>>();
if paths.len() == 2 {
let filename = paths[1];
let mut entry = cache.archive.open_file_by_name(filename, false)?;
let typ = entry.script_type().map(|t| t.clone());
let entry = entry.to_data()?;
preview_image_in_directory(entry, filename, option, typ, 1)
} else {
let filename = paths[1];
let mut entry = cache.archive.open_file_by_name(filename, false)?;
let typ = entry.script_type().map(|t| t.clone());
let entry = entry.to_data()?;
let path = path.splitn(2, "|").nth(1).unwrap();
preview_image_in_archive(path, entry, filename, option, typ, 1)
}
}
// 目前只能缓存根归档文件
fn get_entry(
&mut self,
path: &str,
option: Option<&Vec<FileOptions>>,
) -> Result<&CacheEntry<'static>> {
let paths = path.split("|").collect::<Vec<_>>();
let is_hit = self.cache.as_ref().map_or(false, |cache| {
if paths[0] == cache.path {
let opt = option
.and_then(|opts| opts.get(0).cloned())
.unwrap_or_default();
if opt == cache.option {
return true;
}
}
false
});
let entry = if is_hit {
self.cache.as_ref().unwrap()
} else {
// 关闭当前缓存的文件和归档
self.cache.take();
self.file.take();
let file = Arc::new(Mutex::new(BufReader::new(File::open(paths[0])?)));
let option = option
.and_then(|opts| opts.get(0).cloned())
.unwrap_or_default();
let mfile = MutexWrapper::new(file.clone(), 0);
let cache_entry = CacheEntry::new(Box::new(mfile), paths[0], option, None)?;
self.file = Some(file.clone());
self.cache = Some(cache_entry);
self.cache.as_ref().unwrap()
};
Ok(entry)
}
}
lazy_static::lazy_static!(
static ref CACHE_MANAGER: Mutex<CacheManager> = Mutex::new(CacheManager {
file: None,
cache: None,
});
);
fn query_entry_type(script_type: &ScriptType) -> EntryType {
let mut cache = ENTRY_TYPE_CACHE.lock().unwrap();
if let Some(entry_type) = cache.get(script_type) {
return entry_type.clone();
}
let entry_type = if script_type.is_audio() {
let entry_type = if matches!(script_type, ScriptType::BGIAudio | ScriptType::CircusPcm) {
EntryType::Audio
} else {
let builder = BUILDER
@@ -35,17 +198,6 @@ fn query_entry_type(script_type: &ScriptType) -> EntryType {
entry_type
}
/// 到时候可能考虑把识别写到msg_tool那里
trait ScriptTypeExt {
fn is_audio(&self) -> bool;
}
impl ScriptTypeExt for ScriptType {
fn is_audio(&self) -> bool {
matches!(self, ScriptType::BGIAudio | ScriptType::CircusPcm)
}
}
trait ScriptBuilderExt {
fn entry_type(&self) -> EntryType;
}
@@ -56,7 +208,7 @@ impl<T: ScriptBuilder + ?Sized> ScriptBuilderExt for T {
EntryType::Image
} else if self.is_archive() {
EntryType::Archive
} else if self.script_type().is_audio() {
} else if self.is_audio() {
EntryType::Audio
} else {
EntryType::Unknown
@@ -90,7 +242,7 @@ pub struct GameTitle {
alias: Option<Vec<String>>,
}
#[derive(Debug, Default, Deserialize, Clone)]
#[derive(Debug, Default, Deserialize, Clone, PartialEq, Eq)]
pub struct Xp3Option {
/// 设置游戏标题,用于解密xp3文件
game_title: Option<String>,
@@ -98,7 +250,7 @@ pub struct Xp3Option {
force_decrypt: bool,
}
#[derive(Debug, Default, Deserialize, Clone)]
#[derive(Debug, Default, Deserialize, Clone, PartialEq, Eq)]
pub struct FileOptions {
xp3: Option<Xp3Option>,
}
@@ -199,11 +351,16 @@ fn detect_file_type(filename: &str, data: &[u8]) -> (EntryType, Option<ScriptTyp
(EntryType::Unknown, None)
}
fn try_detect_file_type<P: AsRef<std::path::Path> + ?Sized>(path: &P) -> Result<(EntryType, Option<ScriptType>)> {
fn try_detect_file_type<P: AsRef<std::path::Path> + ?Sized>(
path: &P,
) -> Result<(EntryType, Option<ScriptType>)> {
let mut file = File::open(path)?;
let mut buffer = [0; 1024];
let n = file.read(&mut buffer)?;
Ok(detect_file_type(&path.as_ref().to_string_lossy(), &buffer[..n]))
Ok(detect_file_type(
&path.as_ref().to_string_lossy(),
&buffer[..n],
))
}
fn list_fs_directory(path: &Path) -> Result<Vec<Entry>> {
@@ -242,64 +399,6 @@ fn list_fs_directory(path: &Path) -> Result<Vec<Entry>> {
Ok(result)
}
fn list_archive_directory(path: &Path, option: Option<&Vec<FileOptions>>) -> Result<Vec<Entry>> {
let option = option
.and_then(|opts| opts.get(0).cloned())
.unwrap_or_default();
let mut header = [0; 1024];
let n = {
let mut file = File::open(path)?;
file.read(&mut header)?
};
let (entry_type, msg_tool_type) = detect_file_type(&path.to_string_lossy(), &header[..n]);
if entry_type != EntryType::Archive {
return Err(anyhow::anyhow!("不是归档文件"));
}
let script_type = msg_tool_type.ok_or_else(|| anyhow::anyhow!("无法识别的归档格式"))?;
let builder = BUILDER
.iter()
.find(|b| b.script_type() == &script_type)
.ok_or_else(|| anyhow::anyhow!("不支持的归档格式"))?;
let extra_config = option.to_extra_config();
let encoding = builder.default_encoding();
let archive_encoding = builder.default_archive_encoding().unwrap_or(encoding);
let archive = builder.build_script_from_file(
&path.to_string_lossy(),
encoding,
archive_encoding,
&extra_config,
None,
)?;
let mut result = Vec::new();
let mut index = 0;
for entry in archive.iter_archive_filename()? {
let name = entry?;
let mut entry = archive.open_file(index)?;
index += 1;
let (entry_type, msg_tool_type) = if let Some(typ) = entry.script_type() {
let entry_type = if typ.is_audio() {
EntryType::Audio
} else {
query_entry_type(&typ)
};
(entry_type, Some(typ.clone()))
} else {
let mut buffer = [0; 1024];
let n = entry.read(&mut buffer)?;
detect_file_type(&name, &buffer[..n])
};
// 扁平结构,不区分文件夹,前端根据路径解析出文件夹结构
result.push(Entry {
name,
is_dir: false,
entry_type,
msg_tool_type,
size: None,
});
}
Ok(result)
}
fn list_archive_directory_in_archive<'a>(
path: &str,
mut reader: Box<dyn ReadSeek + Send + Sync + 'a>,
@@ -312,12 +411,7 @@ fn list_archive_directory_in_archive<'a>(
.and_then(|opts| opts.get(index).cloned())
.unwrap_or_default();
let (entry_type, msg_tool_type) = if let Some(typ) = typ {
let entry_type = if typ.is_audio() {
EntryType::Audio
} else {
query_entry_type(&typ)
};
(entry_type, Some(typ.clone()))
(query_entry_type(&typ), Some(typ.clone()))
} else {
let mut buffer = [0; 1024];
let n = reader.read(&mut buffer)?;
@@ -363,14 +457,10 @@ fn list_archive_directory_in_archive<'a>(
for entry in archive.iter_archive_filename()? {
let name = entry?;
let mut entry = archive.open_file(index)?;
let file_size = entry.size();
index += 1;
let (entry_type, msg_tool_type) = if let Some(typ) = entry.script_type() {
let entry_type = if typ.is_audio() {
EntryType::Audio
} else {
query_entry_type(&typ)
};
(entry_type, Some(typ.clone()))
(query_entry_type(&typ), Some(typ.clone()))
} else {
let mut buffer = [0; 1024];
let n = entry.read(&mut buffer)?;
@@ -382,7 +472,7 @@ fn list_archive_directory_in_archive<'a>(
is_dir: false,
entry_type,
msg_tool_type,
size: None,
size: file_size,
});
}
Ok(result)
@@ -415,25 +505,13 @@ pub fn list_directory(
options: Option<Vec<FileOptions>>,
) -> Result<Vec<Entry>, ErrorMsg> {
if path.contains("|") {
let filename = path.split("|").nth(0).unwrap();
let reader = Box::new(std::io::BufReader::new(File::open(filename).map_err(
|e| ErrorMsg {
typ: ErrorType::NotFound,
msg: format!("无法打开文件: {}", e),
},
)?));
return list_archive_directory_in_archive(
path,
reader,
filename,
options.as_ref(),
None,
0,
)
.map_err(|e| ErrorMsg {
typ: ErrorType::Other,
msg: e.to_string(),
});
return CACHE_MANAGER
.lock_blocking()
.list_archive(path, options.as_ref())
.map_err(|e| ErrorMsg {
typ: ErrorType::Other,
msg: e.to_string(),
});
}
let path = std::path::Path::new(path);
if !path.exists() {
@@ -446,10 +524,13 @@ pub fn list_directory(
if let Some(parent) = path.parent() {
let _ = set_last_directory(&app, parent.to_string_lossy().as_ref());
}
return list_archive_directory(path, options.as_ref()).map_err(|e| ErrorMsg {
typ: ErrorType::Other,
msg: e.to_string(),
});
return CACHE_MANAGER
.lock_blocking()
.list_archive(&path.to_string_lossy(), options.as_ref())
.map_err(|e| ErrorMsg {
typ: ErrorType::Other,
msg: e.to_string(),
});
}
let _ = set_last_directory(&app, path.to_string_lossy().as_ref());
list_fs_directory(path).map_err(|e| ErrorMsg {
@@ -479,12 +560,7 @@ fn preview_image_in_directory<'a>(
index: usize,
) -> Result<Vec<u8>> {
let (entry_type, msg_tool_type) = if let Some(typ) = script_type {
let entry_type = if typ.is_audio() {
EntryType::Audio
} else {
query_entry_type(&typ)
};
(entry_type, Some(typ.clone()))
(query_entry_type(&typ), Some(typ.clone()))
} else {
let mut buffer = [0; 1024];
let n = reader.read(&mut buffer)?;
@@ -503,7 +579,8 @@ fn preview_image_in_directory<'a>(
.as_ref()
.and_then(|opts| opts.get(index).cloned())
.unwrap_or_default();
let extra_config = option.to_extra_config();
let mut extra_config = option.to_extra_config();
extra_config.png_compression_level = PngCompressionLevel::Fast;
let encoding = builder.default_encoding();
let archive_encoding = builder.default_archive_encoding().unwrap_or(encoding);
let image = builder.build_script_from_reader(
@@ -538,21 +615,13 @@ fn preview_image_in_archive<'a>(
.and_then(|opts| opts.get(index).cloned())
.unwrap_or_default();
let (entry_type, msg_tool_type) = if let Some(typ) = typ {
let entry_type = if typ.is_audio() {
EntryType::Audio
} else {
query_entry_type(&typ)
};
(entry_type, Some(typ.clone()))
(query_entry_type(&typ), Some(typ.clone()))
} else {
let mut buffer = [0; 1024];
let n = reader.read(&mut buffer)?;
reader.rewind()?;
detect_file_type("", &buffer[..n])
};
if entry_type != EntryType::Archive {
return Err(anyhow::anyhow!("不是归档文件"));
}
let msg_tool_type = msg_tool_type.ok_or_else(|| anyhow::anyhow!("无法识别的归档格式"))?;
let builder = BUILDER
.iter()
@@ -570,6 +639,9 @@ fn preview_image_in_archive<'a>(
None,
)?;
if path.contains("|") {
if !archive.is_archive() {
return Err(anyhow::anyhow!("不是归档文件"));
}
let filename = path.split("|").nth(0).unwrap();
let mut entry = archive.open_file_by_name(filename, false)?;
let typ = entry.script_type().map(|t| t.clone());
@@ -592,20 +664,16 @@ fn preview_image_in_archive<'a>(
/// path: /path/to/archive.zip|image.png 预览archive.zip内的image.png,options[0] 会用于打开archive.zip, options[1] 会用于打开image.png(如果需要的话)
/// path: /path/to/archive.zip|inner/archive2.zip|image.png 预览archive2.zip内的image.png,options[0] 会用于打开archive.zip, options[1] 会用于打开archive2.zip, options[2] 会用于打开image.png(如果需要的话)
#[tauri::command]
pub fn preview_image(path: &str, options: Option<Vec<FileOptions>>) -> Result<Vec<u8>, ErrorMsg> {
pub fn preview_image(path: &str, options: Option<Vec<FileOptions>>) -> Result<Response, ErrorMsg> {
if path.contains("|") {
let filename = path.split("|").nth(0).unwrap();
let reader = Box::new(std::io::BufReader::new(File::open(filename).map_err(
|e| ErrorMsg {
typ: ErrorType::NotFound,
msg: format!("无法打开文件: {}", e),
},
)?));
let path = path.splitn(2, "|").nth(1).unwrap();
return preview_image_in_archive(path, reader, filename, options.as_ref(), None, 0)
return CACHE_MANAGER
.lock_blocking()
.preview_image(path, options.as_ref())
.map_err(|e| ErrorMsg {
typ: ErrorType::Other,
msg: format!("预览图片失败: {}", e),
msg: e.to_string(),
}).map(|data| {
Response::new(data)
});
}
let path = std::path::Path::new(path);
@@ -636,5 +704,7 @@ pub fn preview_image(path: &str, options: Option<Vec<FileOptions>>) -> Result<Ve
.map_err(|e| ErrorMsg {
typ: ErrorType::Other,
msg: format!("预览图片失败: {}", e),
}).map(|data| {
Response::new(data)
})
}

View File

@@ -14,6 +14,5 @@ export async function listDirectory(path: string, options?: FileOptions[]): Prom
}
export async function previewImage(path: string, options?: FileOptions[]): Promise<Uint8Array> {
const bytes: number[] = await invoke("preview_image", { path, options: options ?? null });
return new Uint8Array(bytes);
return await invoke("preview_image", { path, options: options ?? null });
}