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