// 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 finalize_offset_off_base(
raw_offset : Int,
ll0 : Bool,
rep1 : Int,
rep2 : Int,
rep3 : Int,
) -> Int raise ZstdError {
if raw_offset <= 0 {
raise CorruptionDetected
}
if !ll0 && raw_offset == rep1 {
return 1
}
if raw_offset == rep2 {
return if ll0 { 1 } else { 2 }
}
if raw_offset == rep3 {
return if ll0 { 2 } else { 3 }
}
if ll0 && rep1 > 1 && raw_offset == rep1 - 1 {
return 3
}
raw_offset + 3
}
///|
fn update_repcodes_with_off_base(
ll0 : Bool,
off_base : Int,
rep1 : Int,
rep2 : Int,
rep3 : Int,
) -> (Int, Int, Int) raise ZstdError {
if off_base <= 0 {
raise CorruptionDetected
}
if off_base > 3 {
let raw = off_base - 3
if raw <= 0 {
raise CorruptionDetected
}
return (raw, rep1, rep2)
}
let rep_code = off_base - 1 + (if ll0 { 1 } else { 0 })
if rep_code == 0 {
return (rep1, rep2, rep3)
}
let current = if rep_code == 3 {
rep1 - 1
} else if rep_code == 2 {
rep3
} else {
rep2
}
if current <= 0 {
raise CorruptionDetected
}
let nr3 = if rep_code >= 2 { rep2 } else { rep3 }
(current, rep1, nr3)
}
///|
fn offset_symbol_from_off_base(
off_base : Int,
) -> (UInt, UInt, Int) raise ZstdError {
if off_base <= 0 {
raise CorruptionDetected
}
let mut bits = 0
let mut v = off_base
while v > 1 {
v = v >> 1
bits = bits + 1
}
if bits > 31 {
raise CorruptionDetected
}
if bits == 0 {
return (0, (0 : UInt), 0)
}
if bits == 1 {
return (1, (off_base & 1).reinterpret_as_uint(), 1)
}
let base = 1 << bits
let extra = off_base - base
if extra < 0 {
raise CorruptionDetected
}
let span = (((1 : UInt64) << bits) - (1 : UInt64)).to_int()
if extra > span {
raise CorruptionDetected
}
(bits.reinterpret_as_uint(), extra.reinterpret_as_uint(), bits)
}