1 //! This module contains code to read and write fileformats that are used by Jagged Alliance 2
2 
3 use std::io::ErrorKind::{InvalidData, InvalidInput};
4 use std::io::{Error, Read, Result, Write};
5 
6 pub mod slf;
7 
8 /// Trait that adds extra functions to Read.
9 pub trait StracciatellaReadExt: Read {
10     /// Reads and discards unused bytes.
read_unused(&mut self, num_bytes: usize) -> Result<()>11     fn read_unused(&mut self, num_bytes: usize) -> Result<()> {
12         let mut buffer = vec![0u8; num_bytes];
13         self.read_exact(&mut buffer)?;
14         Ok(())
15     }
16 
17     /// Reads a nul terminated fixed size string.
read_fixed_string(&mut self, num_bytes: usize) -> Result<String>18     fn read_fixed_string(&mut self, num_bytes: usize) -> Result<String> {
19         let mut buffer = vec![0u8; num_bytes];
20         self.read_exact(&mut buffer)?;
21         // must be nul terminated and valid utf8
22         match buffer.iter().position(|&byte| byte == 0) {
23             Some(position) => match ::std::str::from_utf8(&buffer[..position]) {
24                 Ok(s) => Ok(s.to_string()),
25                 Err(e) => Err(Error::new(InvalidData, e)),
26             },
27             None => Err(Error::new(InvalidData, "string is not nul terminated")),
28         }
29     }
30 }
31 
32 /// Trait that adds extra functions to Write.
33 pub trait StracciatellaWriteExt: Write {
34     /// Writes zeroed unused bytes.
write_unused(&mut self, num_bytes: usize) -> Result<()>35     fn write_unused(&mut self, num_bytes: usize) -> Result<()> {
36         let buffer = vec![0u8; num_bytes];
37         self.write_all(&buffer)
38     }
39 
40     /// Write a nul terminated fixed size string, unused space is zeroed.
write_fixed_string(&mut self, num_bytes: usize, string: &str) -> Result<()>41     fn write_fixed_string(&mut self, num_bytes: usize, string: &str) -> Result<()> {
42         let mut buffer = vec![0u8; num_bytes];
43         let string_bytes = string.as_bytes();
44         if string_bytes.len() >= buffer.len() {
45             return Err(Error::new(InvalidInput, "string is too long"));
46         }
47         buffer[..string_bytes.len()].copy_from_slice(&string_bytes);
48         self.write_all(&buffer)?;
49         Ok(())
50     }
51 }
52 
53 /// Everything that implements Read gets Ja2WriteExt for free.
54 impl<T: Read + ?Sized> StracciatellaReadExt for T {}
55 
56 /// Everything that implements Write gets Ja2WriteExt for free.
57 impl<T: Write + ?Sized> StracciatellaWriteExt for T {}
58