use std::fmt; use std::io; use std::result; /// A convenient type alias for `Result`. pub type Result = result::Result; /// `IntoInnerError` occurs when consuming an encoder fails. /// /// Consuming the encoder causes a flush to happen. If the flush fails, then /// this error is returned, which contains both the original encoder and the /// error that occurred. /// /// The type parameter `W` is the unconsumed writer. pub struct IntoInnerError { wtr: W, err: io::Error, } impl IntoInnerError { pub(crate) fn new(wtr: W, err: io::Error) -> IntoInnerError { IntoInnerError { wtr, err } } /// Returns the error which caused the call to `into_inner` to fail. /// /// This error was returned when attempting to flush the internal buffer. pub fn error(&self) -> &io::Error { &self.err } /// Returns the underlying writer which generated the error. /// /// The returned value can be used for error recovery, such as /// re-inspecting the buffer. pub fn into_inner(self) -> W { self.wtr } } impl std::error::Error for IntoInnerError {} impl fmt::Display for IntoInnerError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.err.fmt(f) } } impl fmt::Debug for IntoInnerError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.err.fmt(f) } } /// Error describes all the possible errors that may occur during Snappy /// compression or decompression. /// /// Note that it's unlikely that you'll need to care about the specific error /// reported since all of them indicate a corrupt Snappy data or a limitation /// that cannot be worked around. Therefore, /// `From for std::io::Error` is provided so that any Snappy /// errors will be converted to a `std::io::Error` automatically when using /// `try!`. #[derive(Clone, Debug)] pub enum Error { /// This error occurs when the given input is too big. This can happen /// during compression or decompression. TooBig { /// The size of the given input. given: u64, /// The maximum allowed size of an input buffer. max: u64, }, /// This error occurs when the given buffer is too small to contain the /// maximum possible compressed bytes or the total number of decompressed /// bytes. BufferTooSmall { /// The size of the given output buffer. given: u64, /// The minimum size of the output buffer. min: u64, }, /// This error occurs when trying to decompress a zero length buffer. Empty, /// This error occurs when an invalid header is found during decompression. Header, /// This error occurs when there is a mismatch between the number of /// decompressed bytes reported in the header and the number of /// actual decompressed bytes. In this error case, the number of actual /// decompressed bytes is always less than the number reported in the /// header. HeaderMismatch { /// The total number of decompressed bytes expected (i.e., the header /// value). expected_len: u64, /// The total number of actual decompressed bytes. got_len: u64, }, /// This error occurs during decompression when there was a problem /// reading a literal. Literal { /// The expected length of the literal. len: u64, /// The number of remaining bytes in the compressed bytes. src_len: u64, /// The number of remaining slots in the decompression buffer. dst_len: u64, }, /// This error occurs during decompression when there was a problem /// reading a copy. CopyRead { /// The expected length of the copy (as encoded in the compressed /// bytes). len: u64, /// The number of remaining bytes in the compressed bytes. src_len: u64, }, /// This error occurs during decompression when there was a problem /// writing a copy to the decompression buffer. CopyWrite { /// The length of the copy (i.e., the total number of bytes to be /// produced by this copy in the decompression buffer). len: u64, /// The number of remaining bytes in the decompression buffer. dst_len: u64, }, /// This error occurs during decompression when an invalid copy offset /// is found. An offset is invalid if it is zero or if it is out of bounds. Offset { /// The offset that was read. offset: u64, /// The current position in the decompression buffer. If the offset is /// non-zero, then the offset must be greater than this position. dst_pos: u64, }, /// This error occurs when a stream header chunk type was expected but got /// a different chunk type. /// This error only occurs when reading a Snappy frame formatted stream. StreamHeader { /// The chunk type byte that was read. byte: u8, }, /// This error occurs when the magic stream headers bytes do not match /// what is expected. /// This error only occurs when reading a Snappy frame formatted stream. StreamHeaderMismatch { /// The bytes that were read. bytes: Vec, }, /// This error occurs when an unsupported chunk type is seen. /// This error only occurs when reading a Snappy frame formatted stream. UnsupportedChunkType { /// The chunk type byte that was read. byte: u8, }, /// This error occurs when trying to read a chunk with an unexpected or /// incorrect length when reading a Snappy frame formatted stream. /// This error only occurs when reading a Snappy frame formatted stream. UnsupportedChunkLength { /// The length of the chunk encountered. len: u64, /// True when this error occured while reading the stream header. header: bool, }, /// This error occurs when a checksum validity check fails. /// This error only occurs when reading a Snappy frame formatted stream. Checksum { /// The expected checksum read from the stream. expected: u32, /// The computed checksum. got: u32, }, } impl From for io::Error { fn from(err: Error) -> io::Error { io::Error::new(io::ErrorKind::Other, err) } } impl Eq for Error {} impl PartialEq for Error { fn eq(&self, other: &Error) -> bool { use self::Error::*; match (self, other) { ( &TooBig { given: given1, max: max1 }, &TooBig { given: given2, max: max2 }, ) => (given1, max1) == (given2, max2), ( &BufferTooSmall { given: given1, min: min1 }, &BufferTooSmall { given: given2, min: min2 }, ) => (given1, min1) == (given2, min2), (&Empty, &Empty) | (&Header, &Header) => true, ( &HeaderMismatch { expected_len: elen1, got_len: glen1 }, &HeaderMismatch { expected_len: elen2, got_len: glen2 }, ) => (elen1, glen1) == (elen2, glen2), ( &Literal { len: len1, src_len: src_len1, dst_len: dst_len1 }, &Literal { len: len2, src_len: src_len2, dst_len: dst_len2 }, ) => (len1, src_len1, dst_len1) == (len2, src_len2, dst_len2), ( &CopyRead { len: len1, src_len: src_len1 }, &CopyRead { len: len2, src_len: src_len2 }, ) => (len1, src_len1) == (len2, src_len2), ( &CopyWrite { len: len1, dst_len: dst_len1 }, &CopyWrite { len: len2, dst_len: dst_len2 }, ) => (len1, dst_len1) == (len2, dst_len2), ( &Offset { offset: offset1, dst_pos: dst_pos1 }, &Offset { offset: offset2, dst_pos: dst_pos2 }, ) => (offset1, dst_pos1) == (offset2, dst_pos2), (&StreamHeader { byte: byte1 }, &StreamHeader { byte: byte2 }) => { byte1 == byte2 } ( &StreamHeaderMismatch { bytes: ref bytes1 }, &StreamHeaderMismatch { bytes: ref bytes2 }, ) => bytes1 == bytes2, ( &UnsupportedChunkType { byte: byte1 }, &UnsupportedChunkType { byte: byte2 }, ) => byte1 == byte2, ( &UnsupportedChunkLength { len: len1, header: header1 }, &UnsupportedChunkLength { len: len2, header: header2 }, ) => (len1, header1) == (len2, header2), ( &Checksum { expected: e1, got: g1 }, &Checksum { expected: e2, got: g2 }, ) => (e1, g1) == (e2, g2), _ => false, } } } impl std::error::Error for Error {} impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Error::TooBig { given, max } => write!( f, "snappy: input buffer (size = {}) is larger than \ allowed (size = {})", given, max ), Error::BufferTooSmall { given, min } => write!( f, "snappy: output buffer (size = {}) is smaller than \ required (size = {})", given, min ), Error::Empty => write!(f, "snappy: corrupt input (empty)"), Error::Header => { write!(f, "snappy: corrupt input (invalid header)") } Error::HeaderMismatch { expected_len, got_len } => write!( f, "snappy: corrupt input (header mismatch; expected \ {} decompressed bytes but got {})", expected_len, got_len ), Error::Literal { len, src_len, dst_len } => write!( f, "snappy: corrupt input (expected literal read of \ length {}; remaining src: {}; remaining dst: {})", len, src_len, dst_len ), Error::CopyRead { len, src_len } => write!( f, "snappy: corrupt input (expected copy read of \ length {}; remaining src: {})", len, src_len ), Error::CopyWrite { len, dst_len } => write!( f, "snappy: corrupt input (expected copy write of \ length {}; remaining dst: {})", len, dst_len ), Error::Offset { offset, dst_pos } => write!( f, "snappy: corrupt input (expected valid offset but \ got offset {}; dst position: {})", offset, dst_pos ), Error::StreamHeader { byte } => write!( f, "snappy: corrupt input (expected stream header but \ got unexpected chunk type byte {})", byte ), Error::StreamHeaderMismatch { ref bytes } => write!( f, "snappy: corrupt input (expected sNaPpY stream \ header but got {})", escape(&**bytes) ), Error::UnsupportedChunkType { byte } => write!( f, "snappy: corrupt input (unsupported chunk type: {})", byte ), Error::UnsupportedChunkLength { len, header: false } => write!( f, "snappy: corrupt input \ (unsupported chunk length: {})", len ), Error::UnsupportedChunkLength { len, header: true } => write!( f, "snappy: corrupt input \ (invalid stream header length: {})", len ), Error::Checksum { expected, got } => write!( f, "snappy: corrupt input (bad checksum; \ expected: {}, got: {})", expected, got ), } } } fn escape(bytes: &[u8]) -> String { use std::ascii::escape_default; bytes.iter().flat_map(|&b| escape_default(b)).map(|b| b as char).collect() }