194 lines
5.3 KiB
Rust
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_])
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|