use crate::io;
use crate::io::{Read, Write};
use super::bufread;
use super::{GzBuilder, GzHeader};
use crate::bufreader::BufReader;
use crate::Compression;
#[derive(Debug)]
pub struct GzEncoder<R> {
inner: bufread::GzEncoder<BufReader<R>>,
}
pub fn gz_encoder<R: Read>(inner: bufread::GzEncoder<BufReader<R>>) -> GzEncoder<R> {
GzEncoder { inner }
}
impl<R: Read> GzEncoder<R> {
pub fn new(r: R, level: Compression) -> GzEncoder<R> {
GzBuilder::new().read(r, level)
}
}
impl<R> GzEncoder<R> {
pub fn get_ref(&self) -> &R {
self.inner.get_ref().get_ref()
}
pub fn get_mut(&mut self) -> &mut R {
self.inner.get_mut().get_mut()
}
pub fn into_inner(self) -> R {
self.inner.into_inner().into_inner()
}
}
impl<R: Read> Read for GzEncoder<R> {
fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
self.inner.read(into)
}
}
impl<R: Read + Write> Write for GzEncoder<R> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.get_mut().write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.get_mut().flush()
}
}
#[derive(Debug)]
pub struct GzDecoder<R> {
inner: bufread::GzDecoder<BufReader<R>>,
}
impl<R: Read> GzDecoder<R> {
pub fn new(r: R) -> GzDecoder<R> {
GzDecoder {
inner: bufread::GzDecoder::new(BufReader::new(r)),
}
}
}
impl<R> GzDecoder<R> {
pub fn header(&self) -> Option<&GzHeader> {
self.inner.header()
}
pub fn get_ref(&self) -> &R {
self.inner.get_ref().get_ref()
}
pub fn get_mut(&mut self) -> &mut R {
self.inner.get_mut().get_mut()
}
pub fn into_inner(self) -> R {
self.inner.into_inner().into_inner()
}
pub fn reset(&mut self, r: R) -> R {
super::bufread::reset_decoder_data(&mut self.inner);
self.inner.get_mut().reset(r)
}
}
impl<R: Read> Read for GzDecoder<R> {
fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
self.inner.read(into)
}
}
impl<R: Read + Write> Write for GzDecoder<R> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.get_mut().write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.get_mut().flush()
}
}
#[derive(Debug)]
pub struct MultiGzDecoder<R> {
inner: bufread::MultiGzDecoder<BufReader<R>>,
}
impl<R: Read> MultiGzDecoder<R> {
pub fn new(r: R) -> MultiGzDecoder<R> {
MultiGzDecoder {
inner: bufread::MultiGzDecoder::new(BufReader::new(r)),
}
}
}
impl<R> MultiGzDecoder<R> {
pub fn header(&self) -> Option<&GzHeader> {
self.inner.header()
}
pub fn get_ref(&self) -> &R {
self.inner.get_ref().get_ref()
}
pub fn get_mut(&mut self) -> &mut R {
self.inner.get_mut().get_mut()
}
pub fn into_inner(self) -> R {
self.inner.into_inner().into_inner()
}
}
impl<R: Read> Read for MultiGzDecoder<R> {
fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
self.inner.read(into)
}
}
impl<R: Read + Write> Write for MultiGzDecoder<R> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.get_mut().write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.get_mut().flush()
}
}
#[cfg(test)]
mod tests {
use crate::io::{Cursor, ErrorKind, Read, Result, Write};
use alloc::vec::Vec;
use super::GzDecoder;
#[derive(Debug)]
pub struct BlockingCursor {
pub cursor: Cursor<Vec<u8>>,
}
impl BlockingCursor {
pub fn new() -> BlockingCursor {
BlockingCursor {
cursor: Cursor::new(Vec::new()),
}
}
pub fn set_position(&mut self, pos: u64) {
self.cursor.set_position(pos)
}
}
impl Write for BlockingCursor {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.cursor.write(buf)
}
fn flush(&mut self) -> Result<()> {
self.cursor.flush()
}
}
impl Read for BlockingCursor {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let r = self.cursor.read(buf);
match r {
Err(ref err) => {
if err.kind() == ErrorKind::UnexpectedEof {
return Err(ErrorKind::WouldBlock.into());
}
}
Ok(0) => {
return Err(ErrorKind::WouldBlock.into());
}
Ok(_n) => {}
}
r
}
}
#[test]
fn blocked_partial_header_read() {
let mut r = BlockingCursor::new();
let data = vec![1, 2, 3];
match r.write_all(&data) {
Ok(()) => {}
_ => {
panic!("Unexpected result for write_all");
}
}
r.set_position(0);
let mut decoder = GzDecoder::new(r);
let mut out = Vec::with_capacity(7);
match decoder.read(&mut out) {
Err(e) => {
assert_eq!(e.kind(), ErrorKind::WouldBlock);
}
_ => {
panic!("Unexpected result for decoder.read");
}
}
}
fn compress_data(data: &[u8]) -> Vec<u8> {
use crate::write::GzEncoder;
use crate::Compression;
let mut e = GzEncoder::new(Vec::new(), Compression::default());
e.write_all(data).unwrap();
e.finish().unwrap()
}
#[test]
fn decode_with_reset() {
let data1 = b"Hello World";
let data2 = b"Goodbye World";
let compressed1 = compress_data(data1);
let compressed2 = compress_data(data2);
let mut output = Vec::new();
let mut decoder = GzDecoder::new(compressed1.as_slice());
decoder.read_to_end(&mut output).unwrap();
assert_eq!(output, data1);
output.clear();
decoder.reset(compressed2.as_slice());
decoder.read_to_end(&mut output).unwrap();
assert_eq!(output, data2);
}
#[test]
fn decode_with_reset_after_corruption() {
let valid_data = b"Hello World";
let valid_compressed = compress_data(valid_data);
let mut corrupted = valid_compressed.clone();
assert!(corrupted.len() > 13);
corrupted[12] ^= 0xFF;
corrupted[13] ^= 0xFF;
let mut decoder = GzDecoder::new(Cursor::new(corrupted));
let mut output = Vec::new();
let _ = decoder.read_to_end(&mut output).unwrap_err();
decoder.reset(Cursor::new(valid_compressed));
output.clear();
decoder.read_to_end(&mut output).unwrap();
assert_eq!(output, valid_data);
}
}