1use std::path::PathBuf;
6use thiserror::Error;
7
8#[derive(Debug, Error)]
10pub enum ArchiveError {
11 #[error("IO error: {0}")]
13 Io(#[from] std::io::Error),
14
15 #[error("Unsupported archive format: {0}")]
17 UnsupportedFormat(String),
18
19 #[error("Invalid {format} archive header")]
21 InvalidHeader {
22 format: String,
24 },
25
26 #[error("Corrupted {format} entry '{entry_name}': {reason}")]
28 CorruptedEntry {
29 format: String,
31 entry_name: String,
33 reason: String,
35 },
36
37 #[error("Entry index mismatch: {0}")]
39 IndexMismatch(String),
40
41 #[error("CRC mismatch for '{entry}': expected {expected:#010x}, got {actual:#010x}")]
43 CrcMismatch {
44 entry: String,
46 expected: u32,
48 actual: u32,
50 },
51
52 #[error("Decompression failed for '{entry}': {reason}")]
54 DecompressionFailed {
55 entry: String,
57 reason: String,
59 },
60
61 #[error("Unsupported compression method '{method}' in {format} archive")]
63 UnsupportedMethod {
64 format: String,
66 method: String,
68 },
69
70 #[error("Archive '{path}' is encrypted and requires a password")]
72 PasswordRequired {
73 path: PathBuf,
75 },
76
77 #[error("{library} error: {message}")]
79 ExternalLibrary {
80 library: String,
82 message: String,
84 },
85}
86
87pub type Result<T> = std::result::Result<T, ArchiveError>;
89
90impl<T: std::io::Read> From<delharc::decode::LhaDecodeError<T>> for ArchiveError {
93 fn from(err: delharc::decode::LhaDecodeError<T>) -> Self {
94 ArchiveError::ExternalLibrary {
95 library: "delharc".to_string(),
96 message: format!("{:?}", err),
97 }
98 }
99}
100
101impl From<delharc::LhaError<std::io::Error>> for ArchiveError {
102 fn from(err: delharc::LhaError<std::io::Error>) -> Self {
103 ArchiveError::ExternalLibrary {
104 library: "delharc".to_string(),
105 message: format!("{:?}", err),
106 }
107 }
108}
109
110impl From<ArchiveError> for std::io::Error {
112 fn from(err: ArchiveError) -> Self {
113 match err {
114 ArchiveError::Io(io_err) => io_err,
115 other => std::io::Error::other(other.to_string()),
116 }
117 }
118}
119
120impl ArchiveError {
121 pub fn io_error(message: impl Into<String>) -> Self {
123 Self::Io(std::io::Error::other(message.into()))
124 }
125
126 pub fn unsupported_format(path: impl Into<String>) -> Self {
128 Self::UnsupportedFormat(path.into())
129 }
130
131 pub fn invalid_header(format: impl Into<String>) -> Self {
133 Self::InvalidHeader {
134 format: format.into(),
135 }
136 }
137
138 pub fn corrupted_entry(format: impl Into<String>, reason: impl Into<String>) -> Self {
140 Self::CorruptedEntry {
141 format: format.into(),
142 entry_name: String::new(),
143 reason: reason.into(),
144 }
145 }
146
147 pub fn corrupted_entry_named(
149 format: impl Into<String>,
150 entry_name: impl Into<String>,
151 reason: impl Into<String>,
152 ) -> Self {
153 Self::CorruptedEntry {
154 format: format.into(),
155 entry_name: entry_name.into(),
156 reason: reason.into(),
157 }
158 }
159
160 pub fn crc_mismatch(entry: impl Into<String>, expected: u32, actual: u32) -> Self {
162 Self::CrcMismatch {
163 entry: entry.into(),
164 expected,
165 actual,
166 }
167 }
168
169 pub fn decompression_failed(entry: impl Into<String>, reason: impl Into<String>) -> Self {
171 Self::DecompressionFailed {
172 entry: entry.into(),
173 reason: reason.into(),
174 }
175 }
176
177 pub fn unsupported_method(format: impl Into<String>, method: impl Into<String>) -> Self {
179 Self::UnsupportedMethod {
180 format: format.into(),
181 method: method.into(),
182 }
183 }
184
185 pub fn external_library(library: impl Into<String>, message: impl Into<String>) -> Self {
187 Self::ExternalLibrary {
188 library: library.into(),
189 message: message.into(),
190 }
191 }
192}