add rar support

This commit is contained in:
Robin Appelman 2025-07-01 14:57:43 +02:00
commit 14fb51c33d
6 changed files with 93 additions and 1 deletions

View file

@ -27,6 +27,8 @@ pub enum ReadError {
Zstd(#[from] FrameDecoderError),
#[error(transparent)]
SevenZip(#[from] sevenz_rust2::Error),
#[error(transparent)]
Rar(#[from] unrar::error::UnrarError),
#[error("archive contains no files")]
NoFiles,
#[error("log file contained non-utf8 characters: {0:#}")]

View file

@ -1,3 +1,4 @@
mod rar;
mod sevenzip;
mod tar;
mod zip;
@ -6,6 +7,7 @@ use crate::error::ReadError;
use std::borrow::Cow;
use std::io::Read;
pub use rar::RarArchive;
pub use sevenzip::SevenZipArchive;
pub use tar::TarArchive;
pub use zip::ZipArchive;

View file

@ -0,0 +1,52 @@
use crate::error::ReadError;
use crate::logfile::archive::{Archive, ArchiveEntry};
use std::borrow::Cow;
pub struct RarArchive {
path: String,
}
impl RarArchive {
pub fn new(path: &str) -> Result<Self, ReadError> {
Ok(RarArchive { path: path.into() })
}
}
pub struct RarEntry {
archive: String,
name: String,
}
impl ArchiveEntry for RarEntry {
fn name(&self) -> Cow<str> {
self.name.as_str().into()
}
fn extract(self) -> Result<Vec<u8>, 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)
}
}
impl Archive for RarArchive {
type Entry<'a> = RarEntry;
fn entries(&mut self) -> impl Iterator<Item = Self::Entry<'_>> {
unrar::Archive::new(&self.path)
.open_for_listing()
.into_iter()
.flatten()
.into_iter()
.flatten()
.map(|header| RarEntry {
archive: self.path.clone(),
name: header.filename.to_string_lossy().into(),
})
}
}

View file

@ -2,7 +2,9 @@ mod archive;
pub mod logline;
use crate::error::ReadError;
use crate::logfile::archive::{Archive, ArchiveEntry, SevenZipArchive, TarArchive, ZipArchive};
use crate::logfile::archive::{
Archive, ArchiveEntry, RarArchive, SevenZipArchive, TarArchive, ZipArchive,
};
use bzip2_rs::DecoderReader;
use csv::Reader;
use dialoguer::Select;
@ -40,6 +42,9 @@ impl LogFile {
} else if path.ends_with(".7z") {
let mut zip = SevenZipArchive::new(file)?;
return select_file(&mut zip);
} else if path.ends_with(".rar") {
let mut rar = RarArchive::new(path)?;
return select_file(&mut rar);
}
if let Some(path) = path.strip_suffix(".gz") {