Skip to main content

libzstd_rs_sys/lib/decompress/
zstd_decompress_block.rs

1use core::arch::asm;
2use core::ffi::c_void;
3use core::ops::Range;
4use core::ptr::{self, NonNull};
5
6use libc::{ptrdiff_t, size_t};
7
8use crate::lib::common::bitstream::BIT_DStream_t;
9use crate::lib::common::entropy_common::FSE_readNCount_slice;
10use crate::lib::common::error_private::{ERR_isError, Error};
11use crate::lib::common::huf::{HUF_flags_bmi2, HUF_flags_disableAsm};
12use crate::lib::common::mem::{MEM_32bits, MEM_readLE24};
13use crate::lib::common::reader::Reader;
14use crate::lib::common::zstd_internal::{
15    LLFSELog, LL_bits, MLFSELog, ML_bits, MaxFSELog, MaxLL, MaxLLBits, MaxML, MaxMLBits, MaxOff,
16    MaxSeq, OffFSELog, Overlap, ZSTD_copy16, ZSTD_wildcopy, LL_DEFAULTNORMLOG, ML_DEFAULTNORMLOG,
17    OF_DEFAULTNORMLOG, WILDCOPY_OVERLENGTH, WILDCOPY_VECLEN, ZSTD_REP_NUM,
18};
19use crate::lib::decompress::huf_decompress::{
20    HUF_decompress1X1_DCtx_wksp, HUF_decompress1X_usingDTable, HUF_decompress4X_usingDTable,
21};
22use crate::lib::decompress::huf_decompress::{HUF_decompress4X_hufOnly_wksp, Writer};
23use crate::lib::decompress::{blockProperties_t, BlockType, SymbolTable};
24use crate::lib::decompress::{
25    LL_base, LitLocation, ML_base, OF_base, OF_bits, Workspace, ZSTD_DCtx, ZSTD_seqSymbol,
26    ZSTD_seqSymbol_header,
27};
28use crate::lib::polyfill::{cfg_select, likely, prefetch_read_data, unlikely, Locality};
29use crate::lib::zstd::{ZSTD_BLOCKSIZE_MAX, ZSTD_WINDOWLOG_MAX, ZSTD_WINDOWLOG_MAX_32};
30
31pub type BIT_DStream_status = core::ffi::c_uint;
32pub const BIT_DStream_overflow: BIT_DStream_status = 3;
33pub const BIT_DStream_completed: BIT_DStream_status = 2;
34pub const BIT_DStream_endOfBuffer: BIT_DStream_status = 1;
35pub const BIT_DStream_unfinished: BIT_DStream_status = 0;
36pub type C2RustUnnamed_0 = core::ffi::c_uint;
37
38pub type streaming_operation = core::ffi::c_uint;
39pub const is_streaming: streaming_operation = 1;
40pub const not_streaming: streaming_operation = 0;
41
42#[derive(Debug, Copy, Clone, PartialEq, Eq)]
43pub(crate) enum StreamingOperation {
44    NotStreaming = 0,
45    IsStreaming = 1,
46}
47
48impl TryFrom<u32> for StreamingOperation {
49    type Error = ();
50
51    fn try_from(value: u32) -> Result<Self, Self::Error> {
52        match value {
53            0 => Ok(Self::NotStreaming),
54            1 => Ok(Self::IsStreaming),
55            _ => Err(()),
56        }
57    }
58}
59
60#[derive(Debug, Copy, Clone, PartialEq, Eq)]
61enum Offset {
62    Regular = 0,
63    Long = 1,
64}
65
66#[repr(C)]
67pub struct seqState_t<'a> {
68    DStream: BIT_DStream_t<'a>,
69    stateLL: ZSTD_fseState<'a>,
70    stateOffb: ZSTD_fseState<'a>,
71    stateML: ZSTD_fseState<'a>,
72    prevOffset: [size_t; 3],
73}
74
75impl ZSTD_DCtx {
76    fn new_seq_state<'a>(&self, mut bit_stream: BIT_DStream_t<'a>) -> seqState_t<'a> {
77        let stateLL = match self.LLTptr {
78            None => ZSTD_fseState::new(&mut bit_stream, &LL_defaultDTable),
79            Some(table) => ZSTD_fseState::new(&mut bit_stream, unsafe { &*table.as_ptr() }),
80        };
81
82        let stateOffb = match self.OFTptr {
83            None => ZSTD_fseState::new(&mut bit_stream, &OF_defaultDTable),
84            Some(table) => ZSTD_fseState::new(&mut bit_stream, unsafe { &*table.as_ptr() }),
85        };
86
87        let stateML = match self.MLTptr {
88            None => ZSTD_fseState::new(&mut bit_stream, &ML_defaultDTable),
89            Some(table) => ZSTD_fseState::new(&mut bit_stream, unsafe { &*table.as_ptr() }),
90        };
91
92        seqState_t {
93            stateLL,
94            stateOffb,
95            stateML,
96            DStream: bit_stream,
97            prevOffset: self.entropy.rep.map(|v| v as size_t),
98        }
99    }
100}
101
102#[repr(C)]
103pub struct ZSTD_fseState<'a> {
104    pub state: size_t,
105    pub table: &'a [ZSTD_seqSymbol],
106}
107
108impl<'a> ZSTD_fseState<'a> {
109    pub(crate) fn new<const N: usize>(
110        bit_dstream: &mut BIT_DStream_t,
111        dt: &'a SymbolTable<N>,
112    ) -> Self {
113        let table = &dt.symbols;
114
115        let state = bit_dstream.read_bits(dt.header.tableLog);
116        bit_dstream.reload();
117
118        Self { state, table }
119    }
120}
121
122#[derive(Copy, Clone, Default)]
123#[repr(C)]
124pub struct seq_t {
125    pub litLength: size_t,
126    pub matchLength: size_t,
127    pub offset: size_t,
128}
129
130#[derive(Copy, Clone, Default)]
131#[repr(C)]
132pub struct ZSTD_OffsetInfo {
133    pub longOffsetShare: core::ffi::c_uint,
134    pub maxNbAdditionalBits: core::ffi::c_uint,
135}
136
137#[repr(u32)]
138enum SymbolEncodingType_e {
139    set_basic = 0,
140    set_rle = 1,
141    set_compressed = 2,
142    set_repeat = 3,
143}
144
145impl TryFrom<u8> for SymbolEncodingType_e {
146    type Error = ();
147
148    fn try_from(value: u8) -> Result<Self, Self::Error> {
149        match value {
150            0 => Ok(SymbolEncodingType_e::set_basic),
151            1 => Ok(SymbolEncodingType_e::set_rle),
152            2 => Ok(SymbolEncodingType_e::set_compressed),
153            3 => Ok(SymbolEncodingType_e::set_repeat),
154            _ => Err(()),
155        }
156    }
157}
158
159pub const CACHELINE_SIZE: core::ffi::c_int = 64;
160
161pub const STREAM_ACCUMULATOR_MIN: core::ffi::c_int = match size_of::<usize>() {
162    4 => STREAM_ACCUMULATOR_MIN_32,
163    8 => STREAM_ACCUMULATOR_MIN_64,
164    _ => unreachable!(),
165};
166pub const STREAM_ACCUMULATOR_MIN_32: core::ffi::c_int = 25;
167pub const STREAM_ACCUMULATOR_MIN_64: core::ffi::c_int = 57;
168
169pub const ZSTD_BLOCKHEADERSIZE: core::ffi::c_int = 3;
170static ZSTD_blockHeaderSize: size_t = ZSTD_BLOCKHEADERSIZE as size_t;
171pub const LONGNBSEQ: core::ffi::c_int = 0x7f00 as core::ffi::c_int;
172
173impl ZSTD_DCtx {
174    fn block_size_max(&self) -> usize {
175        if self.isFrameDecompression {
176            self.fParams.blockSizeMax as usize
177        } else {
178            ZSTD_BLOCKSIZE_MAX as usize
179        }
180    }
181}
182
183pub(crate) fn ZSTD_getcBlockSize(
184    src: &[u8],
185    bpPtr: &mut blockProperties_t,
186) -> Result<size_t, Error> {
187    if src.len() < ZSTD_blockHeaderSize {
188        return Err(Error::srcSize_wrong);
189    }
190    let cBlockHeader = unsafe { MEM_readLE24(src.as_ptr().cast()) };
191    let cSize = cBlockHeader >> 3;
192
193    bpPtr.lastBlock = (cBlockHeader & 1) != 0;
194    bpPtr.blockType = BlockType::from(cBlockHeader >> 1 & 0b11);
195    bpPtr.origSize = cSize;
196
197    match bpPtr.blockType {
198        BlockType::Raw | BlockType::Compressed => Ok(cSize as size_t),
199        BlockType::Rle => Ok(1),
200        BlockType::Reserved => Err(Error::corruption_detected),
201    }
202}
203
204pub(crate) fn getc_block_size(src: &[u8]) -> Result<(blockProperties_t, usize), Error> {
205    let [a, b, c, ..] = *src else {
206        return Err(Error::srcSize_wrong);
207    };
208
209    let cBlockHeader = u32::from_le_bytes([a, b, c, 0]);
210    let cSize = cBlockHeader >> 3;
211
212    let bp = blockProperties_t {
213        lastBlock: (cBlockHeader & 1) != 0,
214        blockType: BlockType::from(cBlockHeader >> 1 & 0b11),
215        origSize: cSize,
216    };
217
218    match bp.blockType {
219        BlockType::Raw | BlockType::Compressed => Ok((bp, cSize as size_t)),
220        BlockType::Rle => Ok((bp, 1)),
221        BlockType::Reserved => Err(Error::corruption_detected),
222    }
223}
224
225fn ZSTD_allocateLiteralsBuffer(
226    dctx: &mut ZSTD_DCtx,
227    mut dst: Writer<'_>,
228    litSize: usize,
229    streaming: StreamingOperation,
230    expectedWriteSize: usize,
231    split_immediately: bool,
232) {
233    let dstCapacity = dst.capacity();
234    let dst = dst.as_mut_ptr();
235
236    let blockSizeMax = dctx.block_size_max();
237    if streaming == StreamingOperation::NotStreaming
238        && dstCapacity
239            > blockSizeMax.wrapping_add(WILDCOPY_OVERLENGTH + litSize + WILDCOPY_OVERLENGTH)
240    {
241        dctx.litBuffer = dst.wrapping_add(blockSizeMax + WILDCOPY_OVERLENGTH);
242        dctx.litBufferEnd = dctx.litBuffer.wrapping_add(litSize);
243        dctx.litBufferLocation = LitLocation::ZSTD_in_dst;
244    } else if litSize <= ZSTD_LITBUFFEREXTRASIZE {
245        dctx.litBuffer = (dctx.litExtraBuffer).as_mut_ptr();
246        dctx.litBufferEnd = dctx.litBuffer.wrapping_add(litSize);
247        dctx.litBufferLocation = LitLocation::ZSTD_not_in_dst;
248    } else {
249        if split_immediately {
250            dctx.litBuffer = dst
251                .wrapping_add(expectedWriteSize)
252                .wrapping_sub(litSize)
253                .wrapping_add(ZSTD_LITBUFFEREXTRASIZE)
254                .wrapping_sub(WILDCOPY_OVERLENGTH);
255            dctx.litBufferEnd = dctx
256                .litBuffer
257                .wrapping_add(litSize)
258                .wrapping_sub(ZSTD_LITBUFFEREXTRASIZE);
259        } else {
260            dctx.litBuffer = dst.wrapping_add(expectedWriteSize).wrapping_sub(litSize);
261            dctx.litBufferEnd = dst.wrapping_add(expectedWriteSize);
262        }
263        dctx.litBufferLocation = LitLocation::ZSTD_split;
264    }
265}
266
267const ZSTD_LBMIN: usize = 64;
268const ZSTD_LBMAX: usize = 128 << 10;
269
270const ZSTD_DECODER_INTERNAL_BUFFER: usize = 1 << 16;
271
272pub(crate) const ZSTD_LITBUFFEREXTRASIZE: usize = {
273    // just a const clamp
274    if ZSTD_DECODER_INTERNAL_BUFFER < ZSTD_LBMIN {
275        ZSTD_LBMIN
276    } else if ZSTD_DECODER_INTERNAL_BUFFER > ZSTD_LBMAX {
277        ZSTD_LBMAX
278    } else {
279        ZSTD_DECODER_INTERNAL_BUFFER
280    }
281};
282
283fn ZSTD_decodeLiteralsBlock(
284    dctx: &mut ZSTD_DCtx,
285    src: &[u8],
286    dst: Writer<'_>,
287    streaming: StreamingOperation,
288) -> Result<size_t, Error> {
289    // for a non-null block
290    const MIN_CBLOCK_SIZE: usize = 1 /*litCSize*/ + 1/* RLE or RAW */;
291    if src.len() < MIN_CBLOCK_SIZE {
292        return Err(Error::corruption_detected);
293    }
294
295    let blockSizeMax = dctx.block_size_max();
296
297    let litEncType = SymbolEncodingType_e::try_from(src[0] & 0b11).unwrap();
298    match litEncType {
299        SymbolEncodingType_e::set_repeat if !dctx.litEntropy => {
300            return Err(Error::dictionary_corrupted);
301        }
302        SymbolEncodingType_e::set_repeat | SymbolEncodingType_e::set_compressed => {}
303        SymbolEncodingType_e::set_basic => {
304            let (lhSize, litSize) = match src[0] >> 2 & 0b11 {
305                1 => (2usize, (u16::from_le_bytes([src[0], src[1]]) >> 4) as usize),
306                3 => {
307                    let [a, b, c, ..] = *src else {
308                        return Err(Error::corruption_detected);
309                    };
310
311                    (3, (u32::from_le_bytes([a, b, c, 0]) >> 4) as usize)
312                }
313                _ => (1, (src[0] >> 3) as usize),
314            };
315
316            if litSize > 0 && dst.is_null() {
317                return Err(Error::dstSize_tooSmall);
318            }
319            if litSize > blockSizeMax {
320                return Err(Error::corruption_detected);
321            }
322
323            let expectedWriteSize = Ord::min(dst.capacity(), blockSizeMax);
324            if expectedWriteSize < litSize {
325                return Err(Error::dstSize_tooSmall);
326            }
327
328            ZSTD_allocateLiteralsBuffer(dctx, dst, litSize, streaming, expectedWriteSize, true);
329
330            if lhSize + litSize + WILDCOPY_OVERLENGTH > src.len() {
331                if litSize.wrapping_add(lhSize) > src.len() {
332                    return Err(Error::corruption_detected);
333                }
334                if dctx.litBufferLocation == LitLocation::ZSTD_split {
335                    unsafe {
336                        let len = litSize - ZSTD_LITBUFFEREXTRASIZE;
337                        let src = &src[lhSize..][..len];
338
339                        core::ptr::copy_nonoverlapping(src.as_ptr(), dctx.litBuffer, len)
340                    };
341
342                    dctx.litExtraBuffer[..ZSTD_LITBUFFEREXTRASIZE].copy_from_slice(
343                        &src[lhSize + litSize - ZSTD_LITBUFFEREXTRASIZE..]
344                            [..ZSTD_LITBUFFEREXTRASIZE],
345                    );
346                } else {
347                    unsafe {
348                        let src = &src[lhSize..][..litSize];
349
350                        core::ptr::copy_nonoverlapping(src.as_ptr(), dctx.litBuffer, litSize)
351                    };
352                }
353                dctx.litPtr = dctx.litBuffer;
354                dctx.litSize = litSize;
355                return Ok(lhSize.wrapping_add(litSize));
356            }
357
358            dctx.litPtr = src[lhSize..].as_ptr();
359            dctx.litSize = litSize;
360            dctx.litBufferEnd = unsafe { (dctx.litPtr).add(litSize) };
361            dctx.litBufferLocation = LitLocation::ZSTD_not_in_dst;
362
363            return Ok(lhSize.wrapping_add(litSize));
364        }
365        SymbolEncodingType_e::set_rle => {
366            let (lhSize, litSize) = match src[0] >> 2 & 0b11 {
367                1 => {
368                    let [a, b, _, ..] = *src else {
369                        return Err(Error::corruption_detected);
370                    };
371
372                    (2usize, (u16::from_le_bytes([a, b]) >> 4) as usize)
373                }
374                3 => {
375                    let [a, b, c, _, ..] = *src else {
376                        return Err(Error::corruption_detected);
377                    };
378
379                    (3, (u32::from_le_bytes([a, b, c, 0]) >> 4) as usize)
380                }
381                _ => (1, (src[0] >> 3) as usize),
382            };
383
384            if litSize > 0 && dst.is_null() {
385                return Err(Error::dstSize_tooSmall);
386            }
387            if litSize > blockSizeMax {
388                return Err(Error::corruption_detected);
389            }
390
391            let expectedWriteSize = Ord::min(dst.capacity(), blockSizeMax);
392            if expectedWriteSize < litSize {
393                return Err(Error::dstSize_tooSmall);
394            }
395
396            ZSTD_allocateLiteralsBuffer(dctx, dst, litSize, streaming, expectedWriteSize, true);
397
398            if dctx.litBufferLocation == LitLocation::ZSTD_split {
399                unsafe {
400                    ptr::write_bytes(
401                        dctx.litBuffer,
402                        src[lhSize],
403                        litSize - ZSTD_LITBUFFEREXTRASIZE,
404                    )
405                };
406
407                dctx.litExtraBuffer[..ZSTD_LITBUFFEREXTRASIZE].fill(src[lhSize]);
408            } else {
409                unsafe {
410                    ptr::write_bytes(dctx.litBuffer, src[lhSize], litSize);
411                }
412            }
413            dctx.litPtr = dctx.litBuffer;
414            dctx.litSize = litSize;
415            return Ok(lhSize.wrapping_add(1));
416        }
417    }
418
419    let [a, b, c, d, size_correction, ..] = *src else {
420        return Err(Error::corruption_detected);
421    };
422    let lhc = u32::from_le_bytes([a, b, c, d]) as usize;
423
424    let flags = {
425        let bmi_flag = if dctx.bmi2 {
426            HUF_flags_bmi2 as core::ffi::c_int
427        } else {
428            0
429        };
430
431        let disable_asm_flag = if dctx.disableHufAsm {
432            HUF_flags_disableAsm as core::ffi::c_int
433        } else {
434            0
435        };
436
437        bmi_flag | disable_asm_flag
438    };
439
440    let lhlCode = (src[0] >> 2 & 0b11) as u32;
441    let singleStream = lhlCode == 0;
442
443    let (lhSize, litSize, litCSize) = match lhlCode {
444        2 => (4, lhc >> 4 & 0x3fff, lhc >> 18),
445        3 => (
446            5,
447            lhc >> 4 & 0x3ffff,
448            (lhc >> 22) + ((size_correction as usize) << 10),
449        ),
450        _ => (3, lhc >> 4 & 0x3ff, lhc >> 14 & 0x3ff),
451    };
452
453    if litSize > 0 && dst.is_null() {
454        return Err(Error::dstSize_tooSmall);
455    }
456    if litSize > blockSizeMax {
457        return Err(Error::corruption_detected);
458    }
459    if !singleStream && litSize < 6 {
460        return Err(Error::literals_headerWrong);
461    }
462    if litCSize.wrapping_add(lhSize) > src.len() {
463        return Err(Error::corruption_detected);
464    }
465
466    let expectedWriteSize = Ord::min(dst.capacity(), blockSizeMax);
467    if expectedWriteSize < litSize {
468        return Err(Error::dstSize_tooSmall);
469    }
470
471    ZSTD_allocateLiteralsBuffer(dctx, dst, litSize, streaming, expectedWriteSize, false);
472
473    /* prefetch huffman table if cold */
474    if dctx.ddictIsCold && litSize > 768 {
475        // NOTE: the litSize comparison is a heuristic.
476        let ptr = match dctx.HUFptr {
477            None => &raw const dctx.entropy.hufTable,
478            Some(ptr) => ptr.as_ptr().cast_const(),
479        };
480        prefetch_val(ptr);
481    }
482
483    let writer = unsafe { Writer::from_raw_parts(dctx.litBuffer, litSize as _) };
484    let huf_src = &src[lhSize..][..litCSize];
485
486    let hufSuccess = if let SymbolEncodingType_e::set_repeat = litEncType {
487        let dtable = match dctx.HUFptr {
488            None => &dctx.entropy.hufTable,
489            Some(ptr) => unsafe { ptr.as_ref() },
490        };
491
492        if singleStream {
493            HUF_decompress1X_usingDTable(writer, huf_src, dtable, flags)
494        } else {
495            HUF_decompress4X_usingDTable(writer, huf_src, dtable, flags)
496        }
497    } else if singleStream {
498        HUF_decompress1X1_DCtx_wksp(
499            &mut dctx.entropy.hufTable,
500            writer,
501            huf_src,
502            &mut dctx.workspace,
503            flags,
504        )
505    } else {
506        HUF_decompress4X_hufOnly_wksp(
507            &mut dctx.entropy.hufTable,
508            writer,
509            huf_src,
510            &mut dctx.workspace,
511            flags,
512        )
513    };
514
515    if dctx.litBufferLocation == LitLocation::ZSTD_split {
516        debug_assert!(litSize > ZSTD_LITBUFFEREXTRASIZE);
517
518        unsafe {
519            core::ptr::copy_nonoverlapping(
520                dctx.litBufferEnd.sub(ZSTD_LITBUFFEREXTRASIZE),
521                dctx.litExtraBuffer.as_mut_ptr(),
522                ZSTD_LITBUFFEREXTRASIZE,
523            );
524            core::ptr::copy(
525                dctx.litBuffer,
526                dctx.litBuffer
527                    .add(ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH),
528                litSize.wrapping_sub(ZSTD_LITBUFFEREXTRASIZE),
529            );
530            dctx.litBuffer = (dctx.litBuffer).add(ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH);
531            dctx.litBufferEnd = (dctx.litBufferEnd).sub(WILDCOPY_OVERLENGTH);
532        }
533    }
534
535    if ERR_isError(hufSuccess) {
536        return Err(Error::corruption_detected);
537    }
538
539    dctx.litPtr = dctx.litBuffer;
540    dctx.litSize = litSize;
541    dctx.litEntropy = true;
542
543    if let SymbolEncodingType_e::set_compressed = litEncType {
544        dctx.HUFptr = None;
545    }
546
547    Ok(litCSize.wrapping_add(lhSize))
548}
549
550const fn sequence_symbol(
551    nextState: u16,
552    nbAdditionalBits: u8,
553    nbBits: u8,
554    baseValue: u32,
555) -> ZSTD_seqSymbol {
556    ZSTD_seqSymbol {
557        nextState,
558        nbAdditionalBits,
559        nbBits,
560        baseValue,
561    }
562}
563
564const fn sequence_header(fastMode: u32, tableLog: u32) -> ZSTD_seqSymbol_header {
565    ZSTD_seqSymbol_header { fastMode, tableLog }
566}
567
568/// Default FSE distribution table for Literal Lengths.
569#[rustfmt::skip]
570static LL_defaultDTable: SymbolTable< { 1 << LL_DEFAULTNORMLOG }> = SymbolTable {
571    /* header : fastMode, tableLog */
572    header: sequence_header(0x00010101, LL_DEFAULTNORMLOG),
573    /* nextState, nbAddBits, nbBits, baseVal */
574    symbols: [
575        sequence_symbol( 0,  0,  4,    0), sequence_symbol(16,  0,  4,    0),
576        sequence_symbol(32,  0,  5,    1), sequence_symbol( 0,  0,  5,    3),
577        sequence_symbol( 0,  0,  5,    4), sequence_symbol( 0,  0,  5,    6),
578        sequence_symbol( 0,  0,  5,    7), sequence_symbol( 0,  0,  5,    9),
579        sequence_symbol( 0,  0,  5,   10), sequence_symbol( 0,  0,  5,   12),
580        sequence_symbol( 0,  0,  6,   14), sequence_symbol( 0,  1,  5,   16),
581        sequence_symbol( 0,  1,  5,   20), sequence_symbol( 0,  1,  5,   22),
582        sequence_symbol( 0,  2,  5,   28), sequence_symbol( 0,  3,  5,   32),
583        sequence_symbol( 0,  4,  5,   48), sequence_symbol(32,  6,  5,   64),
584        sequence_symbol( 0,  7,  5,  128), sequence_symbol( 0,  8,  6,  256),
585        sequence_symbol( 0, 10,  6, 1024), sequence_symbol( 0, 12,  6, 4096),
586        sequence_symbol(32,  0,  4,    0), sequence_symbol( 0,  0,  4,    1),
587        sequence_symbol( 0,  0,  5,    2), sequence_symbol(32,  0,  5,    4),
588        sequence_symbol( 0,  0,  5,    5), sequence_symbol(32,  0,  5,    7),
589        sequence_symbol( 0,  0,  5,    8), sequence_symbol(32,  0,  5,   10),
590        sequence_symbol( 0,  0,  5,   11), sequence_symbol( 0,  0,  6,   13),
591        sequence_symbol(32,  1,  5,   16), sequence_symbol( 0,  1,  5,   18),
592        sequence_symbol(32,  1,  5,   22), sequence_symbol( 0,  2,  5,   24),
593        sequence_symbol(32,  3,  5,   32), sequence_symbol( 0,  3,  5,   40),
594        sequence_symbol( 0,  6,  4,   64), sequence_symbol(16,  6,  4,   64),
595        sequence_symbol(32,  7,  5,  128), sequence_symbol( 0,  9,  6,  512),
596        sequence_symbol( 0, 11,  6, 2048), sequence_symbol(48,  0,  4,    0),
597        sequence_symbol(16,  0,  4,    1), sequence_symbol(32,  0,  5,    2),
598        sequence_symbol(32,  0,  5,    3), sequence_symbol(32,  0,  5,    5),
599        sequence_symbol(32,  0,  5,    6), sequence_symbol(32,  0,  5,    8),
600        sequence_symbol(32,  0,  5,    9), sequence_symbol(32,  0,  5,   11),
601        sequence_symbol(32,  0,  5,   12), sequence_symbol( 0,  0,  6,   15),
602        sequence_symbol(32,  1,  5,   18), sequence_symbol(32,  1,  5,   20),
603        sequence_symbol(32,  2,  5,   24), sequence_symbol(32,  2,  5,   28),
604        sequence_symbol(32,  3,  5,   40), sequence_symbol(32,  4,  5,   48),
605        sequence_symbol( 0, 16,  6,65536), sequence_symbol( 0, 15,  6,32768),
606        sequence_symbol( 0, 14,  6,16384), sequence_symbol( 0, 13,  6, 8192),
607    ]
608};
609
610/// Default FSE distribution table for Offset Codes.
611#[rustfmt::skip]
612static OF_defaultDTable: SymbolTable<{ 1 << OF_DEFAULTNORMLOG }> = SymbolTable {
613    /* header : fastMode, tableLog */
614    header: sequence_header(0x00010101, OF_DEFAULTNORMLOG),
615    /* nextState, nbAddBits, nbBits, baseVal */
616    symbols: [
617        sequence_symbol( 0,  0,  5,    0),     sequence_symbol( 0,  6,  4,   61),
618        sequence_symbol( 0,  9,  5,  509),     sequence_symbol( 0, 15,  5,32765),
619        sequence_symbol( 0, 21,  5,2097149),   sequence_symbol( 0,  3,  5,    5),
620        sequence_symbol( 0,  7,  4,  125),     sequence_symbol( 0, 12,  5, 4093),
621        sequence_symbol( 0, 18,  5,262141),    sequence_symbol( 0, 23,  5,8388605),
622        sequence_symbol( 0,  5,  5,   29),     sequence_symbol( 0,  8,  4,  253),
623        sequence_symbol( 0, 14,  5,16381),     sequence_symbol( 0, 20,  5,1048573),
624        sequence_symbol( 0,  2,  5,    1),     sequence_symbol(16,  7,  4,  125),
625        sequence_symbol( 0, 11,  5, 2045),     sequence_symbol( 0, 17,  5,131069),
626        sequence_symbol( 0, 22,  5,4194301),   sequence_symbol( 0,  4,  5,   13),
627        sequence_symbol(16,  8,  4,  253),     sequence_symbol( 0, 13,  5, 8189),
628        sequence_symbol( 0, 19,  5,524285),    sequence_symbol( 0,  1,  5,    1),
629        sequence_symbol(16,  6,  4,   61),     sequence_symbol( 0, 10,  5, 1021),
630        sequence_symbol( 0, 16,  5,65533),     sequence_symbol( 0, 28,  5,268435453),
631        sequence_symbol( 0, 27,  5,134217725), sequence_symbol( 0, 26,  5,67108861),
632        sequence_symbol( 0, 25,  5,33554429),  sequence_symbol( 0, 24,  5,16777213),
633    ]
634};
635
636/// Default FSE distribution table for Match Lengths.
637#[rustfmt::skip]
638static ML_defaultDTable: SymbolTable<{ 1 << ML_DEFAULTNORMLOG }> = SymbolTable {
639    /* header : fastMode, tableLog */
640    header: sequence_header(0x00010101, ML_DEFAULTNORMLOG),
641    /* nextState, nbAddBits, nbBits, baseVal */
642    symbols: [
643        sequence_symbol( 0,  0,  6,    3),  sequence_symbol( 0,  0,  4,    4),
644        sequence_symbol(32,  0,  5,    5),  sequence_symbol( 0,  0,  5,    6),
645        sequence_symbol( 0,  0,  5,    8),  sequence_symbol( 0,  0,  5,    9),
646        sequence_symbol( 0,  0,  5,   11),  sequence_symbol( 0,  0,  6,   13),
647        sequence_symbol( 0,  0,  6,   16),  sequence_symbol( 0,  0,  6,   19),
648        sequence_symbol( 0,  0,  6,   22),  sequence_symbol( 0,  0,  6,   25),
649        sequence_symbol( 0,  0,  6,   28),  sequence_symbol( 0,  0,  6,   31),
650        sequence_symbol( 0,  0,  6,   34),  sequence_symbol( 0,  1,  6,   37),
651        sequence_symbol( 0,  1,  6,   41),  sequence_symbol( 0,  2,  6,   47),
652        sequence_symbol( 0,  3,  6,   59),  sequence_symbol( 0,  4,  6,   83),
653        sequence_symbol( 0,  7,  6,  131),  sequence_symbol( 0,  9,  6,  515),
654        sequence_symbol(16,  0,  4,    4),  sequence_symbol( 0,  0,  4,    5),
655        sequence_symbol(32,  0,  5,    6),  sequence_symbol( 0,  0,  5,    7),
656        sequence_symbol(32,  0,  5,    9),  sequence_symbol( 0,  0,  5,   10),
657        sequence_symbol( 0,  0,  6,   12),  sequence_symbol( 0,  0,  6,   15),
658        sequence_symbol( 0,  0,  6,   18),  sequence_symbol( 0,  0,  6,   21),
659        sequence_symbol( 0,  0,  6,   24),  sequence_symbol( 0,  0,  6,   27),
660        sequence_symbol( 0,  0,  6,   30),  sequence_symbol( 0,  0,  6,   33),
661        sequence_symbol( 0,  1,  6,   35),  sequence_symbol( 0,  1,  6,   39),
662        sequence_symbol( 0,  2,  6,   43),  sequence_symbol( 0,  3,  6,   51),
663        sequence_symbol( 0,  4,  6,   67),  sequence_symbol( 0,  5,  6,   99),
664        sequence_symbol( 0,  8,  6,  259),  sequence_symbol(32,  0,  4,    4),
665        sequence_symbol(48,  0,  4,    4),  sequence_symbol(16,  0,  4,    5),
666        sequence_symbol(32,  0,  5,    7),  sequence_symbol(32,  0,  5,    8),
667        sequence_symbol(32,  0,  5,   10),  sequence_symbol(32,  0,  5,   11),
668        sequence_symbol( 0,  0,  6,   14),  sequence_symbol( 0,  0,  6,   17),
669        sequence_symbol( 0,  0,  6,   20),  sequence_symbol( 0,  0,  6,   23),
670        sequence_symbol( 0,  0,  6,   26),  sequence_symbol( 0,  0,  6,   29),
671        sequence_symbol( 0,  0,  6,   32),  sequence_symbol( 0, 16,  6,65539),
672        sequence_symbol( 0, 15,  6,32771),  sequence_symbol( 0, 14,  6,16387),
673        sequence_symbol( 0, 13,  6, 8195),  sequence_symbol( 0, 12,  6, 4099),
674        sequence_symbol( 0, 11,  6, 2051),  sequence_symbol( 0, 10,  6, 1027),
675    ]
676};
677
678fn ZSTD_buildSeqTable_rle<const N: usize>(dt: &mut SymbolTable<N>, baseValue: u32, nbAddBits: u8) {
679    dt.header = ZSTD_seqSymbol_header {
680        fastMode: 0,
681        tableLog: 0,
682    };
683
684    dt.symbols[0] = ZSTD_seqSymbol {
685        nbBits: 0,
686        nextState: 0,
687        nbAdditionalBits: nbAddBits,
688        baseValue,
689    };
690}
691
692#[inline(always)]
693fn ZSTD_buildFSETable_body<const N: usize>(
694    dt: &mut SymbolTable<N>,
695    normalizedCounter: &[i16],
696    baseValue: &'static [u32],
697    nbAdditionalBits: &'static [u8],
698    tableLog: core::ffi::c_uint,
699    wksp: &mut FseWorkspace,
700) {
701    let tableDecode = &mut dt.symbols;
702    let tableSize = 1usize << tableLog;
703    let mut highThreshold = tableSize.wrapping_sub(1);
704    let mut DTableH = ZSTD_seqSymbol_header {
705        fastMode: 1,
706        tableLog,
707    };
708
709    let largeLimit = ((1) << tableLog.wrapping_sub(1)) as i16;
710
711    for (s, &v) in normalizedCounter.iter().enumerate() {
712        if v == -1 {
713            tableDecode[highThreshold].baseValue = s as u32;
714            highThreshold = highThreshold.wrapping_sub(1);
715            wksp.symbols[s] = 1;
716        } else {
717            if v >= largeLimit {
718                DTableH.fastMode = 0;
719            }
720            wksp.symbols[s] = v as u16;
721        }
722    }
723
724    dt.header = DTableH;
725
726    if highThreshold == tableSize - 1 {
727        let tableMask = tableSize - 1;
728        let step = (tableSize >> 1) + (tableSize >> 3) + 3;
729        let add = 0x101010101010101u64;
730        let mut pos = 0usize;
731        let mut sv = 0u64;
732        for &v in normalizedCounter {
733            let n = v as usize;
734            wksp.spread[pos..][..8].copy_from_slice(&sv.to_le_bytes());
735            let mut i: usize = 8;
736            while i < n {
737                wksp.spread[pos..][i..][..8].copy_from_slice(&sv.to_le_bytes());
738                i += 8;
739            }
740            pos = pos.wrapping_add(n);
741            sv = sv.wrapping_add(add);
742        }
743
744        let mut position = 0usize;
745        for s in (0..tableSize).step_by(2) {
746            for u in 0..2 {
747                let uPosition = position.wrapping_add(u * step) & tableMask;
748                tableDecode[uPosition].baseValue = wksp.spread[s + u] as u32;
749            }
750            position = position.wrapping_add(2 * step) & tableMask;
751        }
752    } else {
753        let tableMask = tableSize - 1;
754        let step = (tableSize >> 1) + (tableSize >> 3) + 3;
755        let mut position = 0usize;
756        for (s, &v) in normalizedCounter.iter().enumerate() {
757            for _ in 0..i32::from(v) {
758                tableDecode[position].baseValue = s as u32;
759                position = position.wrapping_add(step) & tableMask;
760                while unlikely(position > highThreshold) {
761                    position = position.wrapping_add(step) & tableMask;
762                }
763            }
764        }
765    }
766
767    for seq_symbol in tableDecode[..tableSize].iter_mut() {
768        let symbol = seq_symbol.baseValue as usize;
769        let nextState = wksp.symbols[symbol] as u32;
770        wksp.symbols[symbol] += 1;
771
772        let nbBits = tableLog.wrapping_sub(nextState.ilog2()) as u8;
773
774        *seq_symbol = ZSTD_seqSymbol {
775            nbBits,
776            nextState: (nextState << nbBits).wrapping_sub(tableSize as u32) as u16,
777            nbAdditionalBits: nbAdditionalBits[symbol],
778            baseValue: baseValue[symbol],
779        };
780    }
781}
782
783fn ZSTD_buildFSETable_body_default<const N: usize>(
784    dt: &mut SymbolTable<N>,
785    normalizedCounter: &[i16],
786    baseValue: &'static [u32],
787    nbAdditionalBits: &'static [u8],
788    tableLog: core::ffi::c_uint,
789    wksp: &mut FseWorkspace,
790) {
791    ZSTD_buildFSETable_body(
792        dt,
793        normalizedCounter,
794        baseValue,
795        nbAdditionalBits,
796        tableLog,
797        wksp,
798    );
799}
800
801fn ZSTD_buildFSETable_body_bmi2<const N: usize>(
802    dt: &mut SymbolTable<N>,
803    normalizedCounter: &[i16],
804    baseValue: &'static [u32],
805    nbAdditionalBits: &'static [u8],
806    tableLog: core::ffi::c_uint,
807    wksp: &mut FseWorkspace,
808) {
809    ZSTD_buildFSETable_body(
810        dt,
811        normalizedCounter,
812        baseValue,
813        nbAdditionalBits,
814        tableLog,
815        wksp,
816    );
817}
818
819#[derive(Copy, Clone)]
820#[repr(C, align(4))]
821pub struct FseWorkspace {
822    symbols: [u16; MaxSeq + 1],
823    spread: [u8; (1 << MaxFSELog) + size_of::<u64>()],
824}
825
826pub fn ZSTD_buildFSETable<const N: usize>(
827    dt: &mut SymbolTable<N>,
828    normalizedCounter: &[i16],
829    baseValue: &'static [u32],
830    nbAdditionalBits: &'static [u8],
831    tableLog: core::ffi::c_uint,
832    wksp: &mut FseWorkspace,
833    bmi2: bool,
834) {
835    if bmi2 {
836        ZSTD_buildFSETable_body_bmi2(
837            dt,
838            normalizedCounter,
839            baseValue,
840            nbAdditionalBits,
841            tableLog,
842            wksp,
843        );
844    } else {
845        ZSTD_buildFSETable_body_default(
846            dt,
847            normalizedCounter,
848            baseValue,
849            nbAdditionalBits,
850            tableLog,
851            wksp,
852        );
853    }
854}
855
856fn ZSTD_buildSeqTableNew<const N: usize>(
857    DTableSpace: &mut SymbolTable<N>,
858    DTablePtr: &mut Option<NonNull<SymbolTable<N>>>,
859    type_0: SymbolEncodingType_e,
860    mut max: core::ffi::c_uint,
861    maxLog: u32,
862    src: &[u8],
863    baseValue: &'static [u32],
864    nbAdditionalBits: &'static [u8],
865    flagRepeatTable: bool,
866    ddictIsCold: bool,
867    nbSeq: core::ffi::c_int,
868    wksp: &mut Workspace,
869    bmi2: bool,
870) -> Result<size_t, Error> {
871    match type_0 {
872        SymbolEncodingType_e::set_rle => {
873            let [symbol, ..] = *src else {
874                return Err(Error::srcSize_wrong);
875            };
876
877            if u32::from(symbol) > max {
878                return Err(Error::corruption_detected);
879            }
880
881            let baseline = baseValue[usize::from(symbol)];
882            let nbBits = nbAdditionalBits[usize::from(symbol)];
883            ZSTD_buildSeqTable_rle(DTableSpace, baseline, nbBits);
884
885            *DTablePtr = NonNull::new(DTableSpace);
886            Ok(1)
887        }
888        SymbolEncodingType_e::set_basic => {
889            *DTablePtr = None;
890            Ok(0)
891        }
892        SymbolEncodingType_e::set_repeat => {
893            if !flagRepeatTable {
894                return Err(Error::corruption_detected);
895            }
896            if ddictIsCold && nbSeq > 24 {
897                let pSize = size_of::<ZSTD_seqSymbol>().wrapping_mul(1 + (1usize << maxLog));
898                if let Some(ptr) = *DTablePtr {
899                    prefetch_area(ptr.as_ptr(), pSize);
900                }
901            }
902            Ok(0)
903        }
904        SymbolEncodingType_e::set_compressed => {
905            let mut tableLog: core::ffi::c_uint = 0;
906            let mut norm: [i16; 53] = [0; 53];
907            let Ok(headerSize) = FSE_readNCount_slice(&mut norm, &mut max, &mut tableLog, src)
908            else {
909                return Err(Error::corruption_detected);
910            };
911            if tableLog > maxLog {
912                return Err(Error::corruption_detected);
913            }
914            ZSTD_buildFSETable(
915                DTableSpace,
916                &norm[..=max as usize],
917                baseValue,
918                nbAdditionalBits,
919                tableLog,
920                wksp.as_fse_workspace(),
921                bmi2,
922            );
923            *DTablePtr = NonNull::new(DTableSpace);
924            Ok(headerSize)
925        }
926    }
927}
928
929fn ZSTD_decodeSeqHeaders(
930    dctx: &mut ZSTD_DCtx,
931    nbSeqPtr: &mut core::ffi::c_int,
932    src: &[u8],
933) -> Result<size_t, Error> {
934    let mut ip = 0;
935    let [nbSeq, ..] = *src else {
936        return Err(Error::srcSize_wrong);
937    };
938    let mut nbSeq = i32::from(nbSeq);
939    ip += 1;
940    if nbSeq > 0x7f {
941        if nbSeq == 0xff {
942            let [_, a, b, ..] = *src else {
943                return Err(Error::srcSize_wrong);
944            };
945            nbSeq = i32::from(u16::from_le_bytes([a, b])) + LONGNBSEQ;
946            ip += 2;
947        } else {
948            if ip >= src.len() {
949                return Err(Error::srcSize_wrong);
950            }
951            nbSeq = ((nbSeq - 0x80) << 8) + i32::from(src[ip]);
952            ip += 1;
953        }
954    }
955    *nbSeqPtr = nbSeq;
956    if nbSeq == 0 {
957        if ip != src.len() {
958            return Err(Error::corruption_detected);
959        }
960        return Ok(ip);
961    }
962
963    /* FSE table descriptors */
964
965    // Minimum possible size: 1 byte for symbol encoding types.
966    if ip + 1 > src.len() {
967        return Err(Error::srcSize_wrong);
968    }
969
970    // The last field, Reserved, must be all-zeroes.
971    if src[ip] & 0b11 != 0 {
972        return Err(Error::corruption_detected);
973    }
974
975    let byte = src[ip];
976    let LLtype = SymbolEncodingType_e::try_from(byte >> 6).unwrap();
977    let OFtype = SymbolEncodingType_e::try_from(byte >> 4 & 0b11).unwrap();
978    let MLtype = SymbolEncodingType_e::try_from(byte >> 2 & 0b11).unwrap();
979
980    /* Build DTables */
981
982    ip += 1;
983    let llhSize = ZSTD_buildSeqTableNew(
984        &mut dctx.entropy.LLTable,
985        &mut dctx.LLTptr,
986        LLtype,
987        MaxLL,
988        LLFSELog,
989        &src[ip..],
990        &LL_base,
991        &LL_bits,
992        dctx.fseEntropy,
993        dctx.ddictIsCold,
994        nbSeq,
995        &mut dctx.workspace,
996        dctx.bmi2,
997    )
998    .map_err(|_| Error::corruption_detected)?;
999
1000    ip += llhSize;
1001    let ofhSize = ZSTD_buildSeqTableNew(
1002        &mut dctx.entropy.OFTable,
1003        &mut dctx.OFTptr,
1004        OFtype,
1005        MaxOff,
1006        OffFSELog,
1007        &src[ip..],
1008        &OF_base,
1009        &OF_bits,
1010        dctx.fseEntropy,
1011        dctx.ddictIsCold,
1012        nbSeq,
1013        &mut dctx.workspace,
1014        dctx.bmi2,
1015    )
1016    .map_err(|_| Error::corruption_detected)?;
1017
1018    ip += ofhSize;
1019    let mlhSize = ZSTD_buildSeqTableNew(
1020        &mut dctx.entropy.MLTable,
1021        &mut dctx.MLTptr,
1022        MLtype,
1023        MaxML,
1024        MLFSELog,
1025        &src[ip..],
1026        &ML_base,
1027        &ML_bits,
1028        dctx.fseEntropy,
1029        dctx.ddictIsCold,
1030        nbSeq,
1031        &mut dctx.workspace,
1032        dctx.bmi2,
1033    )
1034    .map_err(|_| Error::corruption_detected)?;
1035
1036    ip += mlhSize;
1037
1038    Ok(ip)
1039}
1040
1041///  Copies 8 bytes from ip to op and updates op and ip where ip <= op.
1042///  If the offset is < 8 then the offset is spread to at least 8 bytes.
1043///
1044///  Precondition: *ip <= *op
1045///  Postcondition: *op - *ip >= 8
1046#[inline(always)]
1047unsafe fn ZSTD_overlapCopy8(op: &mut *mut u8, ip: &mut *const u8, offset: size_t) {
1048    if offset < 8 {
1049        /* close range match, overlap */
1050        *(*op).add(0) = *(*ip).add(0);
1051        *(*op).add(1) = *(*ip).add(1);
1052        *(*op).add(2) = *(*ip).add(2);
1053        *(*op).add(3) = *(*ip).add(3);
1054
1055        static dec32table: [u8; 8] = [0, 1, 2, 1, 4, 4, 4, 4]; // added
1056        *ip = (*ip).add(usize::from(dec32table[offset]));
1057        core::ptr::copy(*ip, (*op).add(4), 4);
1058
1059        static dec64table: [u8; 8] = [8, 8, 8, 7, 8, 9, 10, 11]; // subtracted
1060        *ip = (*ip).sub(usize::from(dec64table[offset]));
1061    } else {
1062        core::ptr::copy(*ip, *op, 8);
1063    }
1064
1065    *ip = (*ip).add(8);
1066    *op = (*op).add(8);
1067
1068    debug_assert!(unsafe { (*op).offset_from(*ip) } >= 8);
1069}
1070
1071/// Specialized version of `memcpy` that is allowed to READ up to [`WILDCOPY_OVERLENGTH`] past the input buffer
1072/// and write up to 16 bytes past `oend_w` (op >= `oend_w` is allowed).
1073/// This function is only called in the uncommon case where the sequence is near the end of the block. It
1074/// should be fast for a single long sequence, but can be slow for several short sequences.
1075///
1076/// @param ovtype controls the overlap detection
1077///     - [`Overlap::NoOverlap`]: The source and destination are guaranteed to be at least [`WILDCOPY_VECLEN`] bytes apart.
1078///     - [`Overlap::OverlapSrcBeforeDst`]: The src and dst may overlap and may be any distance apart.
1079///     The src buffer must be before the dst buffer.
1080unsafe fn ZSTD_safecopy(
1081    mut op: *mut u8,
1082    oend_w: *const u8,
1083    mut ip: *const u8,
1084    mut length: size_t,
1085    ovtype: Overlap,
1086) {
1087    let diff = op as isize - ip as isize;
1088    let oend = op.add(length);
1089
1090    debug_assert!(match ovtype {
1091        Overlap::NoOverlap => diff <= -8 || diff >= 8 || op >= oend_w.cast_mut(),
1092        Overlap::OverlapSrcBeforeDst => diff >= 0,
1093    });
1094
1095    if length < 8 {
1096        /* Handle short lengths. */
1097        while op < oend {
1098            *op = *ip;
1099            ip = ip.add(1);
1100            op = op.add(1);
1101        }
1102        return;
1103    }
1104    if ovtype == Overlap::OverlapSrcBeforeDst {
1105        /* Copy 8 bytes and ensure the offset >= 8 when there can be overlap. */
1106        debug_assert!(length >= 8);
1107        debug_assert!(diff > 0);
1108        ZSTD_overlapCopy8(&mut op, &mut ip, diff as size_t);
1109        length = length.wrapping_sub(8);
1110        debug_assert!(op.offset_from(ip) >= 8);
1111        debug_assert!(op <= oend);
1112    }
1113    if oend <= oend_w as *mut u8 {
1114        /* No risk of overwrite. */
1115        ZSTD_wildcopy(op, ip, length, ovtype);
1116        return;
1117    }
1118    if op <= oend_w as *mut u8 {
1119        /* Wildcopy until we get close to the end. */
1120        ZSTD_wildcopy(op, ip, oend_w.offset_from_unsigned(op), ovtype);
1121        ip = ip.offset(oend_w.offset_from(op));
1122        op = op.offset(oend_w.offset_from(op));
1123    }
1124
1125    /* Handle the leftovers. */
1126    while op < oend {
1127        *op = *ip;
1128        ip = ip.add(1);
1129        op = op.add(1);
1130    }
1131}
1132
1133/// This version allows overlap with dst before src, or handles the non-overlap case with dst after src
1134/// Kept separate from more common [`ZSTD_safecopy`] case to avoid performance impact to the safecopy common case */
1135unsafe fn ZSTD_safecopyDstBeforeSrc(mut op: *mut u8, mut ip: *const u8, length: size_t) {
1136    let diff = op.offset_from(ip) as ptrdiff_t;
1137    let oend = op.add(length);
1138    if length < 8 || diff > -8 {
1139        /* Handle short lengths, close overlaps, and dst not before src. */
1140        while op < oend {
1141            *op = *ip;
1142            ip = ip.add(1);
1143            op = op.add(1);
1144        }
1145        return;
1146    }
1147    if op <= oend.sub(WILDCOPY_OVERLENGTH) && diff < -WILDCOPY_VECLEN as ptrdiff_t {
1148        ZSTD_wildcopy(
1149            op,
1150            ip,
1151            oend.sub(WILDCOPY_OVERLENGTH).offset_from_unsigned(op),
1152            Overlap::NoOverlap,
1153        );
1154        ip = ip.offset(oend.sub(WILDCOPY_OVERLENGTH).offset_from(op));
1155        op = op.offset(oend.sub(WILDCOPY_OVERLENGTH).offset_from(op));
1156    }
1157
1158    /* Handle the leftovers. */
1159    while op < oend {
1160        *op = *ip;
1161        ip = ip.add(1);
1162        op = op.add(1);
1163    }
1164}
1165
1166/// This version handles cases that are near the end of the output buffer. It requires
1167/// more careful checks to make sure there is no overflow. By separating out these hard
1168/// and unlikely cases, we can speed up the common cases.
1169///
1170/// NOTE: This function needs to be fast for a single long sequence, but doesn't need
1171/// to be optimized for many small sequences, since those fall into [`ZSTD_execSequence`].
1172#[inline(never)]
1173unsafe fn ZSTD_execSequenceEnd(
1174    mut op: *mut u8,
1175    oend: *mut u8,
1176    mut sequence: seq_t,
1177    litPtr: &mut *const u8,
1178    litLimit: *const u8,
1179    prefixStart: *const u8,
1180    virtualStart: *const u8,
1181    dictEnd: *const u8,
1182) -> Result<size_t, Error> {
1183    let oLitEnd = op.add(sequence.litLength);
1184    let sequenceLength = (sequence.litLength).wrapping_add(sequence.matchLength);
1185    let iLitEnd = (*litPtr).add(sequence.litLength);
1186    let mut match_0: *const u8 = oLitEnd.wrapping_sub(sequence.offset);
1187    let oend_w = oend.wrapping_sub(WILDCOPY_OVERLENGTH);
1188
1189    /* bounds checks : careful of address space overflow in 32-bit mode */
1190    if sequenceLength > oend.offset_from_unsigned(op) {
1191        return Err(Error::dstSize_tooSmall);
1192    }
1193    if sequence.litLength > litLimit.offset_from_unsigned(*litPtr) {
1194        return Err(Error::corruption_detected);
1195    }
1196
1197    debug_assert!(op < op.wrapping_add(sequenceLength));
1198    debug_assert!(oLitEnd < op.wrapping_add(sequenceLength));
1199
1200    /* copy literals */
1201    ZSTD_safecopy(op, oend_w, *litPtr, sequence.litLength, Overlap::NoOverlap);
1202    op = oLitEnd;
1203    *litPtr = iLitEnd;
1204
1205    /* copy Match */
1206    if sequence.offset > oLitEnd.offset_from_unsigned(prefixStart) {
1207        /* offset beyond prefix */
1208        if sequence.offset > (oLitEnd.addr() - virtualStart.addr()) {
1209            return Err(Error::corruption_detected);
1210        }
1211        match_0 = dictEnd.sub(prefixStart.addr() - match_0.addr());
1212        if match_0.add(sequence.matchLength) <= dictEnd {
1213            core::ptr::copy(match_0, oLitEnd, sequence.matchLength);
1214            return Ok(sequenceLength);
1215        }
1216        /* span extDict & currentPrefixSegment */
1217        let length1 = dictEnd.addr() - match_0.addr();
1218        core::ptr::copy(match_0, oLitEnd, length1);
1219        op = oLitEnd.add(length1);
1220        sequence.matchLength = (sequence.matchLength).wrapping_sub(length1);
1221        match_0 = prefixStart;
1222    }
1223    ZSTD_safecopy(
1224        op,
1225        oend_w,
1226        match_0,
1227        sequence.matchLength,
1228        Overlap::OverlapSrcBeforeDst,
1229    );
1230    Ok(sequenceLength)
1231}
1232
1233/// This version is intended to be used during instances where the litBuffer is still split.
1234/// It is kept separate to avoid performance impact for the good case.
1235#[inline(never)]
1236unsafe fn ZSTD_execSequenceEndSplitLitBuffer(
1237    mut op: Writer<'_>,
1238    oend: *mut u8,
1239    oend_w: *const u8,
1240    mut sequence: seq_t,
1241    litPtr: &mut *const u8,
1242    litLimit: *const u8,
1243    prefixStart: *const u8,
1244    virtualStart: *const u8,
1245    dictEnd: *const u8,
1246) -> Result<size_t, Error> {
1247    let oLitEnd = op.as_mut_ptr().add(sequence.litLength);
1248    let sequenceLength = (sequence.litLength).wrapping_add(sequence.matchLength);
1249    let iLitEnd = (*litPtr).add(sequence.litLength);
1250    let mut match_0: *const u8 = oLitEnd.sub(sequence.offset);
1251
1252    /* bounds checks : careful of address space overflow in 32-bit mode */
1253    if sequenceLength > oend.offset_from_unsigned(op.as_mut_ptr()) {
1254        return Err(Error::dstSize_tooSmall);
1255    }
1256    if sequence.litLength > litLimit.offset_from_unsigned(*litPtr) {
1257        return Err(Error::corruption_detected);
1258    }
1259
1260    debug_assert!(op.as_mut_ptr() < op.as_mut_ptr().wrapping_add(sequenceLength));
1261    debug_assert!(oLitEnd < op.as_mut_ptr().wrapping_add(sequenceLength));
1262
1263    /* copy literals */
1264    if op.as_mut_ptr() > *litPtr as *mut u8
1265        && op.as_mut_ptr() < (*litPtr).add(sequence.litLength) as *mut u8
1266    {
1267        return Err(Error::dstSize_tooSmall);
1268    }
1269    ZSTD_safecopyDstBeforeSrc(op.as_mut_ptr(), *litPtr, sequence.litLength);
1270    op = op.subslice(sequence.litLength..);
1271    *litPtr = iLitEnd;
1272
1273    /* copy Match */
1274    if sequence.offset > oLitEnd.offset_from_unsigned(prefixStart) {
1275        /* offset beyond prefix */
1276        if sequence.offset > oLitEnd.offset_from_unsigned(virtualStart) {
1277            return Err(Error::corruption_detected);
1278        }
1279        match_0 = dictEnd.offset(-(prefixStart.offset_from(match_0) as core::ffi::c_long as isize));
1280        if match_0.add(sequence.matchLength) <= dictEnd {
1281            core::ptr::copy(match_0, oLitEnd, sequence.matchLength);
1282            return Ok(sequenceLength);
1283        }
1284
1285        /* span extDict & currentPrefixSegment */
1286        let length1 = dictEnd.offset_from_unsigned(match_0);
1287        core::ptr::copy(match_0, oLitEnd, length1);
1288        op = op.subslice(length1..);
1289        sequence.matchLength = (sequence.matchLength).wrapping_sub(length1);
1290        match_0 = prefixStart;
1291    }
1292
1293    ZSTD_safecopy(
1294        op.as_mut_ptr(),
1295        oend_w,
1296        match_0,
1297        sequence.matchLength,
1298        Overlap::OverlapSrcBeforeDst,
1299    );
1300    Ok(sequenceLength)
1301}
1302
1303#[inline(always)]
1304unsafe fn ZSTD_execSequence(
1305    mut op: Writer<'_>,
1306    oend: *mut u8,
1307    mut sequence: seq_t,
1308    litPtr: &mut *const u8,
1309    litLimit: *const u8,
1310    prefixStart: *const u8,
1311    virtualStart: *const u8,
1312    dictEnd: *const u8,
1313) -> Result<size_t, Error> {
1314    let mut op = op.as_mut_ptr();
1315    let oLitEnd = op.add(sequence.litLength);
1316    let sequenceLength = (sequence.litLength).wrapping_add(sequence.matchLength);
1317    let oMatchEnd = op.add(sequenceLength);
1318    let oend_w = oend.wrapping_sub(WILDCOPY_OVERLENGTH);
1319    let iLitEnd = (*litPtr).add(sequence.litLength);
1320    let mut match_0: *const u8 = oLitEnd.wrapping_sub(sequence.offset);
1321
1322    debug_assert!(!op.is_null(), "Precondition");
1323    debug_assert!(oend_w < oend, "No underflow");
1324
1325    if cfg!(target_arch = "aarch64") {
1326        // prefetch sequence starting from match that will be used for copy later.
1327        prefetch_read_data(match_0, Locality::L1);
1328    }
1329
1330    // Handle edge cases in a slow path:
1331    //   - Read beyond end of literals
1332    //   - Match end is within WILDCOPY_OVERLIMIT of oend
1333    //   - 32-bit mode and the match length overflows
1334    if unlikely(
1335        iLitEnd > litLimit
1336            || oMatchEnd > oend_w
1337            || MEM_32bits() && (oend.offset_from_unsigned(op)) < sequenceLength.wrapping_add(32),
1338    ) {
1339        return ZSTD_execSequenceEnd(
1340            op,
1341            oend,
1342            sequence,
1343            litPtr,
1344            litLimit,
1345            prefixStart,
1346            virtualStart,
1347            dictEnd,
1348        );
1349    }
1350
1351    /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */
1352    debug_assert!(op <= oLitEnd, "No overflow");
1353    debug_assert!(oLitEnd < oMatchEnd, "Non-zero match & no overflow");
1354    debug_assert!(oMatchEnd <= oend, "No underflow");
1355    debug_assert!(iLitEnd <= litLimit, "Literal length is in bounds");
1356    debug_assert!(oLitEnd <= oend_w, "Can wildcopy literals");
1357    debug_assert!(oMatchEnd <= oend_w, "Can wildcopy matches");
1358
1359    // Copy Literals:
1360    // Split out litLength <= 16 since it is nearly always true. +1.6% on gcc-9.
1361    // We likely don't need the full 32-byte wildcopy.
1362    const _: () = assert!(WILDCOPY_OVERLENGTH >= 16);
1363    ZSTD_copy16(op, *litPtr);
1364    if unlikely(sequence.litLength > 16) {
1365        ZSTD_wildcopy(
1366            op.add(16),
1367            (*litPtr).add(16),
1368            sequence.litLength.wrapping_sub(16),
1369            Overlap::NoOverlap,
1370        );
1371    }
1372    op = oLitEnd;
1373    *litPtr = iLitEnd; // Update for next sequence.
1374
1375    // Copy match.
1376    if unlikely(sequence.offset > oLitEnd.offset_from_unsigned(prefixStart)) {
1377        // offset beyond prefix -> go into extDict.
1378        if unlikely(sequence.offset > (oLitEnd.addr() - virtualStart.addr())) {
1379            return Err(Error::corruption_detected);
1380        }
1381        match_0 = dictEnd.offset(match_0.addr() as isize - prefixStart.addr() as isize);
1382        if match_0.add(sequence.matchLength) <= dictEnd {
1383            core::ptr::copy(match_0, oLitEnd, sequence.matchLength);
1384            return Ok(sequenceLength);
1385        }
1386
1387        // span extDict & currentPrefixSegment.
1388        let length1 = dictEnd.offset_from_unsigned(match_0);
1389        core::ptr::copy(match_0, oLitEnd, length1);
1390        op = oLitEnd.add(length1);
1391        sequence.matchLength = (sequence.matchLength).wrapping_sub(length1);
1392        match_0 = prefixStart;
1393    }
1394
1395    /* Match within prefix of 1 or more bytes */
1396    debug_assert!(op <= oMatchEnd);
1397    debug_assert!(oMatchEnd <= oend_w);
1398    debug_assert!(match_0 >= prefixStart);
1399    debug_assert!(sequence.matchLength >= 1);
1400
1401    // Nearly all offsets are >= WILDCOPY_VECLEN bytes, which means we can use wildcopy
1402    // without overlap checking.
1403    if likely(sequence.offset >= 16) {
1404        // We bet on a full wildcopy for matches, since we expect matches to be
1405        // longer than literals (in general). In silesia, ~10% of matches are longer
1406        // than 16 bytes.
1407        ZSTD_wildcopy(op, match_0, sequence.matchLength, Overlap::NoOverlap);
1408        return Ok(sequenceLength);
1409    }
1410    debug_assert!(sequence.offset < WILDCOPY_VECLEN as usize);
1411
1412    // Copy 8 bytes and spread the offset to be >= 8.
1413    ZSTD_overlapCopy8(&mut op, &mut match_0, sequence.offset);
1414
1415    // If the match length is > 8 bytes, then continue with the wildcopy.
1416    if sequence.matchLength > 8 {
1417        ZSTD_wildcopy(
1418            op,
1419            match_0,
1420            (sequence.matchLength).wrapping_sub(8),
1421            Overlap::OverlapSrcBeforeDst,
1422        );
1423    }
1424    Ok(sequenceLength)
1425}
1426
1427#[inline(always)]
1428unsafe fn ZSTD_execSequenceSplitLitBuffer(
1429    mut op: Writer<'_>,
1430    oend: *mut u8,
1431    oend_w: *const u8,
1432    mut sequence: seq_t,
1433    litPtr: &mut *const u8,
1434    litLimit: *const u8,
1435    prefixStart: *const u8,
1436    virtualStart: *const u8,
1437    dictEnd: *const u8,
1438) -> Result<size_t, Error> {
1439    let oLitEnd = op.as_mut_ptr().add(sequence.litLength);
1440    let sequenceLength = (sequence.litLength).wrapping_add(sequence.matchLength);
1441    let oMatchEnd = op.as_mut_ptr().add(sequenceLength);
1442    let iLitEnd = (*litPtr).add(sequence.litLength);
1443    let mut match_0: *const u8 = oLitEnd.sub(sequence.offset);
1444
1445    debug_assert!(!op.is_null(), "precondition");
1446    debug_assert!(oend_w < oend, "No underflow");
1447
1448    // Handle edge cases in a slow path:
1449    //   - Read beyond end of literals
1450    //   - Match end is within WILDCOPY_OVERLIMIT of oend
1451    //   - 32-bit mode and the match length overflows
1452    if unlikely(
1453        iLitEnd > litLimit
1454            || oMatchEnd > oend_w as *mut u8
1455            || MEM_32bits()
1456                && (oend.offset_from_unsigned(op.as_mut_ptr())) < sequenceLength.wrapping_add(32),
1457    ) {
1458        return ZSTD_execSequenceEndSplitLitBuffer(
1459            op,
1460            oend,
1461            oend_w,
1462            sequence,
1463            litPtr,
1464            litLimit,
1465            prefixStart,
1466            virtualStart,
1467            dictEnd,
1468        );
1469    }
1470
1471    // Assumptions (everything else goes into ZSTD_execSequenceEnd())
1472    debug_assert!(op.as_mut_ptr() <= oLitEnd, "No overflow");
1473    debug_assert!(oLitEnd < oMatchEnd, "Non-zero match & no overflow");
1474    debug_assert!(oMatchEnd <= oend, "No underflow");
1475    debug_assert!(iLitEnd <= litLimit, "Literal length is in bounds");
1476    debug_assert!(oLitEnd <= oend_w.cast_mut(), "Can wildcopy literals");
1477    debug_assert!(oMatchEnd <= oend_w.cast_mut(), "Can wildcopy matches");
1478
1479    // Copy Literals:
1480    // Split out litLength <= 16 since it is nearly always true. +1.6% on gcc-9.
1481    // We likely don't need the full 32-byte wildcopy.
1482    const _: () = assert!(WILDCOPY_OVERLENGTH >= 16);
1483    ZSTD_copy16(op.as_mut_ptr(), *litPtr);
1484    if unlikely(sequence.litLength > 16) {
1485        ZSTD_wildcopy(
1486            op.as_mut_ptr().add(16),
1487            (*litPtr).add(16),
1488            (sequence.litLength).wrapping_sub(16),
1489            Overlap::NoOverlap,
1490        );
1491    }
1492    op = op.subslice(sequence.litLength..);
1493    *litPtr = iLitEnd; // Update for the next sequence.
1494
1495    // Copy Match
1496    if unlikely(sequence.offset > oLitEnd.offset_from_unsigned(prefixStart)) {
1497        if sequence.offset > oLitEnd.offset_from_unsigned(virtualStart) {
1498            return Err(Error::corruption_detected);
1499        }
1500        match_0 = dictEnd.offset(match_0.offset_from(prefixStart) as core::ffi::c_long as isize);
1501        if match_0.add(sequence.matchLength) <= dictEnd {
1502            core::ptr::copy(match_0, oLitEnd, sequence.matchLength);
1503            return Ok(sequenceLength);
1504        }
1505
1506        /* span extDict & currentPrefixSegment */
1507        let length1 = dictEnd.offset_from_unsigned(match_0);
1508        core::ptr::copy(match_0, oLitEnd, length1);
1509        op = op.subslice(length1..);
1510        sequence.matchLength = (sequence.matchLength).wrapping_sub(length1);
1511        match_0 = prefixStart;
1512    }
1513
1514    /* Match within prefix of 1 or more bytes */
1515    debug_assert!(op.as_mut_ptr() <= oMatchEnd);
1516    debug_assert!(oMatchEnd <= oend_w.cast_mut());
1517    debug_assert!(match_0 >= prefixStart);
1518    debug_assert!(sequence.matchLength >= 1);
1519
1520    if likely(sequence.offset >= WILDCOPY_VECLEN as usize) {
1521        // We bet on a full wildcopy for matches, since we expect matches to be
1522        // longer than literals (in general). In silesia, ~10% of matches are longer
1523        // than 16 bytes.
1524        ZSTD_wildcopy(
1525            op.as_mut_ptr(),
1526            match_0,
1527            sequence.matchLength,
1528            Overlap::NoOverlap,
1529        );
1530        return Ok(sequenceLength);
1531    }
1532    debug_assert!(sequence.offset < WILDCOPY_VECLEN as usize);
1533
1534    // Copy 8 bytes and spread the offset to be >= 8.
1535    ZSTD_overlapCopy8(&mut op.as_mut_ptr(), &mut match_0, sequence.offset);
1536    op = op.subslice(8..);
1537
1538    // If the match length is > 8 bytes, then continue with the wildcopy.
1539    if sequence.matchLength > 8 {
1540        ZSTD_wildcopy(
1541            op.as_mut_ptr(),
1542            match_0,
1543            sequence.matchLength.wrapping_sub(8),
1544            Overlap::OverlapSrcBeforeDst,
1545        );
1546    }
1547    Ok(sequenceLength)
1548}
1549
1550impl ZSTD_fseState<'_> {
1551    #[inline(always)]
1552    fn update_with_d_info(&mut self, bitD: &mut BIT_DStream_t, nextState: u16, nbBits: u32) {
1553        let lowBits = bitD.read_bits(nbBits);
1554        self.state = usize::from(nextState) + lowBits;
1555    }
1556}
1557
1558/// We need to add at most `(ZSTD_WINDOWLOG_MAX_32 - 1)` bits to read the maximum
1559/// offset bits. But we can only read at most [`STREAM_ACCUMULATOR_MIN_32`]
1560/// bits before reloading. This value is the maximum number of bytes we read
1561/// after reloading when we are decoding long offsets.
1562const LONG_OFFSETS_MAX_EXTRA_BITS_32: i32 =
1563    ZSTD_WINDOWLOG_MAX_32.saturating_sub(STREAM_ACCUMULATOR_MIN_32);
1564
1565#[inline(always)]
1566fn ZSTD_decodeSequence(
1567    seqState: &mut seqState_t,
1568    longOffsets: Offset,
1569    is_last_sequence: bool,
1570) -> seq_t {
1571    let mut seq = seq_t {
1572        litLength: 0,
1573        matchLength: 0,
1574        offset: 0,
1575    };
1576    cfg_select! {
1577        feature = "unsafe-performance-experimental" => {
1578            let llDInfo = unsafe { seqState.stateLL.table.get_unchecked(seqState.stateLL.state) };
1579            let mlDInfo = unsafe { seqState.stateML.table.get_unchecked(seqState.stateML.state) };
1580            let ofDInfo = unsafe {
1581                seqState
1582                    .stateOffb
1583                    .table
1584                    .get_unchecked(seqState.stateOffb.state)
1585            };
1586        }
1587        _ => {
1588            let llDInfo = seqState.stateLL.table[seqState.stateLL.state];
1589            let mlDInfo = seqState.stateML.table[seqState.stateML.state];
1590            let ofDInfo = seqState.stateOffb.table[seqState.stateOffb.state];
1591        }
1592    }
1593
1594    seq.matchLength = mlDInfo.baseValue as size_t;
1595    seq.litLength = llDInfo.baseValue as size_t;
1596    let ofBase = ofDInfo.baseValue;
1597
1598    let llBits = llDInfo.nbAdditionalBits;
1599    let mlBits = mlDInfo.nbAdditionalBits;
1600    let ofBits = ofDInfo.nbAdditionalBits;
1601
1602    let totalBits = llBits + mlBits + ofBits;
1603
1604    let llNext = llDInfo.nextState;
1605    let mlNext = mlDInfo.nextState;
1606    let ofNext = ofDInfo.nextState;
1607
1608    let llnbBits = llDInfo.nbBits as u32;
1609    let mlnbBits = mlDInfo.nbBits as u32;
1610    let ofnbBits = ofDInfo.nbBits as u32;
1611
1612    debug_assert!(llBits <= MaxLLBits);
1613    debug_assert!(mlBits <= MaxMLBits);
1614
1615    // NOTE: experimentally this assert provides valuable information for downstream optimizations.
1616    // it is deliberately not a debug_assert!.
1617    assert!(ofBits as u32 <= MaxOff);
1618
1619    let mut offset: size_t = 0;
1620    if ofBits > 1 {
1621        const { assert!(Offset::Long as usize == 1) };
1622        const { assert!(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5) };
1623        const { assert!(STREAM_ACCUMULATOR_MIN_32 > LONG_OFFSETS_MAX_EXTRA_BITS_32) };
1624        const { assert!(STREAM_ACCUMULATOR_MIN_32 - LONG_OFFSETS_MAX_EXTRA_BITS_32 >= MaxMLBits as i32) };
1625
1626        if MEM_32bits()
1627            && longOffsets != Offset::Regular
1628            && i32::from(ofBits) >= STREAM_ACCUMULATOR_MIN_32
1629        {
1630            // Always read extra bits, this keeps the logic simple,
1631            // avoids branches, and avoids accidentally reading 0 bits.
1632            let extraBits = LONG_OFFSETS_MAX_EXTRA_BITS_32 as u32;
1633            offset = (ofBase as size_t).wrapping_add(
1634                (seqState
1635                    .DStream
1636                    .read_bits_fast(u32::from(ofBits) - extraBits) as size_t)
1637                    << extraBits,
1638            );
1639            seqState.DStream.reload();
1640            offset = offset.wrapping_add(seqState.DStream.read_bits_fast(extraBits) as size_t);
1641        } else {
1642            offset = (ofBase as size_t)
1643                .wrapping_add(seqState.DStream.read_bits_fast(u32::from(ofBits)) as size_t);
1644            if MEM_32bits() {
1645                seqState.DStream.reload();
1646            }
1647        }
1648
1649        seqState.prevOffset[2] = seqState.prevOffset[1];
1650        seqState.prevOffset[1] = seqState.prevOffset[0];
1651        seqState.prevOffset[0] = offset;
1652    } else {
1653        let ll0 = usize::from(llDInfo.baseValue == 0);
1654        if likely(ofBits == 0) {
1655            offset = seqState.prevOffset[ll0];
1656            seqState.prevOffset[1] = seqState.prevOffset[usize::from(ll0 == 0)];
1657            seqState.prevOffset[0] = offset;
1658        } else {
1659            offset = (ofBase.wrapping_add(ll0 as u32) as size_t)
1660                .wrapping_add(seqState.DStream.read_bits_fast(1) as size_t);
1661
1662            let mut temp = match offset {
1663                3 => seqState.prevOffset[0] - 1,
1664                _ => seqState.prevOffset[offset as usize],
1665            };
1666            temp = temp.wrapping_sub((temp == 0) as _); /* 0 is not valid: input corrupted => force offset to -1 => corruption detected at execSequence */
1667
1668            if offset != 1 {
1669                seqState.prevOffset[2] = seqState.prevOffset[1];
1670            }
1671            seqState.prevOffset[1] = seqState.prevOffset[0];
1672            seqState.prevOffset[0] = temp;
1673            offset = temp;
1674        }
1675    }
1676    seq.offset = offset;
1677
1678    if mlBits > 0 {
1679        seq.matchLength = seq
1680            .matchLength
1681            .wrapping_add(seqState.DStream.read_bits_fast(mlBits as core::ffi::c_uint) as size_t);
1682    }
1683
1684    if cfg!(target_pointer_width = "32")
1685        && (i32::from(mlBits + llBits)
1686            >= STREAM_ACCUMULATOR_MIN_32 - LONG_OFFSETS_MAX_EXTRA_BITS_32)
1687    {
1688        seqState.DStream.reload();
1689    }
1690    if cfg!(target_pointer_width = "64") && unlikely(totalBits >= 57 - (9 + 9 + 8)) {
1691        seqState.DStream.reload();
1692    }
1693
1694    // Ensure there are enough bits to read the rest of data in 64-bit mode.
1695    const { assert!(16 + LLFSELog + MLFSELog + OffFSELog < STREAM_ACCUMULATOR_MIN_64 as u32) };
1696
1697    if llBits > 0 {
1698        seq.litLength = (seq.litLength)
1699            .wrapping_add(seqState.DStream.read_bits_fast(llBits as core::ffi::c_uint) as size_t);
1700    }
1701    if MEM_32bits() {
1702        seqState.DStream.reload();
1703    }
1704
1705    // Don't update FSE state for last Sequence.
1706    if !is_last_sequence {
1707        seqState
1708            .stateLL
1709            .update_with_d_info(&mut seqState.DStream, llNext, llnbBits);
1710        seqState
1711            .stateML
1712            .update_with_d_info(&mut seqState.DStream, mlNext, mlnbBits);
1713        if MEM_32bits() {
1714            seqState.DStream.reload();
1715        }
1716        seqState
1717            .stateOffb
1718            .update_with_d_info(&mut seqState.DStream, ofNext, ofnbBits);
1719        seqState.DStream.reload();
1720    }
1721
1722    seq
1723}
1724
1725#[inline(always)]
1726fn ZSTD_decompressSequences_bodySplitLitBuffer(
1727    dctx: &mut ZSTD_DCtx,
1728    dst: Writer<'_>,
1729    seq: &[u8],
1730    mut nbSeq: core::ffi::c_int,
1731    offset: Offset,
1732) -> Result<size_t, Error> {
1733    let maxDstSize = dst.capacity();
1734    let mut op = dst;
1735    let mut litPtr = dctx.litPtr;
1736    let mut litBufferEnd = dctx.litBufferEnd;
1737    let prefixStart = dctx.prefixStart as *const u8;
1738    let vBase = dctx.virtualStart as *const u8;
1739    let dictEnd = dctx.dictEnd as *const u8;
1740    if nbSeq != 0 {
1741        let DStream = BIT_DStream_t::new(seq).map_err(|_| Error::corruption_detected)?;
1742        dctx.fseEntropy = true;
1743        let mut seqState = dctx.new_seq_state(DStream);
1744
1745        let mut sequence = seq_t::default();
1746
1747        #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1748        if !cfg!(miri) {
1749            unsafe { asm!(".p2align 6", options(preserves_flags, att_syntax)) }
1750        }
1751
1752        while nbSeq != 0 {
1753            sequence = ZSTD_decodeSequence(&mut seqState, offset, nbSeq == 1);
1754
1755            if litPtr.wrapping_add(sequence.litLength) > dctx.litBufferEnd {
1756                break;
1757            }
1758
1759            let oneSeqSize = unsafe {
1760                ZSTD_execSequenceSplitLitBuffer(
1761                    op.subslice(..),
1762                    op.as_mut_ptr_range().end,
1763                    litPtr.add(sequence.litLength).sub(WILDCOPY_OVERLENGTH),
1764                    sequence,
1765                    &mut litPtr,
1766                    litBufferEnd,
1767                    prefixStart,
1768                    vBase,
1769                    dictEnd,
1770                )?
1771            };
1772
1773            op = op.subslice(oneSeqSize..);
1774            nbSeq -= 1;
1775        }
1776
1777        if nbSeq > 0 {
1778            let leftoverLit = unsafe { dctx.litBufferEnd.offset_from_unsigned(litPtr) };
1779            if leftoverLit != 0 {
1780                if leftoverLit > op.capacity() {
1781                    return Err(Error::dstSize_tooSmall);
1782                }
1783                unsafe { ZSTD_safecopyDstBeforeSrc(op.as_mut_ptr(), litPtr, leftoverLit) };
1784                sequence.litLength = sequence.litLength.wrapping_sub(leftoverLit);
1785                op = op.subslice(leftoverLit..);
1786            }
1787            litPtr = dctx.litExtraBuffer.as_mut_ptr();
1788            litBufferEnd = dctx.litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE..].as_mut_ptr();
1789            dctx.litBufferLocation = LitLocation::ZSTD_not_in_dst;
1790            let oneSeqSize_0 = unsafe {
1791                ZSTD_execSequence(
1792                    op.subslice(..),
1793                    op.as_mut_ptr_range().end,
1794                    sequence,
1795                    &mut litPtr,
1796                    litBufferEnd,
1797                    prefixStart,
1798                    vBase,
1799                    dictEnd,
1800                )?
1801            };
1802            op = op.subslice(oneSeqSize_0..);
1803            nbSeq -= 1;
1804        }
1805        if nbSeq > 0 {
1806            #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1807            if !cfg!(miri) {
1808                unsafe {
1809                    asm!(
1810                        ".p2align 6",
1811                        "nop",
1812                        ".p2align 4",
1813                        "nop",
1814                        ".p2align 3",
1815                        options(preserves_flags)
1816                    )
1817                }
1818            }
1819
1820            while nbSeq != 0 {
1821                let sequence_0 = ZSTD_decodeSequence(&mut seqState, offset, nbSeq == 1);
1822                let oneSeqSize_1 = unsafe {
1823                    ZSTD_execSequence(
1824                        op.subslice(..),
1825                        op.as_mut_ptr_range().end,
1826                        sequence_0,
1827                        &mut litPtr,
1828                        litBufferEnd,
1829                        prefixStart,
1830                        vBase,
1831                        dictEnd,
1832                    )?
1833                };
1834                op = op.subslice(oneSeqSize_1..);
1835                nbSeq -= 1;
1836            }
1837        }
1838        if nbSeq != 0 {
1839            return Err(Error::corruption_detected);
1840        }
1841        if !seqState.DStream.is_empty() {
1842            return Err(Error::corruption_detected);
1843        }
1844
1845        dctx.entropy.rep = seqState.prevOffset.map(|v| v as u32);
1846    }
1847
1848    if dctx.litBufferLocation == LitLocation::ZSTD_split {
1849        let lastLLSize = unsafe { litBufferEnd.offset_from_unsigned(litPtr) };
1850        if lastLLSize > op.capacity() {
1851            return Err(Error::dstSize_tooSmall);
1852        }
1853        if !op.is_null() {
1854            unsafe { core::ptr::copy(litPtr, op.as_mut_ptr(), lastLLSize) };
1855            op = op.subslice(lastLLSize..);
1856        }
1857        litPtr = (dctx.litExtraBuffer).as_mut_ptr();
1858        litBufferEnd = dctx.litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE..].as_mut_ptr();
1859        dctx.litBufferLocation = LitLocation::ZSTD_not_in_dst;
1860    }
1861
1862    let lastLLSize_0 = unsafe { litBufferEnd.offset_from_unsigned(litPtr) };
1863    if lastLLSize_0 > op.capacity() {
1864        return Err(Error::dstSize_tooSmall);
1865    }
1866
1867    if !op.is_null() {
1868        unsafe { core::ptr::copy_nonoverlapping(litPtr, op.as_mut_ptr(), lastLLSize_0) };
1869        op = op.subslice(lastLLSize_0..);
1870    }
1871
1872    Ok(maxDstSize - op.capacity())
1873}
1874
1875#[inline(always)]
1876unsafe fn ZSTD_decompressSequences_body(
1877    dctx: &mut ZSTD_DCtx,
1878    mut dst: Writer<'_>,
1879    seq: &[u8],
1880    nbSeq: core::ffi::c_int,
1881    offset: Offset,
1882) -> Result<size_t, Error> {
1883    let capacity = dst.capacity();
1884
1885    let oend = match dctx.litBufferLocation {
1886        LitLocation::ZSTD_not_in_dst => dst.as_mut_ptr_range().end,
1887        LitLocation::ZSTD_split | LitLocation::ZSTD_in_dst => dctx.litBuffer,
1888    };
1889
1890    let mut op = dst;
1891    let mut litPtr = dctx.litPtr;
1892    let litEnd = litPtr.add(dctx.litSize);
1893    let prefixStart = dctx.prefixStart as *const u8;
1894    let vBase = dctx.virtualStart as *const u8;
1895    let dictEnd = dctx.dictEnd as *const u8;
1896    if nbSeq != 0 {
1897        let DStream = BIT_DStream_t::new(seq).map_err(|_| Error::corruption_detected)?;
1898        dctx.fseEntropy = true;
1899        let mut seqState = dctx.new_seq_state(DStream);
1900
1901        #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1902        if !cfg!(miri) {
1903            asm!(".p2align 6", options(preserves_flags, att_syntax));
1904            asm!("nop", options(preserves_flags, att_syntax));
1905            asm!(".p2align 4", options(preserves_flags, att_syntax));
1906            asm!("nop", options(preserves_flags, att_syntax));
1907            asm!(".p2align 3", options(preserves_flags, att_syntax));
1908        }
1909
1910        for i in 0..nbSeq {
1911            let is_last = i == nbSeq - 1;
1912            let sequence = ZSTD_decodeSequence(&mut seqState, offset, is_last);
1913            let oneSeqSize = ZSTD_execSequence(
1914                op.subslice(..),
1915                oend,
1916                sequence,
1917                &mut litPtr,
1918                litEnd,
1919                prefixStart,
1920                vBase,
1921                dictEnd,
1922            )?;
1923
1924            op = op.subslice(oneSeqSize..);
1925        }
1926
1927        if !seqState.DStream.is_empty() {
1928            return Err(Error::corruption_detected);
1929        }
1930
1931        dctx.entropy.rep = seqState.prevOffset.map(|v| v as u32);
1932    }
1933
1934    let lastLLSize = litEnd.offset_from_unsigned(litPtr);
1935    if lastLLSize > oend.offset_from(op.as_mut_ptr()) as size_t {
1936        return Err(Error::dstSize_tooSmall);
1937    }
1938
1939    if !op.is_null() {
1940        core::ptr::copy_nonoverlapping(litPtr, op.as_mut_ptr(), lastLLSize);
1941        op = op.subslice(lastLLSize..);
1942    }
1943
1944    Ok(capacity - op.capacity())
1945}
1946
1947fn ZSTD_decompressSequences_default(
1948    dctx: &mut ZSTD_DCtx,
1949    dst: Writer<'_>,
1950    seqStart: &[u8],
1951    nbSeq: core::ffi::c_int,
1952    offset: Offset,
1953) -> Result<size_t, Error> {
1954    unsafe { ZSTD_decompressSequences_body(dctx, dst, seqStart, nbSeq, offset) }
1955}
1956
1957fn ZSTD_decompressSequencesSplitLitBuffer_default(
1958    dctx: &mut ZSTD_DCtx,
1959    dst: Writer<'_>,
1960    seqStart: &[u8],
1961    nbSeq: core::ffi::c_int,
1962    offset: Offset,
1963) -> Result<size_t, Error> {
1964    ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, seqStart, nbSeq, offset)
1965}
1966
1967#[inline(always)]
1968fn prefetch_area<T>(ptr: *const T, bytes: usize) {
1969    for pos in (0..bytes).step_by(CACHELINE_SIZE as size_t) {
1970        prefetch_read_data(ptr.wrapping_byte_add(pos), Locality::L2);
1971    }
1972}
1973
1974#[inline(always)]
1975fn prefetch_val<T>(ptr: *const T) {
1976    prefetch_area(ptr, size_of::<T>())
1977}
1978
1979#[inline(always)]
1980fn ZSTD_prefetchMatch(
1981    prefetchPos: size_t,
1982    sequence: seq_t,
1983    prefixStart: *const u8,
1984    dictEnd: *const u8,
1985) -> size_t {
1986    let matchBase = if sequence.offset > prefetchPos.wrapping_add(sequence.litLength) {
1987        dictEnd
1988    } else {
1989        prefixStart
1990    };
1991
1992    let match_ = matchBase
1993        .wrapping_add(prefetchPos)
1994        .wrapping_sub(sequence.offset);
1995
1996    prefetch_read_data(match_, Locality::L1);
1997    prefetch_read_data(match_.wrapping_add(64), Locality::L1);
1998
1999    prefetchPos.wrapping_add(sequence.matchLength)
2000}
2001
2002#[inline(always)]
2003unsafe fn ZSTD_decompressSequencesLong_body(
2004    dctx: &mut ZSTD_DCtx,
2005    mut dst: Writer<'_>,
2006    seq: &[u8],
2007    nbSeq: core::ffi::c_int,
2008    offset: Offset,
2009) -> Result<size_t, Error> {
2010    let dst_capacity = dst.capacity();
2011    let oend = if dctx.litBufferLocation == LitLocation::ZSTD_in_dst {
2012        dctx.litBuffer
2013    } else {
2014        dst.as_mut_ptr_range().end
2015    };
2016    let mut op = dst;
2017    let mut litPtr = dctx.litPtr;
2018    let mut litBufferEnd = dctx.litBufferEnd;
2019    let prefixStart = dctx.prefixStart as *const u8;
2020    let dictStart = dctx.virtualStart as *const u8;
2021    let dictEnd = dctx.dictEnd as *const u8;
2022    if nbSeq != 0 {
2023        let seqAdvance = if nbSeq < 8 { nbSeq } else { 8 };
2024        let DStream = BIT_DStream_t::new(seq).map_err(|_| Error::corruption_detected)?;
2025        dctx.fseEntropy = true;
2026        let mut seqState = dctx.new_seq_state(DStream);
2027
2028        let mut prefetchPos = op.as_mut_ptr().offset_from_unsigned(prefixStart);
2029        let mut sequences: [seq_t; 8] = [seq_t::default(); 8];
2030
2031        for seqNb in 0..seqAdvance {
2032            let sequence = ZSTD_decodeSequence(&mut seqState, offset, seqNb == nbSeq - 1);
2033            prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd);
2034            sequences[seqNb as usize] = sequence;
2035        }
2036
2037        for seqNb in seqAdvance..nbSeq {
2038            let sequence_0 = ZSTD_decodeSequence(&mut seqState, offset, seqNb == nbSeq - 1);
2039            if dctx.litBufferLocation == LitLocation::ZSTD_split
2040                && litPtr.add(
2041                    (sequences[((seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK) as usize]).litLength,
2042                ) > dctx.litBufferEnd
2043            {
2044                let leftoverLit = (dctx.litBufferEnd).offset_from_unsigned(litPtr);
2045                if leftoverLit != 0 {
2046                    if leftoverLit > oend.offset_from_unsigned(op.as_mut_ptr()) {
2047                        return Err(Error::dstSize_tooSmall);
2048                    }
2049                    ZSTD_safecopyDstBeforeSrc(op.as_mut_ptr(), litPtr, leftoverLit);
2050                    sequences[((seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK) as usize].litLength -=
2051                        leftoverLit;
2052                    op = op.subslice(leftoverLit..);
2053                }
2054                litPtr = (dctx.litExtraBuffer).as_mut_ptr();
2055                litBufferEnd = dctx.litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE..].as_mut_ptr();
2056                dctx.litBufferLocation = LitLocation::ZSTD_not_in_dst;
2057                let oneSeqSize = ZSTD_execSequence(
2058                    op.subslice(..),
2059                    oend,
2060                    sequences[((seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK) as usize],
2061                    &mut litPtr,
2062                    litBufferEnd,
2063                    prefixStart,
2064                    dictStart,
2065                    dictEnd,
2066                )?;
2067
2068                prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence_0, prefixStart, dictEnd);
2069                sequences[(seqNb & STORED_SEQS_MASK) as usize] = sequence_0;
2070                op = op.subslice(oneSeqSize..);
2071            } else {
2072                let sequence = sequences[((seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK) as usize];
2073                let oneSeqSize_0 = if dctx.litBufferLocation == LitLocation::ZSTD_split {
2074                    ZSTD_execSequenceSplitLitBuffer(
2075                        op.subslice(..),
2076                        oend,
2077                        litPtr.add(sequence.litLength).sub(WILDCOPY_OVERLENGTH),
2078                        sequences[((seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK) as usize],
2079                        &mut litPtr,
2080                        litBufferEnd,
2081                        prefixStart,
2082                        dictStart,
2083                        dictEnd,
2084                    )?
2085                } else {
2086                    ZSTD_execSequence(
2087                        op.subslice(..),
2088                        oend,
2089                        sequence,
2090                        &mut litPtr,
2091                        litBufferEnd,
2092                        prefixStart,
2093                        dictStart,
2094                        dictEnd,
2095                    )?
2096                };
2097
2098                prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence_0, prefixStart, dictEnd);
2099                sequences[(seqNb & STORED_SEQS_MASK) as usize] = sequence_0;
2100                op = op.subslice(oneSeqSize_0..);
2101            }
2102        }
2103
2104        if !seqState.DStream.is_empty() {
2105            return Err(Error::corruption_detected);
2106        }
2107
2108        for seqNb in nbSeq - seqAdvance..nbSeq {
2109            let sequence = &mut sequences[(seqNb & STORED_SEQS_MASK) as usize];
2110            if dctx.litBufferLocation == LitLocation::ZSTD_split
2111                && litPtr.add(sequence.litLength) > dctx.litBufferEnd
2112            {
2113                let leftoverLit_0 = (dctx.litBufferEnd).offset_from_unsigned(litPtr);
2114                if leftoverLit_0 != 0 {
2115                    if leftoverLit_0 > oend.offset_from_unsigned(op.as_mut_ptr()) {
2116                        return Err(Error::dstSize_tooSmall);
2117                    }
2118                    ZSTD_safecopyDstBeforeSrc(op.as_mut_ptr(), litPtr, leftoverLit_0);
2119                    sequence.litLength = (sequence.litLength).wrapping_sub(leftoverLit_0);
2120                    op = op.subslice(leftoverLit_0..);
2121                }
2122                litPtr = (dctx.litExtraBuffer).as_mut_ptr();
2123                litBufferEnd = dctx.litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE..].as_mut_ptr();
2124                dctx.litBufferLocation = LitLocation::ZSTD_not_in_dst;
2125                let oneSeqSize_1 = ZSTD_execSequence(
2126                    op.subslice(..),
2127                    oend,
2128                    *sequence,
2129                    &mut litPtr,
2130                    litBufferEnd,
2131                    prefixStart,
2132                    dictStart,
2133                    dictEnd,
2134                )?;
2135                op = op.subslice(oneSeqSize_1..);
2136            } else {
2137                let oneSeqSize_2 = if dctx.litBufferLocation == LitLocation::ZSTD_split {
2138                    ZSTD_execSequenceSplitLitBuffer(
2139                        op.subslice(..),
2140                        oend,
2141                        litPtr.add(sequence.litLength).sub(WILDCOPY_OVERLENGTH),
2142                        *sequence,
2143                        &mut litPtr,
2144                        litBufferEnd,
2145                        prefixStart,
2146                        dictStart,
2147                        dictEnd,
2148                    )?
2149                } else {
2150                    ZSTD_execSequence(
2151                        op.subslice(..),
2152                        oend,
2153                        *sequence,
2154                        &mut litPtr,
2155                        litBufferEnd,
2156                        prefixStart,
2157                        dictStart,
2158                        dictEnd,
2159                    )?
2160                };
2161
2162                op = op.subslice(oneSeqSize_2..);
2163            }
2164        }
2165
2166        dctx.entropy.rep = seqState.prevOffset.map(|v| v as u32);
2167    }
2168
2169    if dctx.litBufferLocation == LitLocation::ZSTD_split {
2170        let lastLLSize = litBufferEnd.offset_from_unsigned(litPtr);
2171        if lastLLSize > oend.offset_from_unsigned(op.as_mut_ptr()) {
2172            return Err(Error::dstSize_tooSmall);
2173        }
2174        if !op.is_null() {
2175            core::ptr::copy(litPtr, op.as_mut_ptr(), lastLLSize);
2176            op = op.subslice(lastLLSize..);
2177        }
2178        litPtr = (dctx.litExtraBuffer).as_mut_ptr();
2179        litBufferEnd = dctx.litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE..].as_mut_ptr();
2180    }
2181
2182    let lastLLSize_0 = litBufferEnd.offset_from_unsigned(litPtr);
2183    if lastLLSize_0 > oend.offset_from_unsigned(op.as_mut_ptr()) {
2184        return Err(Error::dstSize_tooSmall);
2185    }
2186
2187    if !op.is_null() {
2188        unsafe {
2189            core::ptr::copy(litPtr, op.as_mut_ptr(), lastLLSize_0);
2190        }
2191        op = op.subslice(lastLLSize_0..);
2192    }
2193
2194    Ok(dst_capacity - op.capacity())
2195}
2196
2197pub const STORED_SEQS: core::ffi::c_int = 8;
2198pub const STORED_SEQS_MASK: core::ffi::c_int = STORED_SEQS - 1;
2199pub const ADVANCED_SEQS: core::ffi::c_int = STORED_SEQS;
2200
2201fn ZSTD_decompressSequencesLong_default(
2202    dctx: &mut ZSTD_DCtx,
2203    dst: Writer<'_>,
2204    seqStart: &[u8],
2205    nbSeq: core::ffi::c_int,
2206    offset: Offset,
2207) -> Result<size_t, Error> {
2208    unsafe { ZSTD_decompressSequencesLong_body(dctx, dst, seqStart, nbSeq, offset) }
2209}
2210
2211#[cfg_attr(target_arch = "x86_64", target_feature(enable = "bmi2"))]
2212fn ZSTD_decompressSequences_bmi2(
2213    dctx: &mut ZSTD_DCtx,
2214    dst: Writer<'_>,
2215    seqStart: &[u8],
2216    nbSeq: core::ffi::c_int,
2217    offset: Offset,
2218) -> Result<size_t, Error> {
2219    unsafe { ZSTD_decompressSequences_body(dctx, dst, seqStart, nbSeq, offset) }
2220}
2221
2222#[cfg_attr(target_arch = "x86_64", target_feature(enable = "bmi2"))]
2223fn ZSTD_decompressSequencesSplitLitBuffer_bmi2(
2224    dctx: &mut ZSTD_DCtx,
2225    dst: Writer<'_>,
2226    seqStart: &[u8],
2227    nbSeq: core::ffi::c_int,
2228    offset: Offset,
2229) -> Result<size_t, Error> {
2230    ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, seqStart, nbSeq, offset)
2231}
2232
2233#[cfg_attr(target_arch = "x86_64", target_feature(enable = "bmi2"))]
2234fn ZSTD_decompressSequencesLong_bmi2(
2235    dctx: &mut ZSTD_DCtx,
2236    dst: Writer<'_>,
2237    seqStart: &[u8],
2238    nbSeq: core::ffi::c_int,
2239    offset: Offset,
2240) -> Result<size_t, Error> {
2241    unsafe { ZSTD_decompressSequencesLong_body(dctx, dst, seqStart, nbSeq, offset) }
2242}
2243
2244fn ZSTD_decompressSequences(
2245    dctx: &mut ZSTD_DCtx,
2246    dst: Writer<'_>,
2247    seqStart: &[u8],
2248    nbSeq: core::ffi::c_int,
2249    offset: Offset,
2250) -> Result<size_t, Error> {
2251    if dctx.bmi2 {
2252        unsafe { ZSTD_decompressSequences_bmi2(dctx, dst, seqStart, nbSeq, offset) }
2253    } else {
2254        ZSTD_decompressSequences_default(dctx, dst, seqStart, nbSeq, offset)
2255    }
2256}
2257
2258fn ZSTD_decompressSequencesSplitLitBuffer(
2259    dctx: &mut ZSTD_DCtx,
2260    dst: Writer<'_>,
2261    seqStart: &[u8],
2262    nbSeq: core::ffi::c_int,
2263    offset: Offset,
2264) -> Result<size_t, Error> {
2265    if dctx.bmi2 {
2266        unsafe { ZSTD_decompressSequencesSplitLitBuffer_bmi2(dctx, dst, seqStart, nbSeq, offset) }
2267    } else {
2268        ZSTD_decompressSequencesSplitLitBuffer_default(dctx, dst, seqStart, nbSeq, offset)
2269    }
2270}
2271
2272fn ZSTD_decompressSequencesLong(
2273    dctx: &mut ZSTD_DCtx,
2274    dst: Writer<'_>,
2275    seqStart: &[u8],
2276    nbSeq: core::ffi::c_int,
2277    offset: Offset,
2278) -> Result<size_t, Error> {
2279    if dctx.bmi2 {
2280        unsafe { ZSTD_decompressSequencesLong_bmi2(dctx, dst, seqStart, nbSeq, offset) }
2281    } else {
2282        ZSTD_decompressSequencesLong_default(dctx, dst, seqStart, nbSeq, offset)
2283    }
2284}
2285
2286impl<const N: usize> SymbolTable<N> {
2287    fn get_offset_info(&self, nbSeq: usize) -> ZSTD_OffsetInfo {
2288        let mut info = ZSTD_OffsetInfo::default();
2289
2290        if nbSeq == 0 {
2291            return info;
2292        }
2293
2294        let tableLog = self.header.tableLog;
2295        for seq_symbol in &self.symbols[..1 << tableLog] {
2296            info.maxNbAdditionalBits = Ord::max(
2297                info.maxNbAdditionalBits,
2298                u32::from(seq_symbol.nbAdditionalBits),
2299            );
2300
2301            if seq_symbol.nbAdditionalBits > 22 {
2302                info.longOffsetShare += 1;
2303            }
2304        }
2305        info.longOffsetShare <<= OffFSELog.wrapping_sub(tableLog);
2306
2307        info
2308    }
2309}
2310
2311/// @returns The maximum offset we can decode in one read of our bitstream, without
2312/// reloading more bits in the middle of the offset bits read. Any offsets larger
2313/// than this must use the long offset decoder.
2314const fn ZSTD_maxShortOffset() -> size_t {
2315    match size_of::<usize>() {
2316        4 => {
2317            // The maximum offBase is (1 << (STREAM_ACCUMULATOR_MIN + 1)) - 1.
2318            // This offBase would require STREAM_ACCUMULATOR_MIN extra bits.
2319            // Then we have to subtract ZSTD_REP_NUM to get the maximum possible offset.
2320            let maxOffbase = ((1 as size_t) << (STREAM_ACCUMULATOR_MIN as u32 + 1)).wrapping_sub(1);
2321
2322            maxOffbase.wrapping_sub(ZSTD_REP_NUM as size_t)
2323        }
2324        8 => {
2325            // We can decode any offset without reloading bits.
2326            // This might change if the max window size grows.
2327            const { assert!(ZSTD_WINDOWLOG_MAX <= 31) }
2328
2329            -(1 as core::ffi::c_int) as size_t
2330        }
2331        _ => unreachable!(),
2332    }
2333}
2334
2335pub(crate) fn ZSTD_decompressBlock_internal_help(
2336    dctx: &mut ZSTD_DCtx,
2337    mut dst: Writer<'_>,
2338    src: &[u8],
2339    streaming: StreamingOperation,
2340) -> Result<size_t, Error> {
2341    if src.len() > dctx.block_size_max() {
2342        return Err(Error::srcSize_wrong);
2343    }
2344
2345    let litCSize = ZSTD_decodeLiteralsBlock(dctx, src, dst.subslice(..), streaming)?;
2346
2347    let mut ip = &src[litCSize..];
2348
2349    let blockSizeMax = Ord::min(dst.capacity(), dctx.block_size_max());
2350    let totalHistorySize =
2351        dst.as_mut_ptr().wrapping_add(blockSizeMax) as usize - dctx.virtualStart as usize;
2352    let mut offset = if MEM_32bits() && totalHistorySize > ZSTD_maxShortOffset() {
2353        Offset::Long
2354    } else {
2355        Offset::Regular
2356    };
2357    let mut use_prefetch_decoder = dctx.ddictIsCold;
2358    let mut nbSeq = 0;
2359    let seqHSize = ZSTD_decodeSeqHeaders(dctx, &mut nbSeq, ip)?;
2360    ip = &ip[seqHSize..];
2361    if dst.is_empty() && nbSeq > 0 {
2362        return Err(Error::dstSize_tooSmall);
2363    }
2364    if size_of::<usize>() == 8
2365        && size_of::<size_t>() == size_of::<*mut core::ffi::c_void>()
2366        && (usize::MAX - dst.as_mut_ptr() as usize) < (1 << 20)
2367    {
2368        return Err(Error::dstSize_tooSmall);
2369    }
2370    if offset == Offset::Long
2371        || !use_prefetch_decoder && totalHistorySize > ((1) << 24) as size_t && nbSeq > 8
2372    {
2373        let info = match dctx.OFTptr {
2374            None => OF_defaultDTable.get_offset_info(nbSeq as usize),
2375            Some(table) => (unsafe { &*table.as_ptr() }).get_offset_info(nbSeq as usize),
2376        };
2377
2378        if offset == Offset::Long && info.maxNbAdditionalBits <= STREAM_ACCUMULATOR_MIN as u32 {
2379            offset = Offset::Regular;
2380        }
2381
2382        if !use_prefetch_decoder {
2383            let minShare = (if size_of::<usize>() == 8 { 7 } else { 20 }) as u32;
2384            use_prefetch_decoder = info.longOffsetShare >= minShare;
2385        }
2386    }
2387
2388    dctx.ddictIsCold = false;
2389
2390    if use_prefetch_decoder {
2391        ZSTD_decompressSequencesLong(dctx, dst.subslice(..), ip, nbSeq, offset)
2392    } else if dctx.litBufferLocation == LitLocation::ZSTD_split {
2393        ZSTD_decompressSequencesSplitLitBuffer(dctx, dst, ip, nbSeq, offset)
2394    } else {
2395        ZSTD_decompressSequences(dctx, dst, ip, nbSeq, offset)
2396    }
2397}
2398
2399pub fn ZSTD_checkContinuity(dctx: &mut ZSTD_DCtx, range: Range<*const u8>) {
2400    if range.start.cast() != dctx.previousDstEnd && !range.is_empty() {
2401        dctx.dictEnd = dctx.previousDstEnd;
2402        let delta = dctx.previousDstEnd.addr() - dctx.prefixStart.addr();
2403        dctx.virtualStart = range.start.wrapping_sub(delta).cast();
2404        dctx.prefixStart = range.start.cast();
2405        dctx.previousDstEnd = range.start.cast();
2406    }
2407}
2408
2409#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_decompressBlock))]
2410pub unsafe extern "C" fn ZSTD_decompressBlock(
2411    dctx: *mut ZSTD_DCtx,
2412    dst: *mut core::ffi::c_void,
2413    dstCapacity: size_t,
2414    src: *const core::ffi::c_void,
2415    srcSize: size_t,
2416) -> size_t {
2417    let dst = Writer::from_raw_parts(dst.cast::<u8>(), dstCapacity);
2418    let src = Reader::from_raw_parts(src.cast::<u8>(), srcSize);
2419
2420    let dctx: &mut ZSTD_DCtx = dctx.as_mut().unwrap();
2421    let mut dst = dst;
2422    dctx.isFrameDecompression = false;
2423
2424    ZSTD_checkContinuity(dctx, dst.as_ptr_range());
2425
2426    // FIXME: can src and dst overlap in this case?
2427    let dSize = ZSTD_decompressBlock_internal_help(
2428        dctx,
2429        dst.subslice(..),
2430        src.as_slice(),
2431        StreamingOperation::NotStreaming,
2432    )
2433    .unwrap_or_else(|err| err.to_error_code());
2434
2435    dctx.previousDstEnd = dst.as_ptr().byte_add(dSize).cast::<c_void>();
2436    dSize
2437}
2438
2439#[cfg(test)]
2440mod test {
2441    use crate::lib::zstd::*;
2442    use core::ffi::*;
2443
2444    #[test]
2445    fn basic_decompress() {
2446        rs(&[40, 181, 47, 253, 48, 21, 44, 0, 0, 0, 253, 49, 0, 21]);
2447    }
2448
2449    fn rs(compressed: &[u8]) -> (usize, Vec<u8>) {
2450        use crate::lib::decompress::zstd_decompress::*;
2451
2452        let compressed_ptr = compressed.as_ptr() as *const c_void;
2453        let compressed_size = compressed.len();
2454
2455        // Get decompressed size from frame header
2456        let decompressed_size =
2457            unsafe { ZSTD_getFrameContentSize(compressed_ptr, compressed_size) };
2458        if decompressed_size == ZSTD_CONTENTSIZE_ERROR {
2459            panic!("ZSTD_CONTENTSIZE_ERROR");
2460        } else if decompressed_size == ZSTD_CONTENTSIZE_UNKNOWN {
2461            panic!("ZSTD_CONTENTSIZE_UNKNOWN");
2462        }
2463
2464        // Allocate buffer for decompressed output
2465        let mut decompressed = vec![0u8; Ord::min(decompressed_size as usize, 1 << 20)];
2466        let result = unsafe {
2467            ZSTD_decompress(
2468                decompressed.as_mut_ptr() as *mut c_void,
2469                decompressed.len(),
2470                compressed_ptr,
2471                compressed_size,
2472            )
2473        };
2474
2475        (result as usize, decompressed)
2476    }
2477}