diff --git a/Cargo.lock b/Cargo.lock index 8cf1e22..edb11d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1027,6 +1027,7 @@ dependencies = [ "main_error", "matchit", "osc94", + "rar-stream", "ratatui", "rayon", "regex", @@ -1039,7 +1040,6 @@ dependencies = [ "tikv-jemallocator", "time", "tinystr", - "unrar", "xz2", "zip", ] @@ -1438,6 +1438,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +[[package]] +name = "rar-stream" +version = "5.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bad41fc4447843b83b5e858b778dedcbbaf116e2bd3d7e21ab19ed096a942ef" +dependencies = [ + "crossbeam-channel", + "rayon", +] + [[package]] name = "ratatui" version = "0.30.0" @@ -2113,29 +2123,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" -[[package]] -name = "unrar" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ec61343a630d2b50d13216dea5125e157d3fc180a7d3f447d22fe146b648fc" -dependencies = [ - "bitflags 2.11.0", - "regex", - "unrar_sys", - "widestring", -] - -[[package]] -name = "unrar_sys" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b77675b883cfbe6bf41e6b7a5cd6008e0a83ba497de3d96e41a064bbeead765" -dependencies = [ - "cc", - "libc", - "winapi", -] - [[package]] name = "utf8parse" version = "0.2.2" @@ -2360,12 +2347,6 @@ dependencies = [ "wezterm-dynamic", ] -[[package]] -name = "widestring" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" - [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index bbf83d6..60c0c15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ xz2 = "0.1.7" bzip2-rs = "0.1.2" ruzstd = "0.8.2" sevenz-rust2 = "0.20.2" +rar-stream = "5.7.1" dialoguer = "0.12.0" indicatif = { version = "0.18.3", features = ["rayon"] } csv = "1.4.0" @@ -39,8 +40,6 @@ matchit = "0.9.0" [target.'cfg(target_env = "musl")'.dependencies] tikv-jemallocator = "0.6.1" -[target.'cfg(all(unix, not(target_env = "musl")))'.dependencies] -unrar = "0.5.8" [profile.dev.package."*"] opt-level = 3 diff --git a/src/error.rs b/src/error.rs index 99a4c58..66b0b2c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -27,9 +27,8 @@ pub enum ReadError { Zstd(#[from] FrameDecoderError), #[error(transparent)] SevenZip(#[from] sevenz_rust2::Error), - #[cfg(all(unix, not(target_env = "musl")))] #[error(transparent)] - Rar(#[from] unrar::error::UnrarError), + Rar(#[from] rar_stream::error::RarError), #[error("archive contains no files")] NoFiles, #[error("log file contained non-utf8 characters: {0:#}")] diff --git a/src/logfile/archive/rar.rs b/src/logfile/archive/rar.rs index 0497c03..c2815a2 100644 --- a/src/logfile/archive/rar.rs +++ b/src/logfile/archive/rar.rs @@ -1,51 +1,50 @@ use crate::error::ReadError; use crate::logfile::archive::{Archive, ArchiveEntry}; +use rar_stream::MemoryArchive; use std::borrow::Cow; +use std::fs::read; pub struct RarArchive { - path: String, + archive: MemoryArchive, } impl RarArchive { pub fn new(path: &str) -> Result { - Ok(RarArchive { path: path.into() }) + let data = read(path)?; + Ok(RarArchive { + archive: MemoryArchive::from_vec(data)?, + }) } } -pub struct RarEntry { - archive: String, +pub struct RarEntry<'a> { + archive: &'a MemoryArchive, + index: usize, name: String, } -impl ArchiveEntry for RarEntry { +impl ArchiveEntry for RarEntry<'_> { fn name<'a>(&'a self) -> Cow<'a, str> { self.name.as_str().into() } fn extract(self) -> Result, ReadError> { - let mut archive = unrar::Archive::new(&self.archive).open_for_processing()?; - while let Some(header) = archive.read_header()? { - if header.entry().filename.to_string_lossy() == self.name { - return Ok(header.read()?.0); - } - archive = header.skip()?; - } - Err(ReadError::NoFiles) + Ok(self.archive.extract(self.index)?) } } impl Archive for RarArchive { - type Entry<'a> = RarEntry; + type Entry<'a> = RarEntry<'a>; fn entries(&mut self) -> impl Iterator> { - unrar::Archive::new(&self.path) - .open_for_listing() - .into_iter() - .flatten() - .flatten() - .map(|header| RarEntry { - archive: self.path.clone(), - name: header.filename.to_string_lossy().into(), + self.archive + .entries_iter() + .enumerate() + .filter(|(_, entry)| !entry.is_directory) + .map(|(index, entry)| RarEntry { + archive: &self.archive, + index, + name: entry.name, }) } }