1use crate::reflection::View;
16use crate::{Result, error, parts};
17
18#[derive(Clone, Debug, PartialEq, Eq)]
20pub struct ClassType {
21 pub name: String,
23 pub stride: u16,
25 pub textures: u16,
27 pub samplers: u16,
29 pub reserved: u16,
31}
32
33#[derive(Clone, Debug, PartialEq, Eq)]
35pub struct ClassInstance {
36 pub name: String,
38 pub ty: u16,
40 pub count: u16,
42 pub buffer: Option<u16>,
44 pub offset: Option<u16>,
46 pub texture: Option<u16>,
48 pub sampler: Option<u16>,
50}
51
52#[derive(Clone, Debug, PartialEq, Eq)]
54pub struct InterfaceSlots {
55 pub span: u32,
57 pub types: Vec<u16>,
59 pub tables: Vec<u32>,
61}
62
63#[derive(Clone, Debug, PartialEq, Eq)]
65pub struct Interfaces {
66 pub slot_count: u32,
68 pub types: Vec<ClassType>,
70 pub instances: Vec<ClassInstance>,
72 pub slots: Vec<InterfaceSlots>,
74 pub reserved: [u32; 2],
76}
77
78fn register(value: u16) -> Option<u16> {
80 (value != 0xffff).then_some(value)
81}
82
83pub fn interfaces(bytes: &[u8]) -> Result<Option<Interfaces>> {
86 let directory = parts(bytes)?;
87 let Some(chunk) = directory.iter().find(|c| &c.kind == b"IFCE") else {
88 return Ok(None);
89 };
90 let v = View(chunk.data);
91 let word = |n: usize| v.u32(n.saturating_mul(4));
92 let count = |n: usize| -> Result<usize> {
93 usize::try_from(word(n)?)
94 .map_err(|_| error(n, format!("IFCE word {n}: the count exceeds the address space")))
95 };
96 let offset = |n: usize| -> Result<usize> {
97 usize::try_from(word(n)?)
98 .map_err(|_| error(n, format!("IFCE word {n}: the offset exceeds the address space")))
99 };
100 let (instance_count, type_count, record_count) = (count(0)?, count(1)?, count(2)?);
101 let (instance_at, type_at, record_at) = (offset(4)?, offset(5)?, offset(6)?);
102 let mut types = Vec::new();
103 for i in v.table(type_at, type_count, 12)? {
104 let p = v.record(type_at, i, 12)?;
105 types.push(ClassType {
106 name: v.string(v.u32(p)? as usize)?,
107 reserved: v.field16(p, 4)?,
108 stride: v.field16(p, 6)?,
109 textures: v.field16(p, 8)?,
110 samplers: v.field16(p, 10)?,
111 });
112 }
113 let mut instances = Vec::new();
114 for i in v.table(instance_at, instance_count, 16)? {
115 let p = v.record(instance_at, i, 16)?;
116 instances.push(ClassInstance {
117 name: v.string(v.u32(p)? as usize)?,
118 ty: v.field16(p, 4)?,
119 count: v.field16(p, 6)?,
120 buffer: register(v.field16(p, 8)?),
121 offset: register(v.field16(p, 10)?),
122 texture: register(v.field16(p, 12)?),
123 sampler: register(v.field16(p, 14)?),
124 });
125 }
126 let mut slots = Vec::new();
127 for i in v.table(record_at, record_count, 16)? {
128 let p = v.record(record_at, i, 16)?;
129 let entries = v.field(p, 4)? as usize;
130 let (type_ids, table_ids) = (v.field(p, 8)? as usize, v.field(p, 12)? as usize);
131 let mut record = InterfaceSlots {
132 span: v.u32(p)?,
133 types: Vec::new(),
134 tables: Vec::new(),
135 };
136 for j in v.table(type_ids, entries, 2)? {
137 record.types.push(v.u16(v.record(type_ids, j, 2)?)?);
138 }
139 for j in v.table(table_ids, entries, 4)? {
140 record.tables.push(v.u32(v.record(table_ids, j, 4)?)?);
141 }
142 slots.push(record);
143 }
144 Ok(Some(Interfaces {
145 slot_count: word(3)?,
146 types,
147 instances,
148 slots,
149 reserved: [word(7)?, word(8)?],
150 }))
151}