pub const HUF_TABLELOG_MAX: u32 = 12;
pub const HUF_TABLELOG_ABSOLUTEMAX: u32 = 12;
pub const HUF_SYMBOLVALUE_MAX: u32 = 255;
pub const HUF_DECODER_FAST_TABLELOG: u32 = 11;
pub const HUF_DECOMPRESS_WORKSPACE_SIZE: usize = (2 << 10) + (1 << 9);
pub const HUF_DECOMPRESS_WORKSPACE_SIZE_U32: usize = HUF_DECOMPRESS_WORKSPACE_SIZE / 4;
pub const HUF_flags_bmi2: i32 = 1 << 0;
pub const HUF_flags_optimalDepth: i32 = 1 << 1;
pub const HUF_flags_preferRepeat: i32 = 1 << 2;
pub const HUF_flags_suspectUncompressible: i32 = 1 << 3;
pub const HUF_flags_disableAsm: i32 = 1 << 4;
pub const HUF_flags_disableFast: i32 = 1 << 5;
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[target_feature(enable = "bmi1,bmi2,lzcnt")]
unsafe fn HUF_lookBitsFast_bmi2(
bitD: &crate::common::bitstream::BIT_DStream_t,
nbBits: u32,
) -> usize {
debug_assert!(nbBits >= 1);
if bitD.bitsConsumed + nbBits <= 64 {
let start = 64 - bitD.bitsConsumed - nbBits;
core::arch::x86_64::_bextr_u64(bitD.bitContainer as u64, start, nbBits) as usize
} else {
crate::common::bitstream::BIT_lookBitsFast(bitD, nbBits)
}
}
#[inline]
pub fn HUF_initRemainingDStream<'a>(
bit: &mut crate::common::bitstream::BIT_DStream_t<'a>,
src: &'a [u8],
) -> usize {
crate::common::bitstream::BIT_initDStream(bit, src, src.len())
}
#[derive(Clone)]
struct HUF_DecompressFastArgs {
ip: [usize; 4],
op: [usize; 4],
bits: [u64; 4],
ilowest: usize,
oend: usize,
iend: [usize; 4],
}
#[inline(always)]
fn HUF_initFastDStream(cSrc: &[u8], ip: usize) -> u64 {
let lastByte = cSrc[ip + 7];
let bitsConsumed = if lastByte != 0 {
8 - crate::common::bits::ZSTD_highbit32(lastByte as u32)
} else {
0
};
debug_assert!(bitsConsumed <= 8);
(crate::common::mem::MEM_readLE64(&cSrc[ip..]) | 1) << bitsConsumed
}
fn HUF_DecompressFastArgs_init(
dstSize: usize,
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> Result<Option<HUF_DecompressFastArgs>, usize> {
use crate::common::error::{ErrorCode, ERROR};
use crate::common::mem::MEM_readLE16;
if !crate::common::mem::is_little_endian() || core::mem::size_of::<usize>() != 8 {
return Ok(None);
}
if dstSize == 0 {
return Ok(None);
}
if cSrc.len() < 10 {
return Err(ERROR(ErrorCode::CorruptionDetected));
}
let dtLog = HUF_getDTableDesc(dtable).tableLog as u32;
if dtLog != HUF_DECODER_FAST_TABLELOG {
return Ok(None);
}
let length1 = MEM_readLE16(&cSrc[0..2]) as usize;
let length2 = MEM_readLE16(&cSrc[2..4]) as usize;
let length3 = MEM_readLE16(&cSrc[4..6]) as usize;
let accounted = length1
.checked_add(length2)
.and_then(|v| v.checked_add(length3))
.and_then(|v| v.checked_add(6))
.ok_or_else(|| ERROR(ErrorCode::CorruptionDetected))?;
if accounted > cSrc.len() {
return Err(ERROR(ErrorCode::CorruptionDetected));
}
let length4 = cSrc.len() - accounted;
if length1 < 8 || length2 < 8 || length3 < 8 || length4 < 8 {
return Ok(None);
}
let mut args = HUF_DecompressFastArgs {
ip: [0; 4],
op: [0; 4],
bits: [0; 4],
ilowest: 0,
oend: dstSize,
iend: [0; 4],
};
args.iend[0] = 6;
args.iend[1] = args.iend[0] + length1;
args.iend[2] = args.iend[1] + length2;
args.iend[3] = args.iend[2] + length3;
args.ip[0] = args.iend[1] - core::mem::size_of::<u64>();
args.ip[1] = args.iend[2] - core::mem::size_of::<u64>();
args.ip[2] = args.iend[3] - core::mem::size_of::<u64>();
args.ip[3] = cSrc.len() - core::mem::size_of::<u64>();
let segmentSize = dstSize.div_ceil(4);
args.op[0] = 0;
args.op[1] = segmentSize;
args.op[2] = args.op[1] + segmentSize;
args.op[3] = args.op[2] + segmentSize;
if args.op[3] >= dstSize {
return Ok(None);
}
args.bits[0] = HUF_initFastDStream(cSrc, args.ip[0]);
args.bits[1] = HUF_initFastDStream(cSrc, args.ip[1]);
args.bits[2] = HUF_initFastDStream(cSrc, args.ip[2]);
args.bits[3] = HUF_initFastDStream(cSrc, args.ip[3]);
Ok(Some(args))
}
#[inline]
fn HUF_initRemainingDStream_fromFast<'a>(
bit: &mut crate::common::bitstream::BIT_DStream_t<'a>,
cSrc: &'a [u8],
args: &HUF_DecompressFastArgs,
stream: usize,
segmentEnd: usize,
) -> usize {
use crate::common::error::{ErrorCode, ERROR};
if args.op[stream] > segmentEnd {
return ERROR(ErrorCode::CorruptionDetected);
}
if args.ip[stream] < args.iend[stream].saturating_sub(8) {
return ERROR(ErrorCode::CorruptionDetected);
}
bit.bitContainer = crate::common::mem::MEM_readLEST(&cSrc[args.ip[stream]..]);
bit.bitsConsumed = args.bits[stream].trailing_zeros();
bit.start = args.ilowest;
bit.limitPtr = args.ilowest + core::mem::size_of::<usize>();
bit.ptr = args.ip[stream];
bit.src = cSrc;
0
}
pub type HUF_DTable = u32;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct DTableDesc {
pub maxTableLog: u8,
pub tableType: u8,
pub tableLog: u8,
pub reserved: u8,
}
#[inline]
fn pack_dtable_desc(d: DTableDesc) -> u32 {
(d.maxTableLog as u32)
| ((d.tableType as u32) << 8)
| ((d.tableLog as u32) << 16)
| ((d.reserved as u32) << 24)
}
#[inline]
fn unpack_dtable_desc(s: u32) -> DTableDesc {
DTableDesc {
maxTableLog: s as u8,
tableType: (s >> 8) as u8,
tableLog: (s >> 16) as u8,
reserved: (s >> 24) as u8,
}
}
#[inline]
pub fn HUF_getDTableDesc(table: &[HUF_DTable]) -> DTableDesc {
unpack_dtable_desc(table[0])
}
#[inline]
pub fn HUF_setDTableDesc(table: &mut [HUF_DTable], d: DTableDesc) {
table[0] = pack_dtable_desc(d);
}
#[inline]
pub const fn HUF_DTABLE_SIZE_U32(maxTableLog: u32) -> usize {
1 + (1 << maxTableLog) as usize
}
#[derive(Debug, Clone, Copy, Default)]
pub struct HUF_DEltX1 {
pub nbBits: u8,
pub byte: u8,
}
#[inline]
pub fn HUF_DEltX1_pack(e: HUF_DEltX1) -> u16 {
(e.nbBits as u16) | ((e.byte as u16) << 8)
}
#[inline]
pub fn HUF_DEltX1_unpack(s: u16) -> HUF_DEltX1 {
HUF_DEltX1 {
nbBits: s as u8,
byte: (s >> 8) as u8,
}
}
pub fn HUF_DEltX1_set4(symbol: u8, nbBits: u8) -> u64 {
let d4_16 = if crate::common::mem::is_little_endian() {
(symbol as u64) << 8 | nbBits as u64
} else {
symbol as u64 | ((nbBits as u64) << 8)
};
debug_assert!(d4_16 < (1u64 << 16));
d4_16 * 0x0001_0001_0001_0001u64
}
pub fn HUF_rescaleStats(
huffWeight: &mut [u8],
rankVal: &mut [u32],
nbSymbols: u32,
tableLog: u32,
targetTableLog: u32,
) -> u32 {
if tableLog > targetTableLog {
return tableLog;
}
if tableLog < targetTableLog {
let scale = targetTableLog - tableLog;
for w in huffWeight.iter_mut().take(nbSymbols as usize) {
if *w != 0 {
*w += scale as u8;
}
}
let mut s = targetTableLog;
while s > scale {
rankVal[s as usize] = rankVal[(s - scale) as usize];
s -= 1;
}
let mut s = scale;
while s > 0 {
rankVal[s as usize] = 0;
s -= 1;
}
}
targetTableLog
}
#[derive(Debug, Clone, Copy, Default)]
pub struct HUF_DEltX2 {
pub sequence: u16,
pub nbBits: u8,
pub length: u8,
}
#[inline]
pub fn HUF_DEltX2_pack(e: HUF_DEltX2) -> u32 {
(e.sequence as u32) | ((e.nbBits as u32) << 16) | ((e.length as u32) << 24)
}
#[inline]
pub fn HUF_DEltX2_unpack(s: u32) -> HUF_DEltX2 {
HUF_DEltX2 {
sequence: s as u16,
nbBits: (s >> 16) as u8,
length: (s >> 24) as u8,
}
}
#[inline]
pub fn read_entry_x2(dtable: &[HUF_DTable], idx: usize) -> HUF_DEltX2 {
HUF_DEltX2_unpack(dtable[1 + idx])
}
#[inline]
pub fn write_entry_x2(dtable: &mut [HUF_DTable], idx: usize, e: HUF_DEltX2) {
dtable[1 + idx] = HUF_DEltX2_pack(e);
}
pub fn HUF_buildDEltX2U32(symbol: u32, nbBits: u32, baseSeq: u32, level: i32) -> u32 {
let seq = if crate::common::mem::is_little_endian() {
if level == 1 {
symbol
} else {
baseSeq + (symbol << 8)
}
} else if level == 1 {
symbol << 8
} else {
(baseSeq << 8) + symbol
};
if crate::common::mem::is_little_endian() {
seq + (nbBits << 16) + ((level as u32) << 24)
} else {
(seq << 16) + (nbBits << 8) + level as u32
}
}
#[inline]
pub fn HUF_buildDEltX2(symbol: u32, nbBits: u32, baseSeq: u32, level: i32) -> u32 {
HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level)
}
#[inline]
pub fn HUF_buildDEltX2U64(symbol: u32, nbBits: u32, baseSeq: u16, level: i32) -> u64 {
let delt = HUF_buildDEltX2U32(symbol, nbBits, baseSeq as u32, level) as u64;
delt + (delt << 32)
}
pub fn HUF_fillDTableX2ForWeight(
dtable: &mut [HUF_DTable],
dtable_start: usize,
sortedList: &[u8],
begin: usize,
end: usize,
nbBits: u32,
tableLog: u32,
baseSeq: u16,
level: i32,
) {
let length = 1u32 << ((tableLog - nbBits) & 0x1F);
let mut pos = dtable_start;
for sym_byte in sortedList.iter().take(end).skip(begin) {
let sym = *sym_byte as u32;
let delt = HUF_buildDEltX2U32(sym, nbBits, baseSeq as u32, level);
for j in 0..length as usize {
dtable[1 + pos + j] = delt;
}
pos += length as usize;
}
}
pub fn HUF_fillDTableX2Level2(
dtable: &mut [HUF_DTable],
dtable_start: usize,
targetLog: u32,
consumedBits: u32,
rankVal: &[u32],
minWeight: i32,
maxWeight1: i32,
sortedSymbols: &[u8],
rankStart: &[u32],
nbBitsBaseline: u32,
baseSeq: u16,
) {
if minWeight > 1 {
let length = 1u32 << ((targetLog - consumedBits) & 0x1F);
let delt = HUF_buildDEltX2U32(baseSeq as u32, consumedBits, 0, 1);
let skipSize = rankVal[minWeight as usize] as usize;
for i in 0..skipSize.min(length as usize) {
dtable[1 + dtable_start + i] = delt;
}
}
for w in minWeight..maxWeight1 {
let begin = rankStart[w as usize] as usize;
let end = rankStart[(w + 1) as usize] as usize;
let nbBits = nbBitsBaseline - w as u32;
let totalBits = nbBits + consumedBits;
let offset = rankVal[w as usize] as usize;
HUF_fillDTableX2ForWeight(
dtable,
dtable_start + offset,
sortedSymbols,
begin,
end,
totalBits,
targetLog,
baseSeq,
2,
);
}
}
pub fn HUF_fillDTableX2(
dtable: &mut [HUF_DTable],
targetLog: u32,
sortedList: &[u8],
rankStart: &[u32],
rankValOrigin: &[[u32; (HUF_TABLELOG_MAX + 1) as usize]],
maxWeight: u32,
nbBitsBaseline: u32,
) {
let rankVal = &rankValOrigin[0];
let scaleLog = nbBitsBaseline as i32 - targetLog as i32;
let minBits = nbBitsBaseline - maxWeight;
let wEnd = maxWeight as i32 + 1;
for w in 1..wEnd {
let begin = rankStart[w as usize] as usize;
let end = rankStart[(w + 1) as usize] as usize;
let nbBits = nbBitsBaseline - w as u32;
if targetLog >= nbBits + minBits {
let mut start = rankVal[w as usize] as usize;
let length = 1usize << ((targetLog - nbBits) & 0x1F);
let mut minWeight = nbBits as i32 + scaleLog;
if minWeight < 1 {
minWeight = 1;
}
for s in begin..end {
HUF_fillDTableX2Level2(
dtable,
start,
targetLog,
nbBits,
&rankValOrigin[nbBits as usize],
minWeight,
wEnd,
sortedList,
rankStart,
nbBitsBaseline,
sortedList[s] as u16,
);
start += length;
}
} else {
let offset = rankVal[w as usize] as usize;
HUF_fillDTableX2ForWeight(
dtable, offset, sortedList, begin, end, nbBits, targetLog, 0, 1,
);
}
}
}
#[inline]
pub fn HUF_decodeSymbolX2(
dst: &mut [u8],
p: usize,
bitD: &mut crate::common::bitstream::BIT_DStream_t,
dtable: &[HUF_DTable],
dtLog: u32,
) -> u32 {
let val = crate::common::bitstream::BIT_lookBitsFast(bitD, dtLog);
let e = read_entry_x2(dtable, val);
let bytes = e.sequence.to_le_bytes();
dst[p] = bytes[0];
if p + 1 < dst.len() {
dst[p + 1] = bytes[1];
}
crate::common::bitstream::BIT_skipBits(bitD, e.nbBits as u32);
e.length as u32
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[target_feature(enable = "bmi1,bmi2,lzcnt")]
unsafe fn HUF_decodeSymbolX2_bmi2(
dst: &mut [u8],
p: usize,
bitD: &mut crate::common::bitstream::BIT_DStream_t,
dtable: &[HUF_DTable],
dtLog: u32,
) -> u32 {
let val = HUF_lookBitsFast_bmi2(bitD, dtLog);
let e = read_entry_x2(dtable, val);
let bytes = e.sequence.to_le_bytes();
dst[p] = bytes[0];
if p + 1 < dst.len() {
dst[p + 1] = bytes[1];
}
crate::common::bitstream::BIT_skipBits(bitD, e.nbBits as u32);
e.length as u32
}
pub fn HUF_decodeLastSymbolX2(
dst: &mut [u8],
p: usize,
bitD: &mut crate::common::bitstream::BIT_DStream_t,
dtable: &[HUF_DTable],
dtLog: u32,
) -> u32 {
let val = crate::common::bitstream::BIT_lookBitsFast(bitD, dtLog);
let e = read_entry_x2(dtable, val);
dst[p] = e.sequence as u8;
let container_bits = (core::mem::size_of::<usize>() as u32) * 8;
if e.length == 1 {
crate::common::bitstream::BIT_skipBits(bitD, e.nbBits as u32);
} else if bitD.bitsConsumed < container_bits {
crate::common::bitstream::BIT_skipBits(bitD, e.nbBits as u32);
if bitD.bitsConsumed > container_bits {
bitD.bitsConsumed = container_bits;
}
}
1
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[target_feature(enable = "bmi1,bmi2,lzcnt")]
unsafe fn HUF_decodeLastSymbolX2_bmi2(
dst: &mut [u8],
p: usize,
bitD: &mut crate::common::bitstream::BIT_DStream_t,
dtable: &[HUF_DTable],
dtLog: u32,
) -> u32 {
let val = HUF_lookBitsFast_bmi2(bitD, dtLog);
let e = read_entry_x2(dtable, val);
dst[p] = e.sequence as u8;
let container_bits = (core::mem::size_of::<usize>() as u32) * 8;
if e.length == 1 {
crate::common::bitstream::BIT_skipBits(bitD, e.nbBits as u32);
} else if bitD.bitsConsumed < container_bits {
crate::common::bitstream::BIT_skipBits(bitD, e.nbBits as u32);
if bitD.bitsConsumed > container_bits {
bitD.bitsConsumed = container_bits;
}
}
1
}
#[inline]
pub fn HUF_decodeStreamX2(
dst: &mut [u8],
p: usize,
pEnd: usize,
bitD: &mut crate::common::bitstream::BIT_DStream_t,
dtable: &[HUF_DTable],
dtLog: u32,
) -> usize {
use crate::common::bitstream::{BIT_DStream_unfinished, BIT_reloadDStream};
let pStart = p;
let mut p = p;
let container_bytes = core::mem::size_of::<usize>();
if pEnd.saturating_sub(p) >= container_bytes {
if dtLog <= 11 {
loop {
let reload = BIT_reloadDStream(bitD);
if reload != BIT_DStream_unfinished || !(pEnd > 9 && p < pEnd - 9) {
break;
}
p += HUF_decodeSymbolX2(dst, p, bitD, dtable, dtLog) as usize;
p += HUF_decodeSymbolX2(dst, p, bitD, dtable, dtLog) as usize;
p += HUF_decodeSymbolX2(dst, p, bitD, dtable, dtLog) as usize;
p += HUF_decodeSymbolX2(dst, p, bitD, dtable, dtLog) as usize;
p += HUF_decodeSymbolX2(dst, p, bitD, dtable, dtLog) as usize;
}
} else {
loop {
let reload = BIT_reloadDStream(bitD);
if reload != BIT_DStream_unfinished || !(pEnd > 7 && p < pEnd - 7) {
break;
}
p += HUF_decodeSymbolX2(dst, p, bitD, dtable, dtLog) as usize;
p += HUF_decodeSymbolX2(dst, p, bitD, dtable, dtLog) as usize;
p += HUF_decodeSymbolX2(dst, p, bitD, dtable, dtLog) as usize;
p += HUF_decodeSymbolX2(dst, p, bitD, dtable, dtLog) as usize;
}
}
} else {
BIT_reloadDStream(bitD);
}
if pEnd.saturating_sub(p) >= 2 {
loop {
let reload = BIT_reloadDStream(bitD);
if reload != BIT_DStream_unfinished || p + 1 >= pEnd {
break;
}
p += HUF_decodeSymbolX2(dst, p, bitD, dtable, dtLog) as usize;
}
while p + 1 < pEnd {
p += HUF_decodeSymbolX2(dst, p, bitD, dtable, dtLog) as usize;
}
}
if p < pEnd {
p += HUF_decodeLastSymbolX2(dst, p, bitD, dtable, dtLog) as usize;
}
p - pStart
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[target_feature(enable = "bmi1,bmi2,lzcnt")]
unsafe fn HUF_decodeStreamX2_bmi2(
dst: &mut [u8],
p: usize,
pEnd: usize,
bitD: &mut crate::common::bitstream::BIT_DStream_t,
dtable: &[HUF_DTable],
dtLog: u32,
) -> usize {
use crate::common::bitstream::{BIT_DStream_unfinished, BIT_reloadDStream};
let pStart = p;
let mut p = p;
let container_bytes = core::mem::size_of::<usize>();
if pEnd.saturating_sub(p) >= container_bytes {
if dtLog <= 11 {
loop {
let reload = BIT_reloadDStream(bitD);
if reload != BIT_DStream_unfinished || !(pEnd > 9 && p < pEnd - 9) {
break;
}
p += HUF_decodeSymbolX2_bmi2(dst, p, bitD, dtable, dtLog) as usize;
p += HUF_decodeSymbolX2_bmi2(dst, p, bitD, dtable, dtLog) as usize;
p += HUF_decodeSymbolX2_bmi2(dst, p, bitD, dtable, dtLog) as usize;
p += HUF_decodeSymbolX2_bmi2(dst, p, bitD, dtable, dtLog) as usize;
p += HUF_decodeSymbolX2_bmi2(dst, p, bitD, dtable, dtLog) as usize;
}
} else {
loop {
let reload = BIT_reloadDStream(bitD);
if reload != BIT_DStream_unfinished || !(pEnd > 7 && p < pEnd - 7) {
break;
}
p += HUF_decodeSymbolX2_bmi2(dst, p, bitD, dtable, dtLog) as usize;
p += HUF_decodeSymbolX2_bmi2(dst, p, bitD, dtable, dtLog) as usize;
p += HUF_decodeSymbolX2_bmi2(dst, p, bitD, dtable, dtLog) as usize;
p += HUF_decodeSymbolX2_bmi2(dst, p, bitD, dtable, dtLog) as usize;
}
}
} else {
BIT_reloadDStream(bitD);
}
if pEnd.saturating_sub(p) >= 2 {
loop {
let reload = BIT_reloadDStream(bitD);
if reload != BIT_DStream_unfinished || p + 1 >= pEnd {
break;
}
p += HUF_decodeSymbolX2_bmi2(dst, p, bitD, dtable, dtLog) as usize;
}
while p + 1 < pEnd {
p += HUF_decodeSymbolX2_bmi2(dst, p, bitD, dtable, dtLog) as usize;
}
}
if p < pEnd {
p += HUF_decodeLastSymbolX2_bmi2(dst, p, bitD, dtable, dtLog) as usize;
}
p - pStart
}
pub fn HUF_selectDecoder(dstSize: usize, cSrcSize: usize) -> u32 {
debug_assert!(dstSize > 0);
debug_assert!(dstSize <= 128 * 1024);
const ALGO_TIME: [[(u32, u32); 2]; 16] = [
[(0, 0), (1, 1)],
[(0, 0), (1, 1)],
[(150, 216), (381, 119)],
[(170, 205), (514, 112)],
[(177, 199), (539, 110)],
[(197, 194), (644, 107)],
[(221, 192), (735, 107)],
[(256, 189), (881, 106)],
[(359, 188), (1167, 109)],
[(582, 187), (1570, 114)],
[(688, 187), (1712, 122)],
[(825, 186), (1965, 136)],
[(976, 185), (2131, 150)],
[(1180, 186), (2070, 175)],
[(1377, 185), (1731, 202)],
[(1412, 185), (1695, 202)],
];
let q = if cSrcSize >= dstSize {
15u32
} else {
((cSrcSize * 16) / dstSize) as u32
};
let d256 = (dstSize >> 8) as u32;
let d_time0 = ALGO_TIME[q as usize][0].0 + ALGO_TIME[q as usize][0].1.wrapping_mul(d256);
let mut d_time1 = ALGO_TIME[q as usize][1].0 + ALGO_TIME[q as usize][1].1.wrapping_mul(d256);
d_time1 = d_time1.wrapping_add(d_time1 >> 5);
(d_time1 < d_time0) as u32
}
pub fn HUF_readDTableX1(
dtable: &mut [HUF_DTable],
src: &[u8],
workSpace: &mut [u32],
flags: i32,
) -> usize {
const RANK_LEN: usize = (HUF_TABLELOG_ABSOLUTEMAX + 1) as usize;
const SYM_LEN: usize = (HUF_SYMBOLVALUE_MAX + 1) as usize;
if workSpace.len() * 4 < HUF_DECOMPRESS_WORKSPACE_SIZE {
return crate::common::error::ERROR(crate::common::error::ErrorCode::TableLogTooLarge);
}
let mut rankVal = [0u32; RANK_LEN];
let mut rankStart = [0u32; RANK_LEN];
let mut symbols = [0u8; SYM_LEN];
let mut huffWeight = [0u8; SYM_LEN];
let mut stats_wksp = [0u32; 256];
let mut nbSymbols: u32 = 0;
let mut tableLog: u32 = 0;
let iSize = crate::common::entropy_common::HUF_readStats_wksp(
&mut huffWeight,
SYM_LEN,
&mut rankVal,
&mut nbSymbols,
&mut tableLog,
src,
&mut stats_wksp,
flags,
);
if crate::common::error::ERR_isError(iSize) {
return iSize;
}
let mut dtd = HUF_getDTableDesc(dtable);
let maxTableLog = dtd.maxTableLog as u32 + 1;
let targetTableLog = maxTableLog.min(HUF_DECODER_FAST_TABLELOG);
tableLog = HUF_rescaleStats(
&mut huffWeight,
&mut rankVal,
nbSymbols,
tableLog,
targetTableLog,
);
if tableLog > dtd.maxTableLog as u32 + 1 {
return crate::common::error::ERROR(crate::common::error::ErrorCode::TableLogTooLarge);
}
dtd.tableType = 0;
dtd.tableLog = tableLog as u8;
HUF_setDTableDesc(dtable, dtd);
let mut nextRankStart: u32 = 0;
for n in 0..(tableLog + 1) as usize {
let curr = nextRankStart;
nextRankStart += rankVal[n];
rankStart[n] = curr;
}
let unroll = 4;
let nLimit = nbSymbols as i32 - unroll + 1;
let mut n = 0i32;
while n < nLimit {
for u in 0..unroll {
let w = huffWeight[(n + u) as usize] as usize;
let pos = rankStart[w] as usize;
symbols[pos] = (n + u) as u8;
rankStart[w] += 1;
}
n += unroll;
}
while (n as u32) < nbSymbols {
let w = huffWeight[n as usize] as usize;
let pos = rankStart[w] as usize;
symbols[pos] = n as u8;
rankStart[w] += 1;
n += 1;
}
let tableSize = 1usize << tableLog;
debug_assert!(dtable.len() > tableSize / 2);
let dt16 = unsafe { dtable.as_mut_ptr().add(1) as *mut u16 };
let mut symbol_idx = rankVal[0] as usize;
let mut rank_slot_start: usize = 0; for w in 1..(tableLog + 1) {
let symbolCount = rankVal[w as usize] as usize;
let length = (1usize << w) >> 1;
let nbBits = (tableLog + 1 - w) as u8;
let mut uStart = rank_slot_start;
for s in 0..symbolCount {
let sym = symbols[symbol_idx + s];
let ent = HUF_DEltX1_pack(HUF_DEltX1 { nbBits, byte: sym });
for j in 0..length {
unsafe {
*dt16.add(uStart + j) = ent;
}
}
uStart += length;
}
symbol_idx += symbolCount;
rank_slot_start += symbolCount * length;
}
iSize
}
#[inline]
pub fn HUF_readDTableX1_wksp(
dtable: &mut [HUF_DTable],
src: &[u8],
workSpace: &mut [u32],
flags: i32,
) -> usize {
HUF_readDTableX1(dtable, src, workSpace, flags)
}
#[inline(always)]
pub fn read_entry(dtable: &[HUF_DTable], idx: usize) -> HUF_DEltX1 {
let slot = dtable[1 + idx / 2];
let half = if idx & 1 == 0 {
slot as u16
} else {
(slot >> 16) as u16
};
HUF_DEltX1_unpack(half)
}
pub fn HUF_readDTableX2(
dtable: &mut [HUF_DTable],
src: &[u8],
workSpace: &mut [u32],
flags: i32,
) -> usize {
use crate::common::error::{ErrorCode, ERROR};
const MAXW_PLUS1: usize = (HUF_TABLELOG_MAX + 1) as usize;
const SYM_LEN: usize = (HUF_SYMBOLVALUE_MAX + 1) as usize;
let mut dtd = HUF_getDTableDesc(dtable);
let mut maxTableLog = dtd.maxTableLog as u32;
let mut rankStats = [0u32; (HUF_TABLELOG_MAX + 1) as usize];
let mut rankStart0 = [0u32; (HUF_TABLELOG_MAX + 3) as usize];
let mut sortedSymbol = [0u8; SYM_LEN];
let mut weightList = [0u8; SYM_LEN];
let mut stats_wksp = [0u32; 256];
let mut rankVal = [[0u32; MAXW_PLUS1]; HUF_TABLELOG_MAX as usize];
if workSpace.len() * 4 < HUF_DECOMPRESS_WORKSPACE_SIZE {
return ERROR(ErrorCode::Generic);
}
if maxTableLog > HUF_TABLELOG_MAX {
return ERROR(ErrorCode::TableLogTooLarge);
}
let mut tableLog: u32 = 0;
let mut nbSymbols: u32 = 0;
let iSize = crate::common::entropy_common::HUF_readStats_wksp(
&mut weightList,
SYM_LEN,
&mut rankStats,
&mut nbSymbols,
&mut tableLog,
src,
&mut stats_wksp,
flags,
);
if crate::common::error::ERR_isError(iSize) {
return iSize;
}
if tableLog > maxTableLog {
return ERROR(ErrorCode::TableLogTooLarge);
}
if tableLog <= HUF_DECODER_FAST_TABLELOG && maxTableLog > HUF_DECODER_FAST_TABLELOG {
maxTableLog = HUF_DECODER_FAST_TABLELOG;
}
let mut maxW = tableLog;
while rankStats[maxW as usize] == 0 && maxW > 0 {
maxW -= 1;
}
{
let mut nextRankStart: u32 = 0;
for w in 1..=maxW {
let curr = nextRankStart;
nextRankStart += rankStats[w as usize];
rankStart0[(w + 1) as usize] = curr;
}
rankStart0[1] = nextRankStart;
rankStart0[(maxW + 2) as usize] = nextRankStart;
}
{
for (s, w_byte) in weightList.iter().enumerate().take(nbSymbols as usize) {
let w = *w_byte as usize;
let r = rankStart0[w + 1] as usize;
rankStart0[w + 1] += 1;
sortedSymbol[r] = s as u8;
}
}
rankStart0[1] = 0;
{
let rescale = (maxTableLog as i32 - tableLog as i32) - 1;
let mut nextRankVal: u32 = 0;
for w in 1..=maxW {
let curr = nextRankVal;
let shift = (w as i32 + rescale).max(0) as u32;
nextRankVal += rankStats[w as usize] << shift;
rankVal[0][w as usize] = curr;
}
let minBits = tableLog + 1 - maxW;
let limit = (maxTableLog - minBits + 1) as usize;
let mut consumed = minBits as usize;
while consumed < limit {
let src_col = rankVal[0];
let dst_col = &mut rankVal[consumed];
for (w, dst_slot) in dst_col
.iter_mut()
.enumerate()
.take(maxW as usize + 1)
.skip(1)
{
*dst_slot = src_col[w] >> consumed;
}
consumed += 1;
}
}
HUF_fillDTableX2(
dtable,
maxTableLog,
&sortedSymbol,
&rankStart0,
&rankVal,
maxW,
tableLog + 1,
);
dtd.tableLog = maxTableLog as u8;
dtd.tableType = 1;
HUF_setDTableDesc(dtable, dtd);
iSize
}
#[inline]
pub fn HUF_readDTableX2_wksp(
dtable: &mut [HUF_DTable],
src: &[u8],
workSpace: &mut [u32],
flags: i32,
) -> usize {
HUF_readDTableX2(dtable, src, workSpace, flags)
}
#[inline]
pub fn HUF_decodeSymbolX1(
bitD: &mut crate::common::bitstream::BIT_DStream_t,
dtable: &[HUF_DTable],
dtLog: u32,
) -> u8 {
let val = crate::common::bitstream::BIT_lookBitsFast(bitD, dtLog);
let e = read_entry(dtable, val);
crate::common::bitstream::BIT_skipBits(bitD, e.nbBits as u32);
e.byte
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[target_feature(enable = "bmi1,bmi2,lzcnt")]
unsafe fn HUF_decodeSymbolX1_bmi2(
bitD: &mut crate::common::bitstream::BIT_DStream_t,
dtable: &[HUF_DTable],
dtLog: u32,
) -> u8 {
let val = HUF_lookBitsFast_bmi2(bitD, dtLog);
let e = read_entry(dtable, val);
crate::common::bitstream::BIT_skipBits(bitD, e.nbBits as u32);
e.byte
}
#[inline]
pub fn HUF_decodeStreamX1(
dst: &mut [u8],
p: usize,
pEnd: usize,
bitD: &mut crate::common::bitstream::BIT_DStream_t,
dtable: &[HUF_DTable],
dtLog: u32,
) -> usize {
use crate::common::bitstream::{BIT_DStream_unfinished, BIT_reloadDStream};
let pStart = p;
let mut p = p;
if pEnd > p + 3 {
while BIT_reloadDStream(bitD) == BIT_DStream_unfinished && p < pEnd - 3 {
dst[p] = HUF_decodeSymbolX1(bitD, dtable, dtLog);
p += 1;
dst[p] = HUF_decodeSymbolX1(bitD, dtable, dtLog);
p += 1;
dst[p] = HUF_decodeSymbolX1(bitD, dtable, dtLog);
p += 1;
dst[p] = HUF_decodeSymbolX1(bitD, dtable, dtLog);
p += 1;
}
} else {
BIT_reloadDStream(bitD);
}
while p < pEnd {
dst[p] = HUF_decodeSymbolX1(bitD, dtable, dtLog);
p += 1;
}
p - pStart
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[target_feature(enable = "bmi1,bmi2,lzcnt")]
unsafe fn HUF_decodeStreamX1_bmi2(
dst: &mut [u8],
p: usize,
pEnd: usize,
bitD: &mut crate::common::bitstream::BIT_DStream_t,
dtable: &[HUF_DTable],
dtLog: u32,
) -> usize {
use crate::common::bitstream::{BIT_DStream_unfinished, BIT_reloadDStream};
let pStart = p;
let mut p = p;
if pEnd > p + 3 {
while BIT_reloadDStream(bitD) == BIT_DStream_unfinished && p < pEnd - 3 {
dst[p] = HUF_decodeSymbolX1_bmi2(bitD, dtable, dtLog);
p += 1;
dst[p] = HUF_decodeSymbolX1_bmi2(bitD, dtable, dtLog);
p += 1;
dst[p] = HUF_decodeSymbolX1_bmi2(bitD, dtable, dtLog);
p += 1;
dst[p] = HUF_decodeSymbolX1_bmi2(bitD, dtable, dtLog);
p += 1;
}
} else {
BIT_reloadDStream(bitD);
}
while p < pEnd {
dst[p] = HUF_decodeSymbolX1_bmi2(bitD, dtable, dtLog);
p += 1;
}
p - pStart
}
pub fn HUF_decompress1X1_usingDTable_internal(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
use crate::common::bitstream::{BIT_DStream_t, BIT_endOfDStream, BIT_initDStream};
use crate::common::error::{ErrorCode, ERROR};
let dstSize = dst.len();
let cSrcSize = cSrc.len();
let dtd = HUF_getDTableDesc(dtable);
let dtLog = dtd.tableLog as u32;
let mut bitD = BIT_DStream_t::default();
let rc = BIT_initDStream(&mut bitD, cSrc, cSrcSize);
if crate::common::error::ERR_isError(rc) {
return rc;
}
HUF_decodeStreamX1(dst, 0, dstSize, &mut bitD, dtable, dtLog);
if BIT_endOfDStream(&bitD) == 0 {
return ERROR(ErrorCode::CorruptionDetected);
}
dstSize
}
#[inline]
pub fn HUF_decompress1X1_usingDTable_internal_body(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
HUF_decompress1X1_usingDTable_internal(dst, cSrc, dtable)
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[target_feature(enable = "bmi1,bmi2,lzcnt")]
unsafe fn HUF_decompress1X1_usingDTable_internal_bmi2_impl(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
use crate::common::bitstream::{BIT_DStream_t, BIT_endOfDStream, BIT_initDStream};
use crate::common::error::{ErrorCode, ERROR};
let dstSize = dst.len();
let cSrcSize = cSrc.len();
let dtd = HUF_getDTableDesc(dtable);
let dtLog = dtd.tableLog as u32;
let mut bitD = BIT_DStream_t::default();
let rc = BIT_initDStream(&mut bitD, cSrc, cSrcSize);
if crate::common::error::ERR_isError(rc) {
return rc;
}
HUF_decodeStreamX1_bmi2(dst, 0, dstSize, &mut bitD, dtable, dtLog);
if BIT_endOfDStream(&bitD) == 0 {
return ERROR(ErrorCode::CorruptionDetected);
}
dstSize
}
#[inline]
pub fn HUF_decompress1X1_usingDTable_internal_bmi2(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
{
if std::is_x86_feature_detected!("bmi1")
&& std::is_x86_feature_detected!("bmi2")
&& std::is_x86_feature_detected!("lzcnt")
{
return unsafe { HUF_decompress1X1_usingDTable_internal_bmi2_impl(dst, cSrc, dtable) };
}
}
HUF_decompress1X1_usingDTable_internal(dst, cSrc, dtable)
}
pub fn HUF_decompress1X_usingDTable<const BMI2: bool>(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
let dtd = HUF_getDTableDesc(dtable);
if dtd.tableType != 0 {
if BMI2 {
HUF_decompress1X2_usingDTable_internal_bmi2(dst, cSrc, dtable)
} else {
HUF_decompress1X2_usingDTable_internal(dst, cSrc, dtable)
}
} else if BMI2 {
HUF_decompress1X1_usingDTable_internal_bmi2(dst, cSrc, dtable)
} else {
HUF_decompress1X1_usingDTable_internal(dst, cSrc, dtable)
}
}
fn HUF_decompress4X1_usingDTable_internal_fast_impl(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
use crate::common::bitstream::BIT_DStream_t;
use crate::common::error::{ERR_isError, ErrorCode, ERROR};
let mut args = match HUF_DecompressFastArgs_init(dst.len(), cSrc, dtable) {
Ok(Some(args)) => args,
Ok(None) => return 0,
Err(err) => return err,
};
HUF_decompress4X1_usingDTable_internal_fast_c_loop_impl(&mut args, dst, cSrc, dtable);
if args.ip.iter().any(|&ip| ip < args.ilowest) || args.op[3] > args.oend {
return ERROR(ErrorCode::CorruptionDetected);
}
let segmentSize = dst.len().div_ceil(4);
let mut segmentEnd = 0usize;
for i in 0..4 {
segmentEnd = (segmentEnd + segmentSize).min(dst.len());
let mut bit = BIT_DStream_t::default();
let rc = HUF_initRemainingDStream_fromFast(&mut bit, cSrc, &args, i, segmentEnd);
if ERR_isError(rc) {
return rc;
}
args.op[i] += HUF_decodeStreamX1(
dst,
args.op[i],
segmentEnd,
&mut bit,
dtable,
HUF_DECODER_FAST_TABLELOG,
);
if args.op[i] != segmentEnd {
return ERROR(ErrorCode::CorruptionDetected);
}
}
dst.len()
}
fn HUF_decompress4X1_usingDTable_internal_fast_c_loop_impl(
args: &mut HUF_DecompressFastArgs,
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) {
let mut bits = args.bits;
let mut ip = args.ip;
let mut op = args.op;
let oend = args.oend;
let ilowest = args.ilowest;
loop {
let oiters = (oend - op[3]) / 5;
let iiters = (ip[0] - ilowest) / 7;
let iters = oiters.min(iiters);
let olimit = op[3] + iters * 5;
if op[3] == olimit {
break;
}
if ip[1] < ip[0] || ip[2] < ip[1] || ip[3] < ip[2] {
break;
}
while op[3] < olimit {
for symbol in 0..5 {
for stream in 0..4 {
let index = (bits[stream] >> 53) as usize;
let entry = HUF_DEltX1_pack(read_entry(dtable, index));
bits[stream] <<= (entry & 0x3f) as u32;
dst[op[stream] + symbol] = (entry >> 8) as u8;
}
}
for stream in 0..4 {
let ctz = bits[stream].trailing_zeros() as usize;
let nbBits = ctz & 7;
let nbBytes = ctz >> 3;
op[stream] += 5;
ip[stream] -= nbBytes;
bits[stream] = crate::common::mem::MEM_readLE64(&cSrc[ip[stream]..]) | 1;
bits[stream] <<= nbBits as u32;
}
}
}
args.bits = bits;
args.ip = ip;
args.op = op;
}
fn HUF_decompress4X1_usingDTable_internal_body_impl(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
use crate::common::bitstream::{
BIT_DStream_t, BIT_DStream_unfinished, BIT_endOfDStream, BIT_initDStream,
BIT_reloadDStreamFast,
};
use crate::common::error::{ErrorCode, ERROR};
use crate::common::mem::MEM_readLE16;
let dstSize = dst.len();
let cSrcSize = cSrc.len();
if cSrcSize < 10 {
return ERROR(ErrorCode::CorruptionDetected);
}
if dstSize < 6 {
return ERROR(ErrorCode::CorruptionDetected);
}
let length1 = MEM_readLE16(&cSrc[0..2]) as usize;
let length2 = MEM_readLE16(&cSrc[2..4]) as usize;
let length3 = MEM_readLE16(&cSrc[4..6]) as usize;
let header_size: usize = 6;
let accounted = match length1
.checked_add(length2)
.and_then(|v| v.checked_add(length3))
.and_then(|v| v.checked_add(header_size))
{
Some(v) => v,
None => return ERROR(ErrorCode::CorruptionDetected),
};
if accounted > cSrcSize {
return ERROR(ErrorCode::CorruptionDetected);
}
let length4 = cSrcSize - accounted;
let istart1 = header_size;
let istart2 = istart1 + length1;
let istart3 = istart2 + length2;
let istart4 = istart3 + length3;
let segmentSize = dstSize.div_ceil(4);
let opStart2 = segmentSize;
let opStart3 = 2 * segmentSize;
let opStart4 = 3 * segmentSize;
if opStart4 > dstSize {
return ERROR(ErrorCode::CorruptionDetected);
}
let dtd = HUF_getDTableDesc(dtable);
let dtLog = dtd.tableLog as u32;
let mut bd1 = BIT_DStream_t::default();
let mut bd2 = BIT_DStream_t::default();
let mut bd3 = BIT_DStream_t::default();
let mut bd4 = BIT_DStream_t::default();
let rc = BIT_initDStream(&mut bd1, &cSrc[istart1..istart1 + length1], length1);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let rc = BIT_initDStream(&mut bd2, &cSrc[istart2..istart2 + length2], length2);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let rc = BIT_initDStream(&mut bd3, &cSrc[istart3..istart3 + length3], length3);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let rc = BIT_initDStream(&mut bd4, &cSrc[istart4..istart4 + length4], length4);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let mut op1 = 0usize;
let mut op2 = opStart2;
let mut op3 = opStart3;
let mut op4 = opStart4;
let olimit = dstSize.saturating_sub(3);
let mut endSignal = 1u32;
if dstSize - op4 >= core::mem::size_of::<usize>() {
loop {
if endSignal == 0 || op4 >= olimit {
break;
}
dst[op1] = HUF_decodeSymbolX1(&mut bd1, dtable, dtLog);
op1 += 1;
dst[op2] = HUF_decodeSymbolX1(&mut bd2, dtable, dtLog);
op2 += 1;
dst[op3] = HUF_decodeSymbolX1(&mut bd3, dtable, dtLog);
op3 += 1;
dst[op4] = HUF_decodeSymbolX1(&mut bd4, dtable, dtLog);
op4 += 1;
dst[op1] = HUF_decodeSymbolX1(&mut bd1, dtable, dtLog);
op1 += 1;
dst[op2] = HUF_decodeSymbolX1(&mut bd2, dtable, dtLog);
op2 += 1;
dst[op3] = HUF_decodeSymbolX1(&mut bd3, dtable, dtLog);
op3 += 1;
dst[op4] = HUF_decodeSymbolX1(&mut bd4, dtable, dtLog);
op4 += 1;
dst[op1] = HUF_decodeSymbolX1(&mut bd1, dtable, dtLog);
op1 += 1;
dst[op2] = HUF_decodeSymbolX1(&mut bd2, dtable, dtLog);
op2 += 1;
dst[op3] = HUF_decodeSymbolX1(&mut bd3, dtable, dtLog);
op3 += 1;
dst[op4] = HUF_decodeSymbolX1(&mut bd4, dtable, dtLog);
op4 += 1;
dst[op1] = HUF_decodeSymbolX1(&mut bd1, dtable, dtLog);
op1 += 1;
dst[op2] = HUF_decodeSymbolX1(&mut bd2, dtable, dtLog);
op2 += 1;
dst[op3] = HUF_decodeSymbolX1(&mut bd3, dtable, dtLog);
op3 += 1;
dst[op4] = HUF_decodeSymbolX1(&mut bd4, dtable, dtLog);
op4 += 1;
endSignal &= (BIT_reloadDStreamFast(&mut bd1) == BIT_DStream_unfinished) as u32;
endSignal &= (BIT_reloadDStreamFast(&mut bd2) == BIT_DStream_unfinished) as u32;
endSignal &= (BIT_reloadDStreamFast(&mut bd3) == BIT_DStream_unfinished) as u32;
endSignal &= (BIT_reloadDStreamFast(&mut bd4) == BIT_DStream_unfinished) as u32;
}
}
if op1 > opStart2 || op2 > opStart3 || op3 > opStart4 {
return ERROR(ErrorCode::CorruptionDetected);
}
HUF_decodeStreamX1(dst, op1, opStart2, &mut bd1, dtable, dtLog);
HUF_decodeStreamX1(dst, op2, opStart3, &mut bd2, dtable, dtLog);
HUF_decodeStreamX1(dst, op3, opStart4, &mut bd3, dtable, dtLog);
HUF_decodeStreamX1(dst, op4, dstSize, &mut bd4, dtable, dtLog);
let endCheck = BIT_endOfDStream(&bd1)
& BIT_endOfDStream(&bd2)
& BIT_endOfDStream(&bd3)
& BIT_endOfDStream(&bd4);
if endCheck == 0 {
return ERROR(ErrorCode::CorruptionDetected);
}
dstSize
}
pub fn HUF_decompress4X1_usingDTable_internal(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
let fast_ret = HUF_decompress4X1_usingDTable_internal_fast_impl(dst, cSrc, dtable);
if fast_ret != 0 {
return fast_ret;
}
HUF_decompress4X1_usingDTable_internal_body_impl(dst, cSrc, dtable)
}
#[inline]
pub fn HUF_decompress4X1_usingDTable_internal_body(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
HUF_decompress4X1_usingDTable_internal_body_impl(dst, cSrc, dtable)
}
#[inline]
pub fn HUF_decompress4X1_usingDTable_internal_default(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
HUF_decompress4X1_usingDTable_internal_body_impl(dst, cSrc, dtable)
}
#[inline]
pub fn HUF_decompress4X1_usingDTable_internal_bmi2(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
{
if std::is_x86_feature_detected!("bmi1")
&& std::is_x86_feature_detected!("bmi2")
&& std::is_x86_feature_detected!("lzcnt")
{
return unsafe { HUF_decompress4X1_usingDTable_internal_bmi2_impl(dst, cSrc, dtable) };
}
}
HUF_decompress4X1_usingDTable_internal_body_impl(dst, cSrc, dtable)
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[target_feature(enable = "bmi1,bmi2,lzcnt")]
unsafe fn HUF_decompress4X1_usingDTable_internal_bmi2_impl(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
use crate::common::bitstream::{
BIT_DStream_t, BIT_DStream_unfinished, BIT_endOfDStream, BIT_initDStream,
BIT_reloadDStreamFast,
};
use crate::common::error::{ErrorCode, ERROR};
use crate::common::mem::MEM_readLE16;
let dstSize = dst.len();
let cSrcSize = cSrc.len();
if cSrcSize < 10 {
return ERROR(ErrorCode::CorruptionDetected);
}
if dstSize < 6 {
return ERROR(ErrorCode::CorruptionDetected);
}
let length1 = MEM_readLE16(&cSrc[0..2]) as usize;
let length2 = MEM_readLE16(&cSrc[2..4]) as usize;
let length3 = MEM_readLE16(&cSrc[4..6]) as usize;
let header_size: usize = 6;
let accounted = match length1
.checked_add(length2)
.and_then(|v| v.checked_add(length3))
.and_then(|v| v.checked_add(header_size))
{
Some(v) => v,
None => return ERROR(ErrorCode::CorruptionDetected),
};
if accounted > cSrcSize {
return ERROR(ErrorCode::CorruptionDetected);
}
let length4 = cSrcSize - accounted;
let istart1 = header_size;
let istart2 = istart1 + length1;
let istart3 = istart2 + length2;
let istart4 = istart3 + length3;
let segmentSize = dstSize.div_ceil(4);
let opStart2 = segmentSize;
let opStart3 = 2 * segmentSize;
let opStart4 = 3 * segmentSize;
if opStart4 > dstSize {
return ERROR(ErrorCode::CorruptionDetected);
}
let dtd = HUF_getDTableDesc(dtable);
let dtLog = dtd.tableLog as u32;
let mut bd1 = BIT_DStream_t::default();
let mut bd2 = BIT_DStream_t::default();
let mut bd3 = BIT_DStream_t::default();
let mut bd4 = BIT_DStream_t::default();
let rc = BIT_initDStream(&mut bd1, &cSrc[istart1..istart1 + length1], length1);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let rc = BIT_initDStream(&mut bd2, &cSrc[istart2..istart2 + length2], length2);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let rc = BIT_initDStream(&mut bd3, &cSrc[istart3..istart3 + length3], length3);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let rc = BIT_initDStream(&mut bd4, &cSrc[istart4..istart4 + length4], length4);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let mut op1 = 0usize;
let mut op2 = opStart2;
let mut op3 = opStart3;
let mut op4 = opStart4;
let olimit = dstSize.saturating_sub(3);
let mut endSignal = 1u32;
if dstSize - op4 >= core::mem::size_of::<usize>() {
loop {
if endSignal == 0 || op4 >= olimit {
break;
}
dst[op1] = HUF_decodeSymbolX1_bmi2(&mut bd1, dtable, dtLog);
op1 += 1;
dst[op2] = HUF_decodeSymbolX1_bmi2(&mut bd2, dtable, dtLog);
op2 += 1;
dst[op3] = HUF_decodeSymbolX1_bmi2(&mut bd3, dtable, dtLog);
op3 += 1;
dst[op4] = HUF_decodeSymbolX1_bmi2(&mut bd4, dtable, dtLog);
op4 += 1;
dst[op1] = HUF_decodeSymbolX1_bmi2(&mut bd1, dtable, dtLog);
op1 += 1;
dst[op2] = HUF_decodeSymbolX1_bmi2(&mut bd2, dtable, dtLog);
op2 += 1;
dst[op3] = HUF_decodeSymbolX1_bmi2(&mut bd3, dtable, dtLog);
op3 += 1;
dst[op4] = HUF_decodeSymbolX1_bmi2(&mut bd4, dtable, dtLog);
op4 += 1;
dst[op1] = HUF_decodeSymbolX1_bmi2(&mut bd1, dtable, dtLog);
op1 += 1;
dst[op2] = HUF_decodeSymbolX1_bmi2(&mut bd2, dtable, dtLog);
op2 += 1;
dst[op3] = HUF_decodeSymbolX1_bmi2(&mut bd3, dtable, dtLog);
op3 += 1;
dst[op4] = HUF_decodeSymbolX1_bmi2(&mut bd4, dtable, dtLog);
op4 += 1;
dst[op1] = HUF_decodeSymbolX1_bmi2(&mut bd1, dtable, dtLog);
op1 += 1;
dst[op2] = HUF_decodeSymbolX1_bmi2(&mut bd2, dtable, dtLog);
op2 += 1;
dst[op3] = HUF_decodeSymbolX1_bmi2(&mut bd3, dtable, dtLog);
op3 += 1;
dst[op4] = HUF_decodeSymbolX1_bmi2(&mut bd4, dtable, dtLog);
op4 += 1;
endSignal &= (BIT_reloadDStreamFast(&mut bd1) == BIT_DStream_unfinished) as u32;
endSignal &= (BIT_reloadDStreamFast(&mut bd2) == BIT_DStream_unfinished) as u32;
endSignal &= (BIT_reloadDStreamFast(&mut bd3) == BIT_DStream_unfinished) as u32;
endSignal &= (BIT_reloadDStreamFast(&mut bd4) == BIT_DStream_unfinished) as u32;
}
}
if op1 > opStart2 || op2 > opStart3 || op3 > opStart4 {
return ERROR(ErrorCode::CorruptionDetected);
}
HUF_decodeStreamX1_bmi2(dst, op1, opStart2, &mut bd1, dtable, dtLog);
HUF_decodeStreamX1_bmi2(dst, op2, opStart3, &mut bd2, dtable, dtLog);
HUF_decodeStreamX1_bmi2(dst, op3, opStart4, &mut bd3, dtable, dtLog);
HUF_decodeStreamX1_bmi2(dst, op4, dstSize, &mut bd4, dtable, dtLog);
let endCheck = BIT_endOfDStream(&bd1)
& BIT_endOfDStream(&bd2)
& BIT_endOfDStream(&bd3)
& BIT_endOfDStream(&bd4);
if endCheck == 0 {
return ERROR(ErrorCode::CorruptionDetected);
}
dstSize
}
#[inline]
pub fn HUF_decompress4X1_usingDTable_internal_fast(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
HUF_decompress4X1_usingDTable_internal_fast_impl(dst, cSrc, dtable)
}
#[inline]
pub fn HUF_decompress4X1_usingDTable_internal_fast_c_loop(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
HUF_decompress4X1_usingDTable_internal_fast(dst, cSrc, dtable)
}
pub fn HUF_decompress4X_usingDTable<const BMI2: bool>(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
let dtd = HUF_getDTableDesc(dtable);
if dtd.tableType != 0 {
if BMI2 {
HUF_decompress4X2_usingDTable_internal_bmi2(dst, cSrc, dtable)
} else {
HUF_decompress4X2_usingDTable_internal_default(dst, cSrc, dtable)
}
} else if BMI2 {
HUF_decompress4X1_usingDTable_internal_bmi2(dst, cSrc, dtable)
} else {
HUF_decompress4X1_usingDTable_internal_default(dst, cSrc, dtable)
}
}
pub fn HUF_decompress1X1_DCtx_wksp(
dctx: &mut [HUF_DTable],
dst: &mut [u8],
cSrc: &[u8],
workSpace: &mut [u32],
flags: i32,
) -> usize {
let hSize = HUF_readDTableX1(dctx, cSrc, workSpace, flags);
if crate::common::error::ERR_isError(hSize) {
return hSize;
}
if hSize >= cSrc.len() {
return crate::common::error::ERROR(crate::common::error::ErrorCode::SrcSizeWrong);
}
if (flags & HUF_flags_bmi2) != 0 {
HUF_decompress1X1_usingDTable_internal_bmi2(dst, &cSrc[hSize..], dctx)
} else {
HUF_decompress1X1_usingDTable_internal(dst, &cSrc[hSize..], dctx)
}
}
pub fn HUF_decompress1X2_usingDTable_internal(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
use crate::common::bitstream::{BIT_DStream_t, BIT_endOfDStream, BIT_initDStream};
use crate::common::error::{ErrorCode, ERROR};
let dstSize = dst.len();
let cSrcSize = cSrc.len();
let mut bitD = BIT_DStream_t::default();
let rc = BIT_initDStream(&mut bitD, cSrc, cSrcSize);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let dtd = HUF_getDTableDesc(dtable);
let dtLog = dtd.tableLog as u32;
HUF_decodeStreamX2(dst, 0, dstSize, &mut bitD, dtable, dtLog);
if BIT_endOfDStream(&bitD) == 0 {
return ERROR(ErrorCode::CorruptionDetected);
}
dstSize
}
#[inline]
pub fn HUF_decompress1X2_usingDTable_internal_body(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
HUF_decompress1X2_usingDTable_internal(dst, cSrc, dtable)
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[target_feature(enable = "bmi1,bmi2,lzcnt")]
unsafe fn HUF_decompress1X2_usingDTable_internal_bmi2_impl(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
use crate::common::bitstream::{BIT_DStream_t, BIT_endOfDStream, BIT_initDStream};
use crate::common::error::{ErrorCode, ERROR};
let dstSize = dst.len();
let cSrcSize = cSrc.len();
let mut bitD = BIT_DStream_t::default();
let rc = BIT_initDStream(&mut bitD, cSrc, cSrcSize);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let dtd = HUF_getDTableDesc(dtable);
let dtLog = dtd.tableLog as u32;
HUF_decodeStreamX2_bmi2(dst, 0, dstSize, &mut bitD, dtable, dtLog);
if BIT_endOfDStream(&bitD) == 0 {
return ERROR(ErrorCode::CorruptionDetected);
}
dstSize
}
#[inline]
pub fn HUF_decompress1X2_usingDTable_internal_bmi2(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
{
if std::is_x86_feature_detected!("bmi1")
&& std::is_x86_feature_detected!("bmi2")
&& std::is_x86_feature_detected!("lzcnt")
{
return unsafe { HUF_decompress1X2_usingDTable_internal_bmi2_impl(dst, cSrc, dtable) };
}
}
HUF_decompress1X2_usingDTable_internal(dst, cSrc, dtable)
}
pub fn HUF_decompress1X2_DCtx_wksp(
dctx: &mut [HUF_DTable],
dst: &mut [u8],
cSrc: &[u8],
workSpace: &mut [u32],
flags: i32,
) -> usize {
let hSize = HUF_readDTableX2(dctx, cSrc, workSpace, flags);
if crate::common::error::ERR_isError(hSize) {
return hSize;
}
if hSize >= cSrc.len() {
return crate::common::error::ERROR(crate::common::error::ErrorCode::SrcSizeWrong);
}
if (flags & HUF_flags_bmi2) != 0 {
HUF_decompress1X2_usingDTable_internal_bmi2(dst, &cSrc[hSize..], dctx)
} else {
HUF_decompress1X2_usingDTable_internal(dst, &cSrc[hSize..], dctx)
}
}
pub fn HUF_decompress1X_DCtx_wksp(
dctx: &mut [HUF_DTable],
dst: &mut [u8],
cSrc: &[u8],
workSpace: &mut [u32],
flags: i32,
) -> usize {
let dstSize = dst.len();
let cSrcSize = cSrc.len();
if dstSize == 0 {
return crate::common::error::ERROR(crate::common::error::ErrorCode::DstSizeTooSmall);
}
if cSrcSize > dstSize {
return crate::common::error::ERROR(crate::common::error::ErrorCode::CorruptionDetected);
}
if cSrcSize == dstSize {
dst[..dstSize].copy_from_slice(&cSrc[..dstSize]);
return dstSize;
}
if cSrcSize == 1 {
for b in dst.iter_mut().take(dstSize) {
*b = cSrc[0];
}
return dstSize;
}
let algoNb = HUF_selectDecoder(dstSize, cSrcSize);
if algoNb != 0 {
HUF_decompress1X2_DCtx_wksp(dctx, dst, cSrc, workSpace, flags)
} else {
HUF_decompress1X1_DCtx_wksp(dctx, dst, cSrc, workSpace, flags)
}
}
pub fn HUF_decompress4X1_DCtx_wksp(
dctx: &mut [HUF_DTable],
dst: &mut [u8],
cSrc: &[u8],
workSpace: &mut [u32],
flags: i32,
) -> usize {
let hSize = HUF_readDTableX1(dctx, cSrc, workSpace, flags);
if crate::common::error::ERR_isError(hSize) {
return hSize;
}
if hSize >= cSrc.len() {
return crate::common::error::ERROR(crate::common::error::ErrorCode::SrcSizeWrong);
}
if (flags & HUF_flags_disableFast) != 0 {
if (flags & HUF_flags_bmi2) != 0 {
HUF_decompress4X1_usingDTable_internal_bmi2(dst, &cSrc[hSize..], dctx)
} else {
HUF_decompress4X1_usingDTable_internal_default(dst, &cSrc[hSize..], dctx)
}
} else {
HUF_decompress4X1_usingDTable_internal(dst, &cSrc[hSize..], dctx)
}
}
fn HUF_decompress4X2_usingDTable_internal_fast_impl(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
use crate::common::bitstream::BIT_DStream_t;
use crate::common::error::{ERR_isError, ErrorCode, ERROR};
let mut args = match HUF_DecompressFastArgs_init(dst.len(), cSrc, dtable) {
Ok(Some(args)) => args,
Ok(None) => return 0,
Err(err) => return err,
};
HUF_decompress4X2_usingDTable_internal_fast_c_loop_impl(&mut args, dst, cSrc, dtable);
if args.ip.iter().any(|&ip| ip < args.ilowest) || args.op[3] > args.oend {
return ERROR(ErrorCode::CorruptionDetected);
}
let segmentSize = dst.len().div_ceil(4);
let mut segmentEnd = 0usize;
for i in 0..4 {
segmentEnd = (segmentEnd + segmentSize).min(dst.len());
let mut bit = BIT_DStream_t::default();
let rc = HUF_initRemainingDStream_fromFast(&mut bit, cSrc, &args, i, segmentEnd);
if ERR_isError(rc) {
return rc;
}
args.op[i] += HUF_decodeStreamX2(
dst,
args.op[i],
segmentEnd,
&mut bit,
dtable,
HUF_DECODER_FAST_TABLELOG,
);
if args.op[i] != segmentEnd {
return ERROR(ErrorCode::CorruptionDetected);
}
}
dst.len()
}
fn HUF_decompress4X2_usingDTable_internal_fast_c_loop_impl(
args: &mut HUF_DecompressFastArgs,
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) {
let mut bits = args.bits;
let mut ip = args.ip;
let mut op = args.op;
let ilowest = args.ilowest;
let mut oend = [0usize; 4];
oend[0] = op[1];
oend[1] = op[2];
oend[2] = op[3];
oend[3] = args.oend;
loop {
let mut iters = (ip[0] - ilowest) / 7;
for stream in 0..4 {
iters = iters.min((oend[stream] - op[stream]) / 10);
}
let olimit = op[3] + iters * 5;
if op[3] == olimit {
break;
}
if ip[1] < ip[0] || ip[2] < ip[1] || ip[3] < ip[2] {
break;
}
while op[3] < olimit {
for _ in 0..5 {
for stream in 0..3 {
let index = (bits[stream] >> 53) as usize;
let entry = read_entry_x2(dtable, index);
let bytes = entry.sequence.to_le_bytes();
dst[op[stream]] = bytes[0];
if entry.length > 1 {
dst[op[stream] + 1] = bytes[1];
}
bits[stream] <<= (entry.nbBits & 0x3f) as u32;
op[stream] += entry.length as usize;
}
}
for _ in 0..5 {
let index = (bits[3] >> 53) as usize;
let entry = read_entry_x2(dtable, index);
let bytes = entry.sequence.to_le_bytes();
dst[op[3]] = bytes[0];
if entry.length > 1 {
dst[op[3] + 1] = bytes[1];
}
bits[3] <<= (entry.nbBits & 0x3f) as u32;
op[3] += entry.length as usize;
}
for stream in 0..4 {
let ctz = bits[stream].trailing_zeros() as usize;
let nbBits = ctz & 7;
let nbBytes = ctz >> 3;
ip[stream] -= nbBytes;
bits[stream] = crate::common::mem::MEM_readLE64(&cSrc[ip[stream]..]) | 1;
bits[stream] <<= nbBits as u32;
}
}
}
args.bits = bits;
args.ip = ip;
args.op = op;
}
fn HUF_decompress4X2_usingDTable_internal_body_impl(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
use crate::common::bitstream::{
BIT_DStream_t, BIT_DStream_unfinished, BIT_endOfDStream, BIT_initDStream,
BIT_reloadDStreamFast,
};
use crate::common::error::{ErrorCode, ERROR};
use crate::common::mem::MEM_readLE16;
let dstSize = dst.len();
let cSrcSize = cSrc.len();
if cSrcSize < 10 {
return ERROR(ErrorCode::CorruptionDetected);
}
if dstSize < 6 {
return ERROR(ErrorCode::CorruptionDetected);
}
let length1 = MEM_readLE16(&cSrc[0..2]) as usize;
let length2 = MEM_readLE16(&cSrc[2..4]) as usize;
let length3 = MEM_readLE16(&cSrc[4..6]) as usize;
let header_size = 6usize;
let accounted = match length1
.checked_add(length2)
.and_then(|v| v.checked_add(length3))
.and_then(|v| v.checked_add(header_size))
{
Some(v) => v,
None => return ERROR(ErrorCode::CorruptionDetected),
};
if accounted > cSrcSize {
return ERROR(ErrorCode::CorruptionDetected);
}
let length4 = cSrcSize - accounted;
let istart1 = header_size;
let istart2 = istart1 + length1;
let istart3 = istart2 + length2;
let istart4 = istart3 + length3;
let segmentSize = dstSize.div_ceil(4);
let opStart2 = segmentSize;
let opStart3 = 2 * segmentSize;
let opStart4 = 3 * segmentSize;
if opStart4 > dstSize {
return ERROR(ErrorCode::CorruptionDetected);
}
let dtd = HUF_getDTableDesc(dtable);
let dtLog = dtd.tableLog as u32;
let mut bd1 = BIT_DStream_t::default();
let mut bd2 = BIT_DStream_t::default();
let mut bd3 = BIT_DStream_t::default();
let mut bd4 = BIT_DStream_t::default();
let rc = BIT_initDStream(&mut bd1, &cSrc[istart1..istart1 + length1], length1);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let rc = BIT_initDStream(&mut bd2, &cSrc[istart2..istart2 + length2], length2);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let rc = BIT_initDStream(&mut bd3, &cSrc[istart3..istart3 + length3], length3);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let rc = BIT_initDStream(&mut bd4, &cSrc[istart4..istart4 + length4], length4);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let olimit = dstSize.saturating_sub(core::mem::size_of::<usize>() - 1);
let mut op1 = 0usize;
let mut op2 = opStart2;
let mut op3 = opStart3;
let mut op4 = opStart4;
let mut endSignal = 1u32;
if dstSize - op4 >= core::mem::size_of::<usize>() {
loop {
if endSignal == 0 || op4 >= olimit {
break;
}
op1 += HUF_decodeSymbolX2(dst, op1, &mut bd1, dtable, dtLog) as usize;
op2 += HUF_decodeSymbolX2(dst, op2, &mut bd2, dtable, dtLog) as usize;
op3 += HUF_decodeSymbolX2(dst, op3, &mut bd3, dtable, dtLog) as usize;
op4 += HUF_decodeSymbolX2(dst, op4, &mut bd4, dtable, dtLog) as usize;
op1 += HUF_decodeSymbolX2(dst, op1, &mut bd1, dtable, dtLog) as usize;
op2 += HUF_decodeSymbolX2(dst, op2, &mut bd2, dtable, dtLog) as usize;
op3 += HUF_decodeSymbolX2(dst, op3, &mut bd3, dtable, dtLog) as usize;
op4 += HUF_decodeSymbolX2(dst, op4, &mut bd4, dtable, dtLog) as usize;
op1 += HUF_decodeSymbolX2(dst, op1, &mut bd1, dtable, dtLog) as usize;
op2 += HUF_decodeSymbolX2(dst, op2, &mut bd2, dtable, dtLog) as usize;
op3 += HUF_decodeSymbolX2(dst, op3, &mut bd3, dtable, dtLog) as usize;
op4 += HUF_decodeSymbolX2(dst, op4, &mut bd4, dtable, dtLog) as usize;
op1 += HUF_decodeSymbolX2(dst, op1, &mut bd1, dtable, dtLog) as usize;
op2 += HUF_decodeSymbolX2(dst, op2, &mut bd2, dtable, dtLog) as usize;
op3 += HUF_decodeSymbolX2(dst, op3, &mut bd3, dtable, dtLog) as usize;
op4 += HUF_decodeSymbolX2(dst, op4, &mut bd4, dtable, dtLog) as usize;
endSignal = (BIT_reloadDStreamFast(&mut bd1) == BIT_DStream_unfinished) as u32
& (BIT_reloadDStreamFast(&mut bd2) == BIT_DStream_unfinished) as u32
& (BIT_reloadDStreamFast(&mut bd3) == BIT_DStream_unfinished) as u32
& (BIT_reloadDStreamFast(&mut bd4) == BIT_DStream_unfinished) as u32;
}
}
if op1 > opStart2 || op2 > opStart3 || op3 > opStart4 {
return ERROR(ErrorCode::CorruptionDetected);
}
HUF_decodeStreamX2(dst, op1, opStart2, &mut bd1, dtable, dtLog);
HUF_decodeStreamX2(dst, op2, opStart3, &mut bd2, dtable, dtLog);
HUF_decodeStreamX2(dst, op3, opStart4, &mut bd3, dtable, dtLog);
HUF_decodeStreamX2(dst, op4, dstSize, &mut bd4, dtable, dtLog);
let endCheck = BIT_endOfDStream(&bd1)
& BIT_endOfDStream(&bd2)
& BIT_endOfDStream(&bd3)
& BIT_endOfDStream(&bd4);
if endCheck == 0 {
return ERROR(ErrorCode::CorruptionDetected);
}
dstSize
}
pub fn HUF_decompress4X2_usingDTable_internal(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
let fast_ret = HUF_decompress4X2_usingDTable_internal_fast_impl(dst, cSrc, dtable);
if fast_ret != 0 {
return fast_ret;
}
HUF_decompress4X2_usingDTable_internal_body_impl(dst, cSrc, dtable)
}
#[inline]
pub fn HUF_decompress4X2_usingDTable_internal_body(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
HUF_decompress4X2_usingDTable_internal_body_impl(dst, cSrc, dtable)
}
#[inline]
pub fn HUF_decompress4X2_usingDTable_internal_default(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
HUF_decompress4X2_usingDTable_internal_body_impl(dst, cSrc, dtable)
}
#[inline]
pub fn HUF_decompress4X2_usingDTable_internal_bmi2(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
{
if std::is_x86_feature_detected!("bmi1")
&& std::is_x86_feature_detected!("bmi2")
&& std::is_x86_feature_detected!("lzcnt")
{
return unsafe { HUF_decompress4X2_usingDTable_internal_bmi2_impl(dst, cSrc, dtable) };
}
}
HUF_decompress4X2_usingDTable_internal_body_impl(dst, cSrc, dtable)
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[target_feature(enable = "bmi1,bmi2,lzcnt")]
unsafe fn HUF_decompress4X2_usingDTable_internal_bmi2_impl(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
use crate::common::bitstream::{
BIT_DStream_t, BIT_DStream_unfinished, BIT_endOfDStream, BIT_initDStream,
BIT_reloadDStreamFast,
};
use crate::common::error::{ErrorCode, ERROR};
use crate::common::mem::MEM_readLE16;
let dstSize = dst.len();
let cSrcSize = cSrc.len();
if cSrcSize < 10 {
return ERROR(ErrorCode::CorruptionDetected);
}
if dstSize < 6 {
return ERROR(ErrorCode::CorruptionDetected);
}
let length1 = MEM_readLE16(&cSrc[0..2]) as usize;
let length2 = MEM_readLE16(&cSrc[2..4]) as usize;
let length3 = MEM_readLE16(&cSrc[4..6]) as usize;
let header_size = 6usize;
let accounted = match length1
.checked_add(length2)
.and_then(|v| v.checked_add(length3))
.and_then(|v| v.checked_add(header_size))
{
Some(v) => v,
None => return ERROR(ErrorCode::CorruptionDetected),
};
if accounted > cSrcSize {
return ERROR(ErrorCode::CorruptionDetected);
}
let length4 = cSrcSize - accounted;
let istart1 = header_size;
let istart2 = istart1 + length1;
let istart3 = istart2 + length2;
let istart4 = istart3 + length3;
let segmentSize = dstSize.div_ceil(4);
let opStart2 = segmentSize;
let opStart3 = 2 * segmentSize;
let opStart4 = 3 * segmentSize;
if opStart4 > dstSize {
return ERROR(ErrorCode::CorruptionDetected);
}
let dtd = HUF_getDTableDesc(dtable);
let dtLog = dtd.tableLog as u32;
let mut bd1 = BIT_DStream_t::default();
let mut bd2 = BIT_DStream_t::default();
let mut bd3 = BIT_DStream_t::default();
let mut bd4 = BIT_DStream_t::default();
let rc = BIT_initDStream(&mut bd1, &cSrc[istart1..istart1 + length1], length1);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let rc = BIT_initDStream(&mut bd2, &cSrc[istart2..istart2 + length2], length2);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let rc = BIT_initDStream(&mut bd3, &cSrc[istart3..istart3 + length3], length3);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let rc = BIT_initDStream(&mut bd4, &cSrc[istart4..istart4 + length4], length4);
if crate::common::error::ERR_isError(rc) {
return rc;
}
let olimit = dstSize.saturating_sub(core::mem::size_of::<usize>() - 1);
let mut op1 = 0usize;
let mut op2 = opStart2;
let mut op3 = opStart3;
let mut op4 = opStart4;
let mut endSignal = 1u32;
if dstSize - op4 >= core::mem::size_of::<usize>() {
loop {
if endSignal == 0 || op4 >= olimit {
break;
}
op1 += HUF_decodeSymbolX2_bmi2(dst, op1, &mut bd1, dtable, dtLog) as usize;
op2 += HUF_decodeSymbolX2_bmi2(dst, op2, &mut bd2, dtable, dtLog) as usize;
op3 += HUF_decodeSymbolX2_bmi2(dst, op3, &mut bd3, dtable, dtLog) as usize;
op4 += HUF_decodeSymbolX2_bmi2(dst, op4, &mut bd4, dtable, dtLog) as usize;
op1 += HUF_decodeSymbolX2_bmi2(dst, op1, &mut bd1, dtable, dtLog) as usize;
op2 += HUF_decodeSymbolX2_bmi2(dst, op2, &mut bd2, dtable, dtLog) as usize;
op3 += HUF_decodeSymbolX2_bmi2(dst, op3, &mut bd3, dtable, dtLog) as usize;
op4 += HUF_decodeSymbolX2_bmi2(dst, op4, &mut bd4, dtable, dtLog) as usize;
op1 += HUF_decodeSymbolX2_bmi2(dst, op1, &mut bd1, dtable, dtLog) as usize;
op2 += HUF_decodeSymbolX2_bmi2(dst, op2, &mut bd2, dtable, dtLog) as usize;
op3 += HUF_decodeSymbolX2_bmi2(dst, op3, &mut bd3, dtable, dtLog) as usize;
op4 += HUF_decodeSymbolX2_bmi2(dst, op4, &mut bd4, dtable, dtLog) as usize;
op1 += HUF_decodeSymbolX2_bmi2(dst, op1, &mut bd1, dtable, dtLog) as usize;
op2 += HUF_decodeSymbolX2_bmi2(dst, op2, &mut bd2, dtable, dtLog) as usize;
op3 += HUF_decodeSymbolX2_bmi2(dst, op3, &mut bd3, dtable, dtLog) as usize;
op4 += HUF_decodeSymbolX2_bmi2(dst, op4, &mut bd4, dtable, dtLog) as usize;
endSignal = (BIT_reloadDStreamFast(&mut bd1) == BIT_DStream_unfinished) as u32
& (BIT_reloadDStreamFast(&mut bd2) == BIT_DStream_unfinished) as u32
& (BIT_reloadDStreamFast(&mut bd3) == BIT_DStream_unfinished) as u32
& (BIT_reloadDStreamFast(&mut bd4) == BIT_DStream_unfinished) as u32;
}
}
if op1 > opStart2 || op2 > opStart3 || op3 > opStart4 {
return ERROR(ErrorCode::CorruptionDetected);
}
HUF_decodeStreamX2_bmi2(dst, op1, opStart2, &mut bd1, dtable, dtLog);
HUF_decodeStreamX2_bmi2(dst, op2, opStart3, &mut bd2, dtable, dtLog);
HUF_decodeStreamX2_bmi2(dst, op3, opStart4, &mut bd3, dtable, dtLog);
HUF_decodeStreamX2_bmi2(dst, op4, dstSize, &mut bd4, dtable, dtLog);
let endCheck = BIT_endOfDStream(&bd1)
& BIT_endOfDStream(&bd2)
& BIT_endOfDStream(&bd3)
& BIT_endOfDStream(&bd4);
if endCheck == 0 {
return ERROR(ErrorCode::CorruptionDetected);
}
dstSize
}
#[inline]
pub fn HUF_decompress4X2_usingDTable_internal_fast(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
HUF_decompress4X2_usingDTable_internal_fast_impl(dst, cSrc, dtable)
}
#[inline]
pub fn HUF_decompress4X2_usingDTable_internal_fast_c_loop(
dst: &mut [u8],
cSrc: &[u8],
dtable: &[HUF_DTable],
) -> usize {
HUF_decompress4X2_usingDTable_internal_fast(dst, cSrc, dtable)
}
pub fn HUF_decompress4X2_DCtx_wksp(
dctx: &mut [HUF_DTable],
dst: &mut [u8],
cSrc: &[u8],
workSpace: &mut [u32],
flags: i32,
) -> usize {
let hSize = HUF_readDTableX2(dctx, cSrc, workSpace, flags);
if crate::common::error::ERR_isError(hSize) {
return hSize;
}
if hSize >= cSrc.len() {
return crate::common::error::ERROR(crate::common::error::ErrorCode::SrcSizeWrong);
}
if (flags & HUF_flags_disableFast) != 0 {
if (flags & HUF_flags_bmi2) != 0 {
HUF_decompress4X2_usingDTable_internal_bmi2(dst, &cSrc[hSize..], dctx)
} else {
HUF_decompress4X2_usingDTable_internal_default(dst, &cSrc[hSize..], dctx)
}
} else {
HUF_decompress4X2_usingDTable_internal(dst, &cSrc[hSize..], dctx)
}
}
pub fn HUF_decompress4X_hufOnly_wksp(
dctx: &mut [HUF_DTable],
dst: &mut [u8],
cSrc: &[u8],
workSpace: &mut [u32],
flags: i32,
) -> usize {
if dst.is_empty() {
return crate::common::error::ERROR(crate::common::error::ErrorCode::DstSizeTooSmall);
}
if cSrc.is_empty() {
return crate::common::error::ERROR(crate::common::error::ErrorCode::CorruptionDetected);
}
let algoNb = HUF_selectDecoder(dst.len(), cSrc.len());
if algoNb != 0 {
HUF_decompress4X2_DCtx_wksp(dctx, dst, cSrc, workSpace, flags)
} else {
HUF_decompress4X1_DCtx_wksp(dctx, dst, cSrc, workSpace, flags)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dtable_desc_roundtrip() {
let d = DTableDesc {
maxTableLog: 12,
tableType: 0,
tableLog: 11,
reserved: 0,
};
let mut tbl = [0u32; 4];
HUF_setDTableDesc(&mut tbl, d);
assert_eq!(HUF_getDTableDesc(&tbl), d);
}
#[test]
fn deltx2_pack_roundtrip() {
let e = HUF_DEltX2 {
sequence: 0xBEEF,
nbBits: 10,
length: 2,
};
let p = HUF_DEltX2_pack(e);
let r = HUF_DEltX2_unpack(p);
assert_eq!(r.sequence, 0xBEEF);
assert_eq!(r.nbBits, 10);
assert_eq!(r.length, 2);
}
#[test]
fn deltx2_u64_stamps_two_identical_entries() {
let packed = HUF_buildDEltX2U32(0x34, 6, 0x12, 2);
let wide = HUF_buildDEltX2U64(0x34, 6, 0x12, 2);
assert_eq!(wide as u32, packed);
assert_eq!((wide >> 32) as u32, packed);
}
#[test]
fn deltx2_read_write_round_trip_via_dtable() {
let mut dt = [0u32; 16];
write_entry_x2(
&mut dt,
3,
HUF_DEltX2 {
sequence: 0x1234,
nbBits: 7,
length: 1,
},
);
let e = read_entry_x2(&dt, 3);
assert_eq!(e.sequence, 0x1234);
assert_eq!(e.nbBits, 7);
assert_eq!(e.length, 1);
}
#[test]
fn huf_port_name_wrappers_forward_to_scalar_paths() {
let mut bit = crate::common::bitstream::BIT_DStream_t::default();
let bit_src = [0x80u8];
assert!(!crate::common::error::ERR_isError(
HUF_initRemainingDStream(&mut bit, &bit_src)
));
let mut dtable = vec![0u32; HUF_DTABLE_SIZE_U32(1)];
HUF_setDTableDesc(
&mut dtable,
DTableDesc {
maxTableLog: 1,
tableType: 0,
tableLog: 1,
reserved: 0,
},
);
let mut dst = [0u8; 4];
let short = [0u8; 1];
let expected = HUF_decompress4X1_usingDTable_internal(&mut dst, &short, &dtable);
assert_eq!(
HUF_decompress4X1_usingDTable_internal_default(&mut dst, &short, &dtable),
expected
);
assert_eq!(
HUF_decompress4X1_usingDTable_internal_bmi2(&mut dst, &short, &dtable),
expected
);
assert_eq!(
HUF_decompress4X1_usingDTable_internal_fast(&mut dst, &short, &dtable),
expected
);
assert_eq!(
HUF_decompress4X1_usingDTable_internal_fast_c_loop(&mut dst, &short, &dtable),
expected
);
let expected = HUF_decompress4X2_usingDTable_internal(&mut dst, &short, &dtable);
assert_eq!(
HUF_decompress4X2_usingDTable_internal_default(&mut dst, &short, &dtable),
expected
);
assert_eq!(
HUF_decompress4X2_usingDTable_internal_bmi2(&mut dst, &short, &dtable),
expected
);
assert_eq!(
HUF_decompress4X2_usingDTable_internal_fast(&mut dst, &short, &dtable),
expected
);
assert_eq!(
HUF_decompress4X2_usingDTable_internal_fast_c_loop(&mut dst, &short, &dtable),
expected
);
}
#[test]
fn fast_wrappers_return_zero_when_fast_decode_declines() {
let mut dtable = vec![0u32; HUF_DTABLE_SIZE_U32(1)];
HUF_setDTableDesc(
&mut dtable,
DTableDesc {
maxTableLog: 1,
tableType: 0,
tableLog: 1,
reserved: 0,
},
);
let mut dst = [0u8; 16];
let csrc = [0x80u8; 10];
assert_eq!(
HUF_decompress4X1_usingDTable_internal_fast(&mut dst, &csrc, &dtable),
0
);
assert_eq!(
HUF_decompress4X1_usingDTable_internal_fast_c_loop(&mut dst, &csrc, &dtable),
0
);
assert_eq!(
HUF_decompress4X2_usingDTable_internal_fast(&mut dst, &csrc, &dtable),
0
);
assert_eq!(
HUF_decompress4X2_usingDTable_internal_fast_c_loop(&mut dst, &csrc, &dtable),
0
);
}
#[test]
fn deltx1_pack_roundtrip() {
let e = HUF_DEltX1 {
nbBits: 7,
byte: 0xA5,
};
let s = HUF_DEltX1_pack(e);
let r = HUF_DEltX1_unpack(s);
assert_eq!(r.nbBits, e.nbBits);
assert_eq!(r.byte, e.byte);
}
#[test]
fn deltx1_set4_stamps_four_identical_entries() {
let word = HUF_DEltX1_set4(0xAA, 3);
let lane = (word & 0xFFFF) as u16;
assert_eq!((word >> 16) & 0xFFFF, lane as u64);
assert_eq!((word >> 32) & 0xFFFF, lane as u64);
assert_eq!((word >> 48) & 0xFFFF, lane as u64);
if crate::common::mem::is_little_endian() {
assert_eq!(lane & 0xFF, 3);
assert_eq!(lane >> 8, 0xAA);
}
}
#[test]
fn rescale_stats_noop_when_below_target() {
let mut weights = [2u8, 3, 0, 5];
let mut ranks = [0u32, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let out = HUF_rescaleStats(&mut weights, &mut ranks, 4, 5, 5);
assert_eq!(out, 5);
assert_eq!(weights, [2, 3, 0, 5]); }
#[test]
fn rescale_stats_noop_when_above_target() {
let mut weights = [2u8, 3, 0, 5];
let mut ranks = [0u32; 13];
let out = HUF_rescaleStats(&mut weights, &mut ranks, 4, 7, 5);
assert_eq!(out, 7);
assert_eq!(weights, [2, 3, 0, 5]);
}
#[test]
fn read_dtable_x1_raw_header_populates_entries() {
let src = [130u8, 0x12, 0x10];
let mut dtable = [0u32; 16];
HUF_setDTableDesc(
&mut dtable,
DTableDesc {
maxTableLog: 2,
..Default::default()
},
);
let mut wksp = [0u32; HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
let iSize = HUF_readDTableX1(&mut dtable, &src, &mut wksp, 0);
assert!(
!crate::common::error::ERR_isError(iSize),
"readDTableX1 returned error: {}",
crate::common::error::ERR_getErrorName(iSize)
);
assert_eq!(iSize, 3);
let dtd = HUF_getDTableDesc(&dtable);
assert_eq!(dtd.tableType, 0);
assert_eq!(dtd.tableLog, 3);
let tableSize = 1usize << dtd.tableLog;
for i in 0..tableSize {
let e = read_entry(&dtable, i);
assert!(
e.nbBits > 0 && e.nbBits <= dtd.tableLog,
"entry {i} has invalid nbBits {}",
e.nbBits
);
assert!(
(e.byte as u32) < 4,
"entry {i} decodes to out-of-range symbol {}",
e.byte
);
}
}
#[test]
fn decompress1X2_DCtx_roundtrips_compress1X_output() {
use crate::compress::huf_compress::HUF_compress1X_repeat;
let mut src = vec![0u8; 4096];
for (i, b) in src.iter_mut().enumerate() {
*b = match i % 16 {
0..=4 => 0,
5..=9 => 1,
10..=12 => 2,
13 => 3,
14 => 4,
_ => 5,
};
}
let mut compressed = vec![0u8; src.len() + 256];
let n = HUF_compress1X_repeat(&mut compressed, &src, 5, 11, None, None, 0);
assert!(
!crate::common::error::ERR_isError(n),
"compress1X failed: {n:#x}"
);
assert!(
n > 0 && n < src.len(),
"expected actual compression, got n={n}"
);
compressed.truncate(n);
let mut dtable = vec![0u32; HUF_DTABLE_SIZE_U32(HUF_TABLELOG_MAX)];
let mtl_minus_1 = HUF_TABLELOG_MAX - 1;
dtable[0] = mtl_minus_1 * 0x01_00_00_01;
let mut wksp = vec![0u32; HUF_DECOMPRESS_WORKSPACE_SIZE_U32];
let mut decoded = vec![0u8; src.len()];
let r = HUF_decompress1X2_DCtx_wksp(&mut dtable, &mut decoded, &compressed, &mut wksp, 0);
assert!(
!crate::common::error::ERR_isError(r),
"1X2 decode failed: {r:#x}"
);
assert_eq!(r, src.len());
assert_eq!(decoded, src, "1X2 decode mismatched input");
}
#[test]
fn rescale_stats_raises_tableLog() {
let mut weights = [2u8, 3, 0, 5];
let mut ranks = [0u32; 13];
ranks[0] = 1;
ranks[2] = 1;
ranks[3] = 1;
ranks[5] = 1;
let out = HUF_rescaleStats(&mut weights, &mut ranks, 4, 5, 8);
assert_eq!(out, 8);
assert_eq!(weights, [5, 6, 0, 8]);
assert_eq!(ranks[8], 1);
assert_eq!(ranks[6], 1);
assert_eq!(ranks[5], 1);
assert_eq!(ranks[1], 0);
assert_eq!(ranks[2], 0);
assert_eq!(ranks[3], 0);
}
}