Merge pull request #160 from fintelia/stream-pack-bits

Make PackBitsReader incrementally decompress output
This commit is contained in:
HeroicKatora authored and GitHub committed 2022-04-16 22:22:28 +02:00
commit 9f2508e37e
2 files changed
+52 -40

No files matched your search

+1 -3
View File
@@ -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))
} }
+51 -37
View File
@@ -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,
}
}
}
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]; let mut header: [u8; 1] = [0];
let mut data: [u8; 1] = [0]; self.reader.read_exact(&mut header)?;
let mut bytes_read = 0;
while bytes_read < length {
reader.read_exact(&mut header)?;
bytes_read += 1;
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();