use crate::structs::{Algorithm, Version};
use fourcc::FourCC;
use std::{fmt, io};
#[derive(Debug)]
pub enum InvalidFileReason {
InvalidHeader,
CreatorCode(FourCC),
FileMagic(FourCC),
}
impl fmt::Display for InvalidFileReason {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InvalidFileReason::CreatorCode(code) => f.write_fmt(format_args!(
"Creator code is '{}' instead of 'rLau'",
code.name()
)),
InvalidFileReason::FileMagic(code) => f.write_fmt(format_args!(
"File code is '{}' but should be one of 'SIT!', 'SITD', 'SIT2' or 'SIT5'",
code.name()
)),
InvalidFileReason::InvalidHeader => {
f.write_str("Could not find valid archive header at the given position")
}
}
}
}
#[derive(Debug)]
pub enum UnsupportedFeature {
Algorithm(Algorithm),
Version(Version),
Encryption,
}
impl fmt::Display for UnsupportedFeature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UnsupportedFeature::Algorithm(algo) => {
f.write_fmt(format_args!("Algorithm {algo} is not implemented yet"))
}
UnsupportedFeature::Version(version) => {
f.write_fmt(format_args!("The version {version} is not implemented yet"))
}
UnsupportedFeature::Encryption => f.write_str("Encryption is not implemented yet"),
}
}
}
impl From<Algorithm> for UnsupportedFeature {
fn from(val: Algorithm) -> Self {
UnsupportedFeature::Algorithm(val)
}
}
impl From<Version> for UnsupportedFeature {
fn from(val: Version) -> Self {
UnsupportedFeature::Version(val)
}
}
#[derive(Debug)]
pub enum ChecksumLocation {
ArchiveHeader,
EntryHeader,
DataFork,
ResourceFork,
DataStream,
}
impl fmt::Display for ChecksumLocation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ChecksumLocation::ArchiveHeader => f.write_str("archive header"),
ChecksumLocation::EntryHeader => f.write_str("entry header"),
ChecksumLocation::DataFork => f.write_str("data fork"),
ChecksumLocation::ResourceFork => f.write_str("resource fork"),
ChecksumLocation::DataStream => f.write_str("data stream"),
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error(transparent)]
Io(io::Error),
#[error(transparent)]
BinRW(#[from] binrw::Error),
#[error("The file is not a Stuffit archive ({0})")]
InvalidFile(InvalidFileReason),
#[error("The entry uses unsupported features ({0})")]
UnsupportedFeature(UnsupportedFeature),
#[error("One or more checksums indicate archive corruption")]
ChecksumMismatch(ChecksumLocation),
#[error("The compressed data stream could not read")]
InvalidDataStream,
}
impl From<Error> for binrw::Error {
fn from(val: Error) -> Self {
match val {
Error::Io(error) => binrw::Error::Io(error),
Error::BinRW(error) => error,
err => binrw::Error::Custom {
pos: 0,
err: Box::new(err),
},
}
}
}
impl From<Error> for io::Error {
fn from(val: Error) -> Self {
match val {
Error::Io(error) => error,
Error::BinRW(error) => io::Error::other(Box::new(error)),
err => io::Error::other(Box::new(err)),
}
}
}
impl From<sit_algos::huffman::Error> for Error {
fn from(_: sit_algos::huffman::Error) -> Self {
Self::InvalidDataStream
}
}
impl From<sit_algos::huffman_fixed::Error> for Error {
fn from(_: sit_algos::huffman_fixed::Error) -> Self {
Self::InvalidDataStream
}
}
impl From<sit_algos::arsenic::Error> for Error {
fn from(_: sit_algos::arsenic::Error) -> Self {
Self::InvalidDataStream
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
match e {
e if e.kind() == io::ErrorKind::Other => match e.downcast() {
Ok(e) => e,
Err(e) => Error::Io(e),
},
e => Error::Io(e),
}
}
}
#[derive(thiserror::Error, Debug)]
pub enum ExtractionError {
#[error("The requested entry does not exist in the sit archive")]
ItemNotFound,
#[error(transparent)]
Error(#[from] Error),
}
impl From<io::Error> for ExtractionError {
fn from(value: io::Error) -> Self {
Self::Error(value.into())
}
}
impl From<ExtractionError> for io::Error {
fn from(value: ExtractionError) -> Self {
match value {
ExtractionError::ItemNotFound => {
io::Error::other("Requested file was not found in the archive")
}
other => other.into(),
}
}
}