Files
cli/vendor/russh/src/compression.rs

194 lines
5.3 KiB
Rust

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<str> for Name {
fn as_ref(&self) -> &str {
self.0
}
}
impl TryFrom<&str> for Name {
type Error = ();
fn try_from(s: &str) -> Result<Name, ()> {
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_])
}
}
}
}