opengr2/parser/
element.rs

1use nom::bytes::complete::{take, take_while};
2use nom::IResult;
3use nom::multi::count;
4use nom::number::complete::{f32, i32, u32, u64};
5use nom::number::Endianness;
6use nom::sequence::tuple;
7use crate::parser::Pointer;
8use crate::sector::Sector;
9
10#[derive(Debug, PartialEq)]
11pub struct Element {
12    pub name: String,
13    pub element: ElementType
14}
15
16#[derive(Debug, Copy, Clone, PartialEq)]
17pub struct Transform {
18    pub flags: u32,
19    pub translation: [f32; 3],
20    pub rotation: [f32; 4],
21    pub scale_shear: [[f32; 3]; 3]
22}
23
24#[derive(Debug, PartialEq)]
25pub enum ElementType {
26    /// A list of elements
27    Reference(Vec<Element>),
28    ArrayOfReferences(Vec<Vec<Element>>),
29    /// A pointer to raw data
30    /// NOTE: This is currently not supported by this library
31    VariantReference,
32    /// A string
33    String(String),
34    /// A real value (aka float 32)
35    F32(f32),
36    /// An unsigned 32 bit integer
37    I32(i32),
38    ///
39    Transform(Transform),
40
41    /// Not really an element type and instead it's an array inside the element
42    Array(Vec<ElementType>)
43}
44
45#[derive(Debug, PartialEq)]
46pub struct TypeInfo {
47    type_id: u32,
48    name_offset: Option<Pointer>,
49    children_offset: Option<Pointer>,
50    array_size: i32,
51}
52
53fn unsigned(is_64bits: bool, endianness: Endianness) -> impl FnMut(&[u8]) -> IResult<&[u8], u64> {
54    move |input| {
55        return if is_64bits {
56            u64(endianness)(input)
57        } else {
58            let (input, val) = u32(endianness)(input)?;
59            Ok((input, val as u64))
60        }
61    }
62}
63
64pub fn parse_type_info(endianness: Endianness, ptr_table: &Vec<Pointer>, is_64bits: bool, offset: u32) -> impl FnMut(&[u8]) -> IResult<&[u8], TypeInfo> + '_ {
65    move |input| {
66        let type_id = u32(endianness); // 0
67        let name_offset = unsigned(is_64bits, endianness); // 4
68        let children_offset = unsigned(is_64bits, endianness); // 8/12
69        let array_size = i32(endianness);
70
71        let (input, (type_id, _, _, array_size)) = tuple((type_id, name_offset, children_offset, array_size))(input)?;
72
73        let (input, _) = take(if is_64bits { 20usize } else { 16usize })(input)?;
74
75        let name_offset = ptr_table.iter().find(|ptr| ptr.src_offset == offset + 4).map(|ptr| ptr.clone());
76        let children_offset = ptr_table.iter().find(|ptr| ptr.src_offset == offset + if is_64bits { 12 } else { 8 }).map(|ptr| ptr.clone());
77
78        Ok((input, TypeInfo {
79            type_id,
80            name_offset,
81            children_offset,
82            array_size
83        }))
84    }
85}
86
87fn parse_string(input: &[u8]) -> IResult<&[u8], String> {
88    let (input, bytes) = take_while(|n| { n != 0x0 })(input)?;
89
90    Ok((input, std::str::from_utf8(bytes).expect("invalid string").to_string()))
91}
92
93pub fn parse_element(endianness: Endianness, is_64bits: bool, sectors: &Vec<Sector>, data_sector_id: u32, type_sector_id: u32, data_offset: u32, type_offset: u32) -> IResult<&[u8], Vec<Element>> {
94    let data_sector = &sectors[data_sector_id as usize];
95    let type_sector = &sectors[type_sector_id as usize];
96
97    let all_type_data = &*type_sector.data;
98    let all_data = &*data_sector.data;
99
100    let mut type_data = &all_type_data[type_offset as usize..];
101    let mut data = &all_data[data_offset as usize..];
102
103    let mut elements = Vec::new();
104
105    loop {
106        let (next, type_info) = parse_type_info(endianness, &type_sector.pointer_table, is_64bits, (all_type_data.len() - type_data.len()) as u32)(type_data)?;
107        if type_info.type_id == 0 || type_info.type_id > 22 {
108            break
109        }
110
111        let name = if let Some(name_offset) = type_info.name_offset {
112            let (_, name) = parse_string(&sectors[name_offset.dst_sector as usize].data[name_offset.dst_offset as usize..])?;
113            name
114        } else {
115            "".to_string()
116        };
117
118        let element = if type_info.array_size > 0 {
119            let mut inners = Vec::new();
120            for _ in 0..(if type_info.array_size == 0 { 1 } else { type_info.array_size }) {
121                let (next, element_inner) = parse_element_data(endianness, is_64bits, &sectors, data_sector_id, data_sector, all_data, data, &type_info)?;
122                data = next;
123
124                inners.push(element_inner);
125            }
126
127            Element {
128                name,
129                element: ElementType::Array(inners)
130            }
131        } else {
132            let (next, element_inner) = parse_element_data(endianness, is_64bits, &sectors, data_sector_id, data_sector, all_data, data, &type_info)?;
133            data = next;
134
135            Element {
136                name,
137                element: element_inner
138            }
139        };
140
141        elements.push(element);
142        type_data = next;
143    }
144
145    Ok((data, elements))
146}
147
148fn parse_element_data<'a>(endianness: Endianness, is_64bits: bool, sectors: &'a Vec<Sector>, data_sector_id: u32, data_sector: &Sector, all_data: &[u8], mut data: &'a [u8], type_info: &TypeInfo) -> IResult<&'a [u8], ElementType> {
149    match type_info.type_id {
150        1 => {
151            Ok((data, ElementType::VariantReference))
152        }
153        2 => {
154            let pos = all_data.len() - data.len();
155            let (next, _) = unsigned(is_64bits, endianness)(data)?;
156
157            data = next;
158
159            let ptr = data_sector.resolve_pointer(pos);
160            let elements = if let Some(ptr) = ptr {
161                assert_eq!(ptr.dst_sector, data_sector_id);
162
163                let children_offset = type_info.children_offset.unwrap();
164
165                let (_, elements) = parse_element(
166                    endianness,
167                    is_64bits,
168                    sectors,
169                    ptr.dst_sector,
170                    children_offset.dst_sector,
171                    ptr.dst_offset,
172                    children_offset.dst_offset
173                )?;
174
175                elements
176            } else {
177                Vec::new()
178            };
179
180            Ok((data, ElementType::Reference(elements)))
181        }
182        3 => {
183            let pos = all_data.len() - data.len() + 4;
184            let size = u32(endianness);
185            let offset = unsigned(is_64bits, endianness);
186
187            let (next, (size, _)) = tuple((size, offset))(data)?;
188            data = next;
189
190            let mut elements = Vec::new();
191
192            let data_ptr = data_sector.resolve_pointer(pos);
193            if size > 0 {
194                let data_ptr = data_ptr.unwrap();
195                let type_ptr = type_info.children_offset.unwrap();
196
197                let data_sector = &sectors[data_ptr.dst_sector as usize];
198
199                let mut data_offset = data_ptr.dst_offset;
200                for _ in 0..size {
201                    let (left_data, mut e) = parse_element(endianness, is_64bits, sectors, data_ptr.dst_sector, type_ptr.dst_sector, data_offset, type_ptr.dst_offset)?;
202                    elements.append(&mut e);
203
204                    data_offset = (data_sector.data.len() - left_data.len()) as u32;
205                }
206            }
207
208            Ok((data, ElementType::Reference(elements)))
209        }
210        4 => {
211            let pos = all_data.len() - data.len() + 4;
212            let size = u32(endianness);
213            let offset = unsigned(is_64bits, endianness);
214
215            let (next, (size, _)) = tuple((size, offset))(data)?;
216            data = next;
217
218            let ptr = data_sector.resolve_pointer(pos);
219
220            let mut references = Vec::new();
221
222            if let Some(ptr) = ptr {
223                let type_ptr = type_info.children_offset.unwrap();
224
225                let element_data_sector = &sectors[ptr.dst_sector as usize];
226
227                for i in 0..size {
228                    let element_ptr = element_data_sector.resolve_pointer((ptr.dst_offset + if is_64bits { 8 * i } else { 4 * i }) as usize).unwrap();
229
230                    let (_, e) = parse_element(endianness, is_64bits, sectors, element_ptr.dst_sector, type_ptr.dst_sector, element_ptr.dst_offset, type_ptr.dst_offset)?;
231
232                    references.push(e);
233                }
234            }
235
236            Ok((data, ElementType::ArrayOfReferences(references)))
237        }
238        5 => {
239            let offset = unsigned(is_64bits, endianness);
240            let data_ptr = unsigned(is_64bits, endianness);
241
242            let (next, (_, _)) = tuple((offset, data_ptr))(data)?;
243            data = next;
244
245            Ok((data, ElementType::VariantReference))
246        }
247        7 => {
248            let pos = all_data.len() - data.len();
249
250            let type_ptr = unsigned(is_64bits, endianness);
251            let size = u32(endianness);
252            let data_ptr = unsigned(is_64bits, endianness);
253
254            let (next, (_, size, _)) = tuple((type_ptr, size, data_ptr))(data)?;
255            data = next;
256
257            let type_ptr = data_sector.resolve_pointer(pos).unwrap();
258            let data_ptr = data_sector.resolve_pointer(pos + if is_64bits { 8 + 4 } else { 4 + 4 }).unwrap();
259
260            let mut data_offset = data_ptr.dst_offset;
261
262            let mut elements = Vec::new();
263
264            for _ in 0..size {
265                let (left_data, e) = parse_element(endianness, is_64bits, sectors, data_ptr.dst_sector, type_ptr.dst_sector, data_offset, type_ptr.dst_offset)?;
266
267                data_offset = (sectors[data_ptr.dst_sector as usize].data.len() - left_data.len()) as _;
268
269                elements.push(e);
270            }
271
272            Ok((data, ElementType::ArrayOfReferences(elements)))
273        }
274        8 => {
275            let pos = all_data.len() - data.len();
276            let (next, _) = unsigned(is_64bits, endianness)(data)?;
277
278            data = next;
279
280            let ptr = data_sector.resolve_pointer(pos).unwrap();
281            let (_, value) = parse_string(&sectors[ptr.dst_sector as usize].data[ptr.dst_offset as usize..])?;
282
283            Ok((data, ElementType::String(value)))
284        }
285        9 => {
286            let flags = u32(endianness);
287            let translation = count(f32(endianness), 3);
288            let rotation = count(f32(endianness), 4);
289            let scale_shear = count(f32(endianness), 3 * 3);
290
291            let (next, (flags, translation, rotation, scale_shear)) = tuple((flags, translation, rotation, scale_shear))(data)?;
292            data = next;
293
294            Ok((data, ElementType::Transform(Transform {
295                flags,
296                translation: [translation[0], translation[1], translation[2]],
297                rotation: [rotation[0], rotation[1], rotation[2], rotation[3]],
298                scale_shear: [
299                    [scale_shear[0], scale_shear[1], scale_shear[2]],
300                    [scale_shear[3], scale_shear[4], scale_shear[5]],
301                    [scale_shear[6], scale_shear[7], scale_shear[8]],
302                ]
303            })))
304        }
305        10 => {
306            let (next, val) = f32(endianness)(data)?;
307            data = next;
308
309            Ok((data, ElementType::F32(val)))
310        },
311        19 => {
312            let (next, val) = i32(endianness)(data)?;
313            data = next;
314
315            Ok((data, ElementType::I32(val)))
316        }
317        _ => {
318            panic!("Unknown element type id {}", type_info.type_id);
319        }
320    }
321}