// Copyright 2026 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.
///|
pub struct CffIndex {
count : Int
off_size : Int
offsets : Array[Int]
data : Bytes
} derive(Eq, Show, ToJson)
///|
pub fn parse_cff1_index(data : BytesView, offset : Int) -> Result[CffIndex, CffError] {
parse_cff_index(data, offset, 2)
}
///|
pub fn parse_cff2_index(data : BytesView, offset : Int) -> Result[CffIndex, CffError] {
parse_cff_index(data, offset, 4)
}
fn parse_cff_index(
data : BytesView,
offset : Int,
count_bytes : Int,
) -> Result[CffIndex, CffError] {
let count =
if count_bytes == 2 {
read_u16_int(data, offset)
} else if count_bytes == 4 {
read_u32_int(data, offset)
} else {
Err(InvalidFormat)
}
match count {
Err(err) => Err(err)
Ok(count) => {
if count < 0 {
return Err(InvalidFormat)
}
if count == 0 {
return Ok(CffIndex::{ count: 0, off_size: 0, offsets: [], data: Bytes::from_array([]) })
}
let off_size = read_u8_int(data, offset + count_bytes)
match off_size {
Err(err) => Err(err)
Ok(off_size) => {
if off_size <= 0 || off_size > 4 {
return Err(InvalidFormat)
}
let mut pos = offset + count_bytes + 1
let offsets : Array[Int] = []
for _ in 0..<(count + 1) {
let value = read_cff_offset(data, pos, off_size)
match value {
Err(err) => return Err(err)
Ok(v) => offsets.push(v)
}
pos = pos + off_size
}
let data_start = pos
let last = offsets[offsets.length() - 1]
if last <= 0 {
return Err(InvalidFormat)
}
let data_len = last - 1
if data_len < 0 || data_start + data_len > data.length() {
return Err(UnexpectedEof)
}
let data_bytes = data[data_start:data_start + data_len].to_bytes()
Ok(CffIndex::{ count, off_size, offsets, data: data_bytes })
}
}
}
}
}
///|
pub fn CffIndex::item_bytes(self : CffIndex, index : Int) -> Result[Bytes, CffError] {
if index < 0 || index >= self.count {
return Err(InvalidFormat)
}
if self.count == 0 {
return Ok(Bytes::from_array([]))
}
let start = self.offsets[index] - 1
let end = self.offsets[index + 1] - 1
if start < 0 || end < start || end > self.data.length() {
return Err(InvalidFormat)
}
Ok(self.data[start:end].to_bytes())
}
///|
pub fn CffIndex::byte_len(self : CffIndex, count_bytes : Int) -> Int {
if self.count == 0 {
return count_bytes
}
count_bytes + 1 + (self.count + 1) * self.off_size + self.data.length()
}