Mercurial > touhou
diff 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 |
line wrap: on
line diff
--- a/src/th06/ecl.rs +++ b/src/th06/ecl.rs @@ -2,8 +2,9 @@ use nom::{ IResult, - bytes::complete::take_while_m_n, number::complete::{le_u8, le_u16, le_u32, le_i16, le_i32, le_f32}, + sequence::tuple, + multi::many_m_n, }; use encoding_rs::SHIFT_JIS; use bitflags::bitflags; @@ -12,19 +13,19 @@ bitflags! { /// Bit flags describing the current difficulty level. pub struct Rank: u16 { /// Easy mode. - const Easy = 0x100; + const EASY = 0x100; /// Normal mode. - const Normal = 0x200; + const NORMAL = 0x200; /// Hard mode. - const Hard = 0x400; + const HARD = 0x400; /// Lunatic mode. - const Lunatic = 0x800; + const LUNATIC = 0x800; /// Any or all modes. - const All = 0xff00; + const ALL = 0xff00; } } @@ -33,10 +34,10 @@ impl std::str::FromStr for Rank { fn from_str(s: &str) -> Result<Rank, Self::Err> { Ok(match s { - "easy" => Rank::Easy, - "normal" => Rank::Normal, - "hard" => Rank::Hard, - "lunatic" => Rank::Lunatic, + "easy" => Rank::EASY, + "normal" => Rank::NORMAL, + "hard" => Rank::HARD, + "lunatic" => Rank::LUNATIC, _ => return Err(format!("unknown rank {}", s)) }) } @@ -329,52 +330,40 @@ fn parse_ecl(input: &[u8]) -> IResult<&[ let i = input; let (i, sub_count) = le_u16(i)?; - let (mut i, main_count) = le_u16(i)?; + let sub_count = sub_count as usize; + let (i, main_count) = le_u16(i)?; assert_eq!(main_count, 0); - let mut main_offsets = Vec::new(); - for _ in 0..3 { - let (i2, offset) = le_u32(i)?; - main_offsets.push(offset as usize); - i = i2; - } - - let mut sub_offsets = Vec::new(); - for _ in 0..sub_count { - let (i2, offset) = le_u32(i)?; - sub_offsets.push(offset as usize); - i = i2; - } + let (i, main_offsets) = many_m_n(3, 3, le_u32)(i)?; + let (_, sub_offsets) = many_m_n(sub_count, sub_count, le_u32)(i)?; // Read all subs. let mut subs = Vec::new(); - for offset in sub_offsets { + for offset in sub_offsets.into_iter().map(|offset| offset as usize) { let mut i = &input[offset..]; let mut instructions = Vec::new(); loop { - let (i2, time) = le_i32(i)?; - let (i2, opcode) = le_u16(i2)?; + let (i2, (time, opcode)) = tuple((le_i32, le_u16))(i)?; if time == -1 || opcode == 0xffff { break; } - let (i2, size) = le_u16(i2)?; - let (i2, rank_mask) = le_u16(i2)?; + let (i2, (size, rank_mask, param_mask)) = tuple((le_u16, le_u16, le_u16))(i2)?; + let size = size as usize; let rank_mask = Rank::from_bits(rank_mask).unwrap(); - let (i2, param_mask) = le_u16(i2)?; // FIXME: this - 12 can trigger a panic, fuzz it! - let data = &i2[..size as usize - 12]; + let data = &i2[..size - 12]; let (data, instr) = parse_sub_instruction_args(data, opcode)?; assert_eq!(data.len(), 0); instructions.push(CallSub { time, rank_mask, param_mask, instr }); - i = &i[size as usize..]; + i = &i[size..]; } subs.push(Sub { instructions }); } // Read all mains (always a single one atm). let mut mains = Vec::new(); - for offset in main_offsets { + for offset in main_offsets.into_iter().map(|offset| offset as usize) { if offset == 0 { break; } @@ -382,20 +371,19 @@ fn parse_ecl(input: &[u8]) -> IResult<&[ let mut i = &input[offset..]; let mut instructions = Vec::new(); loop { - let (i2, time) = le_u16(i)?; - let (i2, sub) = le_u16(i2)?; + let (i2, (time, sub)) = tuple((le_u16, le_u16))(i)?; if time == 0xffff && sub == 4 { break; } - let (i2, opcode) = le_u16(i2)?; - let (i2, size) = le_u16(i2)?; + let (i2, (opcode, size)) = tuple((le_u16, le_u16))(i2)?; + let size = size as usize; // FIXME: this - 8 can trigger a panic, fuzz it! - let data = &i2[..size as usize - 8]; + let data = &i2[..size - 8]; let (data, instr) = parse_main_instruction_args(data, opcode)?; assert_eq!(data.len(), 0); instructions.push(CallMain { time, sub, instr }); - i = &i[size as usize..]; + i = &i[size..]; } mains.push(Main { instructions }); }