# HG changeset patch # User Emmanuel Gil Peyrot # Date 1566573758 -7200 # Node ID 718348c7608ed6fd04fdaa82dd4f80debb7ce65f # Parent b6c351ca0a353bbf6bdaeee3e133bc53e78e1f81 anm0: simplify parsing with more combinators. diff --git a/src/th06/anm0.rs b/src/th06/anm0.rs --- a/src/th06/anm0.rs +++ b/src/th06/anm0.rs @@ -4,6 +4,8 @@ use nom::{ IResult, bytes::complete::{tag, take_while_m_n}, number::complete::{le_u8, le_u16, le_u32, le_i32, le_f32}, + sequence::tuple, + multi::many_m_n, }; use std::collections::HashMap; @@ -81,10 +83,7 @@ impl Anm0 { } } -fn parse_name(i: &[u8], is_present: bool) -> IResult<&[u8], String> { - if !is_present { - return Ok((i, String::new())); - } +fn parse_name(i: &[u8]) -> IResult<&[u8], String> { let (_, slice) = take_while_m_n(0, 32, |c| c != 0)(i)?; let string = match String::from_utf8(slice.to_vec()) { Ok(string) => string, @@ -95,11 +94,7 @@ fn parse_name(i: &[u8], is_present: bool } fn parse_sprite(i: &[u8]) -> IResult<&[u8], Sprite> { - let (i, index) = le_u32(i)?; - let (i, x) = le_f32(i)?; - let (i, y) = le_f32(i)?; - let (i, width) = le_f32(i)?; - let (i, height) = le_f32(i)?; + let (i, (index, x, y, width, height)) = tuple((le_u32, le_f32, le_f32, le_f32, le_f32))(i)?; Ok((i, Sprite { index, x, @@ -177,57 +172,46 @@ fn parse_anm0(input: &[u8]) -> IResult<& let start_offset = 0; loop { let i = &input[start_offset..]; - let (i, num_sprites) = le_u32(i)?; - let (i, num_scripts) = le_u32(i)?; - let (i, _) = tag(b"\0\0\0\0")(i)?; - let (i, width) = le_u32(i)?; - let (i, height) = le_u32(i)?; - let (i, format) = le_u32(i)?; - let (i, _unknown1) = le_u32(i)?; - let (i, first_name_offset) = le_u32(i)?; - let (i, _unused) = le_u32(i)?; - let (i, second_name_offset) = le_u32(i)?; - let (i, version) = le_u32(i)?; - let (i, _unknown2) = le_u32(i)?; - let (i, _texture_offset) = le_u32(i)?; - let (i, has_data) = le_u32(i)?; - let (i, _next_offset) = le_u32(i)?; - let (mut i, unknown3) = le_u32(i)?; + let (mut i, (num_sprites, num_scripts, _, width, height, format, _unknown1, + first_name_offset, _unused, second_name_offset, version, _unknown2, + _texture_offset, has_data, _next_offset, unknown3)) = + tuple((le_u32, le_u32, tag(b"\0\0\0\0"), le_u32, le_u32, le_u32, le_u32, le_u32, + le_u32, le_u32, le_u32, le_u32, le_u32, le_u32, le_u32, le_u32))(i)?; assert_eq!(version, 0); assert_eq!(unknown3, 0); assert_eq!(has_data, 0); + let num_sprites = num_sprites as usize; + let num_scripts = num_scripts as usize; - let mut sprite_offsets = vec![]; - for _ in 0..num_sprites { - let (i2, offset) = le_u32(i)?; - sprite_offsets.push(offset as usize); - i = i2; - } + let (i, sprite_offsets) = many_m_n(num_sprites, num_sprites, le_u32)(i)?; + let (_, script_offsets) = many_m_n(num_scripts, num_scripts, tuple((le_u32, le_u32)))(i)?; - let mut script_offsets = vec![]; - for _ in 0..num_scripts { - let (i2, index) = le_u32(i)?; - let (i2, offset) = le_u32(i2)?; - script_offsets.push((index as u8, offset as usize)); - i = i2; - } + let first_name = if first_name_offset > 0 { + if input.len() < start_offset + first_name_offset as usize { + return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); + } + let i = &input[start_offset + first_name_offset as usize..]; + let (_, name) = parse_name(i)?; + name + } else { + String::new() + }; - if input.len() < start_offset + first_name_offset as usize { - return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); - } - let i = &input[start_offset + first_name_offset as usize..]; - let (_, first_name) = parse_name(i, first_name_offset > 0)?; - - if input.len() < start_offset + second_name_offset as usize { - return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); - } - let i = &input[start_offset + second_name_offset as usize..]; - let (_, second_name) = parse_name(i, second_name_offset > 0)?; + let second_name = if second_name_offset > 0 { + if input.len() < start_offset + second_name_offset as usize { + return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); + } + let i = &input[start_offset + second_name_offset as usize..]; + let (_, name) = parse_name(i)?; + name + } else { + String::new() + }; let mut sprites = vec![]; let mut i; - for offset in sprite_offsets { + for offset in sprite_offsets.into_iter().map(|x| x as usize) { if input.len() < start_offset + offset { return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); } @@ -237,7 +221,7 @@ fn parse_anm0(input: &[u8]) -> IResult<& } let mut scripts = HashMap::new(); - for (index, offset) in script_offsets { + for (index, offset) in script_offsets.into_iter().map(|(index, offset)| (index as u8, offset as usize)) { if input.len() < start_offset + offset { return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); } @@ -248,10 +232,8 @@ fn parse_anm0(input: &[u8]) -> IResult<& loop { let tell = input.len() - i.len(); instruction_offsets.push(tell - (start_offset + offset)); - let (i2, time) = le_u16(i)?; - let (i2, opcode) = le_u8(i2)?; // TODO: maybe check against the size of parsed data? - let (i2, _size) = le_u8(i2)?; + let (i2, (time, opcode, _size)) = tuple((le_u16, le_u8, le_u8))(i)?; let (i2, instr) = parse_instruction_args(i2, opcode)?; instructions.push(Call { time, instr }); i = i2; @@ -287,8 +269,6 @@ fn parse_anm0(input: &[u8]) -> IResult<& }); } - assert!(has_data == 0); - let anm0 = Anm0 { size: (width, height), format,