1pub(crate) mod read;
28pub(crate) mod write;
29
30pub use read::{
31 read_inkb, read_inkb_index, read_section_address_paths, read_section_addresses,
32 read_section_containers, read_section_externals, read_section_line_tables,
33 read_section_list_defs, read_section_list_items, read_section_list_literals,
34 read_section_name_table, read_section_variables,
35};
36pub use write::{
37 assemble_inkb, write_inkb, write_section_address_paths, write_section_addresses,
38 write_section_containers, write_section_externals, write_section_line_tables,
39 write_section_list_defs, write_section_list_items, write_section_list_literals,
40 write_section_name_table, write_section_variables,
41};
42
43use std::ops::Range;
44
45use crate::opcode::DecodeError;
46
47pub(crate) const MAGIC: &[u8; 4] = b"INKB";
50pub(crate) const VERSION: u16 = 3;
56pub(crate) const HEADER_PREAMBLE: usize = 16;
58pub(crate) const SECTION_ENTRY_SIZE: usize = 8;
60pub(crate) const SECTION_COUNT: u8 = 10;
62
63pub(crate) const VAL_INT: u8 = 0x00;
65pub(crate) const VAL_FLOAT: u8 = 0x01;
66pub(crate) const VAL_BOOL: u8 = 0x02;
67pub(crate) const VAL_STRING: u8 = 0x03;
68pub(crate) const VAL_LIST: u8 = 0x04;
69pub(crate) const VAL_DIVERT_TARGET: u8 = 0x05;
70pub(crate) const VAL_NULL: u8 = 0x06;
71pub(crate) const VAL_VAR_POINTER: u8 = 0x07;
72pub(crate) const VAL_FRAGMENT_REF: u8 = 0x08;
73
74pub(crate) const LINE_PLAIN: u8 = 0x00;
76pub(crate) const LINE_TEMPLATE: u8 = 0x01;
77
78pub(crate) const PART_LITERAL: u8 = 0x00;
80pub(crate) const PART_SLOT: u8 = 0x01;
81pub(crate) const PART_SELECT: u8 = 0x02;
82
83pub(crate) const KEY_CARDINAL: u8 = 0x00;
85pub(crate) const KEY_ORDINAL: u8 = 0x01;
86pub(crate) const KEY_EXACT: u8 = 0x02;
87pub(crate) const KEY_KEYWORD: u8 = 0x03;
88
89pub(crate) const CAT_ZERO: u8 = 0x00;
91pub(crate) const CAT_ONE: u8 = 0x01;
92pub(crate) const CAT_TWO: u8 = 0x02;
93pub(crate) const CAT_FEW: u8 = 0x03;
94pub(crate) const CAT_MANY: u8 = 0x04;
95pub(crate) const CAT_OTHER: u8 = 0x05;
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
101#[repr(u8)]
102pub enum SectionKind {
103 NameTable = 0x01,
104 Variables = 0x02,
105 ListDefs = 0x03,
106 ListItems = 0x04,
107 Externals = 0x05,
108 Containers = 0x06,
109 LineTables = 0x07,
110 Labels = 0x08,
111 ListLiterals = 0x09,
112 AddressPaths = 0x0A,
113}
114
115impl SectionKind {
116 pub(crate) fn from_u8(tag: u8) -> Result<Self, DecodeError> {
117 match tag {
118 0x01 => Ok(Self::NameTable),
119 0x02 => Ok(Self::Variables),
120 0x03 => Ok(Self::ListDefs),
121 0x04 => Ok(Self::ListItems),
122 0x05 => Ok(Self::Externals),
123 0x06 => Ok(Self::Containers),
124 0x07 => Ok(Self::LineTables),
125 0x08 => Ok(Self::Labels),
126 0x09 => Ok(Self::ListLiterals),
127 0x0A => Ok(Self::AddressPaths),
128 _ => Err(DecodeError::InvalidSectionKind(tag)),
129 }
130 }
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq)]
135pub struct SectionEntry {
136 pub kind: SectionKind,
137 pub offset: u32,
138}
139
140#[derive(Debug, Clone, PartialEq, Eq)]
144pub struct InkbIndex {
145 pub version: u16,
146 pub file_size: u32,
147 pub checksum: u32,
148 pub sections: Vec<SectionEntry>,
149}
150
151impl InkbIndex {
152 pub fn header_size(&self) -> usize {
154 HEADER_PREAMBLE + self.sections.len() * SECTION_ENTRY_SIZE
155 }
156
157 pub fn section_range(&self, kind: SectionKind) -> Option<Range<usize>> {
163 let idx = self.sections.iter().position(|e| e.kind == kind)?;
164 let start = self.sections[idx].offset as usize;
165 let end = self
166 .sections
167 .get(idx + 1)
168 .map_or(self.file_size, |e| e.offset) as usize;
169 Some(start..end)
170 }
171}
172
173pub(crate) fn safe_capacity(
177 count: usize,
178 buf_len: usize,
179 offset: usize,
180 min_element_size: usize,
181) -> usize {
182 let remaining = buf_len.saturating_sub(offset);
183 let max_possible = remaining.checked_div(min_element_size).unwrap_or(remaining);
184 count.min(max_possible)
185}