// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
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) catch {
e => Err(e)
} noraise {
value => Ok(value)
}
match compressed {
Ok(candidate) =>
if candidate.length() > 0 && candidate.length() < best.length() {
best = candidate
}
Err(_) => ()
}
append_bytes(out, best, 0, best.length())
}