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(kind:io::ErrorKind::Other, error: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: u8| escape_default(b)).map(|b: u8| b as char).collect()
340}
341