1use core::error::Error;
4use core::fmt::{self, Display, Formatter};
5use core::num::TryFromIntError;
6use std::borrow::Cow;
7use std::io;
8
9pub type ZipResult<T> = Result<T, ZipError>;
11
12#[derive(Debug)]
14#[non_exhaustive]
15pub enum ZipError {
16 Io(io::Error),
18
19 InvalidArchive(Cow<'static, str>),
21
22 UnsupportedArchive(&'static str),
24
25 FileNotFound,
27
28 InvalidPassword,
30
31 CompressionMethodNotSupported(u16),
33}
34
35impl ZipError {
36 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#[derive(Debug)]
114pub struct DateTimeRangeError;
115
116impl 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;