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 = 2;
54pub(crate) const HEADER_PREAMBLE: usize = 16;
56pub(crate) const SECTION_ENTRY_SIZE: usize = 8;
58pub(crate) const SECTION_COUNT: u8 = 10;
60
61pub(crate) const VAL_INT: u8 = 0x00;
63pub(crate) const VAL_FLOAT: u8 = 0x01;
64pub(crate) const VAL_BOOL: u8 = 0x02;
65pub(crate) const VAL_STRING: u8 = 0x03;
66pub(crate) const VAL_LIST: u8 = 0x04;
67pub(crate) const VAL_DIVERT_TARGET: u8 = 0x05;
68pub(crate) const VAL_NULL: u8 = 0x06;
69pub(crate) const VAL_VAR_POINTER: u8 = 0x07;
70pub(crate) const VAL_FRAGMENT_REF: u8 = 0x08;
71
72pub(crate) const LINE_PLAIN: u8 = 0x00;
74pub(crate) const LINE_TEMPLATE: u8 = 0x01;
75
76pub(crate) const PART_LITERAL: u8 = 0x00;
78pub(crate) const PART_SLOT: u8 = 0x01;
79pub(crate) const PART_SELECT: u8 = 0x02;
80
81pub(crate) const KEY_CARDINAL: u8 = 0x00;
83pub(crate) const KEY_ORDINAL: u8 = 0x01;
84pub(crate) const KEY_EXACT: u8 = 0x02;
85pub(crate) const KEY_KEYWORD: u8 = 0x03;
86
87pub(crate) const CAT_ZERO: u8 = 0x00;
89pub(crate) const CAT_ONE: u8 = 0x01;
90pub(crate) const CAT_TWO: u8 = 0x02;
91pub(crate) const CAT_FEW: u8 = 0x03;
92pub(crate) const CAT_MANY: u8 = 0x04;
93pub(crate) const CAT_OTHER: u8 = 0x05;
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
99#[repr(u8)]
100pub enum SectionKind {
101 NameTable = 0x01,
102 Variables = 0x02,
103 ListDefs = 0x03,
104 ListItems = 0x04,
105 Externals = 0x05,
106 Containers = 0x06,
107 LineTables = 0x07,
108 Labels = 0x08,
109 ListLiterals = 0x09,
110 AddressPaths = 0x0A,
111}
112
113impl SectionKind {
114 pub(crate) fn from_u8(tag: u8) -> Result<Self, DecodeError> {
115 match tag {
116 0x01 => Ok(Self::NameTable),
117 0x02 => Ok(Self::Variables),
118 0x03 => Ok(Self::ListDefs),
119 0x04 => Ok(Self::ListItems),
120 0x05 => Ok(Self::Externals),
121 0x06 => Ok(Self::Containers),
122 0x07 => Ok(Self::LineTables),
123 0x08 => Ok(Self::Labels),
124 0x09 => Ok(Self::ListLiterals),
125 0x0A => Ok(Self::AddressPaths),
126 _ => Err(DecodeError::InvalidSectionKind(tag)),
127 }
128 }
129}
130
131#[derive(Debug, Clone, Copy, PartialEq, Eq)]
133pub struct SectionEntry {
134 pub kind: SectionKind,
135 pub offset: u32,
136}
137
138#[derive(Debug, Clone, PartialEq, Eq)]
142pub struct InkbIndex {
143 pub version: u16,
144 pub file_size: u32,
145 pub checksum: u32,
146 pub sections: Vec<SectionEntry>,
147}
148
149impl InkbIndex {
150 pub fn header_size(&self) -> usize {
152 HEADER_PREAMBLE + self.sections.len() * SECTION_ENTRY_SIZE
153 }
154
155 pub fn section_range(&self, kind: SectionKind) -> Option<Range<usize>> {
161 let idx = self.sections.iter().position(|e| e.kind == kind)?;
162 let start = self.sections[idx].offset as usize;
163 let end = self
164 .sections
165 .get(idx + 1)
166 .map_or(self.file_size, |e| e.offset) as usize;
167 Some(start..end)
168 }
169}
170
171pub(crate) fn safe_capacity(
175 count: usize,
176 buf_len: usize,
177 offset: usize,
178 min_element_size: usize,
179) -> usize {
180 let remaining = buf_len.saturating_sub(offset);
181 let max_possible = remaining.checked_div(min_element_size).unwrap_or(remaining);
182 count.min(max_possible)
183}