1use flashraw_core::bits::{BitPumpMsb, BitRead};
24use flashraw_core::{Error, Result};
25
26const LUT_BITS: u32 = 12;
27const NONE: u32 = u32::MAX;
28
29const KIND_LEAF: u32 = 1 << 6;
31const KIND_NODE: u32 = 2 << 6;
32const KIND_MASK: u32 = 3 << 6;
33
34#[derive(Debug, Clone)]
36pub struct PrefixCode {
37 nodes: Vec<[u32; 2]>,
39 values: Vec<u32>,
41 lut: Vec<u32>,
42}
43
44impl PrefixCode {
45 pub fn new(codes: &[(u32, u32, u32)]) -> Result<Self> {
47 let mut nodes = vec![[NONE, NONE]];
48 let mut values = vec![NONE];
49 for &(code, len, value) in codes {
50 if len == 0 || len > 27 {
51 return Err(Error::corrupt(format!("X3F prefix code with invalid length {len}")));
52 }
53 if value >= 1 << 24 {
54 return Err(Error::corrupt("X3F prefix code value out of range"));
55 }
56 let mut n = 0usize;
57 for i in (0..len).rev() {
58 let bit = ((code >> i) & 1) as usize;
59 let next = nodes[n][bit];
60 n = if next == NONE {
61 nodes.push([NONE, NONE]);
62 values.push(NONE);
63 let idx = nodes.len() - 1;
64 nodes[n][bit] = idx as u32;
65 idx
66 } else {
67 next as usize
68 };
69 }
70 values[n] = value;
71 }
72 if nodes[0] == [NONE, NONE] {
73 return Err(Error::corrupt("X3F prefix code without codes"));
74 }
75 let mut code = PrefixCode { nodes, values, lut: Vec::new() };
76 code.build_lut();
77 Ok(code)
78 }
79
80 pub fn walk(&self, prefix: u32, nbits: u32) -> Option<(u32, u32)> {
83 let mut n = 0usize;
84 for len in 0..=nbits {
85 if self.is_leaf(n) {
86 return (self.values[n] != NONE).then_some((len, self.values[n]));
87 }
88 if len == nbits {
89 break;
90 }
91 let next = self.nodes[n][((prefix >> (nbits - 1 - len)) & 1) as usize];
92 if next == NONE {
93 return None;
94 }
95 n = next as usize;
96 }
97 None
98 }
99
100 fn is_leaf(&self, n: usize) -> bool {
101 self.nodes[n] == [NONE, NONE]
102 }
103
104 fn build_lut(&mut self) {
105 let mut lut = vec![0u32; 1 << LUT_BITS];
106 for (idx, e) in lut.iter_mut().enumerate() {
107 let mut n = 0usize;
108 let mut len = 0;
109 *e = loop {
110 if self.is_leaf(n) {
111 break if self.values[n] == NONE { 0 } else { len | KIND_LEAF | (self.values[n] << 8) };
113 }
114 if len == LUT_BITS {
115 break LUT_BITS | KIND_NODE | ((n as u32) << 8);
116 }
117 let bit = (idx >> (LUT_BITS - 1 - len)) & 1;
118 let next = self.nodes[n][bit];
119 if next == NONE {
120 break 0;
121 }
122 n = next as usize;
123 len += 1;
124 };
125 }
126 self.lut = lut;
127 }
128
129 #[inline(always)]
131 pub fn decode<B: BitRead>(&self, bits: &mut B) -> Result<u32> {
132 bits.fill();
133 let e = self.lut[bits.peek_no_fill(LUT_BITS) as usize];
134 match e & KIND_MASK {
135 KIND_LEAF => {
136 bits.skip_no_fill(e & 0x3F);
137 Ok(e >> 8)
138 }
139 KIND_NODE => {
140 bits.skip_no_fill(LUT_BITS);
141 self.decode_slow(bits, (e >> 8) as usize)
142 }
143 _ => Err(Error::corrupt("invalid X3F prefix code")),
144 }
145 }
146
147 #[cold]
148 fn decode_slow<B: BitRead>(&self, bits: &mut B, mut n: usize) -> Result<u32> {
149 while !self.is_leaf(n) {
150 let next = self.nodes[n][bits.get(1) as usize];
151 if next == NONE {
152 return Err(Error::corrupt("invalid X3F prefix code"));
153 }
154 n = next as usize;
155 }
156 match self.values[n] {
157 NONE => Err(Error::corrupt("invalid X3F prefix code")),
158 v => Ok(v),
159 }
160 }
161}
162
163#[derive(Debug, Clone)]
165pub struct TrueHeader {
166 pub planes: Option<[(u32, u32); 3]>,
168 pub seeds: [u16; 3],
169 pub table: Vec<(u8, u8)>,
171 pub plane_sizes: [u32; 3],
172 pub data_offset: usize,
174}
175
176fn rd16(d: &[u8], p: &mut usize) -> Result<u16> {
177 let b = d.get(*p..*p + 2).ok_or_else(|| Error::corrupt("truncated X3F TRUE header"))?;
178 *p += 2;
179 Ok(u16::from_le_bytes([b[0], b[1]]))
180}
181
182fn rd32(d: &[u8], p: &mut usize) -> Result<u32> {
183 let b = d.get(*p..*p + 4).ok_or_else(|| Error::corrupt("truncated X3F TRUE header"))?;
184 *p += 4;
185 Ok(u32::from_le_bytes([b[0], b[1], b[2], b[3]]))
186}
187
188impl TrueHeader {
189 pub fn parse(d: &[u8], quattro: bool) -> Result<Self> {
191 let mut p = 0usize;
192 let planes = if quattro {
193 let mut pl = [(0u32, 0u32); 3];
194 for e in pl.iter_mut() {
195 let c = rd16(d, &mut p)? as u32;
196 let r = rd16(d, &mut p)? as u32;
197 *e = (c, r);
198 }
199 Some(pl)
200 } else {
201 None
202 };
203 let seeds = [rd16(d, &mut p)?, rd16(d, &mut p)?, rd16(d, &mut p)?];
204 let _unknown = rd16(d, &mut p)?;
205 let mut table = Vec::new();
206 loop {
207 let b = d.get(p..p + 2).ok_or_else(|| Error::corrupt("truncated X3F TRUE code table"))?;
208 p += 2;
209 table.push((b[0], b[1]));
210 if b[0] == 0 {
211 break;
212 }
213 if table.len() > 256 {
214 return Err(Error::corrupt("X3F TRUE code table too long"));
215 }
216 }
217 if quattro {
218 let _unknown = rd32(d, &mut p)?;
219 }
220 let plane_sizes = [rd32(d, &mut p)?, rd32(d, &mut p)?, rd32(d, &mut p)?];
221 Ok(TrueHeader { planes, seeds, table, plane_sizes, data_offset: p })
222 }
223
224 pub fn table(&self) -> Result<TrueTable> {
226 Ok(TrueTable::new(self.code()?))
227 }
228
229 pub fn code(&self) -> Result<PrefixCode> {
231 true_code(&self.table)
232 }
233
234 pub fn plane_ranges(&self, data_len: usize) -> Result<[(usize, usize); 3]> {
238 let mut out = [(0usize, data_len); 3];
239 let mut off = 0usize;
240 for (i, &s) in self.plane_sizes.iter().enumerate() {
241 out[i].0 = off;
242 off = off
243 .checked_add((s as usize).div_ceil(16) * 16)
244 .ok_or_else(|| Error::corrupt("X3F TRUE plane sizes overflow"))?;
245 }
246 if off > data_len {
247 return Err(Error::corrupt("X3F TRUE planes exceed section size"));
248 }
249 Ok(out)
250 }
251}
252
253fn true_code(table: &[(u8, u8)]) -> Result<PrefixCode> {
256 let codes: Vec<(u32, u32, u32)> = table
257 .iter()
258 .enumerate()
259 .filter(|(_, (len, _))| *len != 0)
260 .map(|(i, &(len, code))| {
261 let len = len as u32;
262 let c = if len <= 8 { (code as u32 >> (8 - len)) & 0xFF } else { u32::MAX };
263 (c, len, i as u32)
264 })
265 .collect();
266 if codes.iter().any(|&(c, _, _)| c == u32::MAX) {
267 return Err(Error::corrupt("X3F TRUE code longer than 8 bits"));
268 }
269 PrefixCode::new(&codes)
270}
271
272const TT_BITS: u32 = 14;
273const TT_FULL: u32 = 1 << 6;
274const TT_VALID: u32 = 1 << 7;
275
276#[derive(Debug, Clone)]
279pub struct TrueTable {
280 lut: Vec<u32>,
281 code: PrefixCode,
282}
283
284#[inline(always)]
285fn extend(v: u32, len: u32) -> i32 {
286 if v >> (len - 1) == 0 { v as i32 - ((1i64 << len) - 1) as i32 } else { v as i32 }
287}
288
289impl TrueTable {
290 pub fn new(code: PrefixCode) -> Self {
291 let lut = (0..1u32 << TT_BITS)
292 .map(|idx| match code.walk(idx, TT_BITS) {
293 Some((clen, 0)) => clen | TT_FULL | TT_VALID,
294 Some((clen, sym)) if clen + sym <= TT_BITS => {
295 let v = (idx >> (TT_BITS - clen - sym)) & ((1 << sym) - 1);
296 (clen + sym) | TT_FULL | TT_VALID | ((extend(v, sym) as i16 as u16 as u32) << 16)
297 }
298 Some((clen, sym)) if sym <= 31 => clen | TT_VALID | (sym << 8),
299 _ => 0,
300 })
301 .collect();
302 TrueTable { lut, code }
303 }
304
305 #[inline(always)]
307 pub fn diff(&self, bits: &mut BitPumpMsb) -> Result<i32> {
308 bits.fill();
309 let e = self.lut[bits.peek_no_fill(TT_BITS) as usize];
310 if e & TT_FULL != 0 {
311 bits.skip_no_fill(e & 0x3F);
312 return Ok((e >> 16) as u16 as i16 as i32);
313 }
314 let len = if e & TT_VALID != 0 {
315 bits.skip_no_fill(e & 0x3F);
316 (e >> 8) & 0x3F
317 } else {
318 self.code.decode(bits)?
319 };
320 if len == 0 {
321 return Ok(0);
322 }
323 if len > 31 {
324 return Err(Error::corrupt("X3F TRUE difference too long"));
325 }
326 Ok(extend(read_bits(bits, len), len))
327 }
328}
329
330#[allow(clippy::needless_range_loop)]
333pub fn decode_true_plane(
334 code: &TrueTable,
335 data: &[u8],
336 seed: u16,
337 cols: usize,
338 rows: usize,
339 out_cols: usize,
340 out: &mut [u16],
341) -> Result<()> {
342 if out_cols > cols || out.len() < out_cols * rows {
343 return Err(Error::corrupt("X3F TRUE plane geometry mismatch"));
344 }
345 let mut bits = BitPumpMsb::new(data);
346 let mut row_start = [[seed as i32; 2]; 2];
347 for (r, orow) in out.chunks_exact_mut(out_cols.max(1)).take(rows).enumerate() {
348 let odd_row = r & 1;
349 let mut acc = [0i32; 2];
350 for col in 0..cols {
351 let diff = code.diff(&mut bits)?;
352 let phase = col & 1;
353 let value = if col < 2 {
354 let v = row_start[odd_row][phase].wrapping_add(diff);
355 row_start[odd_row][phase] = v;
356 v
357 } else {
358 acc[phase].wrapping_add(diff)
359 };
360 acc[phase] = value;
361 if col < out_cols {
362 orow[col] = value as u16;
363 }
364 }
365 if bits.exhausted() {
366 return Err(Error::corrupt("truncated X3F TRUE plane"));
367 }
368 }
369 Ok(())
370}
371
372#[inline(always)]
373fn read_bits<B: BitRead>(bits: &mut B, n: u32) -> u32 {
374 bits.get(n)
376}
377
378pub fn huffman_code(table: &[u32], mapping: &[u16]) -> Result<PrefixCode> {
381 let codes: Vec<(u32, u32, u32)> = table
382 .iter()
383 .enumerate()
384 .filter(|(_, e)| **e != 0)
385 .map(|(i, &e)| {
386 let v = if mapping.len() == table.len() { mapping[i] as u32 } else { i as u32 };
387 (e & 0x07FF_FFFF, (e >> 27) & 0x1F, v)
388 })
389 .collect();
390 PrefixCode::new(&codes)
391}
392
393pub fn decode_huffman(
397 code: &PrefixCode,
398 data: &[u8],
399 row_offsets: &[u32],
400 cols: usize,
401 rows: usize,
402 out: &mut [u16],
403 parallel: bool,
404) -> Result<()> {
405 let rl = cols * 3;
406 if row_offsets.len() < rows || out.len() < rl * rows || rl == 0 {
407 return Err(Error::corrupt("X3F Huffman geometry mismatch"));
408 }
409 let errors = std::sync::Mutex::new(None);
410 let minimum = std::sync::atomic::AtomicI32::new(0);
411 flashraw_core::par::for_each_row_chunk(&mut out[..rl * rows], rl, 16, parallel, |first, chunk| {
413 let mut local_min = 0i32;
414 for (i, row) in chunk.chunks_exact_mut(rl).enumerate() {
415 let r = first + i;
416 let off = row_offsets[r] as usize;
417 if off >= data.len() {
418 *errors.lock().unwrap() = Some(Error::corrupt("X3F Huffman row offset out of range"));
419 return;
420 }
421 let mut bits = BitPumpMsb::new(&data[off..]);
422 let mut c = [0i16; 3];
423 for px in row.chunks_exact_mut(3) {
424 for (k, v) in px.iter_mut().enumerate() {
425 match code.decode(&mut bits) {
426 Ok(d) => c[k] = c[k].wrapping_add(d as i16),
427 Err(e) => {
428 *errors.lock().unwrap() = Some(e);
429 return;
430 }
431 }
432 local_min = local_min.min(c[k] as i32);
433 *v = c[k] as u16;
434 }
435 }
436 if bits.exhausted() {
437 *errors.lock().unwrap() = Some(Error::corrupt("truncated X3F Huffman row"));
438 return;
439 }
440 }
441 minimum.fetch_min(local_min, std::sync::atomic::Ordering::Relaxed);
442 });
443 if let Some(e) = errors.into_inner().unwrap() {
444 return Err(e);
445 }
446 let offset = (-minimum.into_inner()) as i16;
448 flashraw_core::par::for_each_row_chunk(&mut out[..rl * rows], rl, 64, parallel, |_, chunk| {
449 for v in chunk.iter_mut() {
450 let s = (*v as i16).wrapping_add(offset);
451 *v = if s < 0 { 0 } else { s as u16 };
452 }
453 });
454 Ok(())
455}
456
457#[allow(clippy::too_many_arguments)]
460pub fn decode_simple(
461 data: &[u8],
462 row_stride: usize,
463 mapping: &[u16],
464 bits: u32,
465 cols: usize,
466 rows: usize,
467 out: &mut [u16],
468 parallel: bool,
469) -> Result<()> {
470 if !(8..=12).contains(&bits) {
471 return Err(Error::corrupt(format!("X3F simple coding with {bits} bits")));
472 }
473 let rl = cols * 3;
474 if row_stride < cols * 4 || out.len() < rl * rows || rl == 0 {
475 return Err(Error::corrupt("X3F uncompressed geometry mismatch"));
476 }
477 let needed = (rows - 1).checked_mul(row_stride).and_then(|v| v.checked_add(cols * 4));
478 if needed.is_none_or(|n| n > data.len()) {
479 return Err(Error::corrupt("truncated X3F uncompressed data"));
480 }
481 let mask = (1u32 << bits) - 1;
482 flashraw_core::par::for_each_row_chunk(&mut out[..rl * rows], rl, 32, parallel, |first, chunk| {
483 for (i, row) in chunk.chunks_exact_mut(rl).enumerate() {
484 let src = &data[(first + i) * row_stride..];
485 let mut c = [0u16; 3];
486 for (px, w) in row.chunks_exact_mut(3).zip(src.chunks_exact(4)) {
487 let val = u32::from_le_bytes([w[0], w[1], w[2], w[3]]);
488 for k in 0..3 {
489 let idx = ((val >> (k as u32 * bits)) & mask) as usize;
490 let d = if mapping.is_empty() { idx as u16 } else { mapping.get(idx).copied().unwrap_or(0) };
491 c[k] = c[k].wrapping_add(d);
492 px[k] = if (c[k] as i16) > 0 { c[k] } else { 0 };
493 }
494 }
495 }
496 });
497 Ok(())
498}
499
500pub const CAMF_MAX_DECODED: usize = 64 << 20;
502
503enum CamfCoding<'a> {
505 Done,
507 Bytes { code: TrueTable, bits: BitPumpMsb<'a>, acc: i32 },
509 Samples {
511 code: TrueTable,
512 bits: BitPumpMsb<'a>,
513 cols: usize,
514 rows: usize,
515 row: usize,
516 col: usize,
517 acc: [i32; 2],
518 row_start: [[i32; 2]; 2],
519 half: Option<i32>,
520 },
521}
522
523pub struct CamfStream<'a> {
540 out: Vec<u8>,
541 size: usize,
542 coding: CamfCoding<'a>,
543}
544
545impl<'a> CamfStream<'a> {
546 pub fn new(section: &'a [u8]) -> Result<Self> {
548 let word = |i: usize| -> Result<u32> {
549 let b = section.get(i * 4..i * 4 + 4).ok_or_else(|| Error::corrupt("truncated X3F CAMF header"))?;
550 Ok(u32::from_le_bytes([b[0], b[1], b[2], b[3]]))
551 };
552 let kind = word(2)?;
553 let w = [word(3)?, word(4)?, word(5)?, word(6)?];
554 let data = §ion[28..];
555 if kind == 2 {
556 let mut key = w[3];
557 let out: Vec<u8> = data
558 .iter()
559 .map(|&b| {
560 key = key.wrapping_mul(1597).wrapping_add(51749) % 244_944;
561 let tmp = ((key as u64 * 301_593_171) >> 24) as u32;
562 b ^ ((((key << 8).wrapping_sub(tmp) >> 1).wrapping_add(tmp) >> 17) as u8)
563 })
564 .collect();
565 return Ok(CamfStream { size: out.len(), out, coding: CamfCoding::Done });
566 }
567 if kind != 4 && kind != 5 {
568 return Err(Error::corrupt(format!("unknown X3F CAMF coding {kind}")));
569 }
570 let size = w[0] as usize;
571 if size > CAMF_MAX_DECODED || size > data.len().saturating_mul(12) {
573 return Err(Error::corrupt(format!("invalid X3F CAMF block of {size} bytes")));
574 }
575 let mut table = Vec::new();
576 for pair in data.chunks_exact(2) {
577 if pair[0] == 0 {
578 break;
579 }
580 table.push((pair[0], pair[1]));
581 }
582 let code = TrueTable::new(true_code(&table)?);
583 let bits = BitPumpMsb::new(data.get(32..).ok_or_else(|| Error::corrupt("truncated X3F CAMF data"))?);
584 let coding = if kind == 5 {
585 CamfCoding::Bytes { code, bits, acc: w[1] as i32 }
586 } else {
587 let seed = w[1] as i32;
588 CamfCoding::Samples {
589 code,
590 bits,
591 cols: w[2] as usize,
592 rows: w[3] as usize,
593 row: 0,
594 col: 0,
595 acc: [0; 2],
596 row_start: [[seed; 2]; 2],
597 half: None,
598 }
599 };
600 Ok(CamfStream { out: Vec::new(), size, coding })
601 }
602
603 pub fn decoded(&self) -> &[u8] {
605 &self.out
606 }
607
608 pub fn is_done(&self) -> bool {
610 matches!(self.coding, CamfCoding::Done)
611 }
612
613 pub fn fill(&mut self, len: usize) -> Result<()> {
615 let target = len.min(self.size);
616 if self.out.len() >= target {
617 return Ok(());
618 }
619 self.out.reserve(target - self.out.len());
620 let out = &mut self.out;
621 let size = self.size;
622 let finished = match &mut self.coding {
623 CamfCoding::Done => return Ok(()),
624 CamfCoding::Bytes { code, bits, acc } => {
625 while out.len() < target {
626 *acc = acc.wrapping_add(code.diff(bits)?);
627 out.push(*acc as u8);
628 }
629 if bits.exhausted() {
630 return Err(Error::corrupt("truncated X3F CAMF data"));
631 }
632 out.len() >= size
633 }
634 CamfCoding::Samples { code, bits, cols, rows, row, col, acc, row_start, half } => {
635 'rows: while *row < *rows {
636 while *col < *cols {
637 let d = code.diff(bits)?;
638 let phase = *col & 1;
639 let start = &mut row_start[*row & 1][phase];
640 let v = if *col < 2 { *start } else { acc[phase] }.wrapping_add(d);
641 acc[phase] = v;
642 if *col < 2 {
643 *start = v;
644 }
645 *col += 1;
646 match half.take() {
647 None => {
648 out.push((v >> 4) as u8);
649 *half = Some(v);
650 }
651 Some(p) => {
652 out.push(((p << 4) as u8 & 0xf0) | ((v >> 8) as u8 & 0x0f));
653 out.push(v as u8);
654 }
655 }
656 if out.len() >= size {
657 break 'rows;
658 }
659 if out.len() >= target {
660 break;
661 }
662 }
663 if *col >= *cols {
664 *col = 0;
665 *row += 1;
666 *acc = [0; 2];
667 }
668 if out.len() >= target {
669 break;
670 }
671 }
672 if bits.exhausted() {
673 return Err(Error::corrupt("truncated X3F CAMF data"));
674 }
675 let finished = out.len() >= size || *row >= *rows;
676 if finished {
677 if let Some(p) = half.take() {
678 out.push((p << 4) as u8 & 0xf0);
679 }
680 out.resize(size, 0);
682 }
683 finished
684 }
685 };
686 if finished {
687 self.coding = CamfCoding::Done;
688 }
689 Ok(())
690 }
691}
692
693pub fn decode_camf(section: &[u8]) -> Result<Vec<u8>> {
695 let mut s = CamfStream::new(section)?;
696 s.fill(usize::MAX)?;
697 Ok(s.out)
698}
699
700#[cfg(test)]
701mod tests {
702 use super::*;
703
704 struct W {
706 out: Vec<u8>,
707 acc: u64,
708 n: u32,
709 }
710 impl W {
711 fn new() -> Self {
712 W { out: Vec::new(), acc: 0, n: 0 }
713 }
714 fn put(&mut self, v: u32, len: u32) {
715 for i in (0..len).rev() {
716 self.acc = (self.acc << 1) | ((v >> i) & 1) as u64;
717 self.n += 1;
718 if self.n == 8 {
719 self.out.push(self.acc as u8);
720 self.acc = 0;
721 self.n = 0;
722 }
723 }
724 }
725 fn finish(mut self) -> Vec<u8> {
726 if self.n > 0 {
727 self.out.push((self.acc << (8 - self.n)) as u8);
728 }
729 self.out.extend_from_slice(&[0; 16]);
730 self.out
731 }
732 }
733
734 fn table() -> Vec<(u8, u8)> {
736 vec![
737 (2, 0b0000_0000),
738 (2, 0b0100_0000),
739 (2, 0b1000_0000),
740 (4, 0b1100_0000),
741 (4, 0b1101_0000),
742 (4, 0b1110_0000),
743 (4, 0b1111_0000),
744 (0, 0),
745 ]
746 }
747
748 fn encode_diff(w: &mut W, d: i32) {
749 let len = if d == 0 { 0 } else { 32 - (d.unsigned_abs()).leading_zeros() };
750 let (code, clen) = [(0, 2), (1, 2), (2, 2), (12, 4), (13, 4), (14, 4), (15, 4)][len as usize];
751 w.put(code, clen);
752 if len > 0 {
753 let v = if d > 0 { d as u32 } else { (d + (1 << len) - 1) as u32 };
754 w.put(v, len);
755 }
756 }
757
758 #[test]
759 fn true_plane_roundtrip() {
760 let (cols, rows, seed) = (7usize, 5usize, 512u16);
761 let img: Vec<i32> = (0..cols * rows).map(|i| 500 + ((i * 7919) % 23) as i32 - 11).collect();
762 let mut w = W::new();
763 let mut row_start = [[seed as i32; 2]; 2];
764 for r in 0..rows {
765 let mut acc = [0i32; 2];
766 for c in 0..cols {
767 let v = img[r * cols + c];
768 let prev = if c < 2 { row_start[r & 1][c & 1] } else { acc[c & 1] };
769 encode_diff(&mut w, v - prev);
770 acc[c & 1] = v;
771 if c < 2 {
772 row_start[r & 1][c & 1] = v;
773 }
774 }
775 }
776 let data = w.finish();
777 let hdr = TrueHeader {
778 planes: None,
779 seeds: [seed; 3],
780 table: table(),
781 plane_sizes: [data.len() as u32, 0, 0],
782 data_offset: 0,
783 };
784 let code = hdr.table().unwrap();
785 let mut out = vec![0u16; (cols - 1) * rows];
786 decode_true_plane(&code, &data, seed, cols, rows, cols - 1, &mut out).unwrap();
787 for r in 0..rows {
788 for c in 0..cols - 1 {
789 assert_eq!(out[r * (cols - 1) + c] as i32, img[r * cols + c]);
790 }
791 }
792 }
793
794 #[test]
795 fn true_plane_truncated_is_error() {
796 let code = TrueHeader { planes: None, seeds: [0; 3], table: table(), plane_sizes: [0; 3], data_offset: 0 }
797 .table()
798 .unwrap();
799 let data = [0xFFu8; 4];
800 let mut out = vec![0u16; 64 * 64];
801 assert!(decode_true_plane(&code, &data, 0, 64, 64, 64, &mut out).is_err());
802 }
803
804 #[test]
805 fn true_header_parse_and_ranges() {
806 let mut d = Vec::new();
807 for v in [512u16, 512, 512, 0] {
808 d.extend_from_slice(&v.to_le_bytes());
809 }
810 for (l, c) in table() {
811 d.extend_from_slice(&[l, c]);
812 }
813 for s in [17u32, 3, 40] {
814 d.extend_from_slice(&s.to_le_bytes());
815 }
816 let h = TrueHeader::parse(&d, false).unwrap();
817 assert_eq!(h.seeds, [512; 3]);
818 assert_eq!(h.table.len(), 8);
819 assert_eq!(h.data_offset, d.len());
820 assert_eq!(h.plane_ranges(100).unwrap(), [(0, 100), (32, 100), (48, 100)]);
821 assert!(h.plane_ranges(80).is_err());
822 assert!(TrueHeader::parse(&d[..9], false).is_err());
823 }
824
825 #[test]
826 fn prefix_code_long_codes() {
827 let codes = vec![(0, 1, 5), ((1 << 14) - 2, 14, 6), ((1 << 15) - 2, 15, 7), ((1 << 15) - 1, 15, 8)];
829 let pc = PrefixCode::new(&codes).unwrap();
830 let mut w = W::new();
831 for &(c, l, _) in &codes {
832 w.put(c, l);
833 }
834 let data = w.finish();
835 let mut b = BitPumpMsb::new(&data);
836 for &(_, _, v) in &codes {
837 assert_eq!(pc.decode(&mut b).unwrap(), v);
838 }
839 assert!(PrefixCode::new(&[]).is_err());
840 assert!(PrefixCode::new(&[(0, 0, 1)]).is_err());
841 }
842
843 #[test]
844 fn huffman_offset_and_clamp() {
845 let table: Vec<u32> = vec![(1 << 27), (2 << 27) | 2, (2 << 27) | 3];
847 let mapping = vec![5u16, 0xFFF9, 1];
848 let code = huffman_code(&table, &mapping).unwrap();
849 let mut w = W::new();
851 let r0 = w.out.len();
852 w.put(0b10, 2);
853 w.put(0, 1);
854 w.put(0b11, 2);
855 w.put(0, 3); let data0 = std::mem::take(&mut w.out);
857 let mut w = W::new();
858 w.put(0, 3);
859 let mut data = data0.clone();
860 data.extend(w.finish());
861 let offs = [r0 as u32, data0.len() as u32];
862 let mut out = vec![0u16; 6];
863 decode_huffman(&code, &data, &offs, 1, 2, &mut out, false).unwrap();
864 assert_eq!(out, vec![0, 12, 8, 12, 12, 12]);
866 }
867
868 #[test]
869 fn simple_decode() {
870 let mapping: Vec<u16> = (0..1024).map(|i| i as u16).collect();
871 let px = |r: u32, g: u32, b: u32| (r | (g << 10) | (b << 20)).to_le_bytes();
872 let mut data = Vec::new();
873 data.extend_from_slice(&px(10, 20, 30));
874 data.extend_from_slice(&px(1, 2, 3));
875 let mut out = vec![0u16; 6];
876 decode_simple(&data, 8, &mapping, 10, 2, 1, &mut out, false).unwrap();
877 assert_eq!(out, vec![10, 20, 30, 11, 22, 33]);
878 assert!(decode_simple(&data[..6], 8, &mapping, 10, 2, 1, &mut out, false).is_err());
879 }
880
881 fn camf_section(kind: u32, words: [u32; 4], data: &[u8]) -> Vec<u8> {
883 let mut s = b"SECc".to_vec();
884 for w in [0x0002_0000, kind, words[0], words[1], words[2], words[3]] {
885 s.extend_from_slice(&u32::to_le_bytes(w));
886 }
887 s.extend_from_slice(data);
888 s
889 }
890
891 fn camf_table() -> Vec<u8> {
893 let mut d: Vec<u8> = table().iter().flat_map(|&(a, b)| [a, b]).collect();
894 d.resize(32, 0);
895 d
896 }
897
898 #[test]
899 fn camf_type2_is_its_own_inverse() {
900 let plain: Vec<u8> = b"CMbT entries".iter().copied().cycle().take(300).collect();
901 let coded = decode_camf(&camf_section(2, [0, 0, 0, 0x6149_13eb], &plain)).unwrap();
902 assert_ne!(coded, plain);
903 assert_eq!(decode_camf(&camf_section(2, [0, 0, 0, 0x6149_13eb], &coded)).unwrap(), plain);
904 }
905
906 #[test]
907 fn camf_type5_running_bytes() {
908 let plain: Vec<u8> = (0..500u32).map(|i| (100 + (i * 37 % 41) as i32 - 20) as u8).collect();
909 let bias = 90u32;
910 let mut w = W::new();
911 let mut prev = bias as i32;
912 for &b in &plain {
913 encode_diff(&mut w, b as i32 - prev);
914 prev = b as i32;
915 }
916 let mut data = camf_table();
917 data.extend_from_slice(&w.finish());
918 let section = camf_section(5, [plain.len() as u32, bias, 0, 0], &data);
919 assert_eq!(decode_camf(§ion).unwrap(), plain);
920 let mut s = CamfStream::new(§ion).unwrap();
922 s.fill(10).unwrap();
923 assert!(s.decoded().len() >= 10 && s.decoded().len() < plain.len() && !s.is_done());
924 s.fill(usize::MAX).unwrap();
925 assert!(s.is_done());
926 assert_eq!(s.decoded(), &plain[..]);
927 assert!(decode_camf(§ion[..section.len() - 40]).is_err());
929 assert!(decode_camf(&camf_section(5, [u32::MAX, 0, 0, 0], &data)).is_err());
930 assert!(decode_camf(&camf_section(7, [0; 4], &data)).is_err());
931 assert!(CamfStream::new(§ion[..20]).is_err());
932 }
933
934 #[test]
935 fn camf_type4_packed_samples() {
936 let (cols, rows, seed) = (6usize, 4usize, 2048i32);
938 let vals: Vec<i32> = (0..cols * rows).map(|i| 2048 + ((i * 13) % 29) as i32 - 14).collect();
939 let mut w = W::new();
940 let mut row_start = [[seed; 2]; 2];
941 for r in 0..rows {
942 let mut acc = [0i32; 2];
943 for c in 0..cols {
944 let v = vals[r * cols + c];
945 let p = if c < 2 { row_start[r & 1][c & 1] } else { acc[c & 1] };
946 encode_diff(&mut w, v - p);
947 acc[c & 1] = v;
948 if c < 2 {
949 row_start[r & 1][c & 1] = v;
950 }
951 }
952 }
953 let mut packed = Vec::new();
954 for pair in vals.chunks(2) {
955 packed.push((pair[0] >> 4) as u8);
956 packed.push(((pair[0] << 4) as u8 & 0xf0) | ((pair[1] >> 8) as u8 & 0x0f));
957 packed.push(pair[1] as u8);
958 }
959 let mut data = camf_table();
960 data.extend_from_slice(&w.finish());
961 let size = packed.len() - 1;
963 let section = camf_section(4, [size as u32, seed as u32, cols as u32, rows as u32], &data);
964 assert_eq!(decode_camf(§ion).unwrap(), &packed[..size]);
965 let mut s = CamfStream::new(§ion).unwrap();
966 s.fill(7).unwrap();
967 s.fill(20).unwrap();
968 s.fill(usize::MAX).unwrap();
969 assert_eq!(s.decoded(), &packed[..size]);
970 let section = camf_section(4, [packed.len() as u32 + 5, seed as u32, cols as u32, rows as u32], &data);
972 let out = decode_camf(§ion).unwrap();
973 assert_eq!((&out[..packed.len()], &out[packed.len()..]), (&packed[..], &[0u8; 5][..]));
974 }
975}