1use crate::common::error::{ErrorCode, ERROR};
5use crate::common::mem::{MEM_readLE16, MEM_readLE32, MEM_readLE64};
6
7pub const ZSTD_MAGICNUMBER: u32 = 0xFD2FB528;
8pub const ZSTD_MAGIC_DICTIONARY: u32 = 0xEC30A437;
9pub const ZSTD_MAGIC_SKIPPABLE_START: u32 = 0x184D2A50;
10pub const ZSTD_MAGIC_SKIPPABLE_MASK: u32 = 0xFFFFFFF0;
11
12pub const ZSTD_FRAMEIDSIZE: usize = 4;
13pub const ZSTD_SKIPPABLEHEADERSIZE: usize = 8;
14pub const ZSTD_WINDOWLOG_ABSOLUTEMIN: u32 = 10;
15pub const ZSTD_WINDOWLOG_MAX_64: u32 = 31;
16pub const ZSTD_WINDOWLOG_MAX_32: u32 = 30;
17
18pub const ZSTD_CONTENTSIZE_UNKNOWN: u64 = u64::MAX;
19pub const ZSTD_CONTENTSIZE_ERROR: u64 = u64::MAX - 1;
20
21pub const ZSTD_fcs_fieldSize: [usize; 4] = [0, 2, 4, 8];
22pub const ZSTD_did_fieldSize: [usize; 4] = [0, 1, 2, 4];
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
26pub enum ZSTD_format_e {
27 #[default]
28 ZSTD_f_zstd1,
29 ZSTD_f_zstd1_magicless,
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
34pub enum ZSTD_FrameType_e {
35 #[default]
36 ZSTD_frame,
37 ZSTD_skippableFrame,
38}
39
40#[derive(Debug, Clone, Copy, Default)]
42pub struct ZSTD_FrameHeader {
43 pub frameContentSize: u64,
44 pub windowSize: u64,
45 pub blockSizeMax: u32,
46 pub frameType: ZSTD_FrameType_e,
47 pub headerSize: u32,
48 pub dictID: u32,
49 pub checksumFlag: u32,
50 pub _reserved1: u32,
51 pub _reserved2: u32,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
57pub enum ZSTD_dStreamStage {
58 #[default]
59 zdss_init = 0,
60 zdss_loadHeader = 1,
61 zdss_read = 2,
62 zdss_load = 3,
63 zdss_flush = 4,
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
70pub enum ZSTD_dictUses_e {
71 ZSTD_use_indefinitely = -1,
72 #[default]
73 ZSTD_dont_use = 0,
74 ZSTD_use_once = 1,
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
81pub enum ZSTD_dStage {
82 #[default]
83 ZSTDds_getFrameHeaderSize = 0,
84 ZSTDds_decodeFrameHeader = 1,
85 ZSTDds_decodeBlockHeader = 2,
86 ZSTDds_decompressBlock = 3,
87 ZSTDds_decompressLastBlock = 4,
88 ZSTDds_checkChecksum = 5,
89 ZSTDds_decodeSkippableHeader = 6,
90 ZSTDds_skipFrame = 7,
91}
92
93#[inline]
97pub const fn ZSTD_FRAMEHEADERSIZE_PREFIX(format: ZSTD_format_e) -> usize {
98 match format {
99 ZSTD_format_e::ZSTD_f_zstd1 => 5,
100 ZSTD_format_e::ZSTD_f_zstd1_magicless => 1,
101 }
102}
103
104#[inline]
108pub const fn ZSTD_FRAMEHEADERSIZE_MIN(format: ZSTD_format_e) -> usize {
109 match format {
110 ZSTD_format_e::ZSTD_f_zstd1 => 6,
111 ZSTD_format_e::ZSTD_f_zstd1_magicless => 2,
112 }
113}
114
115#[inline]
120pub fn ZSTD_startingInputLength(format: ZSTD_format_e) -> usize {
121 match format {
122 ZSTD_format_e::ZSTD_f_zstd1 => ZSTD_FRAMEIDSIZE + 1,
123 ZSTD_format_e::ZSTD_f_zstd1_magicless => 1,
124 }
125}
126
127pub fn ZSTD_frameHeaderSize_internal(src: &[u8], format: ZSTD_format_e) -> usize {
132 let minInputSize = ZSTD_startingInputLength(format);
133 if src.len() < minInputSize {
134 return ERROR(ErrorCode::SrcSizeWrong);
135 }
136 let fhd = src[minInputSize - 1];
137 let dictID = (fhd & 3) as usize;
138 let singleSegment = ((fhd >> 5) & 1) as usize;
139 let fcsId = (fhd >> 6) as usize;
140 minInputSize
141 + (1 - singleSegment) + ZSTD_did_fieldSize[dictID]
143 + ZSTD_fcs_fieldSize[fcsId]
144 + (singleSegment & (fcsId == 0) as usize) }
146
147pub fn ZSTD_frameHeaderSize(src: &[u8]) -> usize {
153 ZSTD_frameHeaderSize_internal(src, ZSTD_format_e::ZSTD_f_zstd1)
154}
155
156pub fn ZSTD_getFrameHeader_advanced(
161 zfh: &mut ZSTD_FrameHeader,
162 src: &[u8],
163 format: ZSTD_format_e,
164) -> usize {
165 let srcSize = src.len();
166 let minInputSize = ZSTD_startingInputLength(format);
167
168 if srcSize < minInputSize {
169 if srcSize > 0 && format != ZSTD_format_e::ZSTD_f_zstd1_magicless {
171 let toCopy = 4.min(srcSize);
172 let mut hbuf = ZSTD_MAGICNUMBER.to_le_bytes();
173 hbuf[..toCopy].copy_from_slice(&src[..toCopy]);
174 if MEM_readLE32(&hbuf) != ZSTD_MAGICNUMBER {
175 let mut hbuf2 = ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes();
176 hbuf2[..toCopy].copy_from_slice(&src[..toCopy]);
177 if (MEM_readLE32(&hbuf2) & ZSTD_MAGIC_SKIPPABLE_MASK) != ZSTD_MAGIC_SKIPPABLE_START
178 {
179 return ERROR(ErrorCode::PrefixUnknown);
180 }
181 }
182 }
183 return minInputSize;
184 }
185
186 *zfh = ZSTD_FrameHeader::default();
187
188 if format != ZSTD_format_e::ZSTD_f_zstd1_magicless
189 && MEM_readLE32(&src[..4]) != ZSTD_MAGICNUMBER
190 {
191 if (MEM_readLE32(&src[..4]) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START {
192 if srcSize < ZSTD_SKIPPABLEHEADERSIZE {
193 return ZSTD_SKIPPABLEHEADERSIZE;
194 }
195 zfh.frameType = ZSTD_FrameType_e::ZSTD_skippableFrame;
196 zfh.dictID = MEM_readLE32(&src[..4]) - ZSTD_MAGIC_SKIPPABLE_START;
197 zfh.headerSize = ZSTD_SKIPPABLEHEADERSIZE as u32;
198 zfh.frameContentSize =
199 MEM_readLE32(&src[ZSTD_FRAMEIDSIZE..ZSTD_FRAMEIDSIZE + 4]) as u64;
200 return 0;
201 }
202 return ERROR(ErrorCode::PrefixUnknown);
203 }
204
205 let fhsize = ZSTD_frameHeaderSize_internal(src, format);
206 if crate::common::error::ERR_isError(fhsize) {
207 return fhsize;
208 }
209 if srcSize < fhsize {
210 return fhsize;
211 }
212 zfh.headerSize = fhsize as u32;
213
214 let fhdByte = src[minInputSize - 1];
215 let mut pos = minInputSize;
216 let dictIDSizeCode = (fhdByte & 3) as u32;
217 let checksumFlag = ((fhdByte >> 2) & 1) as u32;
218 let singleSegment = ((fhdByte >> 5) & 1) as u32;
219 let fcsID = (fhdByte >> 6) as u32;
220 if (fhdByte & 0x08) != 0 {
221 return ERROR(ErrorCode::FrameParameterUnsupported);
223 }
224
225 let mut windowSize: u64 = 0;
226 let mut dictID: u32 = 0;
227 let mut frameContentSize: u64 = ZSTD_CONTENTSIZE_UNKNOWN;
228
229 if singleSegment == 0 {
230 let wlByte = src[pos];
231 pos += 1;
232 let windowLog = ((wlByte >> 3) as u32) + ZSTD_WINDOWLOG_ABSOLUTEMIN;
233 let winLogMax = if core::mem::size_of::<usize>() == 8 {
234 ZSTD_WINDOWLOG_MAX_64
235 } else {
236 ZSTD_WINDOWLOG_MAX_32
237 };
238 if windowLog > winLogMax {
239 return ERROR(ErrorCode::FrameParameterWindowTooLarge);
240 }
241 windowSize = 1u64 << windowLog;
242 windowSize += (windowSize >> 3) * (wlByte & 7) as u64;
243 }
244 match dictIDSizeCode {
245 0 => {}
246 1 => {
247 dictID = src[pos] as u32;
248 pos += 1;
249 }
250 2 => {
251 dictID = MEM_readLE16(&src[pos..pos + 2]) as u32;
252 pos += 2;
253 }
254 _ => {
255 dictID = MEM_readLE32(&src[pos..pos + 4]);
257 pos += 4;
258 }
259 }
260 match fcsID {
261 0 => {
262 if singleSegment != 0 {
263 frameContentSize = src[pos] as u64;
264 }
265 }
266 1 => frameContentSize = MEM_readLE16(&src[pos..pos + 2]) as u64 + 256,
267 2 => frameContentSize = MEM_readLE32(&src[pos..pos + 4]) as u64,
268 _ => frameContentSize = MEM_readLE64(&src[pos..pos + 8]),
269 }
270 if singleSegment != 0 {
271 windowSize = frameContentSize;
272 }
273
274 zfh.frameType = ZSTD_FrameType_e::ZSTD_frame;
275 zfh.frameContentSize = frameContentSize;
276 zfh.windowSize = windowSize;
277 zfh.blockSizeMax =
278 windowSize.min(crate::decompress::zstd_decompress_block::ZSTD_BLOCKSIZE_MAX as u64) as u32;
279 zfh.dictID = dictID;
280 zfh.checksumFlag = checksumFlag;
281 0
282}
283
284pub fn ZSTD_getFrameHeader(zfh: &mut ZSTD_FrameHeader, src: &[u8]) -> usize {
290 ZSTD_getFrameHeader_advanced(zfh, src, ZSTD_format_e::ZSTD_f_zstd1)
291}
292
293#[cfg(test)]
294#[allow(clippy::field_reassign_with_default)]
295mod tests {
296 use super::*;
297
298 fn build_minimal_zstd_dict(dictID: u32, content: &[u8]) -> Vec<u8> {
303 use crate::common::mem::MEM_writeLE32;
304 use crate::compress::fse_compress::{
305 FSE_buildCTable_wksp, FSE_normalizeCount, FSE_writeNCount,
306 };
307 use crate::compress::huf_compress::{
308 HUF_buildCTable_wksp, HUF_writeCTable, HUF_CTABLE_WORKSPACE_SIZE_U32,
309 };
310 use crate::decompress::zstd_decompress_block::{
311 LL_defaultNorm, LL_defaultNormLog, ML_defaultNorm, ML_defaultNormLog, MaxLL, MaxML,
312 MaxOff, OF_defaultNorm, OF_defaultNormLog,
313 };
314
315 let mut out = Vec::new();
316 let mut magic_bytes = [0u8; 4];
318 MEM_writeLE32(&mut magic_bytes, ZSTD_MAGICNUMBER_DICTIONARY);
319 out.extend_from_slice(&magic_bytes);
320 let mut id_bytes = [0u8; 4];
321 MEM_writeLE32(&mut id_bytes, dictID);
322 out.extend_from_slice(&id_bytes);
323
324 let mut count = [0u32; 256];
326 for &b in content.iter() {
327 count[b as usize] += 1;
328 }
329 for (i, c) in count.iter_mut().enumerate().take(16) {
331 if *c == 0 {
332 *c = 1;
333 let _ = i;
334 }
335 }
336 let maxSymbolValue = count
337 .iter()
338 .enumerate()
339 .rposition(|(_, &c)| c > 0)
340 .unwrap_or(0) as u32;
341 let totalCount: usize = count.iter().sum::<u32>() as usize;
342 let tableLog =
343 crate::compress::huf_compress::HUF_optimalTableLog(11, totalCount, maxSymbolValue);
344 let mut ct = vec![0u64; 257];
345 let mut wksp = vec![0u32; HUF_CTABLE_WORKSPACE_SIZE_U32];
346 FSE_buildCTable_wksp(
347 &mut [0u32; 512], &[0i16; 1],
349 0,
350 5,
351 &mut [0u8; 1024],
352 );
353 let _ = HUF_buildCTable_wksp(&mut ct, &count, maxSymbolValue, tableLog, &mut wksp);
354 let mut huf_hdr = vec![0u8; 512];
355 let w = HUF_writeCTable(&mut huf_hdr, &ct, maxSymbolValue, tableLog);
356 assert!(!crate::common::error::ERR_isError(w));
357 out.extend_from_slice(&huf_hdr[..w]);
358
359 let mut fse_buf = vec![0u8; 256];
361 let w = FSE_writeNCount(&mut fse_buf, &OF_defaultNorm, MaxOff, OF_defaultNormLog);
363 assert!(!crate::common::error::ERR_isError(w));
364 out.extend_from_slice(&fse_buf[..w]);
365 let w = FSE_writeNCount(&mut fse_buf, &ML_defaultNorm, MaxML, ML_defaultNormLog);
367 assert!(!crate::common::error::ERR_isError(w));
368 out.extend_from_slice(&fse_buf[..w]);
369 let w = FSE_writeNCount(&mut fse_buf, &LL_defaultNorm, MaxLL, LL_defaultNormLog);
371 assert!(!crate::common::error::ERR_isError(w));
372 out.extend_from_slice(&fse_buf[..w]);
373 let _ = FSE_normalizeCount;
375
376 let safe = (content.len() as u32).clamp(1, 8);
378 for r in [safe, safe.saturating_sub(1).max(1), 1u32] {
379 let mut rb = [0u8; 4];
380 MEM_writeLE32(&mut rb, r);
381 out.extend_from_slice(&rb);
382 }
383
384 out.extend_from_slice(content);
386 out
387 }
388
389 #[test]
390 fn insertDictionary_roundtrips_magic_prefix_dict() {
391 use crate::decompress::zstd_decompress_block::ZSTD_DCtx;
397 let content = b"zstd-dict-content-bytes-for-compression-context";
398 let dict = build_minimal_zstd_dict(0x1234_5678, content);
399
400 let mut dctx = ZSTD_DCtx::new();
401 let rc = ZSTD_decompress_insertDictionary(&mut dctx, &dict);
402 assert!(
403 !crate::common::error::ERR_isError(rc),
404 "insertDictionary failed: {}",
405 crate::common::error::ERR_getErrorName(rc)
406 );
407 assert_eq!(dctx.dictID, 0x1234_5678);
408 assert_eq!(dctx.stream_dict, content);
409 assert_eq!(dctx.litEntropy, 1);
410 assert_eq!(dctx.fseEntropy, 1);
411 }
412
413 #[test]
414 fn compress_insertDictionary_roundtrips_magic_prefix() {
415 use crate::compress::zstd_compress::{ZSTD_compress_insertDictionary, ZSTD_createCCtx};
419 use crate::compress::zstd_compress_literals::HUF_repeat;
420 use crate::decompress::zstd_ddict::ZSTD_dictContentType_e;
421 let content = b"zstd-dict-content-bytes-for-compression-context";
422 let dict = build_minimal_zstd_dict(0xABCD_1234, content);
423
424 let mut cctx = ZSTD_createCCtx().unwrap();
425 let params = cctx.requestedParams;
426 let rc = ZSTD_compress_insertDictionary(
427 &mut cctx,
428 ¶ms,
429 &dict,
430 ZSTD_dictContentType_e::ZSTD_dct_auto,
431 );
432 assert!(
433 !crate::common::error::ERR_isError(rc),
434 "compress_insertDictionary failed: {}",
435 crate::common::error::ERR_getErrorName(rc)
436 );
437 assert_eq!(cctx.dictID, 0xABCD_1234);
438 assert_eq!(cctx.stream_dict, content);
439 assert_ne!(cctx.prevEntropy.huf.repeatMode, HUF_repeat::HUF_repeat_none);
443 }
444
445 #[test]
446 fn insertDictionary_raw_content_stashes_bytes() {
447 use crate::decompress::zstd_decompress_block::ZSTD_DCtx;
449 let raw = b"this is not a zstd dict, just arbitrary bytes";
450 let mut dctx = ZSTD_DCtx::new();
451 let rc = ZSTD_decompress_insertDictionary(&mut dctx, raw);
452 assert!(!crate::common::error::ERR_isError(rc));
453 assert_eq!(dctx.dictID, 0);
454 assert_eq!(dctx.stream_dict, raw);
455 }
456
457 #[test]
458 fn zstd_sizeof_dctx_includes_owned_tables() {
459 use crate::decompress::zstd_decompress_block::ZSTD_DCtx;
460 let dctx = ZSTD_DCtx::new();
461 let sz = ZSTD_sizeof_DCtx(&dctx);
462 assert!(sz > 4096, "sizeof_DCtx unexpectedly small: {sz}");
464 assert_eq!(ZSTD_sizeof_DStream(&dctx), sz);
466 }
467
468 #[test]
469 fn zstd_sizeof_dctx_grows_when_dict_loaded() {
470 use crate::decompress::zstd_decompress_block::ZSTD_DCtx;
474 let mut dctx = ZSTD_DCtx::new();
475 let before = ZSTD_sizeof_DCtx(&dctx);
476 let dict = vec![0xABu8; 4096];
477 ZSTD_DCtx_loadDictionary(&mut dctx, &dict);
478 let after = ZSTD_sizeof_DCtx(&dctx);
479 assert!(
480 after >= before + dict.len(),
481 "sizeof_DCtx did not reflect loaded dict: before={before} after={after}"
482 );
483 }
484
485 #[test]
486 fn zstd_dParam_getBounds_windowLogMax_range() {
487 let b = ZSTD_dParam_getBounds(ZSTD_dParameter::ZSTD_d_windowLogMax);
492 assert_eq!(b.error, 0);
493 let expected_upper = if crate::common::mem::MEM_32bits() != 0 {
494 30
495 } else {
496 31
497 };
498 assert_eq!((b.lowerBound, b.upperBound), (10, expected_upper));
499 }
500
501 #[test]
502 fn fresh_DCtx_getParameter_windowLogMax_returns_LIMIT_DEFAULT() {
503 let dctx = ZSTD_DCtx::default();
509 let mut got = -999i32;
510 ZSTD_DCtx_getParameter(&dctx, ZSTD_dParameter::ZSTD_d_windowLogMax, &mut got);
511 assert_eq!(got, ZSTD_WINDOWLOG_LIMIT_DEFAULT as i32);
512 }
513
514 #[test]
515 fn DCtx_setParameter_windowLogMax_maps_zero_to_LIMIT_DEFAULT() {
516 let mut dctx = ZSTD_DCtx::default();
521 let rc = ZSTD_DCtx_setParameter(&mut dctx, ZSTD_dParameter::ZSTD_d_windowLogMax, 0);
522 assert_eq!(rc, 0);
523 let mut got = -1i32;
524 ZSTD_DCtx_getParameter(&dctx, ZSTD_dParameter::ZSTD_d_windowLogMax, &mut got);
525 assert_eq!(got, 27);
526 }
527
528 #[test]
529 fn DCtx_setParameter_windowLogMax_rejects_out_of_range() {
530 use crate::common::error::{ERR_getErrorCode, ERR_isError};
533 let mut dctx = ZSTD_DCtx::default();
534 for oor in [-1, 9, 40, 100] {
535 let rc = ZSTD_DCtx_setParameter(&mut dctx, ZSTD_dParameter::ZSTD_d_windowLogMax, oor);
536 assert!(ERR_isError(rc), "expected error for value={oor}");
537 assert_eq!(ERR_getErrorCode(rc), ErrorCode::ParameterOutOfBound);
538 }
539 }
540
541 #[test]
542 fn dParam_bounds_accept_windowLog_at_upper_edge_via_setMaxWindowSize() {
543 let mut dctx = ZSTD_DCtx::default();
554 let min_size = 1usize << 10;
555 assert_eq!(ZSTD_DCtx_setMaxWindowSize(&mut dctx, min_size), 0);
556 let upper = if crate::common::mem::MEM_32bits() != 0 {
557 30
558 } else {
559 31
560 };
561 let max_size = 1usize << upper;
562 assert_eq!(ZSTD_DCtx_setMaxWindowSize(&mut dctx, max_size), 0);
563 }
564
565 #[test]
566 fn zstd_dstream_buffer_sizes_nonzero() {
567 assert!(ZSTD_DStreamInSize() > 0);
568 assert!(ZSTD_DStreamOutSize() > 0);
569 }
570
571 #[test]
572 fn zstd_dctx_setParameter_windowLogMax_roundtrips() {
573 use crate::decompress::zstd_decompress_block::ZSTD_DCtx;
574 let mut dctx = ZSTD_DCtx::new();
575 let rc = ZSTD_DCtx_setParameter(&mut dctx, ZSTD_dParameter::ZSTD_d_windowLogMax, 20);
576 assert_eq!(rc, 0);
577 let mut v = 0i32;
578 ZSTD_DCtx_getParameter(&dctx, ZSTD_dParameter::ZSTD_d_windowLogMax, &mut v);
579 assert_eq!(v, 20);
580 }
581
582 #[test]
583 fn zstd_dctx_reset_clears_streaming_state() {
584 use crate::decompress::zstd_decompress_block::ZSTD_DCtx;
585 let mut dctx = ZSTD_DCtx::new();
586 dctx.stream_in_buffer.extend_from_slice(b"pending");
587 ZSTD_DCtx_reset(&mut dctx, ZSTD_DResetDirective::ZSTD_reset_session_only);
588 assert!(dctx.stream_in_buffer.is_empty());
589 }
590
591 #[test]
592 fn zstd_estimate_dctx_size_positive() {
593 let s = ZSTD_estimateDCtxSize();
594 assert!(s > 0);
595 assert!(ZSTD_estimateDStreamSize(1 << 17) > s);
597 }
598
599 #[test]
600 fn zstd_estimate_dstream_size_from_frame_reflects_window() {
601 let src: Vec<u8> = b"small src for small window".to_vec();
604 let mut dst = vec![0u8; 256];
605 let n = crate::compress::zstd_compress::ZSTD_compress(&mut dst, &src, 1);
606 dst.truncate(n);
607 let from_frame = ZSTD_estimateDStreamSize_fromFrame(&dst);
608 let fallback = ZSTD_estimateDStreamSize_fromFrame(&[0xFF, 0xFF, 0xFF, 0xFF]);
610 assert!(from_frame > 0);
612 assert!(fallback > 0);
613 }
614
615 #[test]
616 fn zstd_decompressBlock_roundtrips_a_compressed_block_body() {
617 use crate::decompress::zstd_decompress_block::{
618 blockProperties_t, blockType_e, ZSTD_DCtx, ZSTD_blockHeaderSize, ZSTD_getcBlockSize,
619 };
620 let src: Vec<u8> = b"hello block api. "
624 .iter()
625 .cycle()
626 .take(200)
627 .copied()
628 .collect();
629
630 let mut frame = vec![0u8; 1024];
633 let n = crate::compress::zstd_compress::ZSTD_compress(&mut frame, &src, 1);
634 frame.truncate(n);
635
636 let mut zfh = super::ZSTD_FrameHeader::default();
638 let rc = super::ZSTD_getFrameHeader(&mut zfh, &frame);
639 assert_eq!(rc, 0);
640 let body_start = zfh.headerSize as usize;
641
642 let mut bp = blockProperties_t {
644 blockType: blockType_e::bt_raw,
645 lastBlock: 0,
646 origSize: 0,
647 };
648 let body_size = ZSTD_getcBlockSize(&frame[body_start..], &mut bp);
649
650 if bp.blockType == blockType_e::bt_compressed {
652 let body = &frame
653 [body_start + ZSTD_blockHeaderSize..body_start + ZSTD_blockHeaderSize + body_size];
654 let mut dctx = ZSTD_DCtx::new();
655 let mut out = vec![0u8; src.len() + 64];
656 let d = ZSTD_decompressBlock(&mut dctx, &mut out, body);
657 assert!(!crate::common::error::ERR_isError(d));
658 assert_eq!(&out[..d], &src[..]);
659 }
660 }
661
662 #[test]
663 fn windowlog_and_contentsize_constants_match_upstream() {
664 assert_eq!(ZSTD_WINDOWLOG_ABSOLUTEMIN, 10);
666 assert_eq!(ZSTD_WINDOWLOG_MAX_64, 31);
667 assert_eq!(ZSTD_WINDOWLOG_MAX_32, 30);
668 assert_eq!(ZSTD_CONTENTSIZE_UNKNOWN, u64::MAX);
673 assert_eq!(ZSTD_CONTENTSIZE_ERROR, u64::MAX - 1);
674 assert_eq!(ZSTD_CONTENTSIZE_UNKNOWN - ZSTD_CONTENTSIZE_ERROR, 1);
678 }
679
680 #[test]
681 fn frame_format_magic_and_size_constants_match_spec() {
682 assert_eq!(ZSTD_MAGICNUMBER, 0xFD2FB528);
686 assert_eq!(ZSTD_MAGIC_DICTIONARY, 0xEC30A437);
687 assert_eq!(ZSTD_MAGIC_SKIPPABLE_START, 0x184D2A50);
688 assert_eq!(ZSTD_MAGIC_SKIPPABLE_MASK, 0xFFFFFFF0);
689 assert_eq!(ZSTD_FRAMEIDSIZE, 4);
690 assert_eq!(ZSTD_SKIPPABLEHEADERSIZE, 8);
691 for v in 0u32..=15 {
694 let magic = ZSTD_MAGIC_SKIPPABLE_START | v;
695 assert_eq!(
696 magic & ZSTD_MAGIC_SKIPPABLE_MASK,
697 ZSTD_MAGIC_SKIPPABLE_START
698 );
699 }
700 }
701
702 #[test]
703 fn zstd_isFrame_detects_regular_and_skippable() {
704 let regular = ZSTD_MAGICNUMBER.to_le_bytes();
706 assert_eq!(ZSTD_isFrame(®ular), 1);
707 let skippable = ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes();
709 assert_eq!(ZSTD_isFrame(&skippable), 1);
710 let skippable15 = (ZSTD_MAGIC_SKIPPABLE_START | 0x0F).to_le_bytes();
712 assert_eq!(ZSTD_isFrame(&skippable15), 1);
713 assert_eq!(ZSTD_isFrame(&[0xDE, 0xAD, 0xBE, 0xEF]), 0);
715 assert_eq!(ZSTD_isFrame(&[0xFD, 0x2F]), 0);
717 assert_eq!(ZSTD_isFrame(&[]), 0);
718 }
719
720 #[test]
721 fn zstd_isSkippableFrame_rejects_regular_frame() {
722 let regular = ZSTD_MAGICNUMBER.to_le_bytes();
723 assert_eq!(ZSTD_isSkippableFrame(®ular), 0);
724 let skippable = (ZSTD_MAGIC_SKIPPABLE_START | 0x05).to_le_bytes();
725 assert_eq!(ZSTD_isSkippableFrame(&skippable), 1);
726 }
727
728 #[test]
729 fn zstd_isFrame_rejects_dictionary_magic() {
730 let dict_magic = ZSTD_MAGIC_DICTIONARY.to_le_bytes();
735 assert_eq!(ZSTD_isFrame(&dict_magic), 0);
736 let mut padded = dict_magic.to_vec();
738 padded.extend_from_slice(&[0u8; 4]);
739 assert_eq!(ZSTD_isFrame(&padded), 0);
740 }
741
742 #[test]
743 fn zstd_isSkippableFrame_rejects_dictionary_magic() {
744 let dict_magic = ZSTD_MAGIC_DICTIONARY.to_le_bytes();
747 assert_eq!(ZSTD_isSkippableFrame(&dict_magic), 0);
748 }
749
750 #[test]
751 fn zstd_isSkippableFrame_accepts_all_16_variants() {
752 for v in 0u32..=15 {
757 let magic = (ZSTD_MAGIC_SKIPPABLE_START + v).to_le_bytes();
758 assert_eq!(
759 ZSTD_isSkippableFrame(&magic),
760 1,
761 "variant {v} didn't register as skippable"
762 );
763 }
764 let invalid = (ZSTD_MAGIC_SKIPPABLE_START + 16).to_le_bytes();
766 assert_eq!(ZSTD_isSkippableFrame(&invalid), 0);
767 }
768
769 #[test]
770 fn zstd_isSkippableFrame_rejects_short_src_safely() {
771 assert_eq!(ZSTD_isSkippableFrame(&[]), 0);
774 assert_eq!(ZSTD_isSkippableFrame(&[0x50]), 0);
775 assert_eq!(ZSTD_isSkippableFrame(&[0x50, 0x2A, 0x4D]), 0);
776 }
777
778 #[test]
779 fn zstd_getDictID_fromFrame_returns_zero_when_absent() {
780 let src: Vec<u8> = b"hello world".to_vec();
782 let mut dst = vec![0u8; 128];
783 let n = crate::compress::zstd_compress::ZSTD_compress(&mut dst, &src, 1);
784 dst.truncate(n);
785 assert_eq!(ZSTD_getDictID_fromFrame(&dst), 0);
786 }
787
788 #[test]
789 fn copyRawBlock_and_setRleBlock_cover_happy_and_dst_too_small_paths() {
790 let src = b"hello-raw";
792 let mut dst = [0u8; 16];
793 let n = ZSTD_copyRawBlock(&mut dst, src);
794 assert_eq!(n, src.len());
795 assert_eq!(&dst[..n], src);
796
797 let mut tiny = [0u8; 4];
798 assert!(crate::common::error::ERR_isError(ZSTD_copyRawBlock(
799 &mut tiny, src
800 )));
801
802 let mut buf = vec![0u8; 32];
804 let rle_n = ZSTD_setRleBlock(&mut buf, 0xAB, 10);
805 assert_eq!(rle_n, 10);
806 assert!(buf[..10].iter().all(|&b| b == 0xAB));
807 assert!(buf[10..].iter().all(|&b| b == 0));
809
810 let mut short = [0u8; 4];
811 assert!(crate::common::error::ERR_isError(ZSTD_setRleBlock(
812 &mut short, 0xCD, 10
813 )));
814 }
815
816 #[test]
817 fn findFrameCompressedSize_matches_compressor_output_for_multi_block() {
818 use crate::compress::zstd_compress::{ZSTD_compress, ZSTD_compressBound};
823 let src: Vec<u8> = b"multi-block frame-size probe. "
824 .iter()
825 .cycle()
826 .take(200_000)
827 .copied()
828 .collect();
829 let bound = ZSTD_compressBound(src.len());
830 let mut dst = vec![0u8; bound];
831 let n = ZSTD_compress(&mut dst, &src, 1);
832 assert!(!crate::common::error::ERR_isError(n));
833
834 let mut with_trailer = dst[..n].to_vec();
837 with_trailer.extend_from_slice(&[0xFFu8; 64]);
838 let reported = ZSTD_findFrameCompressedSize(&with_trailer);
839 assert!(!crate::common::error::ERR_isError(reported));
840 assert_eq!(reported, n);
841 }
842
843 #[test]
844 fn findFrameSizeInfo_reports_skippable_frame_with_zero_decompressed_bound() {
845 let user_data_len: u32 = 10;
853 let mut src = Vec::new();
854 src.extend_from_slice(&ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes());
855 src.extend_from_slice(&user_data_len.to_le_bytes());
856 src.extend(core::iter::repeat_n(0u8, user_data_len as usize));
857
858 let info = ZSTD_findFrameSizeInfo(&src, ZSTD_format_e::ZSTD_f_zstd1);
859 assert_eq!(info.nbBlocks, 0);
860 assert_eq!(info.compressedSize, 8 + user_data_len as usize);
861 assert_eq!(info.decompressedBound, 0);
862 }
863
864 #[test]
865 fn decompressBound_all_skippable_frames_returns_zero() {
866 let mut src = Vec::new();
871 for &user_data_len in &[5u32, 12] {
872 src.extend_from_slice(&ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes());
873 src.extend_from_slice(&user_data_len.to_le_bytes());
874 src.extend(core::iter::repeat_n(0u8, user_data_len as usize));
875 }
876 assert_eq!(ZSTD_decompressBound(&src), 0);
877 }
878
879 #[test]
880 fn findDecompressedSize_all_skippable_frames_returns_zero() {
881 let mut src = Vec::new();
886 for &user_data_len in &[5u32, 12] {
887 src.extend_from_slice(&ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes());
888 src.extend_from_slice(&user_data_len.to_le_bytes());
889 src.extend(core::iter::repeat_n(0u8, user_data_len as usize));
890 }
891 assert_eq!(ZSTD_findDecompressedSize(&src), 0);
892 }
893
894 #[test]
895 fn findDecompressedSize_returns_UNKNOWN_when_any_frame_lacks_fcs() {
896 let raw = make_raw_hello_frame();
901
902 let mut no_fcs = Vec::new();
904 no_fcs.extend_from_slice(&ZSTD_MAGICNUMBER.to_le_bytes());
905 no_fcs.push(0x00); no_fcs.push(0x20); no_fcs.push(((3u32 << 3) | 1) as u8);
909 no_fcs.push(0);
910 no_fcs.push(0);
911 no_fcs.extend_from_slice(b"abc");
912
913 let mut stream = raw;
916 stream.extend_from_slice(&no_fcs);
917 assert_eq!(ZSTD_findDecompressedSize(&stream), ZSTD_CONTENTSIZE_UNKNOWN);
918 }
919
920 #[test]
921 fn getFrameContentSize_reports_compressed_payload_size_across_fcs_encodings() {
922 let sizes: &[u64] = &[
927 1, 300, 100_000, 0x1_0000_0000, ];
932 for &sz in sizes {
933 use crate::compress::zstd_compress::{
937 ZSTD_FrameParameters, ZSTD_writeFrameHeader, ZSTD_FRAMEHEADERSIZE_MAX,
938 };
939 use crate::decompress::zstd_decompress::ZSTD_WINDOWLOG_ABSOLUTEMIN;
940 let fp = ZSTD_FrameParameters {
941 contentSizeFlag: 1,
942 checksumFlag: 0,
943 noDictIDFlag: 1,
944 };
945 let mut hdr = vec![0u8; ZSTD_FRAMEHEADERSIZE_MAX];
946 let n = ZSTD_writeFrameHeader(&mut hdr, &fp, ZSTD_WINDOWLOG_ABSOLUTEMIN + 10, sz, 0);
947 assert!(!crate::common::error::ERR_isError(n));
948 hdr.truncate(n);
949 assert_eq!(
950 ZSTD_getFrameContentSize(&hdr),
951 sz,
952 "FCS roundtrip failed for size={sz}",
953 );
954 }
955 }
956
957 #[test]
958 fn findDecompressedSize_sums_multiple_concatenated_frames() {
959 let parts: &[&[u8]] = &[
964 b"alpha".as_ref(),
965 b"longer-part-here".as_ref(),
966 b"c".as_ref(),
967 ];
968 let expected_total: u64 = parts.iter().map(|p| p.len() as u64).sum();
969
970 let mut stream = Vec::new();
971 for part in parts {
972 let mut buf = vec![0u8; 256];
973 let n = crate::compress::zstd_compress::ZSTD_compress(&mut buf, part, 3);
974 assert!(!crate::common::error::ERR_isError(n));
975 stream.extend_from_slice(&buf[..n]);
976 }
977 assert_eq!(ZSTD_findDecompressedSize(&stream), expected_total);
978
979 let mut stream_with_skip = Vec::new();
982 {
983 let mut buf = vec![0u8; 256];
984 let n = crate::compress::zstd_compress::ZSTD_compress(&mut buf, parts[0], 3);
985 stream_with_skip.extend_from_slice(&buf[..n]);
986 }
987 stream_with_skip.extend_from_slice(&ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes());
988 stream_with_skip.extend_from_slice(&8u32.to_le_bytes());
989 stream_with_skip.extend_from_slice(b"SKIPDATA");
990 {
991 let mut buf = vec![0u8; 256];
992 let n = crate::compress::zstd_compress::ZSTD_compress(&mut buf, parts[1], 3);
993 stream_with_skip.extend_from_slice(&buf[..n]);
994 }
995 assert_eq!(
996 ZSTD_findDecompressedSize(&stream_with_skip),
997 (parts[0].len() + parts[1].len()) as u64,
998 );
999 }
1000
1001 #[test]
1002 fn findDecompressedSize_returns_ERROR_on_trailing_garbage_after_valid_frame() {
1003 let mut src = make_raw_hello_frame();
1009 src.extend_from_slice(&[0x28, 0xB5, 0x2F]);
1012 let rc = ZSTD_findDecompressedSize(&src);
1013 assert_eq!(rc, ZSTD_CONTENTSIZE_ERROR);
1014 }
1015
1016 #[test]
1017 fn zstd_getDictID_fromFrame_reads_dictID_when_present() {
1018 use crate::compress::zstd_compress::{
1022 ZSTD_FrameParameters, ZSTD_writeFrameHeader, ZSTD_FRAMEHEADERSIZE_MAX,
1023 };
1024 let dictID_in = 0xDEAD_BEEFu32;
1025 let fParams = ZSTD_FrameParameters {
1026 contentSizeFlag: 0,
1027 checksumFlag: 0,
1028 noDictIDFlag: 0,
1029 };
1030 let mut buf = [0u8; ZSTD_FRAMEHEADERSIZE_MAX];
1031 let n = ZSTD_writeFrameHeader(&mut buf, &fParams, 17, 0, dictID_in);
1032 assert!(!crate::common::error::ERR_isError(n));
1033 let got = ZSTD_getDictID_fromFrame(&buf[..n]);
1034 assert_eq!(got, dictID_in);
1035 }
1036
1037 #[test]
1038 fn frame_header_truncated_requests_more() {
1039 let mut zfh = ZSTD_FrameHeader::default();
1041 let src = ZSTD_MAGICNUMBER.to_le_bytes();
1042 let rc = ZSTD_getFrameHeader(&mut zfh, &src);
1043 assert_eq!(rc, 5);
1044 }
1045
1046 #[test]
1047 fn createDCtx_advanced_and_createDStream_advanced_return_Some() {
1048 use crate::compress::zstd_compress::ZSTD_customMem;
1051 let _dctx = ZSTD_createDCtx_advanced(ZSTD_customMem::default()).unwrap();
1052 let _dstream = ZSTD_createDStream_advanced(ZSTD_customMem::default()).unwrap();
1053
1054 use crate::compress::zstd_compress::{ZSTD_compress, ZSTD_compressBound};
1057 let src: Vec<u8> = b"DCtx_advanced functional probe ".repeat(20);
1058 let bound = ZSTD_compressBound(src.len());
1059 let mut compressed = vec![0u8; bound];
1060 let n = ZSTD_compress(&mut compressed, &src, 1);
1061 let mut out = vec![0u8; src.len() + 64];
1062 let d = ZSTD_decompress(&mut out, &compressed[..n]);
1063 assert_eq!(&out[..d], &src[..]);
1064 }
1065
1066 #[test]
1067 fn decompresses_upstream_level10_large_real_text_frame() {
1068 use crate::decompress::zstd_decompress_block::{
1069 active_ll_table, active_ml_table, active_of_table, blockProperties_t, blockType_e,
1070 streaming_operation, ZSTD_DCtx, ZSTD_blockHeaderSize, ZSTD_buildDefaultSeqTables,
1071 ZSTD_decodeLiteralsBlock, ZSTD_decodeSeqHeaders, ZSTD_decoder_entropy_rep,
1072 ZSTD_decompressSequences_body, ZSTD_getcBlockSize,
1073 };
1074 use std::fs;
1075 use std::io::Write;
1076 use std::path::PathBuf;
1077 use std::process::{Command, Stdio};
1078
1079 let which = Command::new("which")
1080 .arg("zstd")
1081 .output()
1082 .expect("which zstd");
1083 if !which.status.success() {
1084 eprintln!("upstream zstd not on $PATH; skipping");
1085 return;
1086 }
1087 let zstd = PathBuf::from(String::from_utf8(which.stdout).unwrap().trim());
1088
1089 let seed = fs::read("tests/fixtures/zstd_h.txt").expect("read zstd_h.txt");
1090 let src: Vec<u8> = seed.repeat(20);
1091
1092 let mut child = Command::new(&zstd)
1093 .args(["-q", "--no-check", "-10", "-c", "-"])
1094 .stdin(Stdio::piped())
1095 .stdout(Stdio::piped())
1096 .spawn()
1097 .expect("spawn upstream zstd");
1098 child.stdin.as_mut().unwrap().write_all(&src).unwrap();
1099 let out = child.wait_with_output().expect("wait upstream zstd");
1100 assert!(
1101 out.status.success(),
1102 "upstream compression failed: {}",
1103 String::from_utf8_lossy(&out.stderr)
1104 );
1105 let mut dctx = ZSTD_DCtx::new();
1106 ZSTD_buildDefaultSeqTables(&mut dctx);
1107 let mut decoded = vec![0u8; src.len()];
1108 let mut rep = ZSTD_decoder_entropy_rep::default();
1109 let mut zfh = ZSTD_FrameHeader::default();
1110 let hdr = ZSTD_getFrameHeader_advanced(&mut zfh, &out.stdout, dctx.format);
1111 assert_eq!(hdr, 0);
1112 let mut ip = zfh.headerSize as usize;
1113 let mut op = 0usize;
1114 let mut block_idx = 0usize;
1115 loop {
1116 let mut bp = blockProperties_t {
1117 blockType: blockType_e::bt_raw,
1118 lastBlock: 0,
1119 origSize: 0,
1120 };
1121 let cblock = ZSTD_getcBlockSize(&out.stdout[ip..], &mut bp);
1122 assert!(
1123 !crate::common::error::ERR_isError(cblock),
1124 "block {block_idx}: cblock parse failed: {}",
1125 crate::common::error::ERR_getErrorName(cblock)
1126 );
1127 ip += ZSTD_blockHeaderSize;
1128 match bp.blockType {
1129 blockType_e::bt_compressed => {
1130 let block = &out.stdout[ip..ip + cblock];
1131 let lit_rc = ZSTD_decodeLiteralsBlock(
1132 &mut dctx,
1133 block,
1134 &mut decoded[op..],
1135 streaming_operation::not_streaming,
1136 );
1137 assert!(
1138 !crate::common::error::ERR_isError(lit_rc),
1139 "block {block_idx}: literals failed: {}",
1140 crate::common::error::ERR_getErrorName(lit_rc)
1141 );
1142 let mut nb_seq = 0i32;
1143 let seq_header =
1144 ZSTD_decodeSeqHeaders(&mut dctx, &mut nb_seq, &block[lit_rc..]);
1145 assert!(
1146 !crate::common::error::ERR_isError(seq_header),
1147 "block {block_idx}: seq headers failed: {}",
1148 crate::common::error::ERR_getErrorName(seq_header)
1149 );
1150 let lit_snapshot = dctx.litExtraBuffer[..dctx.litSize].to_vec();
1151 let ll = active_ll_table(&dctx).to_vec();
1152 let of = active_of_table(&dctx).to_vec();
1153 let ml = active_ml_table(&dctx).to_vec();
1154 let seq_rc = ZSTD_decompressSequences_body(
1155 &mut decoded,
1156 op,
1157 &[],
1158 &block[lit_rc + seq_header..],
1159 nb_seq,
1160 &lit_snapshot,
1161 dctx.litSize,
1162 &ll,
1163 &of,
1164 &ml,
1165 &mut rep,
1166 );
1167 assert!(
1168 !crate::common::error::ERR_isError(seq_rc),
1169 "block {block_idx}: sequence body failed: {}",
1170 crate::common::error::ERR_getErrorName(seq_rc)
1171 );
1172 op += seq_rc;
1173 }
1174 blockType_e::bt_raw => {
1175 let rc = ZSTD_copyRawBlock(&mut decoded[op..], &out.stdout[ip..ip + cblock]);
1176 assert!(
1177 !crate::common::error::ERR_isError(rc),
1178 "block {block_idx}: raw block failed: {}",
1179 crate::common::error::ERR_getErrorName(rc)
1180 );
1181 op += rc;
1182 }
1183 blockType_e::bt_rle => {
1184 let rc =
1185 ZSTD_setRleBlock(&mut decoded[op..], out.stdout[ip], bp.origSize as usize);
1186 assert!(
1187 !crate::common::error::ERR_isError(rc),
1188 "block {block_idx}: rle block failed: {}",
1189 crate::common::error::ERR_getErrorName(rc)
1190 );
1191 op += rc;
1192 }
1193 blockType_e::bt_reserved => panic!("block {block_idx}: reserved block"),
1194 }
1195 ip += cblock;
1196 block_idx += 1;
1197 if bp.lastBlock != 0 {
1198 break;
1199 }
1200 }
1201 let d = ZSTD_decompress(&mut decoded, &out.stdout);
1202 assert!(
1203 !crate::common::error::ERR_isError(d),
1204 "rust decompressor rejected upstream frame: {}",
1205 crate::common::error::ERR_getErrorName(d)
1206 );
1207 assert_eq!(&decoded[..op], &src[..]);
1208 assert_eq!(&decoded[..d], &src[..]);
1209 }
1210
1211 #[test]
1212 fn createDCtx_advanced_rejects_invalid_custommem_pairs() {
1213 use crate::compress::zstd_compress::ZSTD_customMem;
1214
1215 fn dummy_alloc(_opaque: usize, _size: usize) -> *mut core::ffi::c_void {
1216 core::ptr::null_mut()
1217 }
1218
1219 let invalid = ZSTD_customMem {
1220 customAlloc: Some(dummy_alloc),
1221 customFree: None,
1222 opaque: 1,
1223 };
1224
1225 assert!(ZSTD_createDCtx_advanced(invalid).is_none());
1226 assert!(ZSTD_createDStream_advanced(invalid).is_none());
1227 }
1228
1229 #[test]
1230 fn advanced_dctx_surfaces_invoke_custom_allocator_callbacks() {
1231 use crate::compress::zstd_compress::ZSTD_customMem;
1232 use core::sync::atomic::{AtomicUsize, Ordering};
1233
1234 static ALLOCS: AtomicUsize = AtomicUsize::new(0);
1235 static FREES: AtomicUsize = AtomicUsize::new(0);
1236
1237 fn counting_alloc(_opaque: usize, size: usize) -> *mut core::ffi::c_void {
1238 use std::alloc::{alloc, Layout};
1239
1240 const ALIGN: usize = 64;
1241 const HEADER_WORDS: usize = 2;
1242
1243 let total = size.max(1) + ALIGN + HEADER_WORDS * core::mem::size_of::<usize>();
1244 let layout = Layout::from_size_align(total, ALIGN).unwrap();
1245 unsafe {
1246 let base = alloc(layout);
1247 if base.is_null() {
1248 return core::ptr::null_mut();
1249 }
1250 let payload_addr =
1251 (base as usize + HEADER_WORDS * core::mem::size_of::<usize>() + ALIGN - 1)
1252 & !(ALIGN - 1);
1253 let header = (payload_addr as *mut usize).sub(HEADER_WORDS);
1254 header.write(base as usize);
1255 header.add(1).write(total);
1256 ALLOCS.fetch_add(1, Ordering::SeqCst);
1257 payload_addr as *mut core::ffi::c_void
1258 }
1259 }
1260
1261 fn counting_free(_opaque: usize, address: *mut core::ffi::c_void) {
1262 use std::alloc::{dealloc, Layout};
1263
1264 const ALIGN: usize = 64;
1265 const HEADER_WORDS: usize = 2;
1266
1267 if address.is_null() {
1268 return;
1269 }
1270 unsafe {
1271 let header = (address as *mut usize).sub(HEADER_WORDS);
1272 let base = header.read() as *mut u8;
1273 let total = header.add(1).read();
1274 let layout = Layout::from_size_align(total, ALIGN).unwrap();
1275 dealloc(base, layout);
1276 FREES.fetch_add(1, Ordering::SeqCst);
1277 }
1278 }
1279
1280 let custom = ZSTD_customMem {
1281 customAlloc: Some(counting_alloc),
1282 customFree: Some(counting_free),
1283 opaque: 11,
1284 };
1285
1286 let dctx = ZSTD_createDCtx_advanced(custom).unwrap();
1287 assert_eq!(dctx.customMem, custom);
1288 let dstream = ZSTD_createDStream_advanced(custom).unwrap();
1289 assert_eq!(dstream.customMem, custom);
1290
1291 assert_eq!(ALLOCS.load(Ordering::SeqCst), 2);
1292 assert_eq!(FREES.load(Ordering::SeqCst), 0);
1293 assert_eq!(ZSTD_freeDCtx(dctx), 0);
1294 assert_eq!(ZSTD_freeDStream(Some(dstream)), 0);
1295 assert_eq!(FREES.load(Ordering::SeqCst), 2);
1296 }
1297
1298 #[test]
1299 fn ZSTD_DStream_is_alias_for_ZSTD_DCtx() {
1300 assert_eq!(
1303 core::mem::size_of::<ZSTD_DStream>(),
1304 core::mem::size_of::<ZSTD_DCtx>()
1305 );
1306 let ds: Box<ZSTD_DStream> = ZSTD_createDStream().unwrap();
1307 assert_eq!(ZSTD_sizeof_DCtx(&ds), ZSTD_sizeof_DStream(&ds));
1308 }
1309
1310 #[test]
1311 fn ZSTD_nextInputType_e_discriminants_match_upstream() {
1312 assert_eq!(ZSTD_nextInputType_e::ZSTDnit_frameHeader as u32, 0);
1318 assert_eq!(ZSTD_nextInputType_e::ZSTDnit_blockHeader as u32, 1);
1319 assert_eq!(ZSTD_nextInputType_e::ZSTDnit_block as u32, 2);
1320 assert_eq!(ZSTD_nextInputType_e::ZSTDnit_lastBlock as u32, 3);
1321 assert_eq!(ZSTD_nextInputType_e::ZSTDnit_checksum as u32, 4);
1322 assert_eq!(ZSTD_nextInputType_e::ZSTDnit_skippableFrame as u32, 5);
1323 }
1324
1325 #[test]
1326 fn decompressStream_simpleArgs_forwards_to_decompressStream() {
1327 use crate::common::error::ERR_isError;
1332 use crate::compress::zstd_compress::{ZSTD_compress, ZSTD_compressBound};
1333
1334 let src = b"decompressStream_simpleArgs smoke test ".repeat(3);
1335 let mut framed = vec![0u8; ZSTD_compressBound(src.len())];
1336 let n = ZSTD_compress(&mut framed, &src, 3);
1337 assert!(!ERR_isError(n));
1338 framed.truncate(n);
1339
1340 let mut dctx = ZSTD_DCtx::new();
1341 ZSTD_initDStream(&mut dctx);
1342 let mut out = vec![0u8; src.len() + 64];
1343 let mut in_pos = 0usize;
1344 let mut out_pos = 0usize;
1345 let _ = ZSTD_decompressStream_simpleArgs(
1346 &mut dctx,
1347 &mut out,
1348 &mut out_pos,
1349 &framed,
1350 &mut in_pos,
1351 );
1352 for _ in 0..8 {
1353 if out_pos >= src.len() {
1354 break;
1355 }
1356 let _ = ZSTD_decompressStream_simpleArgs(
1357 &mut dctx,
1358 &mut out,
1359 &mut out_pos,
1360 &[],
1361 &mut 0usize,
1362 );
1363 }
1364 assert_eq!(&out[..out_pos], &src[..]);
1365 }
1366
1367 #[test]
1368 fn DCtx_reset_parameters_only_rejects_mid_stream_but_combined_variant_always_accepts() {
1369 use crate::common::error::{ERR_getErrorCode, ERR_isError};
1374 use crate::compress::zstd_compress::{ZSTD_compress, ZSTD_compressBound};
1375
1376 let src = b"dctx-reset-stage-semantics ".repeat(3);
1377 let mut framed = vec![0u8; ZSTD_compressBound(src.len())];
1378 let n = ZSTD_compress(&mut framed, &src, 3);
1379 assert!(!ERR_isError(n));
1380 framed.truncate(n);
1381
1382 let mut dctx = ZSTD_DCtx::new();
1383 ZSTD_initDStream(&mut dctx);
1384 let mut out = vec![0u8; src.len() + 64];
1385 let mut in_pos = 0usize;
1386 let mut out_pos = 0usize;
1387 let _ = ZSTD_decompressStream(&mut dctx, &mut out, &mut out_pos, &framed, &mut in_pos);
1388
1389 let rc = ZSTD_DCtx_reset(&mut dctx, ZSTD_DResetDirective::ZSTD_reset_parameters);
1391 assert!(ERR_isError(rc));
1392 assert_eq!(ERR_getErrorCode(rc), ErrorCode::StageWrong);
1393
1394 assert_eq!(
1396 ZSTD_DCtx_reset(&mut dctx, ZSTD_DResetDirective::ZSTD_reset_session_only),
1397 0,
1398 );
1399 assert_eq!(
1401 ZSTD_DCtx_reset(&mut dctx, ZSTD_DResetDirective::ZSTD_reset_parameters),
1402 0,
1403 );
1404
1405 ZSTD_initDStream(&mut dctx);
1407 let mut out = vec![0u8; src.len() + 64];
1408 let mut in_pos = 0usize;
1409 let mut out_pos = 0usize;
1410 let _ = ZSTD_decompressStream(&mut dctx, &mut out, &mut out_pos, &framed, &mut in_pos);
1411 assert_eq!(
1412 ZSTD_DCtx_reset(
1413 &mut dctx,
1414 ZSTD_DResetDirective::ZSTD_reset_session_and_parameters,
1415 ),
1416 0,
1417 );
1418 }
1419
1420 #[test]
1421 fn DCtx_param_setters_reject_mid_stream_with_StageWrong() {
1422 use crate::common::error::{ERR_getErrorCode, ERR_isError};
1428 use crate::compress::zstd_compress::{ZSTD_compress, ZSTD_compressBound};
1429
1430 let src = b"dctx-param-stage-gate ".repeat(4);
1431 let mut framed = vec![0u8; ZSTD_compressBound(src.len())];
1432 let n = ZSTD_compress(&mut framed, &src, 3);
1433 assert!(!ERR_isError(n));
1434 framed.truncate(n);
1435
1436 {
1438 let mut dctx = ZSTD_DCtx::new();
1439 ZSTD_initDStream(&mut dctx);
1440 assert_eq!(
1442 ZSTD_DCtx_setParameter(
1443 &mut dctx,
1444 ZSTD_dParameter::ZSTD_d_format,
1445 ZSTD_format_e::ZSTD_f_zstd1 as i32,
1446 ),
1447 0,
1448 );
1449 let mut out = vec![0u8; src.len() + 64];
1451 let mut in_pos = 0usize;
1452 let mut out_pos = 0usize;
1453 let _ = ZSTD_decompressStream(&mut dctx, &mut out, &mut out_pos, &framed, &mut in_pos);
1454 let rc = ZSTD_DCtx_setParameter(
1455 &mut dctx,
1456 ZSTD_dParameter::ZSTD_d_format,
1457 ZSTD_format_e::ZSTD_f_zstd1_magicless as i32,
1458 );
1459 assert!(ERR_isError(rc));
1460 assert_eq!(ERR_getErrorCode(rc), ErrorCode::StageWrong);
1461 }
1462 {
1464 let mut dctx = ZSTD_DCtx::new();
1465 ZSTD_initDStream(&mut dctx);
1466 assert_eq!(ZSTD_DCtx_setMaxWindowSize(&mut dctx, 1 << 20), 0);
1467 let mut out = vec![0u8; src.len() + 64];
1468 let mut in_pos = 0usize;
1469 let mut out_pos = 0usize;
1470 let _ = ZSTD_decompressStream(&mut dctx, &mut out, &mut out_pos, &framed, &mut in_pos);
1471 let rc = ZSTD_DCtx_setMaxWindowSize(&mut dctx, 1 << 20);
1472 assert!(ERR_isError(rc));
1473 assert_eq!(ERR_getErrorCode(rc), ErrorCode::StageWrong);
1474 }
1475 }
1476
1477 #[test]
1478 fn DCtx_dict_family_setters_reject_mid_stream_with_StageWrong() {
1479 use crate::common::error::{ERR_getErrorCode, ERR_isError};
1484 use crate::compress::zstd_compress::{ZSTD_compress, ZSTD_compressBound};
1485
1486 let dict = b"dctx-dict-family-stage-gate ".repeat(3);
1487 let src = b"some payload bytes ".repeat(4);
1488 let mut framed = vec![0u8; ZSTD_compressBound(src.len())];
1489 let n = ZSTD_compress(&mut framed, &src, 3);
1490 assert!(!ERR_isError(n));
1491 framed.truncate(n);
1492
1493 {
1495 let mut dctx = ZSTD_DCtx::new();
1496 ZSTD_initDStream(&mut dctx);
1497 assert_eq!(ZSTD_DCtx_loadDictionary(&mut dctx, &dict), 0);
1498 let mut out = vec![0u8; src.len() + 64];
1500 let mut in_pos = 0usize;
1501 let mut out_pos = 0usize;
1502 let _ = ZSTD_decompressStream(&mut dctx, &mut out, &mut out_pos, &framed, &mut in_pos);
1503 let rc = ZSTD_DCtx_loadDictionary(&mut dctx, &dict);
1504 assert!(ERR_isError(rc));
1505 assert_eq!(ERR_getErrorCode(rc), ErrorCode::StageWrong);
1506 }
1507 {
1509 let mut dctx = ZSTD_DCtx::new();
1510 ZSTD_initDStream(&mut dctx);
1511 assert_eq!(ZSTD_DCtx_refPrefix(&mut dctx, &dict), 0);
1512 let mut out = vec![0u8; src.len() + 64];
1513 let mut in_pos = 0usize;
1514 let mut out_pos = 0usize;
1515 let _ = ZSTD_decompressStream(&mut dctx, &mut out, &mut out_pos, &framed, &mut in_pos);
1516 let rc = ZSTD_DCtx_refPrefix(&mut dctx, &dict);
1517 assert!(ERR_isError(rc));
1518 assert_eq!(ERR_getErrorCode(rc), ErrorCode::StageWrong);
1519 }
1520 }
1521
1522 #[test]
1523 fn DCtx_getParameter_defaults_on_fresh_dctx_match_upstream() {
1524 let dctx = ZSTD_DCtx::new();
1531 let mut v = 0i32;
1532 assert_eq!(
1533 ZSTD_DCtx_getParameter(&dctx, ZSTD_dParameter::ZSTD_d_windowLogMax, &mut v),
1534 0,
1535 );
1536 assert_eq!(v, ZSTD_WINDOWLOG_LIMIT_DEFAULT as i32);
1537
1538 assert_eq!(
1539 ZSTD_DCtx_getParameter(&dctx, ZSTD_dParameter::ZSTD_d_format, &mut v),
1540 0,
1541 );
1542 assert_eq!(v, ZSTD_format_e::ZSTD_f_zstd1 as i32);
1543 }
1544
1545 #[test]
1546 fn DCtx_reset_parameters_clears_every_dict_slot_via_clearDict_helper() {
1547 let mut dctx = ZSTD_DCtx::new();
1553 dctx.stream_dict = b"reset-wipe-test".to_vec();
1555 dctx.dictID = 0xCA_FE_BA_BE;
1556 dctx.ddict_rep = [7, 8, 9];
1557 dctx.dictUses = ZSTD_dictUses_e::ZSTD_use_indefinitely;
1558
1559 assert_eq!(
1560 ZSTD_DCtx_reset(&mut dctx, ZSTD_DResetDirective::ZSTD_reset_parameters),
1561 0,
1562 );
1563 assert!(dctx.stream_dict.is_empty());
1564 assert_eq!(dctx.dictID, 0);
1565 assert_eq!(dctx.ddict_rep, [0u32; 3]);
1566 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_dont_use);
1567 }
1568
1569 #[test]
1570 fn DCtx_loadDictionary_persists_across_decodes() {
1571 use crate::common::error::ERR_isError;
1577 use crate::common::xxhash::XXH64_state_t;
1578 use crate::compress::zstd_compress::{ZSTD_compress, ZSTD_compressBound};
1579 use crate::decompress::zstd_decompress_block::{
1580 ZSTD_buildDefaultSeqTables, ZSTD_decoder_entropy_rep,
1581 };
1582
1583 let src = b"loadDictionary-persists-across-decodes-payload ".repeat(2);
1584 let mut framed = vec![0u8; ZSTD_compressBound(src.len())];
1585 let n = ZSTD_compress(&mut framed, &src, 3);
1586 framed.truncate(n);
1587
1588 let mut dctx = ZSTD_DCtx::new();
1589 ZSTD_buildDefaultSeqTables(&mut dctx);
1590 let dict = b"persistent-dict-bytes".to_vec();
1591 assert_eq!(ZSTD_DCtx_loadDictionary(&mut dctx, &dict), 0);
1592 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_use_indefinitely);
1593
1594 let mut out = vec![0u8; src.len() + 64];
1595 let mut rep = ZSTD_decoder_entropy_rep::default();
1596 let mut xxh = XXH64_state_t::default();
1597 let d1 = ZSTD_decompressDCtx(&mut dctx, &mut rep, &mut xxh, &mut out, &framed);
1599 assert!(!ERR_isError(d1));
1600 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_use_indefinitely);
1602 assert_eq!(dctx.stream_dict, dict);
1603
1604 let d2 = ZSTD_decompressDCtx(&mut dctx, &mut rep, &mut xxh, &mut out, &framed);
1606 assert!(!ERR_isError(d2));
1607 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_use_indefinitely);
1608 assert_eq!(dctx.stream_dict, dict);
1609 }
1610
1611 #[test]
1612 fn DCtx_refDDict_empty_content_clears_dict_state() {
1613 use crate::decompress::zstd_ddict::ZSTD_DDict;
1618 let mut dctx = ZSTD_DCtx::new();
1619 assert_eq!(ZSTD_DCtx_loadDictionary(&mut dctx, b"pre-existing"), 0);
1620 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_use_indefinitely);
1621
1622 let empty_ddict = ZSTD_DDict {
1624 dictBuffer: Vec::new(),
1625 dictContent: core::ptr::null(),
1626 dictSize: 0,
1627 dictID: 0,
1628 entropyPresent: 0,
1629 };
1630 assert_eq!(ZSTD_DCtx_refDDict(&mut dctx, &empty_ddict), 0);
1631 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_dont_use);
1632 assert!(dctx.stream_dict.is_empty());
1633 assert_eq!(dctx.dictID, 0);
1634 }
1635
1636 #[test]
1637 fn DCtx_loadDictionary_empty_slice_clears_dict_state() {
1638 let mut dctx = ZSTD_DCtx::new();
1642 assert_eq!(ZSTD_DCtx_loadDictionary(&mut dctx, b"real-dict"), 0);
1643 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_use_indefinitely);
1644 assert_eq!(dctx.stream_dict, b"real-dict");
1645
1646 assert_eq!(ZSTD_DCtx_loadDictionary(&mut dctx, &[]), 0);
1648 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_dont_use);
1649 assert!(dctx.stream_dict.is_empty());
1650 assert_eq!(dctx.dictID, 0);
1651 }
1652
1653 #[test]
1654 fn DCtx_refPrefix_empty_slice_clears_dict_state() {
1655 let mut dctx = ZSTD_DCtx::new();
1661 assert_eq!(ZSTD_DCtx_refPrefix(&mut dctx, b"pre-existing"), 0);
1662 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_use_once);
1663 assert!(!dctx.stream_dict.is_empty());
1664
1665 assert_eq!(ZSTD_DCtx_refPrefix(&mut dctx, &[]), 0);
1667 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_dont_use);
1668 assert!(dctx.stream_dict.is_empty());
1669 assert_eq!(dctx.dictID, 0);
1670 }
1671
1672 #[test]
1673 fn decompressStream_refPrefix_auto_clears_after_one_frame() {
1674 use crate::common::error::ERR_isError;
1681 use crate::compress::zstd_compress::{ZSTD_compress, ZSTD_compressBound};
1682
1683 let src = b"streaming-refPrefix-auto-clear-payload ".repeat(2);
1684 let mut framed = vec![0u8; ZSTD_compressBound(src.len())];
1685 let n = ZSTD_compress(&mut framed, &src, 3);
1686 framed.truncate(n);
1687
1688 let mut dctx = ZSTD_DCtx::new();
1689 ZSTD_initDStream(&mut dctx);
1690 let prefix = b"streaming-one-shot-prefix".to_vec();
1692 assert_eq!(ZSTD_DCtx_refPrefix(&mut dctx, &prefix), 0);
1693 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_use_once);
1694
1695 let mut out = vec![0u8; src.len() + 64];
1696 let mut in_pos = 0usize;
1697 let mut out_pos = 0usize;
1698 let _ = ZSTD_decompressStream(&mut dctx, &mut out, &mut out_pos, &framed, &mut in_pos);
1699 for _ in 0..8 {
1700 if out_pos >= src.len() {
1701 break;
1702 }
1703 let _ = ZSTD_decompressStream(&mut dctx, &mut out, &mut out_pos, &[], &mut 0usize);
1704 }
1705 let decoded_len = out_pos;
1706 assert!(!ERR_isError(decoded_len));
1707
1708 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_dont_use);
1711 assert!(
1712 dctx.stream_dict.is_empty(),
1713 "streaming refPrefix dict persisted after one-shot decode",
1714 );
1715 }
1716
1717 #[test]
1718 fn DCtx_refPrefix_auto_clears_after_one_decode() {
1719 use crate::common::error::ERR_isError;
1725 use crate::common::xxhash::XXH64_state_t;
1726 use crate::compress::zstd_compress::{ZSTD_compress, ZSTD_compressBound};
1727 use crate::decompress::zstd_decompress_block::{
1728 ZSTD_buildDefaultSeqTables, ZSTD_decoder_entropy_rep,
1729 };
1730
1731 let src = b"refPrefix-auto-clear-payload ".repeat(3);
1734 let mut framed = vec![0u8; ZSTD_compressBound(src.len())];
1735 let n = ZSTD_compress(&mut framed, &src, 3);
1736 framed.truncate(n);
1737
1738 let mut dctx = ZSTD_DCtx::new();
1739 ZSTD_buildDefaultSeqTables(&mut dctx);
1740 let prefix = b"one-shot-prefix-bytes".to_vec();
1742 assert_eq!(ZSTD_DCtx_refPrefix(&mut dctx, &prefix), 0);
1743 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_use_once);
1744 assert_eq!(dctx.stream_dict, prefix);
1745
1746 let mut out = vec![0u8; src.len() + 64];
1748 let mut rep = ZSTD_decoder_entropy_rep::default();
1749 let mut xxh = XXH64_state_t::default();
1750 let d = ZSTD_decompressDCtx(&mut dctx, &mut rep, &mut xxh, &mut out, &framed);
1751 assert!(!ERR_isError(d));
1752
1753 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_dont_use);
1756 assert!(
1757 dctx.stream_dict.is_empty(),
1758 "refPrefix dict persisted after one-shot decode",
1759 );
1760 }
1761
1762 #[test]
1763 fn DCtx_dict_family_setters_populate_dictUses_lifecycle_tracker() {
1764 use crate::decompress::zstd_ddict::ZSTD_createDDict;
1771 let dict_bytes = b"dictUses-lifecycle-tracker".to_vec();
1772
1773 let mut dctx = ZSTD_DCtx::new();
1775 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_dont_use);
1776 assert_eq!(ZSTD_DCtx_loadDictionary(&mut dctx, &dict_bytes), 0);
1777 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_use_indefinitely);
1778
1779 ZSTD_clearDict(&mut dctx);
1781 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_dont_use);
1782
1783 let mut dctx = ZSTD_DCtx::new();
1785 assert_eq!(ZSTD_DCtx_refPrefix(&mut dctx, &dict_bytes), 0);
1786 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_use_once);
1787
1788 let mut dctx = ZSTD_DCtx::new();
1790 let ddict = ZSTD_createDDict(&dict_bytes).expect("ddict");
1791 assert_eq!(ZSTD_DCtx_refDDict(&mut dctx, &ddict), 0);
1792 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_use_indefinitely);
1793
1794 ZSTD_DCtx_reset(&mut dctx, ZSTD_DResetDirective::ZSTD_reset_parameters);
1796 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_dont_use);
1797 }
1798
1799 #[test]
1800 fn initDStream_usingDDict_parses_magic_prefix_dict_entropy() {
1801 use super::tests::build_minimal_zstd_dict;
1805 use crate::decompress::zstd_ddict::ZSTD_createDDict;
1806 let content = b"initDStream_usingDDict-magic-dict-content ".repeat(2);
1807 let dict = build_minimal_zstd_dict(0x12_34_56_78, &content);
1808 let ddict = ZSTD_createDDict(&dict).expect("ddict create");
1809
1810 let mut dctx = ZSTD_DCtx::new();
1811 let rc = ZSTD_initDStream_usingDDict(&mut dctx, &ddict);
1812 assert!(!crate::common::error::ERR_isError(rc));
1813 assert_eq!(dctx.dictID, 0x12_34_56_78);
1814 assert_eq!(dctx.litEntropy, 1);
1815 assert_eq!(dctx.fseEntropy, 1);
1816 }
1817
1818 #[test]
1819 fn initDStream_usingDict_parses_magic_prefix_dict_entropy() {
1820 use super::tests::build_minimal_zstd_dict;
1828 let content = b"initDStream_usingDict-magic-dict-content ".repeat(2);
1829 let dict = build_minimal_zstd_dict(0xAB_CD_EF_00, &content);
1830
1831 let mut dctx = ZSTD_DCtx::new();
1832 let rc = ZSTD_initDStream_usingDict(&mut dctx, &dict);
1833 assert!(!crate::common::error::ERR_isError(rc));
1834 assert_eq!(dctx.dictID, 0xAB_CD_EF_00);
1836 assert_eq!(dctx.litEntropy, 1);
1838 assert_eq!(dctx.fseEntropy, 1);
1839 }
1840
1841 #[test]
1842 fn DCtx_setMaxWindowSize_handles_non_power_of_two_via_highbit() {
1843 let mut dctx = ZSTD_DCtx::new();
1852 assert_eq!(ZSTD_DCtx_setMaxWindowSize(&mut dctx, 1 << 20), 0);
1854 assert_eq!(dctx.d_windowLogMax, 20);
1855
1856 let mut dctx = ZSTD_DCtx::new();
1859 assert_eq!(ZSTD_DCtx_setMaxWindowSize(&mut dctx, (1usize << 20) + 1), 0,);
1860 assert_eq!(dctx.d_windowLogMax, 20);
1861 }
1862
1863 #[test]
1864 fn internal_decoder_stage_enums_match_upstream() {
1865 assert_eq!(ZSTD_dStreamStage::zdss_init as i32, 0);
1874 assert_eq!(ZSTD_dStreamStage::zdss_loadHeader as i32, 1);
1875 assert_eq!(ZSTD_dStreamStage::zdss_read as i32, 2);
1876 assert_eq!(ZSTD_dStreamStage::zdss_load as i32, 3);
1877 assert_eq!(ZSTD_dStreamStage::zdss_flush as i32, 4);
1878 assert_eq!(ZSTD_dStage::ZSTDds_getFrameHeaderSize as i32, 0);
1879 assert_eq!(ZSTD_dStage::ZSTDds_decodeFrameHeader as i32, 1);
1880 assert_eq!(ZSTD_dStage::ZSTDds_decodeBlockHeader as i32, 2);
1881 assert_eq!(ZSTD_dStage::ZSTDds_decompressBlock as i32, 3);
1882 assert_eq!(ZSTD_dStage::ZSTDds_decompressLastBlock as i32, 4);
1883 assert_eq!(ZSTD_dStage::ZSTDds_checkChecksum as i32, 5);
1884 assert_eq!(ZSTD_dStage::ZSTDds_decodeSkippableHeader as i32, 6);
1885 assert_eq!(ZSTD_dStage::ZSTDds_skipFrame as i32, 7);
1886 assert_eq!(ZSTD_dictUses_e::ZSTD_use_indefinitely as i32, -1);
1887 assert_eq!(ZSTD_dictUses_e::ZSTD_dont_use as i32, 0);
1888 assert_eq!(ZSTD_dictUses_e::ZSTD_use_once as i32, 1);
1889 }
1890
1891 #[test]
1892 fn nextSrcSizeWithInputSize_and_isSkipFrame_match_stage_rules() {
1893 use crate::decompress::zstd_decompress_block::blockType_e;
1894
1895 let mut dctx = ZSTD_DCtx::new();
1896 dctx.expected = 64;
1897 dctx.stage = ZSTD_dStage::ZSTDds_decodeBlockHeader;
1898 assert_eq!(ZSTD_nextSrcSizeToDecompressWithInputSize(&dctx, 7), 64);
1899 assert_eq!(ZSTD_isSkipFrame(&dctx), 0);
1900
1901 dctx.stage = ZSTD_dStage::ZSTDds_decompressBlock;
1902 dctx.bType = blockType_e::bt_compressed;
1903 assert_eq!(ZSTD_nextSrcSizeToDecompressWithInputSize(&dctx, 7), 64);
1904
1905 dctx.bType = blockType_e::bt_raw;
1906 assert_eq!(ZSTD_nextSrcSizeToDecompressWithInputSize(&dctx, 7), 7);
1907 assert_eq!(ZSTD_nextSrcSizeToDecompressWithInputSize(&dctx, 128), 64);
1908
1909 dctx.stage = ZSTD_dStage::ZSTDds_skipFrame;
1910 assert_eq!(ZSTD_isSkipFrame(&dctx), 1);
1911 }
1912
1913 #[test]
1914 fn format_e_and_frameType_e_discriminants_match_upstream() {
1915 assert_eq!(ZSTD_format_e::ZSTD_f_zstd1 as i32, 0);
1922 assert_eq!(ZSTD_format_e::ZSTD_f_zstd1_magicless as i32, 1);
1923 assert_eq!(ZSTD_FrameType_e::ZSTD_frame as i32, 0);
1924 assert_eq!(ZSTD_FrameType_e::ZSTD_skippableFrame as i32, 1);
1925 }
1926
1927 #[test]
1928 fn DResetDirective_discriminants_match_upstream() {
1929 assert_eq!(ZSTD_DResetDirective::ZSTD_reset_session_only as i32, 1);
1932 assert_eq!(ZSTD_DResetDirective::ZSTD_reset_parameters as i32, 2);
1933 assert_eq!(
1934 ZSTD_DResetDirective::ZSTD_reset_session_and_parameters as i32,
1935 3,
1936 );
1937 }
1938
1939 #[test]
1940 fn dParameter_discriminants_match_upstream_zstd_h() {
1941 assert_eq!(ZSTD_dParameter::ZSTD_d_windowLogMax as i32, 100);
1945 assert_eq!(ZSTD_dParameter::ZSTD_d_format as i32, 1000);
1947 }
1948
1949 #[test]
1950 fn DCtx_setParameter_d_format_round_trips_through_getParameter() {
1951 use crate::common::error::{ERR_getErrorCode, ERR_isError, ErrorCode};
1957 let mut dctx = ZSTD_DCtx::new();
1958 let mut value = 0i32;
1959
1960 assert_eq!(
1962 ZSTD_DCtx_getParameter(&dctx, ZSTD_dParameter::ZSTD_d_format, &mut value),
1963 0,
1964 );
1965 assert_eq!(value, ZSTD_format_e::ZSTD_f_zstd1 as i32);
1966
1967 assert_eq!(
1969 ZSTD_DCtx_setParameter(
1970 &mut dctx,
1971 ZSTD_dParameter::ZSTD_d_format,
1972 ZSTD_format_e::ZSTD_f_zstd1_magicless as i32,
1973 ),
1974 0,
1975 );
1976 assert_eq!(dctx.format, ZSTD_format_e::ZSTD_f_zstd1_magicless);
1977
1978 assert_eq!(
1980 ZSTD_DCtx_getParameter(&dctx, ZSTD_dParameter::ZSTD_d_format, &mut value),
1981 0,
1982 );
1983 assert_eq!(value, ZSTD_format_e::ZSTD_f_zstd1_magicless as i32);
1984
1985 let rc = ZSTD_DCtx_setParameter(&mut dctx, ZSTD_dParameter::ZSTD_d_format, 42);
1987 assert!(ERR_isError(rc));
1988 assert_eq!(ERR_getErrorCode(rc), ErrorCode::ParameterOutOfBound);
1989 }
1990
1991 #[test]
1992 fn DCtx_reset_parameters_clears_magicless_format() {
1993 let mut dctx = ZSTD_DCtx::new();
1997 ZSTD_DCtx_setFormat(&mut dctx, ZSTD_format_e::ZSTD_f_zstd1_magicless);
1998 assert_eq!(dctx.format, ZSTD_format_e::ZSTD_f_zstd1_magicless);
1999
2000 ZSTD_DCtx_reset(&mut dctx, ZSTD_DResetDirective::ZSTD_reset_session_only);
2001 assert_eq!(dctx.format, ZSTD_format_e::ZSTD_f_zstd1_magicless);
2002
2003 ZSTD_DCtx_reset(&mut dctx, ZSTD_DResetDirective::ZSTD_reset_parameters);
2004 assert_eq!(dctx.format, ZSTD_format_e::ZSTD_f_zstd1);
2005
2006 ZSTD_DCtx_setFormat(&mut dctx, ZSTD_format_e::ZSTD_f_zstd1_magicless);
2007 ZSTD_DCtx_reset(
2008 &mut dctx,
2009 ZSTD_DResetDirective::ZSTD_reset_session_and_parameters,
2010 );
2011 assert_eq!(dctx.format, ZSTD_format_e::ZSTD_f_zstd1);
2012 }
2013
2014 #[test]
2015 fn DCtx_setFormat_stashes_format_on_dctx() {
2016 use crate::common::error::ERR_isError;
2021 let mut dctx = ZSTD_DCtx::default();
2022 assert_eq!(dctx.format, ZSTD_format_e::ZSTD_f_zstd1);
2023 let rc = ZSTD_DCtx_setFormat(&mut dctx, ZSTD_format_e::ZSTD_f_zstd1_magicless);
2024 assert!(!ERR_isError(rc));
2025 assert_eq!(dctx.format, ZSTD_format_e::ZSTD_f_zstd1_magicless);
2026 }
2027
2028 #[test]
2029 fn initDStream_hint_honors_magicless_format() {
2030 let mut dctx = ZSTD_DCtx::default();
2036 assert_eq!(ZSTD_initDStream(&mut dctx), 5);
2037 assert_eq!(ZSTD_resetDStream(&mut dctx), 5);
2038 dctx.format = ZSTD_format_e::ZSTD_f_zstd1_magicless;
2039 assert_eq!(ZSTD_initDStream(&mut dctx), 1);
2040 assert_eq!(ZSTD_resetDStream(&mut dctx), 1);
2041 }
2042
2043 #[test]
2044 fn decompress_usingDict_honors_magicless_format_on_dctx() {
2045 use crate::common::error::ERR_isError;
2052 use crate::compress::zstd_compress::{
2053 ZSTD_CCtx_setFormat, ZSTD_createCCtx, ZSTD_endStream, ZSTD_initCStream_usingDict,
2054 };
2055
2056 let dict = b"usingDict-magicless-parity-dict-bytes ".repeat(4);
2057 let src = b"payload-referencing-usingDict-magicless-parity-dict-bytes ".repeat(6);
2058 let mut cctx = ZSTD_createCCtx().unwrap();
2059 assert_eq!(
2060 ZSTD_CCtx_setFormat(&mut cctx, ZSTD_format_e::ZSTD_f_zstd1_magicless),
2061 0,
2062 );
2063 ZSTD_initCStream_usingDict(&mut cctx, &dict, 3);
2064
2065 let mut compressed = vec![0u8; 4096];
2066 let mut cp = 0usize;
2067 let mut sp = 0usize;
2068 let _ = crate::compress::zstd_compress::ZSTD_compressStream(
2069 &mut cctx,
2070 &mut compressed,
2071 &mut cp,
2072 &src,
2073 &mut sp,
2074 );
2075 loop {
2076 let r = ZSTD_endStream(&mut cctx, &mut compressed, &mut cp);
2077 assert!(!ERR_isError(r));
2078 if r == 0 {
2079 break;
2080 }
2081 }
2082 compressed.truncate(cp);
2083
2084 let mut dctx = ZSTD_DCtx::new();
2085 assert_eq!(
2086 ZSTD_DCtx_setFormat(&mut dctx, ZSTD_format_e::ZSTD_f_zstd1_magicless),
2087 0,
2088 );
2089 let mut out = vec![0u8; src.len() + 128];
2090 let d = ZSTD_decompress_usingDict(&mut dctx, &mut out, &compressed, &dict);
2091 assert!(!ERR_isError(d), "decode err: {d:#x}");
2092 assert_eq!(&out[..d], &src[..]);
2093 }
2094
2095 #[test]
2096 fn decompressStream_honors_magicless_format() {
2097 use crate::common::error::ERR_isError;
2103 use crate::compress::zstd_compress::{ZSTD_compress, ZSTD_compressBound};
2104 let src = b"streaming-magicless-decode-parity-payload ".repeat(10);
2105 let mut framed = vec![0u8; ZSTD_compressBound(src.len())];
2106 let c_sz = ZSTD_compress(&mut framed, &src, 3);
2107 assert!(!ERR_isError(c_sz));
2108 framed.truncate(c_sz);
2109 let magicless = framed[4..].to_vec();
2110
2111 let mut dctx = ZSTD_DCtx::new();
2112 let _ = ZSTD_DCtx_setFormat(&mut dctx, ZSTD_format_e::ZSTD_f_zstd1_magicless);
2113 ZSTD_initDStream(&mut dctx);
2114
2115 let mut out = vec![0u8; src.len() + 64];
2116 let mut in_pos = 0usize;
2117 let mut out_pos = 0usize;
2118 let _hint =
2119 ZSTD_decompressStream(&mut dctx, &mut out, &mut out_pos, &magicless, &mut in_pos);
2120 for _ in 0..8 {
2121 if out_pos >= src.len() {
2122 break;
2123 }
2124 let _ = ZSTD_decompressStream(&mut dctx, &mut out, &mut out_pos, &[], &mut 0usize);
2125 }
2126 assert_eq!(&out[..out_pos], &src[..]);
2127 }
2128
2129 #[test]
2130 fn decompressFrame_honors_magicless_format() {
2131 use crate::common::xxhash::XXH64_state_t;
2136 use crate::compress::zstd_compress::{ZSTD_compress, ZSTD_compressBound};
2137 use crate::decompress::zstd_decompress_block::{
2138 ZSTD_DCtx, ZSTD_buildDefaultSeqTables, ZSTD_decoder_entropy_rep,
2139 };
2140
2141 let src = b"Hello, magicless zstd world! 0123456789";
2142 let mut zstd_framed = vec![0u8; ZSTD_compressBound(src.len())];
2143 let c_sz = ZSTD_compress(&mut zstd_framed, src, 1);
2144 assert!(!crate::common::error::ERR_isError(c_sz));
2145 zstd_framed.truncate(c_sz);
2146
2147 let magicless = &zstd_framed[4..];
2149
2150 let mut dctx = ZSTD_DCtx::new();
2151 ZSTD_buildDefaultSeqTables(&mut dctx);
2152 let rc = ZSTD_DCtx_setFormat(&mut dctx, ZSTD_format_e::ZSTD_f_zstd1_magicless);
2153 assert!(!crate::common::error::ERR_isError(rc));
2154
2155 let mut out = vec![0u8; src.len()];
2156 let mut rep = ZSTD_decoder_entropy_rep::default();
2157 let mut xxh = XXH64_state_t::default();
2158 let mut consumed = 0usize;
2159 let decoded = ZSTD_decompressFrame(
2160 &mut dctx,
2161 &mut rep,
2162 &mut xxh,
2163 &mut out,
2164 magicless,
2165 &mut consumed,
2166 );
2167 assert!(
2168 !crate::common::error::ERR_isError(decoded),
2169 "decompressFrame failed: {}",
2170 crate::common::error::ERR_getErrorName(decoded)
2171 );
2172 assert_eq!(decoded, src.len());
2173 assert_eq!(&out[..decoded], src);
2174 assert_eq!(consumed, magicless.len());
2176 }
2177
2178 #[test]
2179 fn decompressContinue_rejects_wrong_chunk_size() {
2180 let mut dctx = ZSTD_DCtx::default();
2181 let mut dst = [0u8; 64];
2182 let src = b"some-input";
2183 let rc = ZSTD_decompressContinue(&mut dctx, &mut dst, src);
2184 assert!(crate::common::error::ERR_isError(rc));
2185 use crate::common::error::ERR_getErrorCode;
2186 assert_eq!(ERR_getErrorCode(rc), ErrorCode::SrcSizeWrong);
2187 }
2188
2189 #[test]
2190 fn decompressContinue_roundtrips_single_raw_block_frame() {
2191 use crate::common::mem::MEM_writeLE24;
2192 use crate::compress::zstd_compress::{
2193 ZSTD_FrameParameters, ZSTD_writeFrameHeader, ZSTD_FRAMEHEADERSIZE_MAX,
2194 };
2195
2196 let payload = b"legacy continue raw block";
2197 let fparams = ZSTD_FrameParameters {
2198 contentSizeFlag: 1,
2199 checksumFlag: 0,
2200 noDictIDFlag: 1,
2201 };
2202 let mut header = [0u8; ZSTD_FRAMEHEADERSIZE_MAX];
2203 let hsize = ZSTD_writeFrameHeader(&mut header, &fparams, 17, payload.len() as u64, 0);
2204 assert!(!crate::common::error::ERR_isError(hsize));
2205
2206 let mut frame = Vec::with_capacity(hsize + 3 + payload.len());
2207 frame.extend_from_slice(&header[..hsize]);
2208 let blockHeader = 1u32 | ((payload.len() as u32) << 3);
2209 let mut bh = [0u8; 3];
2210 MEM_writeLE24(&mut bh, blockHeader);
2211 frame.extend_from_slice(&bh);
2212 frame.extend_from_slice(payload);
2213
2214 let mut dctx = ZSTD_DCtx::default();
2215 let mut out = vec![0u8; payload.len()];
2216 let mut ip = 0usize;
2217 let mut op = 0usize;
2218
2219 while ip < frame.len() {
2220 let chunk = ZSTD_nextSrcSizeToDecompress(&dctx);
2221 let produced =
2222 ZSTD_decompressContinue(&mut dctx, &mut out[op..], &frame[ip..ip + chunk]);
2223 assert!(
2224 !crate::common::error::ERR_isError(produced),
2225 "decompressContinue failed at ip={ip}: {}",
2226 crate::common::error::ERR_getErrorName(produced)
2227 );
2228 ip += chunk;
2229 op += produced;
2230 }
2231
2232 assert_eq!(op, payload.len());
2233 assert_eq!(&out[..op], payload);
2234 assert_eq!(
2235 ZSTD_nextSrcSizeToDecompress(&dctx),
2236 ZSTD_startingInputLength(ZSTD_format_e::ZSTD_f_zstd1)
2237 );
2238 }
2239
2240 #[test]
2241 fn decompressContinue_multi_block_with_independent_dst_buffers() {
2242 use crate::compress::zstd_compress::ZSTD_compress;
2252
2253 let chunk: Vec<u8> = (0..65_536u32)
2259 .map(|i| ((i * 17 + 3) & 0xFF) as u8)
2260 .collect();
2261 let mut payload = chunk.clone();
2262 for _ in 0..8 {
2263 payload.extend_from_slice(&chunk);
2264 }
2265
2266 let mut compressed = vec![0u8; payload.len() + 1024];
2267 let n = ZSTD_compress(&mut compressed, &payload, 1);
2268 assert!(
2269 !crate::common::error::ERR_isError(n),
2270 "compress failed: {}",
2271 crate::common::error::ERR_getErrorName(n)
2272 );
2273 compressed.truncate(n);
2274
2275 let mut dctx = ZSTD_DCtx::default();
2281 let mut ip = 0usize;
2282 let mut decoded: Vec<u8> = Vec::with_capacity(payload.len());
2283
2284 while ip < compressed.len() {
2285 let chunk = ZSTD_nextSrcSizeToDecompress(&dctx);
2286 if chunk == 0 {
2287 break;
2288 }
2289 let block_max = dctx
2291 .fParams
2292 .blockSizeMax
2293 .max(crate::decompress::zstd_decompress_block::ZSTD_BLOCKSIZE_MAX as u32)
2294 as usize;
2295 let mut block_dst = vec![0u8; block_max + 64];
2296 let produced =
2297 ZSTD_decompressContinue(&mut dctx, &mut block_dst, &compressed[ip..ip + chunk]);
2298 assert!(
2299 !crate::common::error::ERR_isError(produced),
2300 "decompressContinue at ip={ip}, chunk={chunk}: {}",
2301 crate::common::error::ERR_getErrorName(produced)
2302 );
2303 decoded.extend_from_slice(&block_dst[..produced]);
2304 ip += chunk;
2305 }
2306
2307 assert_eq!(decoded.len(), payload.len(), "decoded length mismatch");
2308 assert_eq!(decoded, payload, "decoded bytes differ from payload");
2309 }
2310
2311 #[test]
2312 fn stream_workspace_helpers_track_overflow_and_continue_wrapper() {
2313 use crate::common::mem::MEM_writeLE24;
2314 use crate::compress::zstd_compress::{
2315 ZSTD_FrameParameters, ZSTD_writeFrameHeader, ZSTD_FRAMEHEADERSIZE_MAX,
2316 };
2317
2318 let mut dctx = ZSTD_DCtx::default();
2319 dctx.stream_in_buffer.reserve(128);
2320 dctx.stream_out_buffer.reserve(128);
2321 assert_eq!(ZSTD_DCtx_isOverflow(&dctx, 16, 16), 1);
2322 ZSTD_DCtx_updateOversizedDuration(&mut dctx, 16, 16);
2323 assert_eq!(dctx.oversizedDuration, 1);
2324 ZSTD_DCtx_updateOversizedDuration(&mut dctx, 1024, 1024);
2325 assert_eq!(dctx.oversizedDuration, 0);
2326 assert_eq!(ZSTD_checkOutBuffer(&dctx, &[], 0), 0);
2327
2328 let payload = b"continue-stream wrapper";
2329 let fparams = ZSTD_FrameParameters {
2330 contentSizeFlag: 1,
2331 checksumFlag: 0,
2332 noDictIDFlag: 1,
2333 };
2334 let mut header = [0u8; ZSTD_FRAMEHEADERSIZE_MAX];
2335 let hsize = ZSTD_writeFrameHeader(&mut header, &fparams, 17, payload.len() as u64, 0);
2336 assert!(!crate::common::error::ERR_isError(hsize));
2337
2338 let mut frame = Vec::new();
2339 frame.extend_from_slice(&header[..hsize]);
2340 let blockHeader = 1u32 | ((payload.len() as u32) << 3);
2341 let mut bh = [0u8; 3];
2342 MEM_writeLE24(&mut bh, blockHeader);
2343 frame.extend_from_slice(&bh);
2344 frame.extend_from_slice(payload);
2345
2346 let mut zds = ZSTD_DCtx::default();
2347 let mut out = vec![0u8; payload.len()];
2348 let mut ip = 0usize;
2349 let mut op = 0usize;
2350 while ip < frame.len() {
2351 let chunk = ZSTD_nextSrcSizeToDecompress(&zds);
2352 let rc =
2353 ZSTD_decompressContinueStream(&mut zds, &mut out, &mut op, &frame[ip..ip + chunk]);
2354 assert!(
2355 !crate::common::error::ERR_isError(rc),
2356 "continue stream failed at ip={ip}: {}",
2357 crate::common::error::ERR_getErrorName(rc)
2358 );
2359 ip += chunk;
2360 }
2361 assert_eq!(&out[..op], payload);
2362 }
2363
2364 #[test]
2365 fn decodeFrameHeader_sets_checksum_and_rejects_wrong_dict() {
2366 use crate::common::error::ERR_getErrorCode;
2367 use crate::compress::zstd_compress::{
2368 ZSTD_FrameParameters, ZSTD_writeFrameHeader, ZSTD_FRAMEHEADERSIZE_MAX,
2369 };
2370
2371 let fparams = ZSTD_FrameParameters {
2372 contentSizeFlag: 1,
2373 checksumFlag: 1,
2374 noDictIDFlag: 0,
2375 };
2376 let mut header = [0u8; ZSTD_FRAMEHEADERSIZE_MAX];
2377 let hsize = ZSTD_writeFrameHeader(&mut header, &fparams, 17, 11, 0x1234);
2378 assert!(!crate::common::error::ERR_isError(hsize));
2379
2380 let mut dctx = ZSTD_DCtx::default();
2381 dctx.dictID = 0x1234;
2382 let rc = ZSTD_decodeFrameHeader(&mut dctx, &header[..hsize], hsize);
2383 assert_eq!(rc, 0);
2384 assert_eq!(dctx.fParams.dictID, 0x1234);
2385 assert_eq!(dctx.validateChecksum, 1);
2386 assert_eq!(dctx.processedCSize, hsize as u64);
2387
2388 let mut wrong = ZSTD_DCtx::default();
2389 wrong.dictID = 0x5678;
2390 let rc = ZSTD_decodeFrameHeader(&mut wrong, &header[..hsize], hsize);
2391 assert!(crate::common::error::ERR_isError(rc));
2392 assert_eq!(ERR_getErrorCode(rc), ErrorCode::DictionaryWrong);
2393 }
2394
2395 #[test]
2396 fn getDDict_and_refDictContent_follow_upstream_lifecycle() {
2397 let mut dctx = ZSTD_DCtx::default();
2398 let dict = b"raw dictionary bytes";
2399
2400 assert_eq!(ZSTD_refDictContent(&mut dctx, dict), 0);
2401 dctx.dictUses = ZSTD_dictUses_e::ZSTD_use_once;
2402 assert_eq!(dctx.prefixStart, Some(dict.as_ptr() as usize));
2403 assert_eq!(
2404 dctx.previousDstEnd,
2405 Some(dict.as_ptr() as usize + dict.len())
2406 );
2407
2408 let used = ZSTD_getDDict(&mut dctx).expect("one-shot dict");
2409 assert_eq!(used, dict);
2410 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_dont_use);
2411 assert!(dctx.stream_dict.is_empty());
2412 assert!(ZSTD_getDDict(&mut dctx).is_none());
2413 }
2414
2415 #[test]
2416 fn ddict_hashset_inserts_replaces_and_expands() {
2417 use crate::compress::zstd_compress::ZSTD_customMem;
2418 use crate::decompress::zstd_ddict::ZSTD_DDict;
2419
2420 fn make_ddict(dictID: u32, content: &[u8]) -> ZSTD_DDict {
2421 let dictBuffer = content.to_vec();
2422 let dictContent = dictBuffer.as_ptr();
2423 ZSTD_DDict {
2424 dictBuffer,
2425 dictContent,
2426 dictSize: content.len(),
2427 dictID,
2428 entropyPresent: 0,
2429 }
2430 }
2431
2432 let first = make_ddict(7, b"first");
2433 let replacement = make_ddict(7, b"replacement");
2434 let mut set = ZSTD_createDDictHashSet(ZSTD_customMem::default());
2435 assert_eq!(
2436 ZSTD_DDictHashSet_addDDict(&mut set, &first, ZSTD_customMem::default()),
2437 0
2438 );
2439 assert_eq!(set.ddictPtrCount, 1);
2440 assert!(core::ptr::eq(
2441 ZSTD_DDictHashSet_getDDict(&set, 7).expect("first"),
2442 &first
2443 ));
2444
2445 assert_eq!(
2446 ZSTD_DDictHashSet_addDDict(&mut set, &replacement, ZSTD_customMem::default()),
2447 0
2448 );
2449 assert_eq!(set.ddictPtrCount, 1);
2450 assert!(core::ptr::eq(
2451 ZSTD_DDictHashSet_getDDict(&set, 7).expect("replacement"),
2452 &replacement
2453 ));
2454
2455 let many: Vec<Box<ZSTD_DDict>> = (100..121)
2456 .map(|id| Box::new(make_ddict(id, &[id as u8; 3])))
2457 .collect();
2458 for ddict in &many {
2459 assert_eq!(
2460 ZSTD_DDictHashSet_addDDict(&mut set, ddict.as_ref(), ZSTD_customMem::default()),
2461 0
2462 );
2463 }
2464 assert!(set.ddictPtrTableSize > DDICT_HASHSET_TABLE_BASE_SIZE);
2465 for ddict in &many {
2466 let found = ZSTD_DDictHashSet_getDDict(&set, ddict.dictID).expect("present");
2467 assert!(core::ptr::eq(found, ddict.as_ref()));
2468 }
2469 assert!(ZSTD_DDictHashSet_getDDict(&set, 0xFFFF).is_none());
2470
2471 let mut dctx = ZSTD_DCtx::default();
2472 dctx.fParams.dictID = 117;
2473 let selected = ZSTD_DCtx_selectFrameDDict(&mut dctx, &set).expect("selected");
2474 assert_eq!(selected.dictID, 117);
2475 assert_eq!(dctx.dictID, 117);
2476 assert_eq!(dctx.dictUses, ZSTD_dictUses_e::ZSTD_use_indefinitely);
2477 assert_eq!(dctx.stream_dict, [117u8; 3]);
2478 }
2479
2480 #[test]
2481 fn decoder_rejects_corrupted_xxh64_trailer_with_checksumWrong() {
2482 use crate::compress::match_state::ZSTD_compressionParameters;
2486 use crate::compress::zstd_compress::{
2487 ZSTD_FrameParameters, ZSTD_compressBound, ZSTD_compressFrame_fast, ZSTD_getCParams,
2488 };
2489
2490 let src: Vec<u8> = b"payload with xxh64 trailer ".repeat(40);
2491 let bound = ZSTD_compressBound(src.len());
2492 let mut dst = vec![0u8; bound];
2493 let cp: ZSTD_compressionParameters = ZSTD_getCParams(3, src.len() as u64, 0);
2494 let fp = ZSTD_FrameParameters {
2495 contentSizeFlag: 1,
2496 checksumFlag: 1,
2497 noDictIDFlag: 1,
2498 };
2499 let n = ZSTD_compressFrame_fast(&mut dst, &src, cp, fp);
2500 assert!(!crate::common::error::ERR_isError(n));
2501 dst.truncate(n);
2502
2503 let last = dst.len() - 1;
2505 dst[last] ^= 0x01;
2506
2507 let mut out = vec![0u8; src.len() + 64];
2508 let rc = ZSTD_decompress(&mut out, &dst);
2509 assert!(
2510 crate::common::error::ERR_isError(rc),
2511 "decoder missed corrupted checksum (rc={rc})"
2512 );
2513 assert_eq!(
2514 crate::common::error::ERR_getErrorCode(rc),
2515 ErrorCode::ChecksumWrong,
2516 "expected ChecksumWrong, got {:?}",
2517 crate::common::error::ERR_getErrorCode(rc)
2518 );
2519 }
2520
2521 #[test]
2522 fn resetDStream_clears_streaming_state_and_returns_next_hint() {
2523 use crate::decompress::zstd_decompress_block::ZSTD_DCtx;
2530 let mut dctx = ZSTD_DCtx::new();
2531 dctx.stream_in_buffer.extend_from_slice(b"pending-in");
2532 dctx.stream_out_buffer.extend_from_slice(b"pending-out");
2533 dctx.stream_out_drained = 4;
2534 dctx.stream_dict = b"sticky-dict".to_vec();
2535
2536 let hint = ZSTD_resetDStream(&mut dctx);
2537 assert_eq!(hint, ZSTD_startingInputLength(ZSTD_format_e::ZSTD_f_zstd1));
2538 assert_eq!(hint, 5);
2539 assert!(dctx.stream_in_buffer.is_empty());
2540 assert!(dctx.stream_out_buffer.is_empty());
2541 assert_eq!(dctx.stream_out_drained, 0);
2542 assert_eq!(dctx.stream_dict, b"sticky-dict");
2544 }
2545
2546 #[test]
2547 fn multi_frame_roundtrip_across_3_frames_with_interleaved_skippables() {
2548 use crate::compress::zstd_compress::{
2553 ZSTD_compress, ZSTD_compressBound, ZSTD_writeSkippableFrame,
2554 };
2555
2556 let payloads: [&[u8]; 3] = [
2557 b"payload-alpha ",
2558 b"payload-beta-is-a-bit-longer ",
2559 b"payload-gamma! ",
2560 ];
2561
2562 let mut combined = Vec::new();
2563 let mut expected = Vec::new();
2564 let mut skip = vec![0u8; 32];
2566 let n = ZSTD_writeSkippableFrame(&mut skip, b"leading", 0);
2567 combined.extend_from_slice(&skip[..n]);
2568 for (i, payload) in payloads.iter().enumerate() {
2570 let bound = ZSTD_compressBound(payload.len());
2571 let mut c = vec![0u8; bound];
2572 let n = ZSTD_compress(&mut c, payload, 1);
2573 assert!(!crate::common::error::ERR_isError(n));
2574 combined.extend_from_slice(&c[..n]);
2575 expected.extend_from_slice(payload);
2576 if i == 0 {
2578 let mut skip2 = vec![0u8; 24];
2579 let n2 = ZSTD_writeSkippableFrame(&mut skip2, b"mid", 7);
2580 combined.extend_from_slice(&skip2[..n2]);
2581 }
2582 }
2583
2584 let mut out = vec![0u8; expected.len() + 64];
2585 let d = ZSTD_decompress(&mut out, &combined);
2586 assert!(!crate::common::error::ERR_isError(d));
2587 assert_eq!(d, expected.len());
2588 assert_eq!(&out[..d], &expected[..]);
2589 }
2590
2591 #[test]
2592 fn zstd_decompress_loops_over_concatenated_frames() {
2593 use crate::compress::zstd_compress::{
2598 ZSTD_compress, ZSTD_compressBound, ZSTD_writeSkippableFrame,
2599 };
2600 let src = b"concat probe content ".to_vec();
2601 let bound = ZSTD_compressBound(src.len());
2602 let mut frame = vec![0u8; bound];
2603 let n = ZSTD_compress(&mut frame, &src, 1);
2604 frame.truncate(n);
2605
2606 let mut combined = frame.clone();
2609 let mut skip = vec![0u8; 16];
2610 let skip_n = ZSTD_writeSkippableFrame(&mut skip, b"meta", 1);
2611 combined.extend_from_slice(&skip[..skip_n]);
2612 combined.extend_from_slice(&frame);
2613
2614 let mut out = vec![0u8; src.len() * 2 + 64];
2615 let d = ZSTD_decompress(&mut out, &combined);
2616 assert!(!crate::common::error::ERR_isError(d));
2617 assert_eq!(d, src.len() * 2);
2618 assert_eq!(&out[..src.len()], &src[..]);
2619 assert_eq!(&out[src.len()..src.len() * 2], &src[..]);
2620 }
2621
2622 #[test]
2623 fn decompress_rejects_truncated_frame_body_with_error() {
2624 use crate::compress::zstd_compress::{ZSTD_compress, ZSTD_compressBound};
2629 let src: Vec<u8> = b"truncation probe content ".repeat(30);
2630 let bound = ZSTD_compressBound(src.len());
2631 let mut compressed = vec![0u8; bound];
2632 let n = ZSTD_compress(&mut compressed, &src, 3);
2633 assert!(!crate::common::error::ERR_isError(n));
2634
2635 let truncated_len = n * 7 / 10;
2638 assert!(truncated_len > 10 && truncated_len < n);
2639 let truncated = &compressed[..truncated_len];
2640
2641 let mut out = vec![0u8; src.len() + 64];
2642 let rc = ZSTD_decompress(&mut out, truncated);
2643 assert!(
2644 crate::common::error::ERR_isError(rc),
2645 "decoder accepted truncated input (rc={rc}) — must reject",
2646 );
2647 }
2648
2649 #[test]
2650 fn two_independent_dctxs_decode_same_frame_to_same_output() {
2651 use crate::compress::zstd_compress::{ZSTD_compress, ZSTD_compressBound};
2657 let src: Vec<u8> = b"DCtx-isolation test payload. ".repeat(30);
2658 let bound = ZSTD_compressBound(src.len());
2659 let mut compressed = vec![0u8; bound];
2660 let n = ZSTD_compress(&mut compressed, &src, 3);
2661 assert!(!crate::common::error::ERR_isError(n));
2662 compressed.truncate(n);
2663
2664 let mut a = ZSTD_DCtx::new();
2667 let mut b = ZSTD_DCtx::new();
2668 ZSTD_DCtx_loadDictionary(&mut a, b"some-dict-A");
2669 ZSTD_DCtx_loadDictionary(&mut b, b"other-dict-B");
2670
2671 let mut out_a = vec![0u8; src.len() + 64];
2672 let d_a = ZSTD_decompress(&mut out_a, &compressed);
2673 assert_eq!(&out_a[..d_a], &src[..]);
2674
2675 let mut out_b = vec![0u8; src.len() + 64];
2676 let d_b = ZSTD_decompress(&mut out_b, &compressed);
2677 assert_eq!(&out_b[..d_b], &src[..]);
2678
2679 assert_eq!(a.stream_dict, b"some-dict-A");
2681 assert_eq!(b.stream_dict, b"other-dict-B");
2682 }
2683
2684 #[test]
2685 fn zstd_decompress_rejects_too_small_dst_buffer() {
2686 use crate::compress::zstd_compress::{ZSTD_compress, ZSTD_compressBound};
2690 let src: Vec<u8> = b"payload that won't fit in a tiny dst. ".repeat(20);
2691 let bound = ZSTD_compressBound(src.len());
2692 let mut compressed = vec![0u8; bound];
2693 let n = ZSTD_compress(&mut compressed, &src, 1);
2694 assert!(!crate::common::error::ERR_isError(n));
2695
2696 let mut tiny_dst = [0u8; 16];
2698 let rc = ZSTD_decompress(&mut tiny_dst, &compressed[..n]);
2699 assert!(crate::common::error::ERR_isError(rc));
2700 }
2701
2702 #[test]
2703 fn zstd_decompress_rejects_garbage_without_panicking() {
2704 let mut dst = vec![0u8; 1024];
2709 let test_inputs: Vec<Vec<u8>> = vec![
2713 vec![0u8], vec![0u8; 3], vec![0xFFu8; 8], {
2717 let mut v = ZSTD_MAGICNUMBER.to_le_bytes().to_vec();
2719 v.push(0x20);
2720 v
2721 },
2722 {
2723 let mut v = ZSTD_MAGICNUMBER.to_le_bytes().to_vec();
2725 v.extend_from_slice(&[0x28, 100]); v
2727 },
2728 (0..200u8).map(|i| i.wrapping_mul(17)).collect(), ];
2730 let empty_rc = ZSTD_decompress(&mut dst, &[]);
2732 assert!(!crate::common::error::ERR_isError(empty_rc));
2733 assert_eq!(empty_rc, 0);
2734 for (i, input) in test_inputs.iter().enumerate() {
2735 let rc = ZSTD_decompress(&mut dst, input);
2736 assert!(
2737 crate::common::error::ERR_isError(rc),
2738 "input #{i} (len={}) should have errored but returned {rc}",
2739 input.len(),
2740 );
2741 }
2742 }
2743
2744 #[test]
2745 fn startingInputLength_differs_by_format() {
2746 assert_eq!(ZSTD_startingInputLength(ZSTD_format_e::ZSTD_f_zstd1), 5);
2749 assert_eq!(
2750 ZSTD_startingInputLength(ZSTD_format_e::ZSTD_f_zstd1_magicless),
2751 1
2752 );
2753 }
2754
2755 #[test]
2756 fn getFrameHeader_advanced_magicless_skips_magic_check() {
2757 let src = [0x20u8, 42];
2762 let mut zfh = ZSTD_FrameHeader::default();
2763 let rc =
2764 ZSTD_getFrameHeader_advanced(&mut zfh, &src, ZSTD_format_e::ZSTD_f_zstd1_magicless);
2765 assert_eq!(rc, 0);
2766 assert_eq!(zfh.frameContentSize, 42);
2767 assert_eq!(zfh.headerSize, 2);
2769 }
2770
2771 #[test]
2772 fn frameHeaderSize_rejects_too_short_input() {
2773 assert!(crate::common::error::ERR_isError(ZSTD_frameHeaderSize(&[])));
2777 assert!(crate::common::error::ERR_isError(ZSTD_frameHeaderSize(&[
2778 0xFDu8
2779 ])));
2780 assert!(crate::common::error::ERR_isError(ZSTD_frameHeaderSize(&[
2781 0u8, 0, 0, 0
2782 ])));
2783 }
2784
2785 #[test]
2786 fn frameHeaderSize_returns_exact_size_for_each_layout() {
2787 let magic = ZSTD_MAGICNUMBER.to_le_bytes();
2796
2797 let mut src = magic.to_vec();
2799 src.push(0x20); src.push(42); assert_eq!(ZSTD_frameHeaderSize(&src), 6);
2802
2803 let mut src = magic.to_vec();
2805 src.push(0x00);
2806 src.push(0x20);
2807 assert_eq!(ZSTD_frameHeaderSize(&src), 6);
2808
2809 let mut src = magic.to_vec();
2811 src.push((1 << 6) | (1 << 5));
2812 src.extend_from_slice(&744u16.to_le_bytes());
2813 assert_eq!(ZSTD_frameHeaderSize(&src), 7);
2814
2815 let mut src = magic.to_vec();
2817 src.push((3 << 6) | (1 << 5));
2818 src.extend_from_slice(&0u64.to_le_bytes());
2819 assert_eq!(ZSTD_frameHeaderSize(&src), 13);
2820 }
2821
2822 #[test]
2823 fn frame_header_rejects_oversized_windowLog() {
2824 let mut src = ZSTD_MAGICNUMBER.to_le_bytes().to_vec();
2828 src.push(0x00); src.push(22u8 << 3); let mut zfh = ZSTD_FrameHeader::default();
2831 let rc = ZSTD_getFrameHeader(&mut zfh, &src);
2832 assert!(crate::common::error::ERR_isError(rc));
2833 assert_eq!(
2834 crate::common::error::ERR_getErrorCode(rc),
2835 ErrorCode::FrameParameterWindowTooLarge
2836 );
2837 }
2838
2839 #[test]
2840 fn frame_header_accepts_max_windowLog() {
2841 let mut src = ZSTD_MAGICNUMBER.to_le_bytes().to_vec();
2844 src.push(0x00);
2845 src.push(21u8 << 3);
2846 let mut zfh = ZSTD_FrameHeader::default();
2847 let rc = ZSTD_getFrameHeader(&mut zfh, &src);
2848 assert_eq!(rc, 0);
2849 assert_eq!(zfh.windowSize, 1u64 << 31);
2850 }
2851
2852 #[test]
2853 fn frame_header_bad_magic_errors() {
2854 let mut zfh = ZSTD_FrameHeader::default();
2855 let src = [0xFF, 0xFF, 0xFF, 0xFF, 0, 0];
2856 let rc = ZSTD_getFrameHeader(&mut zfh, &src);
2857 assert!(crate::common::error::ERR_isError(rc));
2858 assert_eq!(
2859 crate::common::error::ERR_getErrorCode(rc),
2860 ErrorCode::PrefixUnknown
2861 );
2862 }
2863
2864 #[test]
2865 fn frame_header_skippable_frame() {
2866 let mut src = Vec::new();
2868 src.extend_from_slice(&ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes());
2869 src.extend_from_slice(&42u32.to_le_bytes());
2870 let mut zfh = ZSTD_FrameHeader::default();
2871 let rc = ZSTD_getFrameHeader(&mut zfh, &src);
2872 assert_eq!(rc, 0);
2873 assert_eq!(zfh.frameType, ZSTD_FrameType_e::ZSTD_skippableFrame);
2874 assert_eq!(zfh.frameContentSize, 42);
2875 assert_eq!(zfh.dictID, 0);
2876 assert_eq!(zfh.headerSize, ZSTD_SKIPPABLEHEADERSIZE as u32);
2877 }
2878
2879 #[test]
2880 fn frame_header_single_segment_no_dict_no_fcs() {
2881 let mut src = Vec::new();
2886 src.extend_from_slice(&ZSTD_MAGICNUMBER.to_le_bytes());
2887 src.push(0x20); src.push(100); let mut zfh = ZSTD_FrameHeader::default();
2890 let rc = ZSTD_getFrameHeader(&mut zfh, &src);
2891 assert_eq!(rc, 0);
2892 assert_eq!(zfh.frameType, ZSTD_FrameType_e::ZSTD_frame);
2893 assert_eq!(zfh.frameContentSize, 100);
2894 assert_eq!(zfh.windowSize, 100); assert_eq!(zfh.checksumFlag, 0);
2896 assert_eq!(zfh.dictID, 0);
2897 assert_eq!(zfh.headerSize, 6);
2898 }
2899
2900 #[test]
2901 fn frame_header_fcs_size_variants() {
2902 {
2911 let mut src = Vec::new();
2912 src.extend_from_slice(&ZSTD_MAGICNUMBER.to_le_bytes());
2913 src.push((1 << 6) | (1 << 5)); src.extend_from_slice(&744u16.to_le_bytes());
2915 let mut zfh = ZSTD_FrameHeader::default();
2916 let rc = ZSTD_getFrameHeader(&mut zfh, &src);
2917 assert_eq!(rc, 0);
2918 assert_eq!(zfh.frameContentSize, 1000);
2919 assert_eq!(zfh.windowSize, 1000);
2920 assert_eq!(zfh.headerSize, 7);
2921 }
2922
2923 {
2925 let mut src = Vec::new();
2926 src.extend_from_slice(&ZSTD_MAGICNUMBER.to_le_bytes());
2927 src.push((2 << 6) | (1 << 5)); src.extend_from_slice(&123_456u32.to_le_bytes());
2929 let mut zfh = ZSTD_FrameHeader::default();
2930 let rc = ZSTD_getFrameHeader(&mut zfh, &src);
2931 assert_eq!(rc, 0);
2932 assert_eq!(zfh.frameContentSize, 123_456);
2933 assert_eq!(zfh.windowSize, 123_456);
2934 assert_eq!(zfh.headerSize, 9);
2935 }
2936
2937 {
2939 let mut src = Vec::new();
2940 src.extend_from_slice(&ZSTD_MAGICNUMBER.to_le_bytes());
2941 src.push((3 << 6) | (1 << 5)); src.extend_from_slice(&9_999_999_999u64.to_le_bytes());
2943 let mut zfh = ZSTD_FrameHeader::default();
2944 let rc = ZSTD_getFrameHeader(&mut zfh, &src);
2945 assert_eq!(rc, 0);
2946 assert_eq!(zfh.frameContentSize, 9_999_999_999);
2947 assert_eq!(zfh.headerSize, 13);
2948 }
2949 }
2950
2951 #[test]
2952 fn frame_header_window_descriptor() {
2953 let mut src = Vec::new();
2957 src.extend_from_slice(&ZSTD_MAGICNUMBER.to_le_bytes());
2958 src.push(0x00); src.push(0x20); let mut zfh = ZSTD_FrameHeader::default();
2962 let rc = ZSTD_getFrameHeader(&mut zfh, &src);
2963 assert_eq!(rc, 0);
2964 assert_eq!(zfh.windowSize, 1u64 << 14);
2965 assert_eq!(zfh.frameContentSize, ZSTD_CONTENTSIZE_UNKNOWN);
2966 }
2967
2968 fn make_raw_hello_frame() -> Vec<u8> {
2969 let mut src = Vec::new();
2970 src.extend_from_slice(&ZSTD_MAGICNUMBER.to_le_bytes());
2971 src.push(0x20); src.push(5); let bh = (5u32 << 3) | (1); src.push((bh & 0xFF) as u8);
2975 src.push(((bh >> 8) & 0xFF) as u8);
2976 src.push(((bh >> 16) & 0xFF) as u8);
2977 src.extend_from_slice(b"HELLO");
2978 src
2979 }
2980
2981 #[test]
2982 fn get_frame_content_size_returns_declared_fcs() {
2983 let src = make_raw_hello_frame();
2984 let fcs = ZSTD_getFrameContentSize(&src);
2985 assert_eq!(fcs, 5);
2986 }
2987
2988 #[test]
2989 fn get_frame_content_size_unknown_on_absent_fcs() {
2990 let mut src = Vec::new();
2992 src.extend_from_slice(&ZSTD_MAGICNUMBER.to_le_bytes());
2993 src.push(0x00); src.push(0x20); let fcs = ZSTD_getFrameContentSize(&src);
2996 assert_eq!(fcs, ZSTD_CONTENTSIZE_UNKNOWN);
2997 }
2998
2999 #[test]
3000 fn get_frame_content_size_error_on_bad_magic() {
3001 let src = [0xFFu8; 16];
3002 let fcs = ZSTD_getFrameContentSize(&src);
3003 assert_eq!(fcs, ZSTD_CONTENTSIZE_ERROR);
3004 }
3005
3006 #[test]
3007 fn get_frame_content_size_zero_for_skippable_frame() {
3008 let mut src = Vec::new();
3013 src.extend_from_slice(&ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes());
3014 src.extend_from_slice(&12u32.to_le_bytes()); src.extend_from_slice(&[0u8; 12]);
3016 assert_eq!(ZSTD_getFrameContentSize(&src), 0);
3017 }
3018
3019 #[test]
3020 fn find_frame_compressed_size_matches_hand_count() {
3021 let src = make_raw_hello_frame();
3022 let sz = ZSTD_findFrameCompressedSize(&src);
3023 assert_eq!(sz, src.len());
3024 }
3025
3026 #[test]
3027 fn decompressionMargin_nonzero_for_valid_frame() {
3028 let src = b"the fast brown fox ".repeat(32);
3030 let mut dst = vec![0u8; 256];
3031 let n = crate::compress::zstd_compress::ZSTD_compress(&mut dst, &src, 3);
3032 dst.truncate(n);
3033 let margin = ZSTD_decompressionMargin(&dst);
3034 assert!(!crate::common::error::ERR_isError(margin));
3035 assert!(margin > 0);
3036 assert!(margin < 200 * 1024);
3040 }
3041
3042 #[test]
3043 fn decompressionMargin_includes_checksum_bytes_when_flag_is_set() {
3044 let src = b"fast brown fox ".repeat(32);
3049 let mut cctx_a = crate::compress::zstd_compress::ZSTD_createCCtx().unwrap();
3050 crate::compress::zstd_compress::ZSTD_CCtx_setParameter(
3051 &mut cctx_a,
3052 crate::compress::zstd_compress::ZSTD_cParameter::ZSTD_c_checksumFlag,
3053 0,
3054 );
3055 let mut dst_no_chk = vec![0u8; 256];
3056 let n_no =
3057 crate::compress::zstd_compress::ZSTD_compress2(&mut cctx_a, &mut dst_no_chk, &src);
3058 assert!(!crate::common::error::ERR_isError(n_no));
3059 dst_no_chk.truncate(n_no);
3060
3061 let mut cctx_b = crate::compress::zstd_compress::ZSTD_createCCtx().unwrap();
3062 crate::compress::zstd_compress::ZSTD_CCtx_setParameter(
3063 &mut cctx_b,
3064 crate::compress::zstd_compress::ZSTD_cParameter::ZSTD_c_checksumFlag,
3065 1,
3066 );
3067 let mut dst_chk = vec![0u8; 256];
3068 let n_chk = crate::compress::zstd_compress::ZSTD_compress2(&mut cctx_b, &mut dst_chk, &src);
3069 assert!(!crate::common::error::ERR_isError(n_chk));
3070 dst_chk.truncate(n_chk);
3071
3072 let m_no = ZSTD_decompressionMargin(&dst_no_chk);
3073 let m_chk = ZSTD_decompressionMargin(&dst_chk);
3074 assert!(!crate::common::error::ERR_isError(m_no));
3075 assert!(!crate::common::error::ERR_isError(m_chk));
3076 assert!(
3080 m_chk >= m_no + 4,
3081 "checksum margin must include ≥4 bytes over plain margin: chk={m_chk}, no={m_no}"
3082 );
3083 }
3084
3085 #[test]
3086 fn decompressionMargin_rejects_garbage_input() {
3087 let rc = ZSTD_decompressionMargin(&[0u8; 32]);
3089 assert!(crate::common::error::ERR_isError(rc));
3090 }
3091
3092 #[test]
3093 fn decompressBound_empty_input_is_zero() {
3094 assert_eq!(ZSTD_decompressBound(&[]), 0);
3095 }
3096
3097 #[test]
3098 fn decompressBound_corrupted_input_returns_error_sentinel() {
3099 let bogus = [0u8, 1, 2, 3, 4, 5, 6, 7];
3101 assert_eq!(ZSTD_decompressBound(&bogus), ZSTD_CONTENTSIZE_ERROR);
3102 }
3103
3104 #[test]
3105 fn decompressBound_upper_bounds_real_decompressed_size() {
3106 use crate::compress::zstd_compress::{ZSTD_compress, ZSTD_compressBound};
3111 for &size in &[0usize, 1, 33, 1024, 65_536, 131_073] {
3112 let src: Vec<u8> = (0..size as u32).map(|i| (i ^ (i >> 5)) as u8).collect();
3113 for &level in &[1i32, 3, 10] {
3114 let bound = ZSTD_compressBound(src.len());
3115 let mut dst = vec![0u8; bound];
3116 let n = ZSTD_compress(&mut dst, &src, level);
3117 assert!(!crate::common::error::ERR_isError(n));
3118 let db = ZSTD_decompressBound(&dst[..n]);
3119 assert!(
3120 db != ZSTD_CONTENTSIZE_ERROR,
3121 "decompressBound flagged error on valid frame size={size} level={level}"
3122 );
3123 assert!(
3124 db >= size as u64,
3125 "bound under-reports: size={size} level={level} bound={db}",
3126 );
3127 }
3128 }
3129 }
3130
3131 #[test]
3132 fn decompressBound_sums_frames() {
3133 let mut src = make_raw_hello_frame();
3135 src.extend_from_slice(&make_raw_hello_frame());
3136 src.extend_from_slice(&ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes());
3137 src.extend_from_slice(&4u32.to_le_bytes());
3138 src.extend_from_slice(&[0u8; 4]);
3139 let bound = ZSTD_decompressBound(&src);
3140 assert_eq!(bound, 10);
3142 }
3143
3144 #[test]
3145 fn getDecompressedSize_zero_on_unknown() {
3146 let raw = make_raw_hello_frame();
3148 let got = ZSTD_getDecompressedSize(&raw);
3149 assert_eq!(got, 5);
3151
3152 let bogus = [0u8, 1, 2, 3];
3154 assert_eq!(ZSTD_getDecompressedSize(&bogus), 0);
3155
3156 let mut no_fcs = Vec::new();
3160 no_fcs.extend_from_slice(&ZSTD_MAGICNUMBER.to_le_bytes());
3161 no_fcs.push(0x00); no_fcs.push(0x20); assert_eq!(ZSTD_getDecompressedSize(&no_fcs), 0);
3164 }
3165
3166 #[test]
3167 fn decodingBufferSize_min_basic() {
3168 let sz = ZSTD_decodingBufferSize_min(1024, 1024);
3170 assert!(!crate::common::error::ERR_isError(sz));
3171 assert!(sz >= 1024);
3172 }
3173
3174 #[test]
3175 fn decodingBufferSize_min_matches_upstream_formula() {
3176 use crate::common::zstd_internal::WILDCOPY_OVERLENGTH;
3182 use crate::decompress::zstd_decompress_block::ZSTD_BLOCKSIZE_MAX;
3183
3184 let w = 1024u64;
3186 let fcs = u64::MAX; let expected = w + 2 * w + (WILDCOPY_OVERLENGTH as u64) * 2;
3188 assert_eq!(ZSTD_decodingBufferSize_min(w, fcs) as u64, expected);
3189
3190 let w2 = 1u64 << 20;
3192 let expected2 = w2 + 2 * ZSTD_BLOCKSIZE_MAX as u64 + (WILDCOPY_OVERLENGTH as u64) * 2;
3193 assert_eq!(ZSTD_decodingBufferSize_min(w2, fcs) as u64, expected2);
3194
3195 let tiny = 200u64;
3197 assert_eq!(ZSTD_decodingBufferSize_min(w2, tiny) as u64, tiny);
3198 }
3199
3200 #[test]
3201 fn copyDCtx_deep_copies_all_state() {
3202 let mut src = ZSTD_DCtx::default();
3203 src.stream_dict = b"marker-dict".to_vec();
3204 src.d_windowLogMax = 25;
3205
3206 let mut dst = ZSTD_DCtx::default();
3207 ZSTD_copyDCtx(&mut dst, &src);
3208 assert_eq!(dst.stream_dict, b"marker-dict");
3209 assert_eq!(dst.d_windowLogMax, 25);
3210 }
3211
3212 #[test]
3213 fn initDStream_family_returns_startingInputLength() {
3214 use crate::decompress::zstd_ddict::ZSTD_createDDict;
3220 let expected = ZSTD_startingInputLength(ZSTD_format_e::ZSTD_f_zstd1);
3221 let mut a = ZSTD_DCtx::default();
3222 assert_eq!(ZSTD_initDStream(&mut a), expected);
3223 let mut b = ZSTD_DCtx::default();
3224 assert_eq!(ZSTD_initDStream_usingDict(&mut b, b"seed-dict"), expected);
3225 let mut c = ZSTD_DCtx::default();
3226 let ddict = ZSTD_createDDict(b"seed-ddict").expect("ddict");
3227 assert_eq!(ZSTD_initDStream_usingDDict(&mut c, &ddict), expected);
3228 }
3229
3230 #[test]
3231 fn initDStream_usingDDict_copies_dict_content() {
3232 use crate::decompress::zstd_ddict::ZSTD_createDDict;
3233 let dict = b"test-dict-content".to_vec();
3234 let ddict = ZSTD_createDDict(&dict).expect("ddict");
3235 let mut dctx = ZSTD_DCtx::default();
3236 let rc = ZSTD_initDStream_usingDDict(&mut dctx, &ddict);
3237 assert_eq!(rc, ZSTD_startingInputLength(ZSTD_format_e::ZSTD_f_zstd1));
3242 assert_eq!(dctx.stream_dict, dict);
3243 }
3244
3245 #[test]
3246 fn nextSrcSizeToDecompress_starts_at_frame_header_prefix() {
3247 let dctx = ZSTD_DCtx::default();
3248 assert_eq!(
3249 ZSTD_nextSrcSizeToDecompress(&dctx),
3250 ZSTD_startingInputLength(ZSTD_format_e::ZSTD_f_zstd1)
3251 );
3252 }
3253
3254 #[test]
3255 fn insertBlock_updates_history_end_and_contiguity_state() {
3256 let mut dctx = ZSTD_DCtx::default();
3257 let a = vec![1u8; 8];
3258 let b = vec![2u8; 5];
3259
3260 let n = ZSTD_insertBlock(&mut dctx, &a);
3261 assert_eq!(n, a.len());
3262 assert_eq!(dctx.prefixStart, Some(a.as_ptr() as usize));
3263 assert_eq!(dctx.previousDstEnd, Some(a.as_ptr() as usize + a.len()));
3264 assert_eq!(dctx.dictEnd, None);
3265
3266 let n = ZSTD_insertBlock(&mut dctx, &b);
3267 assert_eq!(n, b.len());
3268 assert_eq!(dctx.dictEnd, Some(a.as_ptr() as usize + a.len()));
3269 assert_eq!(dctx.prefixStart, Some(b.as_ptr() as usize));
3270 assert_eq!(dctx.previousDstEnd, Some(b.as_ptr() as usize + b.len()));
3271 }
3272
3273 #[test]
3274 fn initDStream_preserves_configured_dict() {
3275 let mut dctx = ZSTD_DCtx::default();
3279 dctx.stream_dict = b"sticky-dict".to_vec();
3280 ZSTD_initDStream(&mut dctx);
3281 assert_eq!(dctx.stream_dict, b"sticky-dict");
3282 }
3283
3284 #[test]
3285 fn dParam_all_variants_set_get_roundtrip() {
3286 let mut dctx = ZSTD_DCtx::default();
3289 let cases = [(ZSTD_dParameter::ZSTD_d_windowLogMax, 20)];
3290 for &(param, value) in &cases {
3291 ZSTD_DCtx_setParameter(&mut dctx, param, value);
3292 let mut got = -1i32;
3293 ZSTD_DCtx_getParameter(&dctx, param, &mut got);
3294 assert_eq!(got, value, "param {:?} didn't round-trip", param);
3295 }
3296 }
3297
3298 #[test]
3299 fn dctx_reset_modes_differ_correctly() {
3300 let mut dctx = ZSTD_DCtx::default();
3301 dctx.stream_dict = b"prior-dict".to_vec();
3302 dctx.d_windowLogMax = 25;
3303
3304 ZSTD_DCtx_reset(&mut dctx, ZSTD_DResetDirective::ZSTD_reset_session_only);
3306 assert_eq!(dctx.stream_dict, b"prior-dict");
3307 assert_eq!(dctx.d_windowLogMax, 25);
3308
3309 ZSTD_DCtx_reset(&mut dctx, ZSTD_DResetDirective::ZSTD_reset_parameters);
3313 assert!(dctx.stream_dict.is_empty());
3314 assert_eq!(dctx.d_windowLogMax, ZSTD_WINDOWLOG_LIMIT_DEFAULT);
3315
3316 dctx.stream_dict = b"seed-again".to_vec();
3318 dctx.d_windowLogMax = 20;
3319 ZSTD_DCtx_reset(
3320 &mut dctx,
3321 ZSTD_DResetDirective::ZSTD_reset_session_and_parameters,
3322 );
3323 assert!(dctx.stream_dict.is_empty());
3324 assert_eq!(dctx.d_windowLogMax, ZSTD_WINDOWLOG_LIMIT_DEFAULT);
3325 }
3326
3327 #[test]
3328 fn decompress_side_free_functions_accept_none_without_panic() {
3329 assert_eq!(ZSTD_freeDStream(None), 0);
3334 assert_eq!(crate::decompress::zstd_ddict::ZSTD_freeDDict(None), 0);
3335 }
3336
3337 #[test]
3338 fn decompressBegin_variants_seed_dict_consistently() {
3339 use crate::decompress::zstd_ddict::ZSTD_createDDict;
3345 let dict = b"begin-usingDict-seed".to_vec();
3346
3347 let mut a = ZSTD_DCtx::default();
3348 assert_eq!(ZSTD_decompressBegin_usingDict(&mut a, &dict), 0);
3349 assert_eq!(a.stream_dict, dict);
3350
3351 let ddict = ZSTD_createDDict(&dict).expect("ddict");
3352 let mut b = ZSTD_DCtx::default();
3353 assert_eq!(ZSTD_decompressBegin_usingDDict(&mut b, &ddict), 0);
3354 assert_eq!(b.stream_dict, dict);
3355
3356 let mut c = ZSTD_DCtx::default();
3359 c.stream_dict = b"preloaded".to_vec();
3360 assert_eq!(ZSTD_decompressBegin(&mut c), 0);
3361 assert_eq!(c.stream_dict, b"preloaded");
3362 }
3363
3364 #[test]
3365 fn DCtx_refDDict_seeds_stream_dict_and_roundtrips_via_stream_api() {
3366 use crate::compress::zstd_compress::{ZSTD_compress_usingDict, ZSTD_createCCtx};
3370 use crate::decompress::zstd_ddict::ZSTD_createDDict;
3371
3372 let dict = b"refDDict-test-dict ".repeat(8);
3373 let ddict = ZSTD_createDDict(&dict).expect("ddict");
3374
3375 let mut dctx = ZSTD_DCtx::default();
3377 let rc = ZSTD_DCtx_refDDict(&mut dctx, &ddict);
3378 assert_eq!(rc, 0);
3379 assert_eq!(dctx.stream_dict, dict);
3380
3381 let src: Vec<u8> = b"payload wearing the refDDict-test-dict ".repeat(18);
3384 let mut cctx = ZSTD_createCCtx().unwrap();
3385 let mut cbuf = vec![0u8; 4096];
3386 let n = ZSTD_compress_usingDict(&mut cctx, &mut cbuf, &src, &dict, 3);
3387 assert!(!crate::common::error::ERR_isError(n));
3388
3389 ZSTD_initDStream(&mut dctx);
3390 let mut out = vec![0u8; src.len() + 64];
3391 let mut in_pos = 0usize;
3392 let mut out_pos = 0usize;
3393 let drain =
3394 ZSTD_decompressStream(&mut dctx, &mut out, &mut out_pos, &cbuf[..n], &mut in_pos);
3395 assert!(!crate::common::error::ERR_isError(drain));
3396 assert_eq!(&out[..out_pos], &src[..]);
3397 }
3398
3399 #[test]
3400 fn DCtx_refPrefix_roundtrips_with_compressor_using_dict() {
3401 use crate::compress::zstd_compress::{ZSTD_compress_usingDict, ZSTD_createCCtx};
3406 let dict = b"shared-dict-content-for-prefix-test ".repeat(8);
3407 let src = b"payload that uses shared-dict-content-for-prefix-test ".repeat(16);
3408
3409 let mut cctx = ZSTD_createCCtx().unwrap();
3410 let mut dst = vec![0u8; 4096];
3411 let n = ZSTD_compress_usingDict(&mut cctx, &mut dst, &src, &dict, 3);
3412 assert!(!crate::common::error::ERR_isError(n));
3413
3414 let mut dctx = ZSTD_DCtx::default();
3415 let rc = ZSTD_DCtx_refPrefix(&mut dctx, &dict);
3416 assert_eq!(rc, 0);
3417 ZSTD_initDStream(&mut dctx);
3418 let mut out_buf = vec![0u8; src.len() + 64];
3419 let mut in_pos = 0usize;
3420 let mut out_pos = 0usize;
3421 let drain = ZSTD_decompressStream(
3422 &mut dctx,
3423 &mut out_buf,
3424 &mut out_pos,
3425 &dst[..n],
3426 &mut in_pos,
3427 );
3428 assert!(
3429 !crate::common::error::ERR_isError(drain),
3430 "drain err: {drain:#x}"
3431 );
3432 assert_eq!(&out_buf[..out_pos], &src[..]);
3433 }
3434
3435 #[test]
3436 fn DCtx_loadDictionary_variants_store_equivalent_state() {
3437 use crate::decompress::zstd_ddict::{ZSTD_dictContentType_e, ZSTD_dictLoadMethod_e};
3442 let dict = b"variant-equivalence-test-dict".to_vec();
3443
3444 let mut a = ZSTD_DCtx::default();
3445 ZSTD_DCtx_loadDictionary(&mut a, &dict);
3446
3447 let mut b = ZSTD_DCtx::default();
3448 ZSTD_DCtx_loadDictionary_byReference(&mut b, &dict);
3449
3450 let mut c = ZSTD_DCtx::default();
3451 ZSTD_DCtx_loadDictionary_advanced(
3452 &mut c,
3453 &dict,
3454 ZSTD_dictLoadMethod_e::ZSTD_dlm_byCopy,
3455 ZSTD_dictContentType_e::ZSTD_dct_auto,
3456 );
3457
3458 assert_eq!(a.stream_dict, dict);
3459 assert_eq!(b.stream_dict, dict);
3460 assert_eq!(c.stream_dict, dict);
3461 }
3462
3463 #[test]
3464 fn decompressStream_handles_skippable_then_regular_frame() {
3465 let src = b"streaming-skip-then-real ".repeat(20);
3471 let mut frame = vec![0u8; 4096];
3472 let n = crate::compress::zstd_compress::ZSTD_compress(&mut frame, &src, 3);
3473 assert!(!crate::common::error::ERR_isError(n));
3474
3475 let mut stream = Vec::new();
3476 stream.extend_from_slice(&ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes());
3477 stream.extend_from_slice(&8u32.to_le_bytes());
3478 stream.extend_from_slice(b"SKIPDATA");
3479 stream.extend_from_slice(&frame[..n]);
3480
3481 let mut dctx = ZSTD_DCtx::new();
3482 ZSTD_initDStream(&mut dctx);
3483 let mut out = vec![0u8; src.len() + 64];
3484 let mut in_pos = 0usize;
3485 let mut out_pos = 0usize;
3486 let _hint = ZSTD_decompressStream(&mut dctx, &mut out, &mut out_pos, &stream, &mut in_pos);
3487 for _ in 0..8 {
3490 if out_pos >= src.len() {
3491 break;
3492 }
3493 let _ = ZSTD_decompressStream(&mut dctx, &mut out, &mut out_pos, &[], &mut 0usize);
3494 }
3495 assert_eq!(&out[..out_pos], &src[..]);
3496 }
3497
3498 #[test]
3499 fn decompressDCtx_truncated_frame_errors_out_cleanly() {
3500 use crate::decompress::zstd_decompress_block::{
3504 ZSTD_buildDefaultSeqTables, ZSTD_decoder_entropy_rep,
3505 };
3506 let src = b"full-frame-that-we-then-truncate ".repeat(20);
3507 let mut frame = vec![0u8; 4096];
3508 let n = crate::compress::zstd_compress::ZSTD_compress(&mut frame, &src, 3);
3509 assert!(!crate::common::error::ERR_isError(n));
3510
3511 let mut dctx = ZSTD_DCtx::new();
3512 ZSTD_buildDefaultSeqTables(&mut dctx);
3513 let mut rep = ZSTD_decoder_entropy_rep::default();
3514 let mut xxh = crate::common::xxhash::XXH64_state_t::default();
3515 let mut out = vec![0u8; src.len() + 64];
3516 let decoded = ZSTD_decompressDCtx(&mut dctx, &mut rep, &mut xxh, &mut out, &frame[..n / 2]);
3517 assert!(
3518 crate::common::error::ERR_isError(decoded),
3519 "truncated frame should error, got decoded={}",
3520 decoded,
3521 );
3522 }
3523
3524 #[test]
3525 fn decompressDCtx_advances_past_skippable_frames_mid_stream() {
3526 use crate::decompress::zstd_decompress_block::{
3532 ZSTD_buildDefaultSeqTables, ZSTD_decoder_entropy_rep,
3533 };
3534 let first = b"alpha-first-frame".as_ref();
3535 let second = b"omega-second-frame".as_ref();
3536 let mut stream = Vec::new();
3537 {
3538 let mut buf = vec![0u8; 256];
3539 let n = crate::compress::zstd_compress::ZSTD_compress(&mut buf, first, 3);
3540 stream.extend_from_slice(&buf[..n]);
3541 }
3542 stream.extend_from_slice(&ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes());
3543 stream.extend_from_slice(&8u32.to_le_bytes());
3544 stream.extend_from_slice(b"SKIPDATA");
3545 {
3546 let mut buf = vec![0u8; 256];
3547 let n = crate::compress::zstd_compress::ZSTD_compress(&mut buf, second, 3);
3548 stream.extend_from_slice(&buf[..n]);
3549 }
3550
3551 let mut dctx = ZSTD_DCtx::new();
3552 ZSTD_buildDefaultSeqTables(&mut dctx);
3553 let mut rep = ZSTD_decoder_entropy_rep::default();
3554 let mut xxh = crate::common::xxhash::XXH64_state_t::default();
3555 let mut out = vec![0u8; first.len() + second.len() + 64];
3556 let decoded = ZSTD_decompressDCtx(&mut dctx, &mut rep, &mut xxh, &mut out, &stream);
3557 assert!(!crate::common::error::ERR_isError(decoded));
3558 assert_eq!(decoded, first.len() + second.len());
3559 assert_eq!(&out[..first.len()], first);
3560 assert_eq!(&out[first.len()..decoded], second);
3561 }
3562
3563 #[test]
3564 fn decompressDCtx_applies_loaded_stream_dict() {
3565 let dict = b"shared-dict-for-decompressDCtx-apply ".repeat(8);
3572 let src: Vec<u8> = b"payload referring to shared-dict-for-decompressDCtx-apply ".repeat(15);
3573 let mut cctx = crate::compress::zstd_compress::ZSTD_createCCtx().unwrap();
3574 let mut frame = vec![0u8; 4096];
3575 let n = crate::compress::zstd_compress::ZSTD_compress_usingDict(
3576 &mut cctx, &mut frame, &src, &dict, 3,
3577 );
3578 assert!(!crate::common::error::ERR_isError(n));
3579
3580 let mut dctx = ZSTD_DCtx::new();
3581 ZSTD_DCtx_loadDictionary(&mut dctx, &dict);
3582 use crate::decompress::zstd_decompress_block::{
3583 ZSTD_buildDefaultSeqTables, ZSTD_decoder_entropy_rep,
3584 };
3585 ZSTD_buildDefaultSeqTables(&mut dctx);
3586 let mut rep = ZSTD_decoder_entropy_rep::default();
3587 let mut xxh = crate::common::xxhash::XXH64_state_t::default();
3588 let mut out = vec![0u8; src.len() + 64];
3589 let decoded = ZSTD_decompressDCtx(&mut dctx, &mut rep, &mut xxh, &mut out, &frame[..n]);
3590 assert!(!crate::common::error::ERR_isError(decoded));
3591 assert_eq!(&out[..decoded], &src[..]);
3592 }
3593
3594 #[test]
3595 fn getFrameHeader_on_skippable_frame_returns_variant_and_size() {
3596 let mut buf = Vec::new();
3604 buf.extend_from_slice(&(ZSTD_MAGIC_SKIPPABLE_START + 7).to_le_bytes());
3605 buf.extend_from_slice(&12u32.to_le_bytes());
3606 buf.extend_from_slice(&[0xAB; 12]);
3607
3608 let mut zfh = ZSTD_FrameHeader::default();
3609 let rc = ZSTD_getFrameHeader(&mut zfh, &buf);
3610 assert_eq!(rc, 0);
3611 assert_eq!(zfh.frameType, ZSTD_FrameType_e::ZSTD_skippableFrame);
3612 assert_eq!(zfh.dictID, 7);
3613 assert_eq!(zfh.headerSize, ZSTD_SKIPPABLEHEADERSIZE as u32);
3614 assert_eq!(zfh.frameContentSize, 12);
3615 }
3616
3617 #[test]
3618 fn DCtx_loadDictionary_empty_slice_clears_previous_dict() {
3619 let mut dctx = ZSTD_DCtx::default();
3624 ZSTD_DCtx_loadDictionary(&mut dctx, b"sticky-dict");
3625 assert_eq!(dctx.stream_dict, b"sticky-dict");
3626 ZSTD_DCtx_loadDictionary(&mut dctx, &[]);
3627 assert!(dctx.stream_dict.is_empty());
3628 }
3629
3630 #[test]
3631 fn decompress_usingDict_with_empty_dict_matches_no_dict_path() {
3632 let src = b"empty-dict == no-dict ".repeat(20);
3637 let mut cbuf = vec![0u8; 4096];
3638 let n = crate::compress::zstd_compress::ZSTD_compress(&mut cbuf, &src, 3);
3639 assert!(!crate::common::error::ERR_isError(n));
3640
3641 let mut dctx = ZSTD_DCtx::new();
3643 let mut out = vec![0u8; src.len() + 64];
3644 let rc = ZSTD_decompress_usingDict(&mut dctx, &mut out, &cbuf[..n], &[]);
3645 assert!(!crate::common::error::ERR_isError(rc));
3646 assert_eq!(&out[..rc], &src[..]);
3647 }
3648
3649 #[test]
3650 fn decompress_usingDict_rejects_dictID_mismatch() {
3651 use crate::common::error::{ERR_getErrorCode, ERR_isError};
3656 use crate::common::mem::MEM_writeLE32;
3657
3658 let mut dict_a =
3662 include_bytes!("../../tests/fixtures/upstream-zstd/dict-files/zero-weight-dict")
3663 .to_vec();
3664 MEM_writeLE32(&mut dict_a[4..8], 0x11111111);
3665 let mut dict_b = dict_a.clone();
3666 MEM_writeLE32(&mut dict_b[4..8], 0x22222222);
3667
3668 let src = b"dict-A-vs-dict-B dictID mismatch ".repeat(20);
3670 let mut cctx = crate::compress::zstd_compress::ZSTD_createCCtx().unwrap();
3671 let mut frame = vec![0u8; 4096];
3672 let n = crate::compress::zstd_compress::ZSTD_compress_usingDict(
3673 &mut cctx, &mut frame, &src, &dict_a, 3,
3674 );
3675 assert!(!ERR_isError(n));
3676
3677 let mut dctx = ZSTD_DCtx::new();
3679 let mut out = vec![0u8; src.len() + 64];
3680 let rc = ZSTD_decompress_usingDict(&mut dctx, &mut out, &frame[..n], &dict_b);
3681 assert!(ERR_isError(rc));
3682 assert_eq!(ERR_getErrorCode(rc), ErrorCode::DictionaryWrong);
3683 }
3684
3685 #[test]
3686 fn decompress_usingDDict_rejects_dictID_mismatch() {
3687 use crate::common::error::{ERR_getErrorCode, ERR_isError};
3688 use crate::common::mem::MEM_writeLE32;
3689 use crate::decompress::zstd_ddict::ZSTD_createDDict;
3690
3691 let mut dict_a =
3692 include_bytes!("../../tests/fixtures/upstream-zstd/dict-files/zero-weight-dict")
3693 .to_vec();
3694 MEM_writeLE32(&mut dict_a[4..8], 0x11111111);
3695 let mut dict_b = dict_a.clone();
3696 MEM_writeLE32(&mut dict_b[4..8], 0x22222222);
3697
3698 let src = b"dict-A-vs-ddict-B dictID mismatch ".repeat(20);
3699 let mut cctx = crate::compress::zstd_compress::ZSTD_createCCtx().unwrap();
3700 let mut frame = vec![0u8; 4096];
3701 let n = crate::compress::zstd_compress::ZSTD_compress_usingDict(
3702 &mut cctx, &mut frame, &src, &dict_a, 3,
3703 );
3704 assert!(!ERR_isError(n));
3705
3706 let ddict_b = ZSTD_createDDict(&dict_b).expect("ddict");
3707 let mut dctx = ZSTD_DCtx::new();
3708 let mut out = vec![0u8; src.len() + 64];
3709 let rc = ZSTD_decompress_usingDDict(&mut dctx, &mut out, &frame[..n], &ddict_b);
3710 assert!(ERR_isError(rc));
3711 assert_eq!(ERR_getErrorCode(rc), ErrorCode::DictionaryWrong);
3712 }
3713
3714 #[test]
3715 fn decompress_usingDict_uses_caller_owned_dctx() {
3716 use crate::common::error::ERR_isError;
3724 use crate::decompress::zstd_decompress_block::ZSTD_DCtx;
3725
3726 let src_bytes = b"use-caller-dctx-for-decompress-usingDict-parity ".repeat(4);
3727 let mut cctx = crate::compress::zstd_compress::ZSTD_createCCtx().unwrap();
3728 let mut frame = vec![0u8; 4096];
3729 let n = crate::compress::zstd_compress::ZSTD_compress_usingDict(
3732 &mut cctx,
3733 &mut frame,
3734 &src_bytes,
3735 &[],
3736 3,
3737 );
3738 assert!(!ERR_isError(n));
3739
3740 let mut dctx = ZSTD_DCtx::new();
3743 dctx.dictID = 0xDEAD_BEEF;
3744 let mut out = vec![0u8; src_bytes.len() + 64];
3745 let rc = ZSTD_decompress_usingDict(&mut dctx, &mut out, &frame[..n], &[]);
3746 assert!(!ERR_isError(rc));
3747 assert_eq!(&out[..rc], src_bytes.as_slice());
3748 assert_eq!(dctx.dictID, 0);
3750 assert_eq!(dctx.isFrameDecompression, 1);
3752 assert!(dctx.blockSizeMax > 0);
3753 }
3754
3755 #[test]
3756 fn DCtx_refPrefix_advanced_matches_plain_across_every_contentType() {
3757 use crate::decompress::zstd_ddict::ZSTD_dictContentType_e;
3763 let prefix = b"advanced-refPrefix-roundtrip".to_vec();
3764
3765 let mut plain = ZSTD_DCtx::default();
3766 ZSTD_DCtx_refPrefix(&mut plain, &prefix);
3767
3768 for ct in [
3769 ZSTD_dictContentType_e::ZSTD_dct_auto,
3770 ZSTD_dictContentType_e::ZSTD_dct_rawContent,
3771 ZSTD_dictContentType_e::ZSTD_dct_fullDict,
3772 ] {
3773 let mut adv = ZSTD_DCtx::default();
3774 let rc = ZSTD_DCtx_refPrefix_advanced(&mut adv, &prefix, ct);
3775 assert_eq!(rc, 0);
3776 assert_eq!(adv.stream_dict, plain.stream_dict);
3777 }
3778 }
3779
3780 #[test]
3781 fn initStatic_decompression_variants_construct_ctx_and_ddict() {
3782 let mut buf = vec![0u64; (1 << 20) / core::mem::size_of::<u64>()];
3783 let bytes = unsafe {
3784 core::slice::from_raw_parts_mut(
3785 buf.as_mut_ptr() as *mut u8,
3786 buf.len() * core::mem::size_of::<u64>(),
3787 )
3788 };
3789 let dctx = ZSTD_initStaticDCtx(bytes).expect("static dctx");
3790 assert_eq!(
3791 ZSTD_nextSrcSizeToDecompress(dctx),
3792 ZSTD_startingInputLength(ZSTD_format_e::ZSTD_f_zstd1)
3793 );
3794 let dstream = ZSTD_initStaticDStream(bytes).expect("static dstream");
3795 assert_eq!(
3796 ZSTD_nextSrcSizeToDecompress(dstream),
3797 ZSTD_startingInputLength(ZSTD_format_e::ZSTD_f_zstd1)
3798 );
3799 let dict_bytes = b"dict";
3800 let ddict = ZSTD_initStaticDDict(bytes, dict_bytes).expect("static ddict");
3801 assert_eq!(
3802 crate::decompress::zstd_ddict::ZSTD_DDict_dictContent(ddict),
3803 dict_bytes
3804 );
3805 }
3806
3807 #[test]
3808 fn DCtx_setMaxWindowSize_stores_log2() {
3809 let mut dctx = ZSTD_DCtx::default();
3810 let rc = ZSTD_DCtx_setMaxWindowSize(&mut dctx, 1 << 18);
3811 assert_eq!(rc, 0);
3812 assert_eq!(dctx.d_windowLogMax, 18u32);
3813 }
3814
3815 #[test]
3816 fn DCtx_setMaxWindowSize_rejects_out_of_bounds() {
3817 let mut dctx = ZSTD_DCtx::default();
3818 assert!(crate::common::error::ERR_isError(
3820 ZSTD_DCtx_setMaxWindowSize(&mut dctx, 100)
3821 ));
3822 if crate::common::mem::MEM_32bits() == 0 {
3826 assert!(crate::common::error::ERR_isError(
3827 ZSTD_DCtx_setMaxWindowSize(&mut dctx, 1usize << 32)
3828 ));
3829 }
3830 }
3831
3832 #[test]
3833 fn isFrame_and_isSkippable_are_exclusive() {
3834 let mut real = 0xFD2FB528u32.to_le_bytes().to_vec();
3836 real.resize(32, 0);
3837 assert_eq!(ZSTD_isFrame(&real), 1);
3838 assert_eq!(ZSTD_isSkippableFrame(&real), 0);
3839
3840 let mut skip = ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes().to_vec();
3842 skip.extend_from_slice(&0u32.to_le_bytes());
3843 assert_eq!(ZSTD_isFrame(&skip), 1); assert_eq!(ZSTD_isSkippableFrame(&skip), 1);
3845
3846 let rand = [0u8, 1, 2, 3, 4, 5, 6, 7];
3848 assert_eq!(ZSTD_isFrame(&rand), 0);
3849 assert_eq!(ZSTD_isSkippableFrame(&rand), 0);
3850 }
3851
3852 #[test]
3853 fn skippableFrame_all_16_variants_roundtrip() {
3854 use crate::compress::zstd_compress::ZSTD_writeSkippableFrame;
3855 for variant in 0..16u32 {
3856 let payload = [variant as u8; 7];
3857 let mut buf = vec![0u8; 32];
3858 let w = ZSTD_writeSkippableFrame(&mut buf, &payload, variant);
3859 assert!(!crate::common::error::ERR_isError(w));
3860 let mut out = [0u8; 7];
3861 let mut got_variant = 0u32;
3862 let r = ZSTD_readSkippableFrame(&mut out, Some(&mut got_variant), &buf);
3863 assert_eq!(r, 7);
3864 assert_eq!(got_variant, variant);
3865 assert_eq!(&out, &payload);
3866 }
3867 }
3868
3869 #[test]
3870 fn readSkippableFrame_returns_payload_and_variant() {
3871 let mut src = Vec::new();
3873 src.extend_from_slice(&(ZSTD_MAGIC_SKIPPABLE_START + 3).to_le_bytes()); src.extend_from_slice(&5u32.to_le_bytes());
3875 src.extend_from_slice(b"hello");
3876
3877 let mut dst = [0u8; 16];
3878 let mut variant: u32 = 0;
3879 let n = ZSTD_readSkippableFrame(&mut dst, Some(&mut variant), &src);
3880 assert_eq!(n, 5);
3881 assert_eq!(&dst[..5], b"hello");
3882 assert_eq!(variant, 3);
3883 }
3884
3885 #[test]
3886 fn writeSkippableFrame_rejects_error_paths() {
3887 use crate::compress::zstd_compress::ZSTD_writeSkippableFrame;
3891 let payload = b"abcd".as_slice();
3892 let mut tiny = [0u8; 4];
3894 assert!(crate::common::error::ERR_isError(ZSTD_writeSkippableFrame(
3895 &mut tiny, payload, 0
3896 )));
3897 let mut no_room = [0u8; 11];
3899 assert!(crate::common::error::ERR_isError(ZSTD_writeSkippableFrame(
3900 &mut no_room,
3901 payload,
3902 0
3903 )));
3904 let mut ok_buf = [0u8; 64];
3906 assert!(crate::common::error::ERR_isError(ZSTD_writeSkippableFrame(
3907 &mut ok_buf,
3908 payload,
3909 16
3910 )));
3911 let mut exact = [0u8; 8 + 4];
3913 let n = ZSTD_writeSkippableFrame(&mut exact, payload, 0);
3914 assert_eq!(n, 12);
3915 }
3916
3917 #[test]
3918 fn readSkippableFrame_rejects_non_skippable() {
3919 let src = 0xFD2FB528u32.to_le_bytes();
3921 let mut dst = [0u8; 16];
3922 let rc = ZSTD_readSkippableFrame(&mut dst, None, &src);
3923 assert!(crate::common::error::ERR_isError(rc));
3924 }
3925
3926 #[test]
3927 fn readSkippableFrame_rejects_short_src_and_truncated_frame() {
3928 let mut dst = [0u8; 32];
3933
3934 let too_short = [0u8; 4];
3936 assert!(crate::common::error::ERR_isError(ZSTD_readSkippableFrame(
3937 &mut dst, None, &too_short
3938 )));
3939
3940 let mut truncated = Vec::new();
3943 truncated.extend_from_slice(&ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes());
3944 truncated.extend_from_slice(&20u32.to_le_bytes());
3945 truncated.extend_from_slice(&[0u8; 5]);
3946 assert!(crate::common::error::ERR_isError(ZSTD_readSkippableFrame(
3947 &mut dst, None, &truncated
3948 )));
3949 }
3950
3951 #[test]
3952 fn readSkippableFrame_rejects_small_dst() {
3953 let mut src = Vec::new();
3954 src.extend_from_slice(&ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes());
3955 src.extend_from_slice(&10u32.to_le_bytes());
3956 src.extend_from_slice(&[0u8; 10]);
3957 let mut dst = [0u8; 4]; let rc = ZSTD_readSkippableFrame(&mut dst, None, &src);
3959 assert!(crate::common::error::ERR_isError(rc));
3960 }
3961
3962 #[test]
3963 fn find_frame_compressed_size_skippable() {
3964 let mut src = Vec::new();
3965 src.extend_from_slice(&ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes());
3966 src.extend_from_slice(&7u32.to_le_bytes());
3967 src.extend_from_slice(&[0u8; 7]);
3968 let sz = ZSTD_findFrameCompressedSize(&src);
3969 assert_eq!(sz, ZSTD_SKIPPABLEHEADERSIZE + 7);
3970 }
3971
3972 #[test]
3973 fn find_decompressed_size_sums_frames() {
3974 let mut src = make_raw_hello_frame();
3976 src.extend_from_slice(&ZSTD_MAGIC_SKIPPABLE_START.to_le_bytes());
3977 src.extend_from_slice(&3u32.to_le_bytes());
3978 src.extend_from_slice(&[0u8; 3]);
3979 src.extend_from_slice(&make_raw_hello_frame());
3980 let total = ZSTD_findDecompressedSize(&src);
3981 assert_eq!(total, 10);
3982 }
3983
3984 #[test]
3985 fn decompress_frame_raw_block_roundtrip() {
3986 let mut src = Vec::new();
3993 src.extend_from_slice(&ZSTD_MAGICNUMBER.to_le_bytes());
3994 src.push(0x20);
3995 src.push(5);
3996 let bh = (5u32 << 3) | 1; src.push((bh & 0xFF) as u8);
3998 src.push(((bh >> 8) & 0xFF) as u8);
3999 src.push(((bh >> 16) & 0xFF) as u8);
4000 src.extend_from_slice(b"HELLO");
4001
4002 let mut dst = vec![0u8; 32];
4003 let out = ZSTD_decompress(&mut dst, &src);
4004 assert!(
4005 !crate::common::error::ERR_isError(out),
4006 "err: {}",
4007 crate::common::error::ERR_getErrorName(out)
4008 );
4009 assert_eq!(out, 5);
4010 assert_eq!(&dst[..5], b"HELLO");
4011 }
4012
4013 #[test]
4014 fn decompress_frame_rle_block_roundtrip() {
4015 let mut src = Vec::new();
4019 src.extend_from_slice(&ZSTD_MAGICNUMBER.to_le_bytes());
4020 src.push(0x20); src.push(10); let bh = (10u32 << 3) | (1 << 1) | 1;
4023 src.push((bh & 0xFF) as u8);
4024 src.push(((bh >> 8) & 0xFF) as u8);
4025 src.push(((bh >> 16) & 0xFF) as u8);
4026 src.push(b'Z');
4027
4028 let mut dst = vec![0u8; 32];
4029 let out = ZSTD_decompress(&mut dst, &src);
4030 assert!(!crate::common::error::ERR_isError(out));
4031 assert_eq!(out, 10);
4032 for b in dst.iter().take(10) {
4033 assert_eq!(*b, b'Z');
4034 }
4035 }
4036
4037 #[test]
4038 fn frame_header_reserved_bit_errors() {
4039 let mut src = Vec::new();
4040 src.extend_from_slice(&ZSTD_MAGICNUMBER.to_le_bytes());
4041 src.push(0x08); src.push(0);
4043 let mut zfh = ZSTD_FrameHeader::default();
4044 let rc = ZSTD_getFrameHeader(&mut zfh, &src);
4045 assert!(crate::common::error::ERR_isError(rc));
4046 }
4047}
4048
4049pub use crate::decompress::zstd_decompress_block::ZSTD_DCtx;
4053
4054pub fn ZSTD_createDCtx() -> Box<ZSTD_DCtx> {
4057 let mut d = ZSTD_createDCtx_internal(crate::compress::zstd_compress::ZSTD_customMem::default())
4058 .expect("default customMem allocation must succeed");
4059 crate::decompress::zstd_decompress_block::ZSTD_buildDefaultSeqTables(&mut d);
4060 d
4061}
4062
4063pub fn ZSTD_freeDCtx(dctx: Box<ZSTD_DCtx>) -> usize {
4065 let customMem = dctx.customMem;
4066 unsafe {
4067 crate::compress::zstd_compress::ZSTD_customFreeBox(dctx, customMem);
4068 }
4069 0
4070}
4071
4072pub fn ZSTD_copyRawBlock(dst: &mut [u8], src: &[u8]) -> usize {
4074 if src.len() > dst.len() {
4075 return ERROR(ErrorCode::DstSizeTooSmall);
4076 }
4077 dst[..src.len()].copy_from_slice(src);
4078 src.len()
4079}
4080
4081pub fn ZSTD_setRleBlock(dst: &mut [u8], b: u8, regenSize: usize) -> usize {
4083 if regenSize > dst.len() {
4084 return ERROR(ErrorCode::DstSizeTooSmall);
4085 }
4086 for d in dst[..regenSize].iter_mut() {
4087 *d = b;
4088 }
4089 regenSize
4090}
4091
4092#[allow(clippy::too_many_arguments)]
4107pub fn ZSTD_decompressFrame_withOpStart(
4108 dctx: &mut crate::decompress::zstd_decompress_block::ZSTD_DCtx,
4109 entropy_rep: &mut crate::decompress::zstd_decompress_block::ZSTD_decoder_entropy_rep,
4110 xxh: &mut crate::common::xxhash::XXH64_state_t,
4111 dst: &mut [u8],
4112 op_start: usize,
4113 src: &[u8],
4114 src_consumed: &mut usize,
4115) -> usize {
4116 use crate::common::xxhash::{XXH64_digest, XXH64_reset, XXH64_update};
4117 use crate::decompress::zstd_decompress_block::{
4118 blockProperties_t, blockType_e, streaming_operation, ZSTD_blockHeaderSize,
4119 ZSTD_decompressBlock_internal, ZSTD_getcBlockSize,
4120 };
4121 let frameheadersize_min = ZSTD_FRAMEHEADERSIZE_MIN(dctx.format);
4126 let mut ip: usize = 0;
4127 let mut op: usize = op_start;
4128 let mut remaining = src.len();
4129 if remaining < frameheadersize_min + ZSTD_blockHeaderSize {
4130 return ERROR(ErrorCode::SrcSizeWrong);
4131 }
4132 let mut zfh = ZSTD_FrameHeader::default();
4133 let rc = ZSTD_getFrameHeader_advanced(&mut zfh, src, dctx.format);
4135 if crate::common::error::ERR_isError(rc) {
4136 return rc;
4137 }
4138 if rc != 0 {
4139 return ERROR(ErrorCode::SrcSizeWrong);
4140 }
4141 if zfh.frameType != ZSTD_FrameType_e::ZSTD_frame {
4142 return ERROR(ErrorCode::PrefixUnknown);
4143 }
4144 dctx.isFrameDecompression = 1;
4145 dctx.blockSizeMax = zfh.blockSizeMax as usize;
4146 let validateChecksum = zfh.checksumFlag != 0;
4147 if validateChecksum {
4148 XXH64_reset(xxh, 0);
4149 }
4150 ip += zfh.headerSize as usize;
4151 remaining -= zfh.headerSize as usize;
4152 loop {
4153 let mut bp = blockProperties_t {
4154 blockType: blockType_e::bt_raw,
4155 lastBlock: 0,
4156 origSize: 0,
4157 };
4158 let cBlockSize = ZSTD_getcBlockSize(&src[ip..], &mut bp);
4159 if crate::common::error::ERR_isError(cBlockSize) {
4160 return cBlockSize;
4161 }
4162 ip += ZSTD_blockHeaderSize;
4163 remaining -= ZSTD_blockHeaderSize;
4164 if cBlockSize > remaining {
4165 return ERROR(ErrorCode::SrcSizeWrong);
4166 }
4167 let decodedSize = match bp.blockType {
4168 blockType_e::bt_compressed => ZSTD_decompressBlock_internal(
4169 dctx,
4170 entropy_rep,
4171 dst,
4172 op,
4173 &src[ip..ip + cBlockSize],
4174 streaming_operation::not_streaming,
4175 ),
4176 blockType_e::bt_raw => ZSTD_copyRawBlock(&mut dst[op..], &src[ip..ip + cBlockSize]),
4177 blockType_e::bt_rle => ZSTD_setRleBlock(&mut dst[op..], src[ip], bp.origSize as usize),
4178 blockType_e::bt_reserved => return ERROR(ErrorCode::CorruptionDetected),
4179 };
4180 if crate::common::error::ERR_isError(decodedSize) {
4181 return decodedSize;
4182 }
4183 if validateChecksum && decodedSize > 0 {
4184 XXH64_update(xxh, &dst[op..op + decodedSize]);
4185 }
4186 op += decodedSize;
4187 ip += cBlockSize;
4188 remaining -= cBlockSize;
4189 if bp.lastBlock != 0 {
4190 break;
4191 }
4192 }
4193 let decoded = op - op_start;
4194 if zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN && (decoded as u64) != zfh.frameContentSize
4195 {
4196 return ERROR(ErrorCode::CorruptionDetected);
4197 }
4198 if validateChecksum {
4199 if remaining < 4 {
4200 return ERROR(ErrorCode::ChecksumWrong);
4201 }
4202 let calc = XXH64_digest(xxh) as u32;
4203 let read = MEM_readLE32(&src[ip..ip + 4]);
4204 if calc != read {
4205 return ERROR(ErrorCode::ChecksumWrong);
4206 }
4207 ip += 4;
4208 }
4209 *src_consumed = ip;
4210 decoded
4211}
4212
4213pub fn ZSTD_decompressFrame(
4214 dctx: &mut crate::decompress::zstd_decompress_block::ZSTD_DCtx,
4215 entropy_rep: &mut crate::decompress::zstd_decompress_block::ZSTD_decoder_entropy_rep,
4216 xxh: &mut crate::common::xxhash::XXH64_state_t,
4217 dst: &mut [u8],
4218 src: &[u8],
4219 src_consumed: &mut usize,
4220) -> usize {
4221 use crate::common::xxhash::{XXH64_digest, XXH64_reset, XXH64_update};
4222 use crate::decompress::zstd_decompress_block::{
4223 blockProperties_t, blockType_e, streaming_operation, ZSTD_blockHeaderSize,
4224 ZSTD_decompressBlock_internal, ZSTD_getcBlockSize,
4225 };
4226
4227 let mut ip: usize = 0;
4228 let mut op: usize = 0;
4229 let mut remaining = src.len();
4230
4231 let frameHeaderSizeMin = ZSTD_FRAMEHEADERSIZE_MIN(dctx.format);
4234 if remaining < frameHeaderSizeMin + ZSTD_blockHeaderSize {
4235 return ERROR(ErrorCode::SrcSizeWrong);
4236 }
4237
4238 let mut zfh = ZSTD_FrameHeader::default();
4240 let rc = ZSTD_getFrameHeader_advanced(&mut zfh, src, dctx.format);
4241 if crate::common::error::ERR_isError(rc) {
4242 return rc;
4243 }
4244 if rc != 0 {
4245 return ERROR(ErrorCode::SrcSizeWrong);
4247 }
4248 if zfh.frameType != ZSTD_FrameType_e::ZSTD_frame {
4249 return ERROR(ErrorCode::PrefixUnknown);
4252 }
4253
4254 dctx.isFrameDecompression = 1;
4256 dctx.blockSizeMax = zfh.blockSizeMax as usize;
4257 let validateChecksum = zfh.checksumFlag != 0;
4258 if validateChecksum {
4259 XXH64_reset(xxh, 0);
4260 }
4261
4262 ip += zfh.headerSize as usize;
4263 remaining -= zfh.headerSize as usize;
4264
4265 loop {
4266 let mut bp = blockProperties_t {
4267 blockType: blockType_e::bt_raw,
4268 lastBlock: 0,
4269 origSize: 0,
4270 };
4271 let cBlockSize = ZSTD_getcBlockSize(&src[ip..], &mut bp);
4272 if crate::common::error::ERR_isError(cBlockSize) {
4273 return cBlockSize;
4274 }
4275 ip += ZSTD_blockHeaderSize;
4276 remaining -= ZSTD_blockHeaderSize;
4277 if cBlockSize > remaining {
4278 return ERROR(ErrorCode::SrcSizeWrong);
4279 }
4280
4281 let decodedSize = match bp.blockType {
4282 blockType_e::bt_compressed => ZSTD_decompressBlock_internal(
4283 dctx,
4284 entropy_rep,
4285 dst,
4286 op,
4287 &src[ip..ip + cBlockSize],
4288 streaming_operation::not_streaming,
4289 ),
4290 blockType_e::bt_raw => ZSTD_copyRawBlock(&mut dst[op..], &src[ip..ip + cBlockSize]),
4291 blockType_e::bt_rle => ZSTD_setRleBlock(&mut dst[op..], src[ip], bp.origSize as usize),
4292 blockType_e::bt_reserved => {
4293 return ERROR(ErrorCode::CorruptionDetected);
4294 }
4295 };
4296 if crate::common::error::ERR_isError(decodedSize) {
4297 return decodedSize;
4298 }
4299 if validateChecksum && decodedSize > 0 {
4300 XXH64_update(xxh, &dst[op..op + decodedSize]);
4301 }
4302 op += decodedSize;
4303 ip += cBlockSize;
4304 remaining -= cBlockSize;
4305 if bp.lastBlock != 0 {
4306 break;
4307 }
4308 }
4309
4310 if zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN && (op as u64) != zfh.frameContentSize {
4312 return ERROR(ErrorCode::CorruptionDetected);
4313 }
4314
4315 if validateChecksum {
4317 if remaining < 4 {
4318 return ERROR(ErrorCode::ChecksumWrong);
4319 }
4320 let calc = XXH64_digest(xxh) as u32;
4321 let read = MEM_readLE32(&src[ip..ip + 4]);
4322 if calc != read {
4323 return ERROR(ErrorCode::ChecksumWrong);
4324 }
4325 ip += 4;
4326 }
4327
4328 *src_consumed = ip;
4329 op
4330}
4331
4332pub fn ZSTD_decompressDCtx(
4338 dctx: &mut crate::decompress::zstd_decompress_block::ZSTD_DCtx,
4339 entropy_rep: &mut crate::decompress::zstd_decompress_block::ZSTD_decoder_entropy_rep,
4340 xxh: &mut crate::common::xxhash::XXH64_state_t,
4341 dst: &mut [u8],
4342 src: &[u8],
4343) -> usize {
4344 let ddict = ZSTD_getDDict(dctx);
4345 let mut ip = 0usize;
4346 let mut op = 0usize;
4347 while ip < src.len() {
4348 let rem = &src[ip..];
4349 if dctx.format == ZSTD_format_e::ZSTD_f_zstd1
4355 && rem.len() >= ZSTD_SKIPPABLEHEADERSIZE
4356 && (MEM_readLE32(&rem[..4]) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START
4357 {
4358 let sz = readSkippableFrameSize(rem);
4359 if crate::common::error::ERR_isError(sz) {
4360 return sz;
4361 }
4362 ip += sz;
4363 continue;
4364 }
4365 if let Some(dict) = ddict.as_deref() {
4372 let frame_sz = ZSTD_findFrameCompressedSize_advanced(rem, dctx.format);
4376 if crate::common::error::ERR_isError(frame_sz) {
4377 return frame_sz;
4378 }
4379 let decoded = ZSTD_decompress_usingDict(dctx, &mut dst[op..], &rem[..frame_sz], dict);
4380 if crate::common::error::ERR_isError(decoded) {
4381 return decoded;
4382 }
4383 ip += frame_sz;
4384 op += decoded;
4385 continue;
4386 }
4387 let mut consumed = 0usize;
4388 let decoded =
4389 ZSTD_decompressFrame(dctx, entropy_rep, xxh, &mut dst[op..], rem, &mut consumed);
4390 if crate::common::error::ERR_isError(decoded) {
4391 return decoded;
4392 }
4393 ip += consumed;
4394 op += decoded;
4395 }
4396 op
4397}
4398
4399pub fn ZSTD_decompress(dst: &mut [u8], src: &[u8]) -> usize {
4411 use crate::common::xxhash::XXH64_state_t;
4412 use crate::decompress::zstd_decompress_block::{
4413 ZSTD_DCtx, ZSTD_buildDefaultSeqTables, ZSTD_decoder_entropy_rep,
4414 };
4415 let mut dctx = ZSTD_DCtx::new();
4416 ZSTD_buildDefaultSeqTables(&mut dctx);
4417 let mut rep = ZSTD_decoder_entropy_rep::default();
4418 let mut xxh = XXH64_state_t::default();
4419 ZSTD_decompressDCtx(&mut dctx, &mut rep, &mut xxh, dst, src)
4420}
4421
4422pub fn ZSTD_decompress_usingDict(
4436 dctx: &mut ZSTD_DCtx,
4437 dst: &mut [u8],
4438 src: &[u8],
4439 dict: &[u8],
4440) -> usize {
4441 use crate::common::error::ERR_isError;
4442 use crate::common::xxhash::XXH64_state_t;
4443 use crate::decompress::zstd_decompress_block::ZSTD_decoder_entropy_rep;
4444
4445 let frame_dict_id = ZSTD_getDictID_fromFrame(src);
4451 let dict_dict_id = crate::decompress::zstd_ddict::ZSTD_getDictID_fromDict(dict);
4452 if frame_dict_id != 0 && dict_dict_id != 0 && frame_dict_id != dict_dict_id {
4453 return ERROR(ErrorCode::DictionaryWrong);
4454 }
4455
4456 let declared = ZSTD_getFrameContentSize(src);
4458 let out_size = if declared == ZSTD_CONTENTSIZE_UNKNOWN || declared == ZSTD_CONTENTSIZE_ERROR {
4459 dst.len()
4460 } else {
4461 declared as usize
4462 };
4463 if out_size > dst.len() {
4464 return ERROR(ErrorCode::DstSizeTooSmall);
4465 }
4466
4467 let mut combined = vec![0u8; dict.len() + out_size];
4470 combined[..dict.len()].copy_from_slice(dict);
4471
4472 let rc = ZSTD_decompressBegin(dctx);
4478 if ERR_isError(rc) {
4479 return rc;
4480 }
4481 let mut rep = ZSTD_decoder_entropy_rep::default();
4482 let mut xxh = XXH64_state_t::default();
4483
4484 let mut consumed = 0usize;
4492 let decoded = ZSTD_decompressFrame_withOpStart(
4493 dctx,
4494 &mut rep,
4495 &mut xxh,
4496 &mut combined,
4497 dict.len(),
4498 src,
4499 &mut consumed,
4500 );
4501 if ERR_isError(decoded) {
4502 return decoded;
4503 }
4504 dst[..decoded].copy_from_slice(&combined[dict.len()..dict.len() + decoded]);
4505 decoded
4506}
4507
4508pub fn ZSTD_dParam_getBounds(
4514 param: ZSTD_dParameter,
4515) -> crate::compress::zstd_compress::ZSTD_bounds {
4516 match param {
4517 ZSTD_dParameter::ZSTD_d_windowLogMax => {
4518 let upper = if crate::common::mem::MEM_32bits() != 0 {
4519 ZSTD_WINDOWLOG_MAX_32 as i32
4520 } else {
4521 ZSTD_WINDOWLOG_MAX_64 as i32
4522 };
4523 crate::compress::zstd_compress::ZSTD_bounds {
4524 error: 0,
4525 lowerBound: 10,
4526 upperBound: upper,
4527 }
4528 }
4529 ZSTD_dParameter::ZSTD_d_format => crate::compress::zstd_compress::ZSTD_bounds {
4530 error: 0,
4531 lowerBound: ZSTD_format_e::ZSTD_f_zstd1 as i32,
4532 upperBound: ZSTD_format_e::ZSTD_f_zstd1_magicless as i32,
4533 },
4534 }
4535}
4536
4537#[inline]
4541pub fn ZSTD_DCtx_trace_end(
4542 _dctx: &ZSTD_DCtx,
4543 _uncompressedSize: u64,
4544 _compressedSize: u64,
4545 _streaming: i32,
4546) {
4547}
4548
4549pub fn ZSTD_clearDict(dctx: &mut ZSTD_DCtx) {
4554 dctx.stream_dict.clear();
4555 dctx.dictID = 0;
4556 dctx.ddict_rep = [0; 3];
4557 dctx.dictUses = ZSTD_dictUses_e::ZSTD_dont_use;
4563}
4564
4565pub const DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT: usize = 4;
4566pub const DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT: usize = 3;
4567pub const DDICT_HASHSET_TABLE_BASE_SIZE: usize = 64;
4568pub const DDICT_HASHSET_RESIZE_FACTOR: usize = 2;
4569
4570pub struct ZSTD_DDictHashSet<'a> {
4573 pub ddictPtrTable: Vec<Option<&'a crate::decompress::zstd_ddict::ZSTD_DDict>>,
4574 pub ddictPtrTableSize: usize,
4575 pub ddictPtrCount: usize,
4576}
4577
4578pub fn ZSTD_DDictHashSet_getIndex(hashSet: &ZSTD_DDictHashSet<'_>, dictID: u32) -> usize {
4580 let hash = crate::common::xxhash::XXH64(&dictID.to_le_bytes(), 0);
4581 (hash as usize) & (hashSet.ddictPtrTableSize - 1)
4582}
4583
4584pub fn ZSTD_DDictHashSet_emplaceDDict<'a>(
4587 hashSet: &mut ZSTD_DDictHashSet<'a>,
4588 ddict: &'a crate::decompress::zstd_ddict::ZSTD_DDict,
4589) -> usize {
4590 use crate::decompress::zstd_ddict::ZSTD_getDictID_fromDDict;
4591
4592 let dictID = ZSTD_getDictID_fromDDict(ddict);
4593 let mut idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);
4594 let idxRangeMask = hashSet.ddictPtrTableSize - 1;
4595 if hashSet.ddictPtrCount == hashSet.ddictPtrTableSize {
4596 return ERROR(ErrorCode::Generic);
4597 }
4598 while let Some(existing) = hashSet.ddictPtrTable[idx] {
4599 if ZSTD_getDictID_fromDDict(existing) == dictID {
4600 hashSet.ddictPtrTable[idx] = Some(ddict);
4601 return 0;
4602 }
4603 idx = (idx + 1) & idxRangeMask;
4604 }
4605 hashSet.ddictPtrTable[idx] = Some(ddict);
4606 hashSet.ddictPtrCount += 1;
4607 0
4608}
4609
4610pub fn ZSTD_DDictHashSet_expand<'a>(
4612 hashSet: &mut ZSTD_DDictHashSet<'a>,
4613 _customMem: crate::compress::zstd_compress::ZSTD_customMem,
4614) -> usize {
4615 let oldTable = core::mem::take(&mut hashSet.ddictPtrTable);
4616 hashSet.ddictPtrTableSize *= DDICT_HASHSET_RESIZE_FACTOR;
4617 hashSet.ddictPtrTable = vec![None; hashSet.ddictPtrTableSize];
4618 hashSet.ddictPtrCount = 0;
4619 for ddict in oldTable.into_iter().flatten() {
4620 let rc = ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict);
4621 if crate::common::error::ERR_isError(rc) {
4622 return rc;
4623 }
4624 }
4625 0
4626}
4627
4628pub fn ZSTD_DDictHashSet_getDDict<'a>(
4630 hashSet: &ZSTD_DDictHashSet<'a>,
4631 dictID: u32,
4632) -> Option<&'a crate::decompress::zstd_ddict::ZSTD_DDict> {
4633 use crate::decompress::zstd_ddict::ZSTD_getDictID_fromDDict;
4634
4635 let mut idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);
4636 let idxRangeMask = hashSet.ddictPtrTableSize - 1;
4637 loop {
4638 match hashSet.ddictPtrTable[idx] {
4639 Some(ddict) if ZSTD_getDictID_fromDDict(ddict) == dictID => return Some(ddict),
4640 Some(_) => idx = (idx + 1) & idxRangeMask,
4641 None => return None,
4642 }
4643 }
4644}
4645
4646pub fn ZSTD_createDDictHashSet<'a>(
4648 _customMem: crate::compress::zstd_compress::ZSTD_customMem,
4649) -> ZSTD_DDictHashSet<'a> {
4650 ZSTD_DDictHashSet {
4651 ddictPtrTable: vec![None; DDICT_HASHSET_TABLE_BASE_SIZE],
4652 ddictPtrTableSize: DDICT_HASHSET_TABLE_BASE_SIZE,
4653 ddictPtrCount: 0,
4654 }
4655}
4656
4657pub fn ZSTD_DDictHashSet_addDDict<'a>(
4659 hashSet: &mut ZSTD_DDictHashSet<'a>,
4660 ddict: &'a crate::decompress::zstd_ddict::ZSTD_DDict,
4661 customMem: crate::compress::zstd_compress::ZSTD_customMem,
4662) -> usize {
4663 if hashSet.ddictPtrCount * DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT / hashSet.ddictPtrTableSize
4664 * DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT
4665 != 0
4666 {
4667 let rc = ZSTD_DDictHashSet_expand(hashSet, customMem);
4668 if crate::common::error::ERR_isError(rc) {
4669 return rc;
4670 }
4671 }
4672 ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict)
4673}
4674
4675pub fn ZSTD_DCtx_selectFrameDDict<'a>(
4683 dctx: &mut ZSTD_DCtx,
4684 hashSet: &ZSTD_DDictHashSet<'a>,
4685) -> Option<&'a crate::decompress::zstd_ddict::ZSTD_DDict> {
4686 let frameDDict = ZSTD_DDictHashSet_getDDict(hashSet, dctx.fParams.dictID)?;
4687 ZSTD_clearDict(dctx);
4688 dctx.dictID = dctx.fParams.dictID;
4689 crate::decompress::zstd_ddict::ZSTD_copyDDictParameters(dctx, frameDDict);
4690 dctx.stream_dict = crate::decompress::zstd_ddict::ZSTD_DDict_dictContent(frameDDict).to_vec();
4691 dctx.dictUses = ZSTD_dictUses_e::ZSTD_use_indefinitely;
4692 Some(frameDDict)
4693}
4694
4695pub fn ZSTD_getDDict(dctx: &mut ZSTD_DCtx) -> Option<Vec<u8>> {
4703 match dctx.dictUses {
4704 ZSTD_dictUses_e::ZSTD_dont_use => {
4705 ZSTD_clearDict(dctx);
4706 None
4707 }
4708 ZSTD_dictUses_e::ZSTD_use_indefinitely => {
4709 if dctx.stream_dict.is_empty() {
4710 None
4711 } else {
4712 Some(dctx.stream_dict.clone())
4713 }
4714 }
4715 ZSTD_dictUses_e::ZSTD_use_once => {
4716 let dict = if dctx.stream_dict.is_empty() {
4717 None
4718 } else {
4719 Some(dctx.stream_dict.clone())
4720 };
4721 ZSTD_clearDict(dctx);
4722 dict
4723 }
4724 }
4725}
4726
4727pub fn ZSTD_createDCtx_internal(
4734 customMem: crate::compress::zstd_compress::ZSTD_customMem,
4735) -> Option<Box<ZSTD_DCtx>> {
4736 let mut dctx = unsafe {
4737 crate::compress::zstd_compress::ZSTD_customAllocBox(ZSTD_DCtx::new(), customMem)?
4738 };
4739 dctx.customMem = customMem;
4740 ZSTD_initDCtx_internal(&mut dctx);
4741 Some(dctx)
4742}
4743
4744pub fn ZSTD_initDCtx_internal(dctx: &mut ZSTD_DCtx) {
4754 dctx.isFrameDecompression = 1;
4755 ZSTD_clearDict(dctx);
4756 ZSTD_DCtx_resetParameters(dctx);
4757}
4758
4759pub fn ZSTD_DCtx_resetParameters(dctx: &mut ZSTD_DCtx) {
4767 dctx.d_windowLogMax = ZSTD_WINDOWLOG_LIMIT_DEFAULT;
4768 dctx.format = ZSTD_format_e::ZSTD_f_zstd1;
4772 dctx.dictUses = ZSTD_dictUses_e::ZSTD_dont_use;
4776}
4777
4778pub fn ZSTD_dParam_withinBounds(dParam: ZSTD_dParameter, value: i32) -> i32 {
4783 let bounds = ZSTD_dParam_getBounds(dParam);
4784 if crate::common::error::ERR_isError(bounds.error) {
4785 return 0;
4786 }
4787 if value < bounds.lowerBound || value > bounds.upperBound {
4788 return 0;
4789 }
4790 1
4791}
4792
4793pub fn ZSTD_DCtx_setMaxWindowSize(dctx: &mut ZSTD_DCtx, maxWindowSize: usize) -> usize {
4798 use crate::common::error::{ErrorCode, ERROR};
4799 if !dctx_is_in_init_stage(dctx) {
4802 return ERROR(ErrorCode::StageWrong);
4803 }
4804 let bounds = ZSTD_dParam_getBounds(ZSTD_dParameter::ZSTD_d_windowLogMax);
4805 let min = 1usize << bounds.lowerBound;
4806 let max = 1usize << bounds.upperBound;
4807 if maxWindowSize < min || maxWindowSize > max {
4808 return ERROR(ErrorCode::ParameterOutOfBound);
4809 }
4810 dctx.d_windowLogMax = ((maxWindowSize.leading_zeros() as i32 ^ (usize::BITS as i32 - 1))
4818 as u32)
4819 .max(bounds.lowerBound as u32);
4820 0
4821}
4822
4823pub fn ZSTD_DCtx_setFormat(
4830 dctx: &mut ZSTD_DCtx,
4831 format: crate::decompress::zstd_decompress::ZSTD_format_e,
4832) -> usize {
4833 ZSTD_DCtx_setParameter(dctx, ZSTD_dParameter::ZSTD_d_format, format as i32)
4837}
4838
4839pub type ZSTD_DStream = ZSTD_DCtx;
4842
4843pub fn ZSTD_createDStream() -> Option<Box<ZSTD_DStream>> {
4845 Some(ZSTD_createDCtx())
4846}
4847
4848pub fn ZSTD_freeDStream(zds: Option<Box<ZSTD_DStream>>) -> usize {
4850 if let Some(zds) = zds {
4851 return ZSTD_freeDCtx(zds);
4852 }
4853 0
4854}
4855
4856#[inline]
4861fn dctx_is_in_init_stage(dctx: &ZSTD_DCtx) -> bool {
4862 dctx.stream_in_buffer.is_empty()
4863 && dctx.stream_out_buffer.is_empty()
4864 && dctx.stream_out_drained == 0
4865}
4866
4867pub fn ZSTD_DCtx_loadDictionary(dctx: &mut ZSTD_DCtx, dict: &[u8]) -> usize {
4877 if !dctx_is_in_init_stage(dctx) {
4878 return ERROR(ErrorCode::StageWrong);
4879 }
4880 ZSTD_clearDict(dctx);
4884 if dict.is_empty() {
4885 return 0;
4886 }
4887 let rc = ZSTD_decompress_insertDictionary(dctx, dict);
4888 if crate::common::error::ERR_isError(rc) {
4889 return rc;
4890 }
4891 dctx.dictUses = ZSTD_dictUses_e::ZSTD_use_indefinitely;
4896 0
4897}
4898
4899pub fn ZSTD_DCtx_refPrefix(dctx: &mut ZSTD_DCtx, prefix: &[u8]) -> usize {
4906 if !dctx_is_in_init_stage(dctx) {
4907 return ERROR(ErrorCode::StageWrong);
4908 }
4909 ZSTD_clearDict(dctx);
4914 if !prefix.is_empty() {
4915 dctx.stream_dict = prefix.to_vec();
4916 dctx.dictUses = ZSTD_dictUses_e::ZSTD_use_once;
4921 }
4922 0
4923}
4924
4925pub fn ZSTD_DCtx_refPrefix_advanced(
4929 dctx: &mut ZSTD_DCtx,
4930 prefix: &[u8],
4931 _dictContentType: crate::decompress::zstd_ddict::ZSTD_dictContentType_e,
4932) -> usize {
4933 ZSTD_DCtx_refPrefix(dctx, prefix)
4934}
4935
4936pub fn ZSTD_DCtx_loadDictionary_advanced(
4940 dctx: &mut ZSTD_DCtx,
4941 dict: &[u8],
4942 _dictLoadMethod: crate::decompress::zstd_ddict::ZSTD_dictLoadMethod_e,
4943 _dictContentType: crate::decompress::zstd_ddict::ZSTD_dictContentType_e,
4944) -> usize {
4945 ZSTD_DCtx_loadDictionary(dctx, dict)
4946}
4947
4948#[inline]
4951pub fn ZSTD_DCtx_loadDictionary_byReference(dctx: &mut ZSTD_DCtx, dict: &[u8]) -> usize {
4952 ZSTD_DCtx_loadDictionary(dctx, dict)
4953}
4954
4955pub fn ZSTD_DCtx_refDDict(
4961 dctx: &mut ZSTD_DCtx,
4962 ddict: &crate::decompress::zstd_ddict::ZSTD_DDict,
4963) -> usize {
4964 if !dctx_is_in_init_stage(dctx) {
4966 return ERROR(ErrorCode::StageWrong);
4967 }
4968 ZSTD_clearDict(dctx);
4969 let content = crate::decompress::zstd_ddict::ZSTD_DDict_dictContent(ddict);
4970 if content.is_empty() {
4971 return 0;
4972 }
4973 crate::decompress::zstd_ddict::ZSTD_copyDDictParameters(dctx, ddict);
4974 dctx.dictUses = ZSTD_dictUses_e::ZSTD_use_indefinitely;
4977 0
4978}
4979
4980pub fn ZSTD_DStreamInSize() -> usize {
4983 use crate::decompress::zstd_decompress_block::{ZSTD_blockHeaderSize, ZSTD_BLOCKSIZE_MAX};
4984 ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize
4987}
4988
4989pub fn ZSTD_DStreamOutSize() -> usize {
4992 crate::decompress::zstd_decompress_block::ZSTD_BLOCKSIZE_MAX
4993}
4994
4995#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4999#[repr(i32)]
5000pub enum ZSTD_dParameter {
5001 ZSTD_d_windowLogMax = 100,
5002 ZSTD_d_format = 1000,
5005}
5006
5007pub fn ZSTD_DCtx_setParameter(dctx: &mut ZSTD_DCtx, param: ZSTD_dParameter, value: i32) -> usize {
5017 use crate::common::error::{ErrorCode, ERROR};
5018 if !dctx_is_in_init_stage(dctx) {
5025 return ERROR(ErrorCode::StageWrong);
5026 }
5027 match param {
5028 ZSTD_dParameter::ZSTD_d_windowLogMax => {
5029 let effective = if value == 0 {
5030 ZSTD_WINDOWLOG_LIMIT_DEFAULT as i32
5031 } else {
5032 value
5033 };
5034 let bounds = ZSTD_dParam_getBounds(ZSTD_dParameter::ZSTD_d_windowLogMax);
5035 if effective < bounds.lowerBound || effective > bounds.upperBound {
5036 return ERROR(ErrorCode::ParameterOutOfBound);
5037 }
5038 dctx.d_windowLogMax = effective as u32;
5039 0
5040 }
5041 ZSTD_dParameter::ZSTD_d_format => {
5042 let bounds = ZSTD_dParam_getBounds(ZSTD_dParameter::ZSTD_d_format);
5045 if value < bounds.lowerBound || value > bounds.upperBound {
5046 return ERROR(ErrorCode::ParameterOutOfBound);
5047 }
5048 dctx.format = match value {
5049 v if v == ZSTD_format_e::ZSTD_f_zstd1_magicless as i32 => {
5050 ZSTD_format_e::ZSTD_f_zstd1_magicless
5051 }
5052 _ => ZSTD_format_e::ZSTD_f_zstd1,
5053 };
5054 0
5055 }
5056 }
5057}
5058
5059pub const ZSTD_WINDOWLOG_LIMIT_DEFAULT: u32 = 27;
5063
5064pub fn ZSTD_DCtx_getParameter(dctx: &ZSTD_DCtx, param: ZSTD_dParameter, value: &mut i32) -> usize {
5066 *value = match param {
5067 ZSTD_dParameter::ZSTD_d_windowLogMax => dctx.d_windowLogMax as i32,
5068 ZSTD_dParameter::ZSTD_d_format => dctx.format as i32,
5069 };
5070 0
5071}
5072
5073pub fn ZSTD_DCtx_reset(dctx: &mut ZSTD_DCtx, reset: ZSTD_DResetDirective) -> usize {
5078 let clear_session = matches!(
5079 reset,
5080 ZSTD_DResetDirective::ZSTD_reset_session_only
5081 | ZSTD_DResetDirective::ZSTD_reset_session_and_parameters,
5082 );
5083 let clear_params = matches!(
5084 reset,
5085 ZSTD_DResetDirective::ZSTD_reset_parameters
5086 | ZSTD_DResetDirective::ZSTD_reset_session_and_parameters,
5087 );
5088 if clear_params && !clear_session && !dctx_is_in_init_stage(dctx) {
5092 return ERROR(ErrorCode::StageWrong);
5093 }
5094 if clear_session {
5095 ZSTD_resetDStream(dctx);
5096 }
5097 if clear_params {
5098 ZSTD_clearDict(dctx);
5105 ZSTD_DCtx_resetParameters(dctx);
5106 }
5107 0
5108}
5109
5110#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5112#[repr(i32)]
5113pub enum ZSTD_DResetDirective {
5114 ZSTD_reset_session_only = 1,
5118 ZSTD_reset_parameters = 2,
5119 ZSTD_reset_session_and_parameters = 3,
5120}
5121
5122pub fn ZSTD_sizeof_DCtx(dctx: &ZSTD_DCtx) -> usize {
5124 core::mem::size_of::<ZSTD_DCtx>()
5125 + dctx.hufTable.capacity() * core::mem::size_of::<u32>()
5126 + dctx.workspace.capacity() * core::mem::size_of::<u32>()
5127 + dctx.litExtraBuffer.capacity()
5128 + dctx.LLTable.capacity()
5129 * core::mem::size_of::<crate::decompress::zstd_decompress_block::ZSTD_seqSymbol>()
5130 + dctx.OFTable.capacity()
5131 * core::mem::size_of::<crate::decompress::zstd_decompress_block::ZSTD_seqSymbol>()
5132 + dctx.MLTable.capacity()
5133 * core::mem::size_of::<crate::decompress::zstd_decompress_block::ZSTD_seqSymbol>()
5134 + dctx.stream_in_buffer.capacity()
5135 + dctx.stream_out_buffer.capacity()
5136 + dctx.stream_dict.capacity()
5137}
5138
5139pub fn ZSTD_sizeof_DStream(zds: &ZSTD_DStream) -> usize {
5141 ZSTD_sizeof_DCtx(zds)
5142}
5143
5144pub fn ZSTD_estimateDCtxSize() -> usize {
5151 core::mem::size_of::<ZSTD_DCtx>()
5152}
5153
5154pub fn ZSTD_estimateDStreamSize(windowSize: usize) -> usize {
5160 use crate::decompress::zstd_decompress_block::ZSTD_BLOCKSIZE_MAX;
5161 let blockSize = windowSize.min(ZSTD_BLOCKSIZE_MAX);
5162 let inBuffSize = blockSize;
5163 let outBuffSize = ZSTD_decodingBufferSize_min(windowSize as u64, ZSTD_CONTENTSIZE_UNKNOWN);
5164 ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize
5165}
5166
5167pub fn ZSTD_estimateDStreamSize_fromFrame(src: &[u8]) -> usize {
5170 let mut zfh = ZSTD_FrameHeader::default();
5171 let rc = ZSTD_getFrameHeader(&mut zfh, src);
5172 if crate::common::error::ERR_isError(rc) || rc != 0 {
5173 return ZSTD_estimateDStreamSize(1 << 17); }
5175 ZSTD_estimateDStreamSize(zfh.windowSize as usize)
5176}
5177
5178pub fn ZSTD_insertBlock(dctx: &mut ZSTD_DCtx, block: &[u8]) -> usize {
5182 crate::decompress::zstd_decompress_block::ZSTD_checkContinuity(dctx, block, block.len());
5183 dctx.previousDstEnd = Some(block.as_ptr() as usize + block.len());
5184 block.len()
5185}
5186
5187pub fn ZSTD_decompressBlock(dctx: &mut ZSTD_DCtx, dst: &mut [u8], src: &[u8]) -> usize {
5195 use crate::decompress::zstd_decompress_block::{
5196 streaming_operation, ZSTD_buildDefaultSeqTables, ZSTD_decoder_entropy_rep,
5197 ZSTD_decompressBlock_internal,
5198 };
5199 ZSTD_buildDefaultSeqTables(dctx);
5200 let mut entropy_rep = ZSTD_decoder_entropy_rep::default();
5201 ZSTD_decompressBlock_internal(
5202 dctx,
5203 &mut entropy_rep,
5204 dst,
5205 0,
5206 src,
5207 streaming_operation::not_streaming,
5208 )
5209}
5210
5211pub fn ZSTD_decompressBlock_deprecated(dctx: &mut ZSTD_DCtx, dst: &mut [u8], src: &[u8]) -> usize {
5216 ZSTD_decompressBlock(dctx, dst, src)
5217}
5218
5219pub fn ZSTD_getBlockSize(_dctx: &ZSTD_DCtx) -> usize {
5223 crate::decompress::zstd_decompress_block::ZSTD_BLOCKSIZE_MAX
5224}
5225
5226pub fn ZSTD_isFrame(src: &[u8]) -> u32 {
5230 if src.len() < ZSTD_FRAMEIDSIZE {
5231 return 0;
5232 }
5233 let magic = MEM_readLE32(&src[..4]);
5234 if magic == ZSTD_MAGICNUMBER {
5235 return 1;
5236 }
5237 if (magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START {
5238 return 1;
5239 }
5240 0
5241}
5242
5243pub fn ZSTD_isSkippableFrame(src: &[u8]) -> u32 {
5246 if src.len() < ZSTD_FRAMEIDSIZE {
5247 return 0;
5248 }
5249 let magic = MEM_readLE32(&src[..4]);
5250 if (magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START {
5251 return 1;
5252 }
5253 0
5254}
5255
5256pub fn ZSTD_decodeFrameHeader(dctx: &mut ZSTD_DCtx, src: &[u8], headerSize: usize) -> usize {
5262 use crate::common::xxhash::XXH64_reset;
5263
5264 if src.len() < headerSize {
5265 return ERROR(ErrorCode::SrcSizeWrong);
5266 }
5267 let result = ZSTD_getFrameHeader_advanced(&mut dctx.fParams, &src[..headerSize], dctx.format);
5268 if crate::common::error::ERR_isError(result) {
5269 return result;
5270 }
5271 if result != 0 {
5272 return ERROR(ErrorCode::SrcSizeWrong);
5273 }
5274 if dctx.fParams.dictID != 0 && dctx.dictID != dctx.fParams.dictID {
5275 return ERROR(ErrorCode::DictionaryWrong);
5276 }
5277 dctx.isFrameDecompression = 1;
5278 dctx.blockSizeMax = dctx.fParams.blockSizeMax as usize;
5279 dctx.validateChecksum = dctx.fParams.checksumFlag;
5280 if dctx.validateChecksum != 0 {
5281 XXH64_reset(&mut dctx.xxhState, 0);
5282 }
5283 dctx.processedCSize = dctx.processedCSize.wrapping_add(headerSize as u64);
5284 0
5285}
5286
5287pub fn ZSTD_readSkippableFrame(
5294 dst: &mut [u8],
5295 magicVariant: Option<&mut u32>,
5296 src: &[u8],
5297) -> usize {
5298 use crate::common::error::{ErrorCode, ERROR};
5299 if src.len() < ZSTD_SKIPPABLEHEADERSIZE {
5300 return ERROR(ErrorCode::SrcSizeWrong);
5301 }
5302 let magicNumber = MEM_readLE32(&src[..4]);
5303 let skippableFrameSize = readSkippableFrameSize(src);
5304 if ZSTD_isSkippableFrame(src) == 0 {
5305 return ERROR(ErrorCode::FrameParameterUnsupported);
5306 }
5307 if skippableFrameSize < ZSTD_SKIPPABLEHEADERSIZE || skippableFrameSize > src.len() {
5308 return ERROR(ErrorCode::SrcSizeWrong);
5309 }
5310 let skippableContentSize = skippableFrameSize - ZSTD_SKIPPABLEHEADERSIZE;
5311 if skippableContentSize > dst.len() {
5312 return ERROR(ErrorCode::DstSizeTooSmall);
5313 }
5314 if skippableContentSize > 0 {
5315 dst[..skippableContentSize].copy_from_slice(
5316 &src[ZSTD_SKIPPABLEHEADERSIZE..ZSTD_SKIPPABLEHEADERSIZE + skippableContentSize],
5317 );
5318 }
5319 if let Some(v) = magicVariant {
5320 *v = magicNumber - ZSTD_MAGIC_SKIPPABLE_START;
5321 }
5322 skippableContentSize
5323}
5324
5325pub fn ZSTD_getDictID_fromFrame(src: &[u8]) -> u32 {
5329 let mut zfh = ZSTD_FrameHeader::default();
5330 let rc = ZSTD_getFrameHeader(&mut zfh, src);
5331 if crate::common::error::ERR_isError(rc) || rc != 0 {
5332 return 0;
5333 }
5334 zfh.dictID
5335}
5336
5337pub fn ZSTD_decompress_usingDDict(
5342 dctx: &mut ZSTD_DCtx,
5343 dst: &mut [u8],
5344 src: &[u8],
5345 ddict: &crate::decompress::zstd_ddict::ZSTD_DDict,
5346) -> usize {
5347 use crate::common::error::ERR_isError;
5348 use crate::common::xxhash::XXH64_state_t;
5349 use crate::decompress::zstd_decompress_block::ZSTD_decoder_entropy_rep;
5350
5351 let frame_dict_id = ZSTD_getDictID_fromFrame(src);
5352 if frame_dict_id != 0 && ddict.dictID != 0 && frame_dict_id != ddict.dictID {
5353 return ERROR(ErrorCode::DictionaryWrong);
5354 }
5355
5356 let content = crate::decompress::zstd_ddict::ZSTD_DDict_dictContent(ddict);
5357 let declared = ZSTD_getFrameContentSize(src);
5358 let out_size = if declared == ZSTD_CONTENTSIZE_UNKNOWN || declared == ZSTD_CONTENTSIZE_ERROR {
5359 dst.len()
5360 } else {
5361 declared as usize
5362 };
5363 if out_size > dst.len() {
5364 return ERROR(ErrorCode::DstSizeTooSmall);
5365 }
5366
5367 let rc = ZSTD_decompressBegin(dctx);
5368 if ERR_isError(rc) {
5369 return rc;
5370 }
5371 crate::decompress::zstd_ddict::ZSTD_copyDDictParameters(dctx, ddict);
5372
5373 let mut combined = vec![0u8; content.len() + out_size];
5374 combined[..content.len()].copy_from_slice(content);
5375 let mut rep = ZSTD_decoder_entropy_rep {
5376 rep: dctx.ddict_rep,
5377 };
5378 let mut xxh = XXH64_state_t::default();
5379 let mut consumed = 0usize;
5380 let decoded = ZSTD_decompressFrame_withOpStart(
5381 dctx,
5382 &mut rep,
5383 &mut xxh,
5384 &mut combined,
5385 content.len(),
5386 src,
5387 &mut consumed,
5388 );
5389 if ERR_isError(decoded) {
5390 return decoded;
5391 }
5392 dst[..decoded].copy_from_slice(&combined[content.len()..content.len() + decoded]);
5393 decoded
5394}
5395
5396pub fn ZSTD_decompress_insertDictionary(dctx: &mut ZSTD_DCtx, dict: &[u8]) -> usize {
5409 use crate::common::error::{ERR_isError, ErrorCode, ERROR};
5410 use crate::common::mem::MEM_readLE32;
5411
5412 if dict.len() < 8 {
5414 dctx.dictID = 0;
5415 return ZSTD_refDictContent(dctx, dict);
5416 }
5417 let magic = MEM_readLE32(&dict[..4]);
5418 if magic != ZSTD_MAGICNUMBER_DICTIONARY {
5419 dctx.dictID = 0;
5420 return ZSTD_refDictContent(dctx, dict);
5421 }
5422
5423 dctx.dictID = MEM_readLE32(&dict[4..8]);
5425 let mut rep = [0u32; 3];
5426 let eSize = ZSTD_loadDEntropy(dctx, &mut rep, dict);
5427 if ERR_isError(eSize) {
5428 return ERROR(ErrorCode::DictionaryCorrupted);
5429 }
5430 dctx.ddict_rep = rep;
5431 dctx.litEntropy = 1;
5432 dctx.fseEntropy = 1;
5433 ZSTD_refDictContent(dctx, &dict[eSize..])
5435}
5436
5437pub fn ZSTD_refDictContent(dctx: &mut ZSTD_DCtx, dict: &[u8]) -> usize {
5444 let dict_start = dict.as_ptr() as usize;
5445 let dict_end = dict_start + dict.len();
5446 let previous_dst_end = dctx.previousDstEnd.unwrap_or(0);
5447 let prefix_start = dctx.prefixStart.unwrap_or(previous_dst_end);
5448
5449 dctx.dictEnd = dctx.previousDstEnd;
5450 dctx.virtualStart = Some(dict_start.wrapping_sub(previous_dst_end.wrapping_sub(prefix_start)));
5451 dctx.prefixStart = Some(dict_start);
5452 dctx.previousDstEnd = Some(dict_end);
5453 dctx.stream_dict = dict.to_vec();
5454 0
5455}
5456
5457pub const ZSTD_MAGICNUMBER_DICTIONARY: u32 = 0xEC30A437;
5460
5461pub fn ZSTD_loadDEntropy(dctx: &mut ZSTD_DCtx, repOut: &mut [u32; 3], dict: &[u8]) -> usize {
5473 use crate::common::error::{ERR_isError, ErrorCode, ERROR};
5474 use crate::common::mem::MEM_readLE32;
5475 use crate::decompress::huf_decompress::HUF_readDTableX2;
5476 use crate::decompress::zstd_decompress_block::{
5477 LLFSELog, LL_base, LL_bits, MLFSELog, ML_base, ML_bits, MaxLL, MaxML, MaxOff, OF_base,
5478 OF_bits, OffFSELog, ZSTD_buildFSETable,
5479 };
5480
5481 if dict.len() <= 8 {
5482 return ERROR(ErrorCode::DictionaryCorrupted);
5483 }
5484 let mut pos = 8usize; let mut hufWorkspace = vec![0u32; 1024];
5488 let hSize = HUF_readDTableX2(&mut dctx.hufTable, &dict[pos..], &mut hufWorkspace, 0);
5489 if ERR_isError(hSize) {
5490 return ERROR(ErrorCode::DictionaryCorrupted);
5491 }
5492 pos += hSize;
5493
5494 let mut ofcNCount = [0i16; (MaxOff + 1) as usize];
5496 let mut ofcMaxValue: u32 = MaxOff;
5497 let mut ofcLog: u32 = 0;
5498 let ofcSize = crate::common::entropy_common::FSE_readNCount(
5499 &mut ofcNCount,
5500 &mut ofcMaxValue,
5501 &mut ofcLog,
5502 &dict[pos..],
5503 );
5504 if ERR_isError(ofcSize) || ofcMaxValue > MaxOff || ofcLog > OffFSELog {
5505 return ERROR(ErrorCode::DictionaryCorrupted);
5506 }
5507 ZSTD_buildFSETable(
5508 &mut dctx.OFTable,
5509 &ofcNCount,
5510 ofcMaxValue,
5511 &OF_base,
5512 &OF_bits,
5513 ofcLog,
5514 );
5515 pos += ofcSize;
5516
5517 let mut mlNCount = [0i16; (MaxML + 1) as usize];
5519 let mut mlMaxValue: u32 = MaxML;
5520 let mut mlLog: u32 = 0;
5521 let mlSize = crate::common::entropy_common::FSE_readNCount(
5522 &mut mlNCount,
5523 &mut mlMaxValue,
5524 &mut mlLog,
5525 &dict[pos..],
5526 );
5527 if ERR_isError(mlSize) || mlMaxValue > MaxML || mlLog > MLFSELog {
5528 return ERROR(ErrorCode::DictionaryCorrupted);
5529 }
5530 ZSTD_buildFSETable(
5531 &mut dctx.MLTable,
5532 &mlNCount,
5533 mlMaxValue,
5534 &ML_base,
5535 &ML_bits,
5536 mlLog,
5537 );
5538 pos += mlSize;
5539
5540 let mut llNCount = [0i16; (MaxLL + 1) as usize];
5542 let mut llMaxValue: u32 = MaxLL;
5543 let mut llLog: u32 = 0;
5544 let llSize = crate::common::entropy_common::FSE_readNCount(
5545 &mut llNCount,
5546 &mut llMaxValue,
5547 &mut llLog,
5548 &dict[pos..],
5549 );
5550 if ERR_isError(llSize) || llMaxValue > MaxLL || llLog > LLFSELog {
5551 return ERROR(ErrorCode::DictionaryCorrupted);
5552 }
5553 ZSTD_buildFSETable(
5554 &mut dctx.LLTable,
5555 &llNCount,
5556 llMaxValue,
5557 &LL_base,
5558 &LL_bits,
5559 llLog,
5560 );
5561 pos += llSize;
5562
5563 if pos + 12 > dict.len() {
5565 return ERROR(ErrorCode::DictionaryCorrupted);
5566 }
5567 let dictContentSize = dict.len() - (pos + 12);
5568 for slot in repOut.iter_mut() {
5569 let r = MEM_readLE32(&dict[pos..pos + 4]);
5570 if r == 0 || (r as usize) > dictContentSize {
5571 return ERROR(ErrorCode::DictionaryCorrupted);
5572 }
5573 *slot = r;
5574 pos += 4;
5575 }
5576
5577 pos
5578}
5579
5580pub fn ZSTD_decompressMultiFrame(
5590 dctx: &mut ZSTD_DCtx,
5591 dst: &mut [u8],
5592 src: &[u8],
5593 dict: &[u8],
5594 ddict: Option<&crate::decompress::zstd_ddict::ZSTD_DDict>,
5595) -> usize {
5596 debug_assert!(
5597 dict.is_empty() || ddict.is_none(),
5598 "dict xor ddict, not both"
5599 );
5600 if let Some(dd) = ddict {
5601 let content = crate::decompress::zstd_ddict::ZSTD_DDict_dictContent(dd);
5602 ZSTD_decompress_usingDict(dctx, dst, src, content)
5603 } else {
5604 ZSTD_decompress_usingDict(dctx, dst, src, dict)
5605 }
5606}
5607
5608pub fn ZSTD_getFrameContentSize(src: &[u8]) -> u64 {
5613 let mut zfh = ZSTD_FrameHeader::default();
5614 let rc = ZSTD_getFrameHeader(&mut zfh, src);
5615 if rc != 0 {
5616 return ZSTD_CONTENTSIZE_ERROR;
5617 }
5618 if zfh.frameType == ZSTD_FrameType_e::ZSTD_skippableFrame {
5619 return 0;
5620 }
5621 zfh.frameContentSize
5622}
5623
5624fn readSkippableFrameSize(src: &[u8]) -> usize {
5627 if src.len() < ZSTD_SKIPPABLEHEADERSIZE {
5628 return ERROR(ErrorCode::SrcSizeWrong);
5629 }
5630 let sizeU32 = MEM_readLE32(&src[ZSTD_FRAMEIDSIZE..ZSTD_FRAMEIDSIZE + 4]);
5631 let total = ZSTD_SKIPPABLEHEADERSIZE.wrapping_add(sizeU32 as usize);
5632 if (total as u32) < sizeU32 {
5633 return ERROR(ErrorCode::FrameParameterUnsupported);
5634 }
5635 if total > src.len() {
5636 return ERROR(ErrorCode::SrcSizeWrong);
5637 }
5638 total
5639}
5640
5641#[derive(Debug, Clone, Copy, Default)]
5643pub struct ZSTD_frameSizeInfo {
5644 pub nbBlocks: usize,
5645 pub compressedSize: usize,
5646 pub decompressedBound: u64,
5647}
5648
5649fn frameSizeInfo_error(err_code: usize) -> ZSTD_frameSizeInfo {
5650 ZSTD_frameSizeInfo {
5651 nbBlocks: 0,
5652 compressedSize: err_code,
5653 decompressedBound: ZSTD_CONTENTSIZE_ERROR,
5654 }
5655}
5656
5657pub fn ZSTD_findFrameSizeInfo(src: &[u8], format: ZSTD_format_e) -> ZSTD_frameSizeInfo {
5660 use crate::decompress::zstd_decompress_block::{
5661 blockProperties_t, blockType_e, ZSTD_blockHeaderSize, ZSTD_getcBlockSize,
5662 };
5663 let srcSize = src.len();
5664
5665 if format == ZSTD_format_e::ZSTD_f_zstd1
5666 && srcSize >= ZSTD_SKIPPABLEHEADERSIZE
5667 && (MEM_readLE32(&src[..4]) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START
5668 {
5669 return ZSTD_frameSizeInfo {
5670 nbBlocks: 0,
5671 compressedSize: readSkippableFrameSize(src),
5672 decompressedBound: 0,
5673 };
5674 }
5675
5676 let mut zfh = ZSTD_FrameHeader::default();
5678 let rc = ZSTD_getFrameHeader_advanced(&mut zfh, src, format);
5679 if crate::common::error::ERR_isError(rc) {
5680 return frameSizeInfo_error(rc);
5681 }
5682 if rc > 0 {
5683 return frameSizeInfo_error(ERROR(ErrorCode::SrcSizeWrong));
5684 }
5685
5686 let mut ip = zfh.headerSize as usize;
5687 let mut remaining = srcSize - ip;
5688 let mut nbBlocks: usize = 0;
5689
5690 loop {
5691 let mut bp = blockProperties_t {
5692 blockType: blockType_e::bt_raw,
5693 lastBlock: 0,
5694 origSize: 0,
5695 };
5696 let cBlockSize = ZSTD_getcBlockSize(&src[ip..], &mut bp);
5697 if crate::common::error::ERR_isError(cBlockSize) {
5698 return frameSizeInfo_error(cBlockSize);
5699 }
5700 if ZSTD_blockHeaderSize + cBlockSize > remaining {
5701 return frameSizeInfo_error(ERROR(ErrorCode::SrcSizeWrong));
5702 }
5703 ip += ZSTD_blockHeaderSize + cBlockSize;
5704 remaining -= ZSTD_blockHeaderSize + cBlockSize;
5705 nbBlocks += 1;
5706 if bp.lastBlock != 0 {
5707 break;
5708 }
5709 }
5710
5711 if zfh.checksumFlag != 0 {
5712 if remaining < 4 {
5713 return frameSizeInfo_error(ERROR(ErrorCode::SrcSizeWrong));
5714 }
5715 ip += 4;
5716 }
5717
5718 let compressedSize = ip;
5719 let decompressedBound = if zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN {
5720 zfh.frameContentSize
5721 } else {
5722 nbBlocks as u64 * zfh.blockSizeMax as u64
5723 };
5724 ZSTD_frameSizeInfo {
5725 nbBlocks,
5726 compressedSize,
5727 decompressedBound,
5728 }
5729}
5730
5731pub fn ZSTD_findFrameCompressedSize_advanced(src: &[u8], format: ZSTD_format_e) -> usize {
5735 ZSTD_findFrameSizeInfo(src, format).compressedSize
5736}
5737
5738#[inline]
5742pub fn ZSTD_findFrameCompressedSize(src: &[u8]) -> usize {
5743 ZSTD_findFrameCompressedSize_advanced(src, ZSTD_format_e::ZSTD_f_zstd1)
5744}
5745
5746pub fn ZSTD_findDecompressedSize(src: &[u8]) -> u64 {
5749 let mut src = src;
5750 let mut total: u64 = 0;
5751 while src.len() >= ZSTD_startingInputLength(ZSTD_format_e::ZSTD_f_zstd1) {
5752 let magic = MEM_readLE32(&src[..4]);
5753 if (magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START {
5754 let sz = readSkippableFrameSize(src);
5755 if crate::common::error::ERR_isError(sz) {
5756 return ZSTD_CONTENTSIZE_ERROR;
5757 }
5758 src = &src[sz..];
5759 continue;
5760 }
5761 let fcs = ZSTD_getFrameContentSize(src);
5762 if fcs >= ZSTD_CONTENTSIZE_ERROR {
5763 return fcs;
5764 }
5765 if total.checked_add(fcs).is_none() {
5766 return ZSTD_CONTENTSIZE_ERROR;
5767 }
5768 total += fcs;
5769 let sz = ZSTD_findFrameCompressedSize(src);
5770 if crate::common::error::ERR_isError(sz) {
5771 return ZSTD_CONTENTSIZE_ERROR;
5772 }
5773 src = &src[sz..];
5774 }
5775 if !src.is_empty() {
5776 return ZSTD_CONTENTSIZE_ERROR;
5777 }
5778 total
5779}
5780
5781pub fn ZSTD_initDStream(zds: &mut ZSTD_DCtx) -> usize {
5786 zds.stream_in_buffer.clear();
5787 zds.stream_out_buffer.clear();
5788 zds.stream_out_drained = 0;
5789 ZSTD_startingInputLength(zds.format)
5796}
5797
5798pub fn ZSTD_initDStream_usingDict(zds: &mut ZSTD_DCtx, dict: &[u8]) -> usize {
5802 let rc = ZSTD_initDStream(zds);
5803 if crate::common::error::ERR_isError(rc) {
5804 return rc;
5805 }
5806 if !dict.is_empty() {
5812 let rc = ZSTD_DCtx_loadDictionary(zds, dict);
5813 if crate::common::error::ERR_isError(rc) {
5814 return rc;
5815 }
5816 }
5817 ZSTD_startingInputLength(zds.format)
5818}
5819
5820#[inline]
5827pub const fn ZSTD_DECOMPRESSION_MARGIN(originalSize: usize, blockSize: usize) -> usize {
5828 use crate::compress::zstd_compress::ZSTD_FRAMEHEADERSIZE_MAX;
5829 let blocks = if originalSize == 0 {
5830 0
5831 } else {
5832 3 * originalSize.div_ceil(blockSize)
5833 };
5834 ZSTD_FRAMEHEADERSIZE_MAX + 4 + blocks + blockSize
5835}
5836
5837pub fn ZSTD_decompressionMargin(src: &[u8]) -> usize {
5846 use crate::common::error::{ERR_isError, ErrorCode, ERROR};
5847 let mut margin: usize = 0;
5848 let mut maxBlockSize: u32 = 0;
5849 let mut cursor = src;
5850
5851 while !cursor.is_empty() {
5852 let info = ZSTD_findFrameSizeInfo(cursor, ZSTD_format_e::ZSTD_f_zstd1);
5853 let mut zfh = ZSTD_FrameHeader::default();
5854 let rc = ZSTD_getFrameHeader(&mut zfh, cursor);
5855 if ERR_isError(rc) {
5856 return rc;
5857 }
5858 if ERR_isError(info.compressedSize) || info.decompressedBound == ZSTD_CONTENTSIZE_ERROR {
5859 return ERROR(ErrorCode::CorruptionDetected);
5860 }
5861
5862 if zfh.frameType == ZSTD_FrameType_e::ZSTD_frame {
5863 margin += zfh.headerSize as usize;
5864 margin += if zfh.checksumFlag != 0 { 4 } else { 0 };
5865 margin += 3 * info.nbBlocks;
5866 if zfh.blockSizeMax > maxBlockSize {
5867 maxBlockSize = zfh.blockSizeMax;
5868 }
5869 } else {
5870 margin += info.compressedSize;
5872 }
5873
5874 cursor = &cursor[info.compressedSize..];
5875 }
5876
5877 margin + maxBlockSize as usize
5878}
5879
5880pub fn ZSTD_decompressBound(src: &[u8]) -> u64 {
5884 use crate::common::error::ERR_isError;
5885 let mut bound: u64 = 0;
5886 let mut cursor = src;
5887 while !cursor.is_empty() {
5888 let info = ZSTD_findFrameSizeInfo(cursor, ZSTD_format_e::ZSTD_f_zstd1);
5889 if ERR_isError(info.compressedSize) || info.decompressedBound == ZSTD_CONTENTSIZE_ERROR {
5890 return ZSTD_CONTENTSIZE_ERROR;
5891 }
5892 cursor = &cursor[info.compressedSize..];
5893 bound = bound.saturating_add(info.decompressedBound);
5894 }
5895 bound
5896}
5897
5898pub fn ZSTD_getDecompressedSize(src: &[u8]) -> u64 {
5903 let ret = ZSTD_getFrameContentSize(src);
5904 if ret >= ZSTD_CONTENTSIZE_ERROR {
5905 0
5906 } else {
5907 ret
5908 }
5909}
5910
5911pub fn ZSTD_decodingBufferSize_internal(
5918 windowSize: u64,
5919 frameContentSize: u64,
5920 blockSizeMax: usize,
5921) -> usize {
5922 use crate::common::error::{ErrorCode, ERROR};
5923 use crate::common::zstd_internal::WILDCOPY_OVERLENGTH;
5924 use crate::decompress::zstd_decompress_block::ZSTD_BLOCKSIZE_MAX;
5925 let blockSize = windowSize
5926 .min(ZSTD_BLOCKSIZE_MAX as u64)
5927 .min(blockSizeMax as u64) as usize;
5928 let neededRBSize: u64 = windowSize + (blockSize as u64) * 2 + (WILDCOPY_OVERLENGTH as u64) * 2;
5929 let neededSize = frameContentSize.min(neededRBSize);
5930 let minRBSize = neededSize as usize;
5931 if minRBSize as u64 != neededSize {
5932 return ERROR(ErrorCode::FrameParameterWindowTooLarge);
5933 }
5934 minRBSize
5935}
5936
5937pub fn ZSTD_decodingBufferSize_min(windowSize: u64, frameContentSize: u64) -> usize {
5943 use crate::decompress::zstd_decompress_block::ZSTD_BLOCKSIZE_MAX;
5944 ZSTD_decodingBufferSize_internal(windowSize, frameContentSize, ZSTD_BLOCKSIZE_MAX)
5945}
5946
5947pub fn ZSTD_createDCtx_advanced(
5949 customMem: crate::compress::zstd_compress::ZSTD_customMem,
5950) -> Option<Box<ZSTD_DCtx>> {
5951 if !crate::compress::zstd_compress::ZSTD_customMem_validate(customMem) {
5952 return None;
5953 }
5954 ZSTD_createDCtx_internal(customMem)
5955}
5956
5957pub fn ZSTD_createDStream_advanced(
5959 customMem: crate::compress::zstd_compress::ZSTD_customMem,
5960) -> Option<Box<ZSTD_DStream>> {
5961 ZSTD_createDCtx_advanced(customMem)
5962}
5963
5964pub fn ZSTD_initStaticDCtx(workspace: &mut [u8]) -> Option<&mut ZSTD_DCtx> {
5967 use core::mem::{align_of, size_of};
5968 use core::ptr;
5969
5970 if (workspace.as_mut_ptr() as usize) & (align_of::<u64>() - 1) != 0 {
5971 return None;
5972 }
5973 if workspace.len() < size_of::<ZSTD_DCtx>() {
5974 return None;
5975 }
5976
5977 let dctx = unsafe { &mut *(workspace.as_mut_ptr() as *mut ZSTD_DCtx) };
5978 unsafe {
5979 ptr::write(dctx, ZSTD_DCtx::default());
5980 }
5981 ZSTD_initDCtx_internal(dctx);
5982 Some(dctx)
5983}
5984
5985pub fn ZSTD_initStaticDStream(workspace: &mut [u8]) -> Option<&mut ZSTD_DStream> {
5987 ZSTD_initStaticDCtx(workspace)
5988}
5989
5990pub fn ZSTD_initStaticDDict<'a>(
5993 workspace: &'a mut [u8],
5994 dict: &[u8],
5995) -> Option<&'a mut crate::decompress::zstd_ddict::ZSTD_DDict> {
5996 use crate::decompress::zstd_ddict::{ZSTD_DDict, ZSTD_dictContentType_e};
5997 use core::mem::{align_of, size_of};
5998 use core::ptr;
5999
6000 if (workspace.as_mut_ptr() as usize) & (align_of::<u64>() - 1) != 0 {
6001 return None;
6002 }
6003 if workspace.len() < size_of::<ZSTD_DDict>() {
6004 return None;
6005 }
6006
6007 let ddict = unsafe { &mut *(workspace.as_mut_ptr() as *mut ZSTD_DDict) };
6008 unsafe {
6009 ptr::write(
6010 ddict,
6011 ZSTD_DDict {
6012 dictBuffer: Vec::new(),
6013 dictContent: dict.as_ptr(),
6014 dictSize: dict.len(),
6015 dictID: 0,
6016 entropyPresent: 0,
6017 },
6018 );
6019 }
6020 let rc = crate::decompress::zstd_ddict::ZSTD_loadEntropy_intoDDict(
6021 ddict,
6022 ZSTD_dictContentType_e::ZSTD_dct_auto,
6023 );
6024 if crate::common::error::ERR_isError(rc) {
6025 return None;
6026 }
6027 Some(ddict)
6028}
6029
6030#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
6033pub enum ZSTD_nextInputType_e {
6034 #[default]
6035 ZSTDnit_frameHeader = 0,
6036 ZSTDnit_blockHeader = 1,
6037 ZSTDnit_block = 2,
6038 ZSTDnit_lastBlock = 3,
6039 ZSTDnit_checksum = 4,
6040 ZSTDnit_skippableFrame = 5,
6041}
6042
6043#[inline]
6046pub fn ZSTD_nextInputType(dctx: &ZSTD_DCtx) -> ZSTD_nextInputType_e {
6047 match dctx.stage {
6048 ZSTD_dStage::ZSTDds_getFrameHeaderSize | ZSTD_dStage::ZSTDds_decodeFrameHeader => {
6049 ZSTD_nextInputType_e::ZSTDnit_frameHeader
6050 }
6051 ZSTD_dStage::ZSTDds_decodeBlockHeader => ZSTD_nextInputType_e::ZSTDnit_blockHeader,
6052 ZSTD_dStage::ZSTDds_decompressBlock => ZSTD_nextInputType_e::ZSTDnit_block,
6053 ZSTD_dStage::ZSTDds_decompressLastBlock => ZSTD_nextInputType_e::ZSTDnit_lastBlock,
6054 ZSTD_dStage::ZSTDds_checkChecksum => ZSTD_nextInputType_e::ZSTDnit_checksum,
6055 ZSTD_dStage::ZSTDds_decodeSkippableHeader | ZSTD_dStage::ZSTDds_skipFrame => {
6056 ZSTD_nextInputType_e::ZSTDnit_skippableFrame
6057 }
6058 }
6059}
6060
6061#[inline]
6066pub fn ZSTD_nextSrcSizeToDecompressWithInputSize(dctx: &ZSTD_DCtx, inputSize: usize) -> usize {
6067 let in_block = matches!(
6068 dctx.stage,
6069 ZSTD_dStage::ZSTDds_decompressBlock | ZSTD_dStage::ZSTDds_decompressLastBlock
6070 );
6071 if !in_block || dctx.bType != crate::decompress::zstd_decompress_block::blockType_e::bt_raw {
6072 return dctx.expected;
6073 }
6074 if dctx.expected == 0 {
6075 return 0;
6076 }
6077 inputSize.clamp(1, dctx.expected)
6078}
6079
6080#[inline]
6082pub fn ZSTD_isSkipFrame(dctx: &ZSTD_DCtx) -> i32 {
6083 (dctx.stage == ZSTD_dStage::ZSTDds_skipFrame) as i32
6084}
6085
6086#[inline]
6090pub fn ZSTD_decompressBegin(dctx: &mut ZSTD_DCtx) -> usize {
6091 use crate::common::xxhash::XXH64_reset;
6092 dctx.litEntropy = 0;
6097 dctx.fseEntropy = 0;
6098 dctx.dictID = 0;
6099 dctx.isFrameDecompression = 1;
6100 dctx.previousDstEnd = None;
6101 dctx.prefixStart = None;
6102 dctx.virtualStart = None;
6103 dctx.dictEnd = None;
6104 dctx.ddict_rep = [1, 4, 8];
6106 crate::decompress::zstd_decompress_block::ZSTD_buildDefaultSeqTables(dctx);
6112 dctx.expected = ZSTD_startingInputLength(dctx.format);
6113 dctx.stage = ZSTD_dStage::ZSTDds_getFrameHeaderSize;
6114 dctx.processedCSize = 0;
6115 dctx.decodedSize = 0;
6116 dctx.headerSize = 0;
6117 dctx.rleSize = 0;
6118 dctx.bType = crate::decompress::zstd_decompress_block::blockType_e::bt_raw;
6119 dctx.validateChecksum = 0;
6120 dctx.fParams = ZSTD_FrameHeader::default();
6121 dctx.headerBuffer.fill(0);
6122 dctx.historyBuffer.clear();
6123 XXH64_reset(&mut dctx.xxhState, 0);
6124 0
6125}
6126
6127pub fn ZSTD_decompressBegin_usingDict(dctx: &mut ZSTD_DCtx, dict: &[u8]) -> usize {
6132 use crate::common::error::{ERR_isError, ErrorCode, ERROR};
6133 let rc = ZSTD_decompressBegin(dctx);
6134 if ERR_isError(rc) {
6135 return rc;
6136 }
6137 if dict.is_empty() {
6138 return 0;
6139 }
6140 let rc = ZSTD_decompress_insertDictionary(dctx, dict);
6141 if ERR_isError(rc) {
6142 return ERROR(ErrorCode::DictionaryCorrupted);
6143 }
6144 0
6145}
6146
6147pub fn ZSTD_decompressBegin_usingDDict(
6150 dctx: &mut ZSTD_DCtx,
6151 ddict: &crate::decompress::zstd_ddict::ZSTD_DDict,
6152) -> usize {
6153 use crate::common::error::ERR_isError;
6154 let rc = ZSTD_decompressBegin(dctx);
6155 if ERR_isError(rc) {
6156 return rc;
6157 }
6158 let content = crate::decompress::zstd_ddict::ZSTD_DDict_dictContent(ddict);
6159 if content.is_empty() {
6160 return 0;
6161 }
6162 crate::decompress::zstd_ddict::ZSTD_copyDDictParameters(dctx, ddict);
6163 0
6164}
6165
6166pub fn ZSTD_decompressContinue(dctx: &mut ZSTD_DCtx, dst: &mut [u8], src: &[u8]) -> usize {
6170 use crate::common::error::{ErrorCode, ERROR};
6171 use crate::common::mem::MEM_readLE32;
6172 use crate::common::xxhash::{XXH64_digest, XXH64_update};
6173 use crate::decompress::zstd_decompress_block::{
6174 blockProperties_t, blockType_e, streaming_operation, ZSTD_blockHeaderSize,
6175 ZSTD_decoder_entropy_rep, ZSTD_decompressBlock_internal, ZSTD_getcBlockSize,
6176 };
6177
6178 if src.len() != ZSTD_nextSrcSizeToDecompress(dctx) {
6179 return ERROR(ErrorCode::SrcSizeWrong);
6180 }
6181
6182 dctx.processedCSize = dctx.processedCSize.wrapping_add(src.len() as u64);
6183
6184 match dctx.stage {
6185 ZSTD_dStage::ZSTDds_getFrameHeaderSize => {
6186 if dctx.format == ZSTD_format_e::ZSTD_f_zstd1
6187 && src.len() >= ZSTD_FRAMEIDSIZE
6188 && (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START
6189 {
6190 dctx.headerBuffer[..src.len()].copy_from_slice(src);
6191 dctx.expected = ZSTD_SKIPPABLEHEADERSIZE - src.len();
6192 dctx.stage = ZSTD_dStage::ZSTDds_decodeSkippableHeader;
6193 return 0;
6194 }
6195 let headerSize = ZSTD_frameHeaderSize_internal(src, dctx.format);
6196 if crate::common::error::ERR_isError(headerSize) {
6197 return headerSize;
6198 }
6199 dctx.headerSize = headerSize;
6200 dctx.headerBuffer[..src.len()].copy_from_slice(src);
6201 dctx.expected = headerSize - src.len();
6202 dctx.stage = ZSTD_dStage::ZSTDds_decodeFrameHeader;
6203 0
6204 }
6205 ZSTD_dStage::ZSTDds_decodeFrameHeader => {
6206 let offset = dctx.headerSize - src.len();
6207 dctx.headerBuffer[offset..offset + src.len()].copy_from_slice(src);
6208 let header = dctx.headerBuffer[..dctx.headerSize].to_vec();
6209 let rc = ZSTD_decodeFrameHeader(dctx, &header, header.len());
6210 if crate::common::error::ERR_isError(rc) {
6211 return rc;
6212 }
6213 if dctx.fParams.frameType != ZSTD_FrameType_e::ZSTD_frame {
6214 return ERROR(ErrorCode::PrefixUnknown);
6215 }
6216 dctx.expected = ZSTD_blockHeaderSize;
6217 dctx.stage = ZSTD_dStage::ZSTDds_decodeBlockHeader;
6218 0
6219 }
6220 ZSTD_dStage::ZSTDds_decodeBlockHeader => {
6221 let mut bp = blockProperties_t {
6222 blockType: blockType_e::bt_raw,
6223 lastBlock: 0,
6224 origSize: 0,
6225 };
6226 let cBlockSize = ZSTD_getcBlockSize(src, &mut bp);
6227 if crate::common::error::ERR_isError(cBlockSize) {
6228 return cBlockSize;
6229 }
6230 if cBlockSize > dctx.fParams.blockSizeMax as usize {
6231 return ERROR(ErrorCode::CorruptionDetected);
6232 }
6233 dctx.expected = cBlockSize;
6234 dctx.bType = bp.blockType;
6235 dctx.rleSize = bp.origSize as usize;
6236 if cBlockSize != 0 {
6237 dctx.stage = if bp.lastBlock != 0 {
6238 ZSTD_dStage::ZSTDds_decompressLastBlock
6239 } else {
6240 ZSTD_dStage::ZSTDds_decompressBlock
6241 };
6242 return 0;
6243 }
6244 if bp.lastBlock != 0 {
6245 if dctx.fParams.checksumFlag != 0 {
6246 dctx.expected = 4;
6247 dctx.stage = ZSTD_dStage::ZSTDds_checkChecksum;
6248 } else {
6249 dctx.expected = ZSTD_startingInputLength(dctx.format);
6250 dctx.stage = ZSTD_dStage::ZSTDds_getFrameHeaderSize;
6251 }
6252 } else {
6253 dctx.expected = ZSTD_blockHeaderSize;
6254 }
6255 0
6256 }
6257 ZSTD_dStage::ZSTDds_decompressLastBlock | ZSTD_dStage::ZSTDds_decompressBlock => {
6258 let mut entropy_rep = ZSTD_decoder_entropy_rep {
6259 rep: dctx.ddict_rep,
6260 };
6261 let rSize = match dctx.bType {
6262 blockType_e::bt_compressed => {
6263 let r = ZSTD_decompressBlock_internal(
6264 dctx,
6265 &mut entropy_rep,
6266 dst,
6267 0,
6268 src,
6269 streaming_operation::is_streaming,
6270 );
6271 dctx.expected = 0;
6272 r
6273 }
6274 blockType_e::bt_raw => {
6275 let r = ZSTD_copyRawBlock(dst, src);
6276 if crate::common::error::ERR_isError(r) {
6277 return r;
6278 }
6279 dctx.expected -= r;
6280 r
6281 }
6282 blockType_e::bt_rle => {
6283 let r = ZSTD_setRleBlock(dst, src[0], dctx.rleSize);
6284 dctx.expected = 0;
6285 r
6286 }
6287 blockType_e::bt_reserved => return ERROR(ErrorCode::CorruptionDetected),
6288 };
6289 if crate::common::error::ERR_isError(rSize) {
6290 return rSize;
6291 }
6292 if rSize > dctx.fParams.blockSizeMax as usize {
6293 return ERROR(ErrorCode::CorruptionDetected);
6294 }
6295 dctx.ddict_rep = entropy_rep.rep;
6296 dctx.decodedSize = dctx.decodedSize.wrapping_add(rSize as u64);
6297 if dctx.validateChecksum != 0 && rSize > 0 {
6298 XXH64_update(&mut dctx.xxhState, &dst[..rSize]);
6299 }
6300 if rSize > 0 {
6306 let cap = if dctx.fParams.windowSize > 0 {
6307 dctx.fParams.windowSize as usize
6308 } else {
6309 crate::decompress::zstd_decompress_block::ZSTD_BLOCKSIZE_MAX
6310 };
6311 dctx.historyBuffer.extend_from_slice(&dst[..rSize]);
6312 if dctx.historyBuffer.len() > cap {
6313 let drop = dctx.historyBuffer.len() - cap;
6314 dctx.historyBuffer.drain(..drop);
6315 }
6316 }
6317 if dctx.expected > 0 {
6318 return rSize;
6319 }
6320 if dctx.stage == ZSTD_dStage::ZSTDds_decompressLastBlock {
6321 if dctx.fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
6322 && dctx.decodedSize != dctx.fParams.frameContentSize
6323 {
6324 return ERROR(ErrorCode::CorruptionDetected);
6325 }
6326 if dctx.fParams.checksumFlag != 0 {
6327 dctx.expected = 4;
6328 dctx.stage = ZSTD_dStage::ZSTDds_checkChecksum;
6329 } else {
6330 dctx.expected = ZSTD_startingInputLength(dctx.format);
6331 dctx.stage = ZSTD_dStage::ZSTDds_getFrameHeaderSize;
6332 }
6333 dctx.historyBuffer.clear();
6336 } else {
6337 dctx.expected = ZSTD_blockHeaderSize;
6338 dctx.stage = ZSTD_dStage::ZSTDds_decodeBlockHeader;
6339 }
6340 rSize
6341 }
6342 ZSTD_dStage::ZSTDds_checkChecksum => {
6343 if dctx.validateChecksum != 0 {
6344 let h32 = XXH64_digest(&dctx.xxhState) as u32;
6345 let check32 = MEM_readLE32(src);
6346 if check32 != h32 {
6347 return ERROR(ErrorCode::ChecksumWrong);
6348 }
6349 }
6350 dctx.expected = ZSTD_startingInputLength(dctx.format);
6351 dctx.stage = ZSTD_dStage::ZSTDds_getFrameHeaderSize;
6352 0
6353 }
6354 ZSTD_dStage::ZSTDds_decodeSkippableHeader => {
6355 let offset = ZSTD_SKIPPABLEHEADERSIZE - src.len();
6356 dctx.headerBuffer[offset..offset + src.len()].copy_from_slice(src);
6357 dctx.expected = MEM_readLE32(&dctx.headerBuffer[ZSTD_FRAMEIDSIZE..]) as usize;
6358 dctx.stage = ZSTD_dStage::ZSTDds_skipFrame;
6359 0
6360 }
6361 ZSTD_dStage::ZSTDds_skipFrame => {
6362 dctx.expected = ZSTD_startingInputLength(dctx.format);
6363 dctx.stage = ZSTD_dStage::ZSTDds_getFrameHeaderSize;
6364 0
6365 }
6366 }
6367}
6368
6369#[inline]
6376pub fn ZSTD_copyDCtx(dst: &mut ZSTD_DCtx, src: &ZSTD_DCtx) {
6377 dst.clone_from(src);
6378}
6379
6380pub fn ZSTD_initDStream_usingDDict(
6385 zds: &mut ZSTD_DCtx,
6386 ddict: &crate::decompress::zstd_ddict::ZSTD_DDict,
6387) -> usize {
6388 let rc = ZSTD_initDStream(zds);
6389 if crate::common::error::ERR_isError(rc) {
6390 return rc;
6391 }
6392 let rc = ZSTD_DCtx_refDDict(zds, ddict);
6401 if crate::common::error::ERR_isError(rc) {
6402 return rc;
6403 }
6404 ZSTD_startingInputLength(zds.format)
6407}
6408
6409#[inline]
6412pub fn ZSTD_nextSrcSizeToDecompress(dctx: &ZSTD_DCtx) -> usize {
6413 dctx.expected
6414}
6415
6416pub fn ZSTD_resetDStream(zds: &mut ZSTD_DCtx) -> usize {
6420 zds.stream_in_buffer.clear();
6421 zds.stream_out_buffer.clear();
6422 zds.stream_out_drained = 0;
6423 zds.oversizedDuration = 0;
6424 ZSTD_startingInputLength(zds.format)
6429}
6430
6431pub fn ZSTD_DCtx_isOverflow(
6433 zds: &ZSTD_DCtx,
6434 neededInBuffSize: usize,
6435 neededOutBuffSize: usize,
6436) -> i32 {
6437 let retained = zds.stream_in_buffer.capacity() + zds.stream_out_buffer.capacity();
6438 let needed = (neededInBuffSize + neededOutBuffSize)
6439 * crate::common::zstd_internal::ZSTD_WORKSPACETOOLARGE_FACTOR;
6440 (retained >= needed) as i32
6441}
6442
6443pub fn ZSTD_DCtx_updateOversizedDuration(
6445 zds: &mut ZSTD_DCtx,
6446 neededInBuffSize: usize,
6447 neededOutBuffSize: usize,
6448) {
6449 if ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize) != 0 {
6450 zds.oversizedDuration += 1;
6451 } else {
6452 zds.oversizedDuration = 0;
6453 }
6454}
6455
6456#[inline]
6459pub fn ZSTD_checkOutBuffer(_zds: &ZSTD_DCtx, _output: &[u8], _output_pos: usize) -> usize {
6460 0
6461}
6462
6463pub fn ZSTD_decompressContinueStream(
6467 zds: &mut ZSTD_DCtx,
6468 output: &mut [u8],
6469 output_pos: &mut usize,
6470 src: &[u8],
6471) -> usize {
6472 let dstSize = if ZSTD_isSkipFrame(zds) != 0 {
6473 0
6474 } else {
6475 output.len() - *output_pos
6476 };
6477 let decodedSize =
6478 ZSTD_decompressContinue(zds, &mut output[*output_pos..*output_pos + dstSize], src);
6479 if crate::common::error::ERR_isError(decodedSize) {
6480 return decodedSize;
6481 }
6482 *output_pos += decodedSize;
6483 0
6484}
6485
6486pub fn ZSTD_decompressStream(
6498 zds: &mut ZSTD_DCtx,
6499 output: &mut [u8],
6500 output_pos: &mut usize,
6501 input: &[u8],
6502 input_pos: &mut usize,
6503) -> usize {
6504 use crate::common::error::ERR_isError;
6505 let avail = output.len() - *output_pos;
6507 let pending = zds.stream_out_buffer.len() - zds.stream_out_drained;
6508 let n = avail.min(pending);
6509 if n > 0 {
6510 output[*output_pos..*output_pos + n].copy_from_slice(
6511 &zds.stream_out_buffer[zds.stream_out_drained..zds.stream_out_drained + n],
6512 );
6513 zds.stream_out_drained += n;
6514 *output_pos += n;
6515 }
6516
6517 zds.stream_in_buffer.extend_from_slice(&input[*input_pos..]);
6519 *input_pos = input.len();
6520
6521 if zds.stream_out_drained == zds.stream_out_buffer.len() && zds.stream_in_buffer.is_empty() {
6523 return 0;
6524 }
6525 if zds.stream_out_drained == zds.stream_out_buffer.len() {
6528 let frame_sz = ZSTD_findFrameCompressedSize_advanced(&zds.stream_in_buffer, zds.format);
6532 if ERR_isError(frame_sz) {
6533 return 3; }
6537 let declared = ZSTD_getFrameContentSize(&zds.stream_in_buffer);
6539 let out_size = if declared == ZSTD_CONTENTSIZE_UNKNOWN || declared == ZSTD_CONTENTSIZE_ERROR
6540 {
6541 frame_sz * 32
6543 } else {
6544 declared as usize
6545 };
6546 let mut decoded = vec![0u8; out_size.max(1)];
6547 let d = if zds.stream_dict.is_empty() {
6548 use crate::common::xxhash::XXH64_state_t;
6554 use crate::decompress::zstd_decompress_block::ZSTD_decoder_entropy_rep;
6555 let frame_bytes = zds.stream_in_buffer[..frame_sz].to_vec();
6556 let mut rep = ZSTD_decoder_entropy_rep::default();
6557 let mut xxh = XXH64_state_t::default();
6558 ZSTD_decompressDCtx(zds, &mut rep, &mut xxh, &mut decoded, &frame_bytes)
6559 } else {
6560 let was_use_once = zds.dictUses == ZSTD_dictUses_e::ZSTD_use_once;
6573 if was_use_once {
6574 zds.dictUses = ZSTD_dictUses_e::ZSTD_dont_use;
6575 }
6576 let dict = zds.stream_dict.clone();
6577 let frame_bytes = zds.stream_in_buffer[..frame_sz].to_vec();
6578 let decoded_len = ZSTD_decompress_usingDict(zds, &mut decoded, &frame_bytes, &dict);
6579 if was_use_once && !ERR_isError(decoded_len) {
6580 ZSTD_clearDict(zds);
6581 }
6582 decoded_len
6583 };
6584 if ERR_isError(d) {
6585 return d;
6586 }
6587 decoded.truncate(d);
6588 zds.stream_out_buffer = decoded;
6589 zds.stream_out_drained = 0;
6590 zds.stream_in_buffer.drain(..frame_sz);
6593
6594 let avail = output.len() - *output_pos;
6596 let pending = zds.stream_out_buffer.len() - zds.stream_out_drained;
6597 let n = avail.min(pending);
6598 if n > 0 {
6599 output[*output_pos..*output_pos + n].copy_from_slice(
6600 &zds.stream_out_buffer[zds.stream_out_drained..zds.stream_out_drained + n],
6601 );
6602 zds.stream_out_drained += n;
6603 *output_pos += n;
6604 }
6605 }
6606
6607 let remaining = zds.stream_out_buffer.len() - zds.stream_out_drained;
6608 if remaining == 0 && zds.stream_in_buffer.is_empty() {
6609 0
6610 } else {
6611 remaining.max(3)
6612 }
6613}
6614
6615#[allow(clippy::too_many_arguments)]
6623#[inline]
6624pub fn ZSTD_decompressStream_simpleArgs(
6625 dctx: &mut ZSTD_DCtx,
6626 dst: &mut [u8],
6627 dst_pos: &mut usize,
6628 src: &[u8],
6629 src_pos: &mut usize,
6630) -> usize {
6631 ZSTD_decompressStream(dctx, dst, dst_pos, src, src_pos)
6632}