geotiff_rs/parser/
compression.rs

1use weezl::{decode::Decoder, BitOrder, LzwStatus};
2
3use super::TiffParserError;
4
5pub trait Decompressor {
6    fn decompress(&mut self, bytes: &[u8], size: usize) -> Result<Vec<u8>, TiffParserError>;
7}
8
9const COMPRESSION_NONE: u16 = 1;
10const COMPRESSION_LZW: u16 = 5;
11
12pub fn create_decompressor(compression: u16) -> Result<Box<dyn Decompressor>, TiffParserError> {
13    match compression {
14        COMPRESSION_NONE => Ok(Box::new(DummyDecompressor)),
15        COMPRESSION_LZW => Ok(Box::new(Decoder::with_tiff_size_switch(BitOrder::Msb, 8))),
16        compression => Err(TiffParserError::UnknownCompression(compression)),
17    }
18}
19
20struct DummyDecompressor;
21
22impl Decompressor for DummyDecompressor {
23    fn decompress(&mut self, bytes: &[u8], size: usize) -> Result<Vec<u8>, TiffParserError> {
24        Ok(bytes[..size].to_vec())
25    }
26}
27
28impl Decompressor for Decoder {
29    fn decompress(&mut self, bytes: &[u8], size: usize) -> Result<Vec<u8>, TiffParserError> {
30        let mut result = vec![0; size];
31        let mut consumed_in = 0;
32        let mut consumed_out = 0;
33        loop {
34            let decode_result =
35                self.decode_bytes(&bytes[consumed_in..], &mut result[consumed_out..]);
36            consumed_in += decode_result.consumed_in;
37            consumed_out += decode_result.consumed_out;
38            match decode_result.status {
39                Ok(LzwStatus::Ok) => {}
40                Ok(LzwStatus::NoProgress) => {
41                    return Ok(result);
42                }
43                Ok(LzwStatus::Done) => {
44                    return Ok(result);
45                }
46                Err(err) => {
47                    eprintln!(
48                        "error {}; size = {}, consumed_out = {}",
49                        err, size, consumed_out
50                    );
51                    if consumed_out >= size {
52                        return Ok(result);
53                    } else {
54                        return Err(err.into());
55                    }
56                }
57            }
58            if consumed_out >= size {
59                return Ok(result);
60            }
61        }
62    }
63}