1use core::arch::asm;
2use core::ffi::c_void;
3use core::ops::Range;
4use core::ptr::{self, NonNull};
5
6use libc::{ptrdiff_t, size_t};
7
8use crate::lib::common::bitstream::BIT_DStream_t;
9use crate::lib::common::entropy_common::FSE_readNCount_slice;
10use crate::lib::common::error_private::{ERR_isError, Error};
11use crate::lib::common::huf::{HUF_flags_bmi2, HUF_flags_disableAsm};
12use crate::lib::common::mem::{MEM_32bits, MEM_readLE24};
13use crate::lib::common::reader::Reader;
14use crate::lib::common::zstd_internal::{
15 LLFSELog, LL_bits, MLFSELog, ML_bits, MaxFSELog, MaxLL, MaxLLBits, MaxML, MaxMLBits, MaxOff,
16 MaxSeq, OffFSELog, Overlap, ZSTD_copy16, ZSTD_wildcopy, LL_DEFAULTNORMLOG, ML_DEFAULTNORMLOG,
17 OF_DEFAULTNORMLOG, WILDCOPY_OVERLENGTH, WILDCOPY_VECLEN, ZSTD_REP_NUM,
18};
19use crate::lib::decompress::huf_decompress::{
20 HUF_decompress1X1_DCtx_wksp, HUF_decompress1X_usingDTable, HUF_decompress4X_usingDTable,
21};
22use crate::lib::decompress::huf_decompress::{HUF_decompress4X_hufOnly_wksp, Writer};
23use crate::lib::decompress::{blockProperties_t, BlockType, SymbolTable};
24use crate::lib::decompress::{
25 LL_base, LitLocation, ML_base, OF_base, OF_bits, Workspace, ZSTD_DCtx, ZSTD_seqSymbol,
26 ZSTD_seqSymbol_header,
27};
28use crate::lib::polyfill::{cfg_select, likely, prefetch_read_data, unlikely, Locality};
29use crate::lib::zstd::{ZSTD_BLOCKSIZE_MAX, ZSTD_WINDOWLOG_MAX, ZSTD_WINDOWLOG_MAX_32};
30
31pub type BIT_DStream_status = core::ffi::c_uint;
32pub const BIT_DStream_overflow: BIT_DStream_status = 3;
33pub const BIT_DStream_completed: BIT_DStream_status = 2;
34pub const BIT_DStream_endOfBuffer: BIT_DStream_status = 1;
35pub const BIT_DStream_unfinished: BIT_DStream_status = 0;
36pub type C2RustUnnamed_0 = core::ffi::c_uint;
37
38pub type streaming_operation = core::ffi::c_uint;
39pub const is_streaming: streaming_operation = 1;
40pub const not_streaming: streaming_operation = 0;
41
42#[derive(Debug, Copy, Clone, PartialEq, Eq)]
43pub(crate) enum StreamingOperation {
44 NotStreaming = 0,
45 IsStreaming = 1,
46}
47
48impl TryFrom<u32> for StreamingOperation {
49 type Error = ();
50
51 fn try_from(value: u32) -> Result<Self, Self::Error> {
52 match value {
53 0 => Ok(Self::NotStreaming),
54 1 => Ok(Self::IsStreaming),
55 _ => Err(()),
56 }
57 }
58}
59
60#[derive(Debug, Copy, Clone, PartialEq, Eq)]
61enum Offset {
62 Regular = 0,
63 Long = 1,
64}
65
66#[repr(C)]
67pub struct seqState_t<'a> {
68 DStream: BIT_DStream_t<'a>,
69 stateLL: ZSTD_fseState<'a>,
70 stateOffb: ZSTD_fseState<'a>,
71 stateML: ZSTD_fseState<'a>,
72 prevOffset: [size_t; 3],
73}
74
75impl ZSTD_DCtx {
76 fn new_seq_state<'a>(&self, mut bit_stream: BIT_DStream_t<'a>) -> seqState_t<'a> {
77 let stateLL = match self.LLTptr {
78 None => ZSTD_fseState::new(&mut bit_stream, &LL_defaultDTable),
79 Some(table) => ZSTD_fseState::new(&mut bit_stream, unsafe { &*table.as_ptr() }),
80 };
81
82 let stateOffb = match self.OFTptr {
83 None => ZSTD_fseState::new(&mut bit_stream, &OF_defaultDTable),
84 Some(table) => ZSTD_fseState::new(&mut bit_stream, unsafe { &*table.as_ptr() }),
85 };
86
87 let stateML = match self.MLTptr {
88 None => ZSTD_fseState::new(&mut bit_stream, &ML_defaultDTable),
89 Some(table) => ZSTD_fseState::new(&mut bit_stream, unsafe { &*table.as_ptr() }),
90 };
91
92 seqState_t {
93 stateLL,
94 stateOffb,
95 stateML,
96 DStream: bit_stream,
97 prevOffset: self.entropy.rep.map(|v| v as size_t),
98 }
99 }
100}
101
102#[repr(C)]
103pub struct ZSTD_fseState<'a> {
104 pub state: size_t,
105 pub table: &'a [ZSTD_seqSymbol],
106}
107
108impl<'a> ZSTD_fseState<'a> {
109 pub(crate) fn new<const N: usize>(
110 bit_dstream: &mut BIT_DStream_t,
111 dt: &'a SymbolTable<N>,
112 ) -> Self {
113 let table = &dt.symbols;
114
115 let state = bit_dstream.read_bits(dt.header.tableLog);
116 bit_dstream.reload();
117
118 Self { state, table }
119 }
120}
121
122#[derive(Copy, Clone, Default)]
123#[repr(C)]
124pub struct seq_t {
125 pub litLength: size_t,
126 pub matchLength: size_t,
127 pub offset: size_t,
128}
129
130#[derive(Copy, Clone, Default)]
131#[repr(C)]
132pub struct ZSTD_OffsetInfo {
133 pub longOffsetShare: core::ffi::c_uint,
134 pub maxNbAdditionalBits: core::ffi::c_uint,
135}
136
137#[repr(u32)]
138enum SymbolEncodingType_e {
139 set_basic = 0,
140 set_rle = 1,
141 set_compressed = 2,
142 set_repeat = 3,
143}
144
145impl TryFrom<u8> for SymbolEncodingType_e {
146 type Error = ();
147
148 fn try_from(value: u8) -> Result<Self, Self::Error> {
149 match value {
150 0 => Ok(SymbolEncodingType_e::set_basic),
151 1 => Ok(SymbolEncodingType_e::set_rle),
152 2 => Ok(SymbolEncodingType_e::set_compressed),
153 3 => Ok(SymbolEncodingType_e::set_repeat),
154 _ => Err(()),
155 }
156 }
157}
158
159pub const CACHELINE_SIZE: core::ffi::c_int = 64;
160
161pub const STREAM_ACCUMULATOR_MIN: core::ffi::c_int = match size_of::<usize>() {
162 4 => STREAM_ACCUMULATOR_MIN_32,
163 8 => STREAM_ACCUMULATOR_MIN_64,
164 _ => unreachable!(),
165};
166pub const STREAM_ACCUMULATOR_MIN_32: core::ffi::c_int = 25;
167pub const STREAM_ACCUMULATOR_MIN_64: core::ffi::c_int = 57;
168
169pub const ZSTD_BLOCKHEADERSIZE: core::ffi::c_int = 3;
170static ZSTD_blockHeaderSize: size_t = ZSTD_BLOCKHEADERSIZE as size_t;
171pub const LONGNBSEQ: core::ffi::c_int = 0x7f00 as core::ffi::c_int;
172
173impl ZSTD_DCtx {
174 fn block_size_max(&self) -> usize {
175 if self.isFrameDecompression {
176 self.fParams.blockSizeMax as usize
177 } else {
178 ZSTD_BLOCKSIZE_MAX as usize
179 }
180 }
181}
182
183pub(crate) fn ZSTD_getcBlockSize(
184 src: &[u8],
185 bpPtr: &mut blockProperties_t,
186) -> Result<size_t, Error> {
187 if src.len() < ZSTD_blockHeaderSize {
188 return Err(Error::srcSize_wrong);
189 }
190 let cBlockHeader = unsafe { MEM_readLE24(src.as_ptr().cast()) };
191 let cSize = cBlockHeader >> 3;
192
193 bpPtr.lastBlock = (cBlockHeader & 1) != 0;
194 bpPtr.blockType = BlockType::from(cBlockHeader >> 1 & 0b11);
195 bpPtr.origSize = cSize;
196
197 match bpPtr.blockType {
198 BlockType::Raw | BlockType::Compressed => Ok(cSize as size_t),
199 BlockType::Rle => Ok(1),
200 BlockType::Reserved => Err(Error::corruption_detected),
201 }
202}
203
204pub(crate) fn getc_block_size(src: &[u8]) -> Result<(blockProperties_t, usize), Error> {
205 let [a, b, c, ..] = *src else {
206 return Err(Error::srcSize_wrong);
207 };
208
209 let cBlockHeader = u32::from_le_bytes([a, b, c, 0]);
210 let cSize = cBlockHeader >> 3;
211
212 let bp = blockProperties_t {
213 lastBlock: (cBlockHeader & 1) != 0,
214 blockType: BlockType::from(cBlockHeader >> 1 & 0b11),
215 origSize: cSize,
216 };
217
218 match bp.blockType {
219 BlockType::Raw | BlockType::Compressed => Ok((bp, cSize as size_t)),
220 BlockType::Rle => Ok((bp, 1)),
221 BlockType::Reserved => Err(Error::corruption_detected),
222 }
223}
224
225fn ZSTD_allocateLiteralsBuffer(
226 dctx: &mut ZSTD_DCtx,
227 mut dst: Writer<'_>,
228 litSize: usize,
229 streaming: StreamingOperation,
230 expectedWriteSize: usize,
231 split_immediately: bool,
232) {
233 let dstCapacity = dst.capacity();
234 let dst = dst.as_mut_ptr();
235
236 let blockSizeMax = dctx.block_size_max();
237 if streaming == StreamingOperation::NotStreaming
238 && dstCapacity
239 > blockSizeMax.wrapping_add(WILDCOPY_OVERLENGTH + litSize + WILDCOPY_OVERLENGTH)
240 {
241 dctx.litBuffer = dst.wrapping_add(blockSizeMax + WILDCOPY_OVERLENGTH);
242 dctx.litBufferEnd = dctx.litBuffer.wrapping_add(litSize);
243 dctx.litBufferLocation = LitLocation::ZSTD_in_dst;
244 } else if litSize <= ZSTD_LITBUFFEREXTRASIZE {
245 dctx.litBuffer = (dctx.litExtraBuffer).as_mut_ptr();
246 dctx.litBufferEnd = dctx.litBuffer.wrapping_add(litSize);
247 dctx.litBufferLocation = LitLocation::ZSTD_not_in_dst;
248 } else {
249 if split_immediately {
250 dctx.litBuffer = dst
251 .wrapping_add(expectedWriteSize)
252 .wrapping_sub(litSize)
253 .wrapping_add(ZSTD_LITBUFFEREXTRASIZE)
254 .wrapping_sub(WILDCOPY_OVERLENGTH);
255 dctx.litBufferEnd = dctx
256 .litBuffer
257 .wrapping_add(litSize)
258 .wrapping_sub(ZSTD_LITBUFFEREXTRASIZE);
259 } else {
260 dctx.litBuffer = dst.wrapping_add(expectedWriteSize).wrapping_sub(litSize);
261 dctx.litBufferEnd = dst.wrapping_add(expectedWriteSize);
262 }
263 dctx.litBufferLocation = LitLocation::ZSTD_split;
264 }
265}
266
267const ZSTD_LBMIN: usize = 64;
268const ZSTD_LBMAX: usize = 128 << 10;
269
270const ZSTD_DECODER_INTERNAL_BUFFER: usize = 1 << 16;
271
272pub(crate) const ZSTD_LITBUFFEREXTRASIZE: usize = {
273 if ZSTD_DECODER_INTERNAL_BUFFER < ZSTD_LBMIN {
275 ZSTD_LBMIN
276 } else if ZSTD_DECODER_INTERNAL_BUFFER > ZSTD_LBMAX {
277 ZSTD_LBMAX
278 } else {
279 ZSTD_DECODER_INTERNAL_BUFFER
280 }
281};
282
283fn ZSTD_decodeLiteralsBlock(
284 dctx: &mut ZSTD_DCtx,
285 src: &[u8],
286 dst: Writer<'_>,
287 streaming: StreamingOperation,
288) -> Result<size_t, Error> {
289 const MIN_CBLOCK_SIZE: usize = 1 + 1;
291 if src.len() < MIN_CBLOCK_SIZE {
292 return Err(Error::corruption_detected);
293 }
294
295 let blockSizeMax = dctx.block_size_max();
296
297 let litEncType = SymbolEncodingType_e::try_from(src[0] & 0b11).unwrap();
298 match litEncType {
299 SymbolEncodingType_e::set_repeat if !dctx.litEntropy => {
300 return Err(Error::dictionary_corrupted);
301 }
302 SymbolEncodingType_e::set_repeat | SymbolEncodingType_e::set_compressed => {}
303 SymbolEncodingType_e::set_basic => {
304 let (lhSize, litSize) = match src[0] >> 2 & 0b11 {
305 1 => (2usize, (u16::from_le_bytes([src[0], src[1]]) >> 4) as usize),
306 3 => {
307 let [a, b, c, ..] = *src else {
308 return Err(Error::corruption_detected);
309 };
310
311 (3, (u32::from_le_bytes([a, b, c, 0]) >> 4) as usize)
312 }
313 _ => (1, (src[0] >> 3) as usize),
314 };
315
316 if litSize > 0 && dst.is_null() {
317 return Err(Error::dstSize_tooSmall);
318 }
319 if litSize > blockSizeMax {
320 return Err(Error::corruption_detected);
321 }
322
323 let expectedWriteSize = Ord::min(dst.capacity(), blockSizeMax);
324 if expectedWriteSize < litSize {
325 return Err(Error::dstSize_tooSmall);
326 }
327
328 ZSTD_allocateLiteralsBuffer(dctx, dst, litSize, streaming, expectedWriteSize, true);
329
330 if lhSize + litSize + WILDCOPY_OVERLENGTH > src.len() {
331 if litSize.wrapping_add(lhSize) > src.len() {
332 return Err(Error::corruption_detected);
333 }
334 if dctx.litBufferLocation == LitLocation::ZSTD_split {
335 unsafe {
336 let len = litSize - ZSTD_LITBUFFEREXTRASIZE;
337 let src = &src[lhSize..][..len];
338
339 core::ptr::copy_nonoverlapping(src.as_ptr(), dctx.litBuffer, len)
340 };
341
342 dctx.litExtraBuffer[..ZSTD_LITBUFFEREXTRASIZE].copy_from_slice(
343 &src[lhSize + litSize - ZSTD_LITBUFFEREXTRASIZE..]
344 [..ZSTD_LITBUFFEREXTRASIZE],
345 );
346 } else {
347 unsafe {
348 let src = &src[lhSize..][..litSize];
349
350 core::ptr::copy_nonoverlapping(src.as_ptr(), dctx.litBuffer, litSize)
351 };
352 }
353 dctx.litPtr = dctx.litBuffer;
354 dctx.litSize = litSize;
355 return Ok(lhSize.wrapping_add(litSize));
356 }
357
358 dctx.litPtr = src[lhSize..].as_ptr();
359 dctx.litSize = litSize;
360 dctx.litBufferEnd = unsafe { (dctx.litPtr).add(litSize) };
361 dctx.litBufferLocation = LitLocation::ZSTD_not_in_dst;
362
363 return Ok(lhSize.wrapping_add(litSize));
364 }
365 SymbolEncodingType_e::set_rle => {
366 let (lhSize, litSize) = match src[0] >> 2 & 0b11 {
367 1 => {
368 let [a, b, _, ..] = *src else {
369 return Err(Error::corruption_detected);
370 };
371
372 (2usize, (u16::from_le_bytes([a, b]) >> 4) as usize)
373 }
374 3 => {
375 let [a, b, c, _, ..] = *src else {
376 return Err(Error::corruption_detected);
377 };
378
379 (3, (u32::from_le_bytes([a, b, c, 0]) >> 4) as usize)
380 }
381 _ => (1, (src[0] >> 3) as usize),
382 };
383
384 if litSize > 0 && dst.is_null() {
385 return Err(Error::dstSize_tooSmall);
386 }
387 if litSize > blockSizeMax {
388 return Err(Error::corruption_detected);
389 }
390
391 let expectedWriteSize = Ord::min(dst.capacity(), blockSizeMax);
392 if expectedWriteSize < litSize {
393 return Err(Error::dstSize_tooSmall);
394 }
395
396 ZSTD_allocateLiteralsBuffer(dctx, dst, litSize, streaming, expectedWriteSize, true);
397
398 if dctx.litBufferLocation == LitLocation::ZSTD_split {
399 unsafe {
400 ptr::write_bytes(
401 dctx.litBuffer,
402 src[lhSize],
403 litSize - ZSTD_LITBUFFEREXTRASIZE,
404 )
405 };
406
407 dctx.litExtraBuffer[..ZSTD_LITBUFFEREXTRASIZE].fill(src[lhSize]);
408 } else {
409 unsafe {
410 ptr::write_bytes(dctx.litBuffer, src[lhSize], litSize);
411 }
412 }
413 dctx.litPtr = dctx.litBuffer;
414 dctx.litSize = litSize;
415 return Ok(lhSize.wrapping_add(1));
416 }
417 }
418
419 let [a, b, c, d, size_correction, ..] = *src else {
420 return Err(Error::corruption_detected);
421 };
422 let lhc = u32::from_le_bytes([a, b, c, d]) as usize;
423
424 let flags = {
425 let bmi_flag = if dctx.bmi2 {
426 HUF_flags_bmi2 as core::ffi::c_int
427 } else {
428 0
429 };
430
431 let disable_asm_flag = if dctx.disableHufAsm {
432 HUF_flags_disableAsm as core::ffi::c_int
433 } else {
434 0
435 };
436
437 bmi_flag | disable_asm_flag
438 };
439
440 let lhlCode = (src[0] >> 2 & 0b11) as u32;
441 let singleStream = lhlCode == 0;
442
443 let (lhSize, litSize, litCSize) = match lhlCode {
444 2 => (4, lhc >> 4 & 0x3fff, lhc >> 18),
445 3 => (
446 5,
447 lhc >> 4 & 0x3ffff,
448 (lhc >> 22) + ((size_correction as usize) << 10),
449 ),
450 _ => (3, lhc >> 4 & 0x3ff, lhc >> 14 & 0x3ff),
451 };
452
453 if litSize > 0 && dst.is_null() {
454 return Err(Error::dstSize_tooSmall);
455 }
456 if litSize > blockSizeMax {
457 return Err(Error::corruption_detected);
458 }
459 if !singleStream && litSize < 6 {
460 return Err(Error::literals_headerWrong);
461 }
462 if litCSize.wrapping_add(lhSize) > src.len() {
463 return Err(Error::corruption_detected);
464 }
465
466 let expectedWriteSize = Ord::min(dst.capacity(), blockSizeMax);
467 if expectedWriteSize < litSize {
468 return Err(Error::dstSize_tooSmall);
469 }
470
471 ZSTD_allocateLiteralsBuffer(dctx, dst, litSize, streaming, expectedWriteSize, false);
472
473 if dctx.ddictIsCold && litSize > 768 {
475 let ptr = match dctx.HUFptr {
477 None => &raw const dctx.entropy.hufTable,
478 Some(ptr) => ptr.as_ptr().cast_const(),
479 };
480 prefetch_val(ptr);
481 }
482
483 let writer = unsafe { Writer::from_raw_parts(dctx.litBuffer, litSize as _) };
484 let huf_src = &src[lhSize..][..litCSize];
485
486 let hufSuccess = if let SymbolEncodingType_e::set_repeat = litEncType {
487 let dtable = match dctx.HUFptr {
488 None => &dctx.entropy.hufTable,
489 Some(ptr) => unsafe { ptr.as_ref() },
490 };
491
492 if singleStream {
493 HUF_decompress1X_usingDTable(writer, huf_src, dtable, flags)
494 } else {
495 HUF_decompress4X_usingDTable(writer, huf_src, dtable, flags)
496 }
497 } else if singleStream {
498 HUF_decompress1X1_DCtx_wksp(
499 &mut dctx.entropy.hufTable,
500 writer,
501 huf_src,
502 &mut dctx.workspace,
503 flags,
504 )
505 } else {
506 HUF_decompress4X_hufOnly_wksp(
507 &mut dctx.entropy.hufTable,
508 writer,
509 huf_src,
510 &mut dctx.workspace,
511 flags,
512 )
513 };
514
515 if dctx.litBufferLocation == LitLocation::ZSTD_split {
516 debug_assert!(litSize > ZSTD_LITBUFFEREXTRASIZE);
517
518 unsafe {
519 core::ptr::copy_nonoverlapping(
520 dctx.litBufferEnd.sub(ZSTD_LITBUFFEREXTRASIZE),
521 dctx.litExtraBuffer.as_mut_ptr(),
522 ZSTD_LITBUFFEREXTRASIZE,
523 );
524 core::ptr::copy(
525 dctx.litBuffer,
526 dctx.litBuffer
527 .add(ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH),
528 litSize.wrapping_sub(ZSTD_LITBUFFEREXTRASIZE),
529 );
530 dctx.litBuffer = (dctx.litBuffer).add(ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH);
531 dctx.litBufferEnd = (dctx.litBufferEnd).sub(WILDCOPY_OVERLENGTH);
532 }
533 }
534
535 if ERR_isError(hufSuccess) {
536 return Err(Error::corruption_detected);
537 }
538
539 dctx.litPtr = dctx.litBuffer;
540 dctx.litSize = litSize;
541 dctx.litEntropy = true;
542
543 if let SymbolEncodingType_e::set_compressed = litEncType {
544 dctx.HUFptr = None;
545 }
546
547 Ok(litCSize.wrapping_add(lhSize))
548}
549
550const fn sequence_symbol(
551 nextState: u16,
552 nbAdditionalBits: u8,
553 nbBits: u8,
554 baseValue: u32,
555) -> ZSTD_seqSymbol {
556 ZSTD_seqSymbol {
557 nextState,
558 nbAdditionalBits,
559 nbBits,
560 baseValue,
561 }
562}
563
564const fn sequence_header(fastMode: u32, tableLog: u32) -> ZSTD_seqSymbol_header {
565 ZSTD_seqSymbol_header { fastMode, tableLog }
566}
567
568#[rustfmt::skip]
570static LL_defaultDTable: SymbolTable< { 1 << LL_DEFAULTNORMLOG }> = SymbolTable {
571 header: sequence_header(0x00010101, LL_DEFAULTNORMLOG),
573 symbols: [
575 sequence_symbol( 0, 0, 4, 0), sequence_symbol(16, 0, 4, 0),
576 sequence_symbol(32, 0, 5, 1), sequence_symbol( 0, 0, 5, 3),
577 sequence_symbol( 0, 0, 5, 4), sequence_symbol( 0, 0, 5, 6),
578 sequence_symbol( 0, 0, 5, 7), sequence_symbol( 0, 0, 5, 9),
579 sequence_symbol( 0, 0, 5, 10), sequence_symbol( 0, 0, 5, 12),
580 sequence_symbol( 0, 0, 6, 14), sequence_symbol( 0, 1, 5, 16),
581 sequence_symbol( 0, 1, 5, 20), sequence_symbol( 0, 1, 5, 22),
582 sequence_symbol( 0, 2, 5, 28), sequence_symbol( 0, 3, 5, 32),
583 sequence_symbol( 0, 4, 5, 48), sequence_symbol(32, 6, 5, 64),
584 sequence_symbol( 0, 7, 5, 128), sequence_symbol( 0, 8, 6, 256),
585 sequence_symbol( 0, 10, 6, 1024), sequence_symbol( 0, 12, 6, 4096),
586 sequence_symbol(32, 0, 4, 0), sequence_symbol( 0, 0, 4, 1),
587 sequence_symbol( 0, 0, 5, 2), sequence_symbol(32, 0, 5, 4),
588 sequence_symbol( 0, 0, 5, 5), sequence_symbol(32, 0, 5, 7),
589 sequence_symbol( 0, 0, 5, 8), sequence_symbol(32, 0, 5, 10),
590 sequence_symbol( 0, 0, 5, 11), sequence_symbol( 0, 0, 6, 13),
591 sequence_symbol(32, 1, 5, 16), sequence_symbol( 0, 1, 5, 18),
592 sequence_symbol(32, 1, 5, 22), sequence_symbol( 0, 2, 5, 24),
593 sequence_symbol(32, 3, 5, 32), sequence_symbol( 0, 3, 5, 40),
594 sequence_symbol( 0, 6, 4, 64), sequence_symbol(16, 6, 4, 64),
595 sequence_symbol(32, 7, 5, 128), sequence_symbol( 0, 9, 6, 512),
596 sequence_symbol( 0, 11, 6, 2048), sequence_symbol(48, 0, 4, 0),
597 sequence_symbol(16, 0, 4, 1), sequence_symbol(32, 0, 5, 2),
598 sequence_symbol(32, 0, 5, 3), sequence_symbol(32, 0, 5, 5),
599 sequence_symbol(32, 0, 5, 6), sequence_symbol(32, 0, 5, 8),
600 sequence_symbol(32, 0, 5, 9), sequence_symbol(32, 0, 5, 11),
601 sequence_symbol(32, 0, 5, 12), sequence_symbol( 0, 0, 6, 15),
602 sequence_symbol(32, 1, 5, 18), sequence_symbol(32, 1, 5, 20),
603 sequence_symbol(32, 2, 5, 24), sequence_symbol(32, 2, 5, 28),
604 sequence_symbol(32, 3, 5, 40), sequence_symbol(32, 4, 5, 48),
605 sequence_symbol( 0, 16, 6,65536), sequence_symbol( 0, 15, 6,32768),
606 sequence_symbol( 0, 14, 6,16384), sequence_symbol( 0, 13, 6, 8192),
607 ]
608};
609
610#[rustfmt::skip]
612static OF_defaultDTable: SymbolTable<{ 1 << OF_DEFAULTNORMLOG }> = SymbolTable {
613 header: sequence_header(0x00010101, OF_DEFAULTNORMLOG),
615 symbols: [
617 sequence_symbol( 0, 0, 5, 0), sequence_symbol( 0, 6, 4, 61),
618 sequence_symbol( 0, 9, 5, 509), sequence_symbol( 0, 15, 5,32765),
619 sequence_symbol( 0, 21, 5,2097149), sequence_symbol( 0, 3, 5, 5),
620 sequence_symbol( 0, 7, 4, 125), sequence_symbol( 0, 12, 5, 4093),
621 sequence_symbol( 0, 18, 5,262141), sequence_symbol( 0, 23, 5,8388605),
622 sequence_symbol( 0, 5, 5, 29), sequence_symbol( 0, 8, 4, 253),
623 sequence_symbol( 0, 14, 5,16381), sequence_symbol( 0, 20, 5,1048573),
624 sequence_symbol( 0, 2, 5, 1), sequence_symbol(16, 7, 4, 125),
625 sequence_symbol( 0, 11, 5, 2045), sequence_symbol( 0, 17, 5,131069),
626 sequence_symbol( 0, 22, 5,4194301), sequence_symbol( 0, 4, 5, 13),
627 sequence_symbol(16, 8, 4, 253), sequence_symbol( 0, 13, 5, 8189),
628 sequence_symbol( 0, 19, 5,524285), sequence_symbol( 0, 1, 5, 1),
629 sequence_symbol(16, 6, 4, 61), sequence_symbol( 0, 10, 5, 1021),
630 sequence_symbol( 0, 16, 5,65533), sequence_symbol( 0, 28, 5,268435453),
631 sequence_symbol( 0, 27, 5,134217725), sequence_symbol( 0, 26, 5,67108861),
632 sequence_symbol( 0, 25, 5,33554429), sequence_symbol( 0, 24, 5,16777213),
633 ]
634};
635
636#[rustfmt::skip]
638static ML_defaultDTable: SymbolTable<{ 1 << ML_DEFAULTNORMLOG }> = SymbolTable {
639 header: sequence_header(0x00010101, ML_DEFAULTNORMLOG),
641 symbols: [
643 sequence_symbol( 0, 0, 6, 3), sequence_symbol( 0, 0, 4, 4),
644 sequence_symbol(32, 0, 5, 5), sequence_symbol( 0, 0, 5, 6),
645 sequence_symbol( 0, 0, 5, 8), sequence_symbol( 0, 0, 5, 9),
646 sequence_symbol( 0, 0, 5, 11), sequence_symbol( 0, 0, 6, 13),
647 sequence_symbol( 0, 0, 6, 16), sequence_symbol( 0, 0, 6, 19),
648 sequence_symbol( 0, 0, 6, 22), sequence_symbol( 0, 0, 6, 25),
649 sequence_symbol( 0, 0, 6, 28), sequence_symbol( 0, 0, 6, 31),
650 sequence_symbol( 0, 0, 6, 34), sequence_symbol( 0, 1, 6, 37),
651 sequence_symbol( 0, 1, 6, 41), sequence_symbol( 0, 2, 6, 47),
652 sequence_symbol( 0, 3, 6, 59), sequence_symbol( 0, 4, 6, 83),
653 sequence_symbol( 0, 7, 6, 131), sequence_symbol( 0, 9, 6, 515),
654 sequence_symbol(16, 0, 4, 4), sequence_symbol( 0, 0, 4, 5),
655 sequence_symbol(32, 0, 5, 6), sequence_symbol( 0, 0, 5, 7),
656 sequence_symbol(32, 0, 5, 9), sequence_symbol( 0, 0, 5, 10),
657 sequence_symbol( 0, 0, 6, 12), sequence_symbol( 0, 0, 6, 15),
658 sequence_symbol( 0, 0, 6, 18), sequence_symbol( 0, 0, 6, 21),
659 sequence_symbol( 0, 0, 6, 24), sequence_symbol( 0, 0, 6, 27),
660 sequence_symbol( 0, 0, 6, 30), sequence_symbol( 0, 0, 6, 33),
661 sequence_symbol( 0, 1, 6, 35), sequence_symbol( 0, 1, 6, 39),
662 sequence_symbol( 0, 2, 6, 43), sequence_symbol( 0, 3, 6, 51),
663 sequence_symbol( 0, 4, 6, 67), sequence_symbol( 0, 5, 6, 99),
664 sequence_symbol( 0, 8, 6, 259), sequence_symbol(32, 0, 4, 4),
665 sequence_symbol(48, 0, 4, 4), sequence_symbol(16, 0, 4, 5),
666 sequence_symbol(32, 0, 5, 7), sequence_symbol(32, 0, 5, 8),
667 sequence_symbol(32, 0, 5, 10), sequence_symbol(32, 0, 5, 11),
668 sequence_symbol( 0, 0, 6, 14), sequence_symbol( 0, 0, 6, 17),
669 sequence_symbol( 0, 0, 6, 20), sequence_symbol( 0, 0, 6, 23),
670 sequence_symbol( 0, 0, 6, 26), sequence_symbol( 0, 0, 6, 29),
671 sequence_symbol( 0, 0, 6, 32), sequence_symbol( 0, 16, 6,65539),
672 sequence_symbol( 0, 15, 6,32771), sequence_symbol( 0, 14, 6,16387),
673 sequence_symbol( 0, 13, 6, 8195), sequence_symbol( 0, 12, 6, 4099),
674 sequence_symbol( 0, 11, 6, 2051), sequence_symbol( 0, 10, 6, 1027),
675 ]
676};
677
678fn ZSTD_buildSeqTable_rle<const N: usize>(dt: &mut SymbolTable<N>, baseValue: u32, nbAddBits: u8) {
679 dt.header = ZSTD_seqSymbol_header {
680 fastMode: 0,
681 tableLog: 0,
682 };
683
684 dt.symbols[0] = ZSTD_seqSymbol {
685 nbBits: 0,
686 nextState: 0,
687 nbAdditionalBits: nbAddBits,
688 baseValue,
689 };
690}
691
692#[inline(always)]
693fn ZSTD_buildFSETable_body<const N: usize>(
694 dt: &mut SymbolTable<N>,
695 normalizedCounter: &[i16],
696 baseValue: &'static [u32],
697 nbAdditionalBits: &'static [u8],
698 tableLog: core::ffi::c_uint,
699 wksp: &mut FseWorkspace,
700) {
701 let tableDecode = &mut dt.symbols;
702 let tableSize = 1usize << tableLog;
703 let mut highThreshold = tableSize.wrapping_sub(1);
704 let mut DTableH = ZSTD_seqSymbol_header {
705 fastMode: 1,
706 tableLog,
707 };
708
709 let largeLimit = ((1) << tableLog.wrapping_sub(1)) as i16;
710
711 for (s, &v) in normalizedCounter.iter().enumerate() {
712 if v == -1 {
713 tableDecode[highThreshold].baseValue = s as u32;
714 highThreshold = highThreshold.wrapping_sub(1);
715 wksp.symbols[s] = 1;
716 } else {
717 if v >= largeLimit {
718 DTableH.fastMode = 0;
719 }
720 wksp.symbols[s] = v as u16;
721 }
722 }
723
724 dt.header = DTableH;
725
726 if highThreshold == tableSize - 1 {
727 let tableMask = tableSize - 1;
728 let step = (tableSize >> 1) + (tableSize >> 3) + 3;
729 let add = 0x101010101010101u64;
730 let mut pos = 0usize;
731 let mut sv = 0u64;
732 for &v in normalizedCounter {
733 let n = v as usize;
734 wksp.spread[pos..][..8].copy_from_slice(&sv.to_le_bytes());
735 let mut i: usize = 8;
736 while i < n {
737 wksp.spread[pos..][i..][..8].copy_from_slice(&sv.to_le_bytes());
738 i += 8;
739 }
740 pos = pos.wrapping_add(n);
741 sv = sv.wrapping_add(add);
742 }
743
744 let mut position = 0usize;
745 for s in (0..tableSize).step_by(2) {
746 for u in 0..2 {
747 let uPosition = position.wrapping_add(u * step) & tableMask;
748 tableDecode[uPosition].baseValue = wksp.spread[s + u] as u32;
749 }
750 position = position.wrapping_add(2 * step) & tableMask;
751 }
752 } else {
753 let tableMask = tableSize - 1;
754 let step = (tableSize >> 1) + (tableSize >> 3) + 3;
755 let mut position = 0usize;
756 for (s, &v) in normalizedCounter.iter().enumerate() {
757 for _ in 0..i32::from(v) {
758 tableDecode[position].baseValue = s as u32;
759 position = position.wrapping_add(step) & tableMask;
760 while unlikely(position > highThreshold) {
761 position = position.wrapping_add(step) & tableMask;
762 }
763 }
764 }
765 }
766
767 for seq_symbol in tableDecode[..tableSize].iter_mut() {
768 let symbol = seq_symbol.baseValue as usize;
769 let nextState = wksp.symbols[symbol] as u32;
770 wksp.symbols[symbol] += 1;
771
772 let nbBits = tableLog.wrapping_sub(nextState.ilog2()) as u8;
773
774 *seq_symbol = ZSTD_seqSymbol {
775 nbBits,
776 nextState: (nextState << nbBits).wrapping_sub(tableSize as u32) as u16,
777 nbAdditionalBits: nbAdditionalBits[symbol],
778 baseValue: baseValue[symbol],
779 };
780 }
781}
782
783fn ZSTD_buildFSETable_body_default<const N: usize>(
784 dt: &mut SymbolTable<N>,
785 normalizedCounter: &[i16],
786 baseValue: &'static [u32],
787 nbAdditionalBits: &'static [u8],
788 tableLog: core::ffi::c_uint,
789 wksp: &mut FseWorkspace,
790) {
791 ZSTD_buildFSETable_body(
792 dt,
793 normalizedCounter,
794 baseValue,
795 nbAdditionalBits,
796 tableLog,
797 wksp,
798 );
799}
800
801fn ZSTD_buildFSETable_body_bmi2<const N: usize>(
802 dt: &mut SymbolTable<N>,
803 normalizedCounter: &[i16],
804 baseValue: &'static [u32],
805 nbAdditionalBits: &'static [u8],
806 tableLog: core::ffi::c_uint,
807 wksp: &mut FseWorkspace,
808) {
809 ZSTD_buildFSETable_body(
810 dt,
811 normalizedCounter,
812 baseValue,
813 nbAdditionalBits,
814 tableLog,
815 wksp,
816 );
817}
818
819#[derive(Copy, Clone)]
820#[repr(C, align(4))]
821pub struct FseWorkspace {
822 symbols: [u16; MaxSeq + 1],
823 spread: [u8; (1 << MaxFSELog) + size_of::<u64>()],
824}
825
826pub fn ZSTD_buildFSETable<const N: usize>(
827 dt: &mut SymbolTable<N>,
828 normalizedCounter: &[i16],
829 baseValue: &'static [u32],
830 nbAdditionalBits: &'static [u8],
831 tableLog: core::ffi::c_uint,
832 wksp: &mut FseWorkspace,
833 bmi2: bool,
834) {
835 if bmi2 {
836 ZSTD_buildFSETable_body_bmi2(
837 dt,
838 normalizedCounter,
839 baseValue,
840 nbAdditionalBits,
841 tableLog,
842 wksp,
843 );
844 } else {
845 ZSTD_buildFSETable_body_default(
846 dt,
847 normalizedCounter,
848 baseValue,
849 nbAdditionalBits,
850 tableLog,
851 wksp,
852 );
853 }
854}
855
856fn ZSTD_buildSeqTableNew<const N: usize>(
857 DTableSpace: &mut SymbolTable<N>,
858 DTablePtr: &mut Option<NonNull<SymbolTable<N>>>,
859 type_0: SymbolEncodingType_e,
860 mut max: core::ffi::c_uint,
861 maxLog: u32,
862 src: &[u8],
863 baseValue: &'static [u32],
864 nbAdditionalBits: &'static [u8],
865 flagRepeatTable: bool,
866 ddictIsCold: bool,
867 nbSeq: core::ffi::c_int,
868 wksp: &mut Workspace,
869 bmi2: bool,
870) -> Result<size_t, Error> {
871 match type_0 {
872 SymbolEncodingType_e::set_rle => {
873 let [symbol, ..] = *src else {
874 return Err(Error::srcSize_wrong);
875 };
876
877 if u32::from(symbol) > max {
878 return Err(Error::corruption_detected);
879 }
880
881 let baseline = baseValue[usize::from(symbol)];
882 let nbBits = nbAdditionalBits[usize::from(symbol)];
883 ZSTD_buildSeqTable_rle(DTableSpace, baseline, nbBits);
884
885 *DTablePtr = NonNull::new(DTableSpace);
886 Ok(1)
887 }
888 SymbolEncodingType_e::set_basic => {
889 *DTablePtr = None;
890 Ok(0)
891 }
892 SymbolEncodingType_e::set_repeat => {
893 if !flagRepeatTable {
894 return Err(Error::corruption_detected);
895 }
896 if ddictIsCold && nbSeq > 24 {
897 let pSize = size_of::<ZSTD_seqSymbol>().wrapping_mul(1 + (1usize << maxLog));
898 if let Some(ptr) = *DTablePtr {
899 prefetch_area(ptr.as_ptr(), pSize);
900 }
901 }
902 Ok(0)
903 }
904 SymbolEncodingType_e::set_compressed => {
905 let mut tableLog: core::ffi::c_uint = 0;
906 let mut norm: [i16; 53] = [0; 53];
907 let Ok(headerSize) = FSE_readNCount_slice(&mut norm, &mut max, &mut tableLog, src)
908 else {
909 return Err(Error::corruption_detected);
910 };
911 if tableLog > maxLog {
912 return Err(Error::corruption_detected);
913 }
914 ZSTD_buildFSETable(
915 DTableSpace,
916 &norm[..=max as usize],
917 baseValue,
918 nbAdditionalBits,
919 tableLog,
920 wksp.as_fse_workspace(),
921 bmi2,
922 );
923 *DTablePtr = NonNull::new(DTableSpace);
924 Ok(headerSize)
925 }
926 }
927}
928
929fn ZSTD_decodeSeqHeaders(
930 dctx: &mut ZSTD_DCtx,
931 nbSeqPtr: &mut core::ffi::c_int,
932 src: &[u8],
933) -> Result<size_t, Error> {
934 let mut ip = 0;
935 let [nbSeq, ..] = *src else {
936 return Err(Error::srcSize_wrong);
937 };
938 let mut nbSeq = i32::from(nbSeq);
939 ip += 1;
940 if nbSeq > 0x7f {
941 if nbSeq == 0xff {
942 let [_, a, b, ..] = *src else {
943 return Err(Error::srcSize_wrong);
944 };
945 nbSeq = i32::from(u16::from_le_bytes([a, b])) + LONGNBSEQ;
946 ip += 2;
947 } else {
948 if ip >= src.len() {
949 return Err(Error::srcSize_wrong);
950 }
951 nbSeq = ((nbSeq - 0x80) << 8) + i32::from(src[ip]);
952 ip += 1;
953 }
954 }
955 *nbSeqPtr = nbSeq;
956 if nbSeq == 0 {
957 if ip != src.len() {
958 return Err(Error::corruption_detected);
959 }
960 return Ok(ip);
961 }
962
963 if ip + 1 > src.len() {
967 return Err(Error::srcSize_wrong);
968 }
969
970 if src[ip] & 0b11 != 0 {
972 return Err(Error::corruption_detected);
973 }
974
975 let byte = src[ip];
976 let LLtype = SymbolEncodingType_e::try_from(byte >> 6).unwrap();
977 let OFtype = SymbolEncodingType_e::try_from(byte >> 4 & 0b11).unwrap();
978 let MLtype = SymbolEncodingType_e::try_from(byte >> 2 & 0b11).unwrap();
979
980 ip += 1;
983 let llhSize = ZSTD_buildSeqTableNew(
984 &mut dctx.entropy.LLTable,
985 &mut dctx.LLTptr,
986 LLtype,
987 MaxLL,
988 LLFSELog,
989 &src[ip..],
990 &LL_base,
991 &LL_bits,
992 dctx.fseEntropy,
993 dctx.ddictIsCold,
994 nbSeq,
995 &mut dctx.workspace,
996 dctx.bmi2,
997 )
998 .map_err(|_| Error::corruption_detected)?;
999
1000 ip += llhSize;
1001 let ofhSize = ZSTD_buildSeqTableNew(
1002 &mut dctx.entropy.OFTable,
1003 &mut dctx.OFTptr,
1004 OFtype,
1005 MaxOff,
1006 OffFSELog,
1007 &src[ip..],
1008 &OF_base,
1009 &OF_bits,
1010 dctx.fseEntropy,
1011 dctx.ddictIsCold,
1012 nbSeq,
1013 &mut dctx.workspace,
1014 dctx.bmi2,
1015 )
1016 .map_err(|_| Error::corruption_detected)?;
1017
1018 ip += ofhSize;
1019 let mlhSize = ZSTD_buildSeqTableNew(
1020 &mut dctx.entropy.MLTable,
1021 &mut dctx.MLTptr,
1022 MLtype,
1023 MaxML,
1024 MLFSELog,
1025 &src[ip..],
1026 &ML_base,
1027 &ML_bits,
1028 dctx.fseEntropy,
1029 dctx.ddictIsCold,
1030 nbSeq,
1031 &mut dctx.workspace,
1032 dctx.bmi2,
1033 )
1034 .map_err(|_| Error::corruption_detected)?;
1035
1036 ip += mlhSize;
1037
1038 Ok(ip)
1039}
1040
1041#[inline(always)]
1047unsafe fn ZSTD_overlapCopy8(op: &mut *mut u8, ip: &mut *const u8, offset: size_t) {
1048 if offset < 8 {
1049 *(*op).add(0) = *(*ip).add(0);
1051 *(*op).add(1) = *(*ip).add(1);
1052 *(*op).add(2) = *(*ip).add(2);
1053 *(*op).add(3) = *(*ip).add(3);
1054
1055 static dec32table: [u8; 8] = [0, 1, 2, 1, 4, 4, 4, 4]; *ip = (*ip).add(usize::from(dec32table[offset]));
1057 core::ptr::copy(*ip, (*op).add(4), 4);
1058
1059 static dec64table: [u8; 8] = [8, 8, 8, 7, 8, 9, 10, 11]; *ip = (*ip).sub(usize::from(dec64table[offset]));
1061 } else {
1062 core::ptr::copy(*ip, *op, 8);
1063 }
1064
1065 *ip = (*ip).add(8);
1066 *op = (*op).add(8);
1067
1068 debug_assert!(unsafe { (*op).offset_from(*ip) } >= 8);
1069}
1070
1071unsafe fn ZSTD_safecopy(
1081 mut op: *mut u8,
1082 oend_w: *const u8,
1083 mut ip: *const u8,
1084 mut length: size_t,
1085 ovtype: Overlap,
1086) {
1087 let diff = op as isize - ip as isize;
1088 let oend = op.add(length);
1089
1090 debug_assert!(match ovtype {
1091 Overlap::NoOverlap => diff <= -8 || diff >= 8 || op >= oend_w.cast_mut(),
1092 Overlap::OverlapSrcBeforeDst => diff >= 0,
1093 });
1094
1095 if length < 8 {
1096 while op < oend {
1098 *op = *ip;
1099 ip = ip.add(1);
1100 op = op.add(1);
1101 }
1102 return;
1103 }
1104 if ovtype == Overlap::OverlapSrcBeforeDst {
1105 debug_assert!(length >= 8);
1107 debug_assert!(diff > 0);
1108 ZSTD_overlapCopy8(&mut op, &mut ip, diff as size_t);
1109 length = length.wrapping_sub(8);
1110 debug_assert!(op.offset_from(ip) >= 8);
1111 debug_assert!(op <= oend);
1112 }
1113 if oend <= oend_w as *mut u8 {
1114 ZSTD_wildcopy(op, ip, length, ovtype);
1116 return;
1117 }
1118 if op <= oend_w as *mut u8 {
1119 ZSTD_wildcopy(op, ip, oend_w.offset_from_unsigned(op), ovtype);
1121 ip = ip.offset(oend_w.offset_from(op));
1122 op = op.offset(oend_w.offset_from(op));
1123 }
1124
1125 while op < oend {
1127 *op = *ip;
1128 ip = ip.add(1);
1129 op = op.add(1);
1130 }
1131}
1132
1133unsafe fn ZSTD_safecopyDstBeforeSrc(mut op: *mut u8, mut ip: *const u8, length: size_t) {
1136 let diff = op.offset_from(ip) as ptrdiff_t;
1137 let oend = op.add(length);
1138 if length < 8 || diff > -8 {
1139 while op < oend {
1141 *op = *ip;
1142 ip = ip.add(1);
1143 op = op.add(1);
1144 }
1145 return;
1146 }
1147 if op <= oend.sub(WILDCOPY_OVERLENGTH) && diff < -WILDCOPY_VECLEN as ptrdiff_t {
1148 ZSTD_wildcopy(
1149 op,
1150 ip,
1151 oend.sub(WILDCOPY_OVERLENGTH).offset_from_unsigned(op),
1152 Overlap::NoOverlap,
1153 );
1154 ip = ip.offset(oend.sub(WILDCOPY_OVERLENGTH).offset_from(op));
1155 op = op.offset(oend.sub(WILDCOPY_OVERLENGTH).offset_from(op));
1156 }
1157
1158 while op < oend {
1160 *op = *ip;
1161 ip = ip.add(1);
1162 op = op.add(1);
1163 }
1164}
1165
1166#[inline(never)]
1173unsafe fn ZSTD_execSequenceEnd(
1174 mut op: *mut u8,
1175 oend: *mut u8,
1176 mut sequence: seq_t,
1177 litPtr: &mut *const u8,
1178 litLimit: *const u8,
1179 prefixStart: *const u8,
1180 virtualStart: *const u8,
1181 dictEnd: *const u8,
1182) -> Result<size_t, Error> {
1183 let oLitEnd = op.add(sequence.litLength);
1184 let sequenceLength = (sequence.litLength).wrapping_add(sequence.matchLength);
1185 let iLitEnd = (*litPtr).add(sequence.litLength);
1186 let mut match_0: *const u8 = oLitEnd.wrapping_sub(sequence.offset);
1187 let oend_w = oend.wrapping_sub(WILDCOPY_OVERLENGTH);
1188
1189 if sequenceLength > oend.offset_from_unsigned(op) {
1191 return Err(Error::dstSize_tooSmall);
1192 }
1193 if sequence.litLength > litLimit.offset_from_unsigned(*litPtr) {
1194 return Err(Error::corruption_detected);
1195 }
1196
1197 debug_assert!(op < op.wrapping_add(sequenceLength));
1198 debug_assert!(oLitEnd < op.wrapping_add(sequenceLength));
1199
1200 ZSTD_safecopy(op, oend_w, *litPtr, sequence.litLength, Overlap::NoOverlap);
1202 op = oLitEnd;
1203 *litPtr = iLitEnd;
1204
1205 if sequence.offset > oLitEnd.offset_from_unsigned(prefixStart) {
1207 if sequence.offset > (oLitEnd.addr() - virtualStart.addr()) {
1209 return Err(Error::corruption_detected);
1210 }
1211 match_0 = dictEnd.sub(prefixStart.addr() - match_0.addr());
1212 if match_0.add(sequence.matchLength) <= dictEnd {
1213 core::ptr::copy(match_0, oLitEnd, sequence.matchLength);
1214 return Ok(sequenceLength);
1215 }
1216 let length1 = dictEnd.addr() - match_0.addr();
1218 core::ptr::copy(match_0, oLitEnd, length1);
1219 op = oLitEnd.add(length1);
1220 sequence.matchLength = (sequence.matchLength).wrapping_sub(length1);
1221 match_0 = prefixStart;
1222 }
1223 ZSTD_safecopy(
1224 op,
1225 oend_w,
1226 match_0,
1227 sequence.matchLength,
1228 Overlap::OverlapSrcBeforeDst,
1229 );
1230 Ok(sequenceLength)
1231}
1232
1233#[inline(never)]
1236unsafe fn ZSTD_execSequenceEndSplitLitBuffer(
1237 mut op: Writer<'_>,
1238 oend: *mut u8,
1239 oend_w: *const u8,
1240 mut sequence: seq_t,
1241 litPtr: &mut *const u8,
1242 litLimit: *const u8,
1243 prefixStart: *const u8,
1244 virtualStart: *const u8,
1245 dictEnd: *const u8,
1246) -> Result<size_t, Error> {
1247 let oLitEnd = op.as_mut_ptr().add(sequence.litLength);
1248 let sequenceLength = (sequence.litLength).wrapping_add(sequence.matchLength);
1249 let iLitEnd = (*litPtr).add(sequence.litLength);
1250 let mut match_0: *const u8 = oLitEnd.sub(sequence.offset);
1251
1252 if sequenceLength > oend.offset_from_unsigned(op.as_mut_ptr()) {
1254 return Err(Error::dstSize_tooSmall);
1255 }
1256 if sequence.litLength > litLimit.offset_from_unsigned(*litPtr) {
1257 return Err(Error::corruption_detected);
1258 }
1259
1260 debug_assert!(op.as_mut_ptr() < op.as_mut_ptr().wrapping_add(sequenceLength));
1261 debug_assert!(oLitEnd < op.as_mut_ptr().wrapping_add(sequenceLength));
1262
1263 if op.as_mut_ptr() > *litPtr as *mut u8
1265 && op.as_mut_ptr() < (*litPtr).add(sequence.litLength) as *mut u8
1266 {
1267 return Err(Error::dstSize_tooSmall);
1268 }
1269 ZSTD_safecopyDstBeforeSrc(op.as_mut_ptr(), *litPtr, sequence.litLength);
1270 op = op.subslice(sequence.litLength..);
1271 *litPtr = iLitEnd;
1272
1273 if sequence.offset > oLitEnd.offset_from_unsigned(prefixStart) {
1275 if sequence.offset > oLitEnd.offset_from_unsigned(virtualStart) {
1277 return Err(Error::corruption_detected);
1278 }
1279 match_0 = dictEnd.offset(-(prefixStart.offset_from(match_0) as core::ffi::c_long as isize));
1280 if match_0.add(sequence.matchLength) <= dictEnd {
1281 core::ptr::copy(match_0, oLitEnd, sequence.matchLength);
1282 return Ok(sequenceLength);
1283 }
1284
1285 let length1 = dictEnd.offset_from_unsigned(match_0);
1287 core::ptr::copy(match_0, oLitEnd, length1);
1288 op = op.subslice(length1..);
1289 sequence.matchLength = (sequence.matchLength).wrapping_sub(length1);
1290 match_0 = prefixStart;
1291 }
1292
1293 ZSTD_safecopy(
1294 op.as_mut_ptr(),
1295 oend_w,
1296 match_0,
1297 sequence.matchLength,
1298 Overlap::OverlapSrcBeforeDst,
1299 );
1300 Ok(sequenceLength)
1301}
1302
1303#[inline(always)]
1304unsafe fn ZSTD_execSequence(
1305 mut op: Writer<'_>,
1306 oend: *mut u8,
1307 mut sequence: seq_t,
1308 litPtr: &mut *const u8,
1309 litLimit: *const u8,
1310 prefixStart: *const u8,
1311 virtualStart: *const u8,
1312 dictEnd: *const u8,
1313) -> Result<size_t, Error> {
1314 let mut op = op.as_mut_ptr();
1315 let oLitEnd = op.add(sequence.litLength);
1316 let sequenceLength = (sequence.litLength).wrapping_add(sequence.matchLength);
1317 let oMatchEnd = op.add(sequenceLength);
1318 let oend_w = oend.wrapping_sub(WILDCOPY_OVERLENGTH);
1319 let iLitEnd = (*litPtr).add(sequence.litLength);
1320 let mut match_0: *const u8 = oLitEnd.wrapping_sub(sequence.offset);
1321
1322 debug_assert!(!op.is_null(), "Precondition");
1323 debug_assert!(oend_w < oend, "No underflow");
1324
1325 if cfg!(target_arch = "aarch64") {
1326 prefetch_read_data(match_0, Locality::L1);
1328 }
1329
1330 if unlikely(
1335 iLitEnd > litLimit
1336 || oMatchEnd > oend_w
1337 || MEM_32bits() && (oend.offset_from_unsigned(op)) < sequenceLength.wrapping_add(32),
1338 ) {
1339 return ZSTD_execSequenceEnd(
1340 op,
1341 oend,
1342 sequence,
1343 litPtr,
1344 litLimit,
1345 prefixStart,
1346 virtualStart,
1347 dictEnd,
1348 );
1349 }
1350
1351 debug_assert!(op <= oLitEnd, "No overflow");
1353 debug_assert!(oLitEnd < oMatchEnd, "Non-zero match & no overflow");
1354 debug_assert!(oMatchEnd <= oend, "No underflow");
1355 debug_assert!(iLitEnd <= litLimit, "Literal length is in bounds");
1356 debug_assert!(oLitEnd <= oend_w, "Can wildcopy literals");
1357 debug_assert!(oMatchEnd <= oend_w, "Can wildcopy matches");
1358
1359 const _: () = assert!(WILDCOPY_OVERLENGTH >= 16);
1363 ZSTD_copy16(op, *litPtr);
1364 if unlikely(sequence.litLength > 16) {
1365 ZSTD_wildcopy(
1366 op.add(16),
1367 (*litPtr).add(16),
1368 sequence.litLength.wrapping_sub(16),
1369 Overlap::NoOverlap,
1370 );
1371 }
1372 op = oLitEnd;
1373 *litPtr = iLitEnd; if unlikely(sequence.offset > oLitEnd.offset_from_unsigned(prefixStart)) {
1377 if unlikely(sequence.offset > (oLitEnd.addr() - virtualStart.addr())) {
1379 return Err(Error::corruption_detected);
1380 }
1381 match_0 = dictEnd.offset(match_0.addr() as isize - prefixStart.addr() as isize);
1382 if match_0.add(sequence.matchLength) <= dictEnd {
1383 core::ptr::copy(match_0, oLitEnd, sequence.matchLength);
1384 return Ok(sequenceLength);
1385 }
1386
1387 let length1 = dictEnd.offset_from_unsigned(match_0);
1389 core::ptr::copy(match_0, oLitEnd, length1);
1390 op = oLitEnd.add(length1);
1391 sequence.matchLength = (sequence.matchLength).wrapping_sub(length1);
1392 match_0 = prefixStart;
1393 }
1394
1395 debug_assert!(op <= oMatchEnd);
1397 debug_assert!(oMatchEnd <= oend_w);
1398 debug_assert!(match_0 >= prefixStart);
1399 debug_assert!(sequence.matchLength >= 1);
1400
1401 if likely(sequence.offset >= 16) {
1404 ZSTD_wildcopy(op, match_0, sequence.matchLength, Overlap::NoOverlap);
1408 return Ok(sequenceLength);
1409 }
1410 debug_assert!(sequence.offset < WILDCOPY_VECLEN as usize);
1411
1412 ZSTD_overlapCopy8(&mut op, &mut match_0, sequence.offset);
1414
1415 if sequence.matchLength > 8 {
1417 ZSTD_wildcopy(
1418 op,
1419 match_0,
1420 (sequence.matchLength).wrapping_sub(8),
1421 Overlap::OverlapSrcBeforeDst,
1422 );
1423 }
1424 Ok(sequenceLength)
1425}
1426
1427#[inline(always)]
1428unsafe fn ZSTD_execSequenceSplitLitBuffer(
1429 mut op: Writer<'_>,
1430 oend: *mut u8,
1431 oend_w: *const u8,
1432 mut sequence: seq_t,
1433 litPtr: &mut *const u8,
1434 litLimit: *const u8,
1435 prefixStart: *const u8,
1436 virtualStart: *const u8,
1437 dictEnd: *const u8,
1438) -> Result<size_t, Error> {
1439 let oLitEnd = op.as_mut_ptr().add(sequence.litLength);
1440 let sequenceLength = (sequence.litLength).wrapping_add(sequence.matchLength);
1441 let oMatchEnd = op.as_mut_ptr().add(sequenceLength);
1442 let iLitEnd = (*litPtr).add(sequence.litLength);
1443 let mut match_0: *const u8 = oLitEnd.sub(sequence.offset);
1444
1445 debug_assert!(!op.is_null(), "precondition");
1446 debug_assert!(oend_w < oend, "No underflow");
1447
1448 if unlikely(
1453 iLitEnd > litLimit
1454 || oMatchEnd > oend_w as *mut u8
1455 || MEM_32bits()
1456 && (oend.offset_from_unsigned(op.as_mut_ptr())) < sequenceLength.wrapping_add(32),
1457 ) {
1458 return ZSTD_execSequenceEndSplitLitBuffer(
1459 op,
1460 oend,
1461 oend_w,
1462 sequence,
1463 litPtr,
1464 litLimit,
1465 prefixStart,
1466 virtualStart,
1467 dictEnd,
1468 );
1469 }
1470
1471 debug_assert!(op.as_mut_ptr() <= oLitEnd, "No overflow");
1473 debug_assert!(oLitEnd < oMatchEnd, "Non-zero match & no overflow");
1474 debug_assert!(oMatchEnd <= oend, "No underflow");
1475 debug_assert!(iLitEnd <= litLimit, "Literal length is in bounds");
1476 debug_assert!(oLitEnd <= oend_w.cast_mut(), "Can wildcopy literals");
1477 debug_assert!(oMatchEnd <= oend_w.cast_mut(), "Can wildcopy matches");
1478
1479 const _: () = assert!(WILDCOPY_OVERLENGTH >= 16);
1483 ZSTD_copy16(op.as_mut_ptr(), *litPtr);
1484 if unlikely(sequence.litLength > 16) {
1485 ZSTD_wildcopy(
1486 op.as_mut_ptr().add(16),
1487 (*litPtr).add(16),
1488 (sequence.litLength).wrapping_sub(16),
1489 Overlap::NoOverlap,
1490 );
1491 }
1492 op = op.subslice(sequence.litLength..);
1493 *litPtr = iLitEnd; if unlikely(sequence.offset > oLitEnd.offset_from_unsigned(prefixStart)) {
1497 if sequence.offset > oLitEnd.offset_from_unsigned(virtualStart) {
1498 return Err(Error::corruption_detected);
1499 }
1500 match_0 = dictEnd.offset(match_0.offset_from(prefixStart) as core::ffi::c_long as isize);
1501 if match_0.add(sequence.matchLength) <= dictEnd {
1502 core::ptr::copy(match_0, oLitEnd, sequence.matchLength);
1503 return Ok(sequenceLength);
1504 }
1505
1506 let length1 = dictEnd.offset_from_unsigned(match_0);
1508 core::ptr::copy(match_0, oLitEnd, length1);
1509 op = op.subslice(length1..);
1510 sequence.matchLength = (sequence.matchLength).wrapping_sub(length1);
1511 match_0 = prefixStart;
1512 }
1513
1514 debug_assert!(op.as_mut_ptr() <= oMatchEnd);
1516 debug_assert!(oMatchEnd <= oend_w.cast_mut());
1517 debug_assert!(match_0 >= prefixStart);
1518 debug_assert!(sequence.matchLength >= 1);
1519
1520 if likely(sequence.offset >= WILDCOPY_VECLEN as usize) {
1521 ZSTD_wildcopy(
1525 op.as_mut_ptr(),
1526 match_0,
1527 sequence.matchLength,
1528 Overlap::NoOverlap,
1529 );
1530 return Ok(sequenceLength);
1531 }
1532 debug_assert!(sequence.offset < WILDCOPY_VECLEN as usize);
1533
1534 ZSTD_overlapCopy8(&mut op.as_mut_ptr(), &mut match_0, sequence.offset);
1536 op = op.subslice(8..);
1537
1538 if sequence.matchLength > 8 {
1540 ZSTD_wildcopy(
1541 op.as_mut_ptr(),
1542 match_0,
1543 sequence.matchLength.wrapping_sub(8),
1544 Overlap::OverlapSrcBeforeDst,
1545 );
1546 }
1547 Ok(sequenceLength)
1548}
1549
1550impl ZSTD_fseState<'_> {
1551 #[inline(always)]
1552 fn update_with_d_info(&mut self, bitD: &mut BIT_DStream_t, nextState: u16, nbBits: u32) {
1553 let lowBits = bitD.read_bits(nbBits);
1554 self.state = usize::from(nextState) + lowBits;
1555 }
1556}
1557
1558const LONG_OFFSETS_MAX_EXTRA_BITS_32: i32 =
1563 ZSTD_WINDOWLOG_MAX_32.saturating_sub(STREAM_ACCUMULATOR_MIN_32);
1564
1565#[inline(always)]
1566fn ZSTD_decodeSequence(
1567 seqState: &mut seqState_t,
1568 longOffsets: Offset,
1569 is_last_sequence: bool,
1570) -> seq_t {
1571 let mut seq = seq_t {
1572 litLength: 0,
1573 matchLength: 0,
1574 offset: 0,
1575 };
1576 cfg_select! {
1577 feature = "unsafe-performance-experimental" => {
1578 let llDInfo = unsafe { seqState.stateLL.table.get_unchecked(seqState.stateLL.state) };
1579 let mlDInfo = unsafe { seqState.stateML.table.get_unchecked(seqState.stateML.state) };
1580 let ofDInfo = unsafe {
1581 seqState
1582 .stateOffb
1583 .table
1584 .get_unchecked(seqState.stateOffb.state)
1585 };
1586 }
1587 _ => {
1588 let llDInfo = seqState.stateLL.table[seqState.stateLL.state];
1589 let mlDInfo = seqState.stateML.table[seqState.stateML.state];
1590 let ofDInfo = seqState.stateOffb.table[seqState.stateOffb.state];
1591 }
1592 }
1593
1594 seq.matchLength = mlDInfo.baseValue as size_t;
1595 seq.litLength = llDInfo.baseValue as size_t;
1596 let ofBase = ofDInfo.baseValue;
1597
1598 let llBits = llDInfo.nbAdditionalBits;
1599 let mlBits = mlDInfo.nbAdditionalBits;
1600 let ofBits = ofDInfo.nbAdditionalBits;
1601
1602 let totalBits = llBits + mlBits + ofBits;
1603
1604 let llNext = llDInfo.nextState;
1605 let mlNext = mlDInfo.nextState;
1606 let ofNext = ofDInfo.nextState;
1607
1608 let llnbBits = llDInfo.nbBits as u32;
1609 let mlnbBits = mlDInfo.nbBits as u32;
1610 let ofnbBits = ofDInfo.nbBits as u32;
1611
1612 debug_assert!(llBits <= MaxLLBits);
1613 debug_assert!(mlBits <= MaxMLBits);
1614
1615 assert!(ofBits as u32 <= MaxOff);
1618
1619 let mut offset: size_t = 0;
1620 if ofBits > 1 {
1621 const { assert!(Offset::Long as usize == 1) };
1622 const { assert!(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5) };
1623 const { assert!(STREAM_ACCUMULATOR_MIN_32 > LONG_OFFSETS_MAX_EXTRA_BITS_32) };
1624 const { assert!(STREAM_ACCUMULATOR_MIN_32 - LONG_OFFSETS_MAX_EXTRA_BITS_32 >= MaxMLBits as i32) };
1625
1626 if MEM_32bits()
1627 && longOffsets != Offset::Regular
1628 && i32::from(ofBits) >= STREAM_ACCUMULATOR_MIN_32
1629 {
1630 let extraBits = LONG_OFFSETS_MAX_EXTRA_BITS_32 as u32;
1633 offset = (ofBase as size_t).wrapping_add(
1634 (seqState
1635 .DStream
1636 .read_bits_fast(u32::from(ofBits) - extraBits) as size_t)
1637 << extraBits,
1638 );
1639 seqState.DStream.reload();
1640 offset = offset.wrapping_add(seqState.DStream.read_bits_fast(extraBits) as size_t);
1641 } else {
1642 offset = (ofBase as size_t)
1643 .wrapping_add(seqState.DStream.read_bits_fast(u32::from(ofBits)) as size_t);
1644 if MEM_32bits() {
1645 seqState.DStream.reload();
1646 }
1647 }
1648
1649 seqState.prevOffset[2] = seqState.prevOffset[1];
1650 seqState.prevOffset[1] = seqState.prevOffset[0];
1651 seqState.prevOffset[0] = offset;
1652 } else {
1653 let ll0 = usize::from(llDInfo.baseValue == 0);
1654 if likely(ofBits == 0) {
1655 offset = seqState.prevOffset[ll0];
1656 seqState.prevOffset[1] = seqState.prevOffset[usize::from(ll0 == 0)];
1657 seqState.prevOffset[0] = offset;
1658 } else {
1659 offset = (ofBase.wrapping_add(ll0 as u32) as size_t)
1660 .wrapping_add(seqState.DStream.read_bits_fast(1) as size_t);
1661
1662 let mut temp = match offset {
1663 3 => seqState.prevOffset[0] - 1,
1664 _ => seqState.prevOffset[offset as usize],
1665 };
1666 temp = temp.wrapping_sub((temp == 0) as _); if offset != 1 {
1669 seqState.prevOffset[2] = seqState.prevOffset[1];
1670 }
1671 seqState.prevOffset[1] = seqState.prevOffset[0];
1672 seqState.prevOffset[0] = temp;
1673 offset = temp;
1674 }
1675 }
1676 seq.offset = offset;
1677
1678 if mlBits > 0 {
1679 seq.matchLength = seq
1680 .matchLength
1681 .wrapping_add(seqState.DStream.read_bits_fast(mlBits as core::ffi::c_uint) as size_t);
1682 }
1683
1684 if cfg!(target_pointer_width = "32")
1685 && (i32::from(mlBits + llBits)
1686 >= STREAM_ACCUMULATOR_MIN_32 - LONG_OFFSETS_MAX_EXTRA_BITS_32)
1687 {
1688 seqState.DStream.reload();
1689 }
1690 if cfg!(target_pointer_width = "64") && unlikely(totalBits >= 57 - (9 + 9 + 8)) {
1691 seqState.DStream.reload();
1692 }
1693
1694 const { assert!(16 + LLFSELog + MLFSELog + OffFSELog < STREAM_ACCUMULATOR_MIN_64 as u32) };
1696
1697 if llBits > 0 {
1698 seq.litLength = (seq.litLength)
1699 .wrapping_add(seqState.DStream.read_bits_fast(llBits as core::ffi::c_uint) as size_t);
1700 }
1701 if MEM_32bits() {
1702 seqState.DStream.reload();
1703 }
1704
1705 if !is_last_sequence {
1707 seqState
1708 .stateLL
1709 .update_with_d_info(&mut seqState.DStream, llNext, llnbBits);
1710 seqState
1711 .stateML
1712 .update_with_d_info(&mut seqState.DStream, mlNext, mlnbBits);
1713 if MEM_32bits() {
1714 seqState.DStream.reload();
1715 }
1716 seqState
1717 .stateOffb
1718 .update_with_d_info(&mut seqState.DStream, ofNext, ofnbBits);
1719 seqState.DStream.reload();
1720 }
1721
1722 seq
1723}
1724
1725#[inline(always)]
1726fn ZSTD_decompressSequences_bodySplitLitBuffer(
1727 dctx: &mut ZSTD_DCtx,
1728 dst: Writer<'_>,
1729 seq: &[u8],
1730 mut nbSeq: core::ffi::c_int,
1731 offset: Offset,
1732) -> Result<size_t, Error> {
1733 let maxDstSize = dst.capacity();
1734 let mut op = dst;
1735 let mut litPtr = dctx.litPtr;
1736 let mut litBufferEnd = dctx.litBufferEnd;
1737 let prefixStart = dctx.prefixStart as *const u8;
1738 let vBase = dctx.virtualStart as *const u8;
1739 let dictEnd = dctx.dictEnd as *const u8;
1740 if nbSeq != 0 {
1741 let DStream = BIT_DStream_t::new(seq).map_err(|_| Error::corruption_detected)?;
1742 dctx.fseEntropy = true;
1743 let mut seqState = dctx.new_seq_state(DStream);
1744
1745 let mut sequence = seq_t::default();
1746
1747 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1748 if !cfg!(miri) {
1749 unsafe { asm!(".p2align 6", options(preserves_flags, att_syntax)) }
1750 }
1751
1752 while nbSeq != 0 {
1753 sequence = ZSTD_decodeSequence(&mut seqState, offset, nbSeq == 1);
1754
1755 if litPtr.wrapping_add(sequence.litLength) > dctx.litBufferEnd {
1756 break;
1757 }
1758
1759 let oneSeqSize = unsafe {
1760 ZSTD_execSequenceSplitLitBuffer(
1761 op.subslice(..),
1762 op.as_mut_ptr_range().end,
1763 litPtr.add(sequence.litLength).sub(WILDCOPY_OVERLENGTH),
1764 sequence,
1765 &mut litPtr,
1766 litBufferEnd,
1767 prefixStart,
1768 vBase,
1769 dictEnd,
1770 )?
1771 };
1772
1773 op = op.subslice(oneSeqSize..);
1774 nbSeq -= 1;
1775 }
1776
1777 if nbSeq > 0 {
1778 let leftoverLit = unsafe { dctx.litBufferEnd.offset_from_unsigned(litPtr) };
1779 if leftoverLit != 0 {
1780 if leftoverLit > op.capacity() {
1781 return Err(Error::dstSize_tooSmall);
1782 }
1783 unsafe { ZSTD_safecopyDstBeforeSrc(op.as_mut_ptr(), litPtr, leftoverLit) };
1784 sequence.litLength = sequence.litLength.wrapping_sub(leftoverLit);
1785 op = op.subslice(leftoverLit..);
1786 }
1787 litPtr = dctx.litExtraBuffer.as_mut_ptr();
1788 litBufferEnd = dctx.litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE..].as_mut_ptr();
1789 dctx.litBufferLocation = LitLocation::ZSTD_not_in_dst;
1790 let oneSeqSize_0 = unsafe {
1791 ZSTD_execSequence(
1792 op.subslice(..),
1793 op.as_mut_ptr_range().end,
1794 sequence,
1795 &mut litPtr,
1796 litBufferEnd,
1797 prefixStart,
1798 vBase,
1799 dictEnd,
1800 )?
1801 };
1802 op = op.subslice(oneSeqSize_0..);
1803 nbSeq -= 1;
1804 }
1805 if nbSeq > 0 {
1806 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1807 if !cfg!(miri) {
1808 unsafe {
1809 asm!(
1810 ".p2align 6",
1811 "nop",
1812 ".p2align 4",
1813 "nop",
1814 ".p2align 3",
1815 options(preserves_flags)
1816 )
1817 }
1818 }
1819
1820 while nbSeq != 0 {
1821 let sequence_0 = ZSTD_decodeSequence(&mut seqState, offset, nbSeq == 1);
1822 let oneSeqSize_1 = unsafe {
1823 ZSTD_execSequence(
1824 op.subslice(..),
1825 op.as_mut_ptr_range().end,
1826 sequence_0,
1827 &mut litPtr,
1828 litBufferEnd,
1829 prefixStart,
1830 vBase,
1831 dictEnd,
1832 )?
1833 };
1834 op = op.subslice(oneSeqSize_1..);
1835 nbSeq -= 1;
1836 }
1837 }
1838 if nbSeq != 0 {
1839 return Err(Error::corruption_detected);
1840 }
1841 if !seqState.DStream.is_empty() {
1842 return Err(Error::corruption_detected);
1843 }
1844
1845 dctx.entropy.rep = seqState.prevOffset.map(|v| v as u32);
1846 }
1847
1848 if dctx.litBufferLocation == LitLocation::ZSTD_split {
1849 let lastLLSize = unsafe { litBufferEnd.offset_from_unsigned(litPtr) };
1850 if lastLLSize > op.capacity() {
1851 return Err(Error::dstSize_tooSmall);
1852 }
1853 if !op.is_null() {
1854 unsafe { core::ptr::copy(litPtr, op.as_mut_ptr(), lastLLSize) };
1855 op = op.subslice(lastLLSize..);
1856 }
1857 litPtr = (dctx.litExtraBuffer).as_mut_ptr();
1858 litBufferEnd = dctx.litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE..].as_mut_ptr();
1859 dctx.litBufferLocation = LitLocation::ZSTD_not_in_dst;
1860 }
1861
1862 let lastLLSize_0 = unsafe { litBufferEnd.offset_from_unsigned(litPtr) };
1863 if lastLLSize_0 > op.capacity() {
1864 return Err(Error::dstSize_tooSmall);
1865 }
1866
1867 if !op.is_null() {
1868 unsafe { core::ptr::copy_nonoverlapping(litPtr, op.as_mut_ptr(), lastLLSize_0) };
1869 op = op.subslice(lastLLSize_0..);
1870 }
1871
1872 Ok(maxDstSize - op.capacity())
1873}
1874
1875#[inline(always)]
1876unsafe fn ZSTD_decompressSequences_body(
1877 dctx: &mut ZSTD_DCtx,
1878 mut dst: Writer<'_>,
1879 seq: &[u8],
1880 nbSeq: core::ffi::c_int,
1881 offset: Offset,
1882) -> Result<size_t, Error> {
1883 let capacity = dst.capacity();
1884
1885 let oend = match dctx.litBufferLocation {
1886 LitLocation::ZSTD_not_in_dst => dst.as_mut_ptr_range().end,
1887 LitLocation::ZSTD_split | LitLocation::ZSTD_in_dst => dctx.litBuffer,
1888 };
1889
1890 let mut op = dst;
1891 let mut litPtr = dctx.litPtr;
1892 let litEnd = litPtr.add(dctx.litSize);
1893 let prefixStart = dctx.prefixStart as *const u8;
1894 let vBase = dctx.virtualStart as *const u8;
1895 let dictEnd = dctx.dictEnd as *const u8;
1896 if nbSeq != 0 {
1897 let DStream = BIT_DStream_t::new(seq).map_err(|_| Error::corruption_detected)?;
1898 dctx.fseEntropy = true;
1899 let mut seqState = dctx.new_seq_state(DStream);
1900
1901 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1902 if !cfg!(miri) {
1903 asm!(".p2align 6", options(preserves_flags, att_syntax));
1904 asm!("nop", options(preserves_flags, att_syntax));
1905 asm!(".p2align 4", options(preserves_flags, att_syntax));
1906 asm!("nop", options(preserves_flags, att_syntax));
1907 asm!(".p2align 3", options(preserves_flags, att_syntax));
1908 }
1909
1910 for i in 0..nbSeq {
1911 let is_last = i == nbSeq - 1;
1912 let sequence = ZSTD_decodeSequence(&mut seqState, offset, is_last);
1913 let oneSeqSize = ZSTD_execSequence(
1914 op.subslice(..),
1915 oend,
1916 sequence,
1917 &mut litPtr,
1918 litEnd,
1919 prefixStart,
1920 vBase,
1921 dictEnd,
1922 )?;
1923
1924 op = op.subslice(oneSeqSize..);
1925 }
1926
1927 if !seqState.DStream.is_empty() {
1928 return Err(Error::corruption_detected);
1929 }
1930
1931 dctx.entropy.rep = seqState.prevOffset.map(|v| v as u32);
1932 }
1933
1934 let lastLLSize = litEnd.offset_from_unsigned(litPtr);
1935 if lastLLSize > oend.offset_from(op.as_mut_ptr()) as size_t {
1936 return Err(Error::dstSize_tooSmall);
1937 }
1938
1939 if !op.is_null() {
1940 core::ptr::copy_nonoverlapping(litPtr, op.as_mut_ptr(), lastLLSize);
1941 op = op.subslice(lastLLSize..);
1942 }
1943
1944 Ok(capacity - op.capacity())
1945}
1946
1947fn ZSTD_decompressSequences_default(
1948 dctx: &mut ZSTD_DCtx,
1949 dst: Writer<'_>,
1950 seqStart: &[u8],
1951 nbSeq: core::ffi::c_int,
1952 offset: Offset,
1953) -> Result<size_t, Error> {
1954 unsafe { ZSTD_decompressSequences_body(dctx, dst, seqStart, nbSeq, offset) }
1955}
1956
1957fn ZSTD_decompressSequencesSplitLitBuffer_default(
1958 dctx: &mut ZSTD_DCtx,
1959 dst: Writer<'_>,
1960 seqStart: &[u8],
1961 nbSeq: core::ffi::c_int,
1962 offset: Offset,
1963) -> Result<size_t, Error> {
1964 ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, seqStart, nbSeq, offset)
1965}
1966
1967#[inline(always)]
1968fn prefetch_area<T>(ptr: *const T, bytes: usize) {
1969 for pos in (0..bytes).step_by(CACHELINE_SIZE as size_t) {
1970 prefetch_read_data(ptr.wrapping_byte_add(pos), Locality::L2);
1971 }
1972}
1973
1974#[inline(always)]
1975fn prefetch_val<T>(ptr: *const T) {
1976 prefetch_area(ptr, size_of::<T>())
1977}
1978
1979#[inline(always)]
1980fn ZSTD_prefetchMatch(
1981 prefetchPos: size_t,
1982 sequence: seq_t,
1983 prefixStart: *const u8,
1984 dictEnd: *const u8,
1985) -> size_t {
1986 let matchBase = if sequence.offset > prefetchPos.wrapping_add(sequence.litLength) {
1987 dictEnd
1988 } else {
1989 prefixStart
1990 };
1991
1992 let match_ = matchBase
1993 .wrapping_add(prefetchPos)
1994 .wrapping_sub(sequence.offset);
1995
1996 prefetch_read_data(match_, Locality::L1);
1997 prefetch_read_data(match_.wrapping_add(64), Locality::L1);
1998
1999 prefetchPos.wrapping_add(sequence.matchLength)
2000}
2001
2002#[inline(always)]
2003unsafe fn ZSTD_decompressSequencesLong_body(
2004 dctx: &mut ZSTD_DCtx,
2005 mut dst: Writer<'_>,
2006 seq: &[u8],
2007 nbSeq: core::ffi::c_int,
2008 offset: Offset,
2009) -> Result<size_t, Error> {
2010 let dst_capacity = dst.capacity();
2011 let oend = if dctx.litBufferLocation == LitLocation::ZSTD_in_dst {
2012 dctx.litBuffer
2013 } else {
2014 dst.as_mut_ptr_range().end
2015 };
2016 let mut op = dst;
2017 let mut litPtr = dctx.litPtr;
2018 let mut litBufferEnd = dctx.litBufferEnd;
2019 let prefixStart = dctx.prefixStart as *const u8;
2020 let dictStart = dctx.virtualStart as *const u8;
2021 let dictEnd = dctx.dictEnd as *const u8;
2022 if nbSeq != 0 {
2023 let seqAdvance = if nbSeq < 8 { nbSeq } else { 8 };
2024 let DStream = BIT_DStream_t::new(seq).map_err(|_| Error::corruption_detected)?;
2025 dctx.fseEntropy = true;
2026 let mut seqState = dctx.new_seq_state(DStream);
2027
2028 let mut prefetchPos = op.as_mut_ptr().offset_from_unsigned(prefixStart);
2029 let mut sequences: [seq_t; 8] = [seq_t::default(); 8];
2030
2031 for seqNb in 0..seqAdvance {
2032 let sequence = ZSTD_decodeSequence(&mut seqState, offset, seqNb == nbSeq - 1);
2033 prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd);
2034 sequences[seqNb as usize] = sequence;
2035 }
2036
2037 for seqNb in seqAdvance..nbSeq {
2038 let sequence_0 = ZSTD_decodeSequence(&mut seqState, offset, seqNb == nbSeq - 1);
2039 if dctx.litBufferLocation == LitLocation::ZSTD_split
2040 && litPtr.add(
2041 (sequences[((seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK) as usize]).litLength,
2042 ) > dctx.litBufferEnd
2043 {
2044 let leftoverLit = (dctx.litBufferEnd).offset_from_unsigned(litPtr);
2045 if leftoverLit != 0 {
2046 if leftoverLit > oend.offset_from_unsigned(op.as_mut_ptr()) {
2047 return Err(Error::dstSize_tooSmall);
2048 }
2049 ZSTD_safecopyDstBeforeSrc(op.as_mut_ptr(), litPtr, leftoverLit);
2050 sequences[((seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK) as usize].litLength -=
2051 leftoverLit;
2052 op = op.subslice(leftoverLit..);
2053 }
2054 litPtr = (dctx.litExtraBuffer).as_mut_ptr();
2055 litBufferEnd = dctx.litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE..].as_mut_ptr();
2056 dctx.litBufferLocation = LitLocation::ZSTD_not_in_dst;
2057 let oneSeqSize = ZSTD_execSequence(
2058 op.subslice(..),
2059 oend,
2060 sequences[((seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK) as usize],
2061 &mut litPtr,
2062 litBufferEnd,
2063 prefixStart,
2064 dictStart,
2065 dictEnd,
2066 )?;
2067
2068 prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence_0, prefixStart, dictEnd);
2069 sequences[(seqNb & STORED_SEQS_MASK) as usize] = sequence_0;
2070 op = op.subslice(oneSeqSize..);
2071 } else {
2072 let sequence = sequences[((seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK) as usize];
2073 let oneSeqSize_0 = if dctx.litBufferLocation == LitLocation::ZSTD_split {
2074 ZSTD_execSequenceSplitLitBuffer(
2075 op.subslice(..),
2076 oend,
2077 litPtr.add(sequence.litLength).sub(WILDCOPY_OVERLENGTH),
2078 sequences[((seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK) as usize],
2079 &mut litPtr,
2080 litBufferEnd,
2081 prefixStart,
2082 dictStart,
2083 dictEnd,
2084 )?
2085 } else {
2086 ZSTD_execSequence(
2087 op.subslice(..),
2088 oend,
2089 sequence,
2090 &mut litPtr,
2091 litBufferEnd,
2092 prefixStart,
2093 dictStart,
2094 dictEnd,
2095 )?
2096 };
2097
2098 prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence_0, prefixStart, dictEnd);
2099 sequences[(seqNb & STORED_SEQS_MASK) as usize] = sequence_0;
2100 op = op.subslice(oneSeqSize_0..);
2101 }
2102 }
2103
2104 if !seqState.DStream.is_empty() {
2105 return Err(Error::corruption_detected);
2106 }
2107
2108 for seqNb in nbSeq - seqAdvance..nbSeq {
2109 let sequence = &mut sequences[(seqNb & STORED_SEQS_MASK) as usize];
2110 if dctx.litBufferLocation == LitLocation::ZSTD_split
2111 && litPtr.add(sequence.litLength) > dctx.litBufferEnd
2112 {
2113 let leftoverLit_0 = (dctx.litBufferEnd).offset_from_unsigned(litPtr);
2114 if leftoverLit_0 != 0 {
2115 if leftoverLit_0 > oend.offset_from_unsigned(op.as_mut_ptr()) {
2116 return Err(Error::dstSize_tooSmall);
2117 }
2118 ZSTD_safecopyDstBeforeSrc(op.as_mut_ptr(), litPtr, leftoverLit_0);
2119 sequence.litLength = (sequence.litLength).wrapping_sub(leftoverLit_0);
2120 op = op.subslice(leftoverLit_0..);
2121 }
2122 litPtr = (dctx.litExtraBuffer).as_mut_ptr();
2123 litBufferEnd = dctx.litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE..].as_mut_ptr();
2124 dctx.litBufferLocation = LitLocation::ZSTD_not_in_dst;
2125 let oneSeqSize_1 = ZSTD_execSequence(
2126 op.subslice(..),
2127 oend,
2128 *sequence,
2129 &mut litPtr,
2130 litBufferEnd,
2131 prefixStart,
2132 dictStart,
2133 dictEnd,
2134 )?;
2135 op = op.subslice(oneSeqSize_1..);
2136 } else {
2137 let oneSeqSize_2 = if dctx.litBufferLocation == LitLocation::ZSTD_split {
2138 ZSTD_execSequenceSplitLitBuffer(
2139 op.subslice(..),
2140 oend,
2141 litPtr.add(sequence.litLength).sub(WILDCOPY_OVERLENGTH),
2142 *sequence,
2143 &mut litPtr,
2144 litBufferEnd,
2145 prefixStart,
2146 dictStart,
2147 dictEnd,
2148 )?
2149 } else {
2150 ZSTD_execSequence(
2151 op.subslice(..),
2152 oend,
2153 *sequence,
2154 &mut litPtr,
2155 litBufferEnd,
2156 prefixStart,
2157 dictStart,
2158 dictEnd,
2159 )?
2160 };
2161
2162 op = op.subslice(oneSeqSize_2..);
2163 }
2164 }
2165
2166 dctx.entropy.rep = seqState.prevOffset.map(|v| v as u32);
2167 }
2168
2169 if dctx.litBufferLocation == LitLocation::ZSTD_split {
2170 let lastLLSize = litBufferEnd.offset_from_unsigned(litPtr);
2171 if lastLLSize > oend.offset_from_unsigned(op.as_mut_ptr()) {
2172 return Err(Error::dstSize_tooSmall);
2173 }
2174 if !op.is_null() {
2175 core::ptr::copy(litPtr, op.as_mut_ptr(), lastLLSize);
2176 op = op.subslice(lastLLSize..);
2177 }
2178 litPtr = (dctx.litExtraBuffer).as_mut_ptr();
2179 litBufferEnd = dctx.litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE..].as_mut_ptr();
2180 }
2181
2182 let lastLLSize_0 = litBufferEnd.offset_from_unsigned(litPtr);
2183 if lastLLSize_0 > oend.offset_from_unsigned(op.as_mut_ptr()) {
2184 return Err(Error::dstSize_tooSmall);
2185 }
2186
2187 if !op.is_null() {
2188 unsafe {
2189 core::ptr::copy(litPtr, op.as_mut_ptr(), lastLLSize_0);
2190 }
2191 op = op.subslice(lastLLSize_0..);
2192 }
2193
2194 Ok(dst_capacity - op.capacity())
2195}
2196
2197pub const STORED_SEQS: core::ffi::c_int = 8;
2198pub const STORED_SEQS_MASK: core::ffi::c_int = STORED_SEQS - 1;
2199pub const ADVANCED_SEQS: core::ffi::c_int = STORED_SEQS;
2200
2201fn ZSTD_decompressSequencesLong_default(
2202 dctx: &mut ZSTD_DCtx,
2203 dst: Writer<'_>,
2204 seqStart: &[u8],
2205 nbSeq: core::ffi::c_int,
2206 offset: Offset,
2207) -> Result<size_t, Error> {
2208 unsafe { ZSTD_decompressSequencesLong_body(dctx, dst, seqStart, nbSeq, offset) }
2209}
2210
2211#[cfg_attr(target_arch = "x86_64", target_feature(enable = "bmi2"))]
2212fn ZSTD_decompressSequences_bmi2(
2213 dctx: &mut ZSTD_DCtx,
2214 dst: Writer<'_>,
2215 seqStart: &[u8],
2216 nbSeq: core::ffi::c_int,
2217 offset: Offset,
2218) -> Result<size_t, Error> {
2219 unsafe { ZSTD_decompressSequences_body(dctx, dst, seqStart, nbSeq, offset) }
2220}
2221
2222#[cfg_attr(target_arch = "x86_64", target_feature(enable = "bmi2"))]
2223fn ZSTD_decompressSequencesSplitLitBuffer_bmi2(
2224 dctx: &mut ZSTD_DCtx,
2225 dst: Writer<'_>,
2226 seqStart: &[u8],
2227 nbSeq: core::ffi::c_int,
2228 offset: Offset,
2229) -> Result<size_t, Error> {
2230 ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, seqStart, nbSeq, offset)
2231}
2232
2233#[cfg_attr(target_arch = "x86_64", target_feature(enable = "bmi2"))]
2234fn ZSTD_decompressSequencesLong_bmi2(
2235 dctx: &mut ZSTD_DCtx,
2236 dst: Writer<'_>,
2237 seqStart: &[u8],
2238 nbSeq: core::ffi::c_int,
2239 offset: Offset,
2240) -> Result<size_t, Error> {
2241 unsafe { ZSTD_decompressSequencesLong_body(dctx, dst, seqStart, nbSeq, offset) }
2242}
2243
2244fn ZSTD_decompressSequences(
2245 dctx: &mut ZSTD_DCtx,
2246 dst: Writer<'_>,
2247 seqStart: &[u8],
2248 nbSeq: core::ffi::c_int,
2249 offset: Offset,
2250) -> Result<size_t, Error> {
2251 if dctx.bmi2 {
2252 unsafe { ZSTD_decompressSequences_bmi2(dctx, dst, seqStart, nbSeq, offset) }
2253 } else {
2254 ZSTD_decompressSequences_default(dctx, dst, seqStart, nbSeq, offset)
2255 }
2256}
2257
2258fn ZSTD_decompressSequencesSplitLitBuffer(
2259 dctx: &mut ZSTD_DCtx,
2260 dst: Writer<'_>,
2261 seqStart: &[u8],
2262 nbSeq: core::ffi::c_int,
2263 offset: Offset,
2264) -> Result<size_t, Error> {
2265 if dctx.bmi2 {
2266 unsafe { ZSTD_decompressSequencesSplitLitBuffer_bmi2(dctx, dst, seqStart, nbSeq, offset) }
2267 } else {
2268 ZSTD_decompressSequencesSplitLitBuffer_default(dctx, dst, seqStart, nbSeq, offset)
2269 }
2270}
2271
2272fn ZSTD_decompressSequencesLong(
2273 dctx: &mut ZSTD_DCtx,
2274 dst: Writer<'_>,
2275 seqStart: &[u8],
2276 nbSeq: core::ffi::c_int,
2277 offset: Offset,
2278) -> Result<size_t, Error> {
2279 if dctx.bmi2 {
2280 unsafe { ZSTD_decompressSequencesLong_bmi2(dctx, dst, seqStart, nbSeq, offset) }
2281 } else {
2282 ZSTD_decompressSequencesLong_default(dctx, dst, seqStart, nbSeq, offset)
2283 }
2284}
2285
2286impl<const N: usize> SymbolTable<N> {
2287 fn get_offset_info(&self, nbSeq: usize) -> ZSTD_OffsetInfo {
2288 let mut info = ZSTD_OffsetInfo::default();
2289
2290 if nbSeq == 0 {
2291 return info;
2292 }
2293
2294 let tableLog = self.header.tableLog;
2295 for seq_symbol in &self.symbols[..1 << tableLog] {
2296 info.maxNbAdditionalBits = Ord::max(
2297 info.maxNbAdditionalBits,
2298 u32::from(seq_symbol.nbAdditionalBits),
2299 );
2300
2301 if seq_symbol.nbAdditionalBits > 22 {
2302 info.longOffsetShare += 1;
2303 }
2304 }
2305 info.longOffsetShare <<= OffFSELog.wrapping_sub(tableLog);
2306
2307 info
2308 }
2309}
2310
2311const fn ZSTD_maxShortOffset() -> size_t {
2315 match size_of::<usize>() {
2316 4 => {
2317 let maxOffbase = ((1 as size_t) << (STREAM_ACCUMULATOR_MIN as u32 + 1)).wrapping_sub(1);
2321
2322 maxOffbase.wrapping_sub(ZSTD_REP_NUM as size_t)
2323 }
2324 8 => {
2325 const { assert!(ZSTD_WINDOWLOG_MAX <= 31) }
2328
2329 -(1 as core::ffi::c_int) as size_t
2330 }
2331 _ => unreachable!(),
2332 }
2333}
2334
2335pub(crate) fn ZSTD_decompressBlock_internal_help(
2336 dctx: &mut ZSTD_DCtx,
2337 mut dst: Writer<'_>,
2338 src: &[u8],
2339 streaming: StreamingOperation,
2340) -> Result<size_t, Error> {
2341 if src.len() > dctx.block_size_max() {
2342 return Err(Error::srcSize_wrong);
2343 }
2344
2345 let litCSize = ZSTD_decodeLiteralsBlock(dctx, src, dst.subslice(..), streaming)?;
2346
2347 let mut ip = &src[litCSize..];
2348
2349 let blockSizeMax = Ord::min(dst.capacity(), dctx.block_size_max());
2350 let totalHistorySize =
2351 dst.as_mut_ptr().wrapping_add(blockSizeMax) as usize - dctx.virtualStart as usize;
2352 let mut offset = if MEM_32bits() && totalHistorySize > ZSTD_maxShortOffset() {
2353 Offset::Long
2354 } else {
2355 Offset::Regular
2356 };
2357 let mut use_prefetch_decoder = dctx.ddictIsCold;
2358 let mut nbSeq = 0;
2359 let seqHSize = ZSTD_decodeSeqHeaders(dctx, &mut nbSeq, ip)?;
2360 ip = &ip[seqHSize..];
2361 if dst.is_empty() && nbSeq > 0 {
2362 return Err(Error::dstSize_tooSmall);
2363 }
2364 if size_of::<usize>() == 8
2365 && size_of::<size_t>() == size_of::<*mut core::ffi::c_void>()
2366 && (usize::MAX - dst.as_mut_ptr() as usize) < (1 << 20)
2367 {
2368 return Err(Error::dstSize_tooSmall);
2369 }
2370 if offset == Offset::Long
2371 || !use_prefetch_decoder && totalHistorySize > ((1) << 24) as size_t && nbSeq > 8
2372 {
2373 let info = match dctx.OFTptr {
2374 None => OF_defaultDTable.get_offset_info(nbSeq as usize),
2375 Some(table) => (unsafe { &*table.as_ptr() }).get_offset_info(nbSeq as usize),
2376 };
2377
2378 if offset == Offset::Long && info.maxNbAdditionalBits <= STREAM_ACCUMULATOR_MIN as u32 {
2379 offset = Offset::Regular;
2380 }
2381
2382 if !use_prefetch_decoder {
2383 let minShare = (if size_of::<usize>() == 8 { 7 } else { 20 }) as u32;
2384 use_prefetch_decoder = info.longOffsetShare >= minShare;
2385 }
2386 }
2387
2388 dctx.ddictIsCold = false;
2389
2390 if use_prefetch_decoder {
2391 ZSTD_decompressSequencesLong(dctx, dst.subslice(..), ip, nbSeq, offset)
2392 } else if dctx.litBufferLocation == LitLocation::ZSTD_split {
2393 ZSTD_decompressSequencesSplitLitBuffer(dctx, dst, ip, nbSeq, offset)
2394 } else {
2395 ZSTD_decompressSequences(dctx, dst, ip, nbSeq, offset)
2396 }
2397}
2398
2399pub fn ZSTD_checkContinuity(dctx: &mut ZSTD_DCtx, range: Range<*const u8>) {
2400 if range.start.cast() != dctx.previousDstEnd && !range.is_empty() {
2401 dctx.dictEnd = dctx.previousDstEnd;
2402 let delta = dctx.previousDstEnd.addr() - dctx.prefixStart.addr();
2403 dctx.virtualStart = range.start.wrapping_sub(delta).cast();
2404 dctx.prefixStart = range.start.cast();
2405 dctx.previousDstEnd = range.start.cast();
2406 }
2407}
2408
2409#[cfg_attr(feature = "export-symbols", export_name = crate::prefix!(ZSTD_decompressBlock))]
2410pub unsafe extern "C" fn ZSTD_decompressBlock(
2411 dctx: *mut ZSTD_DCtx,
2412 dst: *mut core::ffi::c_void,
2413 dstCapacity: size_t,
2414 src: *const core::ffi::c_void,
2415 srcSize: size_t,
2416) -> size_t {
2417 let dst = Writer::from_raw_parts(dst.cast::<u8>(), dstCapacity);
2418 let src = Reader::from_raw_parts(src.cast::<u8>(), srcSize);
2419
2420 let dctx: &mut ZSTD_DCtx = dctx.as_mut().unwrap();
2421 let mut dst = dst;
2422 dctx.isFrameDecompression = false;
2423
2424 ZSTD_checkContinuity(dctx, dst.as_ptr_range());
2425
2426 let dSize = ZSTD_decompressBlock_internal_help(
2428 dctx,
2429 dst.subslice(..),
2430 src.as_slice(),
2431 StreamingOperation::NotStreaming,
2432 )
2433 .unwrap_or_else(|err| err.to_error_code());
2434
2435 dctx.previousDstEnd = dst.as_ptr().byte_add(dSize).cast::<c_void>();
2436 dSize
2437}
2438
2439#[cfg(test)]
2440mod test {
2441 use crate::lib::zstd::*;
2442 use core::ffi::*;
2443
2444 #[test]
2445 fn basic_decompress() {
2446 rs(&[40, 181, 47, 253, 48, 21, 44, 0, 0, 0, 253, 49, 0, 21]);
2447 }
2448
2449 fn rs(compressed: &[u8]) -> (usize, Vec<u8>) {
2450 use crate::lib::decompress::zstd_decompress::*;
2451
2452 let compressed_ptr = compressed.as_ptr() as *const c_void;
2453 let compressed_size = compressed.len();
2454
2455 let decompressed_size =
2457 unsafe { ZSTD_getFrameContentSize(compressed_ptr, compressed_size) };
2458 if decompressed_size == ZSTD_CONTENTSIZE_ERROR {
2459 panic!("ZSTD_CONTENTSIZE_ERROR");
2460 } else if decompressed_size == ZSTD_CONTENTSIZE_UNKNOWN {
2461 panic!("ZSTD_CONTENTSIZE_UNKNOWN");
2462 }
2463
2464 let mut decompressed = vec![0u8; Ord::min(decompressed_size as usize, 1 << 20)];
2466 let result = unsafe {
2467 ZSTD_decompress(
2468 decompressed.as_mut_ptr() as *mut c_void,
2469 decompressed.len(),
2470 compressed_ptr,
2471 compressed_size,
2472 )
2473 };
2474
2475 (result as usize, decompressed)
2476 }
2477}