Skip to main content

libzstd_rs_sys/lib/decompress/
zstd_decompress.rs

1use core::ptr;
2
3use libc::{calloc, free, malloc, size_t};
4
5use crate::lib::common::entropy_common::FSE_readNCount_slice;
6use crate::lib::common::error_private::{ERR_isError, Error};
7use crate::lib::common::mem::MEM_readLE32;
8use crate::lib::common::xxhash::{
9    ZSTD_XXH64_digest, ZSTD_XXH64_reset, ZSTD_XXH64_slice, ZSTD_XXH64_update,
10};
11use crate::lib::common::zstd_common::ZSTD_getErrorCode;
12use crate::lib::common::zstd_internal::{
13    repStartValue, LL_bits, ML_bits, MaxLL, MaxML, MaxOff, ZSTD_blockHeaderSize,
14    ZSTD_cpuSupportsBmi2, ZSTD_limitCopy, WILDCOPY_OVERLENGTH, ZSTD_FRAMEIDSIZE,
15    ZSTD_WORKSPACETOOLARGE_FACTOR, ZSTD_WORKSPACETOOLARGE_MAXDURATION,
16};
17use crate::lib::compress::zstd_compress::{ZSTD_CCtx_params_s, ZSTD_CCtx_s};
18use crate::lib::decompress::huf_decompress::{
19    DTableDesc, HUF_ReadDTableX2_Workspace, HUF_readDTableX2_wksp,
20};
21use crate::lib::decompress::zstd_ddict::{MultipleDDicts, ZSTD_DDict, ZSTD_DDictHashSet};
22use crate::lib::decompress::zstd_decompress_block::{
23    getc_block_size, ZSTD_buildFSETable, ZSTD_checkContinuity, ZSTD_decompressBlock_internal,
24    ZSTD_getcBlockSize,
25};
26use crate::lib::decompress::{
27    blockProperties_t, BlockType, DecompressStage, LL_base, ML_base, NextInputType, OF_base,
28    OF_bits, StreamStage, ZSTD_DCtx, ZSTD_DCtx_s, ZSTD_FrameHeader, ZSTD_d_ignoreChecksum,
29    ZSTD_d_validateChecksum, ZSTD_dont_use, ZSTD_entropyDTables_t, ZSTD_forceIgnoreChecksum_e,
30    ZSTD_frame, ZSTD_skippableFrame, ZSTD_use_indefinitely, ZSTD_use_once,
31};
32use crate::lib::zstd::experimental::ZSTD_FRAMEHEADERSIZE_MIN;
33use crate::lib::zstd::*;
34
35use crate::lib::common::zstd_trace::{
36    ZSTD_Trace, ZSTD_trace_decompress_begin, ZSTD_trace_decompress_end,
37};
38
39use crate::lib::legacy::zstd_v05::{
40    ZBUFFv05_DCtx, ZBUFFv05_createDCtx, ZBUFFv05_decompressContinue,
41    ZBUFFv05_decompressInitDictionary, ZBUFFv05_freeDCtx, ZSTDv05_createDCtx,
42    ZSTDv05_decompress_usingDict, ZSTDv05_fast, ZSTDv05_findFrameSizeInfoLegacy, ZSTDv05_freeDCtx,
43    ZSTDv05_getFrameParams, ZSTDv05_parameters,
44};
45use crate::lib::legacy::zstd_v06::{
46    ZBUFFv06_DCtx_s, ZBUFFv06_createDCtx, ZBUFFv06_decompressContinue,
47    ZBUFFv06_decompressInitDictionary, ZBUFFv06_freeDCtx, ZSTDv06_createDCtx,
48    ZSTDv06_decompress_usingDict, ZSTDv06_findFrameSizeInfoLegacy, ZSTDv06_frameParams_s,
49    ZSTDv06_freeDCtx, ZSTDv06_getFrameParams,
50};
51use crate::lib::legacy::zstd_v07::{
52    ZBUFFv07_DCtx_s, ZBUFFv07_createDCtx, ZBUFFv07_decompressContinue,
53    ZBUFFv07_decompressInitDictionary, ZBUFFv07_freeDCtx, ZSTDv07_createDCtx,
54    ZSTDv07_decompress_usingDict, ZSTDv07_findFrameSizeInfoLegacy, ZSTDv07_frameParams,
55    ZSTDv07_freeDCtx, ZSTDv07_getFrameParams,
56};
57
58use crate::lib::decompress::zstd_ddict::{
59    ZSTD_DDict_dictContent, ZSTD_DDict_dictSize, ZSTD_copyDDictParameters,
60    ZSTD_createDDict_advanced, ZSTD_freeDDict, ZSTD_getDictID_fromDDict, ZSTD_sizeof_DDict,
61};
62
63pub type ZSTD_outBuffer = ZSTD_outBuffer_s;
64#[repr(C)]
65pub struct ZSTD_cpuid_t {
66    pub f1c: u32,
67    pub f1d: u32,
68    pub f7b: u32,
69    pub f7c: u32,
70}
71type ZBUFFv07_DCtx = ZBUFFv07_DCtx_s;
72type ZBUFFv06_DCtx = ZBUFFv06_DCtx_s;
73type XXH_errorcode = core::ffi::c_uint;
74pub const XXH_ERROR: XXH_errorcode = 1;
75pub const XXH_OK: XXH_errorcode = 0;
76pub type streaming_operation = core::ffi::c_uint;
77pub const is_streaming: streaming_operation = 1;
78pub const not_streaming: streaming_operation = 0;
79#[repr(C)]
80pub struct ZSTD_frameSizeInfo {
81    pub nbBlocks: size_t,
82    pub compressedSize: size_t,
83    pub decompressedBound: core::ffi::c_ulonglong,
84}
85#[repr(C)]
86pub struct ZSTD_bounds {
87    pub error: size_t,
88    pub lowerBound: core::ffi::c_int,
89    pub upperBound: core::ffi::c_int,
90}
91pub type ZSTD_ResetDirective = core::ffi::c_uint;
92pub const ZSTD_reset_session_and_parameters: ZSTD_ResetDirective = 3;
93pub const ZSTD_reset_parameters: ZSTD_ResetDirective = 2;
94pub const ZSTD_reset_session_only: ZSTD_ResetDirective = 1;
95pub type ZSTD_dParameter = core::ffi::c_uint;
96pub const ZSTD_d_experimentalParam6: ZSTD_dParameter = 1005;
97pub const ZSTD_d_experimentalParam5: ZSTD_dParameter = 1004;
98pub const ZSTD_d_experimentalParam4: ZSTD_dParameter = 1003;
99pub const ZSTD_d_experimentalParam3: ZSTD_dParameter = 1002;
100pub const ZSTD_d_experimentalParam2: ZSTD_dParameter = 1001;
101pub const ZSTD_d_experimentalParam1: ZSTD_dParameter = 1000;
102pub const ZSTD_d_windowLogMax: ZSTD_dParameter = 100;
103pub type ZSTD_DStream = ZSTD_DCtx;
104pub type ZSTD_nextInputType_e = core::ffi::c_uint;
105pub const ZSTDnit_skippableFrame: ZSTD_nextInputType_e = 5;
106pub const ZSTDnit_checksum: ZSTD_nextInputType_e = 4;
107pub const ZSTDnit_lastBlock: ZSTD_nextInputType_e = 3;
108pub const ZSTDnit_block: ZSTD_nextInputType_e = 2;
109pub const ZSTDnit_blockHeader: ZSTD_nextInputType_e = 1;
110pub const ZSTDnit_frameHeader: ZSTD_nextInputType_e = 0;
111pub type ZSTD_dictContentType_e = core::ffi::c_uint;
112pub const ZSTD_dct_fullDict: ZSTD_dictContentType_e = 2;
113pub const ZSTD_dct_rawContent: ZSTD_dictContentType_e = 1;
114pub const ZSTD_dct_auto: ZSTD_dictContentType_e = 0;
115pub type ZSTD_dictLoadMethod_e = core::ffi::c_uint;
116pub const ZSTD_dlm_byRef: ZSTD_dictLoadMethod_e = 1;
117pub const ZSTD_dlm_byCopy: ZSTD_dictLoadMethod_e = 0;
118pub const ZSTD_MAXWINDOWSIZE_DEFAULT: u32 = (1u32 << ZSTD_WINDOWLOG_LIMIT_DEFAULT).wrapping_add(1);
119pub const ZSTD_NO_FORWARD_PROGRESS_MAX: core::ffi::c_int = 16;
120pub const ZSTD_VERSION_MAJOR: core::ffi::c_int = 1;
121pub const ZSTD_VERSION_MINOR: core::ffi::c_int = 5;
122pub const ZSTD_VERSION_RELEASE: core::ffi::c_int = 8;
123pub const ZSTD_VERSION_NUMBER: core::ffi::c_int =
124    ZSTD_VERSION_MAJOR * 100 * 100 + ZSTD_VERSION_MINOR * 100 + ZSTD_VERSION_RELEASE;
125pub const ZSTD_MAGICNUMBER: core::ffi::c_uint = 0xfd2fb528;
126pub const ZSTD_MAGIC_DICTIONARY: core::ffi::c_uint = 0xec30a437;
127pub const ZSTD_MAGIC_SKIPPABLE_START: core::ffi::c_int = 0x184d2a50;
128pub const ZSTD_MAGIC_SKIPPABLE_MASK: core::ffi::c_uint = 0xfffffff0;
129pub const ZSTD_BLOCKSIZELOG_MAX: core::ffi::c_int = 17;
130pub const ZSTD_BLOCKSIZE_MAX: core::ffi::c_int = (1) << ZSTD_BLOCKSIZELOG_MAX;
131pub const ZSTD_CONTENTSIZE_UNKNOWN: core::ffi::c_ulonglong =
132    (0 as core::ffi::c_ulonglong).wrapping_sub(1);
133pub const ZSTD_CONTENTSIZE_ERROR: core::ffi::c_ulonglong =
134    (0 as core::ffi::c_ulonglong).wrapping_sub(2);
135pub const ZSTD_SKIPPABLEHEADERSIZE: core::ffi::c_int = 8;
136pub const ZSTD_WINDOWLOG_MAX_32: core::ffi::c_int = 30;
137pub const ZSTD_WINDOWLOG_MAX_64: core::ffi::c_int = 31;
138pub const ZSTD_BLOCKSIZE_MAX_MIN: core::ffi::c_int = (1) << 10;
139pub const ZSTD_WINDOWLOG_LIMIT_DEFAULT: core::ffi::c_int = 27;
140pub const ZSTD_d_format: core::ffi::c_int = 1000;
141pub const ZSTD_d_stableOutBuffer: core::ffi::c_int = 1001;
142pub const ZSTD_d_forceIgnoreChecksum: core::ffi::c_int = 1002;
143pub const ZSTD_d_refMultipleDDicts: core::ffi::c_int = 1003;
144pub const ZSTD_d_disableHuffmanAssembly: core::ffi::c_int = 1004;
145pub const ZSTD_d_maxBlockSize: core::ffi::c_int = 1005;
146pub const ZSTD_WINDOWLOG_ABSOLUTEMIN: core::ffi::c_int = 10;
147
148#[inline]
149unsafe fn ZSTD_customMalloc(size: size_t, customMem: ZSTD_customMem) -> *mut core::ffi::c_void {
150    if (customMem.customAlloc).is_some() {
151        return (customMem.customAlloc).unwrap_unchecked()(customMem.opaque, size);
152    }
153    malloc(size)
154}
155#[inline]
156unsafe fn ZSTD_customCalloc(size: size_t, customMem: ZSTD_customMem) -> *mut core::ffi::c_void {
157    if (customMem.customAlloc).is_some() {
158        let ptr = (customMem.customAlloc).unwrap_unchecked()(customMem.opaque, size);
159        ptr::write_bytes(ptr, 0, size);
160        return ptr;
161    }
162    calloc(1, size)
163}
164#[inline]
165unsafe fn ZSTD_customFree(ptr: *mut core::ffi::c_void, customMem: ZSTD_customMem) {
166    if !ptr.is_null() {
167        if (customMem.customFree).is_some() {
168            (customMem.customFree).unwrap_unchecked()(customMem.opaque, ptr);
169        } else {
170            free(ptr);
171        }
172    }
173}
174
175const ZSTDv01_magicNumberLE: u32 = 0x1EB52FFD;
176
177const ZSTDv02_MAGICNUMBER: core::ffi::c_uint = 0xFD2FB522;
178const ZSTDv03_MAGICNUMBER: core::ffi::c_uint = 0xFD2FB523;
179const ZSTDv04_MAGICNUMBER: core::ffi::c_uint = 0xFD2FB524;
180const ZSTDv05_MAGICNUMBER: core::ffi::c_uint = 0xFD2FB525;
181const ZSTDv06_MAGICNUMBER: core::ffi::c_uint = 0xFD2FB526;
182const ZSTDv07_MAGICNUMBER: core::ffi::c_uint = 0xFD2FB527;
183
184#[inline]
185unsafe fn ZSTD_isLegacy(src: *const core::ffi::c_void, srcSize: size_t) -> u32 {
186    is_legacy(unsafe { core::slice::from_raw_parts(src.cast::<u8>(), srcSize) })
187}
188
189fn is_legacy(src: &[u8]) -> u32 {
190    let Some(chunk) = src.first_chunk() else {
191        return 0;
192    };
193
194    match u32::from_le_bytes(*chunk) {
195        ZSTDv01_magicNumberLE => 1,
196        ZSTDv02_MAGICNUMBER => 2,
197        ZSTDv03_MAGICNUMBER => 3,
198        ZSTDv04_MAGICNUMBER => 4,
199        ZSTDv05_MAGICNUMBER => 5,
200        ZSTDv06_MAGICNUMBER => 6,
201        ZSTDv07_MAGICNUMBER => 7,
202        _ => 0,
203    }
204}
205
206#[inline]
207fn get_decompressed_size_legacy(src: &[u8]) -> Option<u64> {
208    let ptr = src.as_ptr().cast();
209
210    match is_legacy(src) {
211        5 => {
212            let mut fParams = ZSTDv05_parameters {
213                srcSize: 0,
214                windowLog: 0,
215                contentLog: 0,
216                hashLog: 0,
217                searchLog: 0,
218                searchLength: 0,
219                targetLength: 0,
220                strategy: ZSTDv05_fast,
221            };
222
223            match unsafe { ZSTDv05_getFrameParams(&mut fParams, ptr, src.len() as _) } {
224                0 => Some(fParams.srcSize as core::ffi::c_ulonglong),
225                _ => None,
226            }
227        }
228        6 => {
229            let mut fParams_0 = ZSTDv06_frameParams_s {
230                frameContentSize: 0,
231                windowLog: 0,
232            };
233
234            match unsafe { ZSTDv06_getFrameParams(&mut fParams_0, ptr, src.len() as _) } {
235                0 => Some(fParams_0.frameContentSize),
236                _ => None,
237            }
238        }
239        7 => {
240            let mut fParams_1 = ZSTDv07_frameParams {
241                frameContentSize: 0,
242                windowSize: 0,
243                dictID: 0,
244                checksumFlag: 0,
245            };
246
247            match unsafe { ZSTDv07_getFrameParams(&mut fParams_1, ptr, src.len() as _) } {
248                0 => Some(fParams_1.frameContentSize),
249                _ => None,
250            }
251        }
252
253        _ => None,
254    }
255}
256#[inline]
257unsafe fn ZSTD_decompressLegacy(
258    mut dst: *mut core::ffi::c_void,
259    dstCapacity: size_t,
260    mut src: *const core::ffi::c_void,
261    compressedSize: size_t,
262    mut dict: *const core::ffi::c_void,
263    dictSize: size_t,
264) -> size_t {
265    let version = ZSTD_isLegacy(src, compressedSize);
266    let mut x: core::ffi::c_char = 0;
267    if dst.is_null() {
268        dst = &mut x as *mut core::ffi::c_char as *mut core::ffi::c_void;
269    }
270    if src.is_null() {
271        src = &mut x as *mut core::ffi::c_char as *const core::ffi::c_void;
272    }
273    if dict.is_null() {
274        dict = &mut x as *mut core::ffi::c_char as *const core::ffi::c_void;
275    }
276    match version {
277        5 => {
278            let mut result: size_t = 0;
279            let zd = ZSTDv05_createDCtx();
280            if zd.is_null() {
281                return Error::memory_allocation.to_error_code();
282            }
283            result = ZSTDv05_decompress_usingDict(
284                &mut *zd,
285                dst,
286                dstCapacity,
287                src,
288                compressedSize,
289                dict,
290                dictSize,
291            );
292            ZSTDv05_freeDCtx(zd);
293            result
294        }
295        6 => {
296            let mut result_0: size_t = 0;
297            let zd_0 = ZSTDv06_createDCtx();
298            if zd_0.is_null() {
299                return Error::memory_allocation.to_error_code();
300            }
301            result_0 = ZSTDv06_decompress_usingDict(
302                zd_0,
303                dst,
304                dstCapacity,
305                src,
306                compressedSize,
307                dict,
308                dictSize,
309            );
310            ZSTDv06_freeDCtx(zd_0);
311            result_0
312        }
313        7 => {
314            let mut result_1: size_t = 0;
315            let zd_1 = ZSTDv07_createDCtx();
316            if zd_1.is_null() {
317                return Error::memory_allocation.to_error_code();
318            }
319            result_1 = ZSTDv07_decompress_usingDict(
320                zd_1,
321                dst,
322                dstCapacity,
323                src,
324                compressedSize,
325                dict,
326                dictSize,
327            );
328            ZSTDv07_freeDCtx(zd_1);
329            result_1
330        }
331        _ => Error::prefix_unknown.to_error_code(),
332    }
333}
334
335#[inline]
336unsafe fn ZSTD_findFrameSizeInfoLegacy(
337    src: *const core::ffi::c_void,
338    srcSize: size_t,
339) -> ZSTD_frameSizeInfo {
340    find_frame_size_info_legacy(if src.is_null() {
341        &[]
342    } else {
343        core::slice::from_raw_parts(src.cast(), srcSize)
344    })
345}
346
347unsafe fn find_frame_size_info_legacy(src: &[u8]) -> ZSTD_frameSizeInfo {
348    let mut frameSizeInfo = ZSTD_frameSizeInfo {
349        nbBlocks: 0,
350        compressedSize: 0,
351        decompressedBound: 0,
352    };
353
354    match is_legacy(src) {
355        5 => {
356            ZSTDv05_findFrameSizeInfoLegacy(
357                src.as_ptr().cast(),
358                src.len(),
359                &mut frameSizeInfo.compressedSize,
360                &mut frameSizeInfo.decompressedBound,
361            );
362        }
363        6 => {
364            ZSTDv06_findFrameSizeInfoLegacy(
365                src.as_ptr().cast(),
366                src.len(),
367                &mut frameSizeInfo.compressedSize,
368                &mut frameSizeInfo.decompressedBound,
369            );
370        }
371        7 => {
372            ZSTDv07_findFrameSizeInfoLegacy(
373                src.as_ptr().cast(),
374                src.len(),
375                &mut frameSizeInfo.compressedSize,
376                &mut frameSizeInfo.decompressedBound,
377            );
378        }
379        _ => {
380            frameSizeInfo.compressedSize = Error::prefix_unknown.to_error_code();
381            frameSizeInfo.decompressedBound = ZSTD_CONTENTSIZE_ERROR;
382        }
383    }
384
385    if !ERR_isError(frameSizeInfo.compressedSize) && frameSizeInfo.compressedSize > src.len() {
386        frameSizeInfo.compressedSize = Error::srcSize_wrong.to_error_code();
387        frameSizeInfo.decompressedBound = ZSTD_CONTENTSIZE_ERROR;
388    }
389
390    if frameSizeInfo.decompressedBound != ZSTD_CONTENTSIZE_ERROR {
391        frameSizeInfo.nbBlocks = (frameSizeInfo.decompressedBound)
392            .wrapping_div(ZSTD_BLOCKSIZE_MAX as core::ffi::c_ulonglong)
393            as size_t;
394    }
395
396    frameSizeInfo
397}
398
399#[inline]
400unsafe fn ZSTD_findFrameCompressedSizeLegacy(
401    src: *const core::ffi::c_void,
402    srcSize: size_t,
403) -> size_t {
404    let frameSizeInfo = ZSTD_findFrameSizeInfoLegacy(src, srcSize);
405    frameSizeInfo.compressedSize
406}
407
408#[inline]
409unsafe fn ZSTD_freeLegacyStreamContext(
410    legacyContext: *mut core::ffi::c_void,
411    version: u32,
412) -> size_t {
413    match version {
414        5 => ZBUFFv05_freeDCtx(legacyContext as *mut ZBUFFv05_DCtx),
415        6 => ZBUFFv06_freeDCtx(legacyContext as *mut ZBUFFv06_DCtx),
416        7 => ZBUFFv07_freeDCtx(legacyContext as *mut ZBUFFv07_DCtx),
417        1 | 2 | 3 | _ => Error::version_unsupported.to_error_code(),
418    }
419}
420#[inline]
421unsafe fn ZSTD_initLegacyStream(
422    legacyContext: *mut *mut core::ffi::c_void,
423    prevVersion: u32,
424    newVersion: u32,
425    mut dict: *const core::ffi::c_void,
426    dictSize: size_t,
427) -> size_t {
428    let mut x: core::ffi::c_char = 0;
429    if dict.is_null() {
430        dict = &mut x as *mut core::ffi::c_char as *const core::ffi::c_void;
431    }
432    if prevVersion != newVersion {
433        ZSTD_freeLegacyStreamContext(*legacyContext, prevVersion);
434    }
435    match newVersion {
436        5 => {
437            let dctx = if prevVersion != newVersion {
438                ZBUFFv05_createDCtx()
439            } else {
440                *legacyContext as *mut ZBUFFv05_DCtx
441            };
442            if dctx.is_null() {
443                return Error::memory_allocation.to_error_code();
444            }
445            ZBUFFv05_decompressInitDictionary(dctx, dict, dictSize);
446            *legacyContext = dctx as *mut core::ffi::c_void;
447            0
448        }
449        6 => {
450            let dctx_0 = if prevVersion != newVersion {
451                ZBUFFv06_createDCtx()
452            } else {
453                *legacyContext as *mut ZBUFFv06_DCtx
454            };
455            if dctx_0.is_null() {
456                return Error::memory_allocation.to_error_code();
457            }
458            ZBUFFv06_decompressInitDictionary(dctx_0, dict, dictSize);
459            *legacyContext = dctx_0 as *mut core::ffi::c_void;
460            0
461        }
462        7 => {
463            let dctx_1 = if prevVersion != newVersion {
464                ZBUFFv07_createDCtx()
465            } else {
466                *legacyContext as *mut ZBUFFv07_DCtx
467            };
468            if dctx_1.is_null() {
469                return Error::memory_allocation.to_error_code();
470            }
471            ZBUFFv07_decompressInitDictionary(dctx_1, dict, dictSize);
472            *legacyContext = dctx_1 as *mut core::ffi::c_void;
473            0
474        }
475        1 | 2 | 3 | _ => 0,
476    }
477}
478
479#[inline]
480unsafe fn ZSTD_decompressLegacyStream(
481    legacyContext: *mut core::ffi::c_void,
482    version: u32,
483    output: &mut ZSTD_outBuffer,
484    input: &mut ZSTD_inBuffer,
485) -> size_t {
486    static mut x: core::ffi::c_char = 0;
487    if (output.dst).is_null() {
488        output.dst = &raw mut x as *mut core::ffi::c_void;
489    }
490    if (input.src).is_null() {
491        input.src = &raw mut x as *const core::ffi::c_void;
492    }
493    match version {
494        5 => {
495            let dctx = legacyContext as *mut ZBUFFv05_DCtx;
496            let src =
497                (input.src as *const core::ffi::c_char).add(input.pos) as *const core::ffi::c_void;
498            let mut readSize = (input.size).wrapping_sub(input.pos);
499            let dst =
500                (output.dst as *mut core::ffi::c_char).add(output.pos) as *mut core::ffi::c_void;
501            let mut decodedSize = (output.size).wrapping_sub(output.pos);
502            let hintSize =
503                ZBUFFv05_decompressContinue(&mut *dctx, dst, &mut decodedSize, src, &mut readSize);
504            output.pos = (output.pos).wrapping_add(decodedSize);
505            input.pos = (input.pos).wrapping_add(readSize);
506            hintSize
507        }
508        6 => {
509            let dctx_0 = legacyContext as *mut ZBUFFv06_DCtx;
510            let src_0 =
511                (input.src as *const core::ffi::c_char).add(input.pos) as *const core::ffi::c_void;
512            let mut readSize_0 = (input.size).wrapping_sub(input.pos);
513            let dst_0 =
514                (output.dst as *mut core::ffi::c_char).add(output.pos) as *mut core::ffi::c_void;
515            let mut decodedSize_0 = (output.size).wrapping_sub(output.pos);
516            let hintSize_0 = ZBUFFv06_decompressContinue(
517                dctx_0,
518                dst_0,
519                &mut decodedSize_0,
520                src_0,
521                &mut readSize_0,
522            );
523            output.pos = (output.pos).wrapping_add(decodedSize_0);
524            input.pos = (input.pos).wrapping_add(readSize_0);
525            hintSize_0
526        }
527        7 => {
528            let dctx_1 = legacyContext as *mut ZBUFFv07_DCtx;
529            let src_1 =
530                (input.src as *const core::ffi::c_char).add(input.pos) as *const core::ffi::c_void;
531            let mut readSize_1 = (input.size).wrapping_sub(input.pos);
532            let dst_1 =
533                (output.dst as *mut core::ffi::c_char).add(output.pos) as *mut core::ffi::c_void;
534            let mut decodedSize_1 = (output.size).wrapping_sub(output.pos);
535            let hintSize_1 = ZBUFFv07_decompressContinue(
536                dctx_1,
537                dst_1,
538                &mut decodedSize_1,
539                src_1,
540                &mut readSize_1,
541            );
542            output.pos = (output.pos).wrapping_add(decodedSize_1);
543            input.pos = (input.pos).wrapping_add(readSize_1);
544            hintSize_1
545        }
546        1 | 2 | 3 | _ => Error::version_unsupported.to_error_code(),
547    }
548}
549
550pub const DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT: core::ffi::c_int = 4;
551pub const DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT: core::ffi::c_int = 3;
552pub const DDICT_HASHSET_TABLE_BASE_SIZE: core::ffi::c_int = 64;
553pub const DDICT_HASHSET_RESIZE_FACTOR: core::ffi::c_int = 2;
554
555fn ZSTD_DDictHashSet_getIndex(hashSet: &ZSTD_DDictHashSet, dictID: u32) -> size_t {
556    let hash = ZSTD_XXH64_slice(&dictID.to_ne_bytes(), 0);
557    hash as size_t & (hashSet.ddictPtrTableSize).wrapping_sub(1)
558}
559
560unsafe fn ZSTD_DDictHashSet_emplaceDDict(
561    hashSet: &mut ZSTD_DDictHashSet,
562    ddict: *const ZSTD_DDict,
563) -> size_t {
564    let dictID = ZSTD_getDictID_fromDDict(ddict);
565    let mut idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);
566    let idxRangeMask = (hashSet.ddictPtrTableSize).wrapping_sub(1);
567    if hashSet.ddictPtrCount == hashSet.ddictPtrTableSize {
568        return Error::GENERIC.to_error_code();
569    }
570    while !(*(hashSet.ddictPtrTable).add(idx)).is_null() {
571        if ZSTD_getDictID_fromDDict(*(hashSet.ddictPtrTable).add(idx)) == dictID {
572            let fresh0 = &mut (*(hashSet.ddictPtrTable).add(idx));
573            *fresh0 = ddict;
574            return 0;
575        }
576        idx &= idxRangeMask;
577        idx = idx.wrapping_add(1);
578    }
579    let fresh1 = &mut (*(hashSet.ddictPtrTable).add(idx));
580    *fresh1 = ddict;
581    hashSet.ddictPtrCount = (hashSet.ddictPtrCount).wrapping_add(1);
582    hashSet.ddictPtrCount;
583    0
584}
585
586unsafe fn ZSTD_DDictHashSet_expand(
587    hashSet: &mut ZSTD_DDictHashSet,
588    customMem: ZSTD_customMem,
589) -> size_t {
590    let newTableSize = hashSet.ddictPtrTableSize * DDICT_HASHSET_RESIZE_FACTOR as size_t;
591    let newTable = ZSTD_customCalloc(
592        (::core::mem::size_of::<*mut ZSTD_DDict>()).wrapping_mul(newTableSize),
593        customMem,
594    ) as *mut *const ZSTD_DDict;
595    let oldTable = hashSet.ddictPtrTable;
596    let oldTableSize = hashSet.ddictPtrTableSize;
597    let mut i: size_t = 0;
598    if newTable.is_null() {
599        return Error::memory_allocation.to_error_code();
600    }
601    hashSet.ddictPtrTable = newTable;
602    hashSet.ddictPtrTableSize = newTableSize;
603    hashSet.ddictPtrCount = 0;
604    i = 0;
605    while i < oldTableSize {
606        if !(*oldTable.add(i)).is_null() {
607            let err_code = ZSTD_DDictHashSet_emplaceDDict(hashSet, *oldTable.add(i));
608            if ERR_isError(err_code) {
609                return err_code;
610            }
611        }
612        i = i.wrapping_add(1);
613    }
614    ZSTD_customFree(oldTable as *mut core::ffi::c_void, customMem);
615    0
616}
617
618unsafe fn ZSTD_DDictHashSet_getDDict(
619    hashSet: &mut ZSTD_DDictHashSet,
620    dictID: u32,
621) -> *const ZSTD_DDict {
622    let mut idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);
623    let idxRangeMask = (hashSet.ddictPtrTableSize).wrapping_sub(1);
624    loop {
625        let currDictID = ZSTD_getDictID_fromDDict(*(hashSet.ddictPtrTable).add(idx)) as size_t;
626        if currDictID == dictID as size_t || currDictID == 0 {
627            break;
628        }
629        idx &= idxRangeMask;
630        idx = idx.wrapping_add(1);
631    }
632    *(hashSet.ddictPtrTable).add(idx)
633}
634
635unsafe fn ZSTD_createDDictHashSet(customMem: ZSTD_customMem) -> *mut ZSTD_DDictHashSet {
636    let ret = ZSTD_customMalloc(::core::mem::size_of::<ZSTD_DDictHashSet>(), customMem)
637        as *mut ZSTD_DDictHashSet;
638    if ret.is_null() {
639        return core::ptr::null_mut();
640    }
641    (*ret).ddictPtrTable = ZSTD_customCalloc(
642        (DDICT_HASHSET_TABLE_BASE_SIZE as size_t)
643            .wrapping_mul(::core::mem::size_of::<*mut ZSTD_DDict>()),
644        customMem,
645    ) as *mut *const ZSTD_DDict;
646    if ((*ret).ddictPtrTable).is_null() {
647        ZSTD_customFree(ret as *mut core::ffi::c_void, customMem);
648        return core::ptr::null_mut();
649    }
650    (*ret).ddictPtrTableSize = DDICT_HASHSET_TABLE_BASE_SIZE as size_t;
651    (*ret).ddictPtrCount = 0;
652    ret
653}
654
655unsafe fn ZSTD_freeDDictHashSet(hashSet: *mut ZSTD_DDictHashSet, customMem: ZSTD_customMem) {
656    if !hashSet.is_null() && !((*hashSet).ddictPtrTable).is_null() {
657        ZSTD_customFree(
658            (*hashSet).ddictPtrTable as *mut core::ffi::c_void,
659            customMem,
660        );
661    }
662    if !hashSet.is_null() {
663        ZSTD_customFree(hashSet as *mut core::ffi::c_void, customMem);
664    }
665}
666unsafe fn ZSTD_DDictHashSet_addDDict(
667    hashSet: &mut ZSTD_DDictHashSet,
668    ddict: *const ZSTD_DDict,
669    customMem: ZSTD_customMem,
670) -> size_t {
671    if hashSet.ddictPtrCount * DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT as size_t
672        / hashSet.ddictPtrTableSize
673        * DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT as size_t
674        != 0
675    {
676        let err_code = ZSTD_DDictHashSet_expand(hashSet, customMem);
677        if ERR_isError(err_code) {
678            return err_code;
679        }
680    }
681    let err_code_0 = ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict);
682    if ERR_isError(err_code_0) {
683        return err_code_0;
684    }
685    0
686}
687#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_sizeof_DCtx))]
688pub unsafe extern "C" fn ZSTD_sizeof_DCtx(dctx: *const ZSTD_DCtx) -> size_t {
689    if dctx.is_null() {
690        return 0;
691    }
692    (::core::mem::size_of::<ZSTD_DCtx>())
693        .wrapping_add(ZSTD_sizeof_DDict((*dctx).ddictLocal))
694        .wrapping_add((*dctx).inBuffSize)
695        .wrapping_add((*dctx).outBuffSize)
696}
697#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_estimateDCtxSize))]
698pub unsafe extern "C" fn ZSTD_estimateDCtxSize() -> size_t {
699    ::core::mem::size_of::<ZSTD_DCtx>()
700}
701
702const fn ZSTD_startingInputLength(format: Format) -> size_t {
703    match format {
704        Format::ZSTD_f_zstd1 => 5,
705        Format::ZSTD_f_zstd1_magicless => 1,
706    }
707}
708
709unsafe fn ZSTD_DCtx_resetParameters(dctx: *mut ZSTD_DCtx) {
710    (*dctx).format = Format::ZSTD_f_zstd1;
711    (*dctx).maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT as size_t;
712    (*dctx).outBufferMode = BufferMode::Buffered;
713    (*dctx).forceIgnoreChecksum = ZSTD_d_validateChecksum;
714    (*dctx).refMultipleDDicts = MultipleDDicts::Single;
715    (*dctx).disableHufAsm = 0;
716    (*dctx).maxBlockSizeParam = 0;
717}
718
719unsafe fn ZSTD_initDCtx_internal(dctx: *mut ZSTD_DCtx) {
720    (*dctx).staticSize = 0;
721    (*dctx).ddict = core::ptr::null();
722    (*dctx).ddictLocal = core::ptr::null_mut();
723    (*dctx).dictEnd = core::ptr::null();
724    (*dctx).ddictIsCold = 0;
725    (*dctx).dictUses = ZSTD_dont_use;
726    (*dctx).inBuff = core::ptr::null_mut();
727    (*dctx).inBuffSize = 0;
728    (*dctx).outBuffSize = 0;
729    (*dctx).streamStage = StreamStage::Init;
730    (*dctx).legacyContext = core::ptr::null_mut();
731    (*dctx).previousLegacyVersion = 0;
732    (*dctx).noForwardProgress = 0;
733    (*dctx).oversizedDuration = 0;
734    (*dctx).isFrameDecompression = 1;
735    (*dctx).bmi2 = ZSTD_cpuSupportsBmi2() as _;
736    (*dctx).ddictSet = core::ptr::null_mut();
737    ZSTD_DCtx_resetParameters(dctx);
738}
739
740#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_initStaticDCtx))]
741pub unsafe extern "C" fn ZSTD_initStaticDCtx(
742    workspace: *mut core::ffi::c_void,
743    workspaceSize: size_t,
744) -> *mut ZSTD_DCtx {
745    let dctx = workspace as *mut ZSTD_DCtx;
746    if workspace as size_t & 7 != 0 {
747        return core::ptr::null_mut();
748    }
749    if workspaceSize < ::core::mem::size_of::<ZSTD_DCtx>() {
750        return core::ptr::null_mut();
751    }
752    ZSTD_initDCtx_internal(dctx);
753    (*dctx).staticSize = workspaceSize;
754    (*dctx).inBuff = dctx.offset(1) as *mut core::ffi::c_char;
755    dctx
756}
757
758unsafe fn ZSTD_createDCtx_internal(customMem: ZSTD_customMem) -> *mut ZSTD_DCtx {
759    if (customMem.customAlloc).is_none() ^ (customMem.customFree).is_none() {
760        return core::ptr::null_mut();
761    }
762
763    let dctx = ZSTD_customMalloc(::core::mem::size_of::<ZSTD_DCtx>(), customMem) as *mut ZSTD_DCtx;
764    if dctx.is_null() {
765        return core::ptr::null_mut();
766    }
767
768    (*dctx).customMem = customMem;
769    ZSTD_initDCtx_internal(dctx);
770    dctx
771}
772
773#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_createDCtx_advanced))]
774pub unsafe extern "C" fn ZSTD_createDCtx_advanced(customMem: ZSTD_customMem) -> *mut ZSTD_DCtx {
775    ZSTD_createDCtx_internal(customMem)
776}
777#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_createDCtx))]
778pub unsafe extern "C" fn ZSTD_createDCtx() -> *mut ZSTD_DCtx {
779    ZSTD_createDCtx_internal(ZSTD_defaultCMem)
780}
781unsafe fn ZSTD_clearDict(dctx: *mut ZSTD_DCtx) {
782    ZSTD_freeDDict((*dctx).ddictLocal);
783    (*dctx).ddictLocal = core::ptr::null_mut();
784    (*dctx).ddict = core::ptr::null();
785    (*dctx).dictUses = ZSTD_dont_use;
786}
787#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_freeDCtx))]
788pub unsafe extern "C" fn ZSTD_freeDCtx(dctx: *mut ZSTD_DCtx) -> size_t {
789    if dctx.is_null() {
790        return 0;
791    }
792    if (*dctx).staticSize != 0 {
793        return Error::memory_allocation.to_error_code();
794    }
795    let cMem = (*dctx).customMem;
796    ZSTD_clearDict(dctx);
797    ZSTD_customFree((*dctx).inBuff as *mut core::ffi::c_void, cMem);
798    (*dctx).inBuff = core::ptr::null_mut();
799    if !((*dctx).legacyContext).is_null() {
800        ZSTD_freeLegacyStreamContext((*dctx).legacyContext, (*dctx).previousLegacyVersion);
801    }
802    if !((*dctx).ddictSet).is_null() {
803        ZSTD_freeDDictHashSet((*dctx).ddictSet, cMem);
804        (*dctx).ddictSet = core::ptr::null_mut();
805    }
806    ZSTD_customFree(dctx as *mut core::ffi::c_void, cMem);
807    0
808}
809#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_copyDCtx))]
810pub unsafe extern "C" fn ZSTD_copyDCtx(dstDCtx: *mut ZSTD_DCtx, srcDCtx: *const ZSTD_DCtx) {
811    let toCopy = (&mut (*dstDCtx).inBuff as *mut *mut core::ffi::c_char as *mut core::ffi::c_char)
812        .offset_from(dstDCtx as *mut core::ffi::c_char) as core::ffi::c_long
813        as size_t;
814    libc::memcpy(
815        dstDCtx as *mut core::ffi::c_void,
816        srcDCtx as *const core::ffi::c_void,
817        toCopy as libc::size_t,
818    );
819}
820unsafe fn ZSTD_DCtx_selectFrameDDict(dctx: *mut ZSTD_DCtx) {
821    if !((*dctx).ddict).is_null() {
822        let frameDDict =
823            ZSTD_DDictHashSet_getDDict((*dctx).ddictSet.as_mut().unwrap(), (*dctx).fParams.dictID);
824        if !frameDDict.is_null() {
825            ZSTD_clearDict(dctx);
826            (*dctx).dictID = (*dctx).fParams.dictID;
827            (*dctx).ddict = frameDDict;
828            (*dctx).dictUses = ZSTD_use_indefinitely;
829        }
830    }
831}
832
833#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_isFrame))]
834pub unsafe extern "C" fn ZSTD_isFrame(
835    buffer: *const core::ffi::c_void,
836    size: size_t,
837) -> core::ffi::c_uint {
838    let src = if buffer.is_null() {
839        &[]
840    } else {
841        core::slice::from_raw_parts(buffer.cast(), size)
842    };
843
844    is_frame(src) as core::ffi::c_uint
845}
846
847fn is_frame(src: &[u8]) -> bool {
848    let [a, b, c, d] = *src else {
849        return false;
850    };
851
852    let magic = u32::from_le_bytes([a, b, c, d]);
853    if magic == ZSTD_MAGICNUMBER {
854        return true;
855    }
856
857    if magic & ZSTD_MAGIC_SKIPPABLE_MASK == ZSTD_MAGIC_SKIPPABLE_START as core::ffi::c_uint {
858        return true;
859    }
860
861    if is_legacy(src) != 0 {
862        return true;
863    }
864
865    false
866}
867
868#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_isSkippableFrame))]
869pub unsafe extern "C" fn ZSTD_isSkippableFrame(
870    buffer: *const core::ffi::c_void,
871    size: size_t,
872) -> core::ffi::c_uint {
873    let src = if buffer.is_null() {
874        &[]
875    } else {
876        core::slice::from_raw_parts(buffer.cast(), size)
877    };
878
879    is_skippable_frame(src) as core::ffi::c_uint
880}
881
882fn is_skippable_frame(src: &[u8]) -> bool {
883    let [a, b, c, d] = *src else {
884        return false;
885    };
886
887    let magic = u32::from_le_bytes([a, b, c, d]);
888    if magic & ZSTD_MAGIC_SKIPPABLE_MASK == ZSTD_MAGIC_SKIPPABLE_START as core::ffi::c_uint {
889        return true;
890    }
891
892    false
893}
894
895fn frame_header_size_internal(src: &[u8], format: Format) -> usize {
896    static ZSTD_fcs_fieldSize: [u8; 4] = [0, 2, 4, 8];
897    static ZSTD_did_fieldSize: [u8; 4] = [0, 1, 2, 4];
898
899    let minInputSize = ZSTD_startingInputLength(format);
900    let Some([.., fhd]) = src.get(..minInputSize as usize) else {
901        return Error::srcSize_wrong.to_error_code();
902    };
903
904    let dictID = fhd & 0b11;
905    let singleSegment = (fhd >> 5 & 1) != 0;
906    let fcsId = fhd >> 6;
907
908    minInputSize
909        + usize::from(!singleSegment)
910        + usize::from(ZSTD_did_fieldSize[usize::from(dictID)])
911        + usize::from(ZSTD_fcs_fieldSize[usize::from(fcsId)])
912        + usize::from(singleSegment && fcsId == 0)
913}
914
915#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_frameHeaderSize))]
916pub unsafe extern "C" fn ZSTD_frameHeaderSize(
917    src: *const core::ffi::c_void,
918    srcSize: size_t,
919) -> size_t {
920    let src = if src.is_null() {
921        &[]
922    } else {
923        core::slice::from_raw_parts(src.cast(), srcSize)
924    };
925
926    frame_header_size_internal(src, Format::ZSTD_f_zstd1)
927}
928
929#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_getFrameHeader))]
930pub unsafe extern "C" fn ZSTD_getFrameHeader(
931    zfhPtr: *mut ZSTD_FrameHeader,
932    src: *const core::ffi::c_void,
933    srcSize: size_t,
934) -> size_t {
935    ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, Format::ZSTD_f_zstd1 as _)
936}
937
938fn get_frame_header(zfhPtr: &mut ZSTD_FrameHeader, src: &[u8]) -> size_t {
939    get_frame_header_advanced(zfhPtr, src, Format::ZSTD_f_zstd1)
940}
941
942#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_getFrameHeader_advanced))]
943pub unsafe extern "C" fn ZSTD_getFrameHeader_advanced(
944    zfhPtr: *mut ZSTD_FrameHeader,
945    src: *const core::ffi::c_void,
946    srcSize: size_t,
947    format: ZSTD_format_e,
948) -> size_t {
949    // Apparently some sanitizers require this?
950    unsafe { zfhPtr.write(ZSTD_FrameHeader::default()) };
951
952    let Some(zfhPtr) = zfhPtr.as_mut() else {
953        return Error::GENERIC.to_error_code();
954    };
955
956    // Compatibility: this is stricter than zstd.
957    let Ok(format) = Format::try_from(format) else {
958        return Error::GENERIC.to_error_code();
959    };
960
961    if srcSize > 0 && src.is_null() {
962        return Error::GENERIC.to_error_code();
963    }
964
965    get_frame_header_advanced(
966        zfhPtr,
967        if src.is_null() {
968            &[]
969        } else {
970            core::slice::from_raw_parts(src as *const u8, srcSize)
971        },
972        format,
973    )
974}
975
976fn get_frame_header_advanced(zfhPtr: &mut ZSTD_FrameHeader, src: &[u8], format: Format) -> size_t {
977    let minInputSize = ZSTD_startingInputLength(format);
978    if src.len() < minInputSize as usize {
979        if !src.is_empty()
980            && format != Format::ZSTD_f_zstd1_magicless
981            && src != &ZSTD_MAGICNUMBER.to_le_bytes()[..src.len()]
982        {
983            let mut hbuf = ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes();
984            hbuf[..src.len()].copy_from_slice(src);
985            if u32::from_le_bytes(hbuf) & ZSTD_MAGIC_SKIPPABLE_MASK
986                != ZSTD_MAGIC_SKIPPABLE_START as u32
987            {
988                return Error::prefix_unknown.to_error_code();
989            }
990        }
991        return minInputSize;
992    }
993
994    let first_word = u32::from_le_bytes(*src.first_chunk().unwrap());
995
996    if format != Format::ZSTD_f_zstd1_magicless && first_word != ZSTD_MAGICNUMBER {
997        if first_word & ZSTD_MAGIC_SKIPPABLE_MASK == ZSTD_MAGIC_SKIPPABLE_START as core::ffi::c_uint
998        {
999            if src.len() < ZSTD_SKIPPABLEHEADERSIZE as usize {
1000                return ZSTD_SKIPPABLEHEADERSIZE as size_t;
1001            }
1002
1003            let dictID = first_word.wrapping_sub(ZSTD_MAGIC_SKIPPABLE_START as u32);
1004            let frameContentSize =
1005                u32::from_le_bytes(*src[ZSTD_FRAMEIDSIZE..].first_chunk().unwrap());
1006
1007            *zfhPtr = ZSTD_FrameHeader {
1008                frameContentSize: u64::from(frameContentSize),
1009                windowSize: 0,
1010                blockSizeMax: 0,
1011                frameType: ZSTD_skippableFrame,
1012                headerSize: ZSTD_SKIPPABLEHEADERSIZE as core::ffi::c_uint,
1013                dictID,
1014                checksumFlag: 0,
1015                _reserved1: 0,
1016                _reserved2: 0,
1017            };
1018
1019            return 0;
1020        }
1021        return Error::prefix_unknown.to_error_code();
1022    }
1023
1024    let fhsize = frame_header_size_internal(src, format);
1025    if src.len() < fhsize {
1026        return fhsize;
1027    }
1028
1029    let fhdByte = src[minInputSize as usize - 1];
1030    let dictIDSizeCode = fhdByte & 0b11;
1031    let checksumFlag = u32::from(fhdByte) >> 2 & 1;
1032    let singleSegment = (u32::from(fhdByte) >> 5 & 1) != 0;
1033    let fcsID = (u32::from(fhdByte) >> 6) as u32;
1034
1035    let mut windowSize = 0;
1036
1037    if fhdByte & 0x8 != 0 {
1038        return Error::frameParameter_unsupported.to_error_code();
1039    }
1040
1041    let mut pos = minInputSize as usize;
1042    if !singleSegment {
1043        let wlByte = src[pos];
1044        pos += 1;
1045        let windowLog = ((i32::from(wlByte) / 8) + ZSTD_WINDOWLOG_ABSOLUTEMIN) as u32;
1046
1047        if windowLog > (if size_of::<usize>() == 4 { 30 } else { 31 }) as u32 {
1048            return Error::frameParameter_windowTooLarge.to_error_code();
1049        }
1050
1051        windowSize = 1u64 << windowLog;
1052        windowSize = windowSize.wrapping_add((windowSize / 8) * (wlByte & 7) as u64);
1053    }
1054
1055    let dictID;
1056    match dictIDSizeCode {
1057        1 => {
1058            dictID = u32::from(src[pos]);
1059            pos += 1;
1060        }
1061        2 => {
1062            dictID = u32::from(u16::from_le_bytes(src[pos..][..2].try_into().unwrap()));
1063            pos += 2;
1064        }
1065        3 => {
1066            dictID = u32::from_le_bytes(src[pos..][..4].try_into().unwrap());
1067            pos += 4;
1068        }
1069        _ => {
1070            dictID = 0;
1071        }
1072    }
1073
1074    let frameContentSize = match fcsID {
1075        1 => u64::from(u16::from_le_bytes(src[pos..][..2].try_into().unwrap())) + 256,
1076        2 => u64::from(u32::from_le_bytes(src[pos..][..4].try_into().unwrap())),
1077        3 => u64::from_le_bytes(src[pos..][..8].try_into().unwrap()),
1078        _ if singleSegment => u64::from(src[pos]),
1079        _ => ZSTD_CONTENTSIZE_UNKNOWN,
1080    };
1081
1082    if singleSegment {
1083        windowSize = frameContentSize;
1084    }
1085
1086    *zfhPtr = ZSTD_FrameHeader {
1087        frameContentSize: frameContentSize as core::ffi::c_ulonglong,
1088        windowSize: windowSize as core::ffi::c_ulonglong,
1089        blockSizeMax: Ord::min(windowSize, 1 << 17) as u32,
1090        frameType: ZSTD_frame,
1091        headerSize: fhsize as u32,
1092        dictID,
1093        checksumFlag,
1094        _reserved1: 0,
1095        _reserved2: 0,
1096    };
1097
1098    0
1099}
1100
1101#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_getFrameContentSize))]
1102pub unsafe extern "C" fn ZSTD_getFrameContentSize(
1103    src: *const core::ffi::c_void,
1104    srcSize: size_t,
1105) -> core::ffi::c_ulonglong {
1106    let src = if src.is_null() {
1107        &[]
1108    } else {
1109        core::slice::from_raw_parts(src.cast(), srcSize)
1110    };
1111
1112    get_frame_content_size(src)
1113}
1114
1115fn get_frame_content_size(src: &[u8]) -> u64 {
1116    if is_legacy(src) != 0 {
1117        return match get_decompressed_size_legacy(src) {
1118            None | Some(0) => ZSTD_CONTENTSIZE_UNKNOWN,
1119            Some(decompressed_size) => decompressed_size,
1120        };
1121    }
1122
1123    let mut zfh = ZSTD_FrameHeader::default();
1124    if get_frame_header_advanced(&mut zfh, src, Format::ZSTD_f_zstd1) != 0 {
1125        return ZSTD_CONTENTSIZE_ERROR;
1126    }
1127
1128    if zfh.frameType == ZSTD_skippableFrame {
1129        0
1130    } else {
1131        zfh.frameContentSize
1132    }
1133}
1134
1135unsafe fn readSkippableFrameSize(src: *const core::ffi::c_void, srcSize: size_t) -> size_t {
1136    read_skippable_frame_size(if src.is_null() {
1137        &[]
1138    } else {
1139        core::slice::from_raw_parts(src.cast(), srcSize)
1140    })
1141}
1142
1143fn read_skippable_frame_size(src: &[u8]) -> size_t {
1144    let skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE as usize;
1145
1146    let [_, _, _, _, a, b, c, d, ..] = *src else {
1147        return Error::srcSize_wrong.to_error_code();
1148    };
1149
1150    let size = u32::from_le_bytes([a, b, c, d]);
1151
1152    if size.wrapping_add(8) < size {
1153        return Error::frameParameter_unsupported.to_error_code();
1154    }
1155
1156    let skippableSize = skippableHeaderSize.wrapping_add(size as usize);
1157    if skippableSize > src.len() {
1158        return Error::srcSize_wrong.to_error_code();
1159    }
1160
1161    skippableSize
1162}
1163
1164#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_readSkippableFrame))]
1165pub unsafe extern "C" fn ZSTD_readSkippableFrame(
1166    dst: *mut core::ffi::c_void,
1167    dstCapacity: size_t,
1168    magicVariant: *mut core::ffi::c_uint,
1169    src: *const core::ffi::c_void,
1170    srcSize: size_t,
1171) -> size_t {
1172    if srcSize < 8 {
1173        return Error::srcSize_wrong.to_error_code();
1174    }
1175    let magicNumber = MEM_readLE32(src);
1176    let skippableFrameSize = readSkippableFrameSize(src, srcSize);
1177    let skippableContentSize = skippableFrameSize.wrapping_sub(ZSTD_SKIPPABLEHEADERSIZE as size_t);
1178    if ZSTD_isSkippableFrame(src, srcSize) == 0 {
1179        return Error::frameParameter_unsupported.to_error_code();
1180    }
1181    if skippableFrameSize < 8 || skippableFrameSize > srcSize {
1182        return Error::srcSize_wrong.to_error_code();
1183    }
1184    if skippableContentSize > dstCapacity {
1185        return Error::dstSize_tooSmall.to_error_code();
1186    }
1187    if skippableContentSize > 0 && !dst.is_null() {
1188        libc::memcpy(
1189            dst,
1190            (src as *const u8).offset(8) as *const core::ffi::c_void,
1191            skippableContentSize as libc::size_t,
1192        );
1193    }
1194    if !magicVariant.is_null() {
1195        *magicVariant = magicNumber.wrapping_sub(ZSTD_MAGIC_SKIPPABLE_START as u32);
1196    }
1197    skippableContentSize
1198}
1199
1200#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_findDecompressedSize))]
1201pub unsafe extern "C" fn ZSTD_findDecompressedSize(
1202    src: *const core::ffi::c_void,
1203    srcSize: size_t,
1204) -> core::ffi::c_ulonglong {
1205    let src = if src.is_null() {
1206        &[]
1207    } else {
1208        core::slice::from_raw_parts(src.cast(), srcSize)
1209    };
1210
1211    find_decompressed_size(src)
1212}
1213
1214fn find_decompressed_size(mut src: &[u8]) -> u64 {
1215    let mut totalDstSize = 0u64;
1216
1217    while let [a, b, c, d, _, ..] = *src {
1218        let magicNumber = u32::from_le_bytes([a, b, c, d]);
1219        if magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK
1220            == ZSTD_MAGIC_SKIPPABLE_START as core::ffi::c_uint
1221        {
1222            let skippableSize = read_skippable_frame_size(src);
1223            if ERR_isError(skippableSize) {
1224                return ZSTD_CONTENTSIZE_ERROR;
1225            }
1226            src = &src[skippableSize..];
1227        } else {
1228            let fcs = get_frame_content_size(src);
1229            if fcs >= ZSTD_CONTENTSIZE_ERROR {
1230                return fcs;
1231            }
1232            if totalDstSize.wrapping_add(fcs) < totalDstSize {
1233                return ZSTD_CONTENTSIZE_ERROR;
1234            }
1235            totalDstSize = totalDstSize.wrapping_add(fcs);
1236            let frameSrcSize = ZSTD_findFrameCompressedSize_advanced(src, Format::ZSTD_f_zstd1);
1237            if ERR_isError(frameSrcSize) {
1238                return ZSTD_CONTENTSIZE_ERROR;
1239            }
1240            src = &src[frameSrcSize..];
1241        }
1242    }
1243
1244    if !src.is_empty() {
1245        return ZSTD_CONTENTSIZE_ERROR;
1246    }
1247
1248    totalDstSize
1249}
1250
1251#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_getDecompressedSize))]
1252pub unsafe extern "C" fn ZSTD_getDecompressedSize(
1253    src: *const core::ffi::c_void,
1254    srcSize: size_t,
1255) -> core::ffi::c_ulonglong {
1256    let ret = ZSTD_getFrameContentSize(src, srcSize);
1257    if ret >= ZSTD_CONTENTSIZE_ERROR {
1258        0
1259    } else {
1260        ret
1261    }
1262}
1263
1264unsafe fn ZSTD_decodeFrameHeader(dctx: *mut ZSTD_DCtx, src: &[u8]) -> size_t {
1265    let result = get_frame_header_advanced(&mut (*dctx).fParams, src, (*dctx).format);
1266    if ERR_isError(result) {
1267        return result;
1268    }
1269    if result > 0 {
1270        return Error::srcSize_wrong.to_error_code();
1271    }
1272    if (*dctx).refMultipleDDicts == MultipleDDicts::Multiple && !((*dctx).ddictSet).is_null() {
1273        ZSTD_DCtx_selectFrameDDict(dctx);
1274    }
1275    if (*dctx).fParams.dictID != 0 && (*dctx).dictID != (*dctx).fParams.dictID {
1276        return Error::dictionary_wrong.to_error_code();
1277    }
1278    (*dctx).validateChecksum =
1279        ((*dctx).fParams.checksumFlag != 0 && (*dctx).forceIgnoreChecksum as u64 == 0) as u32;
1280    if (*dctx).validateChecksum != 0 {
1281        ZSTD_XXH64_reset(&mut (*dctx).xxhState, 0);
1282    }
1283    (*dctx).processedCSize = ((*dctx).processedCSize as size_t).wrapping_add(src.len()) as u64;
1284    0
1285}
1286
1287fn ZSTD_errorFrameSizeInfo(ret: size_t) -> ZSTD_frameSizeInfo {
1288    ZSTD_frameSizeInfo {
1289        nbBlocks: 0,
1290        compressedSize: ret,
1291        decompressedBound: ZSTD_CONTENTSIZE_ERROR,
1292    }
1293}
1294
1295fn find_frame_size_info(src: &[u8], format: Format) -> ZSTD_frameSizeInfo {
1296    let mut frameSizeInfo = ZSTD_frameSizeInfo {
1297        nbBlocks: 0,
1298        compressedSize: 0,
1299        decompressedBound: 0,
1300    };
1301
1302    if format == Format::ZSTD_f_zstd1 && is_legacy(src) != 0 {
1303        return unsafe { find_frame_size_info_legacy(src) };
1304    }
1305
1306    if format == Format::ZSTD_f_zstd1
1307        && src.len() >= ZSTD_SKIPPABLEHEADERSIZE as usize
1308        && u32::from_le_bytes(*src.first_chunk().unwrap()) & ZSTD_MAGIC_SKIPPABLE_MASK
1309            == ZSTD_MAGIC_SKIPPABLE_START as core::ffi::c_uint
1310    {
1311        frameSizeInfo.compressedSize = read_skippable_frame_size(src);
1312        frameSizeInfo
1313    } else {
1314        let mut ip = 0;
1315        let mut remainingSize = src.len();
1316        let mut nbBlocks = 0usize;
1317        let mut zfh = ZSTD_FrameHeader {
1318            frameContentSize: 0,
1319            windowSize: 0,
1320            blockSizeMax: 0,
1321            frameType: ZSTD_frame,
1322            headerSize: 0,
1323            dictID: 0,
1324            checksumFlag: 0,
1325            _reserved1: 0,
1326            _reserved2: 0,
1327        };
1328        let ret = get_frame_header_advanced(&mut zfh, src, format);
1329        if ERR_isError(ret) {
1330            return ZSTD_errorFrameSizeInfo(ret);
1331        }
1332        if ret > 0 {
1333            return ZSTD_errorFrameSizeInfo(Error::srcSize_wrong.to_error_code());
1334        }
1335        ip += zfh.headerSize as usize;
1336        remainingSize = remainingSize.wrapping_sub(zfh.headerSize as size_t);
1337        loop {
1338            let mut blockProperties = blockProperties_t {
1339                blockType: BlockType::Raw,
1340                lastBlock: 0,
1341                origSize: 0,
1342            };
1343            let cBlockSize = unsafe {
1344                ZSTD_getcBlockSize(
1345                    src[ip..].as_ptr().cast(),
1346                    remainingSize,
1347                    &mut blockProperties,
1348                )
1349            };
1350            if ERR_isError(cBlockSize) {
1351                return ZSTD_errorFrameSizeInfo(cBlockSize);
1352            }
1353            if ZSTD_blockHeaderSize.wrapping_add(cBlockSize) > remainingSize {
1354                return ZSTD_errorFrameSizeInfo(Error::srcSize_wrong.to_error_code());
1355            }
1356            ip += ZSTD_blockHeaderSize.wrapping_add(cBlockSize) as usize;
1357            remainingSize =
1358                remainingSize.wrapping_sub(ZSTD_blockHeaderSize.wrapping_add(cBlockSize));
1359            nbBlocks = nbBlocks.wrapping_add(1);
1360            if blockProperties.lastBlock != 0 {
1361                break;
1362            }
1363        }
1364        if zfh.checksumFlag != 0 {
1365            if remainingSize < 4 {
1366                return ZSTD_errorFrameSizeInfo(Error::srcSize_wrong.to_error_code());
1367            }
1368            ip += 4;
1369        }
1370        frameSizeInfo.nbBlocks = nbBlocks;
1371        frameSizeInfo.compressedSize = ip as size_t;
1372        frameSizeInfo.decompressedBound = if zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN {
1373            zfh.frameContentSize
1374        } else {
1375            (nbBlocks as core::ffi::c_ulonglong)
1376                .wrapping_mul(zfh.blockSizeMax as core::ffi::c_ulonglong)
1377        };
1378        frameSizeInfo
1379    }
1380}
1381
1382fn ZSTD_findFrameCompressedSize_advanced(src: &[u8], format: Format) -> size_t {
1383    find_frame_size_info(src, format).compressedSize
1384}
1385
1386#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_findFrameCompressedSize))]
1387pub unsafe extern "C" fn ZSTD_findFrameCompressedSize(
1388    src: *const core::ffi::c_void,
1389    srcSize: size_t,
1390) -> size_t {
1391    let src = if src.is_null() {
1392        &[]
1393    } else {
1394        core::slice::from_raw_parts(src.cast(), srcSize)
1395    };
1396
1397    ZSTD_findFrameCompressedSize_advanced(src, Format::ZSTD_f_zstd1)
1398}
1399
1400#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_decompressBound))]
1401pub unsafe extern "C" fn ZSTD_decompressBound(
1402    src: *const core::ffi::c_void,
1403    srcSize: size_t,
1404) -> core::ffi::c_ulonglong {
1405    decompress_bound(if src.is_null() {
1406        &[]
1407    } else {
1408        core::slice::from_raw_parts(src.cast(), srcSize)
1409    })
1410}
1411
1412fn decompress_bound(mut src: &[u8]) -> core::ffi::c_ulonglong {
1413    let mut bound = 0;
1414
1415    while !src.is_empty() {
1416        let frameSizeInfo = find_frame_size_info(src, Format::ZSTD_f_zstd1);
1417        let compressedSize = frameSizeInfo.compressedSize;
1418        let decompressedBound = frameSizeInfo.decompressedBound;
1419        if ERR_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR {
1420            return ZSTD_CONTENTSIZE_ERROR;
1421        }
1422        src = &src[compressedSize as usize..];
1423        bound += decompressedBound;
1424    }
1425
1426    bound
1427}
1428
1429#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_decompressionMargin))]
1430pub unsafe extern "C" fn ZSTD_decompressionMargin(
1431    src: *const core::ffi::c_void,
1432    srcSize: size_t,
1433) -> size_t {
1434    decompression_margin(if src.is_null() {
1435        &[]
1436    } else {
1437        core::slice::from_raw_parts(src.cast(), srcSize)
1438    })
1439}
1440
1441fn decompression_margin(mut src: &[u8]) -> size_t {
1442    let mut margin = 0;
1443    let mut maxBlockSize = 0;
1444
1445    /* Iterate over each frame */
1446    while !src.is_empty() {
1447        let frameSizeInfo = find_frame_size_info(src, Format::ZSTD_f_zstd1);
1448        let compressedSize = frameSizeInfo.compressedSize;
1449        let decompressedBound = frameSizeInfo.decompressedBound;
1450
1451        let mut zfh = ZSTD_FrameHeader::default();
1452        let err_code = get_frame_header(&mut zfh, src);
1453        if ERR_isError(err_code) {
1454            return err_code;
1455        }
1456
1457        if ERR_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR {
1458            return Error::corruption_detected.to_error_code();
1459        }
1460
1461        if zfh.frameType as core::ffi::c_uint == ZSTD_frame as core::ffi::c_uint {
1462            /* Add the frame header to our margin */
1463            margin += zfh.headerSize as size_t;
1464            margin += if zfh.checksumFlag != 0 { 4 } else { 0 };
1465            margin += 3 * frameSizeInfo.nbBlocks;
1466            maxBlockSize = Ord::max(maxBlockSize, zfh.blockSizeMax)
1467        } else {
1468            assert!(zfh.frameType == ZSTD_skippableFrame);
1469            /* Add the entire skippable frame size to our margin. */
1470            margin += compressedSize;
1471        }
1472
1473        src = &src[compressedSize as usize..];
1474    }
1475
1476    /* Add the max block size back to the margin. */
1477    margin += maxBlockSize as size_t;
1478
1479    margin
1480}
1481
1482#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_insertBlock))]
1483pub unsafe extern "C" fn ZSTD_insertBlock(
1484    dctx: *mut ZSTD_DCtx,
1485    blockStart: *const core::ffi::c_void,
1486    blockSize: size_t,
1487) -> size_t {
1488    ZSTD_checkContinuity(dctx, blockStart, blockSize);
1489    (*dctx).previousDstEnd =
1490        (blockStart as *const core::ffi::c_char).add(blockSize) as *const core::ffi::c_void;
1491    blockSize
1492}
1493unsafe fn ZSTD_copyRawBlock(
1494    dst: *mut core::ffi::c_void,
1495    dstCapacity: size_t,
1496    src: *const core::ffi::c_void,
1497    srcSize: size_t,
1498) -> size_t {
1499    if srcSize > dstCapacity {
1500        return Error::dstSize_tooSmall.to_error_code();
1501    }
1502    if dst.is_null() {
1503        if srcSize == 0 {
1504            return 0;
1505        }
1506        return Error::dstBuffer_null.to_error_code();
1507    }
1508    libc::memmove(dst, src, srcSize as libc::size_t);
1509    srcSize
1510}
1511unsafe fn ZSTD_setRleBlock(
1512    dst: *mut core::ffi::c_void,
1513    dstCapacity: size_t,
1514    b: u8,
1515    regenSize: size_t,
1516) -> size_t {
1517    if regenSize > dstCapacity {
1518        return Error::dstSize_tooSmall.to_error_code();
1519    }
1520    if dst.is_null() {
1521        if regenSize == 0 {
1522            return 0;
1523        }
1524        return Error::dstBuffer_null.to_error_code();
1525    }
1526    ptr::write_bytes(dst, b, regenSize);
1527    regenSize
1528}
1529unsafe fn ZSTD_DCtx_trace_end(
1530    dctx: *const ZSTD_DCtx,
1531    uncompressedSize: u64,
1532    compressedSize: u64,
1533    streaming: core::ffi::c_int,
1534) {
1535    if (*dctx).traceCtx != 0 {
1536        let mut trace = ZSTD_Trace {
1537            version: 0,
1538            streaming: 0,
1539            dictionaryID: 0,
1540            dictionaryIsCold: 0,
1541            dictionarySize: 0,
1542            uncompressedSize: 0,
1543            compressedSize: 0,
1544            params: core::ptr::null::<ZSTD_CCtx_params_s>(),
1545            cctx: core::ptr::null::<ZSTD_CCtx_s>(),
1546            dctx: core::ptr::null::<ZSTD_DCtx_s>(),
1547        };
1548        ptr::write_bytes(
1549            &mut trace as *mut ZSTD_Trace as *mut u8,
1550            0,
1551            ::core::mem::size_of::<ZSTD_Trace>(),
1552        );
1553        trace.version = ZSTD_VERSION_NUMBER as core::ffi::c_uint;
1554        trace.streaming = streaming;
1555        if !((*dctx).ddict).is_null() {
1556            trace.dictionaryID = ZSTD_getDictID_fromDDict((*dctx).ddict);
1557            trace.dictionarySize = ZSTD_DDict_dictSize((*dctx).ddict);
1558            trace.dictionaryIsCold = (*dctx).ddictIsCold;
1559        }
1560        trace.uncompressedSize = uncompressedSize as size_t;
1561        trace.compressedSize = compressedSize as size_t;
1562        trace.dctx = dctx;
1563        ZSTD_trace_decompress_end((*dctx).traceCtx, &mut trace);
1564    }
1565}
1566unsafe fn ZSTD_decompressFrame(
1567    dctx: *mut ZSTD_DCtx,
1568    dst: *mut core::ffi::c_void,
1569    dstCapacity: size_t,
1570    srcPtr: &mut &[u8],
1571) -> size_t {
1572    let ilen = srcPtr.len();
1573    let ip = srcPtr;
1574    let ostart = dst as *mut u8;
1575    let oend = if dstCapacity != 0 {
1576        ostart.add(dstCapacity)
1577    } else {
1578        ostart
1579    };
1580    let mut op = ostart;
1581    if ip.len()
1582        < (match (*dctx).format {
1583            Format::ZSTD_f_zstd1 => 6usize,
1584            Format::ZSTD_f_zstd1_magicless => 2,
1585        })
1586        .wrapping_add(ZSTD_blockHeaderSize)
1587    {
1588        return Error::srcSize_wrong.to_error_code();
1589    }
1590    let frameHeaderSize = frame_header_size_internal(ip, (*dctx).format);
1591    if ERR_isError(frameHeaderSize) {
1592        return frameHeaderSize;
1593    }
1594    if ip.len() < frameHeaderSize.wrapping_add(ZSTD_blockHeaderSize) {
1595        return Error::srcSize_wrong.to_error_code();
1596    }
1597    let err_code = ZSTD_decodeFrameHeader(dctx, &ip[..frameHeaderSize]);
1598    if ERR_isError(err_code) {
1599        return err_code;
1600    }
1601    *ip = &ip[frameHeaderSize..];
1602    if (*dctx).maxBlockSizeParam != 0 {
1603        (*dctx).fParams.blockSizeMax =
1604            if (*dctx).fParams.blockSizeMax < (*dctx).maxBlockSizeParam as core::ffi::c_uint {
1605                (*dctx).fParams.blockSizeMax
1606            } else {
1607                (*dctx).maxBlockSizeParam as core::ffi::c_uint
1608            };
1609    }
1610    loop {
1611        let mut oBlockEnd = oend;
1612        let mut decodedSize: size_t = 0;
1613
1614        let (blockProperties, cBlockSize) = match getc_block_size(ip) {
1615            Ok(ret) => ret,
1616            Err(e) => return e.to_error_code(),
1617        };
1618
1619        *ip = &ip[ZSTD_blockHeaderSize..];
1620        if cBlockSize > ip.len() {
1621            return Error::srcSize_wrong.to_error_code();
1622        }
1623        if ip.as_ptr() >= op as *const u8 && ip.as_ptr() < oBlockEnd as *const u8 {
1624            oBlockEnd = op.offset(ip.as_ptr().offset_from(op) as core::ffi::c_long as isize);
1625        }
1626        match blockProperties.blockType {
1627            BlockType::Raw => {
1628                decodedSize = ZSTD_copyRawBlock(
1629                    op as *mut core::ffi::c_void,
1630                    oend.offset_from(op) as size_t,
1631                    ip.as_ptr().cast(),
1632                    cBlockSize,
1633                );
1634            }
1635            BlockType::Rle => {
1636                decodedSize = ZSTD_setRleBlock(
1637                    op as *mut core::ffi::c_void,
1638                    oBlockEnd.offset_from(op) as size_t,
1639                    ip[0],
1640                    blockProperties.origSize as size_t,
1641                );
1642            }
1643            BlockType::Compressed => {
1644                decodedSize = ZSTD_decompressBlock_internal(
1645                    dctx,
1646                    op as *mut core::ffi::c_void,
1647                    oBlockEnd.offset_from(op) as size_t,
1648                    ip.as_ptr().cast(),
1649                    cBlockSize,
1650                    not_streaming,
1651                );
1652            }
1653            BlockType::Reserved => {
1654                return Error::corruption_detected.to_error_code();
1655            }
1656        }
1657        let err_code_0 = decodedSize;
1658        if ERR_isError(err_code_0) {
1659            return err_code_0;
1660        }
1661        if (*dctx).validateChecksum != 0 {
1662            ZSTD_XXH64_update(
1663                &mut (*dctx).xxhState,
1664                op as *const core::ffi::c_void,
1665                decodedSize,
1666            );
1667        }
1668        if decodedSize != 0 {
1669            op = op.add(decodedSize);
1670        }
1671        *ip = &ip[cBlockSize..];
1672        if blockProperties.lastBlock != 0 {
1673            break;
1674        }
1675    }
1676    if (*dctx).fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
1677        && op.offset_from(ostart) as core::ffi::c_long as u64 as core::ffi::c_ulonglong
1678            != (*dctx).fParams.frameContentSize
1679    {
1680        return Error::corruption_detected.to_error_code();
1681    }
1682    if (*dctx).fParams.checksumFlag != 0 {
1683        let [a, b, c, d, ..] = **ip else {
1684            return Error::checksum_wrong.to_error_code();
1685        };
1686
1687        if (*dctx).forceIgnoreChecksum == 0 {
1688            if u32::from_le_bytes([a, b, c, d]) != ZSTD_XXH64_digest(&mut (*dctx).xxhState) as u32 {
1689                return Error::checksum_wrong.to_error_code();
1690            }
1691        }
1692
1693        *ip = &ip[4..];
1694    }
1695
1696    ZSTD_DCtx_trace_end(
1697        dctx,
1698        op.offset_from(ostart) as core::ffi::c_long as u64,
1699        (ilen - ip.len()) as u64,
1700        0,
1701    );
1702
1703    op.offset_from(ostart) as size_t
1704}
1705
1706unsafe fn ZSTD_decompressMultiFrame(
1707    dctx: *mut ZSTD_DCtx,
1708    mut dst: *mut core::ffi::c_void,
1709    mut dstCapacity: size_t,
1710    mut src: &[u8],
1711    mut dict: *const core::ffi::c_void,
1712    mut dictSize: size_t,
1713    ddict: Option<&ZSTD_DDict>,
1714) -> size_t {
1715    let dststart = dst;
1716    let mut more_than_one_frame = false;
1717
1718    if let Some(ddict) = ddict {
1719        dict = ZSTD_DDict_dictContent(ddict);
1720        dictSize = ZSTD_DDict_dictSize(ddict);
1721    }
1722
1723    while src.len() >= ZSTD_startingInputLength((*dctx).format) {
1724        if (*dctx).format == Format::ZSTD_f_zstd1 && is_legacy(src) != 0 {
1725            let frameSize;
1726            {
1727                let srcSize = src.len();
1728                let src = src.as_ptr().cast();
1729
1730                let mut decodedSize: size_t = 0;
1731                frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize);
1732                if ERR_isError(frameSize) {
1733                    return frameSize;
1734                }
1735                if (*dctx).staticSize != 0 {
1736                    return Error::memory_allocation.to_error_code();
1737                }
1738                decodedSize =
1739                    ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize);
1740                if ERR_isError(decodedSize) {
1741                    return decodedSize;
1742                }
1743                let expectedSize = ZSTD_getFrameContentSize(src, srcSize);
1744                if expectedSize == ZSTD_CONTENTSIZE_ERROR {
1745                    return Error::corruption_detected.to_error_code();
1746                }
1747                if expectedSize != ZSTD_CONTENTSIZE_UNKNOWN
1748                    && expectedSize != decodedSize as core::ffi::c_ulonglong
1749                {
1750                    return Error::corruption_detected.to_error_code();
1751                }
1752                dst = (dst as *mut u8).add(decodedSize) as *mut core::ffi::c_void;
1753                dstCapacity = dstCapacity.wrapping_sub(decodedSize);
1754            }
1755            src = &src[frameSize..];
1756        } else {
1757            if (*dctx).format == Format::ZSTD_f_zstd1 && src.len() >= 4 {
1758                let magicNumber = u32::from_le_bytes(*src.first_chunk().unwrap());
1759                if magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK
1760                    == ZSTD_MAGIC_SKIPPABLE_START as core::ffi::c_uint
1761                {
1762                    let skippableSize = read_skippable_frame_size(src);
1763                    let err_code = skippableSize;
1764                    if ERR_isError(err_code) {
1765                        return err_code;
1766                    }
1767                    src = &src[skippableSize..];
1768                    continue;
1769                }
1770            }
1771            if let Some(ddict) = ddict {
1772                let err_code_0 = ZSTD_decompressBegin_usingDDict(dctx, ddict);
1773                if ERR_isError(err_code_0) {
1774                    return err_code_0;
1775                }
1776            } else {
1777                let err_code_1 = ZSTD_decompressBegin_usingDict(dctx, dict, dictSize);
1778                if ERR_isError(err_code_1) {
1779                    return err_code_1;
1780                }
1781            }
1782            ZSTD_checkContinuity(dctx, dst, dstCapacity);
1783            let res = ZSTD_decompressFrame(dctx, dst, dstCapacity, &mut src);
1784            if ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown && more_than_one_frame {
1785                return Error::srcSize_wrong.to_error_code();
1786            }
1787            if ERR_isError(res) {
1788                return res;
1789            }
1790            if res != 0 {
1791                dst = (dst as *mut u8).add(res) as *mut core::ffi::c_void;
1792            }
1793            dstCapacity = dstCapacity.wrapping_sub(res);
1794            more_than_one_frame = true;
1795        }
1796    }
1797
1798    if !src.is_empty() {
1799        return Error::srcSize_wrong.to_error_code();
1800    }
1801
1802    (dst as *mut u8).offset_from(dststart as *mut u8) as size_t
1803}
1804
1805#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_decompress_usingDict))]
1806pub unsafe extern "C" fn ZSTD_decompress_usingDict(
1807    dctx: *mut ZSTD_DCtx,
1808    dst: *mut core::ffi::c_void,
1809    dstCapacity: size_t,
1810    src: *const core::ffi::c_void,
1811    srcSize: size_t,
1812    dict: *const core::ffi::c_void,
1813    dictSize: size_t,
1814) -> size_t {
1815    let src = if src.is_null() {
1816        &[]
1817    } else {
1818        core::slice::from_raw_parts(src.cast::<u8>(), srcSize)
1819    };
1820    ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, dict, dictSize, None)
1821}
1822
1823unsafe fn ZSTD_getDDict(dctx: *mut ZSTD_DCtx) -> *const ZSTD_DDict {
1824    match (*dctx).dictUses as core::ffi::c_int {
1825        -1 => (*dctx).ddict,
1826        1 => {
1827            (*dctx).dictUses = ZSTD_dont_use;
1828            (*dctx).ddict
1829        }
1830        0 | _ => {
1831            ZSTD_clearDict(dctx);
1832            core::ptr::null()
1833        }
1834    }
1835}
1836
1837#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_decompressDCtx))]
1838pub unsafe extern "C" fn ZSTD_decompressDCtx(
1839    dctx: *mut ZSTD_DCtx,
1840    dst: *mut core::ffi::c_void,
1841    dstCapacity: size_t,
1842    src: *const core::ffi::c_void,
1843    srcSize: size_t,
1844) -> size_t {
1845    ZSTD_decompress_usingDDict(dctx, dst, dstCapacity, src, srcSize, ZSTD_getDDict(dctx))
1846}
1847
1848#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_decompress))]
1849pub unsafe extern "C" fn ZSTD_decompress(
1850    dst: *mut core::ffi::c_void,
1851    dstCapacity: size_t,
1852    src: *const core::ffi::c_void,
1853    srcSize: size_t,
1854) -> size_t {
1855    let mut regenSize: size_t = 0;
1856    let dctx = ZSTD_createDCtx_internal(ZSTD_defaultCMem);
1857    if dctx.is_null() {
1858        return Error::memory_allocation.to_error_code();
1859    }
1860    regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize);
1861    ZSTD_freeDCtx(dctx);
1862    regenSize
1863}
1864
1865#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_nextSrcSizeToDecompress))]
1866pub unsafe extern "C" fn ZSTD_nextSrcSizeToDecompress(dctx: *mut ZSTD_DCtx) -> size_t {
1867    (*dctx).expected
1868}
1869
1870unsafe fn ZSTD_nextSrcSizeToDecompressWithInputSize(
1871    dctx: *mut ZSTD_DCtx,
1872    inputSize: size_t,
1873) -> size_t {
1874    match (*dctx).stage {
1875        DecompressStage::DecompressBlock | DecompressStage::DecompressLastBlock => {
1876            Ord::clamp(1, inputSize, (*dctx).expected)
1877        }
1878        _ => (*dctx).expected,
1879    }
1880}
1881
1882#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_nextInputType))]
1883pub unsafe extern "C" fn ZSTD_nextInputType(dctx: *mut ZSTD_DCtx) -> ZSTD_nextInputType_e {
1884    (*dctx).stage.to_next_input_type() as ZSTD_nextInputType_e
1885}
1886
1887unsafe fn ZSTD_isSkipFrame(dctx: *mut ZSTD_DCtx) -> core::ffi::c_int {
1888    matches!((*dctx).stage, DecompressStage::SkipFrame) as core::ffi::c_int
1889}
1890
1891#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_decompressContinue))]
1892pub unsafe extern "C" fn ZSTD_decompressContinue(
1893    dctx: *mut ZSTD_DCtx,
1894    dst: *mut core::ffi::c_void,
1895    dstCapacity: size_t,
1896    src: *const core::ffi::c_void,
1897    srcSize: size_t,
1898) -> size_t {
1899    if srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize) {
1900        return Error::srcSize_wrong.to_error_code();
1901    }
1902    ZSTD_checkContinuity(dctx, dst, dstCapacity);
1903    (*dctx).processedCSize = ((*dctx).processedCSize as size_t).wrapping_add(srcSize) as u64;
1904    match (*dctx).stage {
1905        DecompressStage::GetFrameHeaderSize => {
1906            if (*dctx).format == Format::ZSTD_f_zstd1
1907                && MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK
1908                    == ZSTD_MAGIC_SKIPPABLE_START as core::ffi::c_uint
1909            {
1910                libc::memcpy(
1911                    ((*dctx).headerBuffer).as_mut_ptr() as *mut core::ffi::c_void,
1912                    src,
1913                    srcSize as libc::size_t,
1914                );
1915                (*dctx).expected = (ZSTD_SKIPPABLEHEADERSIZE as size_t).wrapping_sub(srcSize);
1916                (*dctx).stage = DecompressStage::DecodeSkippableHeader;
1917                return 0;
1918            }
1919            let src_slice = core::slice::from_raw_parts(src.cast(), srcSize);
1920            (*dctx).headerSize = frame_header_size_internal(src_slice, (*dctx).format);
1921            if ERR_isError((*dctx).headerSize) {
1922                return (*dctx).headerSize;
1923            }
1924            libc::memcpy(
1925                ((*dctx).headerBuffer).as_mut_ptr() as *mut core::ffi::c_void,
1926                src,
1927                srcSize as libc::size_t,
1928            );
1929            (*dctx).expected = ((*dctx).headerSize).wrapping_sub(srcSize);
1930            (*dctx).stage = DecompressStage::DecodeFrameHeader;
1931            0
1932        }
1933        DecompressStage::DecodeFrameHeader => {
1934            libc::memcpy(
1935                ((*dctx).headerBuffer)
1936                    .as_mut_ptr()
1937                    .add(((*dctx).headerSize).wrapping_sub(srcSize))
1938                    as *mut core::ffi::c_void,
1939                src,
1940                srcSize as libc::size_t,
1941            );
1942            let err_code =
1943                ZSTD_decodeFrameHeader(dctx, &(&(*dctx).headerBuffer)[..(*dctx).headerSize]);
1944            if ERR_isError(err_code) {
1945                return err_code;
1946            }
1947            (*dctx).expected = ZSTD_blockHeaderSize;
1948            (*dctx).stage = DecompressStage::DecodeBlockHeader;
1949            0
1950        }
1951        DecompressStage::DecodeBlockHeader => {
1952            let mut bp = blockProperties_t {
1953                blockType: BlockType::Raw,
1954                lastBlock: 0,
1955                origSize: 0,
1956            };
1957            let cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &mut bp);
1958            if ERR_isError(cBlockSize) {
1959                return cBlockSize;
1960            }
1961            if cBlockSize > (*dctx).fParams.blockSizeMax as size_t {
1962                return Error::corruption_detected.to_error_code();
1963            }
1964            (*dctx).expected = cBlockSize;
1965            (*dctx).bType = bp.blockType;
1966            (*dctx).rleSize = bp.origSize as size_t;
1967            if cBlockSize != 0 {
1968                (*dctx).stage = match bp.lastBlock {
1969                    0 => DecompressStage::DecompressBlock,
1970                    _ => DecompressStage::DecompressLastBlock,
1971                };
1972                return 0;
1973            }
1974            if bp.lastBlock != 0 {
1975                if (*dctx).fParams.checksumFlag != 0 {
1976                    (*dctx).expected = 4;
1977                    (*dctx).stage = DecompressStage::CheckChecksum;
1978                } else {
1979                    (*dctx).expected = 0;
1980                    (*dctx).stage = DecompressStage::GetFrameHeaderSize;
1981                }
1982            } else {
1983                (*dctx).expected = ZSTD_blockHeaderSize;
1984                (*dctx).stage = DecompressStage::DecodeBlockHeader;
1985            }
1986            0
1987        }
1988
1989        DecompressStage::DecompressBlock | DecompressStage::DecompressLastBlock => {
1990            let mut rSize: size_t = 0;
1991            match (*dctx).bType {
1992                BlockType::Compressed => {
1993                    rSize = ZSTD_decompressBlock_internal(
1994                        dctx,
1995                        dst,
1996                        dstCapacity,
1997                        src,
1998                        srcSize,
1999                        is_streaming,
2000                    );
2001                    (*dctx).expected = 0;
2002                }
2003                BlockType::Raw => {
2004                    rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize);
2005                    let err_code_0 = rSize;
2006                    if ERR_isError(err_code_0) {
2007                        return err_code_0;
2008                    }
2009                    (*dctx).expected = ((*dctx).expected).wrapping_sub(rSize);
2010                }
2011                BlockType::Rle => {
2012                    rSize =
2013                        ZSTD_setRleBlock(dst, dstCapacity, *(src as *const u8), (*dctx).rleSize);
2014                    (*dctx).expected = 0;
2015                }
2016                BlockType::Reserved => {
2017                    return Error::corruption_detected.to_error_code();
2018                }
2019            }
2020            let err_code_1 = rSize;
2021            if ERR_isError(err_code_1) {
2022                return err_code_1;
2023            }
2024            if rSize > (*dctx).fParams.blockSizeMax as size_t {
2025                return Error::corruption_detected.to_error_code();
2026            }
2027            (*dctx).decodedSize = ((*dctx).decodedSize as size_t).wrapping_add(rSize) as u64 as u64;
2028            if (*dctx).validateChecksum != 0 {
2029                ZSTD_XXH64_update(&mut (*dctx).xxhState, dst, rSize as usize);
2030            }
2031            (*dctx).previousDstEnd =
2032                (dst as *mut core::ffi::c_char).add(rSize) as *const core::ffi::c_void;
2033            if (*dctx).expected > 0 {
2034                return rSize;
2035            }
2036            if (*dctx).stage == DecompressStage::DecompressLastBlock {
2037                if (*dctx).fParams.frameContentSize != (0 as core::ffi::c_ulonglong).wrapping_sub(1)
2038                    && (*dctx).decodedSize as core::ffi::c_ulonglong
2039                        != (*dctx).fParams.frameContentSize
2040                {
2041                    return Error::corruption_detected.to_error_code();
2042                }
2043                if (*dctx).fParams.checksumFlag != 0 {
2044                    (*dctx).expected = 4;
2045                    (*dctx).stage = DecompressStage::CheckChecksum;
2046                } else {
2047                    ZSTD_DCtx_trace_end(dctx, (*dctx).decodedSize, (*dctx).processedCSize, 1);
2048                    (*dctx).expected = 0;
2049                    (*dctx).stage = DecompressStage::GetFrameHeaderSize;
2050                }
2051            } else {
2052                (*dctx).stage = DecompressStage::DecodeBlockHeader;
2053                (*dctx).expected = ZSTD_blockHeaderSize;
2054            }
2055            rSize
2056        }
2057        DecompressStage::CheckChecksum => {
2058            if (*dctx).validateChecksum != 0 {
2059                let h32 = ZSTD_XXH64_digest(&mut (*dctx).xxhState) as u32;
2060                let check32 = MEM_readLE32(src);
2061                if check32 != h32 {
2062                    return Error::checksum_wrong.to_error_code();
2063                }
2064            }
2065            ZSTD_DCtx_trace_end(dctx, (*dctx).decodedSize, (*dctx).processedCSize, 1);
2066            (*dctx).expected = 0;
2067            (*dctx).stage = DecompressStage::GetFrameHeaderSize;
2068            0
2069        }
2070        DecompressStage::DecodeSkippableHeader => {
2071            libc::memcpy(
2072                ((*dctx).headerBuffer)
2073                    .as_mut_ptr()
2074                    .add((8 as size_t).wrapping_sub(srcSize))
2075                    as *mut core::ffi::c_void,
2076                src,
2077                srcSize as libc::size_t,
2078            );
2079            (*dctx).expected =
2080                MEM_readLE32(((*dctx).headerBuffer).as_mut_ptr().add(ZSTD_FRAMEIDSIZE)
2081                    as *const core::ffi::c_void) as size_t;
2082            (*dctx).stage = DecompressStage::SkipFrame;
2083            0
2084        }
2085        DecompressStage::SkipFrame => {
2086            (*dctx).expected = 0;
2087            (*dctx).stage = DecompressStage::GetFrameHeaderSize;
2088            0
2089        }
2090    }
2091}
2092
2093pub unsafe fn ZSTD_loadDEntropy(entropy: &mut ZSTD_entropyDTables_t, dict: &[u8]) -> size_t {
2094    let Some((_, mut dictPtr)) = dict.split_at_checked(8) else {
2095        return Error::dictionary_corrupted.to_error_code();
2096    };
2097
2098    const _: () = assert!(
2099        size_of::<crate::lib::decompress::SymbolTable<512>>()
2100            >= size_of::<HUF_ReadDTableX2_Workspace>()
2101    );
2102    const _: () = assert!(
2103        align_of::<crate::lib::decompress::SymbolTable<512>>()
2104            >= align_of::<HUF_ReadDTableX2_Workspace>()
2105    );
2106
2107    let workspace = &mut entropy.LLTable;
2108    let wksp: &mut HUF_ReadDTableX2_Workspace = unsafe { core::mem::transmute(workspace) };
2109
2110    let hSize = HUF_readDTableX2_wksp(&mut entropy.hufTable, dictPtr, wksp, 0);
2111    if ERR_isError(hSize) {
2112        return Error::dictionary_corrupted.to_error_code();
2113    }
2114
2115    dictPtr = &dictPtr[hSize..];
2116    let mut offcodeNCount: [core::ffi::c_short; 32] = [0; 32];
2117    let mut offcodeMaxValue = MaxOff as core::ffi::c_uint;
2118    let mut offcodeLog: core::ffi::c_uint = 0;
2119    let offcodeHeaderSize = FSE_readNCount_slice(
2120        &mut offcodeNCount,
2121        &mut offcodeMaxValue,
2122        &mut offcodeLog,
2123        dictPtr,
2124    );
2125
2126    let Ok(offcodeHeaderSize) = offcodeHeaderSize else {
2127        return Error::dictionary_corrupted.to_error_code();
2128    };
2129    if offcodeMaxValue > 31 {
2130        return Error::dictionary_corrupted.to_error_code();
2131    }
2132    if offcodeLog > 8 {
2133        return Error::dictionary_corrupted.to_error_code();
2134    }
2135    ZSTD_buildFSETable(
2136        &mut entropy.OFTable,
2137        &offcodeNCount[..=offcodeMaxValue as usize],
2138        &OF_base,
2139        &OF_bits,
2140        offcodeLog,
2141        &mut entropy.workspace,
2142        false,
2143    );
2144    dictPtr = &dictPtr[offcodeHeaderSize..];
2145    let mut matchlengthNCount: [core::ffi::c_short; 53] = [0; 53];
2146    let mut matchlengthMaxValue = MaxML as core::ffi::c_uint;
2147    let mut matchlengthLog: core::ffi::c_uint = 0;
2148    let matchlengthHeaderSize = FSE_readNCount_slice(
2149        &mut matchlengthNCount,
2150        &mut matchlengthMaxValue,
2151        &mut matchlengthLog,
2152        dictPtr,
2153    );
2154    let Ok(matchlengthHeaderSize) = matchlengthHeaderSize else {
2155        return Error::dictionary_corrupted.to_error_code();
2156    };
2157    if matchlengthMaxValue > 52 {
2158        return Error::dictionary_corrupted.to_error_code();
2159    }
2160    if matchlengthLog > 9 {
2161        return Error::dictionary_corrupted.to_error_code();
2162    }
2163    ZSTD_buildFSETable(
2164        &mut entropy.MLTable,
2165        &matchlengthNCount[..=matchlengthMaxValue as usize],
2166        &ML_base,
2167        &ML_bits,
2168        matchlengthLog,
2169        &mut entropy.workspace,
2170        false,
2171    );
2172    dictPtr = &dictPtr[matchlengthHeaderSize..];
2173    let mut litlengthNCount: [core::ffi::c_short; 36] = [0; 36];
2174    let mut litlengthMaxValue = MaxLL as core::ffi::c_uint;
2175    let mut litlengthLog: core::ffi::c_uint = 0;
2176    let litlengthHeaderSize = FSE_readNCount_slice(
2177        &mut litlengthNCount,
2178        &mut litlengthMaxValue,
2179        &mut litlengthLog,
2180        dictPtr,
2181    );
2182    let Ok(litlengthHeaderSize) = litlengthHeaderSize else {
2183        return Error::dictionary_corrupted.to_error_code();
2184    };
2185    if litlengthMaxValue > 35 {
2186        return Error::dictionary_corrupted.to_error_code();
2187    }
2188    if litlengthLog > 9 {
2189        return Error::dictionary_corrupted.to_error_code();
2190    }
2191    ZSTD_buildFSETable(
2192        &mut entropy.LLTable,
2193        &litlengthNCount[..=litlengthMaxValue as usize],
2194        &LL_base,
2195        &LL_bits,
2196        litlengthLog,
2197        &mut entropy.workspace,
2198        false,
2199    );
2200    dictPtr = &dictPtr[litlengthHeaderSize..];
2201    let Some((chunk, dict_content)) = dictPtr.split_first_chunk::<12>() else {
2202        return Error::dictionary_corrupted.to_error_code();
2203    };
2204
2205    let dict_content_size = dict_content.len();
2206    for (i, rep) in chunk.as_chunks::<4>().0.iter().enumerate() {
2207        let rep = u32::from_le_bytes(*rep);
2208        if rep == 0 || rep as size_t > dict_content_size {
2209            return Error::dictionary_corrupted.to_error_code();
2210        }
2211        entropy.rep[i] = rep;
2212    }
2213
2214    dict.len() - dict_content_size
2215}
2216
2217unsafe fn ZSTD_refDictContent(dctx: *mut ZSTD_DCtx, dict: &[u8]) -> size_t {
2218    (*dctx).dictEnd = (*dctx).previousDstEnd;
2219    (*dctx).virtualStart = dict
2220        .as_ptr()
2221        .sub((((*dctx).previousDstEnd).byte_offset_from((*dctx).prefixStart)) as usize)
2222        .cast();
2223    (*dctx).prefixStart = dict.as_ptr().cast();
2224    (*dctx).previousDstEnd = dict.as_ptr_range().end.cast();
2225
2226    0
2227}
2228
2229unsafe fn ZSTD_decompress_insertDictionary(dctx: *mut ZSTD_DCtx, dict: &[u8]) -> size_t {
2230    let ([magic, dict_id, ..], _) = dict.as_chunks::<4>() else {
2231        return ZSTD_refDictContent(dctx, dict);
2232    };
2233
2234    let magic = u32::from_le_bytes(*magic);
2235    if magic != ZSTD_MAGIC_DICTIONARY {
2236        return ZSTD_refDictContent(dctx, dict);
2237    }
2238    (*dctx).dictID = u32::from_le_bytes(*dict_id);
2239    let eSize = ZSTD_loadDEntropy(&mut (*dctx).entropy, dict);
2240    if ERR_isError(eSize) {
2241        return Error::dictionary_corrupted.to_error_code();
2242    }
2243
2244    (*dctx).fseEntropy = 1;
2245    (*dctx).litEntropy = (*dctx).fseEntropy;
2246
2247    ZSTD_refDictContent(dctx, &dict[eSize..])
2248}
2249
2250#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_decompressBegin))]
2251pub unsafe extern "C" fn ZSTD_decompressBegin(dctx: *mut ZSTD_DCtx) -> size_t {
2252    (*dctx).traceCtx = ZSTD_trace_decompress_begin(dctx);
2253    (*dctx).expected = ZSTD_startingInputLength((*dctx).format);
2254    (*dctx).stage = DecompressStage::GetFrameHeaderSize;
2255    (*dctx).processedCSize = 0;
2256    (*dctx).decodedSize = 0;
2257    (*dctx).previousDstEnd = core::ptr::null();
2258    (*dctx).prefixStart = core::ptr::null();
2259    (*dctx).virtualStart = core::ptr::null();
2260    (*dctx).dictEnd = core::ptr::null();
2261    (*dctx).entropy.hufTable.description = DTableDesc::from_u32(12 * 0x1000001);
2262    (*dctx).fseEntropy = 0;
2263    (*dctx).litEntropy = (*dctx).fseEntropy;
2264    (*dctx).dictID = 0;
2265    (*dctx).bType = BlockType::Reserved;
2266    (*dctx).isFrameDecompression = 1;
2267    libc::memcpy(
2268        ((*dctx).entropy.rep).as_mut_ptr() as *mut core::ffi::c_void,
2269        repStartValue.as_ptr() as *const core::ffi::c_void,
2270        ::core::mem::size_of::<[u32; 3]>() as libc::size_t,
2271    );
2272    (*dctx).LLTptr = ((*dctx).entropy.LLTable).as_mut_ptr();
2273    (*dctx).MLTptr = ((*dctx).entropy.MLTable).as_mut_ptr();
2274    (*dctx).OFTptr = ((*dctx).entropy.OFTable).as_mut_ptr();
2275    (*dctx).HUFptr = &raw const (*dctx).entropy.hufTable;
2276    0
2277}
2278
2279#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_decompressBegin_usingDict))]
2280pub unsafe extern "C" fn ZSTD_decompressBegin_usingDict(
2281    dctx: *mut ZSTD_DCtx,
2282    dict: *const core::ffi::c_void,
2283    dictSize: size_t,
2284) -> size_t {
2285    let err_code = ZSTD_decompressBegin(dctx);
2286    if ERR_isError(err_code) {
2287        return err_code;
2288    }
2289
2290    if dict.is_null() || dictSize == 0 {
2291        return 0;
2292    }
2293
2294    let dict = core::slice::from_raw_parts(dict.cast::<u8>(), dictSize);
2295    if ERR_isError(ZSTD_decompress_insertDictionary(dctx, dict)) {
2296        return Error::dictionary_corrupted.to_error_code();
2297    }
2298
2299    0
2300}
2301
2302#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_decompressBegin_usingDDict))]
2303pub unsafe extern "C" fn ZSTD_decompressBegin_usingDDict(
2304    dctx: *mut ZSTD_DCtx,
2305    ddict: *const ZSTD_DDict,
2306) -> size_t {
2307    if !ddict.is_null() {
2308        let dictStart = ZSTD_DDict_dictContent(ddict) as *const core::ffi::c_char;
2309        let dictSize = ZSTD_DDict_dictSize(ddict);
2310        let dictEnd = dictStart.add(dictSize) as *const core::ffi::c_void;
2311        (*dctx).ddictIsCold = ((*dctx).dictEnd != dictEnd) as core::ffi::c_int;
2312    }
2313    let err_code = ZSTD_decompressBegin(dctx);
2314    if ERR_isError(err_code) {
2315        return err_code;
2316    }
2317    if !ddict.is_null() {
2318        ZSTD_copyDDictParameters(dctx, ddict);
2319    }
2320    0
2321}
2322#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_getDictID_fromDict))]
2323pub unsafe extern "C" fn ZSTD_getDictID_fromDict(
2324    dict: *const core::ffi::c_void,
2325    dictSize: size_t,
2326) -> core::ffi::c_uint {
2327    if dictSize < 8 {
2328        return 0;
2329    }
2330    if MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY {
2331        return 0;
2332    }
2333    MEM_readLE32(
2334        (dict as *const core::ffi::c_char).add(ZSTD_FRAMEIDSIZE) as *const core::ffi::c_void
2335    )
2336}
2337#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_getDictID_fromFrame))]
2338pub unsafe extern "C" fn ZSTD_getDictID_fromFrame(
2339    src: *const core::ffi::c_void,
2340    srcSize: size_t,
2341) -> core::ffi::c_uint {
2342    let mut zfp = {
2343        ZSTD_FrameHeader {
2344            frameContentSize: 0,
2345            windowSize: 0,
2346            blockSizeMax: 0,
2347            frameType: ZSTD_frame,
2348            headerSize: 0,
2349            dictID: 0,
2350            checksumFlag: 0,
2351            _reserved1: 0,
2352            _reserved2: 0,
2353        }
2354    };
2355    let hError = ZSTD_getFrameHeader(&mut zfp, src, srcSize);
2356    if ERR_isError(hError) {
2357        return 0;
2358    }
2359    zfp.dictID
2360}
2361
2362#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_decompress_usingDDict))]
2363pub unsafe extern "C" fn ZSTD_decompress_usingDDict(
2364    dctx: *mut ZSTD_DCtx,
2365    dst: *mut core::ffi::c_void,
2366    dstCapacity: size_t,
2367    src: *const core::ffi::c_void,
2368    srcSize: size_t,
2369    ddict: *const ZSTD_DDict,
2370) -> size_t {
2371    let src = if src.is_null() {
2372        &[]
2373    } else {
2374        core::slice::from_raw_parts(src.cast::<u8>(), srcSize)
2375    };
2376
2377    ZSTD_decompressMultiFrame(
2378        dctx,
2379        dst,
2380        dstCapacity,
2381        src,
2382        core::ptr::null(),
2383        0,
2384        ddict.as_ref(),
2385    )
2386}
2387
2388#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_createDStream))]
2389pub unsafe extern "C" fn ZSTD_createDStream() -> *mut ZSTD_DStream {
2390    ZSTD_createDCtx_internal(ZSTD_defaultCMem)
2391}
2392#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_initStaticDStream))]
2393pub unsafe extern "C" fn ZSTD_initStaticDStream(
2394    workspace: *mut core::ffi::c_void,
2395    workspaceSize: size_t,
2396) -> *mut ZSTD_DStream {
2397    ZSTD_initStaticDCtx(workspace, workspaceSize)
2398}
2399#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_createDStream_advanced))]
2400pub unsafe extern "C" fn ZSTD_createDStream_advanced(
2401    customMem: ZSTD_customMem,
2402) -> *mut ZSTD_DStream {
2403    ZSTD_createDCtx_internal(customMem)
2404}
2405#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_freeDStream))]
2406pub unsafe extern "C" fn ZSTD_freeDStream(zds: *mut ZSTD_DStream) -> size_t {
2407    ZSTD_freeDCtx(zds)
2408}
2409#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_DStreamInSize))]
2410pub unsafe extern "C" fn ZSTD_DStreamInSize() -> size_t {
2411    (ZSTD_BLOCKSIZE_MAX as size_t).wrapping_add(ZSTD_blockHeaderSize)
2412}
2413#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_DStreamOutSize))]
2414pub unsafe extern "C" fn ZSTD_DStreamOutSize() -> size_t {
2415    ZSTD_BLOCKSIZE_MAX as size_t
2416}
2417#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_DCtx_loadDictionary_advanced))]
2418pub unsafe extern "C" fn ZSTD_DCtx_loadDictionary_advanced(
2419    dctx: *mut ZSTD_DCtx,
2420    dict: *const core::ffi::c_void,
2421    dictSize: size_t,
2422    dictLoadMethod: ZSTD_dictLoadMethod_e,
2423    dictContentType: ZSTD_dictContentType_e,
2424) -> size_t {
2425    if (*dctx).streamStage != StreamStage::Init {
2426        return Error::stage_wrong.to_error_code();
2427    }
2428    ZSTD_clearDict(dctx);
2429    if !dict.is_null() && dictSize != 0 {
2430        (*dctx).ddictLocal = ZSTD_createDDict_advanced(
2431            dict,
2432            dictSize,
2433            dictLoadMethod,
2434            dictContentType,
2435            (*dctx).customMem,
2436        );
2437        if ((*dctx).ddictLocal).is_null() {
2438            return Error::memory_allocation.to_error_code();
2439        }
2440        (*dctx).ddict = (*dctx).ddictLocal;
2441        (*dctx).dictUses = ZSTD_use_indefinitely;
2442    }
2443    0
2444}
2445#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_DCtx_loadDictionary_byReference))]
2446pub unsafe extern "C" fn ZSTD_DCtx_loadDictionary_byReference(
2447    dctx: *mut ZSTD_DCtx,
2448    dict: *const core::ffi::c_void,
2449    dictSize: size_t,
2450) -> size_t {
2451    ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto)
2452}
2453#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_DCtx_loadDictionary))]
2454pub unsafe extern "C" fn ZSTD_DCtx_loadDictionary(
2455    dctx: *mut ZSTD_DCtx,
2456    dict: *const core::ffi::c_void,
2457    dictSize: size_t,
2458) -> size_t {
2459    ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto)
2460}
2461#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_DCtx_refPrefix_advanced))]
2462pub unsafe extern "C" fn ZSTD_DCtx_refPrefix_advanced(
2463    dctx: *mut ZSTD_DCtx,
2464    prefix: *const core::ffi::c_void,
2465    prefixSize: size_t,
2466    dictContentType: ZSTD_dictContentType_e,
2467) -> size_t {
2468    let err_code = ZSTD_DCtx_loadDictionary_advanced(
2469        dctx,
2470        prefix,
2471        prefixSize,
2472        ZSTD_dlm_byRef,
2473        dictContentType,
2474    );
2475    if ERR_isError(err_code) {
2476        return err_code;
2477    }
2478    (*dctx).dictUses = ZSTD_use_once;
2479    0
2480}
2481#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_DCtx_refPrefix))]
2482pub unsafe extern "C" fn ZSTD_DCtx_refPrefix(
2483    dctx: *mut ZSTD_DCtx,
2484    prefix: *const core::ffi::c_void,
2485    prefixSize: size_t,
2486) -> size_t {
2487    ZSTD_DCtx_refPrefix_advanced(dctx, prefix, prefixSize, ZSTD_dct_rawContent)
2488}
2489#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_initDStream_usingDict))]
2490pub unsafe extern "C" fn ZSTD_initDStream_usingDict(
2491    zds: *mut ZSTD_DStream,
2492    dict: *const core::ffi::c_void,
2493    dictSize: size_t,
2494) -> size_t {
2495    let err_code = ZSTD_DCtx_reset(zds, ZSTD_reset_session_only);
2496    if ERR_isError(err_code) {
2497        return err_code;
2498    }
2499    let err_code_0 = ZSTD_DCtx_loadDictionary(zds, dict, dictSize);
2500    if ERR_isError(err_code_0) {
2501        return err_code_0;
2502    }
2503    ZSTD_startingInputLength((*zds).format)
2504}
2505#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_initDStream))]
2506pub unsafe extern "C" fn ZSTD_initDStream(zds: *mut ZSTD_DStream) -> size_t {
2507    let err_code = ZSTD_DCtx_reset(zds, ZSTD_reset_session_only);
2508    if ERR_isError(err_code) {
2509        return err_code;
2510    }
2511    let err_code_0 = ZSTD_DCtx_refDDict(zds, core::ptr::null::<ZSTD_DDict>());
2512    if ERR_isError(err_code_0) {
2513        return err_code_0;
2514    }
2515    ZSTD_startingInputLength((*zds).format)
2516}
2517#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_initDStream_usingDDict))]
2518pub unsafe extern "C" fn ZSTD_initDStream_usingDDict(
2519    dctx: *mut ZSTD_DStream,
2520    ddict: *const ZSTD_DDict,
2521) -> size_t {
2522    let err_code = ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
2523    if ERR_isError(err_code) {
2524        return err_code;
2525    }
2526    let err_code_0 = ZSTD_DCtx_refDDict(dctx, ddict);
2527    if ERR_isError(err_code_0) {
2528        return err_code_0;
2529    }
2530    ZSTD_startingInputLength((*dctx).format)
2531}
2532#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_resetDStream))]
2533pub unsafe extern "C" fn ZSTD_resetDStream(dctx: *mut ZSTD_DStream) -> size_t {
2534    let err_code = ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
2535    if ERR_isError(err_code) {
2536        return err_code;
2537    }
2538    ZSTD_startingInputLength((*dctx).format)
2539}
2540
2541#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_DCtx_refDDict))]
2542pub unsafe extern "C" fn ZSTD_DCtx_refDDict(
2543    dctx: *mut ZSTD_DCtx,
2544    ddict: *const ZSTD_DDict,
2545) -> size_t {
2546    if (*dctx).streamStage != StreamStage::Init {
2547        return Error::stage_wrong.to_error_code();
2548    }
2549    ZSTD_clearDict(dctx);
2550
2551    if !ddict.is_null() {
2552        (*dctx).ddict = ddict;
2553        (*dctx).dictUses = ZSTD_use_indefinitely;
2554        if (*dctx).refMultipleDDicts == MultipleDDicts::Multiple {
2555            if ((*dctx).ddictSet).is_null() {
2556                (*dctx).ddictSet = ZSTD_createDDictHashSet((*dctx).customMem);
2557            }
2558
2559            let Some(ddictSet) = (*dctx).ddictSet.as_mut() else {
2560                return Error::memory_allocation.to_error_code();
2561            };
2562
2563            let err_code = ZSTD_DDictHashSet_addDDict(ddictSet, ddict, (*dctx).customMem);
2564            if ERR_isError(err_code) {
2565                return err_code;
2566            }
2567        }
2568    }
2569
2570    0
2571}
2572
2573#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_DCtx_setMaxWindowSize))]
2574pub unsafe extern "C" fn ZSTD_DCtx_setMaxWindowSize(
2575    dctx: *mut ZSTD_DCtx,
2576    maxWindowSize: size_t,
2577) -> size_t {
2578    let bounds = ZSTD_dParam_getBounds(ZSTD_d_windowLogMax);
2579    let min = (1) << bounds.lowerBound;
2580    let max = (1) << bounds.upperBound;
2581    if (*dctx).streamStage != StreamStage::Init {
2582        return Error::stage_wrong.to_error_code();
2583    }
2584    if maxWindowSize < min {
2585        return Error::parameter_outOfBound.to_error_code();
2586    }
2587    if maxWindowSize > max {
2588        return Error::parameter_outOfBound.to_error_code();
2589    }
2590    (*dctx).maxWindowSize = maxWindowSize;
2591    0
2592}
2593#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_DCtx_setFormat))]
2594pub unsafe extern "C" fn ZSTD_DCtx_setFormat(
2595    dctx: *mut ZSTD_DCtx,
2596    format: ZSTD_format_e,
2597) -> size_t {
2598    ZSTD_DCtx_setParameter(
2599        dctx,
2600        ZSTD_d_format as ZSTD_dParameter,
2601        format as core::ffi::c_int,
2602    )
2603}
2604#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_dParam_getBounds))]
2605pub unsafe extern "C" fn ZSTD_dParam_getBounds(dParam: ZSTD_dParameter) -> ZSTD_bounds {
2606    let mut bounds = {
2607        ZSTD_bounds {
2608            error: 0,
2609            lowerBound: 0,
2610            upperBound: 0,
2611        }
2612    };
2613    match dParam as core::ffi::c_uint {
2614        100 => {
2615            bounds.lowerBound = ZSTD_WINDOWLOG_ABSOLUTEMIN;
2616            bounds.upperBound = if ::core::mem::size_of::<size_t>() == 4 {
2617                ZSTD_WINDOWLOG_MAX_32
2618            } else {
2619                ZSTD_WINDOWLOG_MAX_64
2620            };
2621            return bounds;
2622        }
2623        1000 => {
2624            bounds.lowerBound = Format::ZSTD_f_zstd1 as core::ffi::c_int;
2625            bounds.upperBound = Format::ZSTD_f_zstd1_magicless as core::ffi::c_int;
2626            return bounds;
2627        }
2628        1001 => {
2629            bounds.lowerBound = BufferMode::Buffered as core::ffi::c_int;
2630            bounds.upperBound = BufferMode::Stable as core::ffi::c_int;
2631            return bounds;
2632        }
2633        1002 => {
2634            bounds.lowerBound = ZSTD_d_validateChecksum as core::ffi::c_int;
2635            bounds.upperBound = ZSTD_d_ignoreChecksum as core::ffi::c_int;
2636            return bounds;
2637        }
2638        1003 => {
2639            bounds.lowerBound = MultipleDDicts::Single as core::ffi::c_int;
2640            bounds.upperBound = MultipleDDicts::Multiple as core::ffi::c_int;
2641            return bounds;
2642        }
2643        1004 => {
2644            bounds.lowerBound = 0;
2645            bounds.upperBound = 1;
2646            return bounds;
2647        }
2648        1005 => {
2649            bounds.lowerBound = ZSTD_BLOCKSIZE_MAX_MIN;
2650            bounds.upperBound = ZSTD_BLOCKSIZE_MAX;
2651            return bounds;
2652        }
2653        _ => {}
2654    }
2655    bounds.error = Error::parameter_unsupported.to_error_code();
2656    bounds
2657}
2658unsafe fn ZSTD_dParam_withinBounds(
2659    dParam: ZSTD_dParameter,
2660    value: core::ffi::c_int,
2661) -> core::ffi::c_int {
2662    let bounds = ZSTD_dParam_getBounds(dParam);
2663    if ERR_isError(bounds.error) {
2664        return 0;
2665    }
2666    if value < bounds.lowerBound {
2667        return 0;
2668    }
2669    if value > bounds.upperBound {
2670        return 0;
2671    }
2672    1
2673}
2674
2675#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_DCtx_getParameter))]
2676pub unsafe extern "C" fn ZSTD_DCtx_getParameter(
2677    dctx: *mut ZSTD_DCtx,
2678    param: ZSTD_dParameter,
2679    value: *mut core::ffi::c_int,
2680) -> size_t {
2681    match param as core::ffi::c_uint {
2682        100 => {
2683            *value = (*dctx).maxWindowSize.ilog2() as i32;
2684            0
2685        }
2686        1000 => {
2687            *value = (*dctx).format as core::ffi::c_int;
2688            0
2689        }
2690        1001 => {
2691            *value = (*dctx).outBufferMode as core::ffi::c_int;
2692            0
2693        }
2694        1002 => {
2695            *value = (*dctx).forceIgnoreChecksum as core::ffi::c_int;
2696            0
2697        }
2698        1003 => {
2699            *value = (*dctx).refMultipleDDicts as core::ffi::c_int;
2700            0
2701        }
2702        1004 => {
2703            *value = (*dctx).disableHufAsm;
2704            0
2705        }
2706        1005 => {
2707            *value = (*dctx).maxBlockSizeParam;
2708            0
2709        }
2710        _ => Error::parameter_unsupported.to_error_code(),
2711    }
2712}
2713
2714#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_DCtx_setParameter))]
2715pub unsafe extern "C" fn ZSTD_DCtx_setParameter(
2716    dctx: *mut ZSTD_DCtx,
2717    dParam: ZSTD_dParameter,
2718    mut value: core::ffi::c_int,
2719) -> size_t {
2720    if (*dctx).streamStage != StreamStage::Init {
2721        return Error::stage_wrong.to_error_code();
2722    }
2723    match dParam as core::ffi::c_uint {
2724        100 => {
2725            if value == 0 {
2726                value = ZSTD_WINDOWLOG_LIMIT_DEFAULT;
2727            }
2728            if ZSTD_dParam_withinBounds(ZSTD_d_windowLogMax, value) == 0 {
2729                return Error::parameter_outOfBound.to_error_code();
2730            }
2731            (*dctx).maxWindowSize = (1) << value;
2732            return 0;
2733        }
2734        1000 => {
2735            let Ok(format) = Format::try_from(value as ZSTD_format_e) else {
2736                return Error::parameter_outOfBound.to_error_code();
2737            };
2738
2739            (*dctx).format = format;
2740
2741            return 0;
2742        }
2743        1001 => {
2744            let Ok(value) = BufferMode::try_from(value as u32) else {
2745                return Error::parameter_outOfBound.to_error_code();
2746            };
2747            (*dctx).outBufferMode = value;
2748            return 0;
2749        }
2750        1002 => {
2751            if ZSTD_dParam_withinBounds(ZSTD_d_experimentalParam3, value) == 0 {
2752                return Error::parameter_outOfBound.to_error_code();
2753            }
2754            (*dctx).forceIgnoreChecksum = value as ZSTD_forceIgnoreChecksum_e;
2755            return 0;
2756        }
2757        1003 => {
2758            let Ok(value) = MultipleDDicts::try_from(value as u32) else {
2759                return Error::parameter_outOfBound.to_error_code();
2760            };
2761            if (*dctx).staticSize != 0 {
2762                return Error::parameter_unsupported.to_error_code();
2763            }
2764            (*dctx).refMultipleDDicts = value;
2765            return 0;
2766        }
2767        1004 => {
2768            if ZSTD_dParam_withinBounds(ZSTD_d_experimentalParam5, value) == 0 {
2769                return Error::parameter_outOfBound.to_error_code();
2770            }
2771            (*dctx).disableHufAsm = (value != 0) as core::ffi::c_int;
2772            return 0;
2773        }
2774        1005 => {
2775            if value != 0 && ZSTD_dParam_withinBounds(ZSTD_d_experimentalParam6, value) == 0 {
2776                return Error::parameter_outOfBound.to_error_code();
2777            }
2778            (*dctx).maxBlockSizeParam = value;
2779            return 0;
2780        }
2781        _ => {}
2782    }
2783    Error::parameter_unsupported.to_error_code()
2784}
2785#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_DCtx_reset))]
2786pub unsafe extern "C" fn ZSTD_DCtx_reset(
2787    dctx: *mut ZSTD_DCtx,
2788    reset: ZSTD_ResetDirective,
2789) -> size_t {
2790    if reset as core::ffi::c_uint
2791        == ZSTD_reset_session_only as core::ffi::c_int as core::ffi::c_uint
2792        || reset as core::ffi::c_uint
2793            == ZSTD_reset_session_and_parameters as core::ffi::c_int as core::ffi::c_uint
2794    {
2795        (*dctx).streamStage = StreamStage::Init;
2796        (*dctx).noForwardProgress = 0;
2797        (*dctx).isFrameDecompression = 1;
2798    }
2799    if reset as core::ffi::c_uint == ZSTD_reset_parameters as core::ffi::c_int as core::ffi::c_uint
2800        || reset as core::ffi::c_uint
2801            == ZSTD_reset_session_and_parameters as core::ffi::c_int as core::ffi::c_uint
2802    {
2803        if (*dctx).streamStage != StreamStage::Init {
2804            return Error::stage_wrong.to_error_code();
2805        }
2806        ZSTD_clearDict(dctx);
2807        ZSTD_DCtx_resetParameters(dctx);
2808    }
2809    0
2810}
2811#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_sizeof_DStream))]
2812pub unsafe extern "C" fn ZSTD_sizeof_DStream(dctx: *const ZSTD_DStream) -> size_t {
2813    ZSTD_sizeof_DCtx(dctx)
2814}
2815unsafe fn ZSTD_decodingBufferSize_internal(
2816    windowSize: core::ffi::c_ulonglong,
2817    frameContentSize: core::ffi::c_ulonglong,
2818    blockSizeMax: size_t,
2819) -> size_t {
2820    let blockSize = if ((if windowSize < ((1) << 17) as core::ffi::c_ulonglong {
2821        windowSize
2822    } else {
2823        ((1) << 17) as core::ffi::c_ulonglong
2824    }) as size_t)
2825        < blockSizeMax
2826    {
2827        (if windowSize < ((1) << 17) as core::ffi::c_ulonglong {
2828            windowSize
2829        } else {
2830            ((1) << 17) as core::ffi::c_ulonglong
2831        }) as size_t
2832    } else {
2833        blockSizeMax
2834    };
2835    let neededRBSize = windowSize
2836        .wrapping_add((blockSize * 2) as core::ffi::c_ulonglong)
2837        .wrapping_add((WILDCOPY_OVERLENGTH * 2) as core::ffi::c_ulonglong);
2838    let neededSize = if frameContentSize < neededRBSize {
2839        frameContentSize
2840    } else {
2841        neededRBSize
2842    };
2843    let minRBSize = neededSize as size_t;
2844    if minRBSize as core::ffi::c_ulonglong != neededSize {
2845        return Error::frameParameter_windowTooLarge.to_error_code();
2846    }
2847    minRBSize
2848}
2849#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_decodingBufferSize_min))]
2850pub unsafe extern "C" fn ZSTD_decodingBufferSize_min(
2851    windowSize: core::ffi::c_ulonglong,
2852    frameContentSize: core::ffi::c_ulonglong,
2853) -> size_t {
2854    ZSTD_decodingBufferSize_internal(windowSize, frameContentSize, ZSTD_BLOCKSIZE_MAX as size_t)
2855}
2856#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_estimateDStreamSize))]
2857pub unsafe extern "C" fn ZSTD_estimateDStreamSize(windowSize: size_t) -> size_t {
2858    let blockSize = if windowSize < ((1) << 17) as size_t {
2859        windowSize
2860    } else {
2861        ((1) << 17) as size_t
2862    };
2863    let inBuffSize = blockSize;
2864    let outBuffSize = ZSTD_decodingBufferSize_min(
2865        windowSize as core::ffi::c_ulonglong,
2866        ZSTD_CONTENTSIZE_UNKNOWN,
2867    );
2868    (ZSTD_estimateDCtxSize())
2869        .wrapping_add(inBuffSize)
2870        .wrapping_add(outBuffSize)
2871}
2872#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_estimateDStreamSize_fromFrame))]
2873pub unsafe extern "C" fn ZSTD_estimateDStreamSize_fromFrame(
2874    src: *const core::ffi::c_void,
2875    srcSize: size_t,
2876) -> size_t {
2877    let windowSizeMax = (1)
2878        << (if ::core::mem::size_of::<size_t>() == 4 {
2879            ZSTD_WINDOWLOG_MAX_32
2880        } else {
2881            ZSTD_WINDOWLOG_MAX_64
2882        });
2883    let mut zfh = ZSTD_FrameHeader {
2884        frameContentSize: 0,
2885        windowSize: 0,
2886        blockSizeMax: 0,
2887        frameType: ZSTD_frame,
2888        headerSize: 0,
2889        dictID: 0,
2890        checksumFlag: 0,
2891        _reserved1: 0,
2892        _reserved2: 0,
2893    };
2894    let err = ZSTD_getFrameHeader(&mut zfh, src, srcSize);
2895    if ERR_isError(err) {
2896        return err;
2897    }
2898    if err > 0 {
2899        return Error::srcSize_wrong.to_error_code();
2900    }
2901    if zfh.windowSize > windowSizeMax as core::ffi::c_ulonglong {
2902        return Error::frameParameter_windowTooLarge.to_error_code();
2903    }
2904    ZSTD_estimateDStreamSize(zfh.windowSize as size_t)
2905}
2906unsafe fn ZSTD_DCtx_isOverflow(
2907    zds: *mut ZSTD_DStream,
2908    neededInBuffSize: size_t,
2909    neededOutBuffSize: size_t,
2910) -> core::ffi::c_int {
2911    (((*zds).inBuffSize).wrapping_add((*zds).outBuffSize)
2912        >= neededInBuffSize.wrapping_add(neededOutBuffSize)
2913            * ZSTD_WORKSPACETOOLARGE_FACTOR as size_t) as core::ffi::c_int
2914}
2915unsafe fn ZSTD_DCtx_updateOversizedDuration(
2916    zds: *mut ZSTD_DStream,
2917    neededInBuffSize: size_t,
2918    neededOutBuffSize: size_t,
2919) {
2920    if ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize) != 0 {
2921        (*zds).oversizedDuration = ((*zds).oversizedDuration).wrapping_add(1);
2922        (*zds).oversizedDuration;
2923    } else {
2924        (*zds).oversizedDuration = 0;
2925    };
2926}
2927unsafe fn ZSTD_DCtx_isOversizedTooLong(zds: *mut ZSTD_DStream) -> core::ffi::c_int {
2928    ((*zds).oversizedDuration >= ZSTD_WORKSPACETOOLARGE_MAXDURATION as size_t) as core::ffi::c_int
2929}
2930unsafe fn ZSTD_checkOutBuffer(zds: *const ZSTD_DStream, output: *const ZSTD_outBuffer) -> size_t {
2931    if (*zds).outBufferMode != BufferMode::Stable {
2932        return 0;
2933    }
2934    if (*zds).streamStage == StreamStage::Init {
2935        return 0;
2936    }
2937    let expect = (*zds).expectedOutBuffer;
2938    if expect.dst == (*output).dst && expect.pos == (*output).pos && expect.size == (*output).size {
2939        return 0;
2940    }
2941    Error::dstBuffer_wrong.to_error_code()
2942}
2943unsafe fn ZSTD_decompressContinueStream(
2944    zds: *mut ZSTD_DStream,
2945    op: *mut *mut core::ffi::c_char,
2946    oend: *mut core::ffi::c_char,
2947    src: *const core::ffi::c_void,
2948    srcSize: size_t,
2949) -> size_t {
2950    let isSkipFrame = ZSTD_isSkipFrame(zds);
2951    if (*zds).outBufferMode == BufferMode::Buffered {
2952        let dstSize = if isSkipFrame != 0 {
2953            0
2954        } else {
2955            ((*zds).outBuffSize).wrapping_sub((*zds).outStart)
2956        };
2957        let decodedSize = ZSTD_decompressContinue(
2958            zds,
2959            ((*zds).outBuff).add((*zds).outStart) as *mut core::ffi::c_void,
2960            dstSize,
2961            src,
2962            srcSize,
2963        );
2964        let err_code = decodedSize;
2965        if ERR_isError(err_code) {
2966            return err_code;
2967        }
2968        if decodedSize == 0 && isSkipFrame == 0 {
2969            (*zds).streamStage = StreamStage::Read;
2970        } else {
2971            (*zds).outEnd = ((*zds).outStart).wrapping_add(decodedSize);
2972            (*zds).streamStage = StreamStage::Flush;
2973        }
2974    } else {
2975        let dstSize_0 = if isSkipFrame != 0 {
2976            0
2977        } else {
2978            oend.offset_from(*op) as size_t
2979        };
2980        let decodedSize_0 =
2981            ZSTD_decompressContinue(zds, *op as *mut core::ffi::c_void, dstSize_0, src, srcSize);
2982        let err_code_0 = decodedSize_0;
2983        if ERR_isError(err_code_0) {
2984            return err_code_0;
2985        }
2986        *op = (*op).add(decodedSize_0);
2987        (*zds).streamStage = StreamStage::Read;
2988    }
2989    0
2990}
2991
2992#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_decompressStream))]
2993pub unsafe extern "C" fn ZSTD_decompressStream(
2994    zds: *mut ZSTD_DStream,
2995    output: *mut ZSTD_outBuffer,
2996    input: *mut ZSTD_inBuffer,
2997) -> size_t {
2998    let output = output.as_mut().unwrap();
2999    let input = input.as_mut().unwrap();
3000
3001    let src = input.src as *const core::ffi::c_char;
3002    let istart = if input.pos != 0 {
3003        src.add(input.pos)
3004    } else {
3005        src
3006    };
3007    let iend = if input.size != 0 {
3008        src.add(input.size)
3009    } else {
3010        src
3011    };
3012    let mut ip = istart;
3013    let dst = output.dst as *mut core::ffi::c_char;
3014    let ostart = if output.pos != 0 {
3015        dst.add(output.pos)
3016    } else {
3017        dst
3018    };
3019    let oend = if output.size != 0 {
3020        dst.add(output.size)
3021    } else {
3022        dst
3023    };
3024    let mut op = ostart;
3025    let mut some_more_work = true;
3026    if input.pos > input.size {
3027        return Error::srcSize_wrong.to_error_code();
3028    }
3029    if output.pos > output.size {
3030        return Error::dstSize_tooSmall.to_error_code();
3031    }
3032    let err_code = ZSTD_checkOutBuffer(zds, output);
3033    if ERR_isError(err_code) {
3034        return err_code;
3035    }
3036
3037    while some_more_work {
3038        #[derive(Eq, PartialEq)]
3039        enum Block {
3040            LoadHeader,
3041            Read,
3042            Load,
3043        }
3044        let mut current_block: Block;
3045        match (*zds).streamStage {
3046            StreamStage::Init => {
3047                (*zds).streamStage = StreamStage::LoadHeader;
3048                (*zds).outEnd = 0;
3049                (*zds).outStart = (*zds).outEnd;
3050                (*zds).inPos = (*zds).outStart;
3051                (*zds).lhSize = (*zds).inPos;
3052                (*zds).legacyVersion = 0;
3053                (*zds).hostageByte = 0;
3054                (*zds).expectedOutBuffer = *output;
3055                current_block = Block::LoadHeader;
3056            }
3057            StreamStage::LoadHeader => {
3058                current_block = Block::LoadHeader;
3059            }
3060            StreamStage::Read => {
3061                current_block = Block::Read;
3062            }
3063            StreamStage::Load => {
3064                current_block = Block::Load;
3065            }
3066            StreamStage::Flush => {
3067                let toFlushSize = ((*zds).outEnd).wrapping_sub((*zds).outStart);
3068                let flushedSize = ZSTD_limitCopy(
3069                    op as *mut core::ffi::c_void,
3070                    oend.offset_from(op) as size_t,
3071                    ((*zds).outBuff).add((*zds).outStart) as *const core::ffi::c_void,
3072                    toFlushSize,
3073                );
3074
3075                op = if !op.is_null() {
3076                    op.add(flushedSize)
3077                } else {
3078                    op
3079                };
3080
3081                (*zds).outStart = ((*zds).outStart).wrapping_add(flushedSize);
3082                if flushedSize == toFlushSize {
3083                    // flush completed
3084                    (*zds).streamStage = StreamStage::Read;
3085                    if ((*zds).outBuffSize as core::ffi::c_ulonglong)
3086                        < (*zds).fParams.frameContentSize
3087                        && ((*zds).outStart).wrapping_add((*zds).fParams.blockSizeMax as size_t)
3088                            > (*zds).outBuffSize
3089                    {
3090                        (*zds).outEnd = 0;
3091                        (*zds).outStart = 0;
3092                    }
3093                    continue;
3094                }
3095
3096                // cannot complete flush
3097                some_more_work = false;
3098                continue;
3099            }
3100        }
3101        if current_block == Block::LoadHeader {
3102            drop(current_block);
3103
3104            if (*zds).legacyVersion != 0 {
3105                if (*zds).staticSize != 0 {
3106                    return Error::memory_allocation.to_error_code();
3107                }
3108                let hint = ZSTD_decompressLegacyStream(
3109                    (*zds).legacyContext,
3110                    (*zds).legacyVersion,
3111                    output,
3112                    input,
3113                );
3114                if hint == 0 {
3115                    (*zds).streamStage = StreamStage::Init;
3116                }
3117                return hint;
3118            }
3119
3120            let hSize = get_frame_header_advanced(
3121                &mut (*zds).fParams,
3122                &(&(*zds).headerBuffer)[..(*zds).lhSize],
3123                (*zds).format,
3124            );
3125            if (*zds).refMultipleDDicts != MultipleDDicts::Single && !(*zds).ddictSet.is_null() {
3126                ZSTD_DCtx_selectFrameDDict(zds);
3127            }
3128            if ERR_isError(hSize) {
3129                let legacyVersion = ZSTD_isLegacy(
3130                    istart as *const core::ffi::c_void,
3131                    iend.offset_from(istart) as size_t,
3132                );
3133                if legacyVersion != 0 {
3134                    let ddict = ZSTD_getDDict(zds);
3135                    let dict = if !ddict.is_null() {
3136                        ZSTD_DDict_dictContent(ddict)
3137                    } else {
3138                        core::ptr::null()
3139                    };
3140                    let dictSize = if !ddict.is_null() {
3141                        ZSTD_DDict_dictSize(ddict)
3142                    } else {
3143                        0
3144                    };
3145                    if (*zds).staticSize != 0 {
3146                        return Error::memory_allocation.to_error_code();
3147                    }
3148                    let err_code = ZSTD_initLegacyStream(
3149                        &mut (*zds).legacyContext,
3150                        (*zds).previousLegacyVersion,
3151                        legacyVersion,
3152                        dict,
3153                        dictSize,
3154                    );
3155                    if ERR_isError(err_code) {
3156                        return err_code;
3157                    }
3158                    (*zds).previousLegacyVersion = legacyVersion;
3159                    (*zds).legacyVersion = (*zds).previousLegacyVersion;
3160                    let hint = ZSTD_decompressLegacyStream(
3161                        (*zds).legacyContext,
3162                        legacyVersion,
3163                        output,
3164                        input,
3165                    );
3166                    if hint == 0 {
3167                        (*zds).streamStage = StreamStage::Init;
3168                    }
3169                    return hint;
3170                }
3171
3172                // error
3173                return hSize;
3174            }
3175
3176            if hSize != 0 {
3177                // need more input
3178                let toLoad = hSize - (*zds).lhSize; // if hSize!=0, hSize > zds->lhSize
3179                let remainingInput = iend.offset_from(ip) as size_t;
3180                if toLoad > remainingInput {
3181                    // not enough input to load full header
3182                    if remainingInput > 0 {
3183                        libc::memcpy(
3184                            ((*zds).headerBuffer).as_mut_ptr().add((*zds).lhSize)
3185                                as *mut core::ffi::c_void,
3186                            ip as *const core::ffi::c_void,
3187                            remainingInput as libc::size_t,
3188                        );
3189                        (*zds).lhSize = ((*zds).lhSize).wrapping_add(remainingInput);
3190                    }
3191                    input.pos = input.size;
3192                    // check first few bytes
3193                    let err_code = get_frame_header_advanced(
3194                        &mut (*zds).fParams,
3195                        &(&(*zds).headerBuffer)[..(*zds).lhSize],
3196                        (*zds).format,
3197                    );
3198                    if ERR_isError(err_code) {
3199                        return err_code;
3200                    }
3201                    // remaining header bytes + next block header
3202                    return std::cmp::max(ZSTD_FRAMEHEADERSIZE_MIN((*zds).format), hSize)
3203                        .wrapping_sub((*zds).lhSize)
3204                        .wrapping_add(ZSTD_blockHeaderSize);
3205                }
3206                assert!(!ip.is_null());
3207                libc::memcpy(
3208                    ((*zds).headerBuffer).as_mut_ptr().add((*zds).lhSize) as *mut core::ffi::c_void,
3209                    ip as *const core::ffi::c_void,
3210                    toLoad as libc::size_t,
3211                );
3212                (*zds).lhSize = hSize;
3213                ip = ip.add(toLoad);
3214                continue;
3215            } else {
3216                // check for single-pass mode opportunity
3217                if (*zds).fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
3218                    && (*zds).fParams.frameType != ZSTD_skippableFrame
3219                    && oend.offset_from(op) as size_t as core::ffi::c_ulonglong
3220                        >= (*zds).fParams.frameContentSize
3221                {
3222                    let cSize = ZSTD_findFrameCompressedSize_advanced(
3223                        core::slice::from_raw_parts(
3224                            istart.cast(),
3225                            iend.offset_from(istart) as usize,
3226                        ),
3227                        (*zds).format,
3228                    );
3229                    if cSize <= iend.offset_from(istart) as size_t {
3230                        let decompressedSize = ZSTD_decompress_usingDDict(
3231                            zds,
3232                            op as *mut core::ffi::c_void,
3233                            oend.offset_from(op) as size_t,
3234                            istart as *const core::ffi::c_void,
3235                            cSize,
3236                            ZSTD_getDDict(zds),
3237                        );
3238                        if ERR_isError(decompressedSize) {
3239                            return decompressedSize;
3240                        }
3241                        assert!(!istart.is_null());
3242                        ip = istart.add(cSize);
3243                        op = if !op.is_null() {
3244                            op.add(decompressedSize)
3245                        } else {
3246                            // can occur if frameContentSize = 0 (empty frame)
3247                            op
3248                        };
3249                        (*zds).expected = 0;
3250                        (*zds).streamStage = StreamStage::Init;
3251                        some_more_work = false;
3252                        continue;
3253                    }
3254                }
3255
3256                // Check output buffer is large enough for ZSTD_odm_stable.
3257                if (*zds).outBufferMode == BufferMode::Stable
3258                    && (*zds).fParams.frameType != ZSTD_skippableFrame
3259                    && (*zds).fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
3260                    && (oend.offset_from(op) as size_t as core::ffi::c_ulonglong)
3261                        < (*zds).fParams.frameContentSize
3262                {
3263                    return Error::dstSize_tooSmall.to_error_code();
3264                }
3265                let err_code = ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds));
3266                if ERR_isError(err_code) {
3267                    return err_code;
3268                }
3269                if (*zds).format == Format::ZSTD_f_zstd1
3270                    && MEM_readLE32(((*zds).headerBuffer).as_mut_ptr() as *const core::ffi::c_void)
3271                        & ZSTD_MAGIC_SKIPPABLE_MASK
3272                        == ZSTD_MAGIC_SKIPPABLE_START as core::ffi::c_uint
3273                {
3274                    // skippable frame
3275                    (*zds).expected =
3276                        MEM_readLE32(((*zds).headerBuffer).as_mut_ptr().add(ZSTD_FRAMEIDSIZE)
3277                            as *const core::ffi::c_void) as size_t;
3278                    (*zds).stage = DecompressStage::SkipFrame;
3279                } else {
3280                    let err_code =
3281                        ZSTD_decodeFrameHeader(zds, &((&(*zds).headerBuffer)[..(*zds).lhSize]));
3282                    if ERR_isError(err_code) {
3283                        return err_code;
3284                    }
3285                    (*zds).expected = ZSTD_blockHeaderSize;
3286                    (*zds).stage = DecompressStage::DecodeBlockHeader;
3287                }
3288
3289                // control buffer memory usage
3290                (*zds).fParams.windowSize = std::cmp::min(
3291                    (*zds).fParams.windowSize,
3292                    (1 << ZSTD_WINDOWLOG_ABSOLUTEMIN) as core::ffi::c_ulonglong,
3293                );
3294                if (*zds).fParams.windowSize > (*zds).maxWindowSize as core::ffi::c_ulonglong {
3295                    return Error::frameParameter_windowTooLarge.to_error_code();
3296                }
3297                if (*zds).maxBlockSizeParam != 0 {
3298                    (*zds).fParams.blockSizeMax = std::cmp::min(
3299                        (*zds).fParams.blockSizeMax,
3300                        (*zds).maxBlockSizeParam as core::ffi::c_uint,
3301                    );
3302                }
3303
3304                // Adapt buffer sizes to frame header instructions
3305                let neededInBuffSize = std::cmp::max((*zds).fParams.blockSizeMax, 4) as size_t;
3306                let neededOutBuffSize = if (*zds).outBufferMode == BufferMode::Buffered {
3307                    ZSTD_decodingBufferSize_internal(
3308                        (*zds).fParams.windowSize,
3309                        (*zds).fParams.frameContentSize,
3310                        (*zds).fParams.blockSizeMax as size_t,
3311                    )
3312                } else {
3313                    0
3314                };
3315
3316                ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize);
3317
3318                let tooSmall = ((*zds).inBuffSize < neededInBuffSize
3319                    || (*zds).outBuffSize < neededOutBuffSize)
3320                    as core::ffi::c_int;
3321                let tooLarge = ZSTD_DCtx_isOversizedTooLong(zds);
3322
3323                if tooSmall != 0 || tooLarge != 0 {
3324                    let bufferSize = neededInBuffSize.wrapping_add(neededOutBuffSize);
3325                    if (*zds).staticSize != 0 {
3326                        // static DCtx
3327                        assert!((*zds).staticSize >= size_of::<ZSTD_DCtx>()); // controlled at init
3328                        if bufferSize > (*zds).staticSize - size_of::<ZSTD_DCtx>() {
3329                            return Error::dictionary_corrupted.to_error_code();
3330                        }
3331                    } else {
3332                        ZSTD_customFree((*zds).inBuff as *mut core::ffi::c_void, (*zds).customMem);
3333                        (*zds).inBuffSize = 0;
3334                        (*zds).outBuffSize = 0;
3335                        (*zds).inBuff = ZSTD_customMalloc(bufferSize, (*zds).customMem)
3336                            as *mut core::ffi::c_char;
3337                        if (*zds).inBuff.is_null() {
3338                            return Error::dictionary_corrupted.to_error_code();
3339                        }
3340                    }
3341                    (*zds).inBuffSize = neededInBuffSize;
3342                    (*zds).outBuff = ((*zds).inBuff).add((*zds).inBuffSize);
3343                    (*zds).outBuffSize = neededOutBuffSize;
3344                }
3345                (*zds).streamStage = StreamStage::Read;
3346                current_block = Block::Read;
3347            }
3348        }
3349
3350        if current_block == Block::Read {
3351            drop(current_block);
3352
3353            let neededInSize =
3354                ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend.offset_from(ip) as size_t);
3355            if neededInSize == 0 {
3356                (*zds).streamStage = StreamStage::Init;
3357                some_more_work = false;
3358                continue;
3359            } else if iend.offset_from(ip) as size_t >= neededInSize {
3360                // decode directly from src
3361                let err_code_4 = ZSTD_decompressContinueStream(
3362                    zds,
3363                    &mut op,
3364                    oend,
3365                    ip as *const core::ffi::c_void,
3366                    neededInSize,
3367                );
3368                if ERR_isError(err_code_4) {
3369                    return err_code_4;
3370                }
3371                assert!(!ip.is_null());
3372                ip = ip.add(neededInSize);
3373                // Function modifies the stage so we must break
3374                continue;
3375            } else if ip == iend {
3376                // no more input
3377                some_more_work = false;
3378                continue;
3379            } else {
3380                (*zds).streamStage = StreamStage::Load;
3381                current_block = Block::Load;
3382            }
3383        }
3384
3385        if current_block == Block::Load {
3386            drop(current_block);
3387
3388            let neededInSize = ZSTD_nextSrcSizeToDecompress(zds);
3389            let toLoad_0 = neededInSize.wrapping_sub((*zds).inPos);
3390            let isSkipFrame = ZSTD_isSkipFrame(zds);
3391            let mut loadedSize: size_t = 0;
3392            // At this point we shouldn't be decompressing a block that we can stream.
3393            assert!(
3394                neededInSize
3395                    == ZSTD_nextSrcSizeToDecompressWithInputSize(
3396                        zds,
3397                        iend.offset_from(ip) as usize
3398                    )
3399            );
3400            if isSkipFrame != 0 {
3401                loadedSize = std::cmp::min(toLoad_0, iend.offset_from(ip) as size_t);
3402            } else {
3403                if toLoad_0 > ((*zds).inBuffSize).wrapping_sub((*zds).inPos) {
3404                    return Error::corruption_detected.to_error_code();
3405                }
3406                loadedSize = ZSTD_limitCopy(
3407                    ((*zds).inBuff).add((*zds).inPos) as *mut core::ffi::c_void,
3408                    toLoad_0,
3409                    ip as *const core::ffi::c_void,
3410                    iend.offset_from(ip) as size_t,
3411                );
3412            }
3413            if loadedSize != 0 {
3414                // ip may be NULL
3415                ip = ip.add(loadedSize);
3416                (*zds).inPos = ((*zds).inPos).wrapping_add(loadedSize);
3417            }
3418            if loadedSize < toLoad_0 {
3419                // not enough input, wait for more
3420                some_more_work = false;
3421            } else {
3422                // decode loaded input
3423                (*zds).inPos = 0; // input is consumed
3424                let err_code_5 = ZSTD_decompressContinueStream(
3425                    zds,
3426                    &mut op,
3427                    oend,
3428                    (*zds).inBuff as *const core::ffi::c_void,
3429                    neededInSize,
3430                );
3431                if ERR_isError(err_code_5) {
3432                    return err_code_5;
3433                }
3434                // Function modifies the stage so we must break
3435            }
3436        }
3437    }
3438
3439    // result
3440    input.pos = ip.offset_from(input.src as *const core::ffi::c_char) as size_t;
3441    output.pos = op.offset_from(output.dst as *mut core::ffi::c_char) as size_t;
3442
3443    // Update the expected output buffer for ZSTD_obm_stable.
3444    (*zds).expectedOutBuffer = *output;
3445
3446    if ip == istart && op == ostart {
3447        // no forward progress
3448        (*zds).noForwardProgress += 1;
3449        (*zds).noForwardProgress;
3450        if (*zds).noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX {
3451            if op == oend {
3452                return Error::noForwardProgress_destFull.to_error_code();
3453            }
3454            if ip == iend {
3455                return Error::noForwardProgress_inputEmpty.to_error_code();
3456            }
3457            unreachable!();
3458        }
3459    } else {
3460        (*zds).noForwardProgress = 0;
3461    }
3462
3463    let mut nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds);
3464    if nextSrcSizeHint == 0 {
3465        // frame fully decoded
3466        if (*zds).outEnd == (*zds).outStart {
3467            // output fully flushed
3468            if (*zds).hostageByte != 0 {
3469                if input.pos >= input.size {
3470                    // can't release hostage (not present)
3471                    (*zds).streamStage = StreamStage::Read;
3472                    return 1;
3473                }
3474                // release hostage
3475                input.pos = (input.pos).wrapping_add(1);
3476            }
3477            return 0;
3478        }
3479        if (*zds).hostageByte == 0 {
3480            // output not fully flushed; keep last byte as hostage; will be
3481            // released when all output is flushed
3482            // note : pos > 0, otherwise, impossible to finish reading last block
3483            input.pos = (input.pos).wrapping_sub(1);
3484            (*zds).hostageByte = 1;
3485        }
3486        return 1;
3487    }
3488    // preload header of next block
3489    nextSrcSizeHint = nextSrcSizeHint.wrapping_add(
3490        ZSTD_blockHeaderSize
3491            * ((*zds).stage.to_next_input_type() == NextInputType::Block) as size_t,
3492    );
3493    assert!((*zds).inPos <= nextSrcSizeHint);
3494    // part already loaded
3495    nextSrcSizeHint = nextSrcSizeHint.wrapping_sub((*zds).inPos);
3496    nextSrcSizeHint
3497}
3498
3499#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_decompressStream_simpleArgs))]
3500pub unsafe extern "C" fn ZSTD_decompressStream_simpleArgs(
3501    dctx: *mut ZSTD_DCtx,
3502    dst: *mut core::ffi::c_void,
3503    dstCapacity: size_t,
3504    dstPos: *mut size_t,
3505    src: *const core::ffi::c_void,
3506    srcSize: size_t,
3507    srcPos: *mut size_t,
3508) -> size_t {
3509    let mut output = ZSTD_outBuffer_s {
3510        dst: core::ptr::null_mut::<core::ffi::c_void>(),
3511        size: 0,
3512        pos: 0,
3513    };
3514    let mut input = ZSTD_inBuffer_s {
3515        src: core::ptr::null::<core::ffi::c_void>(),
3516        size: 0,
3517        pos: 0,
3518    };
3519    output.dst = dst;
3520    output.size = dstCapacity;
3521    output.pos = *dstPos;
3522    input.src = src;
3523    input.size = srcSize;
3524    input.pos = *srcPos;
3525    let cErr = ZSTD_decompressStream(dctx, &mut output, &mut input);
3526    *dstPos = output.pos;
3527    *srcPos = input.pos;
3528    cErr
3529}
3530
3531#[cfg(test)]
3532mod tests {
3533    use super::*;
3534    use quickcheck::quickcheck;
3535
3536    #[test]
3537    fn decompress_bound_null() {
3538        assert_eq!(unsafe { ZSTD_decompressBound(core::ptr::null(), 0) }, 0);
3539    }
3540
3541    quickcheck! {
3542        #[cfg(not(miri))]
3543        fn decompress_bound_quickcheck(input: Vec<u8>) -> bool {
3544            unsafe {
3545                let expected = zstd_sys::ZSTD_decompressBound(input.as_ptr().cast(), input.len() );
3546                let actual = super::ZSTD_decompressBound(input.as_ptr().cast(), input.len());
3547
3548                assert_eq!(expected, actual);
3549                expected == actual
3550            }
3551        }
3552    }
3553
3554    #[test]
3555    fn decompression_margin_null() {
3556        assert_eq!(unsafe { ZSTD_decompressionMargin(core::ptr::null(), 0) }, 0);
3557    }
3558
3559    quickcheck! {
3560        #[cfg(not(miri))]
3561        fn decompression_margin_quickcheck(input: Vec<u8>) -> bool {
3562            unsafe {
3563                let expected = zstd_sys::ZSTD_decompressionMargin(input.as_ptr().cast(), input.len() );
3564                let actual = super::ZSTD_decompressionMargin(input.as_ptr().cast(), input.len());
3565
3566                assert_eq!(expected, actual);
3567                expected == actual
3568            }
3569        }
3570    }
3571}