neige_undump/binary/
reader.rs

1#[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}