zip/
result.rs

1#![allow(unknown_lints)] // non_local_definitions isn't in Rust 1.70
2#![allow(non_local_definitions)]
3//! Error types that can be emitted from this library
4
5use core::error::Error;
6use core::fmt::{self, Display, Formatter};
7use core::num::TryFromIntError;
8use std::borrow::Cow;
9use std::io;
10
11/// Generic result type with ZipError as its error variant
12pub type ZipResult<T> = Result<T, ZipError>;
13
14/// Error type for Zip
15#[derive(Debug)]
16#[non_exhaustive]
17pub enum ZipError {
18    /// i/o error
19    Io(io::Error),
20
21    /// invalid Zip archive
22    InvalidArchive(Cow<'static, str>),
23
24    /// unsupported Zip archive
25    UnsupportedArchive(&'static str),
26
27    /// specified file not found in archive
28    FileNotFound,
29
30    /// provided password is incorrect
31    InvalidPassword,
32}
33
34impl ZipError {
35    /// The text used as an error when a password is required and not supplied
36    ///
37    /// ```rust,no_run
38    /// # use zip::result::ZipError;
39    /// # let mut archive = zip::ZipArchive::new(std::io::Cursor::new(&[])).unwrap();
40    /// match archive.by_index(1) {
41    ///     Err(ZipError::UnsupportedArchive(ZipError::PASSWORD_REQUIRED)) => eprintln!("a password is needed to unzip this file"),
42    ///     _ => (),
43    /// }
44    /// # ()
45    /// ```
46    pub const PASSWORD_REQUIRED: &'static str = "Password required to decrypt file";
47}
48
49impl Display for ZipError {
50    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
51        match self {
52            Self::Io(e) => write!(f, "i/o error: {e}"),
53            Self::InvalidArchive(e) => write!(f, "invalid Zip archive: {e}"),
54            Self::UnsupportedArchive(e) => write!(f, "unsupported Zip archive: {e}"),
55            Self::FileNotFound => f.write_str("specified file not found in archive"),
56            Self::InvalidPassword => f.write_str("provided password is incorrect"),
57        }
58    }
59}
60
61impl Error for ZipError {
62    fn source(&self) -> Option<&(dyn Error + 'static)> {
63        match self {
64            Self::Io(e) => Some(e),
65            Self::InvalidArchive(_)
66            | Self::UnsupportedArchive(_)
67            | Self::FileNotFound
68            | Self::InvalidPassword => None,
69        }
70    }
71}
72
73impl From<ZipError> for io::Error {
74    fn from(err: ZipError) -> io::Error {
75        let kind = match &err {
76            ZipError::Io(err) => err.kind(),
77            ZipError::InvalidArchive(_) => io::ErrorKind::InvalidData,
78            ZipError::UnsupportedArchive(_) => io::ErrorKind::Unsupported,
79            ZipError::FileNotFound => io::ErrorKind::NotFound,
80            ZipError::InvalidPassword => io::ErrorKind::InvalidInput,
81        };
82
83        io::Error::new(kind, err)
84    }
85}
86
87impl From<io::Error> for ZipError {
88    fn from(value: io::Error) -> Self {
89        Self::Io(value)
90    }
91}
92
93impl From<DateTimeRangeError> for ZipError {
94    fn from(_: DateTimeRangeError) -> Self {
95        invalid!("Invalid date or time")
96    }
97}
98
99impl From<std::string::FromUtf8Error> for ZipError {
100    fn from(_: std::string::FromUtf8Error) -> Self {
101        invalid!("Invalid UTF-8")
102    }
103}
104
105/// Error type for time parsing
106#[derive(Debug)]
107pub struct DateTimeRangeError;
108
109// TryFromIntError is also an out-of-range error.
110impl From<TryFromIntError> for DateTimeRangeError {
111    fn from(_value: TryFromIntError) -> Self {
112        DateTimeRangeError
113    }
114}
115
116impl fmt::Display for DateTimeRangeError {
117    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
118        write!(
119            fmt,
120            "a date could not be represented within the bounds the MS-DOS date range (1980-2107)"
121        )
122    }
123}
124
125impl Error for DateTimeRangeError {}
126
127pub(crate) fn invalid_archive<M: Into<Cow<'static, str>>>(message: M) -> ZipError {
128    ZipError::InvalidArchive(message.into())
129}
130
131pub(crate) const fn invalid_archive_const(message: &'static str) -> ZipError {
132    ZipError::InvalidArchive(Cow::Borrowed(message))
133}
134
135macro_rules! invalid {
136    ($message:literal) => {
137        crate::result::invalid_archive_const($message)
138    };
139    ($($arg:tt)*) => {
140        crate::result::invalid_archive(format!($($arg)*))
141    };
142}
143pub(crate) use invalid;