rawloader/decoders/ljpeg/
huffman.rs1use std::fmt;
2use crate::decoders::basics::*;
3
4const DECODE_CACHE_BITS: u32 = 13;
5
6pub struct HuffTable {
7 pub bits: [u32;17],
9 pub huffval: [u32;256],
10
11 pub shiftval: [u32;256],
13
14 pub dng_bug: bool,
17
18 pub disable_cache: bool,
20
21 nbits: u32,
27 hufftable: Vec<(u8,u8,u8)>,
28
29 decodecache: [Option<(u8,i16)>; 1<< DECODE_CACHE_BITS],
33
34 initialized: bool,
35}
36
37struct MockPump {
38 bits: u64,
39 nbits: u32,
40}
41
42impl MockPump {
43 pub fn empty() -> Self {
44 MockPump {
45 bits: 0,
46 nbits: 0,
47 }
48 }
49
50 pub fn set(&mut self, bits: u32, nbits: u32) {
51 self.bits = (bits as u64) << 32;
52 self.nbits = nbits + 32;
53 }
54
55 pub fn validbits(&self) -> i32 {
56 self.nbits as i32 - 32
57 }
58}
59
60impl BitPump for MockPump {
61 fn peek_bits(&mut self, num: u32) -> u32 {
62 (self.bits >> (self.nbits-num)) as u32
63 }
64
65 fn consume_bits(&mut self, num: u32) {
66 self.nbits -= num;
67 self.bits &= (1 << self.nbits) - 1;
68 }
69}
70
71impl HuffTable {
72 pub fn empty() -> HuffTable {
73 HuffTable {
74 bits: [0;17],
75 huffval: [0;256],
76 shiftval: [0;256],
77 dng_bug: false,
78 disable_cache: false,
79
80 nbits: 0,
81 hufftable: Vec::new(),
82 decodecache: [None; 1 << DECODE_CACHE_BITS],
83 initialized: false,
84 }
85 }
86
87 pub fn new(bits: [u32;17], huffval: [u32;256], dng_bug: bool) -> Result<HuffTable,String> {
88 let mut tbl = HuffTable {
89 bits: bits,
90 huffval: huffval,
91 shiftval: [0;256],
92 dng_bug: dng_bug,
93 disable_cache: false,
94
95 nbits: 0,
96 hufftable: Vec::new(),
97 decodecache: [None; 1 << DECODE_CACHE_BITS],
98 initialized: false,
99 };
100 tbl.initialize()?;
101 Ok(tbl)
102 }
103
104 pub fn initialize(&mut self) -> Result<(), String> {
105 self.nbits = 16;
107 for i in 0..16 {
108 if self.bits[16-i] != 0 {
109 break;
110 }
111 self.nbits -= 1;
112 }
113 self.hufftable = vec![(0,0,0); 1 << self.nbits];
114
115 let mut h = 0;
117 let mut pos = 0;
118 for len in 0..self.nbits {
119 for _ in 0..self.bits[len as usize + 1] {
120 for _ in 0..(1 << (self.nbits-len-1)) {
121 self.hufftable[h] = (len as u8 + 1, self.huffval[pos] as u8, self.shiftval[pos] as u8);
122 h += 1;
123 }
124 pos += 1;
125 }
126 }
127
128 if !self.disable_cache {
131 let mut pump = MockPump::empty();
132 let mut i = 0;
133 loop {
134 pump.set(i, DECODE_CACHE_BITS);
135 let (bits, decode) = self.huff_decode_slow(&mut pump);
136 if pump.validbits() >= 0 {
137 self.decodecache[i as usize] = Some((bits, decode as i16));
138 }
139 i += 1;
140 if i >= 1 << DECODE_CACHE_BITS {
141 break;
142 }
143 }
144 }
145
146 self.initialized = true;
147 Ok(())
148 }
149
150 #[inline(always)]
151 pub fn huff_decode(&self, pump: &mut dyn BitPump) -> Result<i32,String> {
152 let code = pump.peek_bits(DECODE_CACHE_BITS) as usize;
153 if let Some((bits,decode)) = self.decodecache[code] {
154 pump.consume_bits(bits as u32);
155 Ok(decode as i32)
156 } else {
157 let decode = self.huff_decode_slow(pump);
158 Ok(decode.1)
159 }
160 }
161
162 #[inline(always)]
163 pub fn huff_decode_slow(&self, pump: &mut dyn BitPump) -> (u8,i32) {
164 let len = self.huff_len(pump);
165 (len.0+len.1, self.huff_diff(pump, len))
166 }
167
168 #[inline(always)]
169 pub fn huff_len(&self, pump: &mut dyn BitPump) -> (u8,u8,u8) {
170 let code = pump.peek_bits(self.nbits) as usize;
171 let (bits, len, shift) = self.hufftable[code];
172 pump.consume_bits(bits as u32);
173 (bits, len, shift)
174 }
175
176 #[inline(always)]
177 pub fn huff_get_bits(&self, pump: &mut dyn BitPump) -> u32 {
178 let code = pump.peek_bits(self.nbits) as usize;
179 let (bits, len, _) = self.hufftable[code];
180 pump.consume_bits(bits as u32);
181 len as u32
182 }
183
184 #[inline(always)]
185 pub fn huff_diff(&self, pump: &mut dyn BitPump, input: (u8,u8,u8)) -> i32 {
186 let (_, len, shift) = input;
187
188 match len {
189 0 => 0,
190 16 => {
191 if self.dng_bug {
192 pump.get_bits(16); }
194 -32768
195 },
196 len => {
197 let fulllen: i32 = len as i32 + shift as i32;
199 let shift: i32 = shift as i32;
200 let bits = pump.get_bits(len as u32) as i32;
201 let mut diff: i32 = ((bits << 1) + 1) << shift >> 1;
202 if (diff & (1 << (fulllen - 1))) == 0 {
203 diff -= (1 << fulllen) - ((shift == 0) as i32);
204 }
205 diff
206 },
207 }
208 }
209}
210
211impl fmt::Debug for HuffTable {
212 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
213 if self.initialized {
214 write!(f, "HuffTable {{ bits: {:?} huffval: {:?} }}", self.bits, &self.huffval[..])
215 } else {
216 write!(f, "HuffTable {{ uninitialized }}")
217 }
218 }
219}