libzstd_rs_sys/lib/decompress/
zstd_ddict.rs1use core::mem::MaybeUninit;
2use core::ptr::NonNull;
3use libc::size_t;
4
5use crate::lib::common::allocations::{ZSTD_customFree, ZSTD_customMalloc};
6use crate::lib::common::error_private::{ERR_isError, Error};
7use crate::lib::decompress::huf_decompress::DTableDesc;
8use crate::lib::decompress::zstd_decompress::ZSTD_loadDEntropy;
9use crate::lib::decompress::{ZSTD_DCtx, ZSTD_entropyDTables_t};
10use crate::lib::zstd::{
11 ZSTD_customMem, ZSTD_dct_auto, ZSTD_dct_fullDict, ZSTD_dct_rawContent, ZSTD_dictContentType_e,
12 ZSTD_dictLoadMethod_e, ZSTD_dlm_byCopy, ZSTD_dlm_byRef, ZSTD_MAGIC_DICTIONARY,
13};
14
15#[repr(u32)]
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum MultipleDDicts {
18 Single = 0,
19 Multiple = 1,
20}
21
22impl TryFrom<u32> for MultipleDDicts {
23 type Error = ();
24
25 fn try_from(value: u32) -> Result<Self, Self::Error> {
26 match value {
27 0 => Ok(Self::Single),
28 1 => Ok(Self::Multiple),
29 _ => Err(()),
30 }
31 }
32}
33
34#[repr(C)]
35pub struct ZSTD_DDictHashSet {
36 pub ddictPtrTable: *mut *const ZSTD_DDict,
37 pub ddictPtrTableSize: size_t,
38 pub ddictPtrCount: size_t,
39}
40
41impl ZSTD_DDictHashSet {
42 pub fn as_slice(&mut self) -> &[*const ZSTD_DDict] {
43 unsafe { core::slice::from_raw_parts(self.ddictPtrTable, self.ddictPtrCount) }
44 }
45}
46
47#[repr(C)]
48pub struct ZSTD_DDict {
49 dictBuffer: *mut core::ffi::c_void,
50 dictContent: *const core::ffi::c_void,
51 dictSize: size_t,
52 entropy: ZSTD_entropyDTables_t,
53 pub(crate) dictID: u32,
54 entropyPresent: u32,
55 cMem: ZSTD_customMem,
56}
57
58impl ZSTD_DDict {
59 pub fn as_slice(&self) -> &[u8] {
60 if self.dictContent.is_null() {
61 debug_assert_eq!(self.dictSize, 0);
62 &[]
63 } else {
64 unsafe { core::slice::from_raw_parts(self.dictContent.cast::<u8>(), self.dictSize) }
65 }
66 }
67}
68
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71enum DictLoadMethod {
72 ByCopy = ZSTD_dlm_byCopy as _,
73 ByRef = ZSTD_dlm_byRef as _,
74}
75
76pub fn ZSTD_DDict_dictContent(ddict: &ZSTD_DDict) -> *const core::ffi::c_void {
77 ddict.dictContent
78}
79
80pub fn ZSTD_DDict_dictSize(ddict: &ZSTD_DDict) -> size_t {
81 ddict.dictSize
82}
83
84pub fn ZSTD_copyDDictParameters(dctx: &mut MaybeUninit<ZSTD_DCtx>, ddict: &ZSTD_DDict) {
85 let dctx = dctx.as_mut_ptr();
86
87 unsafe {
90 (*dctx).dictID = ddict.dictID;
91 (*dctx).prefixStart = ddict.dictContent;
92 (*dctx).virtualStart = ddict.dictContent;
93 (*dctx).dictEnd = (ddict.dictContent).wrapping_byte_add(ddict.dictSize);
94 (*dctx).previousDstEnd = (*dctx).dictEnd;
95
96 if ddict.entropyPresent != 0 {
97 (*dctx).litEntropy = true;
98 (*dctx).fseEntropy = true;
99 (*dctx).LLTptr = NonNull::new((&raw const ddict.entropy.LLTable).cast_mut());
100 (*dctx).MLTptr = NonNull::new((&raw const ddict.entropy.MLTable).cast_mut());
101 (*dctx).OFTptr = NonNull::new((&raw const ddict.entropy.OFTable).cast_mut());
102 (*dctx).HUFptr = NonNull::new((&raw const ddict.entropy.hufTable).cast_mut());
103 (*dctx).entropy.rep = ddict.entropy.rep;
104 } else {
105 (*dctx).litEntropy = false;
106 (*dctx).fseEntropy = false;
107 }
108 }
109}
110
111fn ZSTD_loadEntropy_intoDDict(
112 ddict: &mut ZSTD_DDict,
113 dictContentType: ZSTD_dictContentType_e,
114) -> Result<(), Error> {
115 ddict.dictID = 0;
116 ddict.entropyPresent = 0;
117
118 if dictContentType == ZSTD_dct_rawContent {
119 return Ok(());
120 }
121
122 let dict = if ddict.dictContent.is_null() {
123 &[]
124 } else {
125 unsafe { core::slice::from_raw_parts(ddict.dictContent.cast::<u8>(), ddict.dictSize) }
126 };
127
128 let ([magic, dict_id, ..], _) = dict.as_chunks::<4>() else {
129 if dictContentType == ZSTD_dct_fullDict {
130 return Err(Error::dictionary_corrupted);
131 }
132
133 return Ok(()); };
135
136 let magic = u32::from_le_bytes(*magic);
137 if magic != ZSTD_MAGIC_DICTIONARY {
138 if dictContentType == ZSTD_dct_fullDict {
139 return Err(Error::dictionary_corrupted);
140 }
141
142 return Ok(()); }
144
145 ddict.dictID = u32::from_le_bytes(*dict_id);
146
147 let ret = ZSTD_loadDEntropy(&mut ddict.entropy, dict);
148
149 if ERR_isError(ret) {
150 return Err(Error::dictionary_corrupted);
151 }
152
153 ddict.entropyPresent = 1;
154
155 Ok(())
156}
157
158fn ZSTD_initDDict_internal(
159 ddict: &mut ZSTD_DDict,
160 dict: *const core::ffi::c_void,
161 mut dictSize: size_t,
162 dictLoadMethod: ZSTD_dictLoadMethod_e,
163 dictContentType: ZSTD_dictContentType_e,
164) -> Result<(), Error> {
165 if dictLoadMethod == DictLoadMethod::ByRef as ZSTD_dictLoadMethod_e
166 || dict.is_null()
167 || dictSize == 0
168 {
169 ddict.dictBuffer = core::ptr::null_mut();
170 ddict.dictContent = dict;
171 if dict.is_null() {
172 dictSize = 0;
173 }
174 } else {
175 unsafe {
176 let internalBuffer = ZSTD_customMalloc(dictSize, ddict.cMem);
177 ddict.dictBuffer = internalBuffer;
178 ddict.dictContent = internalBuffer;
179 if internalBuffer.is_null() {
180 return Err(Error::dictionary_corrupted);
181 }
182 core::ptr::copy_nonoverlapping(dict, internalBuffer, dictSize);
183 }
184 }
185
186 ddict.dictSize = dictSize;
187 ddict.entropy.hufTable.description = DTableDesc::default();
188
189 ZSTD_loadEntropy_intoDDict(ddict, dictContentType)?;
190
191 Ok(())
192}
193
194#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_createDDict_advanced))]
195pub unsafe extern "C" fn ZSTD_createDDict_advanced(
196 dict: *const core::ffi::c_void,
197 dictSize: size_t,
198 dictLoadMethod: ZSTD_dictLoadMethod_e,
199 dictContentType: ZSTD_dictContentType_e,
200 customMem: ZSTD_customMem,
201) -> *mut ZSTD_DDict {
202 let ddict = ZSTD_customMalloc(size_of::<ZSTD_DDict>(), customMem) as *mut ZSTD_DDict;
203
204 if ddict.is_null() {
205 return core::ptr::null_mut();
206 }
207
208 (*ddict).cMem = customMem;
209 if ZSTD_initDDict_internal(
210 ddict.as_mut().unwrap(),
211 dict,
212 dictSize,
213 dictLoadMethod,
214 dictContentType,
215 )
216 .is_err()
217 {
218 ZSTD_freeDDict(ddict);
219 return core::ptr::null_mut();
220 }
221
222 ddict
223}
224
225#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_createDDict))]
237pub unsafe extern "C" fn ZSTD_createDDict(
238 dict: *const core::ffi::c_void,
239 dictSize: size_t,
240) -> *mut ZSTD_DDict {
241 ZSTD_createDDict_advanced(
242 dict,
243 dictSize,
244 ZSTD_dlm_byCopy,
245 ZSTD_dct_auto,
246 ZSTD_customMem::default(),
247 )
248}
249
250#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_createDDict_byReference))]
255pub unsafe extern "C" fn ZSTD_createDDict_byReference(
256 dictBuffer: *const core::ffi::c_void,
257 dictSize: size_t,
258) -> *mut ZSTD_DDict {
259 ZSTD_createDDict_advanced(
260 dictBuffer,
261 dictSize,
262 ZSTD_dlm_byRef,
263 ZSTD_dct_auto,
264 ZSTD_customMem::default(),
265 )
266}
267
268#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_initStaticDDict))]
269pub unsafe extern "C" fn ZSTD_initStaticDDict(
270 sBuffer: *mut core::ffi::c_void,
271 sBufferSize: size_t,
272 mut dict: *const core::ffi::c_void,
273 dictSize: size_t,
274 dictLoadMethod: ZSTD_dictLoadMethod_e,
275 dictContentType: ZSTD_dictContentType_e,
276) -> *const ZSTD_DDict {
277 debug_assert!(!sBuffer.is_null());
278 debug_assert!(!dict.is_null());
279
280 if sBuffer as usize & 0b111 != 0 {
282 return core::ptr::null_mut();
283 }
284
285 if sBufferSize < ZSTD_estimateDDictSize(dictSize, dictLoadMethod) {
286 return core::ptr::null_mut();
287 }
288
289 let ddict = sBuffer as *mut ZSTD_DDict;
290 if dictLoadMethod == DictLoadMethod::ByCopy as ZSTD_dictLoadMethod_e {
291 core::ptr::copy_nonoverlapping(dict.cast::<u8>(), ddict.add(1).cast::<u8>(), dictSize); dict = ddict.add(1) as *const core::ffi::c_void;
293 }
294
295 if ZSTD_initDDict_internal(
296 ddict.as_mut().unwrap(),
297 dict,
298 dictSize,
299 DictLoadMethod::ByRef as _,
300 dictContentType,
301 )
302 .is_err()
303 {
304 return core::ptr::null_mut();
305 }
306
307 ddict
308}
309
310#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_freeDDict))]
314pub unsafe extern "C" fn ZSTD_freeDDict(ddict: *mut ZSTD_DDict) -> size_t {
315 if ddict.is_null() {
316 return 0;
317 }
318 let cMem = (*ddict).cMem;
319 ZSTD_customFree((*ddict).dictBuffer, (*ddict).dictSize, cMem);
320 ZSTD_customFree(
321 ddict as *mut core::ffi::c_void,
322 size_of::<ZSTD_DDict>(),
323 cMem,
324 );
325 0
326}
327
328#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_estimateDDictSize))]
332pub const extern "C" fn ZSTD_estimateDDictSize(
333 dict_size: size_t,
334 dict_load_method: ZSTD_dictLoadMethod_e,
335) -> size_t {
336 if dict_load_method == ZSTD_dlm_byRef as ZSTD_dictLoadMethod_e {
337 size_of::<ZSTD_DDict>()
338 } else {
339 size_of::<ZSTD_DDict>() + dict_size
340 }
341}
342
343#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_sizeof_DDict))]
350pub unsafe extern "C" fn ZSTD_sizeof_DDict(ddict: *const ZSTD_DDict) -> size_t {
351 if ddict.is_null() {
352 return 0;
353 }
354 (::core::mem::size_of::<ZSTD_DDict>()).wrapping_add(if !((*ddict).dictBuffer).is_null() {
355 (*ddict).dictSize
356 } else {
357 0
358 })
359}
360
361#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_getDictID_fromDDict))]
366pub unsafe extern "C" fn ZSTD_getDictID_fromDDict(ddict: *const ZSTD_DDict) -> core::ffi::c_uint {
367 if ddict.is_null() {
368 return 0;
369 }
370 (*ddict).dictID
371}
372
373#[cfg(test)]
374mod tests {
375 use super::*;
376
377 #[test]
378 fn test_estimate_ddict_size() {
379 assert_eq!(
380 ZSTD_estimateDDictSize(1234, ZSTD_dlm_byCopy),
381 size_of::<ZSTD_DDict>() + 1234
382 );
383 assert_eq!(
384 ZSTD_estimateDDictSize(1234, ZSTD_dlm_byRef),
385 size_of::<ZSTD_DDict>()
386 );
387 }
388}