Mercurial > touhou
comparison src/th06/ecl.rs @ 703:81232dac8136
ecl: simplify parsing with more combinators.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Fri, 23 Aug 2019 17:37:22 +0200 |
parents | 7ae576a418ff |
children | fcc8f736c746 |
comparison
equal
deleted
inserted
replaced
702:718348c7608e | 703:81232dac8136 |
---|---|
1 //! ECL enemy script format support. | 1 //! ECL enemy script format support. |
2 | 2 |
3 use nom::{ | 3 use nom::{ |
4 IResult, | 4 IResult, |
5 bytes::complete::take_while_m_n, | |
6 number::complete::{le_u8, le_u16, le_u32, le_i16, le_i32, le_f32}, | 5 number::complete::{le_u8, le_u16, le_u32, le_i16, le_i32, le_f32}, |
6 sequence::tuple, | |
7 multi::many_m_n, | |
7 }; | 8 }; |
8 use encoding_rs::SHIFT_JIS; | 9 use encoding_rs::SHIFT_JIS; |
9 use bitflags::bitflags; | 10 use bitflags::bitflags; |
10 | 11 |
11 bitflags! { | 12 bitflags! { |
12 /// Bit flags describing the current difficulty level. | 13 /// Bit flags describing the current difficulty level. |
13 pub struct Rank: u16 { | 14 pub struct Rank: u16 { |
14 /// Easy mode. | 15 /// Easy mode. |
15 const Easy = 0x100; | 16 const EASY = 0x100; |
16 | 17 |
17 /// Normal mode. | 18 /// Normal mode. |
18 const Normal = 0x200; | 19 const NORMAL = 0x200; |
19 | 20 |
20 /// Hard mode. | 21 /// Hard mode. |
21 const Hard = 0x400; | 22 const HARD = 0x400; |
22 | 23 |
23 /// Lunatic mode. | 24 /// Lunatic mode. |
24 const Lunatic = 0x800; | 25 const LUNATIC = 0x800; |
25 | 26 |
26 /// Any or all modes. | 27 /// Any or all modes. |
27 const All = 0xff00; | 28 const ALL = 0xff00; |
28 } | 29 } |
29 } | 30 } |
30 | 31 |
31 impl std::str::FromStr for Rank { | 32 impl std::str::FromStr for Rank { |
32 type Err = String; | 33 type Err = String; |
33 | 34 |
34 fn from_str(s: &str) -> Result<Rank, Self::Err> { | 35 fn from_str(s: &str) -> Result<Rank, Self::Err> { |
35 Ok(match s { | 36 Ok(match s { |
36 "easy" => Rank::Easy, | 37 "easy" => Rank::EASY, |
37 "normal" => Rank::Normal, | 38 "normal" => Rank::NORMAL, |
38 "hard" => Rank::Hard, | 39 "hard" => Rank::HARD, |
39 "lunatic" => Rank::Lunatic, | 40 "lunatic" => Rank::LUNATIC, |
40 _ => return Err(format!("unknown rank {}", s)) | 41 _ => return Err(format!("unknown rank {}", s)) |
41 }) | 42 }) |
42 } | 43 } |
43 } | 44 } |
44 | 45 |
327 | 328 |
328 fn parse_ecl(input: &[u8]) -> IResult<&[u8], Ecl> { | 329 fn parse_ecl(input: &[u8]) -> IResult<&[u8], Ecl> { |
329 let i = input; | 330 let i = input; |
330 | 331 |
331 let (i, sub_count) = le_u16(i)?; | 332 let (i, sub_count) = le_u16(i)?; |
332 let (mut i, main_count) = le_u16(i)?; | 333 let sub_count = sub_count as usize; |
334 let (i, main_count) = le_u16(i)?; | |
333 assert_eq!(main_count, 0); | 335 assert_eq!(main_count, 0); |
334 | 336 |
335 let mut main_offsets = Vec::new(); | 337 let (i, main_offsets) = many_m_n(3, 3, le_u32)(i)?; |
336 for _ in 0..3 { | 338 let (_, sub_offsets) = many_m_n(sub_count, sub_count, le_u32)(i)?; |
337 let (i2, offset) = le_u32(i)?; | |
338 main_offsets.push(offset as usize); | |
339 i = i2; | |
340 } | |
341 | |
342 let mut sub_offsets = Vec::new(); | |
343 for _ in 0..sub_count { | |
344 let (i2, offset) = le_u32(i)?; | |
345 sub_offsets.push(offset as usize); | |
346 i = i2; | |
347 } | |
348 | 339 |
349 // Read all subs. | 340 // Read all subs. |
350 let mut subs = Vec::new(); | 341 let mut subs = Vec::new(); |
351 for offset in sub_offsets { | 342 for offset in sub_offsets.into_iter().map(|offset| offset as usize) { |
352 let mut i = &input[offset..]; | 343 let mut i = &input[offset..]; |
353 let mut instructions = Vec::new(); | 344 let mut instructions = Vec::new(); |
354 loop { | 345 loop { |
355 let (i2, time) = le_i32(i)?; | 346 let (i2, (time, opcode)) = tuple((le_i32, le_u16))(i)?; |
356 let (i2, opcode) = le_u16(i2)?; | |
357 if time == -1 || opcode == 0xffff { | 347 if time == -1 || opcode == 0xffff { |
358 break; | 348 break; |
359 } | 349 } |
360 | 350 |
361 let (i2, size) = le_u16(i2)?; | 351 let (i2, (size, rank_mask, param_mask)) = tuple((le_u16, le_u16, le_u16))(i2)?; |
362 let (i2, rank_mask) = le_u16(i2)?; | 352 let size = size as usize; |
363 let rank_mask = Rank::from_bits(rank_mask).unwrap(); | 353 let rank_mask = Rank::from_bits(rank_mask).unwrap(); |
364 let (i2, param_mask) = le_u16(i2)?; | |
365 // FIXME: this - 12 can trigger a panic, fuzz it! | 354 // FIXME: this - 12 can trigger a panic, fuzz it! |
366 let data = &i2[..size as usize - 12]; | 355 let data = &i2[..size - 12]; |
367 let (data, instr) = parse_sub_instruction_args(data, opcode)?; | 356 let (data, instr) = parse_sub_instruction_args(data, opcode)?; |
368 assert_eq!(data.len(), 0); | 357 assert_eq!(data.len(), 0); |
369 instructions.push(CallSub { time, rank_mask, param_mask, instr }); | 358 instructions.push(CallSub { time, rank_mask, param_mask, instr }); |
370 i = &i[size as usize..]; | 359 i = &i[size..]; |
371 } | 360 } |
372 subs.push(Sub { instructions }); | 361 subs.push(Sub { instructions }); |
373 } | 362 } |
374 | 363 |
375 // Read all mains (always a single one atm). | 364 // Read all mains (always a single one atm). |
376 let mut mains = Vec::new(); | 365 let mut mains = Vec::new(); |
377 for offset in main_offsets { | 366 for offset in main_offsets.into_iter().map(|offset| offset as usize) { |
378 if offset == 0 { | 367 if offset == 0 { |
379 break; | 368 break; |
380 } | 369 } |
381 | 370 |
382 let mut i = &input[offset..]; | 371 let mut i = &input[offset..]; |
383 let mut instructions = Vec::new(); | 372 let mut instructions = Vec::new(); |
384 loop { | 373 loop { |
385 let (i2, time) = le_u16(i)?; | 374 let (i2, (time, sub)) = tuple((le_u16, le_u16))(i)?; |
386 let (i2, sub) = le_u16(i2)?; | |
387 if time == 0xffff && sub == 4 { | 375 if time == 0xffff && sub == 4 { |
388 break; | 376 break; |
389 } | 377 } |
390 | 378 |
391 let (i2, opcode) = le_u16(i2)?; | 379 let (i2, (opcode, size)) = tuple((le_u16, le_u16))(i2)?; |
392 let (i2, size) = le_u16(i2)?; | 380 let size = size as usize; |
393 // FIXME: this - 8 can trigger a panic, fuzz it! | 381 // FIXME: this - 8 can trigger a panic, fuzz it! |
394 let data = &i2[..size as usize - 8]; | 382 let data = &i2[..size - 8]; |
395 let (data, instr) = parse_main_instruction_args(data, opcode)?; | 383 let (data, instr) = parse_main_instruction_args(data, opcode)?; |
396 assert_eq!(data.len(), 0); | 384 assert_eq!(data.len(), 0); |
397 instructions.push(CallMain { time, sub, instr }); | 385 instructions.push(CallMain { time, sub, instr }); |
398 i = &i[size as usize..]; | 386 i = &i[size..]; |
399 } | 387 } |
400 mains.push(Main { instructions }); | 388 mains.push(Main { instructions }); |
401 } | 389 } |
402 | 390 |
403 let ecl = Ecl { | 391 let ecl = Ecl { |