// 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 decode_literals_section_minimal(
src : Bytes,
start : Int,
end_pos : Int,
prev_huf_valid : Ref[Bool],
prev_huf_max_bits : Ref[Int],
prev_huf_left : Ref[Array[Int]],
prev_huf_right : Ref[Array[Int]],
prev_huf_symbol : Ref[Array[Int]],
) -> (Int, Bytes) raise ZstdError {
if start >= end_pos {
raise CorruptionDetected
}
let byte0 = src[start].to_uint()
let literals_block_type = byte0 & 0x3
let size_format = (byte0 >> 2) & 0x3
if literals_block_type == 0 || literals_block_type == 1 {
let (header_size, regenerated_size) = match size_format {
0 => (1, byte0 >> 3)
1 => {
if start + 2 > end_pos {
raise SrcSizeWrong
}
let b1 = src[start + 1].to_uint()
(2, (byte0 >> 4) + (b1 << 4))
}
2 => (1, byte0 >> 3)
3 => {
if start + 3 > end_pos {
raise SrcSizeWrong
}
let b1 = src[start + 1].to_uint()
let b2 = src[start + 2].to_uint()
(3, (byte0 >> 4) + (b1 << 4) + (b2 << 12))
}
_ => raise CorruptionDetected
}
let data_pos = start + header_size
let regen_len = regenerated_size.reinterpret_as_int()
let literals : Array[Byte] = Array::new()
if literals_block_type == 0 {
if data_pos + regen_len > end_pos {
raise SrcSizeWrong
}
append_bytes(literals, src, data_pos, regen_len)
(data_pos + regen_len, Bytes::from_array(literals))
} else if regen_len == 0 {
(data_pos, Bytes::from_array(literals))
} else {
if data_pos + 1 > end_pos {
raise SrcSizeWrong
}
let value = src[data_pos]
let mut i = 0
while i < regen_len {
literals.push(value)
i = i + 1
}
(data_pos + 1, Bytes::from_array(literals))
}
} else if literals_block_type == 2 || literals_block_type == 3 {
if start + 4 > end_pos {
raise SrcSizeWrong
}
let lhc = read_u32_le(src, start)
let single_stream = size_format == 0
let (header_size, lit_size, lit_c_size) = if size_format == 0 ||
size_format == 1 {
(
3,
((lhc >> 4) & 0x3FF).reinterpret_as_int(),
((lhc >> 14) & 0x3FF).reinterpret_as_int(),
)
} else if size_format == 2 {
(
4,
((lhc >> 4) & 0x3FFF).reinterpret_as_int(),
(lhc >> 18).reinterpret_as_int(),
)
} else {
if start + 5 > end_pos {
raise SrcSizeWrong
}
let b4 = src[start + 4].to_uint()
(
5,
((lhc >> 4) & 0x3FFFF).reinterpret_as_int(),
((lhc >> 22) + (b4 << 10)).reinterpret_as_int(),
)
}
if lit_size < 0 || lit_c_size <= 0 {
raise CorruptionDetected
}
if !single_stream && lit_size < 6 {
raise CorruptionDetected
}
let payload_pos = start + header_size
if payload_pos + lit_c_size > end_pos {
raise CorruptionDetected
}
let payload_end = payload_pos + lit_c_size
let (max_bits, left, right, symbol, stream_pos) = if literals_block_type ==
2 {
let (tree_size, tree_max_bits, tree_left, tree_right, tree_symbol) = read_huffman_tree_description(
src, payload_pos, payload_end,
)
prev_huf_valid.val = true
prev_huf_max_bits.val = tree_max_bits
prev_huf_left.val = tree_left
prev_huf_right.val = tree_right
prev_huf_symbol.val = tree_symbol
(
tree_max_bits,
tree_left,
tree_right,
tree_symbol,
payload_pos + tree_size,
)
} else {
if !prev_huf_valid.val {
raise CorruptionDetected
}
(
prev_huf_max_bits.val,
prev_huf_left.val,
prev_huf_right.val,
prev_huf_symbol.val,
payload_pos,
)
}
if stream_pos > payload_end {
raise CorruptionDetected
}
let literals = if single_stream {
decode_huffman_single_stream(
src, stream_pos, payload_end, lit_size, max_bits, left, right, symbol,
)
} else {
decode_huffman_four_streams(
src, stream_pos, payload_end, lit_size, max_bits, left, right, symbol,
)
}
(payload_end, literals)
} else {
raise CorruptionDetected
}
}