ricecomp/read.rs
1use std::ffi::{c_uchar, c_uint, c_ushort};
2
3use crate::log_noop;
4
5/// nonzero_count is lookup table giving number of bits in 8-bit values not including
6/// leading zeros used in fits_rdecomp, fits_rdecomp_short and fits_rdecomp_byte
7const NONZERO_COUNT: [i32; 256] = [
8 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
9 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
10 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
11 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
12 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
13 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
14 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
15 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
16];
17
18#[derive(Debug)]
19pub enum DecodeError {
20 EndOfBuffer,
21 ZeroSizeInput,
22 NotProperlyAllocated,
23}
24
25/// Read the byte at index `c`, returning [`DecodeError::EndOfBuffer`] instead of
26/// panicking when the compressed stream is truncated. The original C decoder
27/// relied on the compressed buffer being over-allocated and only checked the
28/// `c > clen` boundary once per block; with Rust slices an out-of-range index
29/// panics (and a run-of-zeros loop could spin forever), so every streaming read
30/// is bounds-checked here.
31#[inline]
32fn next_byte(input: &[u8], c: usize) -> Result<u8, DecodeError> {
33 match input.get(c) {
34 Some(&v) => Ok(v),
35 None => Err(DecodeError::EndOfBuffer),
36 }
37}
38
39pub struct RCDecoder {
40 log_fn: fn(&str),
41}
42
43impl Default for RCDecoder {
44 fn default() -> Self {
45 Self::new()
46 }
47}
48
49impl RCDecoder {
50 pub fn new() -> RCDecoder {
51 RCDecoder { log_fn: log_noop }
52 }
53
54 pub fn set_log_fn(&mut self, log_fn: fn(&str)) {
55 self.log_fn = log_fn;
56 }
57
58 pub fn decode(
59 &self,
60 input: &[u8], /* input buffer */
61 nx: usize, /* number of output pixels */
62 nblock: usize,
63 output: &mut [c_uint],
64 ) -> Result<(), DecodeError> /* coding block size */ {
65 /* int bsize; */
66
67 let mut k: i32;
68 let mut imax: usize;
69
70 let mut nzero: i32;
71 let mut fs: i32;
72
73 let mut diff: u32;
74
75 assert_eq!(output.len(), nx);
76 output.fill(0);
77
78 /*
79 * Original size of each pixel (bsize, bytes) and coding block
80 * size (nblock, pixels)
81 * Could make bsize a parameter to allow more efficient
82 * compression of short & byte images.
83 */
84 /* bsize = 4; */
85
86 /*
87 * From bsize derive:
88 * FSBITS = # bits required to store FS
89 * FSMAX = maximum value for FS
90 * BBITS = bits/pixel for direct coding
91 */
92
93 /* move out of switch block, to tweak performance */
94 let fsbits: i32 = 5;
95 let fsmax: i32 = 25;
96
97 let bbits: i32 = 1 << fsbits;
98
99 /*
100 * Decode in blocks of nblock pixels
101 */
102
103 /* first 4 bytes of input buffer contain the value of the first */
104 /* 4 byte integer value, without any encoding */
105
106 if input.len() < 4 {
107 (self.log_fn)("decompression error: input buffer not properly allocated");
108 return Err(DecodeError::NotProperlyAllocated);
109 }
110
111 let mut lastpix: u32 = 0;
112 let mut bytevalue: u8 = input[0];
113 lastpix |= (bytevalue as u32) << 24;
114 bytevalue = input[1];
115 lastpix |= (bytevalue as u32) << 16;
116 bytevalue = input[2];
117 lastpix |= (bytevalue as u32) << 8;
118 bytevalue = input[3];
119 lastpix |= bytevalue as u32;
120
121 let mut c_current: usize = 4;
122
123 // cend = c + clen - 4;
124
125 let mut b: u32 = next_byte(input, c_current)? as u32; /* bit buffer */
126 c_current += 1;
127 let mut nbits: i32 = 8; /* number of bits remaining in b */
128
129 let mut i: usize = 0;
130 while i < nx {
131 /* get the FS value from first fsbits */
132 nbits -= fsbits;
133 while nbits < 0 {
134 b = (b << 8) | next_byte(input, c_current)? as u32;
135 c_current += 1;
136 nbits += 8;
137 }
138 fs = ((b >> nbits).wrapping_sub(1)) as i32;
139
140 b &= (1 << nbits) - 1;
141 /* loop over the next block */
142 imax = i + nblock;
143 if imax > nx {
144 imax = nx;
145 }
146 if fs < 0 {
147 /* low-entropy case, all zero differences */
148 while i < imax {
149 output[i] = lastpix;
150 i += 1;
151 }
152 } else if fs == fsmax {
153 /* high-entropy case, directly coded pixel values */
154 while i < imax {
155 k = bbits - nbits;
156 diff = b.wrapping_shl(k as u32);
157 k -= 8;
158 while k >= 0 {
159 b = next_byte(input, c_current)? as u32;
160 c_current += 1;
161 diff |= b << k;
162 k -= 8
163 }
164 if nbits > 0 {
165 b = next_byte(input, c_current)? as u32;
166 c_current += 1;
167 diff |= b >> (-k);
168 b &= (1 << nbits) - 1;
169 } else {
170 b = 0;
171 }
172 /*
173 * undo mapping and differencing
174 * Note that some of these operations will overflow the
175 * unsigned int arithmetic -- that's OK, it all works
176 * out to give the right answers in the output file.
177 */
178 if (diff & 1) == 0 {
179 diff >>= 1;
180 } else {
181 diff = !(diff >> 1);
182 }
183 output[i] = diff.wrapping_add(lastpix);
184 lastpix = output[i];
185 i += 1;
186 }
187 } else {
188 /* normal case, Rice coding */
189 while i < imax {
190 /* count number of leading zeros */
191 while b == 0 {
192 nbits += 8;
193
194 b = next_byte(input, c_current)? as u32;
195 c_current += 1;
196 }
197 nzero = nbits - NONZERO_COUNT[b as usize];
198 nbits -= nzero + 1;
199 /* flip the leading one-bit */
200 b ^= 1 << nbits;
201 /* get the FS trailing bits */
202 nbits -= fs;
203 while nbits < 0 {
204 b = (b << 8) | (next_byte(input, c_current)? as u32);
205
206 c_current += 1;
207 nbits += 8;
208 }
209 diff = ((nzero as u32) << fs) | (b >> nbits);
210 b &= (1 << nbits) - 1;
211
212 /* undo mapping and differencing */
213 if (diff & 1) == 0 {
214 diff >>= 1;
215 } else {
216 diff = !(diff >> 1);
217 }
218 output[i] = diff.wrapping_add(lastpix);
219 lastpix = output[i];
220 i += 1;
221 }
222 }
223 if c_current > input.len() {
224 (self.log_fn)("decompression error: hit end of compressed byte stream");
225 return Err(DecodeError::EndOfBuffer);
226 }
227 }
228 if c_current < input.len() {
229 (self.log_fn)("decompression warning: unused bytes at end of compressed buffer");
230 }
231
232 Ok(())
233 }
234
235 pub fn decode_short(
236 &self,
237 input: &[u8], /* input buffer */
238 nx: usize, /* number of output pixels */
239 nblock: usize,
240 output: &mut [c_ushort],
241 ) -> Result<(), DecodeError> /* coding block size */ {
242 /* int bsize; */
243
244 let mut k: i32;
245 let mut imax: usize;
246
247 let mut nzero: i32;
248 let mut fs: i32;
249
250 let mut diff: u32;
251
252 assert_eq!(output.len(), nx);
253 output.fill(0);
254
255 /*
256 * Original size of each pixel (bsize, bytes) and coding block
257 * size (nblock, pixels)
258 * Could make bsize a parameter to allow more efficient
259 * compression of short & byte images.
260 */
261 /* bsize = 2; */
262
263 /*
264 * From bsize derive:
265 * FSBITS = # bits required to store FS
266 * FSMAX = maximum value for FS
267 * BBITS = bits/pixel for direct coding
268 */
269
270 /* move out of switch block, to tweak performance */
271 let fsbits: i32 = 4;
272 let fsmax: i32 = 14;
273
274 let bbits: i32 = 1 << fsbits;
275
276 /*
277 * Decode in blocks of nblock pixels
278 */
279
280 /* first 2 bytes of input buffer contain the value of the first */
281 /* 2 byte integer value, without any encoding */
282
283 let mut lastpix: u32 = 0;
284 let mut bytevalue: u8 = input[0];
285 lastpix |= (bytevalue as u32) << 8;
286 bytevalue = input[1];
287 lastpix |= bytevalue as u32;
288
289 let mut c_current: usize = 2;
290
291 // cend = c + clen - 2;
292
293 let mut b: u32 = next_byte(input, c_current)? as u32; /* bit buffer */
294 c_current += 1;
295 let mut nbits: i32 = 8; /* number of bits remaining in b */
296
297 let mut i: usize = 0;
298 while i < nx {
299 /* get the FS value from first fsbits */
300 nbits -= fsbits;
301 while nbits < 0 {
302 b = (b << 8) | next_byte(input, c_current)? as u32;
303 c_current += 1;
304 nbits += 8;
305 }
306 fs = ((b >> nbits).wrapping_sub(1)) as i32;
307
308 b &= (1 << nbits) - 1;
309 /* loop over the next block */
310 imax = i + nblock;
311 if imax > nx {
312 imax = nx;
313 }
314 if fs < 0 {
315 /* low-entropy case, all zero differences */
316 while i < imax {
317 output[i] = lastpix as c_ushort;
318 i += 1;
319 }
320 } else if fs == fsmax {
321 /* high-entropy case, directly coded pixel values */
322 while i < imax {
323 k = bbits - nbits;
324 diff = b.wrapping_shl(k as u32);
325 k -= 8;
326 while k >= 0 {
327 b = next_byte(input, c_current)? as u32;
328 c_current += 1;
329 diff |= b << k;
330 k -= 8
331 }
332 if nbits > 0 {
333 b = next_byte(input, c_current)? as u32;
334 c_current += 1;
335 diff |= b >> (-k);
336 b &= (1 << nbits) - 1;
337 } else {
338 b = 0;
339 }
340 /*
341 * undo mapping and differencing
342 * Note that some of these operations will overflow the
343 * unsigned int arithmetic -- that's OK, it all works
344 * out to give the right answers in the output file.
345 */
346 if (diff & 1) == 0 {
347 diff >>= 1;
348 } else {
349 diff = !(diff >> 1);
350 }
351 output[i] = diff.wrapping_add(lastpix) as c_ushort;
352 lastpix = output[i] as u32;
353 i += 1;
354 }
355 } else {
356 /* normal case, Rice coding */
357 while i < imax {
358 /* count number of leading zeros */
359 while b == 0 {
360 nbits += 8;
361
362 b = next_byte(input, c_current)? as u32;
363 c_current += 1;
364 }
365 nzero = nbits - NONZERO_COUNT[b as usize];
366 nbits -= nzero + 1;
367 /* flip the leading one-bit */
368 b ^= 1 << nbits;
369 /* get the FS trailing bits */
370 nbits -= fs;
371 while nbits < 0 {
372 b = (b << 8) | (next_byte(input, c_current)? as u32);
373
374 c_current += 1;
375 nbits += 8;
376 }
377 diff = ((nzero as u32) << fs) | (b >> nbits);
378 b &= (1 << nbits) - 1;
379
380 /* undo mapping and differencing */
381 if (diff & 1) == 0 {
382 diff >>= 1;
383 } else {
384 diff = !(diff >> 1);
385 }
386 output[i] = diff.wrapping_add(lastpix) as c_ushort;
387 lastpix = output[i] as u32;
388 i += 1;
389 }
390 }
391 if c_current > input.len() {
392 (self.log_fn)("decompression error: hit end of compressed byte stream");
393 return Err(DecodeError::EndOfBuffer);
394 }
395 }
396 if c_current < input.len() {
397 (self.log_fn)("decompression warning: unused bytes at end of compressed buffer");
398 }
399
400 Ok(())
401 }
402
403 pub fn decode_byte(
404 &self,
405 input: &[u8], /* input buffer */
406 nx: usize, /* number of output pixels */
407 nblock: usize,
408 output: &mut [c_uchar],
409 ) -> Result<(), DecodeError> /* coding block size */ {
410 /* int bsize; */
411
412 let mut k: i32;
413 let mut imax: usize;
414
415 let mut nzero: i32;
416 let mut fs: i32;
417
418 let mut diff: u32;
419
420 assert_eq!(output.len(), nx);
421 output.fill(0);
422
423 /*
424 * Original size of each pixel (bsize, bytes) and coding block
425 * size (nblock, pixels)
426 * Could make bsize a parameter to allow more efficient
427 * compression of short & byte images.
428 */
429 /* bsize = 1; */
430
431 /*
432 * From bsize derive:
433 * FSBITS = # bits required to store FS
434 * FSMAX = maximum value for FS
435 * BBITS = bits/pixel for direct coding
436 */
437
438 /* move out of switch block, to tweak performance */
439 let fsbits: i32 = 3;
440 let fsmax: i32 = 6;
441
442 let bbits: i32 = 1 << fsbits;
443
444 /*
445 * Decode in blocks of nblock pixels
446 */
447
448 /* first byte of input buffer contain the value of the first */
449 /* byte integer value, without any encoding */
450
451 let mut lastpix: u32 = input[0] as u32;
452
453 let mut c_current: usize = 1;
454
455 // cend = c + clen - 2;
456
457 let mut b: u32 = next_byte(input, c_current)? as u32; /* bit buffer */
458 c_current += 1;
459 let mut nbits: i32 = 8; /* number of bits remaining in b */
460
461 let mut i: usize = 0;
462 while i < nx {
463 /* get the FS value from first fsbits */
464 nbits -= fsbits;
465 while nbits < 0 {
466 b = (b << 8) | next_byte(input, c_current)? as u32;
467 c_current += 1;
468 nbits += 8;
469 }
470 fs = ((b >> nbits).wrapping_sub(1)) as i32;
471
472 b &= (1 << nbits) - 1;
473 /* loop over the next block */
474 imax = i + nblock;
475 if imax > nx {
476 imax = nx;
477 }
478 if fs < 0 {
479 /* low-entropy case, all zero differences */
480 while i < imax {
481 output[i] = lastpix as c_uchar;
482 i += 1;
483 }
484 } else if fs == fsmax {
485 /* high-entropy case, directly coded pixel values */
486 while i < imax {
487 k = bbits - nbits;
488 diff = b.wrapping_shl(k as u32);
489 k -= 8;
490 while k >= 0 {
491 b = next_byte(input, c_current)? as u32;
492 c_current += 1;
493 diff |= b << k;
494 k -= 8
495 }
496 if nbits > 0 {
497 b = next_byte(input, c_current)? as u32;
498 c_current += 1;
499 diff |= b >> (-k);
500 b &= (1 << nbits) - 1;
501 } else {
502 b = 0;
503 }
504 /*
505 * undo mapping and differencing
506 * Note that some of these operations will overflow the
507 * unsigned int arithmetic -- that's OK, it all works
508 * out to give the right answers in the output file.
509 */
510 if (diff & 1) == 0 {
511 diff >>= 1;
512 } else {
513 diff = !(diff >> 1);
514 }
515 output[i] = diff.wrapping_add(lastpix) as c_uchar;
516 lastpix = output[i] as u32;
517 i += 1;
518 }
519 } else {
520 /* normal case, Rice coding */
521 while i < imax {
522 /* count number of leading zeros */
523 while b == 0 {
524 nbits += 8;
525
526 b = next_byte(input, c_current)? as u32;
527 c_current += 1;
528 }
529 nzero = nbits - NONZERO_COUNT[b as usize];
530 nbits -= nzero + 1;
531 /* flip the leading one-bit */
532 b ^= 1 << nbits;
533 /* get the FS trailing bits */
534 nbits -= fs;
535 while nbits < 0 {
536 b = (b << 8) | (next_byte(input, c_current)? as u32);
537
538 c_current += 1;
539 nbits += 8;
540 }
541 diff = ((nzero as u32) << fs) | (b >> nbits);
542 b &= (1 << nbits) - 1;
543
544 /* undo mapping and differencing */
545 if (diff & 1) == 0 {
546 diff >>= 1;
547 } else {
548 diff = !(diff >> 1);
549 }
550 output[i] = diff.wrapping_add(lastpix) as c_uchar;
551 lastpix = output[i] as u32;
552 i += 1;
553 }
554 }
555 if c_current > input.len() {
556 (self.log_fn)("decompression error: hit end of compressed byte stream");
557 return Err(DecodeError::EndOfBuffer);
558 }
559 }
560 if c_current < input.len() {
561 (self.log_fn)("decompression warning: unused bytes at end of compressed buffer");
562 }
563
564 Ok(())
565 }
566}