1use 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);