diff src/th06/anm0.rs @ 702:718348c7608e

anm0: simplify parsing with more combinators.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Fri, 23 Aug 2019 17:22:38 +0200
parents b6c351ca0a35
children 84af5bedbde4
line wrap: on
line diff
--- 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,