Coverage Report

Created: 2026-01-17 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/zune-jpeg-0.5.9/src/bitstream.rs
Line
Count
Source
1
/*
2
 * Copyright (c) 2023.
3
 *
4
 * This software is free software;
5
 *
6
 * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license
7
 */
8
9
#![allow(
10
    clippy::if_not_else,
11
    clippy::similar_names,
12
    clippy::inline_always,
13
    clippy::doc_markdown,
14
    clippy::cast_sign_loss,
15
    clippy::cast_possible_truncation
16
)]
17
18
//! This file exposes a single struct that can decode a huffman encoded
19
//! Bitstream in a JPEG file
20
//!
21
//! This code is optimized for speed.
22
//! It's meant to be super duper super fast, because everyone else depends on this being fast.
23
//! It's (annoyingly) serial hence we cant use parallel bitstreams(it's variable length coding.)
24
//!
25
//! Furthermore, on the case of refills, we have to do bytewise processing because the standard decided
26
//! that we want to support markers in the middle of streams(seriously few people use RST markers).
27
//!
28
//! So we pull in all optimization steps:
29
//! - use `inline[always]`? ✅ ,
30
//! - pre-execute most common cases ✅,
31
//! - add random comments ✅
32
//! -  fast paths ✅.
33
//!
34
//! Speed-wise: It is probably the fastest JPEG BitStream decoder to ever sail the seven seas because of
35
//! a couple of optimization tricks.
36
//! 1. Fast refills from libjpeg-turbo
37
//! 2. As few as possible branches in decoder fast paths.
38
//! 3. Accelerated AC table decoding borrowed from stb_image.h written by Fabian Gissen (@ rygorous),
39
//! improved by me to handle more cases.
40
//! 4. Safe and extensible routines(e.g. cool ways to eliminate bounds check)
41
//! 5. No unsafe here
42
//!
43
//! Readability comes as a second priority(I tried with variable names this time, and we are wayy better than libjpeg).
44
//!
45
//! Anyway if you are reading this it means your cool and I hope you get whatever part of the code you are looking for
46
//! (or learn something cool)
47
//!
48
//! Knock yourself out.
49
use alloc::format;
50
use alloc::string::ToString;
51
use core::cmp::min;
52
53
use zune_core::bytestream::{ZByteReaderTrait, ZReader};
54
55
use crate::errors::DecodeErrors;
56
use crate::huffman::{HuffmanTable, HUFF_LOOKAHEAD};
57
use crate::marker::Marker;
58
use crate::mcu::DCT_BLOCK;
59
use crate::misc::UN_ZIGZAG;
60
61
macro_rules! decode_huff {
62
    ($stream:tt,$symbol:tt,$table:tt) => {
63
        let mut code_length = $symbol >> HUFF_LOOKAHEAD;
64
65
        ($symbol) &= (1 << HUFF_LOOKAHEAD) - 1;
66
67
        if code_length > i32::from(HUFF_LOOKAHEAD)
68
        {
69
            // if the symbol cannot be resolved in the first HUFF_LOOKAHEAD bits,
70
            // we know it lies somewhere between HUFF_LOOKAHEAD and 16 bits since jpeg imposes 16 bit
71
            // limit, we can therefore look 16 bits ahead and try to resolve the symbol
72
            // starting from 1+HUFF_LOOKAHEAD bits.
73
            $symbol = ($stream).peek_bits::<16>() as i32;
74
            // (Credits to Sean T. Barrett stb library for this optimization)
75
            // maxcode is pre-shifted 16 bytes long so that it has (16-code_length)
76
            // zeroes at the end hence we do not need to shift in the inner loop.
77
            while code_length < 17{
78
                if $symbol < $table.maxcode[code_length as usize]  {
79
                    break;
80
                }
81
                code_length += 1;
82
            }
83
84
            if code_length == 17{
85
                // symbol could not be decoded.
86
                //
87
                // We may think, lets fake zeroes, noo
88
                // panic, because Huffman codes are sensitive, probably everything
89
                // after this will be corrupt, so no need to continue.
90
                // panic!("Bad Huffman code length");
91
                return Err(DecodeErrors::Format(format!("Bad Huffman Code 0x{:X}, corrupt JPEG",$symbol)))
92
            }
93
94
            $symbol >>= (16-code_length);
95
            ($symbol) = i32::from(
96
                ($table).values
97
                    [(($symbol + ($table).offset[code_length as usize]) & 0xFF) as usize],
98
            );
99
        }
100
        if code_length> i32::from(($stream).bits_left){
101
            return Err(DecodeErrors::Format(format!("Code length {code_length}  more than bits left {}",($stream).bits_left)))
102
        }
103
        // drop bits read
104
        ($stream).drop_bits(code_length as u8);
105
    };
106
}
107
108
/// A `BitStream` struct, a bit by bit reader with super powers
109
///
110
#[rustfmt::skip]
111
pub(crate) struct BitStream {
112
    /// A MSB type buffer that is used for some certain operations
113
    pub buffer:              u64,
114
    /// A TOP  aligned MSB type buffer that is used to accelerate some operations like
115
    /// peek_bits and get_bits.
116
    ///
117
    /// By top aligned, I mean the top bit (63) represents the top bit in the buffer.
118
    aligned_buffer:          u64,
119
    /// Tell us the bits left the two buffer
120
    pub(crate) bits_left:    u8,
121
    /// Did we find a marker(RST/EOF) during decoding?
122
    pub marker:              Option<Marker>,
123
    /// An i16 with the bit corresponding to successive_low set to 1, others 0.
124
    pub successive_low_mask: i16,
125
    spec_start:              u8,
126
    spec_end:                u8,
127
    pub eob_run:             i32,
128
    pub overread_by:         usize,
129
    /// True if we have seen end of image marker.
130
    /// Don't read anything after that.
131
    pub seen_eoi:            bool,
132
}
133
134
impl BitStream {
135
    /// Create a new BitStream
136
    #[rustfmt::skip]
137
1.73k
    pub(crate) const fn new() -> BitStream {
138
1.73k
        BitStream {
139
1.73k
            buffer:              0,
140
1.73k
            aligned_buffer:      0,
141
1.73k
            bits_left:           0,
142
1.73k
            marker:              None,
143
1.73k
            successive_low_mask: 1,
144
1.73k
            spec_start:          0,
145
1.73k
            spec_end:            0,
146
1.73k
            eob_run:             0,
147
1.73k
            overread_by:         0,
148
1.73k
            seen_eoi:            false,
149
1.73k
        }
150
1.73k
    }
151
152
    /// Create a new Bitstream for progressive decoding
153
    #[allow(clippy::redundant_field_names)]
154
    #[rustfmt::skip]
155
4.51k
    pub(crate) fn new_progressive(al: u8, spec_start: u8, spec_end: u8) -> BitStream {
156
4.51k
        BitStream {
157
4.51k
            buffer:              0,
158
4.51k
            aligned_buffer:      0,
159
4.51k
            bits_left:           0,
160
4.51k
            marker:              None,
161
4.51k
            successive_low_mask: 1i16 << al,
162
4.51k
            spec_start:          spec_start,
163
4.51k
            spec_end:            spec_end,
164
4.51k
            eob_run:             0,
165
4.51k
            overread_by:         0,
166
4.51k
            seen_eoi:            false,
167
4.51k
        }
168
4.51k
    }
169
170
    /// Refill the bit buffer by (a maximum of) 32 bits
171
    ///
172
    /// # Arguments
173
    ///  - `reader`:`&mut BufReader<R>`: A mutable reference to an underlying
174
    ///    File/Memory buffer containing a valid JPEG stream
175
    ///
176
    /// This function will only refill if `self.count` is less than 32
177
    #[inline(always)] // to many call sites? ( perf improvement by 4%)
178
2.12G
    pub fn refill<T>(&mut self, reader: &mut ZReader<T>) -> Result<bool, DecodeErrors>
179
2.12G
    where
180
2.12G
        T: ZByteReaderTrait
181
    {
182
        /// Macro version of a single byte refill.
183
        /// Arguments
184
        /// buffer-> our io buffer, because rust macros cannot get values from
185
        /// the surrounding environment bits_left-> number of bits left
186
        /// to full refill
187
        macro_rules! refill {
188
            ($buffer:expr,$byte:expr,$bits_left:expr) => {
189
                // read a byte from the stream
190
                $byte = u64::from(reader.read_u8());
191
                self.overread_by += usize::from(reader.eof()?);
192
                // append to the buffer
193
                // JPEG is a MSB type buffer so that means we append this
194
                // to the lower end (0..8) of the buffer and push the rest bits above..
195
                $buffer = ($buffer << 8) | $byte;
196
                // Increment bits left
197
                $bits_left += 8;
198
                // Check for special case  of OxFF, to see if it's a stream or a marker
199
                if $byte == 0xff {
200
                    // read next byte
201
                    let mut next_byte = u64::from(reader.read_u8());
202
                    // Byte snuffing, if we encounter byte snuff, we skip the byte
203
                    if next_byte != 0x00 {
204
                        // skip that byte we read
205
                        while next_byte == 0xFF {
206
                            next_byte = u64::from(reader.read_u8());
207
                        }
208
209
                        if next_byte != 0x00 {
210
                            // Undo the byte append and return
211
                            $buffer >>= 8;
212
                            $bits_left -= 8;
213
214
                            if $bits_left != 0 {
215
                                self.aligned_buffer = $buffer << (64 - $bits_left);
216
                            }
217
218
                            let marker = Marker::from_u8(next_byte as u8);
219
                            self.marker = marker;
220
221
                            if let Some(Marker::UNKNOWN(_)) = marker{
222
                                return Err(DecodeErrors::Format("Unknown marker in bit stream".to_string()));
223
                            }
224
                            if next_byte == 0xD9 {
225
                                // special handling for eoi, fill some bytes,even if its zero,
226
                                // removes some panics
227
                                self.buffer <<= 8;
228
                                self.bits_left += 8;
229
                                self.aligned_buffer = self.buffer << (64 - self.bits_left);
230
                            }
231
232
                            return Ok(false);
233
                        }
234
                    }
235
                }
236
            };
237
        }
238
239
        // 32 bits is enough for a decode(16 bits) and receive_extend(max 16 bits)
240
2.12G
        if self.bits_left < 32 {
241
287M
            if self.marker.is_some() || self.overread_by > 0 || self.seen_eoi {
242
                // found a marker, or we are in EOI
243
                // also we are in over-reading mode, where we fill it with zeroes
244
245
                // fill with zeroes
246
276M
                self.buffer <<= 32;
247
276M
                self.bits_left += 32;
248
276M
                self.aligned_buffer = self.buffer << (64 - self.bits_left);
249
276M
                return Ok(true);
250
11.1M
            }
251
252
            // we optimize for the case where we don't have 255 in the stream and have 4 bytes left
253
            // as it is the common case
254
            //
255
            // so we always read 4 bytes, if read_fixed_bytes errors out, the cursor is
256
            // guaranteed not to advance in case of failure (is this true), so
257
            // we revert the read later on (if we have 255), if this fails, we use the normal
258
            // byte at a time read
259
260
11.1M
            if let Ok(bytes) = reader.read_fixed_bytes_or_error::<4>() {
261
                // we have 4 bytes to spare, read the 4 bytes into a temporary buffer
262
                // create buffer
263
11.1M
                let msb_buf = u32::from_be_bytes(bytes);
264
                // check if we have 0xff
265
11.1M
                if !has_byte(msb_buf, 255) {
266
10.2M
                    self.bits_left += 32;
267
10.2M
                    self.buffer <<= 32;
268
10.2M
                    self.buffer |= u64::from(msb_buf);
269
10.2M
                    self.aligned_buffer = self.buffer << (64 - self.bits_left);
270
10.2M
                    return Ok(true);
271
962k
                }
272
273
962k
                reader.rewind(4)?;
274
1.73k
            }
275
            // This serves two reasons,
276
            // 1: Make clippy shut up
277
            // 2: Favour register reuse
278
            let mut byte;
279
            // 4 refills, if all succeed the stream should contain enough bits to decode a
280
            // value
281
963k
            refill!(self.buffer, byte, self.bits_left);
282
936k
            refill!(self.buffer, byte, self.bits_left);
283
890k
            refill!(self.buffer, byte, self.bits_left);
284
859k
            refill!(self.buffer, byte, self.bits_left);
285
            // Construct an MSB buffer whose top bits are the bitstream we are currently holding.
286
826k
            self.aligned_buffer = self.buffer << (64 - self.bits_left);
287
1.83G
        }
288
1.83G
        return Ok(true);
289
2.12G
    }
<zune_jpeg::bitstream::BitStream>::refill::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Line
Count
Source
178
2.12G
    pub fn refill<T>(&mut self, reader: &mut ZReader<T>) -> Result<bool, DecodeErrors>
179
2.12G
    where
180
2.12G
        T: ZByteReaderTrait
181
    {
182
        /// Macro version of a single byte refill.
183
        /// Arguments
184
        /// buffer-> our io buffer, because rust macros cannot get values from
185
        /// the surrounding environment bits_left-> number of bits left
186
        /// to full refill
187
        macro_rules! refill {
188
            ($buffer:expr,$byte:expr,$bits_left:expr) => {
189
                // read a byte from the stream
190
                $byte = u64::from(reader.read_u8());
191
                self.overread_by += usize::from(reader.eof()?);
192
                // append to the buffer
193
                // JPEG is a MSB type buffer so that means we append this
194
                // to the lower end (0..8) of the buffer and push the rest bits above..
195
                $buffer = ($buffer << 8) | $byte;
196
                // Increment bits left
197
                $bits_left += 8;
198
                // Check for special case  of OxFF, to see if it's a stream or a marker
199
                if $byte == 0xff {
200
                    // read next byte
201
                    let mut next_byte = u64::from(reader.read_u8());
202
                    // Byte snuffing, if we encounter byte snuff, we skip the byte
203
                    if next_byte != 0x00 {
204
                        // skip that byte we read
205
                        while next_byte == 0xFF {
206
                            next_byte = u64::from(reader.read_u8());
207
                        }
208
209
                        if next_byte != 0x00 {
210
                            // Undo the byte append and return
211
                            $buffer >>= 8;
212
                            $bits_left -= 8;
213
214
                            if $bits_left != 0 {
215
                                self.aligned_buffer = $buffer << (64 - $bits_left);
216
                            }
217
218
                            let marker = Marker::from_u8(next_byte as u8);
219
                            self.marker = marker;
220
221
                            if let Some(Marker::UNKNOWN(_)) = marker{
222
                                return Err(DecodeErrors::Format("Unknown marker in bit stream".to_string()));
223
                            }
224
                            if next_byte == 0xD9 {
225
                                // special handling for eoi, fill some bytes,even if its zero,
226
                                // removes some panics
227
                                self.buffer <<= 8;
228
                                self.bits_left += 8;
229
                                self.aligned_buffer = self.buffer << (64 - self.bits_left);
230
                            }
231
232
                            return Ok(false);
233
                        }
234
                    }
235
                }
236
            };
237
        }
238
239
        // 32 bits is enough for a decode(16 bits) and receive_extend(max 16 bits)
240
2.12G
        if self.bits_left < 32 {
241
287M
            if self.marker.is_some() || self.overread_by > 0 || self.seen_eoi {
242
                // found a marker, or we are in EOI
243
                // also we are in over-reading mode, where we fill it with zeroes
244
245
                // fill with zeroes
246
276M
                self.buffer <<= 32;
247
276M
                self.bits_left += 32;
248
276M
                self.aligned_buffer = self.buffer << (64 - self.bits_left);
249
276M
                return Ok(true);
250
11.1M
            }
251
252
            // we optimize for the case where we don't have 255 in the stream and have 4 bytes left
253
            // as it is the common case
254
            //
255
            // so we always read 4 bytes, if read_fixed_bytes errors out, the cursor is
256
            // guaranteed not to advance in case of failure (is this true), so
257
            // we revert the read later on (if we have 255), if this fails, we use the normal
258
            // byte at a time read
259
260
11.1M
            if let Ok(bytes) = reader.read_fixed_bytes_or_error::<4>() {
261
                // we have 4 bytes to spare, read the 4 bytes into a temporary buffer
262
                // create buffer
263
11.1M
                let msb_buf = u32::from_be_bytes(bytes);
264
                // check if we have 0xff
265
11.1M
                if !has_byte(msb_buf, 255) {
266
10.2M
                    self.bits_left += 32;
267
10.2M
                    self.buffer <<= 32;
268
10.2M
                    self.buffer |= u64::from(msb_buf);
269
10.2M
                    self.aligned_buffer = self.buffer << (64 - self.bits_left);
270
10.2M
                    return Ok(true);
271
962k
                }
272
273
962k
                reader.rewind(4)?;
274
1.73k
            }
275
            // This serves two reasons,
276
            // 1: Make clippy shut up
277
            // 2: Favour register reuse
278
            let mut byte;
279
            // 4 refills, if all succeed the stream should contain enough bits to decode a
280
            // value
281
963k
            refill!(self.buffer, byte, self.bits_left);
282
936k
            refill!(self.buffer, byte, self.bits_left);
283
890k
            refill!(self.buffer, byte, self.bits_left);
284
859k
            refill!(self.buffer, byte, self.bits_left);
285
            // Construct an MSB buffer whose top bits are the bitstream we are currently holding.
286
826k
            self.aligned_buffer = self.buffer << (64 - self.bits_left);
287
1.83G
        }
288
1.83G
        return Ok(true);
289
2.12G
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<_>
290
    /// Decode the DC coefficient in a MCU block.
291
    ///
292
    /// The decoded coefficient is written to `dc_prediction`
293
    ///
294
    #[allow(
295
        clippy::cast_possible_truncation,
296
        clippy::cast_sign_loss,
297
        clippy::unwrap_used
298
    )]
299
    #[inline(always)]
300
215M
    fn decode_dc<T>(
301
215M
        &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, dc_prediction: &mut i32
302
215M
    ) -> Result<bool, DecodeErrors>
303
215M
    where
304
215M
        T: ZByteReaderTrait
305
    {
306
        let (mut symbol, r);
307
308
215M
        if self.bits_left < 32 {
309
17.9M
            self.refill(reader)?;
310
197M
        };
311
        // look a head HUFF_LOOKAHEAD bits into the bitstream
312
215M
        symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
313
215M
        symbol = dc_table.lookup[symbol as usize];
314
315
215M
        decode_huff!(self, symbol, dc_table);
316
317
215M
        if symbol != 0 {
318
13.6M
            r = self.get_bits(symbol as u8);
319
13.6M
            symbol = huff_extend(r, symbol);
320
201M
        }
321
        // Update DC prediction
322
215M
        *dc_prediction = dc_prediction.wrapping_add(symbol);
323
324
215M
        return Ok(true);
325
215M
    }
<zune_jpeg::bitstream::BitStream>::decode_dc::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Line
Count
Source
300
215M
    fn decode_dc<T>(
301
215M
        &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, dc_prediction: &mut i32
302
215M
    ) -> Result<bool, DecodeErrors>
303
215M
    where
304
215M
        T: ZByteReaderTrait
305
    {
306
        let (mut symbol, r);
307
308
215M
        if self.bits_left < 32 {
309
17.9M
            self.refill(reader)?;
310
197M
        };
311
        // look a head HUFF_LOOKAHEAD bits into the bitstream
312
215M
        symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
313
215M
        symbol = dc_table.lookup[symbol as usize];
314
315
215M
        decode_huff!(self, symbol, dc_table);
316
317
215M
        if symbol != 0 {
318
13.6M
            r = self.get_bits(symbol as u8);
319
13.6M
            symbol = huff_extend(r, symbol);
320
201M
        }
321
        // Update DC prediction
322
215M
        *dc_prediction = dc_prediction.wrapping_add(symbol);
323
324
215M
        return Ok(true);
325
215M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<_>
326
327
    /// Like `decode_dc` but we do not need the result of the component, we only want to remove it
328
    /// from the bitstream of the MCU.
329
0
    fn discard_dc<T>(
330
0
        &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable
331
0
    ) -> Result<bool, DecodeErrors>
332
0
    where
333
0
        T: ZByteReaderTrait
334
    {
335
        let mut symbol;
336
337
0
        if self.bits_left < 32 {
338
0
            self.refill(reader)?;
339
0
        };
340
        // look a head HUFF_LOOKAHEAD bits into the bitstream
341
0
        symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
342
0
        symbol = dc_table.lookup[symbol as usize];
343
344
0
        decode_huff!(self, symbol, dc_table);
345
346
0
        if symbol != 0 {
347
0
            let _ = self.get_bits(symbol as u8);
348
0
        }
349
350
0
        return Ok(true);
351
0
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::discard_dc::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::discard_dc::<_>
352
353
    /// Decode a Minimum Code Unit(MCU) as quickly as possible
354
    ///
355
    /// # Arguments
356
    /// - reader: The bitstream from where we read more bits.
357
    /// - dc_table: The Huffman table used to decode the DC coefficient
358
    /// - ac_table: The Huffman table used to decode AC values
359
    /// - block: A memory region where we will write out the decoded values
360
    /// - DC prediction: Last DC value for this component
361
    ///
362
    #[allow(
363
        clippy::many_single_char_names,
364
        clippy::cast_possible_truncation,
365
        clippy::cast_sign_loss
366
    )]
367
    #[inline(never)]
368
29.9M
    pub fn decode_mcu_block<T>(
369
29.9M
        &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, ac_table: &HuffmanTable,
370
29.9M
        qt_table: &[i32; DCT_BLOCK], block: &mut [i32; 64], dc_prediction: &mut i32
371
29.9M
    ) -> Result<u16, DecodeErrors>
372
29.9M
    where
373
29.9M
        T: ZByteReaderTrait
374
    {
375
        // Get fast AC table as a reference before we enter the hot path
376
29.9M
        let ac_lookup = ac_table.ac_lookup.as_ref().unwrap();
377
378
        let (mut symbol, mut r, mut fast_ac);
379
        // Decode AC coefficients
380
29.9M
        let mut pos: usize = 1;
381
29.9M
        if  self.bits_left < 1 && self.marker.is_some() {
382
1
            return Err(DecodeErrors::Format(
383
1
                "No more bytes left in stream before marker".to_string()
384
1
            ));
385
29.9M
        }
386
        // decode DC, dc prediction will contain the value
387
29.9M
        self.decode_dc(reader, dc_table, dc_prediction)?;
388
389
        // set dc to be the dc prediction.
390
29.9M
        block[0] = *dc_prediction * qt_table[0];
391
392
778M
        while pos < 64 {
393
760M
            self.refill(reader)?;
394
760M
            symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
395
760M
            fast_ac = ac_lookup[symbol as usize];
396
760M
            symbol = ac_table.lookup[symbol as usize];
397
398
760M
            if fast_ac != 0 {
399
700M
                //  FAST AC path
400
700M
                pos += ((fast_ac >> 4) & 15) as usize; // run
401
700M
                let t_pos = UN_ZIGZAG[min(pos, 63)] & 63;
402
700M
403
700M
                block[t_pos] = i32::from(fast_ac >> 8) * (qt_table[t_pos]); // Value
404
700M
                self.drop_bits((fast_ac & 15) as u8);
405
700M
                pos += 1;
406
700M
            } else {
407
59.7M
                decode_huff!(self, symbol, ac_table);
408
409
59.7M
                r = symbol >> 4;
410
59.7M
                symbol &= 15;
411
412
59.7M
                if symbol != 0 {
413
47.7M
                    pos += r as usize;
414
47.7M
                    r = self.get_bits(symbol as u8);
415
47.7M
                    symbol = huff_extend(r, symbol);
416
47.7M
                    let t_pos = UN_ZIGZAG[pos & 63] & 63;
417
47.7M
418
47.7M
                    block[t_pos] = symbol * qt_table[t_pos];
419
47.7M
420
47.7M
                    pos += 1;
421
47.7M
                } else if r != 15 {
422
11.9M
                    return Ok(pos as u16);
423
73.0k
                } else {
424
73.0k
                    pos += 16;
425
73.0k
                }
426
            }
427
        }
428
429
18.0M
        return Ok(64);
430
29.9M
    }
<zune_jpeg::bitstream::BitStream>::decode_mcu_block::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Line
Count
Source
368
29.9M
    pub fn decode_mcu_block<T>(
369
29.9M
        &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, ac_table: &HuffmanTable,
370
29.9M
        qt_table: &[i32; DCT_BLOCK], block: &mut [i32; 64], dc_prediction: &mut i32
371
29.9M
    ) -> Result<u16, DecodeErrors>
372
29.9M
    where
373
29.9M
        T: ZByteReaderTrait
374
    {
375
        // Get fast AC table as a reference before we enter the hot path
376
29.9M
        let ac_lookup = ac_table.ac_lookup.as_ref().unwrap();
377
378
        let (mut symbol, mut r, mut fast_ac);
379
        // Decode AC coefficients
380
29.9M
        let mut pos: usize = 1;
381
29.9M
        if  self.bits_left < 1 && self.marker.is_some() {
382
1
            return Err(DecodeErrors::Format(
383
1
                "No more bytes left in stream before marker".to_string()
384
1
            ));
385
29.9M
        }
386
        // decode DC, dc prediction will contain the value
387
29.9M
        self.decode_dc(reader, dc_table, dc_prediction)?;
388
389
        // set dc to be the dc prediction.
390
29.9M
        block[0] = *dc_prediction * qt_table[0];
391
392
778M
        while pos < 64 {
393
760M
            self.refill(reader)?;
394
760M
            symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
395
760M
            fast_ac = ac_lookup[symbol as usize];
396
760M
            symbol = ac_table.lookup[symbol as usize];
397
398
760M
            if fast_ac != 0 {
399
700M
                //  FAST AC path
400
700M
                pos += ((fast_ac >> 4) & 15) as usize; // run
401
700M
                let t_pos = UN_ZIGZAG[min(pos, 63)] & 63;
402
700M
403
700M
                block[t_pos] = i32::from(fast_ac >> 8) * (qt_table[t_pos]); // Value
404
700M
                self.drop_bits((fast_ac & 15) as u8);
405
700M
                pos += 1;
406
700M
            } else {
407
59.7M
                decode_huff!(self, symbol, ac_table);
408
409
59.7M
                r = symbol >> 4;
410
59.7M
                symbol &= 15;
411
412
59.7M
                if symbol != 0 {
413
47.7M
                    pos += r as usize;
414
47.7M
                    r = self.get_bits(symbol as u8);
415
47.7M
                    symbol = huff_extend(r, symbol);
416
47.7M
                    let t_pos = UN_ZIGZAG[pos & 63] & 63;
417
47.7M
418
47.7M
                    block[t_pos] = symbol * qt_table[t_pos];
419
47.7M
420
47.7M
                    pos += 1;
421
47.7M
                } else if r != 15 {
422
11.9M
                    return Ok(pos as u16);
423
73.0k
                } else {
424
73.0k
                    pos += 16;
425
73.0k
                }
426
            }
427
        }
428
429
18.0M
        return Ok(64);
430
29.9M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<_>
431
432
    /// Advance the bitstream over a block but ignore the data contained.
433
    ///
434
    /// This updates DC prediction but we never dequantize and we never do any Zig-Zag translation
435
    /// either. Still returns the index of the last component read.
436
0
    pub fn discard_mcu_block<T>(
437
0
        &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, ac_table: &HuffmanTable
438
0
    ) -> Result<u16, DecodeErrors>
439
0
    where
440
0
        T: ZByteReaderTrait
441
    {
442
        // Get fast AC table as a reference before we enter the hot path
443
0
        let ac_lookup = ac_table.ac_lookup.as_ref().unwrap();
444
445
        let (mut symbol, mut r, mut fast_ac);
446
        // Decode AC coefficients
447
0
        let mut pos: usize = 1;
448
449
        // decode DC, dc prediction will contain the value
450
0
        self.discard_dc(reader, dc_table)?;
451
452
0
        while pos < 64 {
453
0
            self.refill(reader)?;
454
0
            symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
455
0
            fast_ac = ac_lookup[symbol as usize];
456
0
            symbol = ac_table.lookup[symbol as usize];
457
458
0
            if fast_ac != 0 {
459
0
                //  FAST AC path
460
0
                pos += ((fast_ac >> 4) & 15) as usize; // run
461
0
462
0
                self.drop_bits((fast_ac & 15) as u8);
463
0
                pos += 1;
464
0
            } else {
465
0
                decode_huff!(self, symbol, ac_table);
466
467
0
                r = symbol >> 4;
468
0
                symbol &= 15;
469
470
0
                if symbol != 0 {
471
0
                    pos += r as usize;
472
0
                    // Advance over bits but ignore.
473
0
                    let _ = self.get_bits(symbol as u8);
474
0
475
0
                    pos += 1;
476
0
                } else if r != 15 {
477
0
                    return Ok(pos as u16);
478
0
                } else {
479
0
                    pos += 16;
480
0
                }
481
            }
482
        }
483
484
0
        return Ok(64);
485
0
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::discard_mcu_block::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::discard_mcu_block::<_>
486
487
    /// Peek `look_ahead` bits ahead without discarding them from the buffer
488
    #[inline(always)]
489
    #[allow(clippy::cast_possible_truncation)]
490
2.29G
    const fn peek_bits<const LOOKAHEAD: u8>(&self) -> i32 {
491
2.29G
        (self.aligned_buffer >> (64 - LOOKAHEAD)) as i32
492
2.29G
    }
<zune_jpeg::bitstream::BitStream>::peek_bits::<16>
Line
Count
Source
490
803k
    const fn peek_bits<const LOOKAHEAD: u8>(&self) -> i32 {
491
803k
        (self.aligned_buffer >> (64 - LOOKAHEAD)) as i32
492
803k
    }
<zune_jpeg::bitstream::BitStream>::peek_bits::<9>
Line
Count
Source
490
2.29G
    const fn peek_bits<const LOOKAHEAD: u8>(&self) -> i32 {
491
2.29G
        (self.aligned_buffer >> (64 - LOOKAHEAD)) as i32
492
2.29G
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<_>
493
494
    /// Discard the next `N` bits without checking
495
    #[inline]
496
4.02G
    fn drop_bits(&mut self, n: u8) {
497
        // PS: Its a good check, but triggers fuzzer and a lot of false positives
498
        //debug_assert!(self.bits_left >= n);
499
        //self.bits_left -= n;
500
4.02G
        self.bits_left = self.bits_left.saturating_sub(n);
501
4.02G
        self.aligned_buffer <<= n;
502
4.02G
    }
<zune_jpeg::bitstream::BitStream>::drop_bits
Line
Count
Source
496
2.29G
    fn drop_bits(&mut self, n: u8) {
497
        // PS: Its a good check, but triggers fuzzer and a lot of false positives
498
        //debug_assert!(self.bits_left >= n);
499
        //self.bits_left -= n;
500
2.29G
        self.bits_left = self.bits_left.saturating_sub(n);
501
2.29G
        self.aligned_buffer <<= n;
502
2.29G
    }
<zune_jpeg::bitstream::BitStream>::drop_bits
Line
Count
Source
496
1.73G
    fn drop_bits(&mut self, n: u8) {
497
        // PS: Its a good check, but triggers fuzzer and a lot of false positives
498
        //debug_assert!(self.bits_left >= n);
499
        //self.bits_left -= n;
500
1.73G
        self.bits_left = self.bits_left.saturating_sub(n);
501
1.73G
        self.aligned_buffer <<= n;
502
1.73G
    }
503
504
    /// Read `n_bits` from the buffer  and discard them
505
    #[inline(always)]
506
    #[allow(clippy::cast_possible_truncation)]
507
170M
    fn get_bits(&mut self, n_bits: u8) -> i32 {
508
170M
        let mask = (1_u64 << n_bits) - 1;
509
510
170M
        self.aligned_buffer = self.aligned_buffer.rotate_left(u32::from(n_bits));
511
170M
        let bits = (self.aligned_buffer & mask) as i32;
512
170M
        self.bits_left = self.bits_left.wrapping_sub(n_bits);
513
170M
        bits
514
170M
    }
515
516
    /// Decode a DC block
517
    #[allow(clippy::cast_possible_truncation)]
518
    #[inline]
519
185M
    pub(crate) fn decode_prog_dc_first<T>(
520
185M
        &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, block: &mut i16,
521
185M
        dc_prediction: &mut i32
522
185M
    ) -> Result<(), DecodeErrors>
523
185M
    where
524
185M
        T: ZByteReaderTrait
525
    {
526
185M
        self.decode_dc(reader, dc_table, dc_prediction)?;
527
185M
        *block = (*dc_prediction as i16).wrapping_mul(self.successive_low_mask);
528
185M
        return Ok(());
529
185M
    }
<zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Line
Count
Source
519
185M
    pub(crate) fn decode_prog_dc_first<T>(
520
185M
        &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, block: &mut i16,
521
185M
        dc_prediction: &mut i32
522
185M
    ) -> Result<(), DecodeErrors>
523
185M
    where
524
185M
        T: ZByteReaderTrait
525
    {
526
185M
        self.decode_dc(reader, dc_table, dc_prediction)?;
527
185M
        *block = (*dc_prediction as i16).wrapping_mul(self.successive_low_mask);
528
185M
        return Ok(());
529
185M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<_>
530
    #[inline]
531
205M
    pub(crate) fn decode_prog_dc_refine<T>(
532
205M
        &mut self, reader: &mut ZReader<T>, block: &mut i16
533
205M
    ) -> Result<(), DecodeErrors>
534
205M
    where
535
205M
        T: ZByteReaderTrait
536
    {
537
        // refinement scan
538
205M
        if self.bits_left < 1 {
539
6.38M
            self.refill(reader)?;
540
            // if we find a marker, it may happens we don't refill.
541
            // So let's confirm again that refill worked
542
6.38M
            if self.bits_left < 1 {
543
14
                return Err(DecodeErrors::Format(
544
14
                    "Marker found where not expected in refine bit".to_string()
545
14
                ));
546
6.38M
            }
547
199M
        }
548
549
205M
        if self.get_bit() == 1 {
550
2.41M
            *block = block.wrapping_add(self.successive_low_mask);
551
203M
        }
552
553
205M
        Ok(())
554
205M
    }
<zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Line
Count
Source
531
205M
    pub(crate) fn decode_prog_dc_refine<T>(
532
205M
        &mut self, reader: &mut ZReader<T>, block: &mut i16
533
205M
    ) -> Result<(), DecodeErrors>
534
205M
    where
535
205M
        T: ZByteReaderTrait
536
    {
537
        // refinement scan
538
205M
        if self.bits_left < 1 {
539
6.38M
            self.refill(reader)?;
540
            // if we find a marker, it may happens we don't refill.
541
            // So let's confirm again that refill worked
542
6.38M
            if self.bits_left < 1 {
543
14
                return Err(DecodeErrors::Format(
544
14
                    "Marker found where not expected in refine bit".to_string()
545
14
                ));
546
6.38M
            }
547
199M
        }
548
549
205M
        if self.get_bit() == 1 {
550
2.41M
            *block = block.wrapping_add(self.successive_low_mask);
551
203M
        }
552
553
205M
        Ok(())
554
205M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<_>
555
556
    /// Get a single bit from the bitstream
557
1.73G
    fn get_bit(&mut self) -> u8 {
558
1.73G
        let k = (self.aligned_buffer >> 63) as u8;
559
        // discard a bit
560
1.73G
        self.drop_bits(1);
561
1.73G
        return k;
562
1.73G
    }
563
128M
    pub(crate) fn decode_mcu_ac_first<T>(
564
128M
        &mut self, reader: &mut ZReader<T>, ac_table: &HuffmanTable, block: &mut [i16; 64]
565
128M
    ) -> Result<bool, DecodeErrors>
566
128M
    where
567
128M
        T: ZByteReaderTrait
568
    {
569
128M
        let fast_ac = ac_table.ac_lookup.as_ref().unwrap();
570
128M
        let bit = self.successive_low_mask;
571
572
128M
        let mut k = self.spec_start as usize;
573
        let (mut symbol, mut r, mut fac);
574
575
        // EOB runs are handled in mcu_prog.rs
576
        'block: loop {
577
1.00G
            self.refill(reader)?;
578
            // Check for marker in the stream
579
580
1.00G
            symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
581
1.00G
            fac = fast_ac[symbol as usize];
582
1.00G
            symbol = ac_table.lookup[symbol as usize];
583
584
1.00G
            if fac != 0 {
585
910M
                // fast ac path
586
910M
                k += ((fac >> 4) & 15) as usize; // run
587
910M
                block[UN_ZIGZAG[min(k, 63)] & 63] = (fac >> 8).wrapping_mul(bit); // value
588
910M
                self.drop_bits((fac & 15) as u8);
589
910M
                k += 1;
590
910M
            } else {
591
91.3M
                decode_huff!(self, symbol, ac_table);
592
593
91.3M
                r = symbol >> 4;
594
91.3M
                symbol &= 15;
595
596
91.3M
                if symbol != 0 {
597
49.0M
                    k += r as usize;
598
49.0M
                    r = self.get_bits(symbol as u8);
599
49.0M
                    symbol = huff_extend(r, symbol);
600
49.0M
                    block[UN_ZIGZAG[k & 63] & 63] = (symbol as i16).wrapping_mul(bit);
601
49.0M
                    k += 1;
602
49.0M
                } else {
603
42.2M
                    if r != 15 {
604
42.2M
                        self.eob_run = 1 << r;
605
42.2M
                        self.eob_run += self.get_bits(r as u8);
606
42.2M
                        self.eob_run -= 1;
607
42.2M
                        break;
608
86.8k
                    }
609
610
86.8k
                    k += 16;
611
                }
612
            }
613
614
959M
            if k > self.spec_end as usize {
615
86.7M
                break 'block;
616
872M
            }
617
        }
618
128M
        return Ok(true);
619
128M
    }
<zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Line
Count
Source
563
128M
    pub(crate) fn decode_mcu_ac_first<T>(
564
128M
        &mut self, reader: &mut ZReader<T>, ac_table: &HuffmanTable, block: &mut [i16; 64]
565
128M
    ) -> Result<bool, DecodeErrors>
566
128M
    where
567
128M
        T: ZByteReaderTrait
568
    {
569
128M
        let fast_ac = ac_table.ac_lookup.as_ref().unwrap();
570
128M
        let bit = self.successive_low_mask;
571
572
128M
        let mut k = self.spec_start as usize;
573
        let (mut symbol, mut r, mut fac);
574
575
        // EOB runs are handled in mcu_prog.rs
576
        'block: loop {
577
1.00G
            self.refill(reader)?;
578
            // Check for marker in the stream
579
580
1.00G
            symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
581
1.00G
            fac = fast_ac[symbol as usize];
582
1.00G
            symbol = ac_table.lookup[symbol as usize];
583
584
1.00G
            if fac != 0 {
585
910M
                // fast ac path
586
910M
                k += ((fac >> 4) & 15) as usize; // run
587
910M
                block[UN_ZIGZAG[min(k, 63)] & 63] = (fac >> 8).wrapping_mul(bit); // value
588
910M
                self.drop_bits((fac & 15) as u8);
589
910M
                k += 1;
590
910M
            } else {
591
91.3M
                decode_huff!(self, symbol, ac_table);
592
593
91.3M
                r = symbol >> 4;
594
91.3M
                symbol &= 15;
595
596
91.3M
                if symbol != 0 {
597
49.0M
                    k += r as usize;
598
49.0M
                    r = self.get_bits(symbol as u8);
599
49.0M
                    symbol = huff_extend(r, symbol);
600
49.0M
                    block[UN_ZIGZAG[k & 63] & 63] = (symbol as i16).wrapping_mul(bit);
601
49.0M
                    k += 1;
602
49.0M
                } else {
603
42.2M
                    if r != 15 {
604
42.2M
                        self.eob_run = 1 << r;
605
42.2M
                        self.eob_run += self.get_bits(r as u8);
606
42.2M
                        self.eob_run -= 1;
607
42.2M
                        break;
608
86.8k
                    }
609
610
86.8k
                    k += 16;
611
                }
612
            }
613
614
959M
            if k > self.spec_end as usize {
615
86.7M
                break 'block;
616
872M
            }
617
        }
618
128M
        return Ok(true);
619
128M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<_>
620
    #[allow(clippy::too_many_lines, clippy::op_ref)]
621
52.4M
    pub(crate) fn decode_mcu_ac_refine<T>(
622
52.4M
        &mut self, reader: &mut ZReader<T>, table: &HuffmanTable, block: &mut [i16; 64]
623
52.4M
    ) -> Result<bool, DecodeErrors>
624
52.4M
    where
625
52.4M
        T: ZByteReaderTrait
626
    {
627
52.4M
        let bit = self.successive_low_mask;
628
629
52.4M
        let mut k = self.spec_start;
630
        let (mut symbol, mut r);
631
632
52.4M
        if self.eob_run == 0 {
633
            'no_eob: loop {
634
                // Decode a coefficient from the bit stream
635
319M
                self.refill(reader)?;
636
637
319M
                symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
638
319M
                symbol = table.lookup[symbol as usize];
639
640
319M
                decode_huff!(self, symbol, table);
641
642
319M
                r = symbol >> 4;
643
319M
                symbol &= 15;
644
645
319M
                if symbol == 0 {
646
17.5M
                    if r != 15 {
647
                        // EOB run is 2^r + bits
648
17.5M
                        self.eob_run = 1 << r;
649
17.5M
                        self.eob_run += self.get_bits(r as u8);
650
                        // EOB runs are handled by the eob logic
651
17.5M
                        break 'no_eob;
652
9.18k
                    }
653
                } else {
654
301M
                    if symbol != 1 {
655
265
                        return Err(DecodeErrors::HuffmanDecode(
656
265
                            "Bad Huffman code, corrupt JPEG?".to_string()
657
265
                        ));
658
301M
                    }
659
                    // get sign bit
660
                    // We assume we have enough bits, which should be correct for sane images
661
                    // since we refill by 32 above
662
301M
                    if self.get_bit() == 1 {
663
497k
                        symbol = i32::from(bit);
664
301M
                    } else {
665
301M
                        symbol = i32::from(-bit);
666
301M
                    }
667
                }
668
669
                // Advance over already nonzero coefficients  appending
670
                // correction bits to the non-zeroes.
671
                // A correction bit is 1 if the absolute value of the coefficient must be increased
672
673
302M
                if k <= self.spec_end {
674
                    'advance_nonzero: loop {
675
1.37G
                        let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63];
676
677
1.37G
                        if *coefficient != 0 {
678
1.09G
                            if self.bits_left < 1 {
679
15.5M
                                self.refill(reader)?;
680
15.5M
                                if self.bits_left < 1 && self.marker.is_some() {
681
16
                                    return Err(DecodeErrors::Format(
682
16
                                        "Marker found where not expected in refine bit".to_string()
683
16
                                    ));
684
15.5M
                                }
685
1.08G
                            }
686
1.09G
                            if self.get_bit() == 1 && (*coefficient & bit) == 0 {
687
915k
                                if *coefficient >= 0 {
688
77.3k
                                    *coefficient += bit;
689
838k
                                } else {
690
838k
                                    *coefficient -= bit;
691
838k
                                }
692
1.09G
                            }
693
                        } else {
694
282M
                            r -= 1;
695
696
282M
                            if r < 0 {
697
                                // reached target zero coefficient.
698
280M
                                break 'advance_nonzero;
699
1.73M
                            }
700
                        };
701
702
1.09G
                        if k == self.spec_end {
703
20.2M
                            break 'advance_nonzero;
704
1.07G
                        }
705
706
1.07G
                        k += 1;
707
                    }
708
1.48M
                }
709
710
302M
                if symbol != 0 {
711
301M
                    let pos = UN_ZIGZAG[k as usize & 63];
712
301M
                    // output new non-zero coefficient.
713
301M
                    block[pos & 63] = symbol as i16;
714
301M
                }
715
716
302M
                k += 1;
717
718
302M
                if k > self.spec_end {
719
27.5M
                    break 'no_eob;
720
274M
                }
721
            }
722
7.40M
        }
723
52.4M
        if self.eob_run > 0 {
724
            // only run if block does not consists of purely zeroes
725
24.9M
            if &block[1..] != &[0; 63] {
726
3.10M
                self.refill(reader)?;
727
728
135M
                while k <= self.spec_end {
729
132M
                    let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63];
730
731
132M
                    if *coefficient != 0 && self.get_bit() == 1 {
732
                        // check if we already modified it, if so do nothing, otherwise
733
                        // append the correction bit.
734
8.14M
                        if (*coefficient & bit) == 0 {
735
2.37M
                            if *coefficient >= 0 {
736
253k
                                *coefficient = coefficient.wrapping_add(bit);
737
2.12M
                            } else {
738
2.12M
                                *coefficient = coefficient.wrapping_sub(bit);
739
2.12M
                            }
740
5.76M
                        }
741
124M
                    }
742
132M
                    if self.bits_left < 1 {
743
                        // refill at the last possible moment
744
1.29M
                        self.refill(reader)?;
745
131M
                    }
746
132M
                    k += 1;
747
                }
748
21.8M
            }
749
            // count a block completed in EOB run
750
24.9M
            self.eob_run -= 1;
751
27.5M
        }
752
52.4M
        return Ok(true);
753
52.4M
    }
<zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>>
Line
Count
Source
621
52.4M
    pub(crate) fn decode_mcu_ac_refine<T>(
622
52.4M
        &mut self, reader: &mut ZReader<T>, table: &HuffmanTable, block: &mut [i16; 64]
623
52.4M
    ) -> Result<bool, DecodeErrors>
624
52.4M
    where
625
52.4M
        T: ZByteReaderTrait
626
    {
627
52.4M
        let bit = self.successive_low_mask;
628
629
52.4M
        let mut k = self.spec_start;
630
        let (mut symbol, mut r);
631
632
52.4M
        if self.eob_run == 0 {
633
            'no_eob: loop {
634
                // Decode a coefficient from the bit stream
635
319M
                self.refill(reader)?;
636
637
319M
                symbol = self.peek_bits::<HUFF_LOOKAHEAD>();
638
319M
                symbol = table.lookup[symbol as usize];
639
640
319M
                decode_huff!(self, symbol, table);
641
642
319M
                r = symbol >> 4;
643
319M
                symbol &= 15;
644
645
319M
                if symbol == 0 {
646
17.5M
                    if r != 15 {
647
                        // EOB run is 2^r + bits
648
17.5M
                        self.eob_run = 1 << r;
649
17.5M
                        self.eob_run += self.get_bits(r as u8);
650
                        // EOB runs are handled by the eob logic
651
17.5M
                        break 'no_eob;
652
9.18k
                    }
653
                } else {
654
301M
                    if symbol != 1 {
655
265
                        return Err(DecodeErrors::HuffmanDecode(
656
265
                            "Bad Huffman code, corrupt JPEG?".to_string()
657
265
                        ));
658
301M
                    }
659
                    // get sign bit
660
                    // We assume we have enough bits, which should be correct for sane images
661
                    // since we refill by 32 above
662
301M
                    if self.get_bit() == 1 {
663
497k
                        symbol = i32::from(bit);
664
301M
                    } else {
665
301M
                        symbol = i32::from(-bit);
666
301M
                    }
667
                }
668
669
                // Advance over already nonzero coefficients  appending
670
                // correction bits to the non-zeroes.
671
                // A correction bit is 1 if the absolute value of the coefficient must be increased
672
673
302M
                if k <= self.spec_end {
674
                    'advance_nonzero: loop {
675
1.37G
                        let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63];
676
677
1.37G
                        if *coefficient != 0 {
678
1.09G
                            if self.bits_left < 1 {
679
15.5M
                                self.refill(reader)?;
680
15.5M
                                if self.bits_left < 1 && self.marker.is_some() {
681
16
                                    return Err(DecodeErrors::Format(
682
16
                                        "Marker found where not expected in refine bit".to_string()
683
16
                                    ));
684
15.5M
                                }
685
1.08G
                            }
686
1.09G
                            if self.get_bit() == 1 && (*coefficient & bit) == 0 {
687
915k
                                if *coefficient >= 0 {
688
77.3k
                                    *coefficient += bit;
689
838k
                                } else {
690
838k
                                    *coefficient -= bit;
691
838k
                                }
692
1.09G
                            }
693
                        } else {
694
282M
                            r -= 1;
695
696
282M
                            if r < 0 {
697
                                // reached target zero coefficient.
698
280M
                                break 'advance_nonzero;
699
1.73M
                            }
700
                        };
701
702
1.09G
                        if k == self.spec_end {
703
20.2M
                            break 'advance_nonzero;
704
1.07G
                        }
705
706
1.07G
                        k += 1;
707
                    }
708
1.48M
                }
709
710
302M
                if symbol != 0 {
711
301M
                    let pos = UN_ZIGZAG[k as usize & 63];
712
301M
                    // output new non-zero coefficient.
713
301M
                    block[pos & 63] = symbol as i16;
714
301M
                }
715
716
302M
                k += 1;
717
718
302M
                if k > self.spec_end {
719
27.5M
                    break 'no_eob;
720
274M
                }
721
            }
722
7.40M
        }
723
52.4M
        if self.eob_run > 0 {
724
            // only run if block does not consists of purely zeroes
725
24.9M
            if &block[1..] != &[0; 63] {
726
3.10M
                self.refill(reader)?;
727
728
135M
                while k <= self.spec_end {
729
132M
                    let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63];
730
731
132M
                    if *coefficient != 0 && self.get_bit() == 1 {
732
                        // check if we already modified it, if so do nothing, otherwise
733
                        // append the correction bit.
734
8.14M
                        if (*coefficient & bit) == 0 {
735
2.37M
                            if *coefficient >= 0 {
736
253k
                                *coefficient = coefficient.wrapping_add(bit);
737
2.12M
                            } else {
738
2.12M
                                *coefficient = coefficient.wrapping_sub(bit);
739
2.12M
                            }
740
5.76M
                        }
741
124M
                    }
742
132M
                    if self.bits_left < 1 {
743
                        // refill at the last possible moment
744
1.29M
                        self.refill(reader)?;
745
131M
                    }
746
132M
                    k += 1;
747
                }
748
21.8M
            }
749
            // count a block completed in EOB run
750
24.9M
            self.eob_run -= 1;
751
27.5M
        }
752
52.4M
        return Ok(true);
753
52.4M
    }
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<_>
754
755
21.2k
    pub fn update_progressive_params(&mut self, _ah: u8, al: u8, spec_start: u8, spec_end: u8) {
756
21.2k
        self.successive_low_mask = 1i16 << al;
757
21.2k
        self.spec_start = spec_start;
758
21.2k
        self.spec_end = spec_end;
759
21.2k
    }
760
761
    /// Reset the stream if we have a restart marker
762
    ///
763
    /// Restart markers indicate drop those bits in the stream and zero out
764
    /// everything
765
    #[cold]
766
189k
    pub fn reset(&mut self) {
767
189k
        self.bits_left = 0;
768
189k
        self.marker = None;
769
189k
        self.buffer = 0;
770
189k
        self.aligned_buffer = 0;
771
189k
        self.eob_run = 0;
772
189k
    }
773
}
774
775
/// Do the equivalent of JPEG HUFF_EXTEND
776
#[inline(always)]
777
110M
fn huff_extend(x: i32, s: i32) -> i32 {
778
    // if x<s return x else return x+offset[s] where offset[s] = ( (-1<<s)+1)
779
110M
    (x) + ((((x) - (1 << ((s) - 1))) >> 31) & (((-1) << (s)) + 1))
780
110M
}
781
782
11.1M
const fn has_zero(v: u32) -> bool {
783
    // Retrieved from Stanford bithacks
784
    // @ https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
785
11.1M
    return !((((v & 0x7F7F_7F7F) + 0x7F7F_7F7F) | v) | 0x7F7F_7F7F) != 0;
786
11.1M
}
787
788
11.1M
const fn has_byte(b: u32, val: u8) -> bool {
789
    // Retrieved from Stanford bithacks
790
    // @ https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
791
11.1M
    has_zero(b ^ ((!0_u32 / 255) * (val as u32)))
792
11.1M
}
793
794
// mod tests {
795
//     use zune_core::bytestream::ZCursor;
796
//     use zune_core::colorspace::ColorSpace;
797
//     use zune_core::options::DecoderOptions;
798
//
799
//     use crate::JpegDecoder;
800
//
801
//     #[test]
802
//     fn test_image() {
803
//         let img = "/Users/etemesi/Downloads/test_IDX_45_RAND_168601280367171438891916_minimized_837.jpg";
804
//         let data = std::fs::read(img).unwrap();
805
//         let options = DecoderOptions::new_cmd().jpeg_set_out_colorspace(ColorSpace::RGB);
806
//         let mut decoder = JpegDecoder::new_with_options(ZCursor::new(&data[..]), options);
807
//
808
//         decoder.decode().unwrap();
809
//         println!("{:?}", decoder.options.jpeg_get_out_colorspace())
810
//     }
811
// }