# HG changeset patch # User Emmanuel Gil Peyrot # Date 1568734562 -7200 # Node ID 258f4aebf3fc4d220dd8f4479179a5ef88ebfc34 # Parent 13fd434d5d1b5e41c932b2be0596dfbbdebfcb76 anm0: Parse only a single anm0 at once and use many0 for more, to simplify parsing. diff --git a/src/th06/anm0.rs b/src/th06/anm0.rs --- a/src/th06/anm0.rs +++ b/src/th06/anm0.rs @@ -5,7 +5,7 @@ use nom::{ 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, + multi::{many_m_n, many0}, }; use std::collections::HashMap; @@ -73,7 +73,7 @@ pub struct Anm0 { impl Anm0 { /// Parse a slice of bytes into an `Anm0` struct. pub fn from_slice(data: &[u8]) -> IResult<&[u8], Vec> { - parse_anm0(data) + many0(parse_anm0)(data) } /// TODO @@ -167,120 +167,113 @@ declare_anm_instructions!{ 31 => fn Todo(todo: u32), } -fn parse_anm0(input: &[u8]) -> IResult<&[u8], Vec> { - let mut list = vec![]; - let start_offset = 0; - loop { - let i = &input[start_offset..]; - 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)?; +fn parse_anm0(input: &[u8]) -> IResult<&[u8], Anm0> { + let (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))(input)?; - 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; + 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 (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 (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 png_filename = 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() - }; + let png_filename = if first_name_offset > 0 { + if input.len() < first_name_offset as usize { + return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); + } + let i = &input[first_name_offset as usize..]; + let (_, name) = parse_name(i)?; + name + } else { + String::new() + }; - let alpha_filename = 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)?; - Some(name) - } else { - None - }; + let alpha_filename = if second_name_offset > 0 { + if input.len() < second_name_offset as usize { + return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); + } + let i = &input[second_name_offset as usize..]; + let (_, name) = parse_name(i)?; + Some(name) + } else { + None + }; - let mut sprites = vec![]; - let mut i; - 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))); - } - i = &input[start_offset + offset..]; - let (_, sprite) = parse_sprite(i)?; - sprites.push(sprite); + let mut sprites = vec![]; + let mut i = &input[..]; + for offset in sprite_offsets.into_iter().map(|x| x as usize) { + if input.len() < offset { + return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); } + i = &input[offset..]; + let (_, sprite) = parse_sprite(i)?; + sprites.push(sprite); + } - let mut scripts = HashMap::new(); - 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))); - } - i = &input[start_offset + offset..]; - let mut instruction_offsets = vec![]; + let mut scripts = HashMap::new(); + for (index, offset) in script_offsets.into_iter().map(|(index, offset)| (index as u8, offset as usize)) { + if input.len() < offset { + return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); + } + i = &input[offset..]; + let mut instruction_offsets = vec![]; - let mut instructions = vec![]; - loop { - let tell = input.len() - i.len(); - instruction_offsets.push(tell - (start_offset + offset)); - // TODO: maybe check against the size of parsed data? - 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; - if opcode == 0 { - break; - } + let mut instructions = vec![]; + loop { + let tell = input.len() - i.len(); + instruction_offsets.push(tell - offset); + // TODO: maybe check against the size of parsed data? + 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; + if opcode == 0 { + break; } - let mut interrupts = HashMap::new(); - let mut j = 0; - for Call { time: _, instr } in &mut instructions { - match instr { - Instruction::Jump(ref mut offset) => { - let result = instruction_offsets.binary_search(&(*offset as usize)); - match result { - Ok(ptr) => *offset = ptr as u32, - Err(ptr) => { - // XXX: use a more specific error instead. - return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); - //println!("Instruction offset not found for pointer: {}", ptr); - } + } + let mut interrupts = HashMap::new(); + let mut j = 0; + for Call { time: _, instr } in &mut instructions { + match instr { + Instruction::Jump(ref mut offset) => { + let result = instruction_offsets.binary_search(&(*offset as usize)); + match result { + Ok(ptr) => *offset = ptr as u32, + Err(ptr) => { + // XXX: use a more specific error instead. + return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); + //println!("Instruction offset not found for pointer: {}", ptr); } } - Instruction::InterruptLabel(interrupt) => { - interrupts.insert(*interrupt, j + 1); - } - _ => () + } + Instruction::InterruptLabel(interrupt) => { + interrupts.insert(*interrupt, j + 1); } - j += 1; + _ => () } - scripts.insert(index, Script { - instructions, - interrupts, - }); + j += 1; } + scripts.insert(index, Script { + instructions, + interrupts, + }); + } - let anm0 = Anm0 { - size: (width, height), - format, - png_filename, - alpha_filename, - sprites, - scripts, - }; - list.push(anm0); - break; - } - Ok((b"", list)) + let anm0 = Anm0 { + size: (width, height), + format, + png_filename, + alpha_filename, + sprites, + scripts, + }; + Ok((i, anm0)) } #[cfg(test)]