Skip to main content

zip/
result.rs

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