From 2c53e4d950f6340e8dbefef0a3843074b42c0eaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B2=81=E6=A0=91=E4=BA=BA?= Date: Wed, 4 Sep 2024 21:31:28 +0100 Subject: [PATCH] feat: add experimental cli --- .idea/lib_um_crypto.iml | 3 +- Cargo.lock | 140 +++++++++++++++++++++++++++++++++++++++- Cargo.toml | 2 +- um_cli/Cargo.toml | 10 +++ um_cli/src/cmd/mod.rs | 9 +++ um_cli/src/cmd/qmc1.rs | 41 ++++++++++++ um_cli/src/main.rs | 44 +++++++++++++ 7 files changed, 246 insertions(+), 3 deletions(-) create mode 100644 um_cli/Cargo.toml create mode 100644 um_cli/src/cmd/mod.rs create mode 100644 um_cli/src/cmd/qmc1.rs create mode 100644 um_cli/src/main.rs diff --git a/.idea/lib_um_crypto.iml b/.idea/lib_um_crypto.iml index beec96a..b1d8e6c 100644 --- a/.idea/lib_um_crypto.iml +++ b/.idea/lib_um_crypto.iml @@ -6,9 +6,10 @@ + - + \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 040b006..c6936f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,55 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "anyhow" version = "1.0.86" @@ -35,6 +84,52 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "4.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -51,6 +146,18 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.13.0" @@ -130,6 +237,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "2.0.77" @@ -161,6 +274,16 @@ dependencies = [ "syn", ] +[[package]] +name = "um_cli" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "umc_kuwo", + "umc_qmc", +] + [[package]] name = "um_wasm" version = "0.1.0" @@ -199,6 +322,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "walkdir" version = "2.5.0" @@ -318,7 +447,16 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a31b498..2b57826 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["um_crypto/*", "um_wasm"] +members = ["um_crypto/*", "um_wasm", "um_cli"] [profile.release.package.um_wasm] # Tell `rustc` to optimize for small code size. diff --git a/um_cli/Cargo.toml b/um_cli/Cargo.toml new file mode 100644 index 0000000..9951f2a --- /dev/null +++ b/um_cli/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "um_cli" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0.86" +clap = { version = "4.5.17", features = ["derive"] } +umc_kuwo = { path = "../um_crypto/kuwo" } +umc_qmc = { path = "../um_crypto/qmc" } diff --git a/um_cli/src/cmd/mod.rs b/um_cli/src/cmd/mod.rs new file mode 100644 index 0000000..7ae8d2b --- /dev/null +++ b/um_cli/src/cmd/mod.rs @@ -0,0 +1,9 @@ +use clap::Subcommand; + +pub mod qmc1; + +#[derive(Subcommand)] +pub enum Commands { + #[command(name = "qmc1")] + QMCv1(qmc1::ArgsQMCv1), +} diff --git a/um_cli/src/cmd/qmc1.rs b/um_cli/src/cmd/qmc1.rs new file mode 100644 index 0000000..11007cd --- /dev/null +++ b/um_cli/src/cmd/qmc1.rs @@ -0,0 +1,41 @@ +use anyhow::Result; +use clap::Args; +use std::fs::File; +use std::io::{Read, Write}; +use std::path::PathBuf; + +/// Decrypt a QMCv1 file +#[derive(Args)] +pub struct ArgsQMCv1 { + /// Path to output file, e.g. /export/Music/song.flac + #[clap(short, long)] + output: PathBuf, + + /// Path to input file, e.g. /export/Music/song.qmcflac + #[arg(name = "input")] + input: PathBuf, +} + +// 4MiB buffer is working well on my machine. +const BUFFER_SIZE: usize = 4 * 1024 * 1024; + +impl ArgsQMCv1 { + pub fn run(&self) -> Result { + let mut file_input = File::open(&self.input)?; + let mut file_output = File::create(&self.output)?; + + let mut offset = 0usize; + let mut buffer = vec![0u8; BUFFER_SIZE].into_boxed_slice(); + while let Ok(n) = file_input.read(&mut buffer) { + if n == 0 { + break; + } + + umc_qmc::v1::decrypt(&mut buffer[..n], offset); + file_output.write_all(&buffer[..n])?; + offset += n; + } + + Ok(0) + } +} diff --git a/um_cli/src/main.rs b/um_cli/src/main.rs new file mode 100644 index 0000000..fc034f7 --- /dev/null +++ b/um_cli/src/main.rs @@ -0,0 +1,44 @@ +use crate::cmd::Commands; +use anyhow::Result; +use clap::Parser; +use std::process::exit; +use std::time::Instant; + +mod cmd; + +#[derive(Parser)] +#[command(name = "um_cli")] +#[command(version = "0.1")] +#[command(about = "um_cli (rust ver.)", long_about = None)] +struct Cli { + #[clap(subcommand)] + command: Option, + + /// Time command + #[clap(long, short, action=clap::ArgAction::SetTrue)] + time: Option, +} + +fn run_command(cli: &Cli) -> Result { + match &cli.command { + Some(Commands::QMCv1(cmd)) => cmd.run(), + None => { + // https://github.com/clap-rs/clap/issues/3857#issuecomment-1161796261 + todo!("implement a sensible default command, similar to um/cli"); + } + } +} + +fn main() { + let cli = Cli::parse(); + let start = Instant::now(); + let code = run_command(&cli).unwrap_or_else(|err| { + eprintln!("failed to run command: {}", err); + -1 + }); + let duration = start.elapsed(); + if let Some(true) = cli.time { + eprintln!("time: {:?}", duration); + }; + exit(code); +}