changeset 713:258f4aebf3fc

anm0: Parse only a single anm0 at once and use many0 for more, to simplify parsing.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 17 Sep 2019 17:36:02 +0200
parents 13fd434d5d1b
children fcc8f736c746
files src/th06/anm0.rs
diffstat 1 files changed, 94 insertions(+), 101 deletions(-) [+]
line wrap: on
line diff
--- 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<Anm0>> {
-        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<Anm0>> {
-    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)]