axfive_libzip/
source.rs

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