Skip to main content

libzstd_rs_sys/lib/decompress/
mod.rs

1use core::ptr::NonNull;
2use libc::size_t;
3
4use crate::lib::common::xxhash::XXH64_state_t;
5
6use crate::lib::common::zstd_internal::WILDCOPY_OVERLENGTH;
7use crate::lib::common::zstd_trace::ZSTD_TraceCtx;
8use crate::lib::decompress::huf_decompress::DTable;
9use crate::lib::decompress::zstd_ddict::{MultipleDDicts, ZSTD_DDict, ZSTD_DDictHashSet};
10use crate::lib::decompress::zstd_decompress_block::{FseWorkspace, ZSTD_LITBUFFEREXTRASIZE};
11use crate::lib::zstd::{BufferMode, ForceIgnoreChecksum, Format, ZSTD_customMem, ZSTD_outBuffer};
12
13pub mod huf_decompress;
14pub mod zstd_ddict;
15pub mod zstd_decompress;
16pub mod zstd_decompress_block;
17
18#[cfg(doc)]
19use crate::{ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_FRAMEHEADERSIZE_MAX};
20
21static LL_base: [u32; 36] = [
22    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24, 28, 32, 40, 48, 64,
23    0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000,
24];
25static OF_base: [u32; 32] = [
26    0, 1, 1, 5, 0xd, 0x1d, 0x3d, 0x7d, 0xfd, 0x1fd, 0x3fd, 0x7fd, 0xffd, 0x1ffd, 0x3ffd, 0x7ffd,
27    0xfffd, 0x1fffd, 0x3fffd, 0x7fffd, 0xffffd, 0x1ffffd, 0x3ffffd, 0x7ffffd, 0xfffffd, 0x1fffffd,
28    0x3fffffd, 0x7fffffd, 0xffffffd, 0x1ffffffd, 0x3ffffffd, 0x7ffffffd,
29];
30static OF_bits: [u8; 32] = [
31    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
32    26, 27, 28, 29, 30, 31,
33];
34static ML_base: [u32; 53] = [
35    3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
36    28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 41, 43, 47, 51, 59, 67, 83, 99, 0x83, 0x103, 0x203,
37    0x403, 0x803, 0x1003, 0x2003, 0x4003, 0x8003, 0x10003,
38];
39
40#[derive(Copy, Clone)]
41#[repr(C)]
42pub struct ZSTD_seqSymbol_header {
43    pub fastMode: u32,
44    pub tableLog: u32,
45}
46
47#[derive(Copy, Clone)]
48#[repr(C)]
49pub struct ZSTD_seqSymbol {
50    pub nextState: u16,
51    pub nbAdditionalBits: u8,
52    pub nbBits: u8,
53    pub baseValue: u32,
54}
55
56#[derive(Copy, Clone)]
57#[repr(C)]
58pub struct ZSTD_entropyDTables_t {
59    pub LLTable: SymbolTable<512>,
60    pub OFTable: SymbolTable<256>,
61    pub MLTable: SymbolTable<512>,
62    pub hufTable: DTable,
63    pub rep: [u32; 3],
64    pub workspace: FseWorkspace,
65}
66
67#[derive(Copy, Clone)]
68#[repr(C)]
69pub struct SymbolTable<const N: usize> {
70    header: ZSTD_seqSymbol_header,
71    symbols: [ZSTD_seqSymbol; N],
72}
73
74pub type ZSTD_dStage = core::ffi::c_uint;
75
76#[repr(u32)]
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub enum DecompressStage {
79    GetFrameHeaderSize = 0,
80    DecodeFrameHeader = 1,
81    DecodeBlockHeader = 2,
82    DecompressBlock = 3,
83    DecompressLastBlock = 4,
84    CheckChecksum = 5,
85    DecodeSkippableHeader = 6,
86    SkipFrame = 7,
87}
88
89impl DecompressStage {
90    pub const fn to_next_input_type(self) -> NextInputType {
91        match self {
92            Self::DecodeBlockHeader => NextInputType::BlockHeader,
93            Self::DecompressBlock => NextInputType::Block,
94            Self::DecompressLastBlock => NextInputType::LastBlock,
95            Self::CheckChecksum => NextInputType::Checksum,
96            Self::DecodeSkippableHeader | Self::SkipFrame => NextInputType::SkippableFrame,
97            Self::GetFrameHeaderSize | Self::DecodeFrameHeader => NextInputType::FrameHeader,
98        }
99    }
100}
101
102/// This enum represents [`zstd_decompress::ZSTD_nextInputType_e`].
103#[repr(u32)]
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105pub enum NextInputType {
106    FrameHeader = zstd_decompress::ZSTDnit_frameHeader,
107    BlockHeader = zstd_decompress::ZSTDnit_blockHeader,
108    Block = zstd_decompress::ZSTDnit_block,
109    LastBlock = zstd_decompress::ZSTDnit_lastBlock,
110    Checksum = zstd_decompress::ZSTDnit_checksum,
111    SkippableFrame = zstd_decompress::ZSTDnit_skippableFrame,
112}
113
114#[repr(u32)]
115#[derive(Debug, Clone, Copy, PartialEq, Eq)]
116pub enum StreamStage {
117    Init,
118    LoadHeader,
119    Read,
120    Load,
121    Flush,
122}
123
124#[repr(i32)]
125enum DictUses {
126    ZSTD_use_once = 1,
127    ZSTD_dont_use = 0,
128    ZSTD_use_indefinitely = -1,
129}
130
131#[repr(u32)]
132#[derive(Debug, Clone, Copy, PartialEq, Eq)]
133pub enum LitLocation {
134    /// Split between litExtraBuffer and dst.
135    ZSTD_split = 2,
136    /// Stored entirely within dst (in memory after current output write).
137    ZSTD_in_dst = 1,
138    /// Stored entirely within litExtraBuffer.
139    ZSTD_not_in_dst = 0,
140}
141
142pub type ZSTD_FrameType_e = core::ffi::c_uint;
143pub const ZSTD_skippableFrame: ZSTD_FrameType_e = 1;
144pub const ZSTD_frame: ZSTD_FrameType_e = 0;
145
146#[derive(Copy, Clone, Default)]
147#[repr(C)]
148pub(crate) struct blockProperties_t {
149    pub blockType: BlockType,
150    pub lastBlock: bool,
151    pub origSize: u32,
152}
153
154#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
155pub(crate) enum BlockType {
156    #[default]
157    Raw = 0,
158    Rle = 1,
159    Compressed = 2,
160    Reserved = 3,
161}
162
163impl From<u32> for BlockType {
164    fn from(value: u32) -> Self {
165        match value {
166            0 => Self::Raw,
167            1 => Self::Rle,
168            2 => Self::Compressed,
169            3 => Self::Reserved,
170            _ => panic!("invalid `BlockType`: {value}"),
171        }
172    }
173}
174
175#[derive(Default)]
176#[repr(C)]
177pub struct ZSTD_FrameHeader {
178    /// if set to [`ZSTD_CONTENTSIZE_UNKNOWN`], it means this field is not available, 0 means "empty"
179    pub frameContentSize: core::ffi::c_ulonglong,
180    /// can be very large, up to <= `frameContentSize`
181    pub windowSize: core::ffi::c_ulonglong,
182    pub blockSizeMax: core::ffi::c_uint,
183    /// if set to [`ZSTD_skippableFrame`], `frameContentSize` is the size of skippable content
184    pub frameType: ZSTD_FrameType_e,
185    pub headerSize: core::ffi::c_uint,
186    /// for [`ZSTD_skippableFrame`], contains the skippable magic variant \[0-15]
187    pub dictID: core::ffi::c_uint,
188    pub checksumFlag: core::ffi::c_uint,
189    pub _reserved1: core::ffi::c_uint,
190    pub _reserved2: core::ffi::c_uint,
191}
192
193#[repr(C)]
194pub struct Workspace {
195    data: [u32; 640],
196}
197
198impl Default for Workspace {
199    fn default() -> Self {
200        Self { data: [0; 640] }
201    }
202}
203
204impl Workspace {
205    fn as_x1_mut(&mut self) -> &mut huf_decompress::HUF_ReadDTableX1_Workspace {
206        const { assert!(size_of::<Self>() >= size_of::<huf_decompress::HUF_ReadDTableX1_Workspace>()) }
207        const { assert!(align_of::<Self>() >= align_of::<huf_decompress::HUF_ReadDTableX1_Workspace>()) }
208
209        unsafe { core::mem::transmute(&mut self.data) }
210    }
211
212    fn as_x2_mut(&mut self) -> &mut huf_decompress::HUF_ReadDTableX2_Workspace {
213        const { assert!(size_of::<Self>() >= size_of::<huf_decompress::HUF_ReadDTableX2_Workspace>()) }
214        const { assert!(align_of::<Self>() >= align_of::<huf_decompress::HUF_ReadDTableX2_Workspace>()) }
215
216        unsafe { core::mem::transmute(&mut self.data) }
217    }
218
219    fn as_fse_workspace(&mut self) -> &mut FseWorkspace {
220        const { assert!(size_of::<Self>() >= size_of::<FseWorkspace>()) }
221        const { assert!(align_of::<Self>() >= align_of::<FseWorkspace>()) }
222        unsafe { core::mem::transmute(&mut self.data) }
223    }
224}
225
226pub type ZSTD_DCtx = ZSTD_DCtx_s;
227
228/// Decompression context
229///
230/// When decompressing many times, it is recommended to allocate a context only once, and reuse it
231/// for each successive compression operation. This will make workload friendlier for system's
232/// memory.
233///
234/// You can create a decompression context with [`crate::ZSTD_createDCtx`] and free it with
235/// [`crate::ZSTD_freeDCtx`].
236///
237/// Use one context per thread for parallel execution.
238#[repr(C)]
239pub struct ZSTD_DCtx_s {
240    LLTptr: Option<NonNull<SymbolTable<512>>>,
241    MLTptr: Option<NonNull<SymbolTable<512>>>,
242    OFTptr: Option<NonNull<SymbolTable<256>>>,
243    HUFptr: Option<NonNull<DTable>>, // None encodes dctx.entropy.hufTable
244    entropy: ZSTD_entropyDTables_t,
245    workspace: Workspace,
246    previousDstEnd: *const core::ffi::c_void,
247    prefixStart: *const core::ffi::c_void,
248    virtualStart: *const core::ffi::c_void,
249    dictEnd: *const core::ffi::c_void,
250    expected: size_t,
251    fParams: ZSTD_FrameHeader,
252    processedCSize: u64,
253    decodedSize: u64,
254    bType: BlockType,
255    stage: DecompressStage,
256    litEntropy: bool,
257    _padding0: [u8; 3],
258    fseEntropy: bool,
259    _padding1: [u8; 3],
260    xxhState: XXH64_state_t,
261    headerSize: size_t,
262    format: Format,
263    forceIgnoreChecksum: ForceIgnoreChecksum,
264    _padding5: [u8; 3],
265    validateChecksum: bool,
266    _padding4: [u8; 3],
267    litPtr: *const u8,
268    customMem: ZSTD_customMem,
269    litSize: size_t,
270    rleSize: size_t,
271    staticSize: size_t,
272    isFrameDecompression: bool,
273    _padding7: [u8; 3],
274    bmi2: bool,
275    _padding2: [u8; 3],
276    ddictLocal: *mut ZSTD_DDict,
277    ddict: *const ZSTD_DDict,
278    dictID: u32,
279    ddictIsCold: bool,
280    _padding3: [u8; 3],
281    dictUses: DictUses,
282    ddictSet: *mut ZSTD_DDictHashSet,
283    refMultipleDDicts: MultipleDDicts,
284    disableHufAsm: bool,
285    _padding6: [u8; 3],
286    maxBlockSizeParam: core::ffi::c_int,
287    streamStage: StreamStage,
288
289    // The fields below are part of the workspace and not copied by `ZSTD_copyDCtx`.
290    inBuff: *mut u8,
291    inBuffSize: size_t,
292    inPos: size_t,
293    maxWindowSize: size_t,
294    outBuff: *mut u8,
295    outBuffSize: size_t,
296    outStart: size_t,
297    outEnd: size_t,
298    lhSize: size_t,
299    legacyContext: *mut core::ffi::c_void,
300    previousLegacyVersion: u32,
301    legacyVersion: u32,
302    hostageByte: u32,
303    noForwardProgress: core::ffi::c_int,
304    outBufferMode: BufferMode,
305    expectedOutBuffer: ZSTD_outBuffer,
306    litBuffer: *mut u8,
307    litBufferEnd: *const u8,
308    litBufferLocation: LitLocation,
309    // literal buffer can be split between storage within dst and within this scratch buffer.
310    litExtraBuffer: [u8; ZSTD_LITBUFFEREXTRASIZE + WILDCOPY_OVERLENGTH],
311    headerBuffer: [u8; 18],
312    oversizedDuration: size_t,
313    traceCtx: ZSTD_TraceCtx,
314}