1use alloc::string::String;
4use alloc::vec::Vec;
5
6use crate::codec::{crc32, read_def_id, read_i32, read_str, read_u8, read_u16, read_u32, read_u64};
7use crate::counting::CountingFlags;
8use crate::definition::{
9 AddressDef, AddressPath, AliasEntry, CallAtom, CapabilityParam, ContainerDef, DirectEffects,
10 DispatchEntry, EffectRowEntry, ExternalFnDef, FrameShapeDef, GlobalVarDef, LineEntry, ListDef,
11 ListItemDef, ParamMeta, ScopeLineTable, SlotInfo, SourceLocation, StructShapeDef,
12};
13use crate::id::{DefinitionId, NameId};
14use crate::line::{LineContent, LinePart, PluralCategory, SelectKey};
15use crate::opcode::DecodeError;
16use crate::story::StoryData;
17use crate::value::{
18 ClosureEnvEntry, ListValue, MAX_DECODE_DEPTH, MapKey, OrderedMap, ShapeId, Value, ValueType,
19};
20
21use super::write::{
22 ALIAS_TABLE_SECTION_VERSION, EFFECT_ROWS_SECTION_VERSION, FRAME_SHAPES_SECTION_VERSION,
23};
24use super::{
25 CAP_PARAM_ANY, CAT_FEW, CAT_MANY, CAT_ONE, CAT_OTHER, CAT_TWO, CAT_ZERO, HANDLE_PARAM_NONE,
26 HEADER_PREAMBLE, InkbIndex, KEY_CARDINAL, KEY_EXACT, KEY_KEYWORD, KEY_ORDINAL, LINE_PLAIN,
27 LINE_TEMPLATE, MAGIC, PART_LITERAL, PART_SELECT, PART_SLOT, PART_SPAN, PROJ_SEG_INDEX,
28 PROJ_SEG_KEY, SECTION_ENTRY_SIZE, SectionEntry, SectionKind, VAL_ARRAY, VAL_BOOL, VAL_CLOSURE,
29 VAL_DIVERT_TARGET, VAL_FLOAT, VAL_FN_REF, VAL_FRAGMENT_REF, VAL_HANDLE, VAL_INT, VAL_LIST,
30 VAL_MAP, VAL_MAT2, VAL_MAT3, VAL_MAT4, VAL_NULL, VAL_OPTION, VAL_PROJECTION, VAL_QUAT,
31 VAL_RANGE, VAL_RECORD, VAL_STRING, VAL_VAR_POINTER, VAL_VEC2, VAL_VEC3, VAL_VEC4, VAL_WEIGHTED,
32 VERSION, safe_capacity,
33};
34
35pub fn read_inkb(buf: &[u8]) -> Result<StoryData, DecodeError> {
39 let index = read_inkb_index(buf)?;
40
41 let header_size = index.header_size();
43 let computed = crc32(&buf[header_size..]);
44 if computed != index.checksum {
45 return Err(DecodeError::ChecksumMismatch {
46 expected: index.checksum,
47 actual: computed,
48 });
49 }
50
51 let name_table = read_section_name_table(buf, &index)?;
52 let variables = read_section_variables(buf, &index)?;
53 let list_defs = read_section_list_defs(buf, &index)?;
54 let list_items = read_section_list_items(buf, &index)?;
55 let externals = read_section_externals(buf, &index)?;
56 let containers = read_section_containers(buf, &index)?;
57 let line_tables = read_section_line_tables(buf, &index)?;
58 let addresses = read_section_addresses(buf, &index)?;
59 let list_literals = read_section_list_literals(buf, &index)?;
60 let address_paths = read_section_address_paths(buf, &index)?;
61 let literal_pool = read_section_literal_pool(buf, &index)?;
62 let struct_shapes = read_section_struct_shapes(buf, &index)?;
63 let private_defs = read_section_visibility(buf, &index)?;
64 let alias_table = read_section_alias_table(buf, &index)?;
65 let effect_rows = read_section_effect_rows(buf, &index)?;
66 let frame_shapes = read_section_frame_shapes(buf, &index)?;
67
68 Ok(StoryData {
69 containers,
70 line_tables,
71 variables,
72 list_defs,
73 list_items,
74 externals,
75 addresses,
76 address_paths,
77 name_table,
78 list_literals,
79 literal_pool,
80 struct_shapes,
81 private_defs,
82 alias_table,
83 effect_rows,
84 frame_shapes,
85 source_checksum: index.checksum,
86 })
87}
88
89pub fn read_inkb_index(buf: &[u8]) -> Result<InkbIndex, DecodeError> {
93 if buf.len() < HEADER_PREAMBLE {
94 return Err(DecodeError::UnexpectedEof);
95 }
96
97 let magic: [u8; 4] = [buf[0], buf[1], buf[2], buf[3]];
98 if &magic != MAGIC {
99 return Err(DecodeError::BadMagic(magic));
100 }
101
102 let mut off = 4;
103 let version = read_u16(buf, &mut off)?;
104 if version != VERSION {
105 return Err(DecodeError::UnsupportedVersion(version));
106 }
107
108 let section_count = read_u8(buf, &mut off)?;
109 let _reserved = read_u8(buf, &mut off)?;
110 let file_size = read_u32(buf, &mut off)?;
111 let checksum = read_u32(buf, &mut off)?;
112
113 if file_size as usize != buf.len() {
115 return Err(DecodeError::FileSizeMismatch {
116 expected: file_size,
117 actual: buf.len(),
118 });
119 }
120
121 let total_header = HEADER_PREAMBLE + section_count as usize * SECTION_ENTRY_SIZE;
122 if buf.len() < total_header {
123 return Err(DecodeError::UnexpectedEof);
124 }
125
126 let mut sections = Vec::with_capacity(section_count as usize);
127 for _ in 0..section_count {
128 let kind_tag = read_u8(buf, &mut off)?;
129 let kind = SectionKind::from_u8(kind_tag)?;
130 let _reserved0 = read_u8(buf, &mut off)?;
131 let _reserved1 = read_u8(buf, &mut off)?;
132 let _reserved2 = read_u8(buf, &mut off)?;
133 let offset = read_u32(buf, &mut off)?;
134 sections.push(SectionEntry { kind, offset });
135 }
136
137 #[expect(clippy::cast_possible_truncation)]
143 let header_size = total_header as u32;
144 let mut prev_offset = header_size;
145 for entry in §ions {
146 if entry.offset < header_size || entry.offset > file_size || entry.offset < prev_offset {
147 return Err(DecodeError::InvalidSectionOffset {
148 kind: entry.kind as u8,
149 offset: entry.offset,
150 });
151 }
152 prev_offset = entry.offset;
153 }
154
155 Ok(InkbIndex {
156 version,
157 file_size,
158 checksum,
159 sections,
160 })
161}
162
163pub fn read_section_name_table(buf: &[u8], index: &InkbIndex) -> Result<Vec<String>, DecodeError> {
167 let range =
168 index
169 .section_range(SectionKind::NameTable)
170 .ok_or(DecodeError::MissingSectionKind(
171 SectionKind::NameTable as u8,
172 ))?;
173 let mut off = range.start;
174 let count = read_u32(buf, &mut off)? as usize;
175 let mut names = Vec::with_capacity(safe_capacity(count, buf.len(), off, 4));
176 for _ in 0..count {
177 names.push(read_str(buf, &mut off)?);
178 }
179 Ok(names)
180}
181
182pub fn read_section_variables(
184 buf: &[u8],
185 index: &InkbIndex,
186) -> Result<Vec<GlobalVarDef>, DecodeError> {
187 let range =
188 index
189 .section_range(SectionKind::Variables)
190 .ok_or(DecodeError::MissingSectionKind(
191 SectionKind::Variables as u8,
192 ))?;
193 let mut off = range.start;
194 let count = read_u32(buf, &mut off)? as usize;
195 let mut vars = Vec::with_capacity(safe_capacity(count, buf.len(), off, 12));
196 for _ in 0..count {
197 vars.push(decode_global_var(buf, &mut off)?);
198 }
199 Ok(vars)
200}
201
202pub fn read_section_list_defs(buf: &[u8], index: &InkbIndex) -> Result<Vec<ListDef>, DecodeError> {
204 let range = index
205 .section_range(SectionKind::ListDefs)
206 .ok_or(DecodeError::MissingSectionKind(SectionKind::ListDefs as u8))?;
207 let mut off = range.start;
208 let count = read_u32(buf, &mut off)? as usize;
209 let mut defs = Vec::with_capacity(safe_capacity(count, buf.len(), off, 14));
210 for _ in 0..count {
211 defs.push(decode_list_def(buf, &mut off)?);
212 }
213 Ok(defs)
214}
215
216pub fn read_section_list_items(
218 buf: &[u8],
219 index: &InkbIndex,
220) -> Result<Vec<ListItemDef>, DecodeError> {
221 let range =
222 index
223 .section_range(SectionKind::ListItems)
224 .ok_or(DecodeError::MissingSectionKind(
225 SectionKind::ListItems as u8,
226 ))?;
227 let mut off = range.start;
228 let count = read_u32(buf, &mut off)? as usize;
229 let mut items = Vec::with_capacity(safe_capacity(count, buf.len(), off, 20));
230 for _ in 0..count {
231 items.push(decode_list_item(buf, &mut off)?);
232 }
233 Ok(items)
234}
235
236pub fn read_section_externals(
238 buf: &[u8],
239 index: &InkbIndex,
240) -> Result<Vec<ExternalFnDef>, DecodeError> {
241 let range =
242 index
243 .section_range(SectionKind::Externals)
244 .ok_or(DecodeError::MissingSectionKind(
245 SectionKind::Externals as u8,
246 ))?;
247 let mut off = range.start;
248 let count = read_u32(buf, &mut off)? as usize;
249 let mut exts = Vec::with_capacity(safe_capacity(count, buf.len(), off, 12));
250 for _ in 0..count {
251 exts.push(decode_external(buf, &mut off)?);
252 }
253 Ok(exts)
254}
255
256pub fn read_section_containers(
258 buf: &[u8],
259 index: &InkbIndex,
260) -> Result<Vec<ContainerDef>, DecodeError> {
261 let range =
262 index
263 .section_range(SectionKind::Containers)
264 .ok_or(DecodeError::MissingSectionKind(
265 SectionKind::Containers as u8,
266 ))?;
267 let mut off = range.start;
268 let count = read_u32(buf, &mut off)? as usize;
269 let mut containers = Vec::with_capacity(safe_capacity(count, buf.len(), off, 21));
270 for _ in 0..count {
271 containers.push(decode_container(buf, &mut off)?);
272 }
273 Ok(containers)
274}
275
276pub fn read_section_addresses(
278 buf: &[u8],
279 index: &InkbIndex,
280) -> Result<Vec<AddressDef>, DecodeError> {
281 let Some(range) = index.section_range(SectionKind::Labels) else {
282 return Ok(Vec::new());
284 };
285 let mut off = range.start;
286 let count = read_u32(buf, &mut off)? as usize;
287 let mut addresses = Vec::with_capacity(safe_capacity(count, buf.len(), off, 20));
289 for _ in 0..count {
290 let id = read_def_id(buf, &mut off)?;
291 let container_id = read_def_id(buf, &mut off)?;
292 let byte_offset = read_u32(buf, &mut off)?;
293 addresses.push(AddressDef {
294 id,
295 container_id,
296 byte_offset,
297 });
298 }
299 Ok(addresses)
300}
301
302pub fn read_section_address_paths(
304 buf: &[u8],
305 index: &InkbIndex,
306) -> Result<Vec<AddressPath>, DecodeError> {
307 let Some(range) = index.section_range(SectionKind::AddressPaths) else {
308 return Ok(Vec::new());
311 };
312 let mut off = range.start;
313 let count = read_u32(buf, &mut off)? as usize;
314 let mut paths = Vec::with_capacity(safe_capacity(count, buf.len(), off, 10));
316 for _ in 0..count {
317 let path = NameId(read_u16(buf, &mut off)?);
318 let target = read_def_id(buf, &mut off)?;
319 paths.push(AddressPath { path, target });
320 }
321 Ok(paths)
322}
323
324fn decode_global_var(buf: &[u8], off: &mut usize) -> Result<GlobalVarDef, DecodeError> {
327 let id = read_def_id(buf, off)?;
328 let name = NameId(read_u16(buf, off)?);
329 let value_type = decode_value_type(buf, off)?;
330 let default_value = decode_value(buf, off, 0)?;
331 let mutable = read_u8(buf, off)? != 0;
332 let local = read_u8(buf, off)? != 0;
333 Ok(GlobalVarDef {
334 id,
335 name,
336 value_type,
337 default_value,
338 mutable,
339 local,
340 })
341}
342
343fn decode_value_type(buf: &[u8], off: &mut usize) -> Result<ValueType, DecodeError> {
344 let tag = read_u8(buf, off)?;
345 match tag {
346 VAL_INT => Ok(ValueType::Int),
347 VAL_FLOAT => Ok(ValueType::Float),
348 VAL_BOOL => Ok(ValueType::Bool),
349 VAL_STRING => Ok(ValueType::String),
350 VAL_LIST => Ok(ValueType::List),
351 VAL_DIVERT_TARGET => Ok(ValueType::DivertTarget),
352 VAL_VAR_POINTER => Ok(ValueType::VariablePointer),
353 VAL_FRAGMENT_REF => Ok(ValueType::FragmentRef),
354 VAL_NULL => Ok(ValueType::Null),
355 VAL_ARRAY => Ok(ValueType::Array),
356 VAL_MAP => Ok(ValueType::Map),
357 VAL_RECORD => Ok(ValueType::Record),
358 VAL_FN_REF => Ok(ValueType::FnRef),
359 VAL_CLOSURE => Ok(ValueType::Closure),
360 VAL_HANDLE => Ok(ValueType::Handle),
361 VAL_PROJECTION => Ok(ValueType::Projection),
362 VAL_OPTION => Ok(ValueType::Option),
363 VAL_RANGE => Ok(ValueType::Range),
364 VAL_VEC2 => Ok(ValueType::Vec2),
365 VAL_VEC3 => Ok(ValueType::Vec3),
366 VAL_VEC4 => Ok(ValueType::Vec4),
367 VAL_QUAT => Ok(ValueType::Quat),
368 VAL_MAT2 => Ok(ValueType::Mat2),
369 VAL_MAT3 => Ok(ValueType::Mat3),
370 VAL_MAT4 => Ok(ValueType::Mat4),
371 VAL_WEIGHTED => Ok(ValueType::Weighted),
372 _ => Err(DecodeError::InvalidValueType(tag)),
373 }
374}
375
376fn read_f32_lanes<const N: usize>(buf: &[u8], off: &mut usize) -> Result<[f32; N], DecodeError> {
382 if *off + 4 * N > buf.len() {
383 return Err(DecodeError::UnexpectedEof);
384 }
385 let mut lanes = [0.0f32; N];
386 for lane in &mut lanes {
387 *lane = f32::from_le_bytes([buf[*off], buf[*off + 1], buf[*off + 2], buf[*off + 3]]);
388 *off += 4;
389 }
390 Ok(lanes)
391}
392
393#[expect(
394 clippy::too_many_lines,
395 reason = "one match arm per value tag — the NS-A1 VAL_OPTION arm pushed this past 100"
396)]
397fn decode_value(buf: &[u8], off: &mut usize, depth: usize) -> Result<Value, DecodeError> {
398 if depth > MAX_DECODE_DEPTH {
399 return Err(DecodeError::MaxDepthExceeded(MAX_DECODE_DEPTH));
400 }
401 let tag = read_u8(buf, off)?;
402 match tag {
403 VAL_INT => Ok(Value::Int(read_i32(buf, off)?)),
404 VAL_FLOAT => {
405 if *off + 4 > buf.len() {
406 return Err(DecodeError::UnexpectedEof);
407 }
408 let v = f32::from_le_bytes([buf[*off], buf[*off + 1], buf[*off + 2], buf[*off + 3]]);
409 *off += 4;
410 Ok(Value::Float(v))
411 }
412 VAL_BOOL => Ok(Value::Bool(read_u8(buf, off)? != 0)),
413 VAL_STRING => Ok(Value::String(read_str(buf, off)?.into())),
414 VAL_LIST => {
415 let item_count = read_u32(buf, off)? as usize;
416 let mut items = Vec::with_capacity(safe_capacity(item_count, buf.len(), *off, 8));
417 for _ in 0..item_count {
418 items.push(read_def_id(buf, off)?);
419 }
420 let origin_count = read_u32(buf, off)? as usize;
421 let mut origins = Vec::with_capacity(safe_capacity(origin_count, buf.len(), *off, 8));
422 for _ in 0..origin_count {
423 origins.push(read_def_id(buf, off)?);
424 }
425 Ok(Value::List(ListValue { items, origins }.into()))
426 }
427 VAL_DIVERT_TARGET => Ok(Value::DivertTarget(read_def_id(buf, off)?)),
428 VAL_VAR_POINTER => Ok(Value::VariablePointer(read_def_id(buf, off)?)),
429 VAL_FRAGMENT_REF => Ok(Value::FragmentRef(read_u32(buf, off)?)),
430 VAL_NULL => Ok(Value::Null),
431 VAL_ARRAY => {
432 let len = read_u32(buf, off)? as usize;
433 let mut items = Vec::with_capacity(safe_capacity(len, buf.len(), *off, 1));
436 for _ in 0..len {
437 items.push(decode_value(buf, off, depth + 1)?);
438 }
439 Ok(Value::array(items))
440 }
441 VAL_MAP => {
442 let len = read_u32(buf, off)? as usize;
443 let mut map = OrderedMap::with_capacity(safe_capacity(len, buf.len(), *off, 2));
444 for _ in 0..len {
445 let key = decode_map_key(buf, off)?;
446 let val = decode_value(buf, off, depth + 1)?;
447 if map.contains_key(&key) {
451 return Err(DecodeError::DuplicateMapKey);
452 }
453 map.insert(key, val);
454 }
455 Ok(Value::map(map))
456 }
457 VAL_RECORD => {
458 let shape = ShapeId(read_u32(buf, off)?);
459 let len = read_u32(buf, off)? as usize;
460 let mut fields = Vec::with_capacity(safe_capacity(len, buf.len(), *off, 1));
461 for _ in 0..len {
462 fields.push(decode_value(buf, off, depth + 1)?);
463 }
464 Ok(Value::record(shape, fields))
465 }
466 VAL_FN_REF => Ok(Value::FnRef(read_def_id(buf, off)?)),
468 VAL_CLOSURE => {
469 let target = read_def_id(buf, off)?;
470 let count = read_u16(buf, off)? as usize;
471 let mut env = Vec::with_capacity(safe_capacity(count, buf.len(), *off, 4));
472 for _ in 0..count {
473 let name = NameId(read_u16(buf, off)?);
474 let is_ref = read_u8(buf, off)? != 0;
475 let payload = decode_value(buf, off, depth + 1)?;
476 env.push(ClosureEnvEntry {
477 name,
478 is_ref,
479 payload,
480 });
481 }
482 Ok(Value::closure(target, env))
483 }
484 VAL_HANDLE => {
486 let kind = NameId(read_u16(buf, off)?);
487 let id = read_u64(buf, off)?;
488 Ok(Value::handle(kind, id))
489 }
490 VAL_PROJECTION => {
494 let cell = read_def_id(buf, off)?;
495 let count = read_u8(buf, off)? as usize;
496 let mut segments = Vec::with_capacity(safe_capacity(count, buf.len(), *off, 1));
497 for _ in 0..count {
498 segments.push(decode_proj_segment(buf, off, depth + 1)?);
499 }
500 Ok(Value::projection(cell, segments))
501 }
502 VAL_OPTION => match read_u8(buf, off)? {
508 0 => Ok(Value::none()),
509 1 => Ok(Value::some(decode_value(buf, off, depth + 1)?)),
510 other => Err(DecodeError::InvalidValueType(other)),
511 },
512 VAL_RANGE => {
517 let start = read_i32(buf, off)?;
518 let end = read_i32(buf, off)?;
519 let inclusive = match read_u8(buf, off)? {
520 0 => false,
521 1 => true,
522 other => return Err(DecodeError::InvalidValueType(other)),
523 };
524 Ok(Value::range(start, end, inclusive))
525 }
526 VAL_VEC2 => Ok(Value::Vec2(glam::Vec2::from_array(read_f32_lanes::<2>(
532 buf, off,
533 )?))),
534 VAL_VEC3 => Ok(Value::Vec3(glam::Vec3::from_array(read_f32_lanes::<3>(
535 buf, off,
536 )?))),
537 VAL_VEC4 => Ok(Value::Vec4(glam::Vec4::from_array(read_f32_lanes::<4>(
538 buf, off,
539 )?))),
540 VAL_QUAT => Ok(Value::Quat(glam::Quat::from_array(read_f32_lanes::<4>(
541 buf, off,
542 )?))),
543 VAL_MAT2 => Ok(Value::Mat2(glam::Mat2::from_cols_array(&read_f32_lanes::<
544 4,
545 >(
546 buf, off
547 )?))),
548 VAL_MAT3 => Ok(Value::Mat3(glam::Mat3::from_cols_array(&read_f32_lanes::<
549 9,
550 >(
551 buf, off
552 )?))),
553 VAL_MAT4 => Ok(Value::Mat4(glam::Mat4::from_cols_array(&read_f32_lanes::<
554 16,
555 >(
556 buf, off
557 )?))),
558 VAL_WEIGHTED => {
566 let count = read_u32(buf, off)?;
567 if count == 0 {
568 return Err(DecodeError::InvalidValueType(VAL_WEIGHTED));
569 }
570 let mut entries = Vec::with_capacity(safe_capacity(count as usize, buf.len(), *off, 5));
571 for _ in 0..count {
572 let weight = read_i32(buf, off)?;
573 if weight < 1 {
574 return Err(DecodeError::InvalidValueType(VAL_WEIGHTED));
575 }
576 let value = decode_value(buf, off, depth + 1)?;
577 entries.push((weight, value));
578 }
579 Ok(Value::weighted(entries))
580 }
581 _ => Err(DecodeError::InvalidValueType(tag)),
582 }
583}
584
585fn decode_proj_segment(
587 buf: &[u8],
588 off: &mut usize,
589 depth: usize,
590) -> Result<crate::ProjSegment, DecodeError> {
591 let kind = read_u8(buf, off)?;
592 match kind {
593 PROJ_SEG_INDEX => Ok(crate::ProjSegment::Index(read_i32(buf, off)?)),
594 PROJ_SEG_KEY => Ok(crate::ProjSegment::Key(decode_value(buf, off, depth)?)),
595 other => Err(DecodeError::InvalidProjSegmentKind(other)),
596 }
597}
598
599fn decode_map_key(buf: &[u8], off: &mut usize) -> Result<MapKey, DecodeError> {
603 let tag = read_u8(buf, off)?;
604 match tag {
605 VAL_INT => Ok(MapKey::Int(read_i32(buf, off)?)),
606 VAL_STRING => Ok(MapKey::Str(read_str(buf, off)?.into())),
607 VAL_BOOL => Ok(MapKey::Bool(read_u8(buf, off)? != 0)),
608 _ => Err(DecodeError::InvalidValueType(tag)),
609 }
610}
611
612fn decode_list_def(buf: &[u8], off: &mut usize) -> Result<ListDef, DecodeError> {
613 let id = read_def_id(buf, off)?;
614 let name = NameId(read_u16(buf, off)?);
615 let item_count = read_u32(buf, off)? as usize;
616 let mut items = Vec::with_capacity(safe_capacity(item_count, buf.len(), *off, 6));
617 for _ in 0..item_count {
618 let name_id = NameId(read_u16(buf, off)?);
619 let ordinal = read_i32(buf, off)?;
620 items.push((name_id, ordinal));
621 }
622 Ok(ListDef { id, name, items })
623}
624
625fn decode_list_item(buf: &[u8], off: &mut usize) -> Result<ListItemDef, DecodeError> {
626 let id = read_def_id(buf, off)?;
627 let origin = read_def_id(buf, off)?;
628 let ordinal = read_i32(buf, off)?;
629 let name = NameId(read_u16(buf, off)?);
630 Ok(ListItemDef {
631 id,
632 origin,
633 ordinal,
634 name,
635 })
636}
637
638pub fn read_section_list_literals(
640 buf: &[u8],
641 index: &InkbIndex,
642) -> Result<Vec<ListValue>, DecodeError> {
643 let Some(range) = index.section_range(SectionKind::ListLiterals) else {
644 return Ok(Vec::new());
645 };
646 let mut off = range.start;
647 let count = read_u32(buf, &mut off)? as usize;
648 let mut literals = Vec::with_capacity(safe_capacity(count, buf.len(), off, 8));
649 for _ in 0..count {
650 let item_count = read_u32(buf, &mut off)? as usize;
651 let mut items = Vec::with_capacity(safe_capacity(item_count, buf.len(), off, 8));
652 for _ in 0..item_count {
653 items.push(read_def_id(buf, &mut off)?);
654 }
655 let origin_count = read_u32(buf, &mut off)? as usize;
656 let mut origins = Vec::with_capacity(safe_capacity(origin_count, buf.len(), off, 8));
657 for _ in 0..origin_count {
658 origins.push(read_def_id(buf, &mut off)?);
659 }
660 literals.push(ListValue { items, origins });
661 }
662 Ok(literals)
663}
664
665pub fn read_section_literal_pool(buf: &[u8], index: &InkbIndex) -> Result<Vec<Value>, DecodeError> {
669 let Some(range) = index.section_range(SectionKind::LiteralPool) else {
670 return Ok(Vec::new());
671 };
672 let mut off = range.start;
673 let count = read_u32(buf, &mut off)? as usize;
674 let mut pool = Vec::with_capacity(safe_capacity(count, buf.len(), off, 1));
675 for _ in 0..count {
676 pool.push(decode_value(buf, &mut off, 0)?);
677 }
678 Ok(pool)
679}
680
681pub fn read_section_struct_shapes(
685 buf: &[u8],
686 index: &InkbIndex,
687) -> Result<Vec<StructShapeDef>, DecodeError> {
688 let Some(range) = index.section_range(SectionKind::StructShapes) else {
689 return Ok(Vec::new());
690 };
691 let mut off = range.start;
692 let count = read_u32(buf, &mut off)? as usize;
693 let mut shapes = Vec::with_capacity(safe_capacity(count, buf.len(), off, 8));
694 for _ in 0..count {
695 let id = ShapeId(read_u32(buf, &mut off)?);
696 let name = NameId(read_u16(buf, &mut off)?);
697 let field_count = read_u16(buf, &mut off)? as usize;
698 let mut fields = Vec::with_capacity(safe_capacity(field_count, buf.len(), off, 2));
699 for _ in 0..field_count {
700 fields.push(NameId(read_u16(buf, &mut off)?));
701 }
702 shapes.push(StructShapeDef { id, name, fields });
703 }
704 Ok(shapes)
705}
706
707pub fn read_section_visibility(
712 buf: &[u8],
713 index: &InkbIndex,
714) -> Result<Vec<DefinitionId>, DecodeError> {
715 let Some(range) = index.section_range(SectionKind::Visibility) else {
716 return Ok(Vec::new());
717 };
718 let mut off = range.start;
719 let count = read_u32(buf, &mut off)? as usize;
720 let mut ids = Vec::with_capacity(safe_capacity(count, buf.len(), off, 4));
721 for _ in 0..count {
722 ids.push(read_def_id(buf, &mut off)?);
723 }
724 Ok(ids)
725}
726
727pub fn read_section_alias_table(
733 buf: &[u8],
734 index: &InkbIndex,
735) -> Result<Vec<AliasEntry>, DecodeError> {
736 let Some(range) = index.section_range(SectionKind::AliasTable) else {
737 return Ok(Vec::new());
738 };
739 let mut off = range.start;
740 let section_version = read_u8(buf, &mut off)?;
741 if section_version != ALIAS_TABLE_SECTION_VERSION {
742 return Err(DecodeError::UnsupportedSectionVersion {
743 section: SectionKind::AliasTable as u8,
744 version: section_version,
745 });
746 }
747 let count = read_u32(buf, &mut off)? as usize;
748 let mut entries = Vec::with_capacity(safe_capacity(count, buf.len(), off, 16));
749 for _ in 0..count {
750 let old = read_def_id(buf, &mut off)?;
751 let new = read_def_id(buf, &mut off)?;
752 entries.push(AliasEntry { old, new });
753 }
754 Ok(entries)
755}
756
757pub fn read_section_effect_rows(
763 buf: &[u8],
764 index: &InkbIndex,
765) -> Result<Vec<EffectRowEntry>, DecodeError> {
766 let Some(range) = index.section_range(SectionKind::EffectRows) else {
767 return Ok(Vec::new());
768 };
769 let mut off = range.start;
770 let section_version = read_u8(buf, &mut off)?;
771 if section_version != EFFECT_ROWS_SECTION_VERSION {
772 return Err(DecodeError::UnsupportedSectionVersion {
773 section: SectionKind::EffectRows as u8,
774 version: section_version,
775 });
776 }
777 let count = read_u32(buf, &mut off)? as usize;
778 let mut rows = Vec::with_capacity(safe_capacity(count, buf.len(), off, 27));
782 for _ in 0..count {
783 let def = read_def_id(buf, &mut off)?;
784 let is_entry = read_u8(buf, &mut off)? != 0;
786 let direct = decode_direct_effects(buf, &mut off)?;
787 let dispatch_count = read_u32(buf, &mut off)? as usize;
788 let mut dispatches = Vec::with_capacity(safe_capacity(dispatch_count, buf.len(), off, 13));
789 for _ in 0..dispatch_count {
790 let cell = read_def_id(buf, &mut off)?;
791 let narrowable = read_u8(buf, &mut off)? != 0;
792 let fallback = decode_direct_effects(buf, &mut off)?;
793 dispatches.push(DispatchEntry {
794 cell,
795 narrowable,
796 fallback,
797 });
798 }
799 rows.push(EffectRowEntry {
800 def,
801 is_entry,
802 direct,
803 dispatches,
804 });
805 }
806 Ok(rows)
807}
808
809pub fn read_section_frame_shapes(
816 buf: &[u8],
817 index: &InkbIndex,
818) -> Result<Vec<FrameShapeDef>, DecodeError> {
819 let Some(range) = index.section_range(SectionKind::FrameShapes) else {
820 return Ok(Vec::new());
821 };
822 let mut off = range.start;
823 let section_version = read_u8(buf, &mut off)?;
824 if section_version != FRAME_SHAPES_SECTION_VERSION {
825 return Err(DecodeError::UnsupportedSectionVersion {
826 section: SectionKind::FrameShapes as u8,
827 version: section_version,
828 });
829 }
830 let count = read_u32(buf, &mut off)? as usize;
831 let mut shapes = Vec::with_capacity(safe_capacity(count, buf.len(), off, 12));
833 for _ in 0..count {
834 let site = read_def_id(buf, &mut off)?;
835 let slot_count = read_u32(buf, &mut off)? as usize;
836 let mut slots = Vec::with_capacity(safe_capacity(slot_count, buf.len(), off, 2));
837 for _ in 0..slot_count {
838 slots.push(NameId(read_u16(buf, &mut off)?));
839 }
840 shapes.push(FrameShapeDef { site, slots });
841 }
842 Ok(shapes)
843}
844
845fn decode_direct_effects(buf: &[u8], off: &mut usize) -> Result<DirectEffects, DecodeError> {
847 let read_count = read_u32(buf, off)? as usize;
848 let mut reads = Vec::with_capacity(safe_capacity(read_count, buf.len(), *off, 8));
849 for _ in 0..read_count {
850 reads.push(read_def_id(buf, off)?);
851 }
852 let write_count = read_u32(buf, off)? as usize;
853 let mut writes = Vec::with_capacity(safe_capacity(write_count, buf.len(), *off, 8));
854 for _ in 0..write_count {
855 writes.push(read_def_id(buf, off)?);
856 }
857 let call_count = read_u32(buf, off)? as usize;
858 let mut calls = Vec::with_capacity(safe_capacity(call_count, buf.len(), *off, 4));
859 for _ in 0..call_count {
860 calls.push(decode_call_atom(buf, off)?);
861 }
862 let opaque = read_u8(buf, off)? != 0;
863 let dims = read_u8(buf, off)?;
867 if dims & !super::EFFECT_DIM_KNOWN_MASK != 0 {
868 return Err(DecodeError::InvalidEffectDimensions(dims));
869 }
870 Ok(DirectEffects {
871 reads,
872 writes,
873 calls,
874 opaque,
875 emits: dims & super::EFFECT_DIM_EMITS != 0,
876 tags: dims & super::EFFECT_DIM_TAGS != 0,
877 faults: dims & super::EFFECT_DIM_FAULTS != 0,
878 })
879}
880
881fn decode_call_atom(buf: &[u8], off: &mut usize) -> Result<CallAtom, DecodeError> {
886 let name = NameId(read_u16(buf, off)?);
887 let cap_tag = read_u8(buf, off)?;
888 let capability = match cap_tag {
889 CAP_PARAM_ANY => CapabilityParam::Any,
890 other => return Err(DecodeError::InvalidEffectCapParam(other)),
891 };
892 let handle_tag = read_u8(buf, off)?;
893 if handle_tag != HANDLE_PARAM_NONE {
894 return Err(DecodeError::InvalidEffectHandleParam(handle_tag));
895 }
896 Ok(CallAtom {
897 name,
898 capability,
899 handle_param: None,
900 })
901}
902
903fn decode_external(buf: &[u8], off: &mut usize) -> Result<ExternalFnDef, DecodeError> {
904 let id = read_def_id(buf, off)?;
905 let name = NameId(read_u16(buf, off)?);
906 let arg_count = read_u8(buf, off)?;
907 let has_fallback = read_u8(buf, off)? != 0;
908 let fallback = if has_fallback {
909 Some(read_def_id(buf, off)?)
910 } else {
911 None
912 };
913 Ok(ExternalFnDef {
914 id,
915 name,
916 arg_count,
917 fallback,
918 })
919}
920
921fn decode_container(buf: &[u8], off: &mut usize) -> Result<ContainerDef, DecodeError> {
922 let id = read_def_id(buf, off)?;
923 let scope_id = read_def_id(buf, off)?;
924 let has_name = read_u8(buf, off)? != 0;
925 let name = if has_name {
926 Some(NameId(read_u16(buf, off)?))
927 } else {
928 None
929 };
930 let counting_bits = read_u8(buf, off)?;
931 let counting_flags = CountingFlags::from_bits(counting_bits).unwrap_or(CountingFlags::empty());
932 let path_hash = read_i32(buf, off)?;
933 let param_count = read_u8(buf, off)?;
934 let local = read_u8(buf, off)? != 0;
935 let param_meta_count = read_u16(buf, off)? as usize;
937 let mut params = Vec::with_capacity(safe_capacity(param_meta_count, buf.len(), *off, 3));
938 for _ in 0..param_meta_count {
939 let name = NameId(read_u16(buf, off)?);
940 let is_ref = read_u8(buf, off)? != 0;
941 params.push(ParamMeta { name, is_ref });
942 }
943 if !params.is_empty() && params.len() != usize::from(param_count) {
951 return Err(DecodeError::ParamCountMismatch {
952 declared: param_count,
953 actual: params.len(),
954 });
955 }
956
957 let bytecode_len = read_u32(buf, off)? as usize;
958 if *off + bytecode_len > buf.len() {
959 return Err(DecodeError::UnexpectedEof);
960 }
961 let bytecode = buf[*off..*off + bytecode_len].to_vec();
962 *off += bytecode_len;
963
964 Ok(ContainerDef {
965 id,
966 scope_id,
967 name,
968 bytecode,
969 counting_flags,
970 path_hash,
971 param_count,
972 params,
973 local,
974 })
975}
976
977pub fn read_section_line_tables(
979 buf: &[u8],
980 index: &InkbIndex,
981) -> Result<Vec<ScopeLineTable>, DecodeError> {
982 let range =
983 index
984 .section_range(SectionKind::LineTables)
985 .ok_or(DecodeError::MissingSectionKind(
986 SectionKind::LineTables as u8,
987 ))?;
988 let mut off = range.start;
989 let count = read_u32(buf, &mut off)? as usize;
990 let mut tables = Vec::with_capacity(safe_capacity(count, buf.len(), off, 12));
991 for _ in 0..count {
992 tables.push(decode_scope_line_table(buf, &mut off)?);
993 }
994 Ok(tables)
995}
996
997fn decode_scope_line_table(buf: &[u8], off: &mut usize) -> Result<ScopeLineTable, DecodeError> {
998 let scope_id = read_def_id(buf, off)?;
999 let line_count = read_u32(buf, off)? as usize;
1000 let mut lines = Vec::with_capacity(safe_capacity(line_count, buf.len(), *off, 9));
1001 for _ in 0..line_count {
1002 lines.push(decode_line_entry(buf, off)?);
1003 }
1004 Ok(ScopeLineTable { scope_id, lines })
1005}
1006
1007fn decode_line_entry(buf: &[u8], off: &mut usize) -> Result<LineEntry, DecodeError> {
1008 let content = decode_line_content(buf, off)?;
1009 let source_hash = read_u64(buf, off)?;
1010 let has_audio = read_u8(buf, off)? != 0;
1011 let audio_ref = if has_audio {
1012 Some(read_str(buf, off)?)
1013 } else {
1014 None
1015 };
1016 let slot_count = read_u8(buf, off)? as usize;
1018 let mut slot_info = Vec::with_capacity(slot_count);
1019 for _ in 0..slot_count {
1020 let index = read_u8(buf, off)?;
1021 let name = read_str(buf, off)?;
1022 slot_info.push(SlotInfo { index, name });
1023 }
1024
1025 let has_source_loc = read_u8(buf, off)? != 0;
1027 let source_location = if has_source_loc {
1028 let file = read_str(buf, off)?;
1029 let range_start = read_u32(buf, off)?;
1030 let range_end = read_u32(buf, off)?;
1031 Some(SourceLocation {
1032 file,
1033 range_start,
1034 range_end,
1035 })
1036 } else {
1037 None
1038 };
1039
1040 let flags = crate::LineFlags::from_content(&content);
1041 Ok(LineEntry {
1042 content,
1043 flags,
1044 source_hash,
1045 audio_ref,
1046 slot_info,
1047 source_location,
1048 })
1049}
1050
1051pub(crate) fn decode_line_content(buf: &[u8], off: &mut usize) -> Result<LineContent, DecodeError> {
1052 let tag = read_u8(buf, off)?;
1053 match tag {
1054 LINE_PLAIN => Ok(LineContent::Plain(read_str(buf, off)?)),
1055 LINE_TEMPLATE => {
1056 let part_count = read_u32(buf, off)? as usize;
1057 let mut parts = Vec::with_capacity(safe_capacity(part_count, buf.len(), *off, 2));
1058 for _ in 0..part_count {
1059 parts.push(decode_line_part(buf, off, 0)?);
1060 }
1061 Ok(LineContent::Template(parts))
1062 }
1063 _ => Err(DecodeError::InvalidLineContent(tag)),
1064 }
1065}
1066
1067fn decode_line_part(buf: &[u8], off: &mut usize, depth: usize) -> Result<LinePart, DecodeError> {
1072 if depth > MAX_DECODE_DEPTH {
1073 return Err(DecodeError::MaxDepthExceeded(MAX_DECODE_DEPTH));
1074 }
1075 let tag = read_u8(buf, off)?;
1076 match tag {
1077 PART_LITERAL => Ok(LinePart::Literal(read_str(buf, off)?)),
1078 PART_SLOT => Ok(LinePart::Slot(read_u8(buf, off)?)),
1079 PART_SELECT => {
1080 let slot = read_u8(buf, off)?;
1081 let variant_count = read_u32(buf, off)? as usize;
1082 let mut variants = Vec::with_capacity(safe_capacity(variant_count, buf.len(), *off, 6));
1083 for _ in 0..variant_count {
1084 let key = decode_select_key(buf, off)?;
1085 let text = read_str(buf, off)?;
1086 variants.push((key, text));
1087 }
1088 let default = read_str(buf, off)?;
1089 Ok(LinePart::Select {
1090 slot,
1091 variants,
1092 default,
1093 })
1094 }
1095 PART_SPAN => {
1096 let name = read_str(buf, off)?;
1097 let attr_count = read_u32(buf, off)? as usize;
1098 let attrs_cap = safe_capacity(attr_count, buf.len(), *off, 8);
1101 let mut attrs = Vec::with_capacity(attrs_cap);
1102 for _ in 0..attr_count {
1103 let k = read_str(buf, off)?;
1104 let v = read_str(buf, off)?;
1105 attrs.push((k, v));
1106 }
1107 let child_count = read_u32(buf, off)? as usize;
1108 let mut children = Vec::with_capacity(safe_capacity(child_count, buf.len(), *off, 2));
1109 for _ in 0..child_count {
1110 children.push(decode_line_part(buf, off, depth + 1)?);
1111 }
1112 Ok(LinePart::Span {
1113 name,
1114 attrs,
1115 children,
1116 })
1117 }
1118 _ => Err(DecodeError::InvalidLinePart(tag)),
1119 }
1120}
1121
1122fn decode_select_key(buf: &[u8], off: &mut usize) -> Result<SelectKey, DecodeError> {
1123 let tag = read_u8(buf, off)?;
1124 match tag {
1125 KEY_CARDINAL => Ok(SelectKey::Cardinal(decode_plural_category(buf, off)?)),
1126 KEY_ORDINAL => Ok(SelectKey::Ordinal(decode_plural_category(buf, off)?)),
1127 KEY_EXACT => Ok(SelectKey::Exact(read_i32(buf, off)?)),
1128 KEY_KEYWORD => Ok(SelectKey::Keyword(read_str(buf, off)?)),
1129 _ => Err(DecodeError::InvalidSelectKey(tag)),
1130 }
1131}
1132
1133fn decode_plural_category(buf: &[u8], off: &mut usize) -> Result<PluralCategory, DecodeError> {
1134 let tag = read_u8(buf, off)?;
1135 match tag {
1136 CAT_ZERO => Ok(PluralCategory::Zero),
1137 CAT_ONE => Ok(PluralCategory::One),
1138 CAT_TWO => Ok(PluralCategory::Two),
1139 CAT_FEW => Ok(PluralCategory::Few),
1140 CAT_MANY => Ok(PluralCategory::Many),
1141 CAT_OTHER => Ok(PluralCategory::Other),
1142 _ => Err(DecodeError::InvalidPluralCategory(tag)),
1143 }
1144}
1145
1146#[cfg(test)]
1147mod tests {
1148 use super::*;
1149 use crate::codec::{write_u8, write_u32};
1150
1151 fn duplicate_int_key_map_bytes() -> Vec<u8> {
1158 let mut buf = Vec::new();
1159 write_u8(&mut buf, VAL_MAP);
1160 write_u32(&mut buf, 2); write_u8(&mut buf, VAL_INT);
1163 buf.extend_from_slice(&0i32.to_le_bytes());
1164 write_u8(&mut buf, VAL_INT);
1165 buf.extend_from_slice(&1i32.to_le_bytes());
1166 write_u8(&mut buf, VAL_INT);
1168 buf.extend_from_slice(&0i32.to_le_bytes());
1169 write_u8(&mut buf, VAL_INT);
1170 buf.extend_from_slice(&2i32.to_le_bytes());
1171 buf
1172 }
1173
1174 #[test]
1175 fn decode_value_rejects_duplicate_map_key() {
1176 let buf = duplicate_int_key_map_bytes();
1177 let mut off = 0;
1178 assert_eq!(
1179 decode_value(&buf, &mut off, 0),
1180 Err(DecodeError::DuplicateMapKey)
1181 );
1182 }
1183
1184 #[test]
1185 fn decode_value_accepts_distinct_map_keys() {
1186 let mut buf = Vec::new();
1187 write_u8(&mut buf, VAL_MAP);
1188 write_u32(&mut buf, 2);
1189 write_u8(&mut buf, VAL_INT);
1190 buf.extend_from_slice(&0i32.to_le_bytes());
1191 write_u8(&mut buf, VAL_INT);
1192 buf.extend_from_slice(&1i32.to_le_bytes());
1193 write_u8(&mut buf, VAL_INT);
1194 buf.extend_from_slice(&5i32.to_le_bytes());
1195 write_u8(&mut buf, VAL_INT);
1196 buf.extend_from_slice(&2i32.to_le_bytes());
1197
1198 let mut off = 0;
1199 let value = decode_value(&buf, &mut off, 0).expect("distinct keys decode cleanly");
1200 let Value::Map(map) = value else {
1201 unreachable!("expected a map value");
1202 };
1203 assert_eq!(map.len(), 2);
1204 }
1205}