Skip to main content

oxiarc_snappy/
error.rs

1//! Error types for Snappy compression/decompression.
2
3use std::fmt;
4use std::io;
5
6/// Error type for Snappy operations.
7#[derive(Debug)]
8pub enum SnappyError {
9    /// The input data is too short or truncated.
10    UnexpectedEof {
11        /// Description of what was expected.
12        context: &'static str,
13    },
14    /// The decompressed length header is invalid or too large.
15    InvalidLength {
16        /// The decoded length value.
17        length: usize,
18        /// Maximum allowed length.
19        max_length: usize,
20    },
21    /// An invalid tag byte was encountered during decompression.
22    InvalidTag {
23        /// The tag byte value.
24        tag: u8,
25        /// Byte offset in the compressed stream.
26        offset: usize,
27    },
28    /// A copy operation references data before the start of the output.
29    InvalidOffset {
30        /// The back-reference offset.
31        offset: usize,
32        /// Current output position.
33        position: usize,
34    },
35    /// The decompressed output does not match the expected length.
36    OutputLengthMismatch {
37        /// Expected output length from the header.
38        expected: usize,
39        /// Actual decompressed length.
40        actual: usize,
41    },
42    /// CRC32C checksum mismatch in framed format.
43    ChecksumMismatch {
44        /// Expected checksum from the frame.
45        expected: u32,
46        /// Computed checksum from the data.
47        computed: u32,
48    },
49    /// Invalid or unrecognized chunk type in framed format.
50    InvalidChunkType {
51        /// The chunk type byte.
52        chunk_type: u8,
53    },
54    /// The stream identifier is missing or invalid.
55    InvalidStreamIdentifier,
56    /// The compressed data is corrupted.
57    CorruptedData {
58        /// Description of the corruption.
59        message: String,
60    },
61    /// An I/O error occurred.
62    Io(io::Error),
63}
64
65impl fmt::Display for SnappyError {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        match self {
68            Self::UnexpectedEof { context } => {
69                write!(f, "unexpected end of input: {context}")
70            }
71            Self::InvalidLength { length, max_length } => {
72                write!(f, "invalid decompressed length {length} (max {max_length})")
73            }
74            Self::InvalidTag { tag, offset } => {
75                write!(f, "invalid tag byte {tag:#04x} at offset {offset}")
76            }
77            Self::InvalidOffset { offset, position } => {
78                write!(
79                    f,
80                    "invalid back-reference offset {offset} at output position {position}"
81                )
82            }
83            Self::OutputLengthMismatch { expected, actual } => {
84                write!(
85                    f,
86                    "output length mismatch: expected {expected}, got {actual}"
87                )
88            }
89            Self::ChecksumMismatch { expected, computed } => {
90                write!(
91                    f,
92                    "CRC32C checksum mismatch: expected {expected:#010x}, computed {computed:#010x}"
93                )
94            }
95            Self::InvalidChunkType { chunk_type } => {
96                write!(f, "invalid chunk type: {chunk_type:#04x}")
97            }
98            Self::InvalidStreamIdentifier => {
99                write!(f, "missing or invalid stream identifier")
100            }
101            Self::CorruptedData { message } => {
102                write!(f, "corrupted data: {message}")
103            }
104            Self::Io(err) => write!(f, "I/O error: {err}"),
105        }
106    }
107}
108
109impl std::error::Error for SnappyError {
110    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
111        match self {
112            Self::Io(err) => Some(err),
113            _ => None,
114        }
115    }
116}
117
118impl From<io::Error> for SnappyError {
119    fn from(err: io::Error) -> Self {
120        Self::Io(err)
121    }
122}
123
124impl From<SnappyError> for io::Error {
125    fn from(err: SnappyError) -> Self {
126        match err {
127            SnappyError::Io(e) => e,
128            other => io::Error::new(io::ErrorKind::InvalidData, other.to_string()),
129        }
130    }
131}
132
133impl From<SnappyError> for oxiarc_core::error::OxiArcError {
134    fn from(err: SnappyError) -> Self {
135        match err {
136            SnappyError::Io(e) => Self::Io(e),
137            SnappyError::ChecksumMismatch { expected, computed } => {
138                Self::CrcMismatch { expected, computed }
139            }
140            SnappyError::UnexpectedEof { .. } => Self::UnexpectedEof { expected: 0 },
141            other => Self::CorruptedData {
142                offset: 0,
143                message: other.to_string(),
144            },
145        }
146    }
147}