snap/
error.rs

1use std::fmt;
2use std::io;
3use std::result;
4
5/// A convenient type alias for `Result<T, snap::Error>`.
6pub type Result<T> = result::Result<T, Error>;
7
8/// `IntoInnerError` occurs when consuming an encoder fails.
9///
10/// Consuming the encoder causes a flush to happen. If the flush fails, then
11/// this error is returned, which contains both the original encoder and the
12/// error that occurred.
13///
14/// The type parameter `W` is the unconsumed writer.
15pub struct IntoInnerError<W> {
16    wtr: W,
17    err: io::Error,
18}
19
20impl<W> IntoInnerError<W> {
21    pub(crate) fn new(wtr: W, err: io::Error) -> IntoInnerError<W> {
22        IntoInnerError { wtr, err }
23    }
24
25    /// Returns the error which caused the call to `into_inner` to fail.
26    ///
27    /// This error was returned when attempting to flush the internal buffer.
28    pub fn error(&self) -> &io::Error {
29        &self.err
30    }
31
32    /// Returns the error which caused the call to `into_inner` to fail.
33    ///
34    /// This error was returned when attempting to flush the internal buffer.
35    pub fn into_error(self) -> io::Error {
36        self.err
37    }
38
39    /// Returns the underlying writer which generated the error.
40    ///
41    /// The returned value can be used for error recovery, such as
42    /// re-inspecting the buffer.
43    pub fn into_inner(self) -> W {
44        self.wtr
45    }
46}
47
48impl<W: std::any::Any> std::error::Error for IntoInnerError<W> {}
49
50impl<W> fmt::Display for IntoInnerError<W> {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        self.err.fmt(f)
53    }
54}
55
56impl<W> fmt::Debug for IntoInnerError<W> {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        self.err.fmt(f)
59    }
60}
61
62/// Error describes all the possible errors that may occur during Snappy
63/// compression or decompression.
64///
65/// Note that it's unlikely that you'll need to care about the specific error
66/// reported since all of them indicate a corrupt Snappy data or a limitation
67/// that cannot be worked around. Therefore,
68/// `From<snap::Error> for std::io::Error` is provided so that any Snappy
69/// errors will be converted to a `std::io::Error` automatically when using
70/// `try!`.
71#[derive(Clone, Debug)]
72pub enum Error {
73    /// This error occurs when the given input is too big. This can happen
74    /// during compression or decompression.
75    TooBig {
76        /// The size of the given input.
77        given: u64,
78        /// The maximum allowed size of an input buffer.
79        max: u64,
80    },
81    /// This error occurs when the given buffer is too small to contain the
82    /// maximum possible compressed bytes or the total number of decompressed
83    /// bytes.
84    BufferTooSmall {
85        /// The size of the given output buffer.
86        given: u64,
87        /// The minimum size of the output buffer.
88        min: u64,
89    },
90    /// This error occurs when trying to decompress a zero length buffer.
91    Empty,
92    /// This error occurs when an invalid header is found during decompression.
93    Header,
94    /// This error occurs when there is a mismatch between the number of
95    /// decompressed bytes reported in the header and the number of
96    /// actual decompressed bytes. In this error case, the number of actual
97    /// decompressed bytes is always less than the number reported in the
98    /// header.
99    HeaderMismatch {
100        /// The total number of decompressed bytes expected (i.e., the header
101        /// value).
102        expected_len: u64,
103        /// The total number of actual decompressed bytes.
104        got_len: u64,
105    },
106    /// This error occurs during decompression when there was a problem
107    /// reading a literal.
108    Literal {
109        /// The expected length of the literal.
110        len: u64,
111        /// The number of remaining bytes in the compressed bytes.
112        src_len: u64,
113        /// The number of remaining slots in the decompression buffer.
114        dst_len: u64,
115    },
116    /// This error occurs during decompression when there was a problem
117    /// reading a copy.
118    CopyRead {
119        /// The expected length of the copy (as encoded in the compressed
120        /// bytes).
121        len: u64,
122        /// The number of remaining bytes in the compressed bytes.
123        src_len: u64,
124    },
125    /// This error occurs during decompression when there was a problem
126    /// writing a copy to the decompression buffer.
127    CopyWrite {
128        /// The length of the copy (i.e., the total number of bytes to be
129        /// produced by this copy in the decompression buffer).
130        len: u64,
131        /// The number of remaining bytes in the decompression buffer.
132        dst_len: u64,
133    },
134    /// This error occurs during decompression when an invalid copy offset
135    /// is found. An offset is invalid if it is zero or if it is out of bounds.
136    Offset {
137        /// The offset that was read.
138        offset: u64,
139        /// The current position in the decompression buffer. If the offset is
140        /// non-zero, then the offset must be greater than this position.
141        dst_pos: u64,
142    },
143    /// This error occurs when a stream header chunk type was expected but got
144    /// a different chunk type.
145    /// This error only occurs when reading a Snappy frame formatted stream.
146    StreamHeader {
147        /// The chunk type byte that was read.
148        byte: u8,
149    },
150    /// This error occurs when the magic stream headers bytes do not match
151    /// what is expected.
152    /// This error only occurs when reading a Snappy frame formatted stream.
153    StreamHeaderMismatch {
154        /// The bytes that were read.
155        bytes: Vec<u8>,
156    },
157    /// This error occurs when an unsupported chunk type is seen.
158    /// This error only occurs when reading a Snappy frame formatted stream.
159    UnsupportedChunkType {
160        /// The chunk type byte that was read.
161        byte: u8,
162    },
163    /// This error occurs when trying to read a chunk with an unexpected or
164    /// incorrect length when reading a Snappy frame formatted stream.
165    /// This error only occurs when reading a Snappy frame formatted stream.
166    UnsupportedChunkLength {
167        /// The length of the chunk encountered.
168        len: u64,
169        /// True when this error occured while reading the stream header.
170        header: bool,
171    },
172    /// This error occurs when a checksum validity check fails.
173    /// This error only occurs when reading a Snappy frame formatted stream.
174    Checksum {
175        /// The expected checksum read from the stream.
176        expected: u32,
177        /// The computed checksum.
178        got: u32,
179    },
180}
181
182impl From<Error> for io::Error {
183    fn from(err: Error) -> io::Error {
184        io::Error::new(io::ErrorKind::Other, err)
185    }
186}
187
188impl Eq for Error {}
189
190impl PartialEq for Error {
191    fn eq(&self, other: &Error) -> bool {
192        use self::Error::*;
193        match (self, other) {
194            (
195                &TooBig { given: given1, max: max1 },
196                &TooBig { given: given2, max: max2 },
197            ) => (given1, max1) == (given2, max2),
198            (
199                &BufferTooSmall { given: given1, min: min1 },
200                &BufferTooSmall { given: given2, min: min2 },
201            ) => (given1, min1) == (given2, min2),
202            (&Empty, &Empty) | (&Header, &Header) => true,
203            (
204                &HeaderMismatch { expected_len: elen1, got_len: glen1 },
205                &HeaderMismatch { expected_len: elen2, got_len: glen2 },
206            ) => (elen1, glen1) == (elen2, glen2),
207            (
208                &Literal { len: len1, src_len: src_len1, dst_len: dst_len1 },
209                &Literal { len: len2, src_len: src_len2, dst_len: dst_len2 },
210            ) => (len1, src_len1, dst_len1) == (len2, src_len2, dst_len2),
211            (
212                &CopyRead { len: len1, src_len: src_len1 },
213                &CopyRead { len: len2, src_len: src_len2 },
214            ) => (len1, src_len1) == (len2, src_len2),
215            (
216                &CopyWrite { len: len1, dst_len: dst_len1 },
217                &CopyWrite { len: len2, dst_len: dst_len2 },
218            ) => (len1, dst_len1) == (len2, dst_len2),
219            (
220                &Offset { offset: offset1, dst_pos: dst_pos1 },
221                &Offset { offset: offset2, dst_pos: dst_pos2 },
222            ) => (offset1, dst_pos1) == (offset2, dst_pos2),
223            (&StreamHeader { byte: byte1 }, &StreamHeader { byte: byte2 }) => {
224                byte1 == byte2
225            }
226            (
227                &StreamHeaderMismatch { bytes: ref bytes1 },
228                &StreamHeaderMismatch { bytes: ref bytes2 },
229            ) => bytes1 == bytes2,
230            (
231                &UnsupportedChunkType { byte: byte1 },
232                &UnsupportedChunkType { byte: byte2 },
233            ) => byte1 == byte2,
234            (
235                &UnsupportedChunkLength { len: len1, header: header1 },
236                &UnsupportedChunkLength { len: len2, header: header2 },
237            ) => (len1, header1) == (len2, header2),
238            (
239                &Checksum { expected: e1, got: g1 },
240                &Checksum { expected: e2, got: g2 },
241            ) => (e1, g1) == (e2, g2),
242            _ => false,
243        }
244    }
245}
246
247impl std::error::Error for Error {}
248
249impl fmt::Display for Error {
250    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251        match *self {
252            Error::TooBig { given, max } => write!(
253                f,
254                "snappy: input buffer (size = {}) is larger than \
255                         allowed (size = {})",
256                given, max
257            ),
258            Error::BufferTooSmall { given, min } => write!(
259                f,
260                "snappy: output buffer (size = {}) is smaller than \
261                         required (size = {})",
262                given, min
263            ),
264            Error::Empty => write!(f, "snappy: corrupt input (empty)"),
265            Error::Header => {
266                write!(f, "snappy: corrupt input (invalid header)")
267            }
268            Error::HeaderMismatch { expected_len, got_len } => write!(
269                f,
270                "snappy: corrupt input (header mismatch; expected \
271                         {} decompressed bytes but got {})",
272                expected_len, got_len
273            ),
274            Error::Literal { len, src_len, dst_len } => write!(
275                f,
276                "snappy: corrupt input (expected literal read of \
277                         length {}; remaining src: {}; remaining dst: {})",
278                len, src_len, dst_len
279            ),
280            Error::CopyRead { len, src_len } => write!(
281                f,
282                "snappy: corrupt input (expected copy read of \
283                         length {}; remaining src: {})",
284                len, src_len
285            ),
286            Error::CopyWrite { len, dst_len } => write!(
287                f,
288                "snappy: corrupt input (expected copy write of \
289                         length {}; remaining dst: {})",
290                len, dst_len
291            ),
292            Error::Offset { offset, dst_pos } => write!(
293                f,
294                "snappy: corrupt input (expected valid offset but \
295                         got offset {}; dst position: {})",
296                offset, dst_pos
297            ),
298            Error::StreamHeader { byte } => write!(
299                f,
300                "snappy: corrupt input (expected stream header but \
301                         got unexpected chunk type byte {})",
302                byte
303            ),
304            Error::StreamHeaderMismatch { ref bytes } => write!(
305                f,
306                "snappy: corrupt input (expected sNaPpY stream \
307                         header but got {})",
308                escape(&**bytes)
309            ),
310            Error::UnsupportedChunkType { byte } => write!(
311                f,
312                "snappy: corrupt input (unsupported chunk type: {})",
313                byte
314            ),
315            Error::UnsupportedChunkLength { len, header: false } => write!(
316                f,
317                "snappy: corrupt input \
318                         (unsupported chunk length: {})",
319                len
320            ),
321            Error::UnsupportedChunkLength { len, header: true } => write!(
322                f,
323                "snappy: corrupt input \
324                         (invalid stream header length: {})",
325                len
326            ),
327            Error::Checksum { expected, got } => write!(
328                f,
329                "snappy: corrupt input (bad checksum; \
330                         expected: {}, got: {})",
331                expected, got
332            ),
333        }
334    }
335}
336
337fn escape(bytes: &[u8]) -> String {
338    use std::ascii::escape_default;
339    bytes.iter().flat_map(|&b| escape_default(b)).map(|b| b as char).collect()
340}