180 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Rust
		
	
	
			
		
		
	
	
			180 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Rust
		
	
	
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::<std::option::Option<extern "C" fn()>, *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<T: AsRef<Path>>(self, file: T) -> Result<FileReader> {
 | 
						|
        self.check_consumed()?;
 | 
						|
        FileReader::open(self, file)
 | 
						|
    }
 | 
						|
 | 
						|
    /// Open a stream with this builder, consuming it and returning a `StreamReader`
 | 
						|
    // pub fn open_stream<T: Any + Read>(self, src: T) -> Result<StreamReader> {
 | 
						|
    //     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,
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |