1use core::ptr::{self, NonNull};
2use std::ops::Bound;
3
4use libc::size_t;
5
6use crate::lib::common::bitstream::{BIT_DStream_t, BitContainerType, StreamStatus};
7use crate::lib::common::entropy_common::HUF_readStats_wksp;
8use crate::lib::common::error_private::{ERR_isError, Error};
9use crate::lib::common::huf::{
10 HUF_flags_bmi2, HUF_flags_disableAsm, HUF_flags_disableFast, HUF_SYMBOLVALUE_MAX,
11 HUF_TABLELOG_MAX,
12};
13use crate::lib::common::mem::{MEM_read64, MEM_readLEST, MEM_write16};
14use crate::lib::decompress::Workspace;
15
16#[cfg(target_arch = "x86_64")]
17extern "C" {
18 fn HUF_decompress4X1_usingDTable_internal_fast_asm_loop(args: &mut HUF_DecompressFastArgs);
19 fn HUF_decompress4X2_usingDTable_internal_fast_asm_loop(args: &mut HUF_DecompressFastArgs);
20}
21
22#[derive(Copy, Clone)]
23#[repr(C)]
24pub struct algo_time_t {
25 pub tableTime: u32,
26 pub decode256Time: u32,
27}
28
29#[derive(Copy, Clone)]
30#[repr(C)]
31pub struct DTable {
32 pub description: DTableDesc,
33 pub data: DTableData,
34}
35
36#[derive(Copy, Clone)]
37#[repr(C)]
38pub struct DTableData {
39 data: [u32; 4096],
40}
41
42impl DTableData {
43 fn as_x1(&self) -> &[HUF_DEltX1; 4096] {
44 unsafe { core::mem::transmute(&self.data) }
45 }
46
47 fn as_x1_mut(&mut self) -> &mut [HUF_DEltX1; 4096] {
48 unsafe { core::mem::transmute(&mut self.data) }
49 }
50
51 fn as_x2(&self) -> &[HUF_DEltX2; 4096] {
52 unsafe { core::mem::transmute(&self.data) }
53 }
54
55 fn as_x2_mut(&mut self) -> &mut [HUF_DEltX2; 4096] {
56 unsafe { core::mem::transmute(&mut self.data) }
57 }
58
59 fn as_symbols(&self) -> &[u16; 2 * 4096] {
60 unsafe { core::mem::transmute(&self.data) }
61 }
62}
63
64#[derive(Copy, Clone)]
65#[repr(C)]
66pub struct DTableDesc {
67 pub maxTableLog: u8,
68 pub tableType: u8,
69 pub tableLog: u8,
70 pub reserved: u8,
71}
72
73impl DTableDesc {
74 pub fn from_u32(value: u32) -> Self {
75 let [maxTableLog, tableType, tableLog, reserved] = value.to_le_bytes();
76
77 Self {
78 maxTableLog,
79 tableType,
80 tableLog,
81 reserved,
82 }
83 }
84}
85
86#[derive(Copy, Clone)]
87#[repr(C)]
88pub struct HUF_DEltX1 {
89 pub nbBits: u8,
90 pub byte: u8,
91}
92#[repr(C)]
93pub struct HUF_ReadDTableX1_Workspace {
94 rankVal: [u32; 13],
95 rankStart: [u32; 13],
96 statsWksp: crate::lib::common::entropy_common::Workspace,
97 symbols: [u8; 256],
98 huffWeight: [u8; 256],
99}
100
101#[derive(Debug, Copy, Clone, PartialEq, Eq)]
102#[repr(C)]
103pub struct HUF_DEltX2 {
104 pub sequence: u16,
105 pub nbBits: u8,
106 pub length: u8,
107}
108
109pub type rankValCol_t = [u32; 13];
110#[repr(C)]
111pub struct HUF_ReadDTableX2_Workspace {
112 rankVal: [rankValCol_t; 12],
113 rankStats: [u32; 13],
114 rankStart0: [u32; 15],
115 sortedSymbol: [sortedSymbol_t; 256],
116 weightList: [u8; 256],
117 calleeWksp: crate::lib::common::entropy_common::Workspace,
118}
119#[repr(C)]
120pub struct sortedSymbol_t {
121 pub symbol: u8,
122}
123#[repr(C)]
124pub struct HUF_DecompressFastArgs<'a> {
125 pub ip: [*const u8; 4],
126 pub op: [*mut u8; 4],
127 pub bits: [u64; 4],
128 pub dt: &'a DTableData,
129 pub ilowest: *const u8,
130 pub oend: *mut u8,
131 pub iend: [*const u8; 4],
132}
133
134pub const HUF_DECODER_FAST_TABLELOG: core::ffi::c_int = 11;
135pub const HUF_ENABLE_FAST_DECODE: core::ffi::c_int = 1;
136
137unsafe fn HUF_initFastDStream(ip: *const u8) -> size_t {
138 let lastByte = *ip.offset(7);
139 let bitsConsumed = match lastByte.checked_ilog2() {
140 Some(v) => 8 - v,
141 None => 0,
142 };
143 let value = MEM_readLEST(ip as *const core::ffi::c_void) | 1;
144 value << bitsConsumed
145}
146
147impl<'a> HUF_DecompressFastArgs<'a> {
148 unsafe fn new(
149 mut dst: Writer<'_>,
150 src: &[u8],
151 DTable: &'a DTable,
152 ) -> Result<Option<Self>, Error> {
153 if cfg!(target_endian = "big") || cfg!(target_pointer_width = "32") {
155 return Ok(None);
156 }
157
158 if dst.is_empty() {
159 return Ok(None);
160 }
161
162 let [b0, b1, b2, b3, b4, b5, _, _, _, _, ..] = *src else {
164 return Err(Error::corruption_detected);
165 };
166
167 let dtLog = DTable.description.tableLog as u32;
171 if dtLog != HUF_DECODER_FAST_TABLELOG as u32 {
172 return Ok(None);
173 }
174
175 let length1 = usize::from(u16::from_le_bytes([b0, b1]));
176 let length2 = usize::from(u16::from_le_bytes([b2, b3]));
177 let length3 = usize::from(u16::from_le_bytes([b4, b5]));
178 let length4 = src.len().wrapping_sub(6 + length1 + length2 + length3);
179
180 if 6 + length1 + length2 + length3 > src.len() {
181 return Err(Error::corruption_detected);
182 }
183
184 let istart = src.as_ptr();
185 let mut iend = [core::ptr::null(); 4];
186 iend[0] = istart.add(6); iend[1] = iend[0].add(length1);
188 iend[2] = iend[1].add(length2);
189 iend[3] = iend[2].add(length3);
190
191 if length1 < 8 || length2 < 8 || length3 < 8 || length4 < 8 {
193 return Ok(None);
194 }
195
196 let mut ip = [core::ptr::null(); 4];
198 ip[0] = iend[1].sub(size_of::<u64>());
199 ip[1] = iend[2].sub(size_of::<u64>());
200 ip[2] = iend[3].sub(size_of::<u64>());
201 ip[3] = src.as_ptr().add(src.len() - size_of::<u64>());
202
203 let mut op = [core::ptr::null_mut(); 4];
205 op[0] = dst.as_mut_ptr();
206 op[1] = op[0].add(dst.capacity().div_ceil(4));
207 op[2] = op[1].add(dst.capacity().div_ceil(4));
208 op[3] = op[2].add(dst.capacity().div_ceil(4));
209
210 if op[3] >= dst.as_mut_ptr_range().end {
212 return Ok(None);
213 }
214
215 let bits = ip.map(|v| HUF_initFastDStream(v) as u64);
223
224 let args = Self {
229 ip,
230 op,
231 bits,
232 dt: &DTable.data,
233 ilowest: istart,
234 oend: dst.as_mut_ptr_range().end,
235 iend,
236 };
237
238 Ok(Some(args))
239 }
240}
241
242unsafe fn init_remaining_dstream(
243 args: &HUF_DecompressFastArgs,
244 stream: usize,
245 segmentEnd: *mut u8,
246) -> Result<BIT_DStream_t, Error> {
247 if args.op[stream] > segmentEnd {
248 return Err(Error::corruption_detected);
249 }
250
251 if args.ip[stream] < args.iend[stream].sub(8) {
252 return Err(Error::corruption_detected);
253 }
254
255 let bitContainer = MEM_readLEST(args.ip[stream] as *const core::ffi::c_void) as usize;
256 let bitsConsumed = args.bits[stream].trailing_zeros();
257 let start = args.ilowest as *const core::ffi::c_char;
258 let limitPtr = start.add(::core::mem::size_of::<size_t>());
259 let ptr = args.ip[stream] as *const core::ffi::c_char;
260
261 Ok(BIT_DStream_t {
262 bitContainer,
263 bitsConsumed,
264 ptr,
265 start,
266 limitPtr,
267 })
268}
269
270fn HUF_rescaleStats(
275 huffWeight: &mut [u8; 256],
276 rankVal: &mut rankValCol_t,
277 nbSymbols: u32,
278 tableLog: u32,
279 targetTableLog: u32,
280) -> u32 {
281 if tableLog > targetTableLog {
282 return tableLog;
283 }
284
285 if tableLog < targetTableLog {
286 let scale = targetTableLog as usize - tableLog as usize;
287
288 for s in 0..nbSymbols as usize {
290 huffWeight[s] += (if huffWeight[s] == 0 { 0 } else { scale }) as u8;
291 }
292
293 let mut s = targetTableLog as usize;
297 while s > scale {
298 rankVal[s] = rankVal[s - scale];
299 s -= 1;
300 }
301
302 rankVal[1..=scale].fill(0);
303 }
304
305 targetTableLog
306}
307
308pub fn HUF_readDTableX1_wksp(
309 DTable: &mut DTable,
310 src: &[u8],
311 workSpace: &mut Workspace,
312 flags: core::ffi::c_int,
313) -> size_t {
314 let mut dtd = DTable.description;
315 let dt = DTable.data.as_x1_mut();
316
317 let mut tableLog = 0;
318 let mut nbSymbols = 0;
319 let mut iSize: size_t = 0;
320
321 let wksp = workSpace.as_x1_mut();
322
323 iSize = HUF_readStats_wksp(
324 &mut wksp.huffWeight,
325 (HUF_SYMBOLVALUE_MAX + 1) as size_t,
326 &mut wksp.rankVal,
327 &mut nbSymbols,
328 &mut tableLog,
329 src,
330 &mut wksp.statsWksp,
331 flags,
332 );
333 if ERR_isError(iSize) {
334 return iSize;
335 }
336
337 let maxTableLog = (dtd.maxTableLog as core::ffi::c_int + 1) as u32;
338 let targetTableLog = if maxTableLog < 11 { maxTableLog } else { 11 };
339 tableLog = HUF_rescaleStats(
340 &mut wksp.huffWeight,
341 &mut wksp.rankVal,
342 nbSymbols,
343 tableLog,
344 targetTableLog,
345 );
346 if tableLog > (dtd.maxTableLog as core::ffi::c_int + 1) as u32 {
347 return Error::tableLog_tooLarge.to_error_code();
348 }
349 dtd.tableType = 0;
350 dtd.tableLog = tableLog as u8;
351
352 DTable.description = dtd;
353
354 let mut nextRankStart = 0u32;
366 for n in 0..tableLog as usize + 1 {
367 let curr = nextRankStart;
368 nextRankStart += wksp.rankVal[n];
369 wksp.rankStart[n] = curr;
370 }
371
372 for (n, w) in wksp.huffWeight[..nbSymbols as usize].iter().enumerate() {
373 let w = usize::from(*w);
374 wksp.symbols[wksp.rankStart[w] as usize] = n as u8;
375 wksp.rankStart[w] += 1;
376 }
377
378 let mut symbol = wksp.rankVal[0] as usize;
385 let mut rankStart = 0;
386 for w in 1..tableLog.wrapping_add(1) {
387 let symbolCount = wksp.rankVal[w as usize] as usize;
388 let length = (1) << w >> 1;
389 let dt = dt[rankStart..][..length * symbolCount].chunks_exact_mut(length);
390 let nbBits = tableLog.wrapping_add(1).wrapping_sub(w) as u8;
391
392 for (s, chunk) in dt.enumerate() {
395 let byte = wksp.symbols[symbol + s];
396 chunk.fill(HUF_DEltX1 { nbBits, byte });
397 }
398
399 symbol += symbolCount;
400 rankStart += symbolCount * length;
401 }
402
403 iSize
404}
405
406#[inline(always)]
407fn HUF_decodeSymbolX1(Dstream: &mut BIT_DStream_t, dt: &[HUF_DEltX1; 4096], dtLog: u32) -> u8 {
408 let HUF_DEltX1 { byte, nbBits, .. } = dt[Dstream.look_bits_fast(dtLog)];
409 Dstream.skip_bits(u32::from(nbBits));
410 byte
411}
412
413#[inline(always)]
414fn HUF_decodeStreamX1(
415 mut p: Writer<'_>,
416 bitDPtr: &mut BIT_DStream_t,
417 dt: &[HUF_DEltX1; 4096],
418 dtLog: u32,
419) -> size_t {
420 let capacity = p.capacity();
421
422 if p.capacity() >= 4 {
423 while bitDPtr.reload() == StreamStatus::Unfinished && p.capacity() >= 4 {
424 if cfg!(target_pointer_width = "64") {
425 p.write_u8(HUF_decodeSymbolX1(bitDPtr, dt, dtLog));
426 }
427 if cfg!(target_pointer_width = "64") || HUF_TABLELOG_MAX <= 12 {
428 p.write_u8(HUF_decodeSymbolX1(bitDPtr, dt, dtLog));
429 }
430 if cfg!(target_pointer_width = "64") {
431 p.write_u8(HUF_decodeSymbolX1(bitDPtr, dt, dtLog));
432 }
433 p.write_u8(HUF_decodeSymbolX1(bitDPtr, dt, dtLog));
434 }
435 } else {
436 bitDPtr.reload();
437 }
438
439 if cfg!(target_pointer_width = "32") {
440 while bitDPtr.reload() == StreamStatus::Unfinished && !p.is_empty() {
441 p.write_u8(HUF_decodeSymbolX1(bitDPtr, dt, dtLog));
442 }
443 }
444
445 while !p.is_empty() {
446 p.write_u8(HUF_decodeSymbolX1(bitDPtr, dt, dtLog));
447 }
448
449 capacity - p.capacity()
450}
451
452#[inline(always)]
453fn HUF_decompress1X1_usingDTable_internal_body(
454 mut dst: Writer<'_>,
455 src: &[u8],
456 DTable: &DTable,
457) -> size_t {
458 let dt = DTable.data.as_x1();
459 let dtd = DTable.description;
460 let dtLog = dtd.tableLog as u32;
461
462 let mut bitD = match BIT_DStream_t::new(src) {
463 Ok(v) => v,
464 Err(e) => return e.to_error_code(),
465 };
466
467 HUF_decodeStreamX1(dst.subslice(..), &mut bitD, dt, dtLog);
468
469 if !bitD.is_empty() {
470 return Error::corruption_detected.to_error_code();
471 }
472
473 dst.capacity()
474}
475
476#[inline(always)]
477fn HUF_decompress4X1_usingDTable_internal_body(
478 mut dst: Writer<'_>,
479 src: &[u8],
480 DTable: &DTable,
481) -> size_t {
482 let [b0, b1, b2, b3, b4, b5, _, _, _, _, ..] = *src else {
484 return Error::corruption_detected.to_error_code();
485 };
486
487 if dst.capacity() < 6 {
488 return Error::corruption_detected.to_error_code();
489 }
490
491 let length1 = usize::from(u16::from_le_bytes([b0, b1]));
492 let length2 = usize::from(u16::from_le_bytes([b2, b3]));
493 let length3 = usize::from(u16::from_le_bytes([b4, b5]));
494
495 if 6 + length1 + length2 + length3 > src.len() {
496 return Error::corruption_detected.to_error_code();
497 }
498
499 let istart1 = &src[6..][..length1];
500 let istart2 = &src[6 + length1..][..length2];
501 let istart3 = &src[6 + length1 + length2..][..length3];
502 let istart4 = &src[6 + length1 + length2 + length3..];
503
504 let Some((mut w1, mut w2, mut w3, mut w4)) = dst.quarter() else {
505 return Error::corruption_detected.to_error_code();
506 };
507
508 let mut end_signal = true;
509
510 let mut bitD1 = match BIT_DStream_t::new(istart1) {
511 Ok(v) => v,
512 Err(e) => return e.to_error_code(),
513 };
514 let mut bitD2 = match BIT_DStream_t::new(istart2) {
515 Ok(v) => v,
516 Err(e) => return e.to_error_code(),
517 };
518 let mut bitD3 = match BIT_DStream_t::new(istart3) {
519 Ok(v) => v,
520 Err(e) => return e.to_error_code(),
521 };
522 let mut bitD4 = match BIT_DStream_t::new(istart4) {
523 Ok(v) => v,
524 Err(e) => return e.to_error_code(),
525 };
526
527 let dt = DTable.data.as_x1();
528 let dtLog = DTable.description.tableLog as u32;
529
530 if w4.capacity() >= size_of::<size_t>() {
531 while end_signal && w4.capacity() >= 4 {
532 if cfg!(target_pointer_width = "64") {
533 w1.write_u8(HUF_decodeSymbolX1(&mut bitD1, dt, dtLog));
534 w2.write_u8(HUF_decodeSymbolX1(&mut bitD2, dt, dtLog));
535 w3.write_u8(HUF_decodeSymbolX1(&mut bitD3, dt, dtLog));
536 w4.write_u8(HUF_decodeSymbolX1(&mut bitD4, dt, dtLog));
537 }
538
539 if cfg!(target_pointer_width = "64") || HUF_TABLELOG_MAX <= 12 {
540 w1.write_u8(HUF_decodeSymbolX1(&mut bitD1, dt, dtLog));
541 w2.write_u8(HUF_decodeSymbolX1(&mut bitD2, dt, dtLog));
542 w3.write_u8(HUF_decodeSymbolX1(&mut bitD3, dt, dtLog));
543 w4.write_u8(HUF_decodeSymbolX1(&mut bitD4, dt, dtLog));
544 }
545
546 if cfg!(target_pointer_width = "64") {
547 w1.write_u8(HUF_decodeSymbolX1(&mut bitD1, dt, dtLog));
548 w2.write_u8(HUF_decodeSymbolX1(&mut bitD2, dt, dtLog));
549 w3.write_u8(HUF_decodeSymbolX1(&mut bitD3, dt, dtLog));
550 w4.write_u8(HUF_decodeSymbolX1(&mut bitD4, dt, dtLog));
551 }
552
553 w1.write_u8(HUF_decodeSymbolX1(&mut bitD1, dt, dtLog));
554 w2.write_u8(HUF_decodeSymbolX1(&mut bitD2, dt, dtLog));
555 w3.write_u8(HUF_decodeSymbolX1(&mut bitD3, dt, dtLog));
556 w4.write_u8(HUF_decodeSymbolX1(&mut bitD4, dt, dtLog));
557
558 end_signal &= bitD1.reload_fast() == StreamStatus::Unfinished;
559 end_signal &= bitD2.reload_fast() == StreamStatus::Unfinished;
560 end_signal &= bitD3.reload_fast() == StreamStatus::Unfinished;
561 end_signal &= bitD4.reload_fast() == StreamStatus::Unfinished;
562 }
563 }
564
565 HUF_decodeStreamX1(w1, &mut bitD1, dt, dtLog);
566 HUF_decodeStreamX1(w2, &mut bitD2, dt, dtLog);
567 HUF_decodeStreamX1(w3, &mut bitD3, dt, dtLog);
568 HUF_decodeStreamX1(w4, &mut bitD4, dt, dtLog);
569
570 if !(bitD1.is_empty() && bitD2.is_empty() && bitD3.is_empty() && bitD4.is_empty()) {
571 return Error::corruption_detected.to_error_code();
572 }
573
574 dst.capacity()
575}
576
577fn HUF_decompress4X1_usingDTable_internal_bmi2(
578 dst: Writer<'_>,
579 src: &[u8],
580 DTable: &DTable,
581) -> size_t {
582 HUF_decompress4X1_usingDTable_internal_body(dst, src, DTable)
583}
584
585fn HUF_decompress4X1_usingDTable_internal_default(
586 dst: Writer<'_>,
587 src: &[u8],
588 DTable: &DTable,
589) -> size_t {
590 HUF_decompress4X1_usingDTable_internal_body(dst, src, DTable)
591}
592
593macro_rules! HUF_4X_FOR_EACH_STREAM_WITH_VAR {
594 ($mac:ident, $var:literal) => {
595 $mac!(0, $var);
596 $mac!(1, $var);
597 $mac!(2, $var);
598 $mac!(3, $var);
599 };
600}
601
602macro_rules! HUF_4X_FOR_EACH_STREAM {
603 ($mac:ident ) => {
604 $mac!(0);
605 $mac!(1);
606 $mac!(2);
607 $mac!(3);
608 };
609}
610
611unsafe extern "C" fn HUF_decompress4X1_usingDTable_internal_fast_c_loop(
612 args: &mut HUF_DecompressFastArgs,
613) {
614 let dtable = args.dt.as_symbols();
615 let oend = args.oend;
616 let ilowest = args.ilowest;
617
618 let mut bits = args.bits;
620 let mut ip = args.ip;
621 let mut op = args.op;
622
623 assert!(cfg!(target_endian = "little"));
624 assert!(cfg!(target_pointer_width = "64"));
625
626 'out: loop {
627 if cfg!(debug_assertions) {
629 for stream in 0..4 {
630 assert!(op[stream] <= (if stream == 3 { oend } else { op[stream + 1] }));
631 assert!(ip[stream] >= ilowest);
632 }
633 }
634
635 let oiters = oend.offset_from(op[3]) / 5;
639 let iiters = (ip[0]).offset_from(ilowest) / 7;
640 let iters = Ord::min(oiters, iiters);
641 let symbols = iters * 5;
642
643 let olimit = op[3].offset(symbols);
647
648 if op[3] == olimit {
650 break;
651 }
652
653 for stream in 1..4 {
657 if ip[stream] < ip[stream - 1] {
658 break 'out;
659 }
660 }
661
662 if cfg!(debug_assertions) {
663 for stream in 1..4 {
664 assert!(ip[stream] >= ip[stream - 1]);
665 }
666 }
667
668 macro_rules! HUF_4X1_DECODE_SYMBOL {
669 ($stream:expr, $symbol:expr) => {
670 let index = bits[$stream] >> 53;
671 let entry = dtable[index as usize];
672
673 bits[$stream] <<= entry & 0x3F;
674 op[$stream]
675 .offset($symbol)
676 .write(((entry >> 8) & 0xFF) as u8)
677 };
678 }
679
680 macro_rules! HUF_4X1_RELOAD_STREAM {
681 ($stream: expr) => {
682 let ctz = bits[$stream].trailing_zeros();
683 let nbBits = ctz & 7;
684 let nbBytes = ctz >> 3;
685
686 op[$stream] = op[$stream].add(5);
687 ip[$stream] = ip[$stream].sub(nbBytes as usize);
688 bits[$stream] = MEM_read64(ip[$stream] as *const core::ffi::c_void) | 1;
689 bits[$stream] <<= nbBits;
690 };
691 }
692
693 loop {
697 HUF_4X_FOR_EACH_STREAM_WITH_VAR!(HUF_4X1_DECODE_SYMBOL, 0);
699 HUF_4X_FOR_EACH_STREAM_WITH_VAR!(HUF_4X1_DECODE_SYMBOL, 1);
700 HUF_4X_FOR_EACH_STREAM_WITH_VAR!(HUF_4X1_DECODE_SYMBOL, 2);
701 HUF_4X_FOR_EACH_STREAM_WITH_VAR!(HUF_4X1_DECODE_SYMBOL, 3);
702 HUF_4X_FOR_EACH_STREAM_WITH_VAR!(HUF_4X1_DECODE_SYMBOL, 4);
703
704 HUF_4X_FOR_EACH_STREAM!(HUF_4X1_RELOAD_STREAM);
706
707 if op[3] >= olimit {
708 break;
709 }
710 }
711 }
712
713 args.bits = bits;
715 args.ip = ip;
716 args.op = op;
717}
718
719pub type HUF_DecompressFastLoopFn = unsafe extern "C" fn(&mut HUF_DecompressFastArgs) -> ();
720unsafe fn HUF_decompress4X1_usingDTable_internal_fast(
721 mut dst: Writer<'_>,
722 src: &[u8],
723 DTable: &DTable,
724 loopFn: HUF_DecompressFastLoopFn,
725) -> size_t {
726 let oend = dst.as_mut_ptr_range().end;
727
728 let mut args = match HUF_DecompressFastArgs::new(dst.subslice(..), src, DTable) {
729 Ok(Some(args)) => args,
730 Ok(None) => return 0,
731 Err(e) => return e.to_error_code(),
732 };
733
734 assert!(args.ip[0] >= args.ilowest);
735 loopFn(&mut args);
736
737 let istart = src.as_ptr();
739 assert!(args.ip[0] >= istart);
740 assert!(args.ip[1] >= istart);
741 assert!(args.ip[2] >= istart);
742 assert!(args.ip[3] >= istart);
743 assert!(args.op[3] <= oend);
744
745 assert_eq!(istart, args.ilowest);
746 assert_eq!(istart.add(6), args.iend[0]);
747
748 let segmentSize = dst.capacity().div_ceil(4);
749 let mut segmentEnd = dst.as_mut_ptr_range().start;
750
751 for (i, op) in args.op.iter().copied().enumerate() {
753 segmentEnd = Ord::min(segmentEnd.add(segmentSize), oend);
754
755 let mut bit = match init_remaining_dstream(&args, i, segmentEnd) {
756 Ok(v) => v,
757 Err(e) => return e.to_error_code(),
758 };
759
760 let length = HUF_decodeStreamX1(
762 Writer::from_raw_parts(op, segmentEnd as usize - op as usize),
763 &mut bit,
764 DTable.data.as_x1(),
765 HUF_DECODER_FAST_TABLELOG as u32,
766 );
767
768 if op.add(length as usize) != segmentEnd {
769 return Error::corruption_detected.to_error_code();
770 }
771 }
772
773 dst.capacity()
774}
775
776fn HUF_decompress1X1_usingDTable_internal_bmi2(
777 dst: Writer<'_>,
778 src: &[u8],
779 DTable: &DTable,
780) -> size_t {
781 HUF_decompress1X1_usingDTable_internal_body(dst, src, DTable)
782}
783
784fn HUF_decompress1X1_usingDTable_internal_default(
785 dst: Writer<'_>,
786 src: &[u8],
787 DTable: &DTable,
788) -> size_t {
789 HUF_decompress1X1_usingDTable_internal_body(dst, src, DTable)
790}
791
792fn HUF_decompress1X1_usingDTable_internal(
793 dst: Writer<'_>,
794 src: &[u8],
795 DTable: &DTable,
796 flags: core::ffi::c_int,
797) -> size_t {
798 if flags & HUF_flags_bmi2 as core::ffi::c_int != 0 {
799 HUF_decompress1X1_usingDTable_internal_bmi2(dst, src, DTable)
800 } else {
801 HUF_decompress1X1_usingDTable_internal_default(dst, src, DTable)
802 }
803}
804
805unsafe fn HUF_decompress4X1_usingDTable_internal(
806 mut dst: Writer<'_>,
807 src: &[u8],
808 DTable: &DTable,
809 flags: core::ffi::c_int,
810) -> size_t {
811 if flags & HUF_flags_bmi2 as core::ffi::c_int != 0 {
812 let loopFn = match flags & HUF_flags_disableAsm as i32 {
813 #[cfg(target_arch = "x86_64")]
814 0 => HUF_decompress4X1_usingDTable_internal_fast_asm_loop as HUF_DecompressFastLoopFn,
815 _ => HUF_decompress4X1_usingDTable_internal_fast_c_loop as HUF_DecompressFastLoopFn,
816 };
817
818 if HUF_ENABLE_FAST_DECODE != 0 && flags & HUF_flags_disableFast as core::ffi::c_int == 0 {
819 let ret =
820 HUF_decompress4X1_usingDTable_internal_fast(dst.subslice(..), src, DTable, loopFn);
821 if ret != 0 {
822 return ret;
823 }
824 }
825
826 HUF_decompress4X1_usingDTable_internal_bmi2(dst, src, DTable)
827 } else {
828 HUF_decompress4X1_usingDTable_internal_default(dst, src, DTable)
829 }
830}
831
832unsafe fn HUF_decompress4X1_DCtx_wksp(
833 dctx: &mut DTable,
834 dst: Writer<'_>,
835 src: &[u8],
836 workSpace: &mut Workspace,
837 flags: core::ffi::c_int,
838) -> size_t {
839 let hSize = HUF_readDTableX1_wksp(dctx, src, workSpace, flags);
840 if ERR_isError(hSize) {
841 return hSize;
842 }
843 if hSize as usize >= src.len() {
844 return Error::srcSize_wrong.to_error_code();
845 }
846
847 HUF_decompress4X1_usingDTable_internal(dst, &src[hSize as usize..], dctx, flags)
848}
849
850impl HUF_DEltX2 {
851 #[inline]
852 fn from_u32(value: u32) -> Self {
853 let [a, b, c, d] = value.to_le_bytes();
854
855 Self {
856 sequence: u16::from_le_bytes([a, b]),
857 nbBits: c,
858 length: d,
859 }
860 }
861}
862
863fn HUF_buildDEltX2U32(symbol: u32, nbBits: u32, baseSeq: u32, level: core::ffi::c_int) -> u32 {
864 const _: () = assert!(core::mem::offset_of!(HUF_DEltX2, sequence) == 0);
865 const _: () = assert!(core::mem::offset_of!(HUF_DEltX2, nbBits) == 2);
866 const _: () = assert!(core::mem::offset_of!(HUF_DEltX2, length) == 3);
867 const _: () = assert!(size_of::<HUF_DEltX2>() == size_of::<u32>());
868
869 let seq = if level == 1 {
870 symbol
871 } else {
872 baseSeq.wrapping_add(symbol << 8)
873 };
874 let result = seq
875 .wrapping_add(nbBits << 16)
876 .wrapping_add((level as u32) << 24);
877
878 result
882}
883
884fn HUF_buildDEltX2(symbol: u8, nbBits: u32, baseSeq: u16, level: core::ffi::c_int) -> HUF_DEltX2 {
885 HUF_DEltX2::from_u32(HUF_buildDEltX2U32(
886 symbol as u32,
887 nbBits,
888 baseSeq as u32,
889 level,
890 ))
891}
892
893fn HUF_fillDTableX2ForWeight(
894 DTableRank: &mut [HUF_DEltX2],
895 sorted_symbols: &[sortedSymbol_t],
896 nbBits: u32,
897 tableLog: u32,
898 baseSeq: u16,
899 level: core::ffi::c_int,
900) {
901 let length = (1) << (tableLog.wrapping_sub(nbBits) & 0x1f);
902 let chunks = DTableRank[..sorted_symbols.len() * length].chunks_exact_mut(length);
903
904 for (sorted_symbol, chunk) in sorted_symbols.iter().zip(chunks) {
905 let DElt = HUF_buildDEltX2(sorted_symbol.symbol, nbBits, baseSeq, level);
906 chunk.fill(DElt);
907 }
908}
909
910fn HUF_fillDTableX2Level2(
911 DTable: &mut [HUF_DEltX2],
912 targetLog: u32,
913 consumedBits: u32,
914 rankVal: &[u32; 13],
915 minWeight: core::ffi::c_int,
916 maxWeight1: core::ffi::c_int,
917 sortedSymbols: &[sortedSymbol_t],
918 rankStart: &[u32; 15],
919 nbBitsBaseline: u32,
920 baseSeq: u16,
921) {
922 if minWeight > 1 {
923 let length = 1 << (targetLog.wrapping_sub(consumedBits) & 0x1f);
924 let elem = HUF_DEltX2::from_u32(HUF_buildDEltX2U32(baseSeq as u32, consumedBits, 0, 1));
925 let skipSize = rankVal[minWeight as usize];
926 match length {
927 2 => {
928 DTable[..2].fill(elem);
929 }
930 4 => {
931 DTable[..4].fill(elem);
932 }
933 _ => {
934 for i in (0..skipSize as usize).step_by(8) {
935 DTable[i..][..8].fill(elem);
936 }
937 }
938 }
939 }
940
941 for w in minWeight as usize..maxWeight1 as usize {
942 let nbBits = nbBitsBaseline.wrapping_sub(w as u32);
943 let totalBits = nbBits.wrapping_add(consumedBits);
944
945 HUF_fillDTableX2ForWeight(
946 &mut DTable[rankVal[w] as usize..],
947 &sortedSymbols[rankStart[w] as usize..rankStart[w + 1] as usize],
948 totalBits,
949 targetLog,
950 baseSeq,
951 2,
952 );
953 }
954}
955
956fn HUF_fillDTableX2(
957 DTable: &mut [HUF_DEltX2; 4096],
958 targetLog: u32,
959 sortedList: &[sortedSymbol_t; 256],
960 rankStart: &[u32; 15],
961 rankValOrigin: &mut [rankValCol_t; 12],
962 maxWeight: u32,
963 nbBitsBaseline: u32,
964) {
965 let rankVal = rankValOrigin[0];
966 let scaleLog = nbBitsBaseline.wrapping_sub(targetLog) as core::ffi::c_int;
967 let minBits = nbBitsBaseline.wrapping_sub(maxWeight);
968
969 let wEnd = maxWeight as core::ffi::c_int + 1;
970 for w in 1..wEnd as usize {
971 let range = rankStart[w] as usize..rankStart[w + 1] as usize;
972
973 let nbBits = nbBitsBaseline.wrapping_sub(w as u32);
974 if targetLog.wrapping_sub(nbBits) >= minBits {
975 let mut start = rankVal[w] as core::ffi::c_int;
976 let length = (1) << (targetLog.wrapping_sub(nbBits) & 0x1f as core::ffi::c_int as u32);
977 let minWeight = Ord::max(nbBits.wrapping_add(scaleLog as u32) as core::ffi::c_int, 1);
978
979 for s in range {
980 HUF_fillDTableX2Level2(
981 &mut DTable[start as usize..],
982 targetLog,
983 nbBits,
984 &rankValOrigin[nbBits as usize],
985 minWeight,
986 wEnd,
987 sortedList,
988 rankStart,
989 nbBitsBaseline,
990 u16::from(sortedList[s].symbol),
991 );
992 start = (start as u32).wrapping_add(length) as core::ffi::c_int as core::ffi::c_int;
993 }
994 } else {
995 HUF_fillDTableX2ForWeight(
996 &mut DTable[rankVal[w] as usize..],
997 &sortedList[range],
998 nbBits,
999 targetLog,
1000 0,
1001 1,
1002 );
1003 }
1004 }
1005}
1006
1007pub fn HUF_readDTableX2_wksp(
1008 DTable: &mut DTable,
1009 src: &[u8],
1010 wksp: &mut HUF_ReadDTableX2_Workspace,
1011 flags: core::ffi::c_int,
1012) -> size_t {
1013 let mut dtd = DTable.description;
1014
1015 let mut tableLog: u32 = 0;
1016 let mut nbSymbols: u32 = 0;
1017 let mut maxTableLog = dtd.maxTableLog as u32;
1018 let mut iSize: size_t = 0;
1019
1020 let dt = DTable.data.as_x2_mut();
1021
1022 wksp.rankStats.fill(0);
1023 wksp.rankStart0.fill(0);
1024 let rankStart = &mut wksp.rankStart0[1..];
1025
1026 if maxTableLog > HUF_TABLELOG_MAX as u32 {
1027 return Error::tableLog_tooLarge.to_error_code();
1028 }
1029
1030 iSize = HUF_readStats_wksp(
1031 &mut wksp.weightList,
1032 (HUF_SYMBOLVALUE_MAX + 1) as size_t,
1033 &mut wksp.rankStats,
1034 &mut nbSymbols,
1035 &mut tableLog,
1036 src,
1037 &mut wksp.calleeWksp,
1038 flags,
1039 );
1040 if ERR_isError(iSize) {
1041 return iSize;
1042 }
1043 if tableLog > maxTableLog {
1044 return Error::tableLog_tooLarge.to_error_code();
1045 }
1046 if tableLog <= HUF_DECODER_FAST_TABLELOG as u32
1047 && maxTableLog > HUF_DECODER_FAST_TABLELOG as u32
1048 {
1049 maxTableLog = HUF_DECODER_FAST_TABLELOG as u32;
1050 }
1051
1052 let mut maxW: u32 = tableLog;
1054 while wksp.rankStats[maxW as usize] == 0 {
1055 maxW = maxW.wrapping_sub(1);
1056 }
1057
1058 let mut nextRankStart = 0u32;
1060 for w in 1..maxW + 1 {
1061 let curr = nextRankStart;
1062 nextRankStart += wksp.rankStats[w as usize];
1063 rankStart[w as usize] = curr;
1064 }
1065
1066 rankStart[0] = nextRankStart;
1067 rankStart[maxW.wrapping_add(1) as usize] = nextRankStart;
1068
1069 for s in 0..nbSymbols {
1071 let w = usize::from(wksp.weightList[s as usize]);
1072 let r = rankStart[w];
1073 rankStart[w] += 1;
1074 wksp.sortedSymbol[r as usize].symbol = s as u8;
1075 }
1076
1077 rankStart[0] = 0;
1079
1080 let rescale = maxTableLog.wrapping_sub(tableLog).wrapping_sub(1) as core::ffi::c_int;
1082 let mut nextRankVal = 0u32;
1083
1084 for w_1 in 1..maxW.wrapping_add(1) {
1085 let curr_0 = nextRankVal;
1086 nextRankVal = nextRankVal
1087 .wrapping_add(wksp.rankStats[w_1 as usize] << w_1.wrapping_add(rescale as u32));
1088
1089 wksp.rankVal[0][w_1 as usize] = curr_0;
1090 }
1091
1092 let minBits = tableLog.wrapping_add(1).wrapping_sub(maxW);
1093 let mut consumed: u32 = 0;
1094 consumed = minBits;
1095 while consumed < maxTableLog.wrapping_sub(minBits).wrapping_add(1) {
1096 for w_2 in 0..maxW.wrapping_add(1) {
1097 wksp.rankVal[consumed as usize][w_2 as usize] =
1098 wksp.rankVal[0][w_2 as usize] >> consumed;
1099 }
1100 consumed = consumed.wrapping_add(1);
1101 }
1102
1103 HUF_fillDTableX2(
1104 dt,
1105 maxTableLog,
1106 &wksp.sortedSymbol,
1107 &wksp.rankStart0,
1108 &mut wksp.rankVal,
1109 maxW,
1110 tableLog.wrapping_add(1),
1111 );
1112
1113 dtd.tableLog = maxTableLog as u8;
1114 dtd.tableType = 1;
1115
1116 DTable.description = dtd;
1117
1118 iSize
1119}
1120
1121#[inline(always)]
1122unsafe fn HUF_decodeSymbolX2(
1123 w: &mut Writer<'_>,
1124 DStream: &mut BIT_DStream_t,
1125 dt: &[HUF_DEltX2; 4096],
1126 dtLog: u32,
1127) {
1128 let HUF_DEltX2 {
1129 sequence,
1130 nbBits,
1131 length,
1132 } = dt[DStream.look_bits_fast(dtLog)];
1133
1134 DStream.skip_bits(nbBits as u32);
1135 w.write_symbol_x2(sequence, length);
1136}
1137
1138#[inline(always)]
1139fn HUF_decodeLastSymbolX2(
1140 w: &mut Writer<'_>,
1141 DStream: &mut BIT_DStream_t,
1142 dt: &[HUF_DEltX2; 4096],
1143 dtLog: u32,
1144) {
1145 let HUF_DEltX2 {
1146 sequence,
1147 nbBits,
1148 length,
1149 } = dt[DStream.look_bits_fast(dtLog)];
1150
1151 w.write_u8(sequence.to_le_bytes()[0]);
1152
1153 if length == 1 {
1154 DStream.skip_bits(u32::from(nbBits));
1155 } else if (DStream.bitsConsumed as usize) < BitContainerType::BITS as usize {
1156 DStream.skip_bits(u32::from(nbBits));
1157 DStream.bitsConsumed = Ord::min(DStream.bitsConsumed, BitContainerType::BITS);
1158 }
1159}
1160
1161macro_rules! HUF_DECODE_SYMBOLX2_0 {
1162 ($($args:expr),*) => {
1163 HUF_decodeSymbolX2($($args),*)
1164 }
1165}
1166
1167macro_rules! HUF_DECODE_SYMBOLX2_1 {
1168 ($($args:expr),*) => {
1169 if cfg!(target_pointer_width = "64") || HUF_TABLELOG_MAX <= 12 {
1170 HUF_decodeSymbolX2($($args),*)
1171 }
1172 }
1173}
1174
1175macro_rules! HUF_DECODE_SYMBOLX2_2 {
1176 ($($args:expr),*) => {
1177 if cfg!(target_pointer_width = "64") {
1178 HUF_decodeSymbolX2($($args),*)
1179 }
1180 }
1181}
1182
1183#[inline(always)]
1184unsafe fn HUF_decodeStreamX2(
1185 mut p: Writer<'_>,
1186 bitDPtr: &mut BIT_DStream_t,
1187 dt: &[HUF_DEltX2; 4096],
1188 dtLog: u32,
1189) -> size_t {
1190 let capacity = p.capacity();
1191
1192 if p.capacity() >= size_of::<usize>() {
1194 if dtLog <= 11 && cfg!(target_pointer_width = "64") {
1195 while (bitDPtr.reload() == StreamStatus::Unfinished) && p.capacity() >= 10 {
1197 HUF_DECODE_SYMBOLX2_0!(&mut p, bitDPtr, dt, dtLog);
1198 HUF_DECODE_SYMBOLX2_0!(&mut p, bitDPtr, dt, dtLog);
1199 HUF_DECODE_SYMBOLX2_0!(&mut p, bitDPtr, dt, dtLog);
1200 HUF_DECODE_SYMBOLX2_0!(&mut p, bitDPtr, dt, dtLog);
1201 HUF_DECODE_SYMBOLX2_0!(&mut p, bitDPtr, dt, dtLog);
1202 }
1203 } else {
1204 while bitDPtr.reload() == StreamStatus::Unfinished && p.capacity() >= size_of::<usize>()
1206 {
1207 HUF_DECODE_SYMBOLX2_2!(&mut p, bitDPtr, dt, dtLog);
1208 HUF_DECODE_SYMBOLX2_1!(&mut p, bitDPtr, dt, dtLog);
1209 HUF_DECODE_SYMBOLX2_2!(&mut p, bitDPtr, dt, dtLog);
1210 HUF_DECODE_SYMBOLX2_0!(&mut p, bitDPtr, dt, dtLog);
1211 }
1212 }
1213 } else {
1214 bitDPtr.reload();
1215 }
1216
1217 if p.capacity() >= 2 {
1219 while (bitDPtr.reload() == StreamStatus::Unfinished) && p.capacity() >= 2 {
1220 HUF_DECODE_SYMBOLX2_0!(&mut p, bitDPtr, dt, dtLog);
1221 }
1222
1223 while p.capacity() >= 2 {
1224 HUF_DECODE_SYMBOLX2_0!(&mut p, bitDPtr, dt, dtLog);
1225 }
1226 }
1227
1228 if !p.is_empty() {
1229 HUF_decodeLastSymbolX2(&mut p, bitDPtr, dt, dtLog);
1230 }
1231
1232 capacity - p.capacity()
1233}
1234
1235#[inline(always)]
1236unsafe fn HUF_decompress1X2_usingDTable_internal_body(
1237 mut dst: Writer<'_>,
1238 src: &[u8],
1239 DTable: &DTable,
1240) -> size_t {
1241 let mut bitD = match BIT_DStream_t::new(src) {
1242 Ok(v) => v,
1243 Err(e) => return e.to_error_code(),
1244 };
1245
1246 let dt = DTable.data.as_x2();
1247 let dtd = DTable.description;
1248 HUF_decodeStreamX2(dst.subslice(..), &mut bitD, dt, dtd.tableLog as u32);
1249 if !bitD.is_empty() {
1250 return Error::corruption_detected.to_error_code();
1251 }
1252
1253 dst.capacity()
1254}
1255
1256#[inline(always)]
1257unsafe fn HUF_decompress4X2_usingDTable_internal_body(
1258 mut dst: Writer<'_>,
1259 src: &[u8],
1260 DTable: &DTable,
1261) -> size_t {
1262 let [b0, b1, b2, b3, b4, b5, _, _, _, _, ..] = *src else {
1264 return Error::corruption_detected.to_error_code();
1265 };
1266
1267 if dst.capacity() < 6 {
1269 return Error::corruption_detected.to_error_code();
1270 }
1271
1272 let length1 = usize::from(u16::from_le_bytes([b0, b1]));
1273 let length2 = usize::from(u16::from_le_bytes([b2, b3]));
1274 let length3 = usize::from(u16::from_le_bytes([b4, b5]));
1275
1276 if 6 + length1 + length2 + length3 > src.len() {
1277 return Error::corruption_detected.to_error_code();
1278 }
1279
1280 let istart1 = &src[6..][..length1];
1281 let istart2 = &src[6 + length1..][..length2];
1282 let istart3 = &src[6 + length1 + length2..][..length3];
1283 let istart4 = &src[6 + length1 + length2 + length3..];
1284
1285 let Some((mut op1, mut op2, mut op3, mut op4)) = dst.quarter() else {
1286 return Error::corruption_detected.to_error_code();
1287 };
1288
1289 let mut end_signal = true;
1290
1291 let dtLog = DTable.description.tableLog as u32;
1292
1293 if op4.is_empty() {
1294 return Error::corruption_detected.to_error_code();
1295 }
1296
1297 let mut bitD1 = match BIT_DStream_t::new(istart1) {
1298 Ok(v) => v,
1299 Err(e) => return e.to_error_code(),
1300 };
1301 let mut bitD2 = match BIT_DStream_t::new(istart2) {
1302 Ok(v) => v,
1303 Err(e) => return e.to_error_code(),
1304 };
1305 let mut bitD3 = match BIT_DStream_t::new(istart3) {
1306 Ok(v) => v,
1307 Err(e) => return e.to_error_code(),
1308 };
1309 let mut bitD4 = match BIT_DStream_t::new(istart4) {
1310 Ok(v) => v,
1311 Err(e) => return e.to_error_code(),
1312 };
1313
1314 let dt = DTable.data.as_x2();
1315
1316 if op4.capacity() >= size_of::<usize>() {
1318 while end_signal && op4.capacity() >= size_of::<usize>() {
1319 if cfg!(any(target_arch = "x86_64", target_arch = "x86")) {
1320 HUF_DECODE_SYMBOLX2_2!(&mut op1, &mut bitD1, dt, dtLog);
1321 HUF_DECODE_SYMBOLX2_1!(&mut op1, &mut bitD1, dt, dtLog);
1322 HUF_DECODE_SYMBOLX2_2!(&mut op1, &mut bitD1, dt, dtLog);
1323 HUF_DECODE_SYMBOLX2_0!(&mut op1, &mut bitD1, dt, dtLog);
1324 HUF_DECODE_SYMBOLX2_2!(&mut op2, &mut bitD2, dt, dtLog);
1325 HUF_DECODE_SYMBOLX2_1!(&mut op2, &mut bitD2, dt, dtLog);
1326 HUF_DECODE_SYMBOLX2_2!(&mut op2, &mut bitD2, dt, dtLog);
1327 HUF_DECODE_SYMBOLX2_0!(&mut op2, &mut bitD2, dt, dtLog);
1328
1329 end_signal &= bitD1.reload_fast() == StreamStatus::Unfinished;
1330 end_signal &= bitD2.reload_fast() == StreamStatus::Unfinished;
1331
1332 HUF_DECODE_SYMBOLX2_2!(&mut op3, &mut bitD3, dt, dtLog);
1333 HUF_DECODE_SYMBOLX2_1!(&mut op3, &mut bitD3, dt, dtLog);
1334 HUF_DECODE_SYMBOLX2_2!(&mut op3, &mut bitD3, dt, dtLog);
1335 HUF_DECODE_SYMBOLX2_0!(&mut op3, &mut bitD3, dt, dtLog);
1336 HUF_DECODE_SYMBOLX2_2!(&mut op4, &mut bitD4, dt, dtLog);
1337 HUF_DECODE_SYMBOLX2_1!(&mut op4, &mut bitD4, dt, dtLog);
1338 HUF_DECODE_SYMBOLX2_2!(&mut op4, &mut bitD4, dt, dtLog);
1339 HUF_DECODE_SYMBOLX2_0!(&mut op4, &mut bitD4, dt, dtLog);
1340
1341 end_signal &= bitD3.reload_fast() == StreamStatus::Unfinished;
1342 end_signal &= bitD4.reload_fast() == StreamStatus::Unfinished;
1343 } else {
1344 HUF_DECODE_SYMBOLX2_2!(&mut op1, &mut bitD1, dt, dtLog);
1345 HUF_DECODE_SYMBOLX2_2!(&mut op2, &mut bitD2, dt, dtLog);
1346 HUF_DECODE_SYMBOLX2_2!(&mut op3, &mut bitD3, dt, dtLog);
1347 HUF_DECODE_SYMBOLX2_2!(&mut op4, &mut bitD4, dt, dtLog);
1348 HUF_DECODE_SYMBOLX2_1!(&mut op1, &mut bitD1, dt, dtLog);
1349 HUF_DECODE_SYMBOLX2_1!(&mut op2, &mut bitD2, dt, dtLog);
1350 HUF_DECODE_SYMBOLX2_1!(&mut op3, &mut bitD3, dt, dtLog);
1351 HUF_DECODE_SYMBOLX2_1!(&mut op4, &mut bitD4, dt, dtLog);
1352 HUF_DECODE_SYMBOLX2_2!(&mut op1, &mut bitD1, dt, dtLog);
1353 HUF_DECODE_SYMBOLX2_2!(&mut op2, &mut bitD2, dt, dtLog);
1354 HUF_DECODE_SYMBOLX2_2!(&mut op3, &mut bitD3, dt, dtLog);
1355 HUF_DECODE_SYMBOLX2_2!(&mut op4, &mut bitD4, dt, dtLog);
1356 HUF_DECODE_SYMBOLX2_0!(&mut op1, &mut bitD1, dt, dtLog);
1357 HUF_DECODE_SYMBOLX2_0!(&mut op2, &mut bitD2, dt, dtLog);
1358 HUF_DECODE_SYMBOLX2_0!(&mut op3, &mut bitD3, dt, dtLog);
1359 HUF_DECODE_SYMBOLX2_0!(&mut op4, &mut bitD4, dt, dtLog);
1360
1361 end_signal &= bitD1.reload_fast() == StreamStatus::Unfinished;
1362 end_signal &= bitD2.reload_fast() == StreamStatus::Unfinished;
1363 end_signal &= bitD3.reload_fast() == StreamStatus::Unfinished;
1364 end_signal &= bitD4.reload_fast() == StreamStatus::Unfinished;
1365 }
1366 }
1367 }
1368
1369 if op1.ptr.unwrap().as_ptr() > op1.end {
1373 return Error::corruption_detected.to_error_code();
1374 }
1375 if op2.ptr.unwrap().as_ptr() > op2.end {
1376 return Error::corruption_detected.to_error_code();
1377 }
1378 if op3.ptr.unwrap().as_ptr() > op3.end {
1379 return Error::corruption_detected.to_error_code();
1380 }
1381 HUF_decodeStreamX2(op1, &mut bitD1, dt, dtLog);
1385 HUF_decodeStreamX2(op2, &mut bitD2, dt, dtLog);
1386 HUF_decodeStreamX2(op3, &mut bitD3, dt, dtLog);
1387 HUF_decodeStreamX2(op4, &mut bitD4, dt, dtLog);
1388
1389 if !(bitD1.is_empty() && bitD2.is_empty() && bitD3.is_empty() && bitD4.is_empty()) {
1391 return Error::corruption_detected.to_error_code();
1392 }
1393
1394 dst.capacity()
1396}
1397
1398unsafe fn HUF_decompress4X2_usingDTable_internal_bmi2(
1399 dst: Writer<'_>,
1400 src: &[u8],
1401 DTable: &DTable,
1402) -> size_t {
1403 HUF_decompress4X2_usingDTable_internal_body(dst, src, DTable)
1404}
1405
1406unsafe fn HUF_decompress4X2_usingDTable_internal_default(
1407 dst: Writer<'_>,
1408 src: &[u8],
1409 DTable: &DTable,
1410) -> size_t {
1411 HUF_decompress4X2_usingDTable_internal_body(dst, src, DTable)
1412}
1413
1414unsafe extern "C" fn HUF_decompress4X2_usingDTable_internal_fast_c_loop(
1415 args: &mut HUF_DecompressFastArgs,
1416) {
1417 let dtable: &[HUF_DEltX2; 4096] = core::mem::transmute(args.dt);
1418 let ilowest = args.ilowest;
1419
1420 let mut bits = args.bits;
1421 let mut ip = args.ip;
1422 let mut op = args.op;
1423
1424 let mut oend: [*mut u8; 4] = [core::ptr::null_mut::<u8>(); 4];
1425 oend[0] = op[1];
1426 oend[1] = op[2];
1427 oend[2] = op[3];
1428 oend[3] = args.oend;
1429
1430 'out: loop {
1431 let mut olimit = core::ptr::null_mut::<u8>();
1432
1433 if cfg!(debug_assertions) {
1435 for stream in 0..4 {
1436 assert!(op[stream] <= oend[stream]);
1437 assert!(ip[stream] >= ilowest);
1438 }
1439 }
1440
1441 let mut iters = ip[0].offset_from(ilowest) as size_t / 7;
1452
1453 for stream in 0..4 {
1458 let oiters = oend[stream].offset_from(op[stream]) as size_t / 10;
1459 iters = Ord::min(iters, oiters);
1460 }
1461
1462 olimit = op[3].add(iters * 5);
1469
1470 if op[3] == olimit {
1472 break;
1473 }
1474
1475 for stream in 1..4 {
1480 if ip[stream] < ip[stream - 1] {
1481 break 'out;
1482 }
1483 }
1484
1485 for stream in 1..4 {
1486 assert!(ip[stream] >= ip[stream - 1]);
1487 }
1488
1489 macro_rules! HUF_4X2_DECODE_SYMBOL {
1490 ($stream:expr, $decode3:expr) => {
1491 if (($decode3) != 0 || ($stream) != 3) {
1492 let index = (bits[($stream)] >> 53);
1493 let entry = dtable[index as usize];
1494 MEM_write16(op[($stream)].cast(), entry.sequence);
1495 bits[($stream)] <<= (entry.nbBits) & 0x3F;
1496 op[($stream)] = op[($stream)].add(usize::from(entry.length));
1497 }
1498 };
1499 }
1500
1501 macro_rules! HUF_4X2_RELOAD_STREAM {
1502 ($stream:expr) => {
1503 HUF_4X2_DECODE_SYMBOL!(3, 1);
1504 {
1505 let ctz = bits[($stream)].trailing_zeros();
1506 let nbBits = ctz & 7;
1507 let nbBytes = ctz >> 3;
1508 ip[($stream)] = ip[$stream].sub(nbBytes as usize);
1509 bits[($stream)] = MEM_read64(ip[($stream)].cast()) | 1;
1510 bits[($stream)] <<= nbBits;
1511 }
1512 };
1513 }
1514
1515 loop {
1520 HUF_4X_FOR_EACH_STREAM_WITH_VAR!(HUF_4X2_DECODE_SYMBOL, 0);
1525 HUF_4X_FOR_EACH_STREAM_WITH_VAR!(HUF_4X2_DECODE_SYMBOL, 0);
1526 HUF_4X_FOR_EACH_STREAM_WITH_VAR!(HUF_4X2_DECODE_SYMBOL, 0);
1527 HUF_4X_FOR_EACH_STREAM_WITH_VAR!(HUF_4X2_DECODE_SYMBOL, 0);
1528 HUF_4X_FOR_EACH_STREAM_WITH_VAR!(HUF_4X2_DECODE_SYMBOL, 0);
1529
1530 HUF_4X2_DECODE_SYMBOL!(3, 1);
1532
1533 HUF_4X_FOR_EACH_STREAM!(HUF_4X2_RELOAD_STREAM);
1538
1539 if op[3] >= olimit {
1540 break;
1541 }
1542 }
1543 }
1544
1545 args.bits = bits;
1547 args.ip = ip;
1548 args.op = op;
1549}
1550
1551unsafe fn HUF_decompress4X2_usingDTable_internal_fast(
1552 mut dst: Writer<'_>,
1553 src: &[u8],
1554 DTable: &DTable,
1555 loopFn: HUF_DecompressFastLoopFn,
1556) -> size_t {
1557 let oend = dst.as_mut_ptr_range().end;
1558
1559 let mut args = match HUF_DecompressFastArgs::new(dst.subslice(..), src, DTable) {
1560 Ok(Some(args)) => args,
1561 Ok(None) => return 0,
1562 Err(e) => return e.to_error_code(),
1563 };
1564
1565 assert!(args.ip[0] >= args.ilowest);
1566 loopFn(&mut args);
1567
1568 let ilowest = src.as_ptr();
1570 assert!(args.ip[0] >= ilowest);
1571 assert!(args.ip[1] >= ilowest);
1572 assert!(args.ip[2] >= ilowest);
1573 assert!(args.ip[3] >= ilowest);
1574 assert!(args.op[3] <= oend);
1575
1576 assert_eq!(ilowest, args.ilowest);
1577 assert_eq!(ilowest.add(6), args.iend[0]);
1578
1579 let segmentSize = dst.capacity().div_ceil(4) as isize;
1580 let mut segmentEnd = dst.as_mut_ptr();
1581
1582 for (i, op) in args.op.iter().copied().enumerate() {
1583 if segmentSize <= oend.offset_from(segmentEnd) {
1584 segmentEnd = segmentEnd.offset(segmentSize);
1585 } else {
1586 segmentEnd = oend;
1587 }
1588
1589 let mut bit = match init_remaining_dstream(&args, i, segmentEnd) {
1590 Ok(v) => v,
1591 Err(e) => return e.to_error_code(),
1592 };
1593
1594 let length = HUF_decodeStreamX2(
1595 Writer::from_raw_parts(op, segmentEnd as usize - op as usize),
1596 &mut bit,
1597 DTable.data.as_x2(),
1598 HUF_DECODER_FAST_TABLELOG as u32,
1599 );
1600
1601 if op.add(length as usize) != segmentEnd {
1602 return Error::corruption_detected.to_error_code();
1603 }
1604 }
1605
1606 dst.capacity()
1607}
1608
1609unsafe fn HUF_decompress4X2_usingDTable_internal(
1610 mut dst: Writer<'_>,
1611 src: &[u8],
1612 DTable: &DTable,
1613 flags: core::ffi::c_int,
1614) -> size_t {
1615 if flags & HUF_flags_bmi2 as core::ffi::c_int != 0 {
1616 let loopFn = match flags & HUF_flags_disableAsm as core::ffi::c_int {
1617 #[cfg(target_arch = "x86_64")]
1618 0 => HUF_decompress4X2_usingDTable_internal_fast_asm_loop as HUF_DecompressFastLoopFn,
1619 _ => HUF_decompress4X2_usingDTable_internal_fast_c_loop as HUF_DecompressFastLoopFn,
1620 };
1621
1622 if HUF_ENABLE_FAST_DECODE != 0 && flags & HUF_flags_disableFast as core::ffi::c_int == 0 {
1623 let ret =
1624 HUF_decompress4X2_usingDTable_internal_fast(dst.subslice(..), src, DTable, loopFn);
1625 if ret != 0 {
1626 return ret;
1627 }
1628 }
1629
1630 HUF_decompress4X2_usingDTable_internal_bmi2(dst, src, DTable)
1631 } else {
1632 HUF_decompress4X2_usingDTable_internal_default(dst, src, DTable)
1633 }
1634}
1635
1636unsafe fn HUF_decompress1X2_usingDTable_internal_bmi2(
1637 dst: Writer<'_>,
1638 src: &[u8],
1639 DTable: &DTable,
1640) -> size_t {
1641 HUF_decompress1X2_usingDTable_internal_body(dst, src, DTable)
1642}
1643unsafe fn HUF_decompress1X2_usingDTable_internal_default(
1644 dst: Writer<'_>,
1645 src: &[u8],
1646 DTable: &DTable,
1647) -> size_t {
1648 HUF_decompress1X2_usingDTable_internal_body(dst, src, DTable)
1649}
1650
1651unsafe fn HUF_decompress1X2_usingDTable_internal(
1652 dst: Writer<'_>,
1653 src: &[u8],
1654 DTable: &DTable,
1655 flags: core::ffi::c_int,
1656) -> size_t {
1657 if flags & HUF_flags_bmi2 as core::ffi::c_int != 0 {
1658 HUF_decompress1X2_usingDTable_internal_bmi2(dst, src, DTable)
1659 } else {
1660 HUF_decompress1X2_usingDTable_internal_default(dst, src, DTable)
1661 }
1662}
1663
1664pub unsafe fn HUF_decompress1X2_DCtx_wksp(
1665 dctx: &mut DTable,
1666 dst: Writer<'_>,
1667 src: &[u8],
1668 workSpace: &mut Workspace,
1669 flags: core::ffi::c_int,
1670) -> size_t {
1671 let hSize = HUF_readDTableX2_wksp(dctx, src, workSpace.as_x2_mut(), flags);
1672 if ERR_isError(hSize) {
1673 return hSize;
1674 }
1675 if hSize as usize >= src.len() {
1676 return Error::srcSize_wrong.to_error_code();
1677 }
1678
1679 HUF_decompress1X2_usingDTable_internal(dst, &src[hSize as usize..], dctx, flags)
1680}
1681
1682unsafe fn HUF_decompress4X2_DCtx_wksp(
1683 dctx: &mut DTable,
1684 dst: Writer<'_>,
1685 src: &[u8],
1686 workSpace: &mut Workspace,
1687 flags: core::ffi::c_int,
1688) -> size_t {
1689 let hSize = HUF_readDTableX2_wksp(dctx, src, workSpace.as_x2_mut(), flags);
1690 if ERR_isError(hSize) {
1691 return hSize;
1692 }
1693 if hSize as usize >= src.len() {
1694 return Error::srcSize_wrong.to_error_code();
1695 }
1696
1697 HUF_decompress4X2_usingDTable_internal(dst, &src[hSize as usize..], dctx, flags)
1698}
1699
1700static algoTime: [[algo_time_t; 2]; 16] = [
1701 [
1702 {
1703 algo_time_t {
1704 tableTime: 0,
1705 decode256Time: 0,
1706 }
1707 },
1708 {
1709 algo_time_t {
1710 tableTime: 1,
1711 decode256Time: 1,
1712 }
1713 },
1714 ],
1715 [
1716 {
1717 algo_time_t {
1718 tableTime: 0,
1719 decode256Time: 0,
1720 }
1721 },
1722 {
1723 algo_time_t {
1724 tableTime: 1,
1725 decode256Time: 1,
1726 }
1727 },
1728 ],
1729 [
1730 {
1731 algo_time_t {
1732 tableTime: 150,
1733 decode256Time: 216,
1734 }
1735 },
1736 {
1737 algo_time_t {
1738 tableTime: 381,
1739 decode256Time: 119,
1740 }
1741 },
1742 ],
1743 [
1744 {
1745 algo_time_t {
1746 tableTime: 170,
1747 decode256Time: 205,
1748 }
1749 },
1750 {
1751 algo_time_t {
1752 tableTime: 514,
1753 decode256Time: 112,
1754 }
1755 },
1756 ],
1757 [
1758 {
1759 algo_time_t {
1760 tableTime: 177,
1761 decode256Time: 199,
1762 }
1763 },
1764 {
1765 algo_time_t {
1766 tableTime: 539,
1767 decode256Time: 110,
1768 }
1769 },
1770 ],
1771 [
1772 {
1773 algo_time_t {
1774 tableTime: 197,
1775 decode256Time: 194,
1776 }
1777 },
1778 {
1779 algo_time_t {
1780 tableTime: 644,
1781 decode256Time: 107,
1782 }
1783 },
1784 ],
1785 [
1786 {
1787 algo_time_t {
1788 tableTime: 221,
1789 decode256Time: 192,
1790 }
1791 },
1792 {
1793 algo_time_t {
1794 tableTime: 735,
1795 decode256Time: 107,
1796 }
1797 },
1798 ],
1799 [
1800 {
1801 algo_time_t {
1802 tableTime: 256,
1803 decode256Time: 189,
1804 }
1805 },
1806 {
1807 algo_time_t {
1808 tableTime: 881,
1809 decode256Time: 106,
1810 }
1811 },
1812 ],
1813 [
1814 {
1815 algo_time_t {
1816 tableTime: 359,
1817 decode256Time: 188,
1818 }
1819 },
1820 {
1821 algo_time_t {
1822 tableTime: 1167,
1823 decode256Time: 109,
1824 }
1825 },
1826 ],
1827 [
1828 {
1829 algo_time_t {
1830 tableTime: 582,
1831 decode256Time: 187,
1832 }
1833 },
1834 {
1835 algo_time_t {
1836 tableTime: 1570,
1837 decode256Time: 114,
1838 }
1839 },
1840 ],
1841 [
1842 {
1843 algo_time_t {
1844 tableTime: 688,
1845 decode256Time: 187,
1846 }
1847 },
1848 {
1849 algo_time_t {
1850 tableTime: 1712,
1851 decode256Time: 122,
1852 }
1853 },
1854 ],
1855 [
1856 {
1857 algo_time_t {
1858 tableTime: 825,
1859 decode256Time: 186,
1860 }
1861 },
1862 {
1863 algo_time_t {
1864 tableTime: 1965,
1865 decode256Time: 136,
1866 }
1867 },
1868 ],
1869 [
1870 {
1871 algo_time_t {
1872 tableTime: 976,
1873 decode256Time: 185,
1874 }
1875 },
1876 {
1877 algo_time_t {
1878 tableTime: 2131,
1879 decode256Time: 150,
1880 }
1881 },
1882 ],
1883 [
1884 {
1885 algo_time_t {
1886 tableTime: 1180,
1887 decode256Time: 186,
1888 }
1889 },
1890 {
1891 algo_time_t {
1892 tableTime: 2070,
1893 decode256Time: 175,
1894 }
1895 },
1896 ],
1897 [
1898 {
1899 algo_time_t {
1900 tableTime: 1377,
1901 decode256Time: 185,
1902 }
1903 },
1904 {
1905 algo_time_t {
1906 tableTime: 1731,
1907 decode256Time: 202,
1908 }
1909 },
1910 ],
1911 [
1912 {
1913 algo_time_t {
1914 tableTime: 1412,
1915 decode256Time: 185,
1916 }
1917 },
1918 {
1919 algo_time_t {
1920 tableTime: 1695,
1921 decode256Time: 202,
1922 }
1923 },
1924 ],
1925];
1926
1927enum Decoder {
1928 A1,
1929 A2,
1930}
1931
1932fn HUF_selectDecoder(dst_size: usize, src_size: usize) -> Decoder {
1938 let D256 = (dst_size >> 8) as u32;
1939
1940 let Q = if src_size >= dst_size {
1941 15
1942 } else {
1943 src_size * 16 / dst_size
1944 };
1945
1946 let [time0, time1] = algoTime[Q];
1947 let DTime0 = time0.tableTime + time0.decode256Time * D256;
1948 let DTime1 = time1.tableTime + time1.decode256Time * D256;
1949
1950 if (DTime1 + (DTime1 >> 5)) < DTime0 {
1951 Decoder::A2
1952 } else {
1953 Decoder::A1
1954 }
1955}
1956
1957pub unsafe fn HUF_decompress1X_DCtx_wksp(
1958 dctx: &mut DTable,
1959 mut dst: Writer<'_>,
1960 src: &[u8],
1961 workSpace: &mut Workspace,
1962 flags: core::ffi::c_int,
1963) -> size_t {
1964 if dst.capacity() == 0 {
1965 return Error::dstSize_tooSmall.to_error_code();
1966 }
1967 if src.len() > dst.capacity() {
1968 return Error::corruption_detected.to_error_code();
1969 }
1970 if src.len() == dst.capacity() {
1971 ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), dst.capacity());
1972 return dst.capacity();
1973 }
1974 if src.len() == 1 {
1975 ptr::write_bytes(dst.as_mut_ptr(), src[0], dst.capacity());
1976 return dst.capacity();
1977 }
1978
1979 match HUF_selectDecoder(dst.capacity(), src.len()) {
1980 Decoder::A1 => HUF_decompress1X1_DCtx_wksp(dctx, dst, src, workSpace, flags),
1981 Decoder::A2 => HUF_decompress1X2_DCtx_wksp(dctx, dst, src, workSpace, flags),
1982 }
1983}
1984
1985pub unsafe fn HUF_decompress1X_usingDTable(
1986 dst: Writer<'_>,
1987 src: &[u8],
1988 DTable: &DTable,
1989 flags: core::ffi::c_int,
1990) -> size_t {
1991 if DTable.description.tableType != 0 {
1992 HUF_decompress1X2_usingDTable_internal(dst, src, DTable, flags)
1993 } else {
1994 HUF_decompress1X1_usingDTable_internal(dst, src, DTable, flags)
1995 }
1996}
1997
1998pub unsafe fn HUF_decompress1X1_DCtx_wksp(
1999 dctx: &mut DTable,
2000 dst: Writer<'_>,
2001 src: &[u8],
2002 workSpace: &mut Workspace,
2003 flags: core::ffi::c_int,
2004) -> size_t {
2005 let hSize = { HUF_readDTableX1_wksp(dctx, src, workSpace, flags) };
2006 if ERR_isError(hSize) {
2007 return hSize;
2008 }
2009 if hSize as usize >= src.len() {
2010 return Error::srcSize_wrong.to_error_code();
2011 }
2012
2013 HUF_decompress1X1_usingDTable_internal(dst, &src[hSize as usize..], dctx, flags)
2014}
2015
2016pub unsafe fn HUF_decompress4X_usingDTable(
2017 dst: Writer<'_>,
2018 src: &[u8],
2019 DTable: &DTable,
2020 flags: core::ffi::c_int,
2021) -> size_t {
2022 if DTable.description.tableType != 0 {
2023 HUF_decompress4X2_usingDTable_internal(dst, src, DTable, flags)
2024 } else {
2025 HUF_decompress4X1_usingDTable_internal(dst, src, DTable, flags)
2026 }
2027}
2028
2029pub unsafe fn HUF_decompress4X_hufOnly_wksp(
2030 dctx: &mut DTable,
2031 dst: Writer<'_>,
2032 src: &[u8],
2033 workSpace: &mut Workspace,
2034 flags: core::ffi::c_int,
2035) -> size_t {
2036 if dst.is_empty() {
2037 return Error::dstSize_tooSmall.to_error_code();
2038 }
2039 if src.is_empty() {
2040 return Error::corruption_detected.to_error_code();
2041 }
2042
2043 match HUF_selectDecoder(dst.capacity(), src.len()) {
2044 Decoder::A1 => HUF_decompress4X1_DCtx_wksp(dctx, dst, src, workSpace, flags),
2045 Decoder::A2 => HUF_decompress4X2_DCtx_wksp(dctx, dst, src, workSpace, flags),
2046 }
2047}
2048
2049#[derive(Debug)]
2050pub struct Writer<'a> {
2051 ptr: Option<NonNull<u8>>,
2052 end: *mut u8,
2053 _marker: core::marker::PhantomData<&'a mut [u8]>,
2054}
2055
2056impl<'a> Writer<'a> {
2057 pub unsafe fn from_raw_parts(ptr: *mut u8, len: usize) -> Self {
2062 let ptr = NonNull::new(ptr);
2063
2064 if ptr.is_none() {
2065 assert_eq!(len, 0);
2066 }
2067
2068 Self {
2069 ptr,
2070 end: match ptr {
2071 None => core::ptr::null_mut(),
2072 Some(ptr) => unsafe { ptr.as_ptr().add(len) },
2073 },
2074 _marker: core::marker::PhantomData,
2075 }
2076 }
2077
2078 #[inline]
2079 pub fn capacity(&self) -> usize {
2080 match self.ptr {
2081 None => 0,
2082 Some(ptr) => unsafe { self.end.offset_from_unsigned(ptr.as_ptr()) },
2083 }
2084 }
2085
2086 #[inline]
2087 pub fn is_null(&self) -> bool {
2088 self.ptr.is_none()
2089 }
2090
2091 #[inline]
2092 pub fn is_empty(&self) -> bool {
2093 match self.ptr {
2094 None => true,
2095 Some(ptr) => ptr.as_ptr() == self.end,
2096 }
2097 }
2098
2099 #[inline]
2100 pub fn as_mut_ptr(&mut self) -> *mut u8 {
2101 match self.ptr {
2102 None => core::ptr::null_mut(),
2103 Some(ptr) => ptr.as_ptr(),
2104 }
2105 }
2106
2107 #[inline]
2108 pub fn as_mut_ptr_range(&mut self) -> core::ops::Range<*mut u8> {
2109 match self.ptr {
2110 None => core::ptr::null_mut()..core::ptr::null_mut(),
2111 Some(ptr) => ptr.as_ptr()..self.end,
2112 }
2113 }
2114
2115 pub fn subslice<R: core::ops::RangeBounds<usize>>(&mut self, range: R) -> Self {
2116 let Some(ptr) = self.ptr else {
2117 match (range.start_bound(), range.end_bound()) {
2118 (Bound::Unbounded, Bound::Unbounded)
2119 | (
2120 Bound::Included(&0),
2121 Bound::Included(&0) | Bound::Excluded(&1) | Bound::Unbounded,
2122 ) => {
2123 return Self {
2124 ptr: self.ptr,
2125 end: self.end,
2126 _marker: self._marker,
2127 };
2128 }
2129 _ => panic!("out of bounds"),
2130 }
2131 };
2132
2133 let new_ptr = match range.start_bound() {
2134 Bound::Included(&count) => ptr.as_ptr().wrapping_add(count),
2135 Bound::Excluded(_) => unreachable!("I think?"),
2136 Bound::Unbounded => ptr.as_ptr(),
2137 };
2138
2139 if new_ptr > self.end {
2140 panic!("out of bounds");
2141 }
2142
2143 let new_end = match range.end_bound() {
2144 Bound::Included(&count) => ptr.as_ptr().wrapping_add(count + 1),
2145 Bound::Excluded(&count) => ptr.as_ptr().wrapping_add(count),
2146 Bound::Unbounded => self.end,
2147 };
2148
2149 if new_end > self.end {
2150 panic!("out of bounds");
2151 }
2152
2153 Self {
2154 ptr: NonNull::new(new_ptr),
2155 end: new_end,
2156 _marker: core::marker::PhantomData,
2157 }
2158 }
2159
2160 fn quarter(&mut self) -> Option<(Self, Self, Self, Self)> {
2161 let capacity = self.capacity();
2162 let segment_size = capacity.div_ceil(4);
2163 let range = self.as_mut_ptr_range();
2164 let remainder = capacity - 3 * segment_size;
2165
2166 if (range.end as usize - range.start as usize) < 6 {
2167 panic!("length must be at least six when splitting into 4 streams");
2168 };
2169
2170 unsafe {
2171 let w1 = Self::from_raw_parts(range.start, segment_size);
2172 let w2 = Self::from_raw_parts(range.start.add(segment_size), segment_size);
2173 let w3 = Self::from_raw_parts(range.start.add(2 * segment_size), segment_size);
2174 let w4 = Self::from_raw_parts(range.start.add(3 * segment_size), remainder);
2175
2176 if !range.contains(&w4.ptr.unwrap().as_ptr()) {
2178 return None;
2179 }
2180
2181 assert!(w1.end <= range.end);
2182 assert!(w2.end <= range.end);
2183 assert!(w3.end <= range.end);
2184 assert!(w4.end <= range.end);
2185
2186 Some((w1, w2, w3, w4))
2187 }
2188 }
2189
2190 fn write_u8(&mut self, byte: u8) {
2191 let Some(ptr) = self.ptr else {
2192 panic!("write out of bounds");
2193 };
2194
2195 if ptr.as_ptr() >= self.end {
2196 panic!("write out of bounds");
2197 }
2198
2199 unsafe { ptr.as_ptr().write(byte) }
2201
2202 self.ptr = unsafe { NonNull::new(ptr.as_ptr().add(1)) }
2204 }
2205
2206 fn write_symbol_x2(&mut self, value: u16, length: u8) {
2207 debug_assert!(length <= 2);
2208
2209 let Some(ptr) = self.ptr else {
2210 panic!("write out of bounds");
2211 };
2212
2213 unsafe { ptr.as_ptr().cast::<u16>().write_unaligned(value.to_le()) }
2219
2220 self.ptr = unsafe { NonNull::new(ptr.as_ptr().add(length as usize)) }
2222 }
2223}
2224
2225#[cfg(test)]
2226mod tests {
2227 use super::*;
2228
2229 #[test]
2230 fn test_DEltX2_to_u32() {
2231 assert_eq!(
2232 HUF_buildDEltX2U32(0xAABB, 0xCC, 0xDD, 0xEE).to_le_bytes(),
2233 [0xDD, 0xBB, 0x76, 0xEF]
2234 );
2235 assert_eq!(HUF_buildDEltX2U32(1, 2, 3, 4).to_le_bytes(), [3, 1, 2, 4]);
2236 }
2237
2238 #[test]
2239 fn test_buildDEltX2() {
2240 assert_eq!(
2241 HUF_buildDEltX2(0xAA, 0xBB, 0xCC, 0xDD),
2242 HUF_DEltX2 {
2243 sequence: 0xAACC,
2244 nbBits: 0xBB,
2245 length: 0xDD,
2246 }
2247 );
2248
2249 assert_eq!(
2250 HUF_buildDEltX2(1, 2, 3, 4),
2251 HUF_DEltX2 {
2252 sequence: 0x0103,
2253 nbBits: 2,
2254 length: 4,
2255 }
2256 );
2257 }
2258
2259 #[test]
2260 fn writer_subslice() {
2261 let mut arr = [1u8, 2, 3, 4, 5, 6, 7, 8];
2262 let mut w = unsafe { Writer::from_raw_parts(arr.as_mut_ptr(), arr.len()) };
2263
2264 assert_eq!(w.subslice(..).capacity(), 8);
2265 assert_eq!(w.subslice(..4).capacity(), 4);
2266 assert_eq!(w.subslice(4..).capacity(), 4);
2267
2268 assert_eq!(w.subslice(..=4).capacity(), 5);
2269 }
2270}