Skip to main content

libzstd_rs_sys/lib/decompress/
zstd_decompress_block.rs

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