From 40b7a6072bc0a3abef9270ea18e444013a9e3bf0 Mon Sep 17 00:00:00 2001 From: Lkhsss Date: Sun, 24 Nov 2024 01:38:56 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=A7=E9=87=8F=E9=87=8D=E6=9E=84=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E4=BC=A0=E9=80=92=E9=80=BB=E8=BE=91.=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=B0=91=E9=87=8Fbug.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +- CHANGELOG.md | 44 +++++++++++++++ Cargo.lock | 106 ++++++++++++++++++++++++++++++----- Cargo.toml | 3 +- README.md | 41 -------------- src/clap.rs | 2 +- src/logger.rs | 2 +- src/main.rs | 40 ++++++++++---- src/ncmdump.rs | 146 ++++++++++++++++++++++++++----------------------- 9 files changed, 247 insertions(+), 141 deletions(-) create mode 100644 CHANGELOG.md diff --git a/.gitignore b/.gitignore index a24a40b..420fdb6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ /target -src/main.rs.old -src/lib.rs.bak +src/*.old +src/*.bak /testfile /output \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9be79dd --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,44 @@ +# CHANGELOG +## [1.0.0] - 2024-1-27 +### Features :sparkles: +- 初步完成解密函数。主程序成型 + +## [1.1.1] - 2024-2-1 +### Features :sparkles: +- 完成批量解密 +### Fixed :bug: +- 修正了提取音乐信息会有数据类型错误导致panic的问题 + +## [1.1.2] - 2024-2-5 +### Fixed :bug: + - 修正了提取音乐信息时,部分歌曲信息提取失败的问题 + - 修正了音乐数据解密失败的问题 +## [1.1.3] - 2024-2-6 +### Fixed :bug: + - 修正了部分音乐名称中含有不合法字符时创建文件失败的问题 +## [1.1.4] - 2024-7-14 +### Features :sparkles: +- 增加多线程支持! + > ~~目前固定4线程,还没写命令行参数。可以源代码修改线程数~~ 已于2.1.4版本修复~ +### Fixed +- 优化代码结构 + +## [2.2.4] - 2024-11-17 +### Features :sparkles: +- :ambulance:完整的多线程支持!可自定线程数! +- :ambulance:自动添加封面,解密文件不再需要musictag! +- :sparkles: 完整的命令行参数支持! +- :sparkles: 计时功能! +### Fixed +- :arrow_up: 升级依赖 +- 优化保存文件逻辑,保存时间缩短到毫秒 +### Refactoring +- :hammer: 重构代码! +## [2.2.4] - 2024-11-17 +### Features :sparkles: +- 完整的自动构建流程! + +## [2.3.7] - 2024.11.24 +### Refactoring +- 优化读取逻辑 +- :hammer: 重构代码!大量减少panic! \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 3ec809e..2a4b75f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -220,9 +220,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" [[package]] name = "byteorder" @@ -349,6 +349,19 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width 0.1.14", + "windows-sys 0.52.0", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -357,9 +370,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -420,6 +433,12 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "env_filter" version = "0.1.2" @@ -573,9 +592,9 @@ dependencies = [ [[package]] name = "id3" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55f4e785f2c700217ee82a1c727c720449421742abd5fcb2f1df04e1244760e9" +checksum = "ab55e9dc8caf811048062c5711b338e0582c89504737d5a95c4568f723a46cf3" dependencies = [ "bitflags 2.6.0", "byteorder", @@ -631,6 +650,19 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.17.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width 0.2.0", + "web-time", +] + [[package]] name = "inout" version = "0.1.3" @@ -668,9 +700,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2" [[package]] name = "jobserver" @@ -799,7 +831,7 @@ checksum = "07dcca13d1740c0a665f77104803360da0bdb3323ecce2e93fa2c959a6d52806" [[package]] name = "ncmmiao" -version = "2.3.7" +version = "2.3.8" dependencies = [ "aes", "audiotags", @@ -810,6 +842,7 @@ dependencies = [ "env_logger", "hex", "image", + "indicatif", "lazy_static", "log", "serde", @@ -890,6 +923,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "once_cell" version = "1.20.2" @@ -921,6 +960,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "portable-atomic" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -932,9 +977,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -1214,9 +1259,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.87" +version = "2.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" dependencies = [ "proc-macro2", "quote", @@ -1315,9 +1360,21 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "utf8parse" @@ -1419,6 +1476,16 @@ version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "weezl" version = "0.1.8" @@ -1452,6 +1519,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.59.0" diff --git a/Cargo.toml b/Cargo.toml index 2852010..9e27411 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ncmmiao" -version = "2.3.7" +version = "2.3.8" edition = "2021" authors = ["Lkhsss "] description = "A magic tool convert ncm to flac" @@ -21,6 +21,7 @@ colored = "2.1.0" env_logger = "0.11.1" hex = "0.4.3" image = "0.25.*" +indicatif = "0.17.9" lazy_static = "1.5.0" log = "0.4.20" serde = { version = "1.0.195", features = ["derive"] } diff --git a/README.md b/README.md index e423212..b98a5df 100644 --- a/README.md +++ b/README.md @@ -40,47 +40,6 @@ Options: --- -# CHANGELOG -## [1.0.0] - 2024-1-27 -### Features :sparkles: -- 初步完成解密函数。主程序成型 - -## [1.1.1] - 2024-2-1 -### Features :sparkles: -- 完成批量解密 -### Fixed :bug: -- 修正了提取音乐信息会有数据类型错误导致panic的问题 - -## [1.1.2] - 2024-2-5 -### Fixed :bug: - - 修正了提取音乐信息时,部分歌曲信息提取失败的问题 - - 修正了音乐数据解密失败的问题 -## [1.1.3] - 2024-2-6 -### Fixed :bug: - - 修正了部分音乐名称中含有不合法字符时创建文件失败的问题 -## [1.1.4] - 2024-7-14 -### Features :sparkles: -- 增加多线程支持! - > ~~目前固定4线程,还没写命令行参数。可以源代码修改线程数~~ 已于2.1.4版本修复~ -### Fixed -- 优化代码结构 - -## [2.2.4] - 2024-11-17 -### Features :sparkles: -- :ambulance:完整的多线程支持!可自定线程数! -- :ambulance:自动添加封面,解密文件不再需要musictag! -- :sparkles: 完整的命令行参数支持! -- :sparkles: 计时功能! -### Fixed -- :arrow_up: 升级依赖 -- 优化保存文件逻辑,保存时间缩短到毫秒 -### Refactoring -- :hammer: 重构代码! -## [2.2.4] - 2024-11-17 -### Features :sparkles: -- 完整的自动构建流程! ---- - # 附 - ncm文件结构 |信息|大小|作用| |:-:|:-:|:-:| diff --git a/src/clap.rs b/src/clap.rs index 53e9cd8..cee8b26 100644 --- a/src/clap.rs +++ b/src/clap.rs @@ -3,7 +3,7 @@ use clap::Parser; #[derive(Parser)] #[command(name = "ncmmiao")] #[command(author = "lkhsss")] -#[command(version,about = "一个解密ncm文件的神秘程序", long_about = None)] +#[command(version,about = "一个解密ncm文件的神秘程序 By Lkhsss", long_about = None)] pub struct Cli { /// 并发的最大线程数,默认为4线程 #[arg(short, long)] diff --git a/src/logger.rs b/src/logger.rs index c5ba71e..f49d34f 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -32,7 +32,7 @@ impl Logger { } log::Level::Debug => { let style = buf.default_level_style(log::Level::Debug); - format!("{style}Warn{style:#}") + format!("{style}Debug{style:#}") } log::Level::Trace => { let style = buf.default_level_style(log::Level::Trace); diff --git a/src/main.rs b/src/main.rs index c799105..e9de838 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,10 @@ +use std::{ops::Add, path::Path, sync::{Arc, Mutex}}; use ::clap::Parser; #[allow(unused_imports)] use log::{error, info, warn}; -use std::path::Path; +use colored::Colorize; + use walkdir::WalkDir; //遍历目录 mod clap; @@ -70,27 +72,43 @@ fn main() { } } let taskcount = undumpfile.len(); + let successful = Arc::new(Mutex::new(0)); if taskcount == 0 { error!("没有找到有效文件。使用-i参数输入需要解密的文件或文件夹。") } else { // 初始化线程池 let pool = threadpool::Pool::new(max_workers); - info!("启用{}线程",max_workers); + info!("启用{}线程", max_workers); for filepath in undumpfile { let output = outputdir.clone(); + let successful = Arc::clone(&successful); pool.execute(move || { - Ncmfile::new(filepath.as_str()) - .unwrap() - .dump(Path::new(&output)) - .unwrap(); + match Ncmfile::new(filepath.as_str()) { + Ok(mut n) => match n.dump(Path::new(&output)) { + Ok(_) => { + let mut num = successful.lock().unwrap(); + *num += 1;}, + Err(e) => error!("[{}]解密失败: {}", filepath.yellow(), e), + }, + Err(e) => error!("[{}]解密失败: {}", filepath.yellow(), e), + } }); } } let timecount = timer.compare(); - if timecount > 2000 { - info!("解密{}个文件,共计用时{}秒", taskcount, timecount / 1000) - } else { - info!("解密{}个文件,共计用时{}毫秒", taskcount, timecount) - } + let showtime = || { + if timecount > 2000 { + format!("共计用时{}秒", timecount / 1000) + } else { + format!("共计用时{}毫秒", timecount) + } + }; + let successful = *successful.lock().unwrap(); + info!( + "成功解密{}个文件,{}个文件解密失败,{}", + successful.to_string().bright_green(), + (taskcount - successful).to_string().bright_red(), + showtime() + ) } diff --git a/src/ncmdump.rs b/src/ncmdump.rs index 8235a50..d329fff 100644 --- a/src/ncmdump.rs +++ b/src/ncmdump.rs @@ -11,7 +11,7 @@ use log::{debug, error, info, trace, warn}; use serde_derive::{Deserialize, Serialize}; use serde_json::{self, Value}; use std::fs::{self, File}; -use std::io::{BufReader, BufWriter, Error, ErrorKind, Read, Seek, SeekFrom, Write}; +use std::io::{BufReader, BufWriter, Read, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; use std::str::from_utf8; use std::vec; @@ -39,14 +39,17 @@ pub struct Ncmfile { pub position: u64, } impl Ncmfile { - pub fn new(filepath: &str) -> Result { - let file = File::open(filepath)?; + pub fn new(filepath: &str) -> Result { + let file = match File::open(filepath) { + Ok(f) => f, + Err(_) => return Err(NcmError::FileReadError), + }; let path = Path::new(filepath); let fullfilename = path.file_name().unwrap().to_str().unwrap().to_string(); let size = file.metadata().unwrap().len(); let filename = match Path::new(&filepath).file_stem() { Some(f) => f.to_str().unwrap().to_string(), - None => panic!("获取文件名失败"), + None => return Err(NcmError::CannotReadFileName), }; Ok(Ncmfile { file, @@ -60,17 +63,14 @@ impl Ncmfile { /// /// 该函数可以记录上次读取的位置,下次读取时从上次读取的位置开始 /// - length 想要读取的长度 - pub fn seekread(&mut self, length: u64) -> Result, std::io::Error> { + pub fn seekread(&mut self, length: u64) -> Result, NcmError> { if self.position + length > self.size { - return Err(Error::new( - ErrorKind::UnexpectedEof, - "无法读取!读取长度大于剩余文件大小!", - )); + return Err(NcmError::FileReadError); } else { let mut reader = BufReader::new(&self.file); - reader.seek(SeekFrom::Start(self.position))?; + let _ = reader.seek(SeekFrom::Start(self.position)); let mut buf = vec![0; length as usize]; - reader.read_exact(&mut buf)?; + let _ = reader.read_exact(&mut buf); self.position += length; Ok(buf[..].to_vec()) } @@ -82,17 +82,14 @@ impl Ncmfile { /// - offset 开始位置 /// - length 想要读取的长度 #[allow(dead_code)] - pub fn seekread_from(&mut self, offset: u64, length: u64) -> Result, std::io::Error> { + pub fn seekread_from(&mut self, offset: u64, length: u64) -> Result, NcmError> { if self.position + length > self.size { - return Err(Error::new( - ErrorKind::UnexpectedEof, - "无法读取!读取长度大于剩余文件大小!", - )); + return Err(NcmError::FileReadError); } else { let mut reader = BufReader::new(&self.file); - reader.seek(SeekFrom::Start(offset))?; + let _ = reader.seek(SeekFrom::Start(offset)); let mut buf = vec![0; length as usize]; - reader.read_exact(&mut buf)?; + let _ = reader.read_exact(&mut buf); self.position = offset + length; Ok(buf[..].to_vec()) } @@ -129,12 +126,9 @@ impl Ncmfile { } } /// 跳过某些数据 - pub fn skip(&mut self, length: u64) -> Result<(), std::io::Error> { + pub fn skip(&mut self, length: u64) -> Result<(), NcmError> { if self.position + length > self.size { - return Err(Error::new( - ErrorKind::UnexpectedEof, - "无法跳过!跳过长度大于剩余文件大小!", - )); + return Err(NcmError::FileReadError); } else { self.position += length; Ok(()) @@ -150,14 +144,13 @@ impl Ncmfile { /// 解密函数 #[allow(unused_assignments)] - pub fn dump(&mut self, outputdir: &Path) -> Result<(), MyError> { + pub fn dump(&mut self, outputdir: &Path) -> Result<(), NcmError> { info!("开始解密[{}]文件", self.fullfilename.yellow()); // 获取magic header 。应为CTENFDAM let magic_header = match self.seekread(8) { Ok(header) => header, Err(_e) => { - error!("读取magic header失败"); - return Err(MyError::MagicHeaderError); + return Err(NcmError::FileReadError); } }; @@ -166,27 +159,21 @@ impl Ncmfile { Ok(header) => { if header != "CTENFDAM" { // 传播错误至dump - return Err(MyError::MagicHeaderError); - } else { - trace!("[{}]为ncm格式文件", self.fullfilename.yellow()); - debug!("magic header: {}", header); + return Err(NcmError::NotNcmFile); } } // 传播错误至dump - Err(_e) => return Err(MyError::MagicHeaderError), + Err(_e) => return Err(NcmError::NotNcmFile), } // 跳过2字节 trace!("跳过2字节"); - match self.skip(2) { - Ok(_) => (), - Err(_e) => return Err(MyError::FileSkipError), - }; + self.skip(2)?; trace!("获取RC4密钥长度"); //小端模式读取RC4密钥长度 正常情况下应为128 let key_length = u32::from_le_bytes(self.seekread(4).unwrap().try_into().unwrap()) as u64; - debug!("RC4密钥长度为:{}", key_length); + // debug!("RC4密钥长度为:{}", key_length); //读取密钥 开头应为 neteasecloudmusic trace!("读取RC4密钥"); @@ -194,55 +181,58 @@ impl Ncmfile { //aes128解密 let key_data = &aes128_to_slice(&KEY_CORE, Self::parse_key(&mut key_data[..])); //先把密钥按照字节进行0x64异或 // RC4密钥 - let key_data = unpad(&key_data[..])[17..].to_vec(); + let key_data = unpad(&key_data[..])[17..].to_vec(); //去掉neteasecloudmusic //读取meta信息的数据大小 trace!("获取meta信息数据大小"); - let meta_length = u32::from_le_bytes(self.seekread(4).unwrap().try_into().unwrap()) as u64; + let meta_length = u32::from_le_bytes(self.seekread(4)?.try_into().unwrap()) as u64; // 读取meta信息 trace!("读取meta信息"); let meta_data = { - let mut meta_data = self.seekread(meta_length).unwrap(); //读取源数据 - //字节对0x63进行异或。 + let mut meta_data = self.seekread(meta_length)?; //读取源数据 + //字节对0x63进行异或。 for i in 0..meta_data.len() { meta_data[i] ^= 0x63; } // base64解密 let mut decode_data = Vec::::new(); - let _ = &base64::engine::general_purpose::STANDARD + let _ = match &base64::engine::general_purpose::STANDARD .decode_vec(&mut meta_data[22..], &mut decode_data) - .unwrap(); + { + Err(_) => return Err(NcmError::CannotReadMetaInfo), + _ => (), + }; // aes128解密 let aes_data = aes128_to_slice(&KEY_META, &decode_data); // unpadding - let json_data = String::from_utf8(unpad(&aes_data)[6..].to_vec()).unwrap(); + let json_data = match String::from_utf8(unpad(&aes_data)[6..].to_vec()) { + Ok(o) => o, + Err(_) => return Err(NcmError::CannotReadMetaInfo), + }; debug!("json_data: {}", json_data); - let data: Value = serde_json::from_str(&json_data[..]).unwrap(); //解析json数据 + let data: Value = match serde_json::from_str(&json_data[..]){Ok(o) => o, + Err(_) => return Err(NcmError::CannotReadMetaInfo), + }; //解析json数据 data }; // 跳过4个字节的校验码 trace!("读取校验码"); - let _crc32 = u32::from_le_bytes(self.seekread(4).unwrap().try_into().unwrap()) as u64; + // let _crc32 = u32::from_le_bytes(self.seekread(4).unwrap().try_into().unwrap()) as u64; + self.skip(4)?; // 跳过5个字节 trace!("跳过5个字节"); - self.skip(5).unwrap(); + self.skip(5)?; // 获取图片数据的大小 trace!("获取图片数据的大小"); let image_data_length = - u32::from_le_bytes(self.seekread(4).unwrap().try_into().unwrap()) as u64; + u32::from_le_bytes(self.seekread(4)?.try_into().unwrap()) as u64; // 读取图片,并写入文件当中 - trace!("暂不需要保存图片,跳过{}字节", image_data_length); - let image_data = self.seekread(image_data_length).unwrap(); //读取图片数据 - // let _ = self.skip(image_data_length); //暂不需要保存图片,直接跳过这些字节就好 - //保存图片 - // trace!("保存图片"); - // let mut file = File::create(format!("TEST.jpg",)).unwrap(); - // file.write_all(&image_data).unwrap(); + let image_data = self.seekread(image_data_length)?; //读取图片数据 trace!("组成密码盒"); let key_box = { @@ -264,7 +254,7 @@ impl Ncmfile { key_box[temp as usize] = swap as u8; last_byte = temp; } - let key_box = key_box.clone(); + // let key_box = key_box.clone(); key_box }; @@ -347,16 +337,19 @@ impl Ncmfile { // let filename = standardize_filename(filename); debug!("文件名:{}", filename.yellow()); //链级创建输出目录 - fs::create_dir_all(outputdir).unwrap(); + match fs::create_dir_all(outputdir){Err(_)=>return Err(NcmError::FileWriteError),_=>()}; outputdir.join(filename) }; debug!("文件路径: {:?}", path); - self.save(&path, music_data); + self.save(&path, music_data)?; { // 保存封面 - let mut tag = Tag::new().read_from_path(&path).unwrap(); + let mut tag = match Tag::new().read_from_path(&path){ + Ok(o)=>o, + Err(_)=>return Err(NcmError::CoverCannotSave) + }; let cover = Picture { mime_type: MimeType::Jpeg, data: &image_data, @@ -366,7 +359,7 @@ impl Ncmfile { } info!( - "[{}]文件已保存到: {}", + "[{}] 文件已保存到: {}", self.filename.yellow(), path.to_str().unwrap().bright_cyan() ); @@ -377,12 +370,19 @@ impl Ncmfile { ); Ok(()) } - fn save(&mut self, path: &PathBuf, data: Vec) { - let music_file = File::create(path).unwrap(); + fn save(&mut self, path: &PathBuf, data: Vec)->Result<(),NcmError> { + let music_file = match File::create(path){ + Ok(o)=>o, + Err(_)=>return Err(NcmError::FileWriteError) + }; let mut writer = BufWriter::new(music_file); let _ = writer.write_all(&data); // 关闭文件 - writer.flush().unwrap(); + match writer.flush(){ + Ok(o)=>o, + Err(_)=>return Err(NcmError::FileWriteError) + }; + Ok(()) } } @@ -514,6 +514,7 @@ fn aes128_to_slice(key: &[u8], blocks: &[u8]) -> Vec { /// 符号一一对应: /// - \ / * ? " : < > | /// - _ _ * ? " : ⟨ ⟩ _ +#[allow(dead_code)] fn standardize_filename(old_fullfilename: String) -> String { trace!("格式化文件名"); let mut new_fullfilename = String::from(old_fullfilename); @@ -534,8 +535,11 @@ fn unpad(data: &[u8]) -> Vec { #[derive(Debug)] #[allow(dead_code)] -pub enum MyError { - MagicHeaderError, +pub enum NcmError { + NotNcmFile, + CannotReadFileName, + CannotReadMetaInfo, + CoverCannotSave, FileReadError, FileSkipError, FileWriteError, @@ -543,14 +547,18 @@ pub enum MyError { FileNotFoundError, } -impl std::error::Error for MyError {} +impl std::error::Error for NcmError {} -impl std::fmt::Display for MyError { +impl std::fmt::Display for NcmError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Self::MagicHeaderError => write!(f, "文件不为NCM格式"), - Self::FileReadError => write!(f, "文件读取错误"), - Self::FileWriteError => write!(f, "文件写入错误"), + Self::NotNcmFile => write!(f, "该文件不为NCM格式"), + Self::CannotReadFileName => write!(f, "无法读取文件名称"), + Self::CannotReadMetaInfo => write!(f, "无法读取歌曲元信息"), + Self::CoverCannotSave => write!(f, "封面无法保存"), + + Self::FileReadError => write!(f, "读取文件时发生错误"), + Self::FileWriteError => write!(f, "写入文件时错误"), Self::FullFilenameError => write!(f, "文件名不符合规范"), _ => write!(f, "未知错误"), }