use std::convert::TryFrom; #[derive(Debug, Clone)] pub enum Compression { None, #[cfg(feature = "flate2")] Zlib, } #[derive(Debug)] pub enum Compress { None, #[cfg(feature = "flate2")] Zlib(flate2::Compress), } #[derive(Debug)] pub enum Decompress { None, #[cfg(feature = "flate2")] Zlib(flate2::Decompress), } #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] pub struct Name(&'static str); impl AsRef for Name { fn as_ref(&self) -> &str { self.0 } } impl TryFrom<&str> for Name { type Error = (); fn try_from(s: &str) -> Result { ALL_COMPRESSION_ALGORITHMS .iter() .find(|x| x.0 == s) .map(|x| **x) .ok_or(()) } } pub const NONE: Name = Name("none"); #[cfg(feature = "flate2")] pub const ZLIB: Name = Name("zlib"); #[cfg(feature = "flate2")] pub const ZLIB_LEGACY: Name = Name("zlib@openssh.com"); pub const ALL_COMPRESSION_ALGORITHMS: &[&Name] = &[ &NONE, #[cfg(feature = "flate2")] &ZLIB, #[cfg(feature = "flate2")] &ZLIB_LEGACY, ]; #[cfg(feature = "flate2")] impl Compression { pub fn new(name: &Name) -> Self { if name == &ZLIB || name == &ZLIB_LEGACY { Compression::Zlib } else { Compression::None } } pub fn init_compress(&self, comp: &mut Compress) { if let Compression::Zlib = *self { if let Compress::Zlib(ref mut c) = *comp { c.reset() } else { *comp = Compress::Zlib(flate2::Compress::new(flate2::Compression::fast(), true)) } } else { *comp = Compress::None } } pub fn init_decompress(&self, comp: &mut Decompress) { if let Compression::Zlib = *self { if let Decompress::Zlib(ref mut c) = *comp { c.reset(true) } else { *comp = Decompress::Zlib(flate2::Decompress::new(true)) } } else { *comp = Decompress::None } } } #[cfg(not(feature = "flate2"))] impl Compression { pub fn new(_name: &Name) -> Self { Compression::None } pub fn init_compress(&self, _: &mut Compress) {} pub fn init_decompress(&self, _: &mut Decompress) {} } #[cfg(not(feature = "flate2"))] impl Compress { pub fn compress<'a>( &mut self, input: &'a [u8], _: &'a mut russh_cryptovec::CryptoVec, ) -> Result<&'a [u8], crate::Error> { Ok(input) } } #[cfg(not(feature = "flate2"))] impl Decompress { pub fn decompress<'a>( &mut self, input: &'a [u8], _: &'a mut russh_cryptovec::CryptoVec, ) -> Result<&'a [u8], crate::Error> { Ok(input) } } #[cfg(feature = "flate2")] impl Compress { pub fn compress<'a>( &mut self, input: &'a [u8], output: &'a mut russh_cryptovec::CryptoVec, ) -> Result<&'a [u8], crate::Error> { match *self { Compress::None => Ok(input), Compress::Zlib(ref mut z) => { output.clear(); let n_in = z.total_in() as usize; let n_out = z.total_out() as usize; output.resize(input.len() + 10); let flush = flate2::FlushCompress::Partial; loop { let n_in_ = z.total_in() as usize - n_in; let n_out_ = z.total_out() as usize - n_out; #[allow(clippy::indexing_slicing)] // length checked let c = z.compress(&input[n_in_..], &mut output[n_out_..], flush)?; match c { flate2::Status::BufError => { output.resize(output.len() * 2); } _ => break, } } let n_out_ = z.total_out() as usize - n_out; #[allow(clippy::indexing_slicing)] // length checked Ok(&output[..n_out_]) } } } } #[cfg(feature = "flate2")] impl Decompress { pub fn decompress<'a>( &mut self, input: &'a [u8], output: &'a mut russh_cryptovec::CryptoVec, ) -> Result<&'a [u8], crate::Error> { match *self { Decompress::None => Ok(input), Decompress::Zlib(ref mut z) => { output.clear(); let n_in = z.total_in() as usize; let n_out = z.total_out() as usize; output.resize(input.len()); let flush = flate2::FlushDecompress::None; loop { let n_in_ = z.total_in() as usize - n_in; let n_out_ = z.total_out() as usize - n_out; #[allow(clippy::indexing_slicing)] // length checked let d = z.decompress(&input[n_in_..], &mut output[n_out_..], flush); match d? { flate2::Status::Ok => { output.resize(output.len() * 2); } _ => break, } } let n_out_ = z.total_out() as usize - n_out; #[allow(clippy::indexing_slicing)] // length checked Ok(&output[..n_out_]) } } } }