Mercurial > touhou
comparison src/th06/anm0.rs @ 702:718348c7608e
anm0: simplify parsing with more combinators.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Fri, 23 Aug 2019 17:22:38 +0200 |
parents | b6c351ca0a35 |
children | 84af5bedbde4 |
comparison
equal
deleted
inserted
replaced
701:b6c351ca0a35 | 702:718348c7608e |
---|---|
2 | 2 |
3 use nom::{ | 3 use nom::{ |
4 IResult, | 4 IResult, |
5 bytes::complete::{tag, take_while_m_n}, | 5 bytes::complete::{tag, take_while_m_n}, |
6 number::complete::{le_u8, le_u16, le_u32, le_i32, le_f32}, | 6 number::complete::{le_u8, le_u16, le_u32, le_i32, le_f32}, |
7 sequence::tuple, | |
8 multi::many_m_n, | |
7 }; | 9 }; |
8 use std::collections::HashMap; | 10 use std::collections::HashMap; |
9 | 11 |
10 /// Coordinates of a sprite into the image. | 12 /// Coordinates of a sprite into the image. |
11 #[derive(Debug, Clone)] | 13 #[derive(Debug, Clone)] |
79 let (x, y) = self.size; | 81 let (x, y) = self.size; |
80 (1. / x as f32, 1. / y as f32) | 82 (1. / x as f32, 1. / y as f32) |
81 } | 83 } |
82 } | 84 } |
83 | 85 |
84 fn parse_name(i: &[u8], is_present: bool) -> IResult<&[u8], String> { | 86 fn parse_name(i: &[u8]) -> IResult<&[u8], String> { |
85 if !is_present { | |
86 return Ok((i, String::new())); | |
87 } | |
88 let (_, slice) = take_while_m_n(0, 32, |c| c != 0)(i)?; | 87 let (_, slice) = take_while_m_n(0, 32, |c| c != 0)(i)?; |
89 let string = match String::from_utf8(slice.to_vec()) { | 88 let string = match String::from_utf8(slice.to_vec()) { |
90 Ok(string) => string, | 89 Ok(string) => string, |
91 // XXX: use a more specific error instead. | 90 // XXX: use a more specific error instead. |
92 Err(_) => return Err(nom::Err::Failure((i, nom::error::ErrorKind::Eof))) | 91 Err(_) => return Err(nom::Err::Failure((i, nom::error::ErrorKind::Eof))) |
93 }; | 92 }; |
94 Ok((i, string)) | 93 Ok((i, string)) |
95 } | 94 } |
96 | 95 |
97 fn parse_sprite(i: &[u8]) -> IResult<&[u8], Sprite> { | 96 fn parse_sprite(i: &[u8]) -> IResult<&[u8], Sprite> { |
98 let (i, index) = le_u32(i)?; | 97 let (i, (index, x, y, width, height)) = tuple((le_u32, le_f32, le_f32, le_f32, le_f32))(i)?; |
99 let (i, x) = le_f32(i)?; | |
100 let (i, y) = le_f32(i)?; | |
101 let (i, width) = le_f32(i)?; | |
102 let (i, height) = le_f32(i)?; | |
103 Ok((i, Sprite { | 98 Ok((i, Sprite { |
104 index, | 99 index, |
105 x, | 100 x, |
106 y, | 101 y, |
107 width, | 102 width, |
175 fn parse_anm0(input: &[u8]) -> IResult<&[u8], Vec<Anm0>> { | 170 fn parse_anm0(input: &[u8]) -> IResult<&[u8], Vec<Anm0>> { |
176 let mut list = vec![]; | 171 let mut list = vec![]; |
177 let start_offset = 0; | 172 let start_offset = 0; |
178 loop { | 173 loop { |
179 let i = &input[start_offset..]; | 174 let i = &input[start_offset..]; |
180 let (i, num_sprites) = le_u32(i)?; | 175 let (mut i, (num_sprites, num_scripts, _, width, height, format, _unknown1, |
181 let (i, num_scripts) = le_u32(i)?; | 176 first_name_offset, _unused, second_name_offset, version, _unknown2, |
182 let (i, _) = tag(b"\0\0\0\0")(i)?; | 177 _texture_offset, has_data, _next_offset, unknown3)) = |
183 let (i, width) = le_u32(i)?; | 178 tuple((le_u32, le_u32, tag(b"\0\0\0\0"), le_u32, le_u32, le_u32, le_u32, le_u32, |
184 let (i, height) = le_u32(i)?; | 179 le_u32, le_u32, le_u32, le_u32, le_u32, le_u32, le_u32, le_u32))(i)?; |
185 let (i, format) = le_u32(i)?; | |
186 let (i, _unknown1) = le_u32(i)?; | |
187 let (i, first_name_offset) = le_u32(i)?; | |
188 let (i, _unused) = le_u32(i)?; | |
189 let (i, second_name_offset) = le_u32(i)?; | |
190 let (i, version) = le_u32(i)?; | |
191 let (i, _unknown2) = le_u32(i)?; | |
192 let (i, _texture_offset) = le_u32(i)?; | |
193 let (i, has_data) = le_u32(i)?; | |
194 let (i, _next_offset) = le_u32(i)?; | |
195 let (mut i, unknown3) = le_u32(i)?; | |
196 | 180 |
197 assert_eq!(version, 0); | 181 assert_eq!(version, 0); |
198 assert_eq!(unknown3, 0); | 182 assert_eq!(unknown3, 0); |
199 assert_eq!(has_data, 0); | 183 assert_eq!(has_data, 0); |
200 | 184 let num_sprites = num_sprites as usize; |
201 let mut sprite_offsets = vec![]; | 185 let num_scripts = num_scripts as usize; |
202 for _ in 0..num_sprites { | 186 |
203 let (i2, offset) = le_u32(i)?; | 187 let (i, sprite_offsets) = many_m_n(num_sprites, num_sprites, le_u32)(i)?; |
204 sprite_offsets.push(offset as usize); | 188 let (_, script_offsets) = many_m_n(num_scripts, num_scripts, tuple((le_u32, le_u32)))(i)?; |
205 i = i2; | 189 |
206 } | 190 let first_name = if first_name_offset > 0 { |
207 | 191 if input.len() < start_offset + first_name_offset as usize { |
208 let mut script_offsets = vec![]; | 192 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); |
209 for _ in 0..num_scripts { | 193 } |
210 let (i2, index) = le_u32(i)?; | 194 let i = &input[start_offset + first_name_offset as usize..]; |
211 let (i2, offset) = le_u32(i2)?; | 195 let (_, name) = parse_name(i)?; |
212 script_offsets.push((index as u8, offset as usize)); | 196 name |
213 i = i2; | 197 } else { |
214 } | 198 String::new() |
215 | 199 }; |
216 if input.len() < start_offset + first_name_offset as usize { | 200 |
217 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); | 201 let second_name = if second_name_offset > 0 { |
218 } | 202 if input.len() < start_offset + second_name_offset as usize { |
219 let i = &input[start_offset + first_name_offset as usize..]; | 203 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); |
220 let (_, first_name) = parse_name(i, first_name_offset > 0)?; | 204 } |
221 | 205 let i = &input[start_offset + second_name_offset as usize..]; |
222 if input.len() < start_offset + second_name_offset as usize { | 206 let (_, name) = parse_name(i)?; |
223 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); | 207 name |
224 } | 208 } else { |
225 let i = &input[start_offset + second_name_offset as usize..]; | 209 String::new() |
226 let (_, second_name) = parse_name(i, second_name_offset > 0)?; | 210 }; |
227 | 211 |
228 let mut sprites = vec![]; | 212 let mut sprites = vec![]; |
229 let mut i; | 213 let mut i; |
230 for offset in sprite_offsets { | 214 for offset in sprite_offsets.into_iter().map(|x| x as usize) { |
231 if input.len() < start_offset + offset { | 215 if input.len() < start_offset + offset { |
232 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); | 216 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); |
233 } | 217 } |
234 i = &input[start_offset + offset..]; | 218 i = &input[start_offset + offset..]; |
235 let (_, sprite) = parse_sprite(i)?; | 219 let (_, sprite) = parse_sprite(i)?; |
236 sprites.push(sprite); | 220 sprites.push(sprite); |
237 } | 221 } |
238 | 222 |
239 let mut scripts = HashMap::new(); | 223 let mut scripts = HashMap::new(); |
240 for (index, offset) in script_offsets { | 224 for (index, offset) in script_offsets.into_iter().map(|(index, offset)| (index as u8, offset as usize)) { |
241 if input.len() < start_offset + offset { | 225 if input.len() < start_offset + offset { |
242 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); | 226 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); |
243 } | 227 } |
244 i = &input[start_offset + offset..]; | 228 i = &input[start_offset + offset..]; |
245 let mut instruction_offsets = vec![]; | 229 let mut instruction_offsets = vec![]; |
246 | 230 |
247 let mut instructions = vec![]; | 231 let mut instructions = vec![]; |
248 loop { | 232 loop { |
249 let tell = input.len() - i.len(); | 233 let tell = input.len() - i.len(); |
250 instruction_offsets.push(tell - (start_offset + offset)); | 234 instruction_offsets.push(tell - (start_offset + offset)); |
251 let (i2, time) = le_u16(i)?; | |
252 let (i2, opcode) = le_u8(i2)?; | |
253 // TODO: maybe check against the size of parsed data? | 235 // TODO: maybe check against the size of parsed data? |
254 let (i2, _size) = le_u8(i2)?; | 236 let (i2, (time, opcode, _size)) = tuple((le_u16, le_u8, le_u8))(i)?; |
255 let (i2, instr) = parse_instruction_args(i2, opcode)?; | 237 let (i2, instr) = parse_instruction_args(i2, opcode)?; |
256 instructions.push(Call { time, instr }); | 238 instructions.push(Call { time, instr }); |
257 i = i2; | 239 i = i2; |
258 if opcode == 0 { | 240 if opcode == 0 { |
259 break; | 241 break; |
285 instructions, | 267 instructions, |
286 interrupts, | 268 interrupts, |
287 }); | 269 }); |
288 } | 270 } |
289 | 271 |
290 assert!(has_data == 0); | |
291 | |
292 let anm0 = Anm0 { | 272 let anm0 = Anm0 { |
293 size: (width, height), | 273 size: (width, height), |
294 format, | 274 format, |
295 first_name, | 275 first_name, |
296 second_name, | 276 second_name, |