# HG changeset patch # User Emmanuel Gil Peyrot # Date 1568731570 -7200 # Node ID 13fd434d5d1b5e41c932b2be0596dfbbdebfcb76 # Parent 464c1b02a996e88858a831ccf70628122b7366fb std: Split parser to simplify parsing. diff --git a/src/th06/std.rs b/src/th06/std.rs --- a/src/th06/std.rs +++ b/src/th06/std.rs @@ -2,13 +2,15 @@ use nom::{ IResult, - bytes::complete::{tag, take_while_m_n}, + bytes::complete::tag, number::complete::{le_u8, le_u16, le_u32, le_i32, le_f32}, sequence::tuple, combinator::map, + multi::{many0, count}, + error::ErrorKind, + Err, }; use encoding_rs::SHIFT_JIS; -use std::collections::HashMap; /// A float position in the 3D space. #[derive(Debug, Clone)] @@ -88,9 +90,10 @@ pub struct Call { } /// Parse a SHIFT_JIS byte string of length 128 into a String. +#[allow(non_snake_case)] pub fn le_String(i: &[u8]) -> IResult<&[u8], String> { let data = i.splitn(2, |c| *c == b'\0').nth(0).unwrap(); - let (string, encoding, replaced) = SHIFT_JIS.decode(data); + let (string, _encoding, _replaced) = SHIFT_JIS.decode(data); Ok((&i[128..], string.into_owned())) } @@ -160,88 +163,81 @@ declare_stage_instructions!{ 5 => fn Unknown(_unused: i32, _unused: i32, _unused: i32), } +fn parse_quad(i: &[u8]) -> IResult<&[u8], Quad> { + let (i, (unk1, size)) = tuple((le_u16, le_u16))(i)?; + if unk1 == 0xffff { + return Err(Err::Error((i, ErrorKind::Eof))); + } + // TODO: replace this assert with a custom error. + assert_eq!(size, 0x1c); + let (i, (anm_script, _, x, y, z, width, height)) = tuple((le_u16, tag(b"\0\0"), le_f32, le_f32, le_f32, le_f32, le_f32))(i)?; + let quad = Quad { + anm_script, + pos: Position { x, y, z }, + size_override: Box2D { width, height }, + }; + Ok((i, quad)) +} + +fn parse_model(i: &[u8]) -> IResult<&[u8], Model> { + let (i, (_id, unknown, x, y, z, width, height, depth, quads)) = tuple((le_u16, le_u16, le_f32, le_f32, le_f32, le_f32, le_f32, le_f32, many0(parse_quad)))(i)?; + let bounding_box = [x, y, z, width, height, depth]; + let model = Model { + unknown, + bounding_box, + quads, + }; + Ok((i, model)) +} + +fn parse_instance(i: &[u8]) -> IResult<&[u8], Instance> { + let (i, (id, unknown, x, y, z)) = tuple((le_u16, le_u16, le_f32, le_f32, le_f32))(i)?; + if id == 0xffff && unknown == 0xffff { + return Err(Err::Error((i, ErrorKind::Eof))); + } + // TODO: replace this assert with a custom error. + assert_eq!(unknown, 0x100); + let instance = Instance { + id, + pos: Position { x, y, z }, + }; + Ok((i, instance)) +} + +fn parse_instruction(i: &[u8]) -> IResult<&[u8], Call> { + let (i, (time, opcode, size)) = tuple((le_u32, le_u16, le_u16))(i)?; + if time == 0xffffffff && opcode == 0xffff && size == 0xffff { + return Err(Err::Error((i, ErrorKind::Eof))); + } + // TODO: replace this assert with a custom error. + assert_eq!(size, 12); + let (i, instr) = parse_instruction_args(i, opcode)?; + println!("{} {:?}", time, instr); + let call = Call { time, instr }; + Ok((i, call)) +} + fn parse_stage(input: &[u8]) -> IResult<&[u8], Stage> { - let start_offset = 0; - let i = &input[start_offset..]; - let (i, (num_models, num_faces, object_instances_offset, script_offset, _)) = tuple((le_u16, le_u16, le_u32, le_u32, tag(b"\0\0\0\0")))(i)?; - let object_instances_offset = object_instances_offset as usize; - let script_offset = script_offset as usize; + let i = &input[..]; - let (i, name) = le_String(i)?; - let (i, music_names) = map(tuple((le_String, le_String, le_String, le_String)), |(a, b, c, d)| [a, b, c, d])(i)?; - let (mut i, music_paths) = map(tuple((le_String, le_String, le_String, le_String)), |(a, b, c, d)| [a, b, c, d])(i)?; + let (i, (num_models, _num_faces, object_instances_offset, script_offset, _, name, music_names, music_paths)) = tuple(( + le_u16, le_u16, le_u32, le_u32, tag(b"\0\0\0\0"), + le_String, + map(tuple((le_String, le_String, le_String, le_String)), |(a, b, c, d)| [a, b, c, d]), + map(tuple((le_String, le_String, le_String, le_String)), |(a, b, c, d)| [a, b, c, d]) + ))(i)?; let musics = music_names.iter().zip(&music_paths).map(|(name, path)| if name == " " { None } else { Some((name.clone(), path.clone())) }).collect(); - let mut offsets = vec![]; - for _ in 0..num_models { - let (i2, offset) = le_u32(i)?; - offsets.push(offset as usize); - i = i2; - } + let (_, offsets) = count(le_u32, num_models as usize)(i)?; - // Read model definitions. let mut models = vec![]; for offset in offsets { - let i = &input[offset..]; - let (mut i, (id, unknown, x, y, z, width, height, depth)) = tuple((le_u16, le_u16, le_f32, le_f32, le_f32, le_f32, le_f32, le_f32))(i)?; - let bounding_box = [x, y, z, width, height, depth]; - let mut quads = vec![]; - loop { - let (i2, (unk1, size)) = tuple((le_u16, le_u16))(i)?; - if unk1 == 0xffff { - break; - } - assert_eq!(size, 0x1c); - let (i2, (anm_script, _, x, y, z, width, height)) = tuple((le_u16, tag(b"\0\0"), le_f32, le_f32, le_f32, le_f32, le_f32))(i2)?; - let quad = Quad { - anm_script, - pos: Position { x, y, z }, - size_override: Box2D { width, height }, - }; - quads.push(quad); - i = i2; - } - let model = Model { - unknown, - bounding_box, - quads, - }; + let (_, model) = parse_model(&input[offset as usize..])?; models.push(model); } - // Read object usage. - let mut instances = vec![]; - let mut i = &input[object_instances_offset..]; - loop { - let (i2, (id, unknown, x, y, z)) = tuple((le_u16, le_u16, le_f32, le_f32, le_f32))(i)?; - if id == 0xffff && unknown == 0xffff { - break; - } - assert_eq!(unknown, 0x100); - let instance = Instance { - id, - pos: Position { x, y, z }, - }; - instances.push(instance); - i = i2; - } - - // Read the script. - let mut script = vec![]; - let mut i = &input[script_offset..]; - loop { - let (i2, (time, opcode, size)) = tuple((le_u32, le_u16, le_u16))(i)?; - if time == 0xffffffff && opcode == 0xffff && size == 0xffff { - break; - } - assert_eq!(size, 12); - let data = &i2[..12]; - let (data, instr) = parse_instruction_args(data, opcode)?; - assert_eq!(data.len(), 0); - println!("{} {:?}", time, instr); - script.push(Call { time, instr }); - i = &i2[12..]; - } + let (_, instances) = many0(parse_instance)(&input[object_instances_offset as usize..])?; + let (_, script) = many0(parse_instruction)(&input[script_offset as usize..])?; let stage = Stage { name,