gcode_nom/binary/
inflate.rs

1use std::sync::LazyLock;
2
3use heatshrink::decode;
4use heatshrink::Config;
5use meatpack::MeatPackResult;
6use meatpack::Unpacker;
7use nom::bytes::streaming::take;
8use nom::Err::Error;
9use nom::IResult;
10
11use super::block_header::BlockHeader;
12use super::default_params::Encoding;
13use super::BlockError;
14use super::CompressionType;
15
16use inflate::inflate_bytes_zlib;
17
18static CONFIG_W12_L4: LazyLock<Config> =
19    LazyLock::new(|| Config::new(12, 4).expect("Failed to configure HeatshrinkW11L4 decoder"));
20
21/// Return type for `decompress_data_block`.
22#[derive(Debug)]
23pub enum DecompressError {
24    /// Unexpected length while taking data.
25    None,
26    /// Error decompressing, with the "`Deflate`" algorithm.
27    Deflate,
28    /// Error decompressing, with the "`HeatShrink11`" algorithm.
29    HeatShrink11,
30    /// Error decompressing, with the "`HeatShrink12`" algorithm.
31    HeatShrink12,
32    /// Error decompressing, with the  "`MeatPackAlgorithm`" algorithm.
33    MeatPackAlgorithm,
34}
35
36/// Decompresses the data block
37///
38/// Using the appropriate decompression algorithm and encoding type.
39///
40/// # Panics
41///  Some decompression algorithms are unimplemented
42///
43/// # Errors
44///
45/// When matching fails.
46pub fn decompress_data_block<'a>(
47    data: &'a [u8],
48    encoding: &Encoding,
49    header: &BlockHeader,
50) -> IResult<&'a [u8], Vec<u8>, DecompressError> {
51    // Decompress data-block
52    let (after_data, data) = match header.compression_type {
53        CompressionType::None => {
54            let (remain, data_raw) = take(header.uncompressed_size)(data)
55                .map_err(|e| e.map(|_e: nom::error::Error<_>| DecompressError::None))?;
56            (remain, data_raw.to_vec())
57        }
58        CompressionType::Deflate => {
59            let (remain, encoded) = take(header.compressed_size.unwrap())(data)
60                .map_err(|e| e.map(|_e: nom::error::Error<_>| DecompressError::Deflate))?;
61
62            match inflate_bytes_zlib(encoded) {
63                Ok(decoded) => (remain, decoded),
64                Err(msg) => {
65                    log::error!("Failed to decode decompression failed {msg}");
66                    return Err(Error(DecompressError::Deflate))?;
67                }
68            }
69        }
70        CompressionType::HeatShrink11 => {
71            let (_remain, _data_compressed) = take(header.uncompressed_size)(data)
72                .map_err(|e| e.map(|_e: nom::error::Error<_>| DecompressError::HeatShrink11))?;
73            // Must decompress here
74            log::info!("TODO: Must implement decompression");
75            todo!()
76        }
77        CompressionType::HeatShrink12 => {
78            let (remain, encoded) = take::<_, _, BlockError>(header.compressed_size.unwrap())(data)
79                .map_err(|e| e.map(|_e| DecompressError::HeatShrink12))?;
80
81            // TODO Figure out why size is is off by 1 -  crashes with buffer was not large enough.
82            let mut scratch = vec![0u8; 1 + header.uncompressed_size as usize];
83
84            let data = match decode(encoded, &mut scratch, &CONFIG_W12_L4) {
85                Ok(decoded_hs) => match encoding {
86                    Encoding::None => scratch,
87                    Encoding::MeatPackAlgorithm => {
88                        log::error!("Must decode with standard meat packing algorithm");
89                        unimplemented!("Decoding with the meatpacking algorithm is not yet support please create an issue.");
90                    }
91                    Encoding::MeatPackModifiedAlgorithm => {
92                        let mut data = vec![];
93                        let mut unpacker = Unpacker::<64>::default();
94                        for b in decoded_hs {
95                            match unpacker.unpack(b) {
96                                Ok(MeatPackResult::WaitingForNextByte) => {
97                                    // absorb byte and continue
98                                }
99                                Ok(MeatPackResult::Line(line)) => {
100                                    data.extend_from_slice(line);
101                                }
102                                Err(_e) => {
103                                    // let msg = format!("Failed running the deflate MeatPackModifiedAlgorithm 'unpack()' algorithm {e:?}");
104                                    // log::error!("{msg}");
105                                    return Err(nom::Err::Error(
106                                        DecompressError::MeatPackAlgorithm,
107                                    ));
108                                }
109                            }
110                        }
111                        data
112                    }
113                },
114                Err(_e) => {
115                    // let msg = format!("GCodeBlock:  Failed running the deflate MeatPackModifiedAlgorithm 'decode()' algorithm {e:?}");
116                    // log::error!("{msg}");
117                    return Err(nom::Err::Error(DecompressError::MeatPackAlgorithm));
118                }
119            };
120
121            (remain, data)
122        }
123    };
124
125    Ok((after_data, data))
126}