use super::file::FileReader; use crate::archive::{Handle, ReadCompression, ReadFilter, ReadFormat}; use crate::error::{ArchiveError, Result}; use crate::read::Archive; use libarchive3_sys::ffi; use std::ffi::CString; use std::mem; use std::path::Path; /// A struct that allows configuration of the reader before it is created. pub struct Builder { handle: *mut ffi::Struct_archive, consumed: bool, } impl Builder { pub fn new() -> Self { Builder::default() } /// Enable support for a given compression method. pub fn support_compression(&mut self, compression: ReadCompression) -> Result<()> { #[rustfmt::skip] let result = match compression { ReadCompression::All => unsafe { ffi::archive_read_support_compression_all(self.handle_mut()) }, ReadCompression::Bzip2 => unsafe { ffi::archive_read_support_compression_bzip2(self.handle_mut()) }, ReadCompression::Compress => unsafe { ffi::archive_read_support_compression_compress(self.handle_mut()) }, ReadCompression::Gzip => unsafe { ffi::archive_read_support_compression_gzip(self.handle_mut()) }, ReadCompression::Lzip => unsafe { ffi::archive_read_support_compression_lzip(self.handle_mut()) }, ReadCompression::Lzma => unsafe { ffi::archive_read_support_compression_lzma(self.handle_mut()) }, ReadCompression::None => unsafe { ffi::archive_read_support_compression_none(self.handle_mut()) }, ReadCompression::Rpm => unsafe { ffi::archive_read_support_compression_rpm(self.handle_mut()) }, ReadCompression::Uu => unsafe { ffi::archive_read_support_compression_uu(self.handle_mut()) }, ReadCompression::Xz => unsafe { ffi::archive_read_support_compression_xz(self.handle_mut()) }, ReadCompression::Program(prog) => { let c_prog = CString::new(prog).unwrap(); unsafe { ffi::archive_read_support_compression_program( self.handle_mut(), c_prog.as_ptr(), ) } } }; match result { ffi::ARCHIVE_OK => Ok(()), _ => Result::from(self as &dyn Handle), } } /// Enable support for a given filter pub fn support_filter(&mut self, filter: ReadFilter) -> Result<()> { #[rustfmt::skip] let result = match filter { ReadFilter::All => unsafe { ffi::archive_read_support_filter_all(self.handle_mut()) }, ReadFilter::Bzip2 => unsafe { ffi::archive_read_support_filter_bzip2(self.handle_mut()) }, ReadFilter::Compress => unsafe { ffi::archive_read_support_filter_compress(self.handle_mut()) }, ReadFilter::Grzip => unsafe { ffi::archive_read_support_filter_grzip(self.handle_mut()) }, ReadFilter::Gzip => unsafe { ffi::archive_read_support_filter_gzip(self.handle_mut()) }, ReadFilter::Lrzip => unsafe { ffi::archive_read_support_filter_lrzip(self.handle_mut()) }, ReadFilter::Lzip => unsafe { ffi::archive_read_support_filter_lzip(self.handle_mut()) }, ReadFilter::Lzma => unsafe { ffi::archive_read_support_filter_lzma(self.handle_mut()) }, ReadFilter::Lzop => unsafe { ffi::archive_read_support_filter_lzop(self.handle_mut()) }, ReadFilter::None => unsafe { ffi::archive_read_support_filter_none(self.handle_mut()) }, ReadFilter::Rpm => unsafe { ffi::archive_read_support_filter_rpm(self.handle_mut()) }, ReadFilter::Uu => unsafe { ffi::archive_read_support_filter_uu(self.handle_mut()) }, ReadFilter::Xz => unsafe { ffi::archive_read_support_filter_xz(self.handle_mut()) }, ReadFilter::Zstd => unsafe { ffi::archive_read_support_filter_zstd(self.handle_mut()) }, ReadFilter::Program(prog) => { let c_prog = CString::new(prog).unwrap(); unsafe { ffi::archive_read_support_filter_program(self.handle_mut(), c_prog.as_ptr()) } } ReadFilter::ProgramSignature(prog, cb, size) => { let c_prog = CString::new(prog).unwrap(); unsafe { ffi::archive_read_support_filter_program_signature( self.handle_mut(), c_prog.as_ptr(), mem::transmute::, *const std::ffi::c_void>(cb), size, ) } } }; match result { ffi::ARCHIVE_OK => Ok(()), _ => Result::from(self as &dyn Handle), } } /// Enable support for a given format. pub fn support_format(&mut self, format: ReadFormat) -> Result<()> { // SAFETY: Casting to *mut because these c functions take T* not const T*. They do not // modify the pointer, so this is sound. #[rustfmt::skip] let result = match format { ReadFormat::SevenZip => unsafe { ffi::archive_read_support_format_7zip(self.handle_mut()) }, ReadFormat::All => unsafe { ffi::archive_read_support_format_all(self.handle_mut()) }, ReadFormat::Ar => unsafe { ffi::archive_read_support_format_ar(self.handle_mut()) }, ReadFormat::Cab => unsafe { ffi::archive_read_support_format_cab(self.handle_mut()) }, ReadFormat::Cpio => unsafe { ffi::archive_read_support_format_cpio(self.handle_mut()) }, ReadFormat::Empty => unsafe { ffi::archive_read_support_format_empty(self.handle_mut()) }, ReadFormat::Gnutar => unsafe { ffi::archive_read_support_format_gnutar(self.handle_mut()) }, ReadFormat::Iso9660 => unsafe { ffi::archive_read_support_format_iso9660(self.handle_mut()) }, ReadFormat::Lha => unsafe { ffi::archive_read_support_format_lha(self.handle_mut()) }, ReadFormat::Mtree => unsafe { ffi::archive_read_support_format_mtree(self.handle_mut()) }, ReadFormat::Rar => unsafe { ffi::archive_read_support_format_rar(self.handle_mut()) }, ReadFormat::Raw => unsafe { ffi::archive_read_support_format_raw(self.handle_mut()) }, ReadFormat::Tar => unsafe { ffi::archive_read_support_format_tar(self.handle_mut()) }, ReadFormat::Xar => unsafe { ffi::archive_read_support_format_xar(self.handle_mut()) }, ReadFormat::Zip => unsafe { ffi::archive_read_support_format_zip(self.handle_mut()) }, }; match result { ffi::ARCHIVE_OK => Ok(()), _ => Result::from(self as &dyn Handle), } } /// Open a file with this builder, consuming it and returning a `FileReader` pub fn open_file>(self, file: T) -> Result { self.check_consumed()?; FileReader::open(self, file) } /// Open a stream with this builder, consuming it and returning a `StreamReader` // pub fn open_stream(self, src: T) -> Result { // self.check_consumed()?; // StreamReader::open(self, src) // } pub fn check_consumed(&self) -> Result<()> { if self.consumed { Err(ArchiveError::Consumed) } else { Ok(()) } } pub fn consume(&mut self) { self.consumed = true; } } impl Handle for Builder { unsafe fn handle(&self) -> *const ffi::Struct_archive { self.handle as *const _ } unsafe fn handle_mut(&mut self) -> *mut ffi::Struct_archive { self.handle } } impl Drop for Builder { fn drop(&mut self) { if !self.consumed { unsafe { ffi::archive_read_free(self.handle); } } } } impl Default for Builder { fn default() -> Self { unsafe { let handle = ffi::archive_read_new(); if handle.is_null() { panic!("Allocation error"); } Builder { handle, consumed: false, } } } }