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