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