pub(crate) mod read;
pub(crate) mod write;
pub use read::{
read_inkb, read_inkb_index, read_section_address_paths, read_section_addresses,
read_section_containers, read_section_externals, read_section_line_tables,
read_section_list_defs, read_section_list_items, read_section_list_literals,
read_section_name_table, read_section_variables,
};
pub use write::{
assemble_inkb, write_inkb, write_section_address_paths, write_section_addresses,
write_section_containers, write_section_externals, write_section_line_tables,
write_section_list_defs, write_section_list_items, write_section_list_literals,
write_section_name_table, write_section_variables,
};
use std::ops::Range;
use crate::opcode::DecodeError;
pub(crate) const MAGIC: &[u8; 4] = b"INKB";
pub(crate) const VERSION: u16 = 2;
pub(crate) const HEADER_PREAMBLE: usize = 16;
pub(crate) const SECTION_ENTRY_SIZE: usize = 8;
pub(crate) const SECTION_COUNT: u8 = 10;
pub(crate) const VAL_INT: u8 = 0x00;
pub(crate) const VAL_FLOAT: u8 = 0x01;
pub(crate) const VAL_BOOL: u8 = 0x02;
pub(crate) const VAL_STRING: u8 = 0x03;
pub(crate) const VAL_LIST: u8 = 0x04;
pub(crate) const VAL_DIVERT_TARGET: u8 = 0x05;
pub(crate) const VAL_NULL: u8 = 0x06;
pub(crate) const VAL_VAR_POINTER: u8 = 0x07;
pub(crate) const VAL_FRAGMENT_REF: u8 = 0x08;
pub(crate) const LINE_PLAIN: u8 = 0x00;
pub(crate) const LINE_TEMPLATE: u8 = 0x01;
pub(crate) const PART_LITERAL: u8 = 0x00;
pub(crate) const PART_SLOT: u8 = 0x01;
pub(crate) const PART_SELECT: u8 = 0x02;
pub(crate) const KEY_CARDINAL: u8 = 0x00;
pub(crate) const KEY_ORDINAL: u8 = 0x01;
pub(crate) const KEY_EXACT: u8 = 0x02;
pub(crate) const KEY_KEYWORD: u8 = 0x03;
pub(crate) const CAT_ZERO: u8 = 0x00;
pub(crate) const CAT_ONE: u8 = 0x01;
pub(crate) const CAT_TWO: u8 = 0x02;
pub(crate) const CAT_FEW: u8 = 0x03;
pub(crate) const CAT_MANY: u8 = 0x04;
pub(crate) const CAT_OTHER: u8 = 0x05;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum SectionKind {
NameTable = 0x01,
Variables = 0x02,
ListDefs = 0x03,
ListItems = 0x04,
Externals = 0x05,
Containers = 0x06,
LineTables = 0x07,
Labels = 0x08,
ListLiterals = 0x09,
AddressPaths = 0x0A,
}
impl SectionKind {
pub(crate) fn from_u8(tag: u8) -> Result<Self, DecodeError> {
match tag {
0x01 => Ok(Self::NameTable),
0x02 => Ok(Self::Variables),
0x03 => Ok(Self::ListDefs),
0x04 => Ok(Self::ListItems),
0x05 => Ok(Self::Externals),
0x06 => Ok(Self::Containers),
0x07 => Ok(Self::LineTables),
0x08 => Ok(Self::Labels),
0x09 => Ok(Self::ListLiterals),
0x0A => Ok(Self::AddressPaths),
_ => Err(DecodeError::InvalidSectionKind(tag)),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SectionEntry {
pub kind: SectionKind,
pub offset: u32,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InkbIndex {
pub version: u16,
pub file_size: u32,
pub checksum: u32,
pub sections: Vec<SectionEntry>,
}
impl InkbIndex {
pub fn header_size(&self) -> usize {
HEADER_PREAMBLE + self.sections.len() * SECTION_ENTRY_SIZE
}
pub fn section_range(&self, kind: SectionKind) -> Option<Range<usize>> {
let idx = self.sections.iter().position(|e| e.kind == kind)?;
let start = self.sections[idx].offset as usize;
let end = self
.sections
.get(idx + 1)
.map_or(self.file_size, |e| e.offset) as usize;
Some(start..end)
}
}
pub(crate) fn safe_capacity(
count: usize,
buf_len: usize,
offset: usize,
min_element_size: usize,
) -> usize {
let remaining = buf_len.saturating_sub(offset);
let max_possible = remaining.checked_div(min_element_size).unwrap_or(remaining);
count.min(max_possible)
}