assembly_maps/lvl/
parser.rs

1//! # Parsers for the data
2use super::file::*;
3use assembly_core::{
4    nom::{
5        cond, count, do_parse, length_count, map, named,
6        number::complete::{le_f32, le_u16, le_u32, le_u8},
7        tag, take, IResult,
8    },
9    parser::{
10        parse_object_id, parse_object_template, parse_quat, parse_quat_wxyz, parse_u32_string,
11        parse_u32_wstring, parse_vec3f,
12    },
13};
14use std::convert::TryInto;
15
16named!(pub parse_chunk_version<ChunkVersion>,
17    do_parse!(
18        header: le_u16 >>
19        data: le_u16 >>
20        (ChunkVersion{header, data})
21    )
22);
23
24named!(pub parse_chunk_header<ChunkHeader>,
25    do_parse!(
26        tag!("CHNK") >>
27        id: le_u32 >>
28        version: parse_chunk_version >>
29        size: le_u32 >>
30        offset: le_u32 >>
31        (ChunkHeader{id, version, size, offset})
32    )
33);
34
35named!(pub parse_file_meta_chunk_data<FileMetaChunkData>,
36    do_parse!(
37        version: le_u32 >>
38        revision: le_u32 >>
39        chunk_2000_offset: le_u32 >>
40        chunk_2001_offset: le_u32 >>
41        chunk_2002_offset: le_u32 >>
42        (FileMetaChunkData{
43            version, revision,
44            chunk_2000_offset, chunk_2001_offset, chunk_2002_offset
45        })
46    )
47);
48
49named!(
50    parse_object_extra<ObjectExtra>,
51    do_parse!(
52        field_1a: take!(32)
53            >> field_1b: take!(32)
54            >> field_2: le_u32
55            >> field_3: map!(le_u8, |b| b != 0)
56            >> field_4: count!(le_u32, 16)
57            >> field_5: take!(3)
58            >> (ObjectExtra {
59                field_1a: field_1a.try_into().unwrap(),
60                field_1b: field_1b.try_into().unwrap(),
61                field_2,
62                field_3,
63                field_4: field_4[..].try_into().unwrap(),
64                field_5: field_5.try_into().unwrap(),
65            })
66    )
67);
68
69pub fn parse_objects_chunk_data<'a>(
70    version: u32,
71    i: &'a [u8],
72) -> IResult<&'a [u8], ObjectsChunkData<String>> {
73    let parse_object = move |i: &'a [u8]| -> IResult<&'a [u8], Object<String>> {
74        do_parse!(
75            i,
76            obj_id: parse_object_id
77                >> lot: parse_object_template
78                >> asset_type: cond!(version >= 0x26, le_u32)
79                >> value_1: cond!(version >= 0x20, le_u32)
80                >> position: parse_vec3f
81                >> rotation: parse_quat_wxyz
82                >> scale: le_f32
83                >> settings: parse_u32_wstring
84                >> extra: cond!(version >= 0x07, length_count!(le_u32, parse_object_extra))
85                >> (Object {
86                    obj_id,
87                    lot,
88                    asset_type,
89                    value_1,
90                    position,
91                    rotation,
92                    scale,
93                    settings,
94                    extra: extra.unwrap_or_default(),
95                })
96        )
97    };
98
99    let _parse_objects_chunk_data =
100        move |i: &'a [u8]| -> IResult<&'a [u8], ObjectsChunkData<String>> {
101            map!(i, length_count!(le_u32, parse_object), |objects| {
102                ObjectsChunkData { objects }
103            })
104        };
105
106    _parse_objects_chunk_data(i)
107}
108
109named!(pub parse_env_chunk_data<EnvironmentChunkData>,
110    do_parse!(
111        section1_address: le_u32 >>
112        sky_address: le_u32 >>
113        section3_address: le_u32 >>
114        (EnvironmentChunkData {
115            section1_address,
116            sky_address,
117            section3_address,
118        })
119    )
120);
121
122named!(
123    parse_color<Color>,
124    do_parse!(red: le_f32 >> green: le_f32 >> blue: le_f32 >> (Color { red, green, blue }))
125);
126
127named!(
128    parse_section1_40<Section1_40>,
129    do_parse!(
130        id: le_u32 >> float1: le_f32 >> float2: le_f32 >> (Section1_40 { id, float1, float2 })
131    )
132);
133
134pub fn parse_section1<'a>(version: u32, i: &'a [u8]) -> IResult<&'a [u8], Section1> {
135    let parse_section1_31e = |i: &'a [u8]| {
136        if version >= 39 {
137            do_parse!(
138                i,
139                value1: le_f32
140                    >> value2: le_f32
141                    >> value3: le_f32
142                    >> value4: le_f32
143                    >> value5: le_f32
144                    >> value6: le_f32
145                    >> value7: le_f32
146                    >> value8: le_f32
147                    >> value9: le_f32
148                    >> value10: le_f32
149                    >> value11: le_f32
150                    >> value12: le_f32
151                    >> array:
152                        map!(
153                            cond!(version >= 40, length_count!(le_u32, parse_section1_40)),
154                            Option::unwrap_or_default
155                        )
156                    >> (Section1_39::After {
157                        values: Box::new([
158                            value1, value2, value3, value4, value5, value6, value7, value8, value9,
159                            value10, value11, value12,
160                        ]),
161                        array,
162                    })
163            )
164        } else {
165            do_parse!(
166                i,
167                value1: le_f32 >> value2: le_f32 >> (Section1_39::Before { value1, value2 })
168            )
169        }
170    };
171
172    let parse_section1_31 = |i: &'a [u8]| {
173        do_parse!(
174            i,
175            value1: parse_section1_31e >> value2: parse_color >> (Section1_31 { value1, value2 })
176        )
177    };
178
179    let parse_section1_43 = |i: &'a [u8]| {
180        do_parse!(
181            i,
182            pos: parse_vec3f >> rot: cond!(version >= 33, parse_quat) >> (Section1_43 { pos, rot })
183        )
184    };
185
186    do_parse!(
187        i,
188        value1: cond!(version >= 45, le_f32)
189            >> value2: parse_color
190            >> value3: parse_color
191            >> value4: parse_color
192            >> value5: parse_vec3f
193            >> value6: cond!(version >= 31, parse_section1_31)
194            >> value7: cond!(version >= 36, parse_color)
195            >> value8: cond!(version < 42, parse_section1_43)
196            >> (Section1 {
197                value1,
198                value2,
199                value3,
200                value4,
201                value5,
202                value6,
203                value7,
204                value8,
205            })
206    )
207}
208
209named!(pub parse_sky_section<SkySection>,
210    do_parse!(
211        file1: parse_u32_string >>
212        file2: parse_u32_string >>
213        file3: parse_u32_string >>
214        file4: parse_u32_string >>
215        file5: parse_u32_string >>
216        file6: parse_u32_string >>
217        (SkySection {
218            files: [file1, file2, file3, file4, file5, file6]
219        })
220    )
221);