1use crate::ffi;
6use derive_more::{Display, Error, From};
7use std::{borrow::Cow, ffi::CStr, io};
8
9pub type Result<T> = std::result::Result<T, Error>;
10
11#[derive(Display, From, Error, Debug)]
12#[non_exhaustive]
13pub enum Error {
14 #[display(
15 "Extraction error:{}{} '{}'",
16 match code {
17 Some(_) => " ",
18 None => ""
19 },
20 if let Some(e) = code {
21 e as &dyn std::fmt::Display
22 } else {
23 &"" as &_
24 },
25 details
26 )]
27 Extraction {
28 #[error(source)]
31 code: Option<io::Error>,
32 details: String,
34 },
35
36 Io(io::Error),
37
38 Utf(std::str::Utf8Error),
39
40 #[display("Encoding error: '{}'", _0)]
41 Encoding(#[error(not(source))] Cow<'static, str>),
42
43 #[cfg(feature = "tokio_support")]
44 JoinError(tokio::task::JoinError),
45
46 #[display("Error to create the archive struct, is null")]
47 NullArchive,
48
49 #[display(
50 "Unsupported ZIP compression method in {} {}: {:?}",
51 _0.len(),
52 if _0.len() == 1 { "entry" } else { "entries" },
53 _0
54 )]
55 UnsupportedZipCompression(#[error(not(source))] Vec<(String, u16)>),
56
57 #[display("Unknown error")]
58 Unknown,
59}
60
61pub(crate) fn archive_result(value: i32, archive: *mut ffi::archive) -> Result<()> {
62 match value {
63 ffi::ARCHIVE_OK | ffi::ARCHIVE_WARN => Ok(()),
64 _ => Err(Error::from(archive)),
65 }
66}
67
68pub(crate) fn archive_result_strict(value: i32, archive: *mut ffi::archive) -> Result<()> {
75 match value {
76 ffi::ARCHIVE_OK => Ok(()),
77 _ => Err(Error::from(archive)),
78 }
79}
80
81#[allow(clippy::not_unsafe_ptr_arg_deref)]
82impl From<*mut ffi::archive> for Error {
83 fn from(input: *mut ffi::archive) -> Self {
84 let (details, code) = unsafe {
85 let error_string = ffi::archive_error_string(input);
86 let details = if !error_string.is_null() {
87 Some(CStr::from_ptr(error_string).to_string_lossy().into_owned())
88 } else {
89 None
90 };
91
92 let errno = ffi::archive_errno(input);
93 let code = if errno > 0 {
94 Some(io::Error::from_raw_os_error(errno))
95 } else {
96 None
98 };
99 (details, code)
100 };
101 match (details, code) {
102 (Some(details), code) => Error::Extraction { code, details },
103 (None, Some(code)) => Error::Io(code),
104 (None, None) => Error::Unknown,
105 }
106 }
107}