1use std::io::{self, Read};
4use std::mem::size_of;
5use byteorder::ReadBytesExt;
6use byteorder::NativeEndian as E;
7
8use super::{
9 SIGNATURE, FORMAT, VERSION, DATA, TEST_INT, TEST_NUMBER,
10 Int, Size, Instruction, Integer, Number,
11 Constant, Upvalue, LocalVar, Debug, Function,
12};
13
14pub fn read_file<R: Read>(read: R) -> io::Result<Function> {
16 let mut reader = Reader { out: read };
17 try!(reader.read_header());
18 try!(reader.out.read_u8()); reader.read_function()
20}
21
22struct Reader<R: Read> {
23 out: R,
24}
25
26fn invalid<T, S: Into<Box<::std::error::Error + Send + Sync>>>(s: S) -> io::Result<T> {
27 Err(io::Error::new(io::ErrorKind::InvalidInput, s))
28}
29
30macro_rules! check {
31 ($get:expr, $want:expr, $note:expr) => {{
32 let get = $get;
33 let want = $want;
34 if get != want {
35 return Err(io::Error::new(io::ErrorKind::InvalidInput, format!(
36 "invalid {}, expected {:?} but got {:?}",
37 $note, want, get,
38 )));
39 }
40 }}
41}
42
43impl<R: Read> Reader<R> {
44 fn read_all(&mut self, mut buf: &mut [u8]) -> io::Result<()> {
45 let mut start = 0;
46 let len = buf.len();
47 while start < len {
48 let n = try!(self.out.read(&mut buf[start..]));
49 if n == 0 {
50 return invalid("unexpected EOF");
51 }
52 start += n;
53 }
54 Ok(())
55 }
56
57 fn read_header(&mut self) -> io::Result<()> {
58 let mut buffer = [0u8; 6];
59 try!(self.read_all(&mut buffer[..4]));
60 check!(&buffer[..4], SIGNATURE, "signature");
61 check!(try!(self.out.read_u8()), VERSION, "version");
62 check!(try!(self.out.read_u8()), FORMAT, "format");
63 try!(self.read_all(&mut buffer));
64 check!(&buffer, DATA, "test data");
65 check!(try!(self.out.read_u8()), size_of::<Int>() as u8, "sizeof(int)");
66 check!(try!(self.out.read_u8()), size_of::<Size>() as u8, "sizeof(size_t)");
67 check!(try!(self.out.read_u8()), size_of::<Instruction>() as u8, "sizeof(Instruction)");
68 check!(try!(self.out.read_u8()), size_of::<Integer>() as u8, "sizeof(Integer)");
69 check!(try!(self.out.read_u8()), size_of::<Number>() as u8, "sizeof(Number)");
70 check!(try!(self.out.read_i64::<E>()), TEST_INT, "test integer");
71 check!(try!(self.out.read_f64::<E>()), TEST_NUMBER, "test number");
72 Ok(())
73 }
74
75 fn read_function(&mut self) -> io::Result<Function> {
76 Ok(Function {
77 source: try!(self.read_string()),
78 line_start: try!(self.out.read_i32::<E>()),
79 line_end: try!(self.out.read_i32::<E>()),
80 num_params: try!(self.out.read_u8()),
81 is_vararg: try!(self.out.read_u8()) != 0,
82 max_stack_size: try!(self.out.read_u8()),
83 code: try!(self.read_vec(|this| Ok(try!(this.out.read_u32::<E>())))),
84 constants: try!(self.read_vec(|this| Ok(match try!(this.out.read_u8()) {
85 0x00 => Constant::Nil,
86 0x01 => Constant::Boolean(try!(this.out.read_u8()) != 0),
87 0x03 => Constant::Float(try!(this.out.read_f64::<E>())),
88 0x13 => Constant::Int(try!(this.out.read_i64::<E>())),
89 0x04 => Constant::ShortString(try!(this.read_string())),
90 0x14 => Constant::LongString(try!(this.read_string())),
91 o => return invalid(format!("unknown constant type {}", o)),
92 }))),
93 upvalues: try!(self.read_vec(|this| {
94 let stack = try!(this.out.read_u8());
95 let idx = try!(this.out.read_u8());
96 Ok(match stack {
97 0 => Upvalue::Outer(idx),
98 _ => Upvalue::Stack(idx),
99 })
100 })),
101 protos: try!(self.read_vec(|this| this.read_function())),
102 debug: Debug {
103 lineinfo: try!(self.read_vec(|this| Ok(try!(this.out.read_i32::<E>())))),
104 localvars: try!(self.read_vec(|this| Ok(LocalVar {
105 name: try!(this.read_string()),
106 start_pc: try!(this.out.read_i32::<E>()),
107 end_pc: try!(this.out.read_i32::<E>()),
108 }))),
109 upvalues: try!(self.read_vec(|this| this.read_string())),
110 },
111 })
112 }
113
114 #[inline]
115 fn read_vec<F, T>(&mut self, f: F) -> io::Result<Vec<T>>
116 where F: Fn(&mut Self) -> io::Result<T>
117 {
118 let len = try!(self.out.read_u32::<E>());
119 (0..len).map(|_| f(self)).collect()
120 }
121
122 fn read_string(&mut self) -> io::Result<String> {
123 let first = try!(self.out.read_u8());
124 if first == 0 {
125 Ok(String::new())
126 } else {
127 let len = if first < 0xff {
128 first as usize
129 } else {
130 try!(self.out.read_u32::<E>()) as usize
131 } - 1;
132 let mut buffer = vec![0u8; len];
133 try!(self.read_all(&mut buffer));
134 match String::from_utf8(buffer) {
136 Ok(s) => Ok(s),
137 Err(_) => invalid("not utf8"),
138 }
139 }
140 }
141}