axfive_libzip/
source.rs

1use crate::error::ZipErrorT;
2use crate::ffi;
3use crate::Error;
4use crate::Result;
5use std::convert::{TryFrom, TryInto};
6use std::ffi::{CStr, CString};
7use std::marker::PhantomData;
8use std::path::Path;
9use std::ptr::null_mut;
10
11/// A simple marker enum, used to indicate that the source holds an open file handle.
12pub enum File {}
13
14/// Borrows or owns a source
15#[derive(Debug)]
16pub struct Source<T> {
17    handle: *mut ffi::zip_source_t,
18    phantom: PhantomData<T>,
19}
20
21impl<T> Source<T> {
22    /// Indicate that the ownership has been taken by zip_open_from_source, zip_file_add, or
23    /// zip_file_replace, and therefore shouldn't be freed.
24    pub(crate) fn taken(mut self) {
25        self.handle = null_mut();
26    }
27
28    pub(crate) fn handle_mut(&mut self) -> *mut ffi::zip_source_t {
29        self.handle
30    }
31}
32
33impl<'a> TryFrom<&'a [u8]> for Source<&'a [u8]> {
34    type Error = Error;
35
36    fn try_from(buffer: &[u8]) -> Result<Source<&[u8]>> {
37        let mut error = ZipErrorT::default();
38        let handle = unsafe {
39            ffi::zip_source_buffer_create(buffer.as_ptr() as _, buffer.len() as _, 0, &mut *error)
40        };
41        if handle.is_null() {
42            Err(error.into())
43        } else {
44            Ok(Source {
45                handle,
46                phantom: PhantomData,
47            })
48        }
49    }
50}
51
52impl TryFrom<&CStr> for Source<File> {
53    type Error = Error;
54
55    fn try_from(filename: &CStr) -> Result<Source<File>> {
56        let mut error = ZipErrorT::default();
57        let handle = unsafe { ffi::zip_source_file_create(filename.as_ptr(), 0, 0, &mut *error) };
58        if handle.is_null() {
59            Err(error.into())
60        } else {
61            Ok(Source {
62                handle,
63                phantom: PhantomData,
64            })
65        }
66    }
67}
68
69/// Open a zip file from a path.
70/// This is less efficient than the &CStr variant, so that should be preferred when you can
71/// construct a &CStr type directly or cache one.  If you would just be converting a path to a
72/// cstring and then discarding it, this method might be preferable because that's all this does.
73/// This will also panic if the Path contains any null bytes.
74impl TryFrom<&Path> for Source<File> {
75    type Error = Error;
76
77    fn try_from(filename: &Path) -> Result<Source<File>> {
78        let filename = CString::new(filename.to_string_lossy().into_owned())
79            .expect("The path could not be converted into a CString");
80        filename.as_ref().try_into()
81    }
82}
83
84impl<T> Drop for Source<T> {
85    fn drop(&mut self) {
86        if !self.handle.is_null() {
87            unsafe {
88                ffi::zip_source_free(self.handle);
89            }
90        }
91    }
92}