use std::{error, fmt, io};
use crate::parse::Method;
use super::encoding;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub enum Error {
Format(FormatError),
Unsupported(UnsupportedError),
Encoding(encoding::DecodingError),
IO(io::Error),
Decompression {
method: Method,
msg: String,
},
UnknownSize,
}
impl Error {
pub fn method_not_supported(method: Method) -> Self {
Self::Unsupported(UnsupportedError::MethodNotSupported(method))
}
pub fn method_not_enabled(method: Method) -> Self {
Self::Unsupported(UnsupportedError::MethodNotEnabled(method))
}
}
impl From<FormatError> for Error {
fn from(fmt_err: FormatError) -> Self {
Self::Format(fmt_err)
}
}
impl From<UnsupportedError> for Error {
fn from(unsupported: UnsupportedError) -> Self {
Self::Unsupported(unsupported)
}
}
impl From<encoding::DecodingError> for Error {
fn from(enc: encoding::DecodingError) -> Self {
Self::Encoding(enc)
}
}
impl From<io::Error> for Error {
fn from(io: io::Error) -> Self {
Self::IO(io)
}
}
impl From<Error> for io::Error {
fn from(e: Error) -> Self {
match e {
Error::IO(e) => e,
e => io::Error::other(e),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Format(format) => write!(f, "format: {format}"),
Self::Unsupported(unsupported) => write!(f, "unsupported: {unsupported}"),
Self::Encoding(enc) => write!(f, "encoding: {enc:?}"),
Self::IO(io) => write!(f, "io: {io}"),
Self::Decompression { method, msg } => {
write!(f, "{method:?} decompression error: {msg}")
}
Self::UnknownSize => f.write_str("size must be known to open zip file"),
}
}
}
impl error::Error for Error {}
#[derive(Debug)]
pub enum UnsupportedError {
MethodNotSupported(Method),
MethodNotEnabled(Method),
LzmaVersionUnsupported {
major: u8,
minor: u8,
},
LzmaPropertiesHeaderWrongSize {
expected: u16,
actual: u16,
},
}
impl fmt::Display for UnsupportedError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::MethodNotSupported(m) => write!(f, "compression method not supported: {m:?}"),
Self::MethodNotEnabled(m) => write!(
f,
"compression method supported, but not enabled in this build: {m:?}"
),
Self::LzmaVersionUnsupported { major, minor } => {
write!(f, "only LZMA2.0 is supported, found LZMA{major}.{minor}")
}
Self::LzmaPropertiesHeaderWrongSize { expected, actual } => {
write!(f, "LZMA properties header wrong size: expected {expected} bytes, got {actual} bytes")
}
}
}
}
impl error::Error for UnsupportedError {}
#[derive(Debug)]
pub enum FormatError {
DirectoryEndSignatureNotFound,
Directory64EndRecordInvalid,
DirectoryOffsetPointsOutsideFile,
InvalidCentralRecord {
expected: u16,
actual: u16,
},
InvalidExtraField,
InvalidHeaderOffset,
ImpossibleNumberOfFiles {
claimed_records_count: u64,
zip_size: u64,
},
InvalidLocalHeader,
InvalidDataDescriptor,
WrongSize {
expected: u64,
actual: u64,
},
WrongChecksum {
expected: u32,
actual: u32,
},
}
impl fmt::Display for FormatError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::DirectoryEndSignatureNotFound => {
f.write_str("end of central directory record not found")
}
Self::Directory64EndRecordInvalid => {
f.write_str("zip64 end of central directory record not found")
}
Self::DirectoryOffsetPointsOutsideFile => {
f.write_str("directory offset points outside of file")
}
Self::InvalidCentralRecord { expected, actual } => {
write!(
f,
"invalid central record: expected to read {expected} files, got {actual}"
)
}
Self::InvalidExtraField => f.write_str("could not decode extra field"),
Self::InvalidHeaderOffset => f.write_str("invalid header offset"),
Self::ImpossibleNumberOfFiles {
claimed_records_count,
zip_size,
} => {
write!(
f,
"impossible number of files: claims to have {claimed_records_count}, but zip size is {zip_size}"
)
}
Self::InvalidLocalHeader => f.write_str("invalid local file header"),
Self::InvalidDataDescriptor => f.write_str("invalid data descriptor"),
Self::WrongSize { expected, actual } => {
write!(
f,
"uncompressed size didn't match: expected {expected}, got {actual}"
)
}
Self::WrongChecksum { expected, actual } => {
write!(
f,
"checksum didn't match: expected {expected:x?}, got {actual:x?}"
)
}
}
}
}
impl error::Error for FormatError {}