1use crate::structs::{Algorithm, Version};
2use fourcc::FourCC;
3use std::{fmt, io};
4
5#[derive(Debug)]
6pub enum InvalidFileReason {
8 InvalidHeader,
9 CreatorCode(FourCC),
10 FileMagic(FourCC),
11}
12
13impl fmt::Display for InvalidFileReason {
14 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15 match self {
16 InvalidFileReason::CreatorCode(code) => f.write_fmt(format_args!(
17 "Creator code is '{}' instead of 'rLau'",
18 code.name()
19 )),
20 InvalidFileReason::FileMagic(code) => f.write_fmt(format_args!(
21 "File code is '{}' but should be one of 'SIT!', 'SITD', 'SIT2' or 'SIT5'",
22 code.name()
23 )),
24 InvalidFileReason::InvalidHeader => {
25 f.write_str("Could not find valid archive header at the given position")
26 }
27 }
28 }
29}
30
31#[derive(Debug)]
32pub enum UnsupportedFeature {
34 Algorithm(Algorithm),
35 Version(Version),
36 Encryption,
37}
38
39impl fmt::Display for UnsupportedFeature {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 match self {
42 UnsupportedFeature::Algorithm(algo) => {
43 f.write_fmt(format_args!("Algorithm {algo} is not implemented yet"))
44 }
45 UnsupportedFeature::Version(version) => {
46 f.write_fmt(format_args!("The version {version} is not implemented yet"))
47 }
48 UnsupportedFeature::Encryption => f.write_str("Encryption is not implemented yet"),
49 }
50 }
51}
52
53impl From<Algorithm> for UnsupportedFeature {
54 fn from(val: Algorithm) -> Self {
55 UnsupportedFeature::Algorithm(val)
56 }
57}
58
59impl From<Version> for UnsupportedFeature {
60 fn from(val: Version) -> Self {
61 UnsupportedFeature::Version(val)
62 }
63}
64
65#[derive(Debug)]
66pub enum ChecksumLocation {
67 ArchiveHeader,
69 EntryHeader,
71 DataFork,
73 ResourceFork,
75 DataStream,
76}
77
78impl fmt::Display for ChecksumLocation {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 match self {
81 ChecksumLocation::ArchiveHeader => f.write_str("archive header"),
82 ChecksumLocation::EntryHeader => f.write_str("entry header"),
83 ChecksumLocation::DataFork => f.write_str("data fork"),
84 ChecksumLocation::ResourceFork => f.write_str("resource fork"),
85 ChecksumLocation::DataStream => f.write_str("data stream"),
86 }
87 }
88}
89
90#[derive(Debug, thiserror::Error)]
91pub enum Error {
93 #[error(transparent)]
94 Io(io::Error),
95
96 #[error(transparent)]
97 BinRW(#[from] binrw::Error),
98
99 #[error("The file is not a Stuffit archive ({0})")]
100 InvalidFile(InvalidFileReason),
101
102 #[error("The entry uses unsupported features ({0})")]
103 UnsupportedFeature(UnsupportedFeature),
104
105 #[error("One or more checksums indicate archive corruption")]
106 ChecksumMismatch(ChecksumLocation),
107
108 #[error("The compressed data stream could not read")]
109 InvalidDataStream,
110}
111
112impl From<Error> for binrw::Error {
113 fn from(val: Error) -> Self {
114 match val {
115 Error::Io(error) => binrw::Error::Io(error),
116 Error::BinRW(error) => error,
117 err => binrw::Error::Custom {
118 pos: 0,
119 err: Box::new(err),
120 },
121 }
122 }
123}
124
125impl From<Error> for io::Error {
126 fn from(val: Error) -> Self {
127 match val {
128 Error::Io(error) => error,
129 Error::BinRW(error) => io::Error::other(Box::new(error)),
130 err => io::Error::other(Box::new(err)),
131 }
132 }
133}
134
135impl From<crate::algos::huffman::Error> for Error {
136 fn from(_: crate::algos::huffman::Error) -> Self {
137 Self::InvalidDataStream
138 }
139}
140
141impl From<crate::algos::huffman_fixed::Error> for Error {
142 fn from(_: crate::algos::huffman_fixed::Error) -> Self {
143 Self::InvalidDataStream
144 }
145}
146
147impl From<crate::algos::arsenic::Error> for Error {
148 fn from(_: crate::algos::arsenic::Error) -> Self {
149 Self::InvalidDataStream
150 }
151}
152
153impl From<io::Error> for Error {
154 fn from(e: io::Error) -> Self {
155 match e {
156 e if e.kind() == io::ErrorKind::Other => match e.downcast() {
157 Ok(e) => e,
158 Err(e) => Error::Io(e),
159 },
160 e => Error::Io(e),
161 }
162 }
163}
164
165#[derive(thiserror::Error, Debug)]
166pub enum ExtractionError {
168 #[error("The requested entry does not exist in the sit archive")]
169 ItemNotFound,
170 #[error(transparent)]
171 Error(#[from] Error),
172}
173
174impl From<io::Error> for ExtractionError {
175 fn from(value: io::Error) -> Self {
176 Self::Error(value.into())
177 }
178}
179
180impl From<ExtractionError> for io::Error {
181 fn from(value: ExtractionError) -> Self {
182 match value {
183 ExtractionError::ItemNotFound => {
184 io::Error::other("Requested file was not found in the archive")
185 }
186 other => other.into(),
187 }
188 }
189}