1use core::{array::TryFromSliceError, fmt};
2
3use alloc::{borrow::ToOwned, boxed::Box, vec::Vec};
4use base64::{prelude::BASE64_STANDARD, Engine};
5use embedded_heatshrink::{
6 HSDFinishRes, HSDPollRes, HSDSinkRes, HeatshrinkDecoder,
7};
8use meatpack::Unpacker;
9use miniz_oxide::inflate::decompress_to_vec_zlib;
10
11use crate::components::common::{
12 crc32, BinaryGcodeError, BlockKind, Checksum, CompressionAlgorithm,
13 Encoding, MAGIC,
14};
15
16enum DeserialiserState {
19 FileHeader,
20 Block,
21}
22
23#[derive(Debug)]
25pub enum DeserialisedResult {
26 FileHeader(DeserialisedFileHeader),
27 MoreBytesRequired(usize),
28 Block(DeserialisedBlock),
29}
30
31#[derive(Debug)]
33pub struct DeserialisedFileHeader {
34 pub magic: u32,
35 pub version: u32,
36 pub checksum: Checksum,
37}
38
39pub(crate) fn try_from_slice<const N: usize>(
41 buf: &[u8]
42) -> Result<[u8; N], BinaryGcodeError> {
43 let bytes: Result<[u8; N], TryFromSliceError> = buf.try_into();
44 match bytes {
45 Ok(bytes) => Ok(bytes),
46 Err(_) => Err(BinaryGcodeError::TryFromSliceError),
47 }
48}
49
50pub struct Deserialiser {
55 pub inner: Vec<u8>,
56 state: DeserialiserState,
57 checksum: Checksum,
58}
59
60impl Default for Deserialiser {
61 fn default() -> Self {
62 Self {
63 inner: Vec::new(),
64 state: DeserialiserState::FileHeader,
65 checksum: Checksum::None,
66 }
67 }
68}
69
70impl Deserialiser {
71 pub fn digest(
73 &mut self,
74 buf: &[u8],
75 ) {
76 self.inner.extend(buf);
77 }
78
79 pub fn reset(&mut self) {
81 self.inner.clear();
82 self.state = DeserialiserState::FileHeader;
83 }
84
85 pub fn deserialise(
88 &mut self
89 ) -> Result<DeserialisedResult, BinaryGcodeError> {
90 match self.state {
91 DeserialiserState::FileHeader => self.deserialise_file_header(),
92 DeserialiserState::Block => self.deserialise_block(),
93 }
94 }
95
96 fn deserialise_file_header(
98 &mut self
99 ) -> Result<DeserialisedResult, BinaryGcodeError> {
100 if self.inner.len() < 10 {
101 return Ok(DeserialisedResult::MoreBytesRequired(
102 10 - self.inner.len(),
103 ));
104 }
105 let bytes = try_from_slice::<4>(&self.inner[0..=3])?;
107 let magic = u32::from_le_bytes(bytes);
108 if magic != MAGIC {
109 return Err(BinaryGcodeError::InvalidMagic(magic));
110 }
111
112 let bytes = try_from_slice::<4>(&self.inner[4..=7])?;
113 let version = u32::from_le_bytes(bytes);
114
115 let bytes = try_from_slice::<2>(&self.inner[8..=9])?;
116 let checksum_value = u16::from_le_bytes(bytes);
117
118 let checksum = match checksum_value {
119 1 => Checksum::Crc32,
120 0 => Checksum::None,
121 v => return Err(BinaryGcodeError::InvalidChecksumType(v)),
122 };
123
124 let fh = DeserialisedFileHeader {
125 magic,
126 version,
127 checksum: checksum.clone(),
128 };
129
130 self.checksum = checksum;
131 self.state = DeserialiserState::Block;
132 self.inner.drain(..10);
133
134 Ok(DeserialisedResult::FileHeader(fh))
135 }
136
137 fn deserialise_block(
139 &mut self
140 ) -> Result<DeserialisedResult, BinaryGcodeError> {
141 if self.inner.len() < 12 {
143 return Ok(DeserialisedResult::MoreBytesRequired(
144 12 - self.inner.len(),
145 ));
146 }
147
148 let bytes = try_from_slice::<2>(&self.inner[0..=1])?;
150 let kind = BlockKind::from_le_bytes(bytes)?;
151
152 let bytes = try_from_slice::<2>(&self.inner[2..=3])?;
153 let compression = CompressionAlgorithm::from_le_bytes(bytes)?;
154
155 let bytes = try_from_slice::<4>(&self.inner[4..=7])?;
156 let data_uncompressed_len = u32::from_le_bytes(bytes) as usize;
157
158 let data_compressed_len: Option<usize> = match compression {
159 CompressionAlgorithm::None => None,
160 _ => {
161 let bytes = try_from_slice::<4>(&self.inner[8..=11])?;
162 Some(u32::from_le_bytes(bytes) as usize)
163 }
164 };
165
166 let param_len = match kind {
167 BlockKind::Thumbnail => 6,
168 _ => 2,
169 };
170
171 let block_len = match data_compressed_len {
173 Some(compressed_len) => {
174 let mut block_len = 12 + param_len + compressed_len;
176 if self.checksum == Checksum::Crc32 {
177 block_len += 4;
178 }
179 if self.inner.len() < block_len {
180 return Ok(DeserialisedResult::MoreBytesRequired(
181 block_len - self.inner.len(),
182 ));
183 }
184 block_len
185 }
186 None => {
187 let mut block_len = 8 + param_len + data_uncompressed_len;
188 if self.checksum == Checksum::Crc32 {
189 block_len += 4;
190 }
191 if self.inner.len() < block_len {
192 return Ok(DeserialisedResult::MoreBytesRequired(
193 block_len - self.inner.len(),
194 ));
195 }
196 block_len
197 }
198 };
199
200 match self.checksum {
202 Checksum::None => {}
203 Checksum::Crc32 => {
204 let bytes =
205 try_from_slice::<4>(&self.inner[block_len - 4..block_len])?;
206 let c = u32::from_le_bytes(bytes);
207 let chk = crc32(&self.inner[..block_len - 4]);
208 if c != chk {
209 return Err(BinaryGcodeError::InvalidChecksum(c, chk));
210 }
211 }
212 }
213
214 let param_start = match data_compressed_len {
215 Some(_) => 12,
216 None => 8,
217 };
218
219 let encoding = &self.inner[param_start..param_start + 2];
220 let encoding = try_from_slice::<2>(encoding)?;
221 let encoding = Encoding::from_le_bytes(encoding, &kind)?;
222
223 let parameters = self.inner[param_start..param_start + param_len]
224 .to_owned()
225 .into_boxed_slice();
226 let data = self.inner[param_start + param_len..block_len - 4]
227 .to_owned()
228 .into_boxed_slice();
229
230 let b = DeserialisedBlock {
232 kind,
233 data_compressed_len,
234 data_uncompressed_len,
235 compression,
236 encoding,
237 parameters,
238 data,
239 };
240
241 self.inner.drain(..block_len);
242
243 Ok(DeserialisedResult::Block(b))
244 }
245}
246
247#[derive(Debug)]
248pub enum BlockError {
249 DecodeError(&'static str),
250}
251
252#[derive(Debug)]
254pub struct DeserialisedBlock {
255 pub kind: BlockKind,
256 pub data_compressed_len: Option<usize>,
257 pub data_uncompressed_len: usize,
258 pub compression: CompressionAlgorithm,
259 pub encoding: Encoding,
260 pub parameters: Box<[u8]>,
261 pub data: Box<[u8]>,
262}
263
264impl fmt::Display for DeserialisedBlock {
265 fn fmt(
266 &self,
267 f: &mut fmt::Formatter<'_>,
268 ) -> fmt::Result {
269 write!(
270 f,
271 "{:?} {{ compressed_len: {:?}, uncompressed_len: {}, compression: {:?}, encoding: {:?} }}",
272 self.kind, self.data_compressed_len, self.data_uncompressed_len, self.compression, self.encoding
273 )
274 }
275}
276
277impl DeserialisedBlock {
278 pub fn decompress(&self) -> Result<Box<[u8]>, BlockError> {
280 match self.compression {
281 CompressionAlgorithm::None => Ok(self.data.clone()),
282 CompressionAlgorithm::Deflate => {
283 let output = decompress_to_vec_zlib(&self.data);
284 if let Ok(o) = output {
285 Ok(o.into_boxed_slice())
286 } else {
287 Err(BlockError::DecodeError("deflate"))
288 }
289 }
290 CompressionAlgorithm::Heatshrink11_4 => {
291 unshrink(&self.data, self.data_uncompressed_len, 11, 4)
292 }
293 CompressionAlgorithm::Heatshrink12_4 => {
294 unshrink(&self.data, self.data_uncompressed_len, 12, 4)
295 }
296 }
297 }
298
299 pub fn to_ascii(
301 &mut self,
302 buf: &mut Vec<u8>,
303 with_block_comments: bool,
304 ) -> Result<(), BinaryGcodeError> {
305 let data = self.decompress().unwrap();
306 match self.kind {
307 BlockKind::FileMetadata => {
308 if with_block_comments {
309 buf.extend("; [FILE_METADATA_BLOCK_START]\n".as_bytes());
310 }
311 buf.extend(data);
312 if with_block_comments {
313 buf.extend("\n; [FILE_METADATA_BLOCK_END]\n".as_bytes());
315 }
316 }
317 BlockKind::PrinterMetadata => {
318 if with_block_comments {
319 buf.extend("; [PRINTER_METADATA_BLOCK_START]\n".as_bytes());
320 }
321 buf.extend(data);
322 if with_block_comments {
323 buf.extend("\n; [PRINTER_METADATA_BLOCK_END]\n".as_bytes());
324 }
325 }
326 BlockKind::PrintMetadata => {
327 if with_block_comments {
328 buf.extend("; [PRINT_METADATA_BLOCK_START]\n".as_bytes());
329 }
330 buf.extend(data);
331 if with_block_comments {
332 buf.extend("\n; [PRINT_METADATA_BLOCK_END]\n".as_bytes());
333 }
334 }
335 BlockKind::SlicerMetadata => {
336 if with_block_comments {
337 buf.extend("; [SLICER_METADATA_BLOCK_START]\n".as_bytes());
338 }
339 buf.extend(data);
340 if with_block_comments {
341 buf.extend("\n; [SLICER_METADATA_BLOCK_END]\n".as_bytes());
342 }
343 }
344 BlockKind::Thumbnail => {
345 let width = try_from_slice::<2>(&self.parameters[2..=3])?;
347 let width = u16::from_le_bytes(width);
348 let height = try_from_slice::<2>(&self.parameters[4..=5])?;
349 let height = u16::from_le_bytes(height);
350
351 if with_block_comments {
352 buf.extend("; [THUMBNAIL_BLOCK_START]\n".as_bytes());
353 }
354 let r = BASE64_STANDARD.encode(&data).into_bytes();
355 match self.encoding {
356 Encoding::Png => {
357 let header = format!(
358 "; thumbnail begin {}x{} {}\n",
359 width,
360 height,
361 r.len()
362 );
363 buf.extend(header.as_bytes());
364 }
365 Encoding::Jpg => {
366 let header = format!(
367 "; thumbnail_JPG begin {}x{} {}\n",
368 width,
369 height,
370 r.len()
371 );
372 buf.extend(header.as_bytes());
373 }
374 Encoding::Qoi => {
375 let header = format!(
376 "; thumbnail_QOI begin {}x{} {}\n",
377 width,
378 height,
379 r.len()
380 );
381 buf.extend(header.as_bytes());
382 }
383 _ => {}
384 }
385 for chunk in r.chunks(78) {
387 buf.extend("; ".as_bytes());
388 buf.extend(chunk);
389 buf.push(b'\n');
390 }
391 match self.encoding {
392 Encoding::Png => {
393 buf.extend("; thumbnail end \n\n".as_bytes())
394 }
395 Encoding::Jpg => {
396 buf.extend("; thumbnail_JPG end \n\n".as_bytes())
397 }
398 Encoding::Qoi => {
399 buf.extend("; thumbnail_QOI end \n\n".as_bytes())
400 }
401 _ => {}
402 }
403 if with_block_comments {
404 buf.extend("; [THUMBNAIL_BLOCK_END]\n".as_bytes());
405 }
406 }
407 BlockKind::GCode => {
408 if with_block_comments {
409 buf.extend("; [GCODE_BLOCK_START]\n".as_bytes());
410 }
411 match self.encoding {
412 Encoding::Ascii => buf.extend(data),
413 Encoding::Meatpack => {
414 if let Some(e) =
416 Unpacker::<64>::unpack_slice(&data, buf).err()
417 {
418 return Err(BinaryGcodeError::Meatpack(e));
419 }
420 }
421 Encoding::MeatpackWithComments => {
422 if let Some(e) =
423 Unpacker::<64>::unpack_slice(&data, buf).err()
424 {
425 return Err(BinaryGcodeError::Meatpack(e));
426 }
427 }
428 _ => {}
429 }
430 if with_block_comments {
431 buf.extend("; [GCODE_BLOCK_END]\n".as_bytes());
432 }
433 }
434 }
435 Ok(())
436 }
437}
438
439fn unshrink(
441 input: &[u8],
442 uncompressed_len: usize,
443 window: u8,
444 lookahead: u8,
445) -> Result<Box<[u8]>, BlockError> {
446 let input_buffer_size = input.len();
447 let mut decoder =
448 HeatshrinkDecoder::new(input_buffer_size as u16, window, lookahead)
449 .unwrap();
450 let mut uncompressed: Vec<u8> = vec![0; uncompressed_len];
451 let mut sunk: usize = 0;
452 let mut polled: usize = 0;
453
454 while sunk < input_buffer_size {
455 match decoder.sink(&input[sunk..]) {
456 HSDSinkRes::Ok(sz) => {
457 sunk += sz;
458 }
459 HSDSinkRes::Full => {
460 return Err(BlockError::DecodeError("HSDSinkRes::Full"))
461 }
462 HSDSinkRes::ErrorNull => {
463 return Err(BlockError::DecodeError("HSDSinkRes::ErrorNull"))
464 }
465 }
466 loop {
467 let res = decoder.poll(&mut uncompressed[polled..]);
468 match res {
469 HSDPollRes::Empty(sz) => {
470 polled += sz;
471 if sz == 0 {
472 break;
473 }
474 }
475 HSDPollRes::More(sz) => {
479 polled += sz;
480 break;
481 }
482 HSDPollRes::ErrorNull => {
483 return Err(BlockError::DecodeError(
484 "HSDPollRes::ErrorNull",
485 ))
486 }
487 HSDPollRes::ErrorUnknown => {
488 return Err(BlockError::DecodeError(
489 "HSDPollRes::ErrorUnknown",
490 ))
491 }
492 }
493 }
494 }
495
496 loop {
497 match decoder.finish() {
498 HSDFinishRes::Done => break,
499 HSDFinishRes::More => {
500 match decoder.poll(&mut uncompressed[polled..]) {
501 HSDPollRes::Empty(sz) => {
502 polled += sz;
503 if sz == 0 {
504 break;
505 }
506 }
507 HSDPollRes::More(sz) => {
508 polled += sz;
509 }
510 HSDPollRes::ErrorUnknown => {
511 return Err(BlockError::DecodeError(
512 "HSDPollRes::ErrorUnknown",
513 ))
514 }
515 HSDPollRes::ErrorNull => {
516 return Err(BlockError::DecodeError(
517 "HSDPollRes::ErrorNull",
518 ))
519 }
520 }
521 }
522 HSDFinishRes::ErrorNull => {
523 return Err(BlockError::DecodeError("HSDFinishRes::ErrorNull"))
524 }
525 }
526 }
527
528 Ok(uncompressed.into_boxed_slice())
529}