1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
use crate::{codec::Encode, util::PartialBuffer};
use std::{fmt, io};
use bzip2::{Action, Compress, Compression, Status};
pub struct BzEncoder {
compress: Compress,
}
impl fmt::Debug for BzEncoder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"BzEncoder {{total_in: {}, total_out: {}}}",
self.compress.total_in(),
self.compress.total_out()
)
}
}
impl BzEncoder {
/// Creates a new stream prepared for compression.
///
/// The `work_factor` parameter controls how the compression phase behaves
/// when presented with worst case, highly repetitive, input data. If
/// compression runs into difficulties caused by repetitive data, the
/// library switches from the standard sorting algorithm to a fallback
/// algorithm. The fallback is slower than the standard algorithm by perhaps
/// a factor of three, but always behaves reasonably, no matter how bad the
/// input.
///
/// Lower values of `work_factor` reduce the amount of effort the standard
/// algorithm will expend before resorting to the fallback. You should set
/// this parameter carefully; too low, and many inputs will be handled by
/// the fallback algorithm and so compress rather slowly, too high, and your
/// average-to-worst case compression times can become very large. The
/// default value of 30 gives reasonable behaviour over a wide range of
/// circumstances.
///
/// Allowable values range from 0 to 250 inclusive. 0 is a special case,
/// equivalent to using the default value of 30.
pub(crate) fn new(level: Compression, work_factor: u32) -> Self {
Self {
compress: Compress::new(level, work_factor),
}
}
fn encode(
&mut self,
input: &mut PartialBuffer<impl AsRef<[u8]>>,
output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
action: Action,
) -> io::Result<Status> {
let prior_in = self.compress.total_in();
let prior_out = self.compress.total_out();
let status = self
.compress
.compress(input.unwritten(), output.unwritten_mut(), action)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
input.advance((self.compress.total_in() - prior_in) as usize);
output.advance((self.compress.total_out() - prior_out) as usize);
Ok(status)
}
}
impl Encode for BzEncoder {
fn encode(
&mut self,
input: &mut PartialBuffer<impl AsRef<[u8]>>,
output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
) -> io::Result<()> {
match self.encode(input, output, Action::Run)? {
// Decompression went fine, nothing much to report.
Status::Ok => Ok(()),
// The Flush action on a compression went ok.
Status::FlushOk => unreachable!(),
// The Run action on compression went ok.
Status::RunOk => Ok(()),
// The Finish action on compression went ok.
Status::FinishOk => unreachable!(),
// The stream's end has been met, meaning that no more data can be input.
Status::StreamEnd => unreachable!(),
// There was insufficient memory in the input or output buffer to complete
// the request, but otherwise everything went normally.
Status::MemNeeded => Err(io::Error::new(io::ErrorKind::Other, "out of memory")),
}
}
fn flush(
&mut self,
output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
) -> io::Result<bool> {
match self.encode(&mut PartialBuffer::new(&[][..]), output, Action::Flush)? {
// Decompression went fine, nothing much to report.
Status::Ok => unreachable!(),
// The Flush action on a compression went ok.
Status::FlushOk => Ok(false),
// The Run action on compression went ok.
Status::RunOk => Ok(true),
// The Finish action on compression went ok.
Status::FinishOk => unreachable!(),
// The stream's end has been met, meaning that no more data can be input.
Status::StreamEnd => unreachable!(),
// There was insufficient memory in the input or output buffer to complete
// the request, but otherwise everything went normally.
Status::MemNeeded => Err(io::Error::new(io::ErrorKind::Other, "out of memory")),
}
}
fn finish(
&mut self,
output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
) -> io::Result<bool> {
match self.encode(&mut PartialBuffer::new(&[][..]), output, Action::Finish)? {
// Decompression went fine, nothing much to report.
Status::Ok => Ok(false),
// The Flush action on a compression went ok.
Status::FlushOk => unreachable!(),
// The Run action on compression went ok.
Status::RunOk => unreachable!(),
// The Finish action on compression went ok.
Status::FinishOk => Ok(false),
// The stream's end has been met, meaning that no more data can be input.
Status::StreamEnd => Ok(true),
// There was insufficient memory in the input or output buffer to complete
// the request, but otherwise everything went normally.
Status::MemNeeded => Err(io::Error::new(io::ErrorKind::Other, "out of memory")),
}
}
}