// 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.
///|
fn parse_lookup(
data : BytesView,
offset : Int,
extension_lookup_type : Int,
) -> Result[(Int, Int, Int?, Array[Int]), OtLayoutError] {
if offset < 0 || offset + 6 > data.length() {
return Err(UnexpectedEof)
}
let lookup_type = read_u16_int(data, offset)
let lookup_flag = read_u16_int(data, offset + 2)
let subtable_count = read_u16_int(data, offset + 4)
match (lookup_type, lookup_flag, subtable_count) {
(Err(err), _, _) => Err(err)
(_, Err(err), _) => Err(err)
(_, _, Err(err)) => Err(err)
(Ok(lookup_type), Ok(lookup_flag), Ok(subtable_count)) => {
let header_len = 6 + subtable_count * 2
if offset + header_len > data.length() {
return Err(UnexpectedEof)
}
let offsets : Array[Int] = []
let mut resolved_type = lookup_type
let mut extension_subtable_type : Int? = None
let base = offset + 6
for i in 0.. return Err(err)
Ok(sub_offset) => {
if sub_offset == 0 {
return Err(InvalidFormat)
}
let abs_offset = offset + sub_offset
if abs_offset < 0 || abs_offset >= data.length() {
return Err(UnexpectedEof)
}
if lookup_type == extension_lookup_type {
let ext = parse_extension_subtable(data, abs_offset)
match ext {
Err(err) => return Err(err)
Ok((ext_type, ext_offset)) => {
match extension_subtable_type {
None => extension_subtable_type = Some(ext_type)
Some(prev) => if prev != ext_type { return Err(InvalidFormat) }
}
offsets.push(ext_offset)
}
}
} else {
offsets.push(abs_offset)
}
}
}
}
if lookup_type == extension_lookup_type {
match extension_subtable_type {
None => return Err(InvalidFormat)
Some(value) => resolved_type = value
}
}
let mark_filtering_set =
if (lookup_flag & 0x0010) != 0 {
let mark_offset = offset + header_len
if mark_offset + 2 > data.length() {
return Err(UnexpectedEof)
}
match read_u16_int(data, mark_offset) {
Err(err) => return Err(err)
Ok(value) => Some(value)
}
} else {
None
}
Ok((resolved_type, lookup_flag, mark_filtering_set, offsets))
}
}
}
///|
fn parse_extension_subtable(
data : BytesView,
offset : Int,
) -> Result[(Int, Int), OtLayoutError] {
if offset < 0 || offset + 8 > data.length() {
return Err(UnexpectedEof)
}
let format = read_u16_int(data, offset)
let lookup_type = read_u16_int(data, offset + 2)
let extension_offset = read_u32_int(data, offset + 4)
match (format, lookup_type, extension_offset) {
(Err(err), _, _) => Err(err)
(_, Err(err), _) => Err(err)
(_, _, Err(err)) => Err(err)
(Ok(format), Ok(lookup_type), Ok(extension_offset)) => {
if format != 1 {
return Err(InvalidFormat)
}
if extension_offset <= 0 {
return Err(InvalidFormat)
}
let abs_offset = offset + extension_offset
if abs_offset < 0 || abs_offset >= data.length() {
return Err(UnexpectedEof)
}
Ok((lookup_type, abs_offset))
}
}
}