neige_undump/binary/
reader.rs1#[cfg(feature = "wasm")]
2use std::rc::Rc;
3#[cfg(not(feature = "wasm"))]
4use std::{
5 fs::File,
6 io::{BufReader, Read},
7 rc::Rc,
8};
9
10use neige_infra::{Constant, LocVar, Prototype, Upvalue};
11
12#[cfg(not(feature = "wasm"))]
13pub struct Reader {
14 data: BufReader<File>,
15}
16
17#[cfg(feature = "wasm")]
18pub struct Reader {
19 data: Vec<u8>,
20 pos: usize,
21}
22
23impl Reader {
24 #[cfg(not(feature = "wasm"))]
25 pub fn new(data: BufReader<File>) -> Self {
26 Self { data }
27 }
28
29 #[cfg(feature = "wasm")]
30 pub fn new(data: Vec<u8>) -> Self {
31 Self { data, pos: 0 }
32 }
33
34 #[cfg(not(feature = "wasm"))]
35 pub fn read_byte(&mut self) -> u8 {
36 let mut b = [0u8; 1];
37 self.data.read(&mut b).unwrap();
38 b[0]
39 }
40
41 #[cfg(feature = "wasm")]
42 pub fn read_byte(&mut self) -> u8 {
43 let b = self.data[self.pos];
44 self.pos += 1;
45 b
46 }
47
48 fn read_bytes(&mut self, n: usize) -> Vec<u8> {
49 let mut v = Vec::with_capacity(n);
50 for _ in 0..n {
51 v.push(self.read_byte())
52 }
53 v
54 }
55
56 fn read_u32(&mut self) -> u32 {
57 let a = self.read_byte() as u32;
58 let b = self.read_byte() as u32;
59 let c = self.read_byte() as u32;
60 let d = self.read_byte() as u32;
61 d << 24 | c << 16 | b << 8 | a
62 }
63
64 fn read_u64(&mut self) -> u64 {
65 let a = self.read_u32() as u64;
66 let b = self.read_u32() as u64;
67 b << 32 | a
68 }
69
70 fn read_vec<T, F>(&mut self, f: F) -> Vec<T>
71 where
72 F: Fn(&mut Self) -> T,
73 {
74 let n = self.read_u32() as usize;
75 let mut v = Vec::with_capacity(n);
76 for _ in 0..n {
77 v.push(f(self))
78 }
79 v
80 }
81}
82
83impl Reader {
84 fn read_lua_integer(&mut self) -> i64 {
85 self.read_u64() as i64
86 }
87
88 fn read_lua_number(&mut self) -> f64 {
89 use std::f64;
90 f64::from_bits(self.read_u64())
91 }
92
93 fn read_string(&mut self) -> String {
94 match self.read_byte() as usize {
95 0 => String::new(),
96 mut x => {
97 if x == 0xff {
98 x = self.read_u64() as usize
99 }
100 let bytes = self.read_bytes(x - 1);
101 String::from_utf8(bytes).unwrap_or(String::new())
102 }
103 }
104 }
105
106 pub fn check_header(&mut self) {
107 assert_eq!(
108 self.read_bytes(4),
109 [0x1b, 0x4c, 0x75, 0x61],
110 "not a precompiled chunk!"
111 );
112 assert_eq!(self.read_byte(), 0x53, "version mismatch!");
113 assert_eq!(self.read_byte(), 0, "format mismatch!");
114 assert_eq!(
115 self.read_bytes(6),
116 [0x19, 0x93, 0x0d, 0x0a, 0x1a, 0x0a],
117 "corrupted!"
118 );
119 assert_eq!(self.read_byte(), 4, "int size mismatch!");
120 assert_eq!(self.read_byte(), 8, "size_t size mismatch!");
121 assert_eq!(self.read_byte(), 4, "instruction size mismatch!");
122 assert_eq!(self.read_byte(), 8, "lua_Integer size mismatch!");
123 assert_eq!(self.read_byte(), 8, "lua_Number size mismatch!");
124 assert_eq!(self.read_lua_integer(), 0x5678, "endianness mismatch!");
125 assert_eq!(self.read_lua_number(), 370.5, "float format mismatch!");
126 }
127}
128
129impl Reader {
130 pub fn read_proto(&mut self, parent_source: Option<String>) -> Rc<Prototype> {
131 let s = self.read_string();
132 let source = if s.len() > 0 { Some(s) } else { parent_source };
133
134 Rc::new(Prototype {
135 source: source.clone(),
136 line_defined: self.read_u32(),
137 last_line_defined: self.read_u32(),
138 num_params: self.read_byte(),
139 is_vararg: self.read_byte(),
140 max_stack_size: self.read_byte(),
141 code: self.read_vec(|r| r.read_u32().into()),
142 constants: self.read_vec(|r| r.read_constant()),
143 upvalues: self.read_vec(|r| r.read_upvalue()),
144 protos: self.read_vec(|r| r.read_proto(source.clone())),
145 line_info: self.read_vec(|r| r.read_u32()),
146 loc_vars: self.read_vec(|r| r.read_loc_var()),
147 upvalue_names: self.read_vec(|r| r.read_string()),
148 })
149 }
150
151 fn read_constant(&mut self) -> Constant {
152 let tag = self.read_byte();
153 match tag {
154 0 => Constant::Nil,
155 1 => Constant::Boolean(self.read_byte() != 0),
156 3 => Constant::Number(self.read_lua_number()),
157 4 => Constant::Str(self.read_string()),
158 19 => Constant::Integer(self.read_lua_integer()),
159 20 => Constant::Str(self.read_string()),
160 _ => panic!("error"),
161 }
162 }
163
164 fn read_upvalue(&mut self) -> Upvalue {
165 Upvalue {
166 in_stack: self.read_byte(),
167 idx: self.read_byte(),
168 }
169 }
170
171 fn read_loc_var(&mut self) -> LocVar {
172 LocVar {
173 var_name: self.read_string(),
174 start_pc: self.read_u32(),
175 end_pc: self.read_u32(),
176 }
177 }
178}