Skip to main content

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}