ds_rom/compress/
huffman.rs1use bitreader::BitReader;
2use rust_bitwriter::BitWriter;
3
4pub struct NibbleHuffman {
8 pub codes: [NibbleHuffmanCode; 16],
11}
12
13pub struct NibbleHuffmanCode {
15 pub length: u8,
17 pub bits: u8,
19}
20
21impl NibbleHuffman {
22 fn decompress_nibble(&self, reader: &mut BitReader) -> u8 {
23 let (bits_read, value) = self
24 .codes
25 .iter()
26 .enumerate()
27 .find_map(|(index, code)| {
28 let (bits_read, value) = if code.length as u64 > reader.remaining() {
29 let rem = reader.remaining() as u8;
30 (rem, reader.peek_u8(rem).unwrap() << (code.length - rem))
31 } else {
32 (code.length, reader.peek_u8(code.length).unwrap())
33 };
34 (value == code.bits).then_some((bits_read, index as u8))
35 })
36 .unwrap();
37 reader.skip(bits_read as u64).unwrap();
38 value
39 }
40
41 pub fn decompress_to_slice(&self, data: &[u8], out: &mut [u8]) {
44 let mut reader = BitReader::new(data);
45
46 for i in 0..out.len() {
47 let low = self.decompress_nibble(&mut reader);
48 let high = self.decompress_nibble(&mut reader);
49 out[i] = (high << 4) | low;
50 }
51 }
52
53 fn compress_nibble(&self, writer: &mut BitWriter, data: u8) {
54 assert!(data < 16);
55 let (_, code) = &self.codes.iter().enumerate().find(|(value, _)| *value as u8 == data).unwrap();
56 writer.write_u8(code.bits, code.length).unwrap();
57 }
58
59 pub fn compress_to_slice(&self, bytes: &[u8], out: &mut [u8]) {
61 let mut writer = BitWriter::new();
62
63 for byte in bytes.iter() {
64 let low = byte & 0xf;
65 let high = byte >> 4;
66 self.compress_nibble(&mut writer, low);
67 self.compress_nibble(&mut writer, high);
68 }
69
70 let _ = writer.close();
71 let data = writer.data();
72 let len = out.len().min(data.len());
73 out[..len].copy_from_slice(&data[..len]);
74 }
75
76 pub fn diff16_to_data(&self, data: &mut [u8]) {
83 assert!(data.len().is_multiple_of(2));
84 let mut prev = 0;
85 for i in (0..data.len()).step_by(2) {
86 let curr = u16::from_le_bytes([data[i], data[i + 1]]);
87 let value = curr.wrapping_add(prev);
88 data[i..i + 2].copy_from_slice(&value.to_le_bytes());
89 prev = value;
90 }
91 }
92
93 pub fn data_to_diff16(&self, data: &mut [u8]) {
103 assert!(data.len().is_multiple_of(2));
104 let mut prev = 0;
105 for i in (0..data.len()).step_by(2) {
106 let curr = u16::from_le_bytes([data[i], data[i + 1]]);
107 let value = curr.wrapping_sub(prev);
108 data[i..i + 2].copy_from_slice(&value.to_le_bytes());
109 prev = curr;
110 }
111 }
112}