///|
fn append_literals_header(
out : Array[Byte],
lit_len : Int,
literals_block_type : UInt,
) -> Unit raise ZstdError {
if literals_block_type != 0 && literals_block_type != 1 {
raise CorruptionDetected
}
if lit_len < 0 || lit_len > 131072 {
raise CorruptionDetected
}
if lit_len <= 31 {
out.push(
((lit_len.reinterpret_as_uint() << 3) + literals_block_type).to_byte(),
)
} else if lit_len <= 4095 {
out.push(
(((lit_len & 0xF).reinterpret_as_uint() << 4) + 0x04 + literals_block_type).to_byte(),
)
out.push(((lit_len >> 4).reinterpret_as_uint() & 0xFF).to_byte())
} else {
out.push(
(((lit_len & 0xF).reinterpret_as_uint() << 4) + 0x0C + literals_block_type).to_byte(),
)
out.push(((lit_len >> 4).reinterpret_as_uint() & 0xFF).to_byte())
out.push(((lit_len >> 12).reinterpret_as_uint() & 0xFF).to_byte())
}
}
///|
fn append_raw_literals_section_bytes(literals : Bytes) -> Bytes raise ZstdError {
let out : Array[Byte] = Array::new()
let lit_len = literals.length()
append_literals_header(out, lit_len, 0)
append_bytes(out, literals, 0, lit_len)
Bytes::from_array(out)
}
///|
fn append_rle_literals_section_bytes(literals : Bytes) -> Bytes raise ZstdError {
let out : Array[Byte] = Array::new()
let lit_len = literals.length()
if lit_len <= 0 {
raise CorruptionDetected
}
append_literals_header(out, lit_len, 1)
out.push(literals[0])
Bytes::from_array(out)
}
///|
fn is_single_value_literals(literals : Bytes) -> Bool {
let lit_len = literals.length()
if lit_len <= 1 {
return false
}
let first = literals[0]
let mut i = 1
while i < lit_len {
if literals[i] != first {
return false
}
i = i + 1
}
true
}
///|
fn append_best_literals_section(
out : Array[Byte],
literals : Bytes,
) -> Unit raise ZstdError {
let mut best = append_raw_literals_section_bytes(literals)
if is_single_value_literals(literals) {
let rle = append_rle_literals_section_bytes(literals)
if rle.length() < best.length() {
best = rle
}
}
let compressed = try? try_build_compressed_literals_section(literals)
match compressed {
Ok(candidate) =>
if candidate.length() > 0 && candidate.length() < best.length() {
best = candidate
}
Err(_) => ()
}
append_bytes(out, best, 0, best.length())
}