- 修改默认线程数为cpu核心数
- 修改多线程通信为crossbeam-channel库,增加通讯性能 - ⬆️ 升级依赖 - 🔨 优化解密算法,提高解密效率
This commit is contained in:
@ -5,7 +5,7 @@ use clap::Parser;
|
||||
#[command(author = "lkhsss")]
|
||||
#[command(version,about = "一个解密ncm文件的神秘程序 By Lkhsss", long_about = None)]
|
||||
pub struct Cli {
|
||||
/// 并发的最大线程数,默认为8线程
|
||||
/// 并发的最大线程数,默认为cpu核心数
|
||||
#[arg(short, long)]
|
||||
pub workers: Option<usize>,
|
||||
/// 需要解密的文件夹或文件
|
||||
@ -23,4 +23,7 @@ pub struct Cli {
|
||||
/// 自动打开输出目录
|
||||
#[arg(short, long, name = "自动打开输出目录")]
|
||||
pub autoopen: bool,
|
||||
|
||||
#[arg(short, long, action = clap::ArgAction::Count)]
|
||||
pub debug: u8,
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use colored::Color::{Cyan, Green, Red, Yellow,Magenta};
|
||||
use colored::Colorize;
|
||||
use indicatif::MultiProgress;
|
||||
use log::{LevelFilter, Log, Metadata, Record, SetLoggerError};
|
||||
use log::{Log, Metadata, Record, SetLoggerError};
|
||||
use std::sync::Arc;
|
||||
|
||||
// 自定义Logger,将日志发送到MultiProgress
|
||||
@ -42,10 +42,6 @@ pub fn init_logger() -> Result<(), SetLoggerError> {
|
||||
mp: crate::MP.clone(),
|
||||
};
|
||||
log::set_boxed_logger(Box::new(logger))?;
|
||||
if cfg!(debug_assertions) {
|
||||
log::set_max_level(LevelFilter::Trace);//FIXME
|
||||
} else {
|
||||
log::set_max_level(LevelFilter::Info);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
70
src/main.rs
70
src/main.rs
@ -1,20 +1,13 @@
|
||||
#![deny(clippy::all)]
|
||||
use ::clap::Parser;
|
||||
use colored::{Color, Colorize};
|
||||
use crossbeam_channel::{bounded, Sender};
|
||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||
use lazy_static::lazy_static;
|
||||
use log::{error, info, trace, warn};
|
||||
use messager::Message;
|
||||
use rayon::ThreadPoolBuilder;
|
||||
use log::{error, info, warn, LevelFilter};
|
||||
use messager::{Message, Messager, Signals};
|
||||
use std::process::exit;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
path::Path,
|
||||
sync::{
|
||||
mpsc::{self, Sender},
|
||||
Arc, Mutex,
|
||||
},
|
||||
};
|
||||
use std::{path::Path, sync::Arc};
|
||||
|
||||
mod apperror;
|
||||
mod clap;
|
||||
@ -29,7 +22,7 @@ mod time;
|
||||
use apperror::AppError;
|
||||
use ncmdump::Ncmfile;
|
||||
use time::TimeCompare;
|
||||
const DEFAULT_MAXWORKER: usize = 8;
|
||||
|
||||
|
||||
fn main() -> Result<(), AppError> {
|
||||
let timer = match TimeCompare::new() {
|
||||
@ -49,6 +42,8 @@ fn main() -> Result<(), AppError> {
|
||||
|
||||
let cli = clap::Cli::parse();
|
||||
|
||||
//获取cpu核心数
|
||||
let cpus = num_cpus::get();
|
||||
// 最大线程数
|
||||
let max_workers = match cli.workers {
|
||||
Some(n) => {
|
||||
@ -58,7 +53,7 @@ fn main() -> Result<(), AppError> {
|
||||
1
|
||||
}
|
||||
}
|
||||
None => DEFAULT_MAXWORKER,
|
||||
None => cpus,//默认使用cpu核心数作为线程数
|
||||
};
|
||||
//输入目录
|
||||
let input = cli.input;
|
||||
@ -69,11 +64,23 @@ fn main() -> Result<(), AppError> {
|
||||
if forcesave {
|
||||
warn!("文件{}已开启!", "强制覆盖".bright_red())
|
||||
}
|
||||
let level = match cli.debug {
|
||||
0 | 3 => LevelFilter::Info,
|
||||
1 => LevelFilter::Error,
|
||||
2 => LevelFilter::Warn,
|
||||
4 => LevelFilter::Debug,
|
||||
5 => LevelFilter::Trace,
|
||||
_ => LevelFilter::Off,
|
||||
};
|
||||
info!("日志等级:{}", level.to_string());
|
||||
log::set_max_level(level);
|
||||
|
||||
let undumpfile = pathparse::pathparse(input); // 该列表将存入文件的路径
|
||||
|
||||
let taskcount = undumpfile.len();
|
||||
let mut success_count = 0; //成功任务数
|
||||
let mut ignore_count = 0; //忽略的任务数
|
||||
let mut failure_count = 0; //发生错误的
|
||||
|
||||
if taskcount == 0 {
|
||||
error!("没有找到有效文件。使用-i参数输入需要解密的文件或文件夹。");
|
||||
@ -81,40 +88,34 @@ fn main() -> Result<(), AppError> {
|
||||
};
|
||||
// 初始化线程池
|
||||
let pool = threadpool::Pool::new(max_workers);
|
||||
// let threadpoolbuilder = ThreadPoolBuilder::new()
|
||||
// .num_threads(max_workers)
|
||||
// .build()
|
||||
// .unwrap(); //初始化线程池
|
||||
// //FIXME暂时unwrap
|
||||
|
||||
info!(
|
||||
"将启用{}线程",
|
||||
max_workers.to_string().color(Color::BrightGreen)
|
||||
);
|
||||
// 初始化通讯
|
||||
let (tx, rx) = mpsc::channel();
|
||||
// let (tx, rx) = mpsc::channel();
|
||||
let (tx, rx) = bounded(taskcount * 6);
|
||||
|
||||
// 循环开始
|
||||
for filepath in undumpfile {
|
||||
let output = outputdir.clone();
|
||||
let senderin: Sender<messager::Message> = tx.clone();
|
||||
let senderon: Sender<messager::Message> = tx.clone();
|
||||
let senderin: Sender<Message> = tx.clone();
|
||||
let senderon: Sender<Message> = tx.clone();
|
||||
// 多线程
|
||||
pool.execute(move || match Ncmfile::new(filepath.as_str()) {
|
||||
Ok(mut n) => match n.dump(Path::new(&output), senderin, forcesave) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
let messager = messager::Messager::new(n.fullfilename, senderon);
|
||||
let _ = messager.send(messager::Signals::Err(e));
|
||||
let messager = Messager::new(n.fullfilename, senderon);
|
||||
let _ = messager.send(Signals::Err(e));
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
let messager = messager::Messager::new(filepath, senderon);
|
||||
let _ = messager.send(messager::Signals::Err(e));
|
||||
let messager = Messager::new(filepath, senderon);
|
||||
let _ = messager.send(Signals::Err(e));
|
||||
}
|
||||
});
|
||||
// threadpoolbuilder.install(|| {
|
||||
// //TODO
|
||||
// })
|
||||
}
|
||||
//循环到此结束
|
||||
//进度条
|
||||
@ -134,12 +135,14 @@ fn main() -> Result<(), AppError> {
|
||||
// 接受消息!!!!!!!!!!
|
||||
for messages in rx {
|
||||
match messages.signal {
|
||||
messager::Signals::End | messager::Signals::Err(_) => success_count += 1,
|
||||
Signals::End => success_count += 1,
|
||||
Signals::Err(AppError::ProtectFile) => ignore_count += 1,
|
||||
Signals::Err(_) => failure_count += 1,
|
||||
_ => (),
|
||||
}
|
||||
if success_count < taskcount {
|
||||
if (success_count+ignore_count+failure_count) < taskcount {
|
||||
progressbar.inc(1);
|
||||
messages.log(); //发送log
|
||||
// messages.log(); //发送log
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -155,9 +158,10 @@ fn main() -> Result<(), AppError> {
|
||||
}
|
||||
};
|
||||
info!(
|
||||
"成功解密{}个文件,{}个文件解密失败,{}",
|
||||
"成功解密{}个文件,跳过{}个文件,{}个文件解密失败,{}",
|
||||
success_count.to_string().bright_green(),
|
||||
(taskcount - success_count).to_string().bright_red(),
|
||||
ignore_count.to_string().purple(),
|
||||
failure_count.to_string().bright_red(),
|
||||
showtime()
|
||||
);
|
||||
|
||||
|
||||
@ -1,39 +1,35 @@
|
||||
use colored::Colorize;
|
||||
use log::{error, info, warn};
|
||||
|
||||
use crate::{messager, ncmdump,AppError};
|
||||
|
||||
use crate::{messager, AppError};
|
||||
use std::fmt::Debug;
|
||||
use std::sync::mpsc;
|
||||
// use
|
||||
pub struct Messager {
|
||||
name: String,
|
||||
sender: mpsc::Sender<messager::Message>,
|
||||
sender: crossbeam_channel::Sender<messager::Message>,
|
||||
}
|
||||
|
||||
pub struct Message {
|
||||
pub name: String,
|
||||
pub signal: Signals,
|
||||
}
|
||||
impl Message {
|
||||
// 定义一个公共方法 log,用于记录不同信号状态下的日志信息
|
||||
pub fn log(&self) {
|
||||
let loginfo = match &self.signal {
|
||||
Signals::Start => "读取文件",
|
||||
Signals::GetMetaInfo => "解密歌曲元信息",
|
||||
Signals::GetCover => "解密封面图片数据",
|
||||
Signals::Decrypt => "解密歌曲信息",
|
||||
Signals::Save => "保存文件",
|
||||
Signals::End => "成功!",
|
||||
Signals::Err(e) => &e.to_string(),
|
||||
};
|
||||
match &self.signal {
|
||||
Signals::Err(e) => match e {
|
||||
AppError::ProtectFile => warn!("[{}] {}", self.name.cyan(), loginfo),
|
||||
_ => error!("[{}] {}", self.name.cyan(), loginfo),
|
||||
},
|
||||
_ => info!("[{}] {}", self.name.cyan(), loginfo),
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl Message {
|
||||
// // 定义一个公共方法 log,用于记录不同信号状态下的日志信息
|
||||
// pub fn log(&self) {
|
||||
|
||||
// match &self.signal {
|
||||
// Signals::Err(e) => match e {
|
||||
// AppError::ProtectFile => warn!("[{}] {}", self.name.cyan(), "强制覆盖已关闭。不保存文件"),
|
||||
// _ => error!("[{}] {}", self.name.cyan(), e),
|
||||
// },
|
||||
// Signals::Start => trace!("开始读取文件"),
|
||||
// Signals::GetMetaInfo => trace!("解密歌曲元信息"),
|
||||
// Signals::GetCover => trace!("解密封面图片数据"),
|
||||
// Signals::Decrypt => trace!("解密歌曲信息"),
|
||||
// Signals::Save => info!("保存文件"),
|
||||
// Signals::End => trace!("解密流程结束")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
#[derive(PartialEq)]
|
||||
pub enum Signals {
|
||||
Start,
|
||||
@ -46,10 +42,10 @@ pub enum Signals {
|
||||
}
|
||||
|
||||
impl Messager {
|
||||
pub fn new(name: String, sender: mpsc::Sender<messager::Message>) -> Self {
|
||||
pub fn new(name: String, sender: crossbeam_channel::Sender<messager::Message>) -> Self {
|
||||
Self { name, sender }
|
||||
}
|
||||
pub fn send(&self, s: Signals) -> Result<(), std::sync::mpsc::SendError<messager::Message>> {
|
||||
pub fn send(&self, s: Signals) -> Result<(), crossbeam_channel::SendError<messager::Message>> {
|
||||
self.sender.send(Message {
|
||||
name: self.name.clone(),
|
||||
signal: s,
|
||||
|
||||
111
src/ncmdump.rs
111
src/ncmdump.rs
@ -6,8 +6,7 @@ use aes::Aes128;
|
||||
use audiotags::{MimeType, Picture, Tag};
|
||||
use base64::{self, Engine};
|
||||
use colored::*;
|
||||
#[allow(unused_imports)]
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use log::{debug, info, trace};
|
||||
use messager::Signals;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde_json::{self, Value};
|
||||
@ -16,7 +15,6 @@ use std::fs::{self, File};
|
||||
use std::io::{BufReader, BufWriter, Read, Seek, SeekFrom, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::from_utf8;
|
||||
use std::sync::mpsc;
|
||||
use std::vec;
|
||||
|
||||
// lazy_static! {
|
||||
@ -26,9 +24,13 @@ use std::vec;
|
||||
// }
|
||||
|
||||
// 原KEY_CORE数据:687A4852416D736F356B496E62617857
|
||||
const NEW_KEY_CORE:[u8;16] = [0x68, 0x7A, 0x48, 0x52, 0x41, 0x6D, 0x73, 0x6F, 0x35, 0x6B, 0x49, 0x6E, 0x62, 0x61, 0x78, 0x57];
|
||||
const NEW_KEY_CORE: [u8; 16] = [
|
||||
0x68, 0x7A, 0x48, 0x52, 0x41, 0x6D, 0x73, 0x6F, 0x35, 0x6B, 0x49, 0x6E, 0x62, 0x61, 0x78, 0x57,
|
||||
];
|
||||
// 原KEY_META数据:2331346C6A6B5F215C5D2630553C2728
|
||||
const NEW_KEY_META:[u8;16]=[0x23, 0x31, 0x34, 0x6C, 0x6A, 0x6B, 0x5F, 0x21, 0x5C, 0x5D, 0x26, 0x30, 0x55, 0x3C, 0x27, 0x28];
|
||||
const NEW_KEY_META: [u8; 16] = [
|
||||
0x23, 0x31, 0x34, 0x6C, 0x6A, 0x6B, 0x5F, 0x21, 0x5C, 0x5D, 0x26, 0x30, 0x55, 0x3C, 0x27, 0x28,
|
||||
];
|
||||
#[derive(Debug)]
|
||||
#[allow(unused_variables)]
|
||||
pub struct Ncmfile {
|
||||
@ -80,7 +82,7 @@ impl Ncmfile {
|
||||
/// - length 想要读取的长度
|
||||
pub fn seekread(&mut self, length: u64) -> Result<Vec<u8>, AppError> {
|
||||
if self.position + length > self.size {
|
||||
return Err(AppError::FileReadError);
|
||||
Err(AppError::FileReadError)
|
||||
} else {
|
||||
let mut reader = BufReader::new(&self.file);
|
||||
let _ = reader.seek(SeekFrom::Start(self.position));
|
||||
@ -100,7 +102,7 @@ impl Ncmfile {
|
||||
#[allow(dead_code)]
|
||||
pub fn seekread_from(&mut self, offset: u64, length: u64) -> Result<Vec<u8>, AppError> {
|
||||
if self.position + length > self.size {
|
||||
return Err(AppError::FileReadError);
|
||||
Err(AppError::FileReadError)
|
||||
} else {
|
||||
let mut reader = BufReader::new(&self.file);
|
||||
let _ = reader.seek(SeekFrom::Start(offset));
|
||||
@ -122,7 +124,7 @@ impl Ncmfile {
|
||||
pub fn seekread_no_error(&mut self, length: u64) -> Vec<u8> {
|
||||
if self.position + length > self.size {
|
||||
if self.position >= self.size {
|
||||
return vec![];
|
||||
vec![]
|
||||
} else {
|
||||
let mut reader = BufReader::new(&self.file);
|
||||
let _ = reader.seek(SeekFrom::Start(self.position));
|
||||
@ -130,7 +132,7 @@ impl Ncmfile {
|
||||
let mut buf: Vec<u8> = vec![0; (self.size - self.position) as usize];
|
||||
let _ = reader.read_exact(&mut buf);
|
||||
self.position += length;
|
||||
return buf[..].to_vec();
|
||||
buf[..].to_vec()
|
||||
}
|
||||
} else {
|
||||
let mut reader = BufReader::new(&self.file);
|
||||
@ -144,7 +146,7 @@ impl Ncmfile {
|
||||
/// 跳过某些数据
|
||||
pub fn skip(&mut self, length: u64) -> Result<(), AppError> {
|
||||
if self.position + length > self.size {
|
||||
return Err(AppError::FileReadError);
|
||||
Err(AppError::FileReadError)
|
||||
} else {
|
||||
self.position += length;
|
||||
Ok(())
|
||||
@ -152,8 +154,8 @@ impl Ncmfile {
|
||||
}
|
||||
///按字节进行0x64异或。
|
||||
fn parse_key(key: &mut [u8]) -> &[u8] {
|
||||
for i in 0..key.len() {
|
||||
key[i] ^= 0x64;
|
||||
for item in &mut *key {
|
||||
*item ^= 0x64;
|
||||
}
|
||||
key
|
||||
}
|
||||
@ -175,7 +177,7 @@ impl Ncmfile {
|
||||
fn is_ncm(data: Vec<u8>) -> Result<(), AppError> {
|
||||
let header = from_utf8(&data).map_err(|_| AppError::NotNcmFile)?;
|
||||
if header != "CTENFDAM" {
|
||||
return Err(AppError::NotNcmFile);
|
||||
Err(AppError::NotNcmFile)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
@ -192,13 +194,12 @@ impl Ncmfile {
|
||||
pub fn dump(
|
||||
&mut self,
|
||||
outputdir: &Path,
|
||||
tx: mpsc::Sender<messager::Message>,
|
||||
tx: crossbeam_channel::Sender<messager::Message>,
|
||||
force_save: bool,
|
||||
) -> Result<(), AppError> {
|
||||
let messager = messager::Messager::new(self.fullfilename.clone(), tx);
|
||||
let _ = messager.send(Signals::Start);
|
||||
//TODO 通讯合法化
|
||||
// info!("开始解密[{}]文件", self.fullfilename.yellow());
|
||||
|
||||
// 获取magic header 应为CTENFDAM
|
||||
trace!("读取magic header");
|
||||
let magic_header = self.seekread(8)?;
|
||||
@ -217,15 +218,16 @@ impl Ncmfile {
|
||||
self.seekread(4)?
|
||||
.try_into()
|
||||
.map_err(|_| AppError::FileReadError)?,
|
||||
) as u64;//数据长度不够只能使用u32 然后转化为u64
|
||||
// debug!("RC4密钥长度为:{}", key_length);
|
||||
) as u64; //数据长度不够只能使用u32 然后转化为u64
|
||||
// debug!("RC4密钥长度为:{}", key_length);
|
||||
|
||||
//读取密钥 开头应为 neteasecloudmusic
|
||||
trace!("读取RC4密钥");
|
||||
let mut key_data = self.seekread(key_length)?;
|
||||
//aes128解密
|
||||
let key_data = &aes128_to_slice(&NEW_KEY_CORE, Self::parse_key(&mut key_data[..]).to_vec())?; //先把密钥按照字节进行0x64异或
|
||||
// RC4密钥
|
||||
let key_data =
|
||||
&aes128_to_slice(&NEW_KEY_CORE, Self::parse_key(&mut key_data[..]).to_vec())?; //先把密钥按照字节进行0x64异或
|
||||
// RC4密钥
|
||||
let key_data = Self::unpad(&key_data[..])[17..].to_vec(); //去掉neteasecloudmusic
|
||||
|
||||
//读取meta信息的数据大小
|
||||
@ -242,16 +244,16 @@ impl Ncmfile {
|
||||
let meta_data = {
|
||||
let mut meta_data = self.seekread(meta_length)?; //读取源数据
|
||||
//字节对0x63进行异或。
|
||||
for i in 0..meta_data.len() {
|
||||
meta_data[i] ^= 0x63;
|
||||
for item in &mut meta_data {
|
||||
*item ^= 0x63;
|
||||
}
|
||||
// base64解密
|
||||
let mut decode_data = Vec::<u8>::new();
|
||||
let _ = match &base64::engine::general_purpose::STANDARD
|
||||
if base64::engine::general_purpose::STANDARD
|
||||
.decode_vec(&mut meta_data[22..], &mut decode_data)
|
||||
.is_err()
|
||||
{
|
||||
Err(_) => return Err(AppError::CannotReadMetaInfo),
|
||||
_ => (),
|
||||
return Err(AppError::CannotReadMetaInfo);
|
||||
};
|
||||
// aes128解密
|
||||
let aes_data = aes128_to_slice(&NEW_KEY_META, decode_data)?;
|
||||
@ -284,10 +286,9 @@ impl Ncmfile {
|
||||
// let filename = standardize_filename(filename);
|
||||
debug!("文件名:{}", filename.yellow());
|
||||
//链级创建输出目录
|
||||
match fs::create_dir_all(outputdir) {
|
||||
Err(_) => return Err(AppError::FileWriteError),
|
||||
_ => (),
|
||||
};
|
||||
if fs::create_dir_all(outputdir).is_err() {
|
||||
return Err(AppError::FileWriteError);
|
||||
}
|
||||
outputdir.join(filename)
|
||||
};
|
||||
|
||||
@ -323,7 +324,7 @@ impl Ncmfile {
|
||||
trace!("组成密码盒");
|
||||
let key_box = {
|
||||
let key_length = key_data.len();
|
||||
let key_data = Vec::from(key_data);
|
||||
// let key_data = Vec::from(key_data);
|
||||
let mut key_box = (0..=255).collect::<Vec<u8>>();
|
||||
let mut temp = 0;
|
||||
let mut last_byte = 0;
|
||||
@ -331,7 +332,7 @@ impl Ncmfile {
|
||||
|
||||
for i in 0..=255 {
|
||||
let swap = key_box[i as usize] as u64;
|
||||
temp = (swap + last_byte as u64 + key_data[key_offset as usize] as u64) & 0xFF;
|
||||
temp = (swap + last_byte + key_data[key_offset] as u64) & 0xFF;
|
||||
key_offset += 1;
|
||||
if key_offset >= key_length {
|
||||
key_offset = 0;
|
||||
@ -357,7 +358,7 @@ impl Ncmfile {
|
||||
let j = i & 0xFF;
|
||||
|
||||
chunk[i - 1] ^= key_box[(key_box[j] as usize
|
||||
+ key_box[(key_box[j as usize] as usize + j) & 0xff] as usize)
|
||||
+ key_box[(key_box[j] as usize + j) & 0xff] as usize)
|
||||
& 0xff]
|
||||
// chunk[i - 1] ^= key_box[(key_box[j] + key_box[(key_box[j as usize] as usize + j as usize) & 0xFF]) & 0xFF];
|
||||
}
|
||||
@ -385,7 +386,7 @@ impl Ncmfile {
|
||||
};
|
||||
tag.set_album_cover(cover); //添加封面
|
||||
let _ = tag
|
||||
.write_to_path(&path.to_str().ok_or(AppError::SaveError)?)
|
||||
.write_to_path(path.to_str().ok_or(AppError::SaveError)?)
|
||||
.map_err(|_| AppError::SaveError); //保存
|
||||
}
|
||||
|
||||
@ -464,7 +465,9 @@ pub struct Key {
|
||||
|
||||
fn convert_to_generic_arrays(input: &[u8]) -> Result<Vec<GenericArray<u8, U16>>, AppError> {
|
||||
// 确保输入的长度是16的倍数
|
||||
if input.len() % 16 == 0 {}
|
||||
if input.len() % 16 != 0 {
|
||||
return Err(AppError::FileDataError);
|
||||
}
|
||||
|
||||
Ok(input
|
||||
.chunks(16)
|
||||
@ -484,7 +487,7 @@ fn aes128_to_slice<T: AsRef<[u8]>>(key: &T, blocks: Vec<u8>) -> Result<Vec<u8>,
|
||||
let mut blocks = convert_to_generic_arrays(&blocks)?;
|
||||
|
||||
// 初始化密钥
|
||||
let cipher = Aes128::new(&key);
|
||||
let cipher = Aes128::new(key);
|
||||
|
||||
// 开始解密
|
||||
cipher.decrypt_blocks(&mut blocks);
|
||||
@ -496,24 +499,24 @@ fn aes128_to_slice<T: AsRef<[u8]>>(key: &T, blocks: Vec<u8>) -> Result<Vec<u8>,
|
||||
x.push(i.to_owned());
|
||||
}
|
||||
}
|
||||
Ok(x.into())
|
||||
Ok(x)
|
||||
}
|
||||
|
||||
/// ## 规范文件名称
|
||||
/// 防止创建文件失败
|
||||
/// 符号一一对应:
|
||||
/// - \ / * ? " : < > |
|
||||
/// - _ _ * ? " : ⟨ ⟩ _
|
||||
#[allow(dead_code)]
|
||||
fn standardize_filename(old_fullfilename: String) -> String {
|
||||
trace!("格式化文件名");
|
||||
let mut new_fullfilename = String::from(old_fullfilename);
|
||||
// debug!("规范文件名:{}", new_fullfilename);
|
||||
let standard = ["\\", "/", "*", "?", "\"", ":", "<", ">", "|"];
|
||||
let resolution = ["_", "_", "*", "?", """, ":", "⟨", "⟩", "_"];
|
||||
for i in 0..standard.len() {
|
||||
new_fullfilename =
|
||||
new_fullfilename.replace(&standard[i].to_string(), &resolution[i].to_string());
|
||||
}
|
||||
new_fullfilename
|
||||
}
|
||||
// ## 规范文件名称
|
||||
// 防止创建文件失败
|
||||
// 符号一一对应:
|
||||
// - \ / * ? " : < > |
|
||||
// - _ _ * ? " : ⟨ ⟩ _
|
||||
// #[allow(dead_code)]
|
||||
// fn standardize_filename(old_fullfilename: String) -> String {
|
||||
// trace!("格式化文件名");
|
||||
// let mut new_fullfilename = String::from(old_fullfilename);
|
||||
// // debug!("规范文件名:{}", new_fullfilename);
|
||||
// let standard = ["\\", "/", "*", "?", "\"", ":", "<", ">", "|"];
|
||||
// let resolution = ["_", "_", "*", "?", """, ":", "⟨", "⟩", "_"];
|
||||
// for i in 0..standard.len() {
|
||||
// new_fullfilename =
|
||||
// new_fullfilename.replace(&standard[i].to_string(), &resolution[i].to_string());
|
||||
// }
|
||||
// new_fullfilename
|
||||
// }
|
||||
|
||||
@ -3,9 +3,9 @@ use std::{path::PathBuf, process::Command};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn opendir(dir: PathBuf) {
|
||||
if let Err(_) = Command::new("explorer")
|
||||
if Command::new("explorer")
|
||||
.arg(&dir) // <- Specify the directory you'd like to open.
|
||||
.spawn()
|
||||
.spawn().is_err()
|
||||
{
|
||||
error!("无法打开输出文件夹:[{}]", dir.display())
|
||||
}
|
||||
@ -13,18 +13,18 @@ pub fn opendir(dir: PathBuf) {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn opendir(dir: PathBuf) {
|
||||
if let Err(_) = Command::new("open")
|
||||
if Command::new("open")
|
||||
.arg(&dir) // <- Specify the directory you'd like to open.
|
||||
.spawn()
|
||||
.spawn().is_err()
|
||||
{
|
||||
error!("无法打开输出文件夹:[{}]", dir.display())
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn opendir(dir: PathBuf) {
|
||||
if let Err(_) = Command::new("open")
|
||||
if Command::new("open")
|
||||
.arg(&dir) // <- Specify the directory you'd like to open.
|
||||
.spawn()
|
||||
.spawn().is_err()
|
||||
{
|
||||
error!("无法打开输出文件夹:[{}]", dir.display())
|
||||
}
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
use log::{debug, error, warn};
|
||||
use log::{debug, error};
|
||||
use std::path::Path;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use crate::apperror::AppError;
|
||||
|
||||
pub fn pathparse(input: Vec<String>) -> Vec<String> {
|
||||
let mut undumpfile = Vec::new(); // 该列表将存入文件的路径
|
||||
// 遍历输入的每一个路径参数
|
||||
|
||||
@ -58,8 +58,8 @@ impl Pool {
|
||||
}
|
||||
|
||||
Pool {
|
||||
workers: workers,
|
||||
max_workers: max_workers,
|
||||
workers,
|
||||
max_workers,
|
||||
sender: tx,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user