Merge pull request #160 from fintelia/stream-pack-bits
Make PackBitsReader incrementally decompress output
This commit is contained in:
2 files changed
+53
-41
No files matched your search
+1
-3
@@ -1141,9 +1141,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
CompressionMethod::LZW => {
|
CompressionMethod::LZW => {
|
||||||
Box::new(LZWReader::new(reader, usize::try_from(compressed_length)?))
|
Box::new(LZWReader::new(reader, usize::try_from(compressed_length)?))
|
||||||
}
|
}
|
||||||
CompressionMethod::PackBits => {
|
CompressionMethod::PackBits => Box::new(PackBitsReader::new(reader, compressed_length)),
|
||||||
Box::new(PackBitsReader::new(reader, usize::try_from(compressed_length)?)?.1)
|
|
||||||
}
|
|
||||||
CompressionMethod::Deflate | CompressionMethod::OldDeflate => {
|
CompressionMethod::Deflate | CompressionMethod::OldDeflate => {
|
||||||
Box::new(DeflateReader::new(reader))
|
Box::new(DeflateReader::new(reader))
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-38
@@ -255,56 +255,70 @@ impl Read for JpegReader {
|
|||||||
/// ## PackBits Reader
|
/// ## PackBits Reader
|
||||||
///
|
///
|
||||||
|
|
||||||
/// Reader that unpacks Apple's `PackBits` format
|
enum PackBitsReaderState {
|
||||||
pub struct PackBitsReader {
|
Header,
|
||||||
buffer: io::Cursor<Vec<u8>>,
|
Literal,
|
||||||
|
Repeat { value: u8 },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PackBitsReader {
|
/// Reader that unpacks Apple's `PackBits` format
|
||||||
|
pub struct PackBitsReader<R: Read> {
|
||||||
|
reader: Take<R>,
|
||||||
|
state: PackBitsReaderState,
|
||||||
|
count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Read> PackBitsReader<R> {
|
||||||
/// Wraps a reader
|
/// Wraps a reader
|
||||||
pub fn new<R: Read + Seek>(
|
pub fn new(reader: R, length: u64) -> Self {
|
||||||
mut reader: R,
|
Self {
|
||||||
length: usize,
|
reader: reader.take(length),
|
||||||
) -> io::Result<(usize, PackBitsReader)> {
|
state: PackBitsReaderState::Header,
|
||||||
let mut buffer = Vec::new();
|
count: 0,
|
||||||
let mut header: [u8; 1] = [0];
|
}
|
||||||
let mut data: [u8; 1] = [0];
|
}
|
||||||
|
}
|
||||||
let mut bytes_read = 0;
|
|
||||||
while bytes_read < length {
|
|
||||||
reader.read_exact(&mut header)?;
|
|
||||||
bytes_read += 1;
|
|
||||||
|
|
||||||
|
impl<R: Read> Read for PackBitsReader<R> {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
|
while let PackBitsReaderState::Header = self.state {
|
||||||
|
if self.reader.limit() == 0 {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
let mut header: [u8; 1] = [0];
|
||||||
|
self.reader.read_exact(&mut header)?;
|
||||||
let h = header[0] as i8;
|
let h = header[0] as i8;
|
||||||
if h >= -127 && h <= -1 {
|
if h >= -127 && h <= -1 {
|
||||||
let new_len = buffer.len() + (1 - h as isize) as usize;
|
let mut data: [u8; 1] = [0];
|
||||||
reader.read_exact(&mut data)?;
|
self.reader.read_exact(&mut data)?;
|
||||||
buffer.resize(new_len, data[0]);
|
self.state = PackBitsReaderState::Repeat { value: data[0] };
|
||||||
bytes_read += 1;
|
self.count = (1 - h as isize) as usize;
|
||||||
} else if h >= 0 {
|
} else if h >= 0 {
|
||||||
let num_vals = h as usize + 1;
|
self.state = PackBitsReaderState::Literal;
|
||||||
let start = buffer.len();
|
self.count = h as usize + 1;
|
||||||
buffer.resize(start + num_vals, 0);
|
|
||||||
reader.read_exact(&mut buffer[start..])?;
|
|
||||||
bytes_read += num_vals
|
|
||||||
} else {
|
} else {
|
||||||
// h = -128 is a no-op.
|
// h = -128 is a no-op.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((
|
let length = buf.len().min(self.count);
|
||||||
buffer.len(),
|
match self.state {
|
||||||
PackBitsReader {
|
PackBitsReaderState::Literal => {
|
||||||
buffer: io::Cursor::new(buffer),
|
self.reader.read(&mut buf[..length])?;
|
||||||
},
|
}
|
||||||
))
|
PackBitsReaderState::Repeat { value } => {
|
||||||
}
|
for b in &mut buf[..length] {
|
||||||
}
|
*b = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PackBitsReaderState::Header => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
impl Read for PackBitsReader {
|
self.count -= length;
|
||||||
#[inline]
|
if self.count == 0 {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
self.state = PackBitsReaderState::Header;
|
||||||
self.buffer.read(buf)
|
}
|
||||||
|
return Ok(length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,7 +391,7 @@ mod test {
|
|||||||
let encoded_len = encoded.len();
|
let encoded_len = encoded.len();
|
||||||
|
|
||||||
let buff = io::Cursor::new(encoded);
|
let buff = io::Cursor::new(encoded);
|
||||||
let (_, mut decoder) = PackBitsReader::new(buff, encoded_len).unwrap();
|
let mut decoder = PackBitsReader::new(buff, encoded_len as u64);
|
||||||
|
|
||||||
let mut decoded = Vec::new();
|
let mut decoded = Vec::new();
|
||||||
decoder.read_to_end(&mut decoded).unwrap();
|
decoder.read_to_end(&mut decoded).unwrap();
|
||||||
|
|||||||
Reference in new issue
Block a user