gdritter repos thermidor / a813f16
Added ByteReader abstraction for file types Getty Ritter 7 years ago
2 changed file(s) with 128 addition(s) and 0 deletion(s). Collapse all Expand all
1 pub mod reader;
2
13 #[cfg(test)]
24 mod tests {
35 #[test]
1 use std::{fs,io,iter,slice,vec};
2
3 /// A `ByteReader` is just a tiny wrapper over a mutable byte iterator, so we
4 /// can parse things more easily.
5 pub struct ByteReader<Rd> {
6 bytes: Rd,
7 }
8
9 pub type ByteReaderT = ByteReader<Iterator<Item=u8>>;
10
11 const MK_OK: &'static Fn(io::Result<u8>) -> Option<u8> = &|s| s.ok();
12
13 impl<R: io::Read>
14 ByteReader<iter::FilterMap<io::Bytes<R>,
15 &'static Fn(io::Result<u8>) -> Option<u8>>>
16 {
17 /// Create a ByteReader from any type that implement Read
18 pub fn from_reader(r: R) -> Self {
19 let bytes = r.bytes().filter_map(MK_OK);
20 ByteReader { bytes: bytes }
21 }
22 }
23
24 impl ByteReader<iter::FilterMap<io::Bytes<fs::File>,
25 &'static Fn(io::Result<u8>) -> Option<u8>>>
26 {
27 /// Create a reader by opening a named file for reading
28 pub fn from_file(path: &str) -> io::Result<Self> {
29 let f = try!(fs::File::open(path));
30 Ok(ByteReader::from_reader(f))
31 }
32 }
33
34 impl ByteReader<vec::IntoIter<u8>> {
35 /// Create a reader from a vector of u8s
36 pub fn from_vec(lst: Vec<u8>) -> Self {
37 ByteReader { bytes: lst.into_iter() }
38 }
39 }
40
41 impl<'a> ByteReader<slice::Iter<'a, u8>> {
42 pub fn from_slice(lst: &'a [u8]) -> Self {
43 ByteReader { bytes: lst.iter() }
44 }
45 }
46
47 impl<T> ByteReader<T> where T: Iterator<Item=u8> {
48 /// This gets the next byte, or fails if it's out of input.
49 pub fn next(&mut self) -> Result<u8, String> {
50 Ok(try!(self.bytes.next().ok_or("out of input")))
51 }
52
53 /// This reads a one-byte or two-byte float in the rough range of
54 /// (192 .. -128). We're going to treat all models as if they're
55 /// supposed to be centered in a 64x64x64 square, so this gives
56 /// us 128 units on either side of the central square, as well.
57 pub fn read_twip(&mut self) -> Result<f32, String> {
58 let b1 = try!(self.next());
59 if (b1 & 0x80) != 0 {
60 let b2 = try!(self.next());
61 let val = ((b1 as u16 & 0x7f) << 8) | b2 as u16;
62 Ok((val as f32 / 102.0) - 128.0)
63 } else {
64 Ok((b1 as f32) - 32.0)
65 }
66 }
67
68 /// This reads a single byte and treats it as a ratio.
69 pub fn read_ratio(&mut self) -> Result<f32, String> {
70 let b = try!(self.next());
71 Ok(b as f32 / 255.0)
72 }
73
74 /// This reads a 64-bit int with a packed PrefixInteger representation.
75 /// The shorter the int, the shorter the representation.
76 pub fn read_prefix_int(&mut self) -> Result<u64, String> {
77 fn match_bits(n: u8, mask: u8) -> bool {
78 n & mask == mask
79 }
80 let b = try!(self.next());
81 if match_bits(b, 0xff) { self.continue_prefix_int(8, 0) }
82 else if match_bits(b, 0xfe) { self.continue_prefix_int(7, 0) }
83 else if match_bits(b, 0xfc) { self.continue_prefix_int(6, b & 0x01) }
84 else if match_bits(b, 0xf8) { self.continue_prefix_int(5, b & 0x03) }
85 else if match_bits(b, 0xf0) { self.continue_prefix_int(4, b & 0x07) }
86 else if match_bits(b, 0xe0) { self.continue_prefix_int(3, b & 0x0f) }
87 else if match_bits(b, 0xc0) { self.continue_prefix_int(2, b & 0x1f) }
88 else if match_bits(b, 0x80) { self.continue_prefix_int(1, b & 0x3f) }
89 else { self.continue_prefix_int(0, b) }
90 }
91
92 /// This is a helper function for parsing prefix ints, too.
93 fn continue_prefix_int(&mut self, mut left: u8, upper: u8) -> Result<u64, String> {
94 let mut ret = upper as u64;
95 while left > 0 {
96 left -= 1;
97 ret = (ret << 8) | try!(self.next()) as u64;
98 }
99 Ok(ret)
100 }
101
102 /// This reads a PrefixInteger to find out how many other things to read,
103 /// and then reads that number of things.
104 pub fn read_several<F, R>(&mut self, reader: F) -> Result<Vec<R>, String>
105 where F: Fn(&mut ByteReader<T>) -> Result<R, String>
106 {
107 let ct = try!(self.read_prefix_int());
108 let mut ret = Vec::with_capacity(ct as usize);
109 for _ in 0..ct {
110 ret.push(try!(reader(self)))
111 }
112 Ok(ret)
113 }
114
115 /// This reads a PrefixInteger number of bytes, and then parses those
116 /// bytes as a UTF-8 string. This means, importantly, that we cannot
117 /// naïvely produce values intended to be parsed with this using a
118 /// basic string length.
119 pub fn read_string(&mut self) -> Result<String, String> {
120 let raw_bytes = try!(self.read_several(|r| r.next()));
121 match String::from_utf8(raw_bytes) {
122 Ok(s) => Ok(s),
123 Err(e) => Err(format!("Exception when parsing UTF-8: {:?}", e)),
124 }
125 }
126 }