diff src/th06/anm0.rs @ 694:3ff1af76e413

anm0: only use recoverable errors, no panics except for anm0 asserts.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Fri, 23 Aug 2019 02:24:08 +0200
parents 7bde50132735
children b6c351ca0a35
line wrap: on
line diff
--- a/src/th06/anm0.rs
+++ b/src/th06/anm0.rs
@@ -89,8 +89,11 @@ fn parse_name(i: &[u8], is_present: bool
         return Ok((i, String::new()));
     }
     let (_, slice) = take_while_m_n(0, 32, |c| c != 0)(i)?;
-    // XXX: no unwrap!
-    let string = String::from_utf8(slice.to_vec()).unwrap();
+    let string = match String::from_utf8(slice.to_vec()) {
+        Ok(string) => string,
+        // XXX: use a more specific error instead.
+        Err(_) => return Err(nom::Err::Failure((i, nom::error::ErrorKind::Eof)))
+    };
     Ok((i, string))
 }
 
@@ -120,8 +123,7 @@ macro_rules! declare_anm_instructions {
             ),*
         }
 
-        fn parse_instruction_args(input: &[u8], opcode: u8) -> IResult<&[u8], Instruction> {
-            let mut i = &input[..];
+        fn parse_instruction_args(mut i: &[u8], opcode: u8) -> IResult<&[u8], Instruction> {
             let instr = match opcode {
                 $(
                     $opcode => {
@@ -132,7 +134,8 @@ macro_rules! declare_anm_instructions {
                         Instruction::$name($($arg),*)
                     }
                 )*
-                _ => unreachable!()
+                // XXX: use a more specific error instead.
+                _ => return Err(nom::Err::Failure((i, nom::error::ErrorKind::Eof)))
             };
             Ok((i, instr))
         }
@@ -213,15 +216,24 @@ fn parse_anm0(input: &[u8]) -> IResult<&
             i = i2;
         }
 
+        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 mut sprites = vec![];
         let mut i;
         for offset in sprite_offsets {
+            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);
@@ -229,6 +241,9 @@ fn parse_anm0(input: &[u8]) -> IResult<&
 
         let mut scripts = HashMap::new();
         for (index, offset) in script_offsets {
+            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![];
 
@@ -255,8 +270,11 @@ fn parse_anm0(input: &[u8]) -> IResult<&
                         let result = instruction_offsets.binary_search(&(*offset as usize));
                         match result {
                             Ok(ptr) => *offset = ptr as u32,
-                            // TODO: make that a recoverable error instead.
-                            Err(ptr) => panic!("Instruction offset not found for pointer: {}", ptr),
+                            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) => {