axfive_libzip/
error.rs

1use crate::ffi;
2use std::borrow::{Borrow, BorrowMut};
3use std::ffi::CStr;
4use std::fmt;
5use std::mem::zeroed;
6use std::ops::{Deref, DerefMut};
7use std::os::raw::c_int;
8
9#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub enum System {
11    Sys(c_int),
12    Zlib(c_int),
13    Unknown(c_int),
14}
15
16#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub enum Zip {
18    Changed,
19    Close,
20    CompressionNotSupported,
21    CompressedDataInvalid,
22    Crc,
23    Deleted,
24    EncryptionNotSupported,
25    Eof,
26    Exists,
27    Inconsistent,
28    Internal,
29    InUse,
30    InvalidArgument,
31    Memory,
32    Multidisk,
33    NoSuchFile,
34    NoPassword,
35    NotZip,
36    Open,
37    OperationNotSupported,
38    ReadOnly,
39    Read,
40    Remove,
41    Rename,
42    Seek,
43    Tell,
44    TempFile,
45    Write,
46    WrongPassword,
47    ZipClosed,
48    Zlib,
49    Unknown,
50}
51
52#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
53pub struct Error {
54    system: Option<System>,
55    zip: Option<Zip>,
56    message: String,
57}
58
59impl fmt::Display for Error {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        write!(f, "Error: {}", self.message)
62    }
63}
64
65impl std::error::Error for Error {}
66
67pub type Result<T> = std::result::Result<T, Error>;
68
69/// A containment structure for a zip_error_t.
70/// This can be either Default instantiated for an owned version or borrowed with its From
71/// implementation.
72#[derive(Debug)]
73pub(crate) struct ZipErrorT<T: Borrow<ffi::zip_error_t> + BorrowMut<ffi::zip_error_t>> {
74    error: T,
75    cleanup: bool,
76}
77
78impl Default for ZipErrorT<ffi::zip_error_t> {
79    fn default() -> Self {
80        unsafe {
81            let mut handle: ffi::zip_error_t = zeroed();
82            ffi::zip_error_init(&mut handle);
83            ZipErrorT {
84                error: handle,
85                cleanup: true,
86            }
87        }
88    }
89}
90
91impl From<c_int> for ZipErrorT<ffi::zip_error_t> {
92    fn from(error: c_int) -> Self {
93        unsafe {
94            let mut handle: ffi::zip_error_t = zeroed();
95            ffi::zip_error_init_with_code(&mut handle, error);
96            ZipErrorT {
97                error: handle,
98                cleanup: true,
99            }
100        }
101    }
102}
103
104impl<'a> From<&'a mut ffi::zip_error_t> for ZipErrorT<&'a mut ffi::zip_error_t> {
105    fn from(error: &'a mut ffi::zip_error_t) -> Self {
106        ZipErrorT {
107            error,
108            cleanup: false,
109        }
110    }
111}
112
113impl<T> ZipErrorT<T>
114where
115    T: Borrow<ffi::zip_error_t> + BorrowMut<ffi::zip_error_t>,
116{
117    pub fn system(&self) -> Option<System> {
118        let system = unsafe { ffi::zip_error_system_type(self.deref()) };
119        match system as _ {
120            ffi::ZIP_ET_NONE => None,
121            _ => {
122                let code = unsafe { ffi::zip_error_code_system(self.deref()) };
123                Some(match system as _ {
124                    ffi::ZIP_ET_SYS => System::Sys(code),
125                    ffi::ZIP_ET_ZLIB => System::Zlib(code),
126                    _ => System::Unknown(code),
127                })
128            }
129        }
130    }
131    pub fn zip(&self) -> Option<Zip> {
132        let code = unsafe { ffi::zip_error_code_zip(self.deref()) };
133        Some(match code as _ {
134            ffi::ZIP_ER_CHANGED => Zip::Changed,
135            ffi::ZIP_ER_CLOSE => Zip::Close,
136            ffi::ZIP_ER_COMPNOTSUPP => Zip::CompressionNotSupported,
137            ffi::ZIP_ER_COMPRESSED_DATA => Zip::CompressedDataInvalid,
138            ffi::ZIP_ER_CRC => Zip::Crc,
139            ffi::ZIP_ER_DELETED => Zip::Deleted,
140            ffi::ZIP_ER_ENCRNOTSUPP => Zip::EncryptionNotSupported,
141            ffi::ZIP_ER_EOF => Zip::Eof,
142            ffi::ZIP_ER_EXISTS => Zip::Exists,
143            ffi::ZIP_ER_INCONS => Zip::Inconsistent,
144            ffi::ZIP_ER_INTERNAL => Zip::Internal,
145            ffi::ZIP_ER_INUSE => Zip::InUse,
146            ffi::ZIP_ER_INVAL => Zip::InvalidArgument,
147            ffi::ZIP_ER_MEMORY => Zip::Memory,
148            ffi::ZIP_ER_MULTIDISK => Zip::Multidisk,
149            ffi::ZIP_ER_NOENT => Zip::NoSuchFile,
150            ffi::ZIP_ER_NOPASSWD => Zip::NoPassword,
151            ffi::ZIP_ER_NOZIP => Zip::NotZip,
152            ffi::ZIP_ER_OK => return None,
153            ffi::ZIP_ER_OPEN => Zip::Open,
154            ffi::ZIP_ER_OPNOTSUPP => Zip::OperationNotSupported,
155            ffi::ZIP_ER_RDONLY => Zip::ReadOnly,
156            ffi::ZIP_ER_READ => Zip::Read,
157            ffi::ZIP_ER_REMOVE => Zip::Remove,
158            ffi::ZIP_ER_RENAME => Zip::Rename,
159            ffi::ZIP_ER_SEEK => Zip::Seek,
160            ffi::ZIP_ER_TELL => Zip::Tell,
161            ffi::ZIP_ER_TMPOPEN => Zip::TempFile,
162            ffi::ZIP_ER_WRITE => Zip::Write,
163            ffi::ZIP_ER_WRONGPASSWD => Zip::WrongPassword,
164            ffi::ZIP_ER_ZIPCLOSED => Zip::ZipClosed,
165            ffi::ZIP_ER_ZLIB => Zip::Zlib,
166            _ => Zip::Unknown,
167        })
168    }
169
170    pub fn message(&mut self) -> &CStr {
171        unsafe {
172            let message = ffi::zip_error_strerror(self.deref_mut());
173            assert!(!message.is_null());
174            CStr::from_ptr(message)
175        }
176    }
177}
178
179impl<T> Drop for ZipErrorT<T>
180where
181    T: Borrow<ffi::zip_error_t> + BorrowMut<ffi::zip_error_t>,
182{
183    fn drop(&mut self) {
184        if self.cleanup {
185            unsafe { ffi::zip_error_fini(self.error.borrow_mut()) }
186        }
187    }
188}
189
190impl<T> Deref for ZipErrorT<T>
191where
192    T: Borrow<ffi::zip_error_t> + BorrowMut<ffi::zip_error_t>,
193{
194    type Target = ffi::zip_error_t;
195    fn deref(&self) -> &Self::Target {
196        self.error.borrow()
197    }
198}
199
200impl<T> DerefMut for ZipErrorT<T>
201where
202    T: Borrow<ffi::zip_error_t> + BorrowMut<ffi::zip_error_t>,
203{
204    fn deref_mut(&mut self) -> &mut Self::Target {
205        self.error.borrow_mut()
206    }
207}
208
209impl<T> From<ZipErrorT<T>> for Error
210where
211    T: Borrow<ffi::zip_error_t> + BorrowMut<ffi::zip_error_t>,
212{
213    fn from(mut error: ZipErrorT<T>) -> Self {
214        let system = error.system();
215        let zip = error.zip();
216        let message = error.message().to_string_lossy().into_owned();
217        Error {
218            system,
219            zip,
220            message,
221        }
222    }
223}