changeset 712:13fd434d5d1b

std: Split parser to simplify parsing.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 17 Sep 2019 16:46:10 +0200
parents 464c1b02a996
children 258f4aebf3fc
files src/th06/std.rs
diffstat 1 files changed, 71 insertions(+), 75 deletions(-) [+]
line wrap: on
line diff
--- 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,