weakauras_codec_lib_serialize/deserialization/
mod.rs

1// Based on code from LibSerialize
2// https://github.com/rossnichols/LibSerialize
3// Copyright 2020-2021 Ross Nichols
4// Copyright 2020-2025 Velithris
5// SPDX-License-Identifier: MIT
6
7mod reader;
8
9use crate::{
10    EmbeddedTypeTag, FORMAT_VERSION, TypeTag, error::DeserializationError, macros::check_recursion,
11};
12use reader::SliceReader;
13use weakauras_codec_lua_value::{LuaMapKey, LuaValue, Map};
14
15/// A structure for deserializing data produced by LibSerialize.
16///
17/// # Example
18///
19/// ```
20/// use weakauras_codec_lib_serialize::{deserialization::Deserializer, error::DeserializationError};
21///
22/// fn main() -> Result<(), DeserializationError> {
23///     assert_eq!(
24///         Deserializer::from_slice(b"\x01\xd2Hello, world!")
25///             .deserialize_first()?
26///             .unwrap(),
27///         "Hello, world!".into()
28///     );
29///     Ok(())
30/// }
31/// ```
32pub struct Deserializer<'s> {
33    remaining_depth: usize,
34    reader: SliceReader<'s>,
35
36    table_refs: Vec<LuaValue>,
37    string_refs: Vec<String>,
38}
39
40impl<'s> Deserializer<'s> {
41    /// Create a deserializer from a slice of bytes.
42    pub fn from_slice(slice: &'s [u8]) -> Self {
43        Self {
44            remaining_depth: 128,
45            reader: SliceReader::new(slice),
46
47            table_refs: Vec::new(),
48            string_refs: Vec::new(),
49        }
50    }
51
52    /// Deserialize all values.
53    pub fn deserialize_all(mut self) -> Result<Vec<LuaValue>, DeserializationError> {
54        match self.reader.read_u8() {
55            Some(val) if val == FORMAT_VERSION || val == FORMAT_VERSION + 1 => {}
56            _ => return Err(DeserializationError::InvalidPrefix),
57        }
58
59        let mut result = Vec::new();
60
61        while let Some(v) = self.deserialize_helper()? {
62            result.push(v);
63        }
64
65        Ok(result)
66    }
67
68    /// Deserialize the first value.
69    pub fn deserialize_first(mut self) -> Result<Option<LuaValue>, DeserializationError> {
70        match self.reader.read_u8() {
71            Some(val) if val == FORMAT_VERSION || val == FORMAT_VERSION + 1 => {}
72            _ => return Err(DeserializationError::InvalidPrefix),
73        }
74
75        self.deserialize_helper()
76    }
77
78    fn deserialize_helper(&mut self) -> Result<Option<LuaValue>, DeserializationError> {
79        match self.reader.read_u8() {
80            None => Ok(None),
81            Some(value) => {
82                if value & 1 == 1 {
83                    // `NNNN NNN1`: a 7 bit non-negative int
84                    Ok(Some(LuaValue::Number((value >> 1) as f64)))
85                } else if value & 3 == 2 {
86                    // * `CCCC TT10`: a 2 bit type index and 4 bit count (strlen, #tab, etc.)
87                    //     * Followed by the type-dependent payload
88                    let tag = EmbeddedTypeTag::from_u8((value & 0x0F) >> 2)
89                        .ok_or(DeserializationError::InvalidEmbeddedTag)?;
90                    let len = value >> 4;
91
92                    self.deserialize_embedded(tag, len).map(Option::Some)
93                } else if value & 7 == 4 {
94                    // * `NNNN S100`: the lower four bits of a 12 bit int and 1 bit for its sign
95                    //     * Followed by a byte for the upper bits
96                    let next_byte = self
97                        .reader
98                        .read_u8()
99                        .ok_or(DeserializationError::UnexpectedEof)?
100                        as u16;
101                    let packed = (next_byte << 8) + value as u16;
102
103                    Ok(Some(LuaValue::Number(if value & 15 == 12 {
104                        -((packed >> 4) as f64)
105                    } else {
106                        (packed >> 4) as f64
107                    })))
108                } else {
109                    // * `TTTT T000`: a 5 bit type index
110                    //     * Followed by the type-dependent payload, including count(s) if needed
111                    let tag =
112                        TypeTag::from_u8(value >> 3).ok_or(DeserializationError::InvalidTag)?;
113
114                    self.deserialize_one(tag).map(Option::Some)
115                }
116            }
117        }
118    }
119
120    #[inline(always)]
121    fn extract_value(&mut self) -> Result<LuaValue, DeserializationError> {
122        match self.deserialize_helper() {
123            Ok(Some(value)) => Ok(value),
124            Ok(None) => Err(DeserializationError::UnexpectedEof),
125            Err(e) => Err(e),
126        }
127    }
128
129    fn deserialize_embedded(
130        &mut self,
131        tag: EmbeddedTypeTag,
132        len: u8,
133    ) -> Result<LuaValue, DeserializationError> {
134        match tag {
135            EmbeddedTypeTag::Str => self.deserialize_string(len as usize),
136            EmbeddedTypeTag::Map => self.deserialize_map(len as usize),
137            EmbeddedTypeTag::Array => self.deserialize_array(len as usize),
138            // For MIXED, the 4-bit count contains two 2-bit counts that are one less than the true count.
139            EmbeddedTypeTag::Mixed => {
140                self.deserialize_mixed(((len & 3) + 1) as usize, ((len >> 2) + 1) as usize)
141            }
142        }
143    }
144
145    fn deserialize_one(&mut self, tag: TypeTag) -> Result<LuaValue, DeserializationError> {
146        match tag {
147            TypeTag::Null => Ok(LuaValue::Null),
148
149            TypeTag::Int16Pos => self.deserialize_int(2).map(|v| LuaValue::Number(v as f64)),
150            TypeTag::Int16Neg => self
151                .deserialize_int(2)
152                .map(|v| LuaValue::Number(-(v as f64))),
153            TypeTag::Int24Pos => self.deserialize_int(3).map(|v| LuaValue::Number(v as f64)),
154            TypeTag::Int24Neg => self
155                .deserialize_int(3)
156                .map(|v| LuaValue::Number(-(v as f64))),
157            TypeTag::Int32Pos => self.deserialize_int(4).map(|v| LuaValue::Number(v as f64)),
158            TypeTag::Int32Neg => self
159                .deserialize_int(4)
160                .map(|v| LuaValue::Number(-(v as f64))),
161            TypeTag::Int64Pos => self.deserialize_int(7).map(|v| LuaValue::Number(v as f64)),
162            TypeTag::Int64Neg => self
163                .deserialize_int(7)
164                .map(|v| LuaValue::Number(-(v as f64))),
165
166            TypeTag::Float => self.deserialize_f64().map(LuaValue::Number),
167            TypeTag::FloatStrPos => self.deserialize_f64_from_str().map(LuaValue::Number),
168            TypeTag::FloatStrNeg => self
169                .deserialize_f64_from_str()
170                .map(|v| LuaValue::Number(-v)),
171
172            TypeTag::True => Ok(LuaValue::Boolean(true)),
173            TypeTag::False => Ok(LuaValue::Boolean(false)),
174
175            TypeTag::Str8 => {
176                let len = self
177                    .reader
178                    .read_u8()
179                    .ok_or(DeserializationError::UnexpectedEof)?;
180                self.deserialize_string(len as usize)
181            }
182            TypeTag::Str16 => {
183                let len = self.deserialize_int(2)?;
184                self.deserialize_string(len as usize)
185            }
186            TypeTag::Str24 => {
187                let len = self.deserialize_int(3)?;
188                self.deserialize_string(len as usize)
189            }
190
191            TypeTag::Map8 => {
192                let len = self
193                    .reader
194                    .read_u8()
195                    .ok_or(DeserializationError::UnexpectedEof)?;
196                self.deserialize_map(len as usize)
197            }
198            TypeTag::Map16 => {
199                let len = self.deserialize_int(2)?;
200                self.deserialize_map(len as usize)
201            }
202            TypeTag::Map24 => {
203                let len = self.deserialize_int(3)?;
204                self.deserialize_map(len as usize)
205            }
206
207            TypeTag::Array8 => {
208                let len = self
209                    .reader
210                    .read_u8()
211                    .ok_or(DeserializationError::UnexpectedEof)?;
212                self.deserialize_array(len as usize)
213            }
214            TypeTag::Array16 => {
215                let len = self.deserialize_int(2)?;
216                self.deserialize_array(len as usize)
217            }
218            TypeTag::Array24 => {
219                let len = self.deserialize_int(3)?;
220                self.deserialize_array(len as usize)
221            }
222
223            TypeTag::Mixed8 => {
224                let array_len = self
225                    .reader
226                    .read_u8()
227                    .ok_or(DeserializationError::UnexpectedEof)?;
228                let map_len = self
229                    .reader
230                    .read_u8()
231                    .ok_or(DeserializationError::UnexpectedEof)?;
232
233                self.deserialize_mixed(array_len as usize, map_len as usize)
234            }
235            TypeTag::Mixed16 => {
236                let array_len = self.deserialize_int(2)?;
237                let map_len = self.deserialize_int(2)?;
238
239                self.deserialize_mixed(array_len as usize, map_len as usize)
240            }
241            TypeTag::Mixed24 => {
242                let array_len = self.deserialize_int(3)?;
243                let map_len = self.deserialize_int(3)?;
244
245                self.deserialize_mixed(array_len as usize, map_len as usize)
246            }
247
248            TypeTag::StrRef8 => {
249                let index = self
250                    .reader
251                    .read_u8()
252                    .ok_or(DeserializationError::UnexpectedEof)?
253                    .checked_sub(1)
254                    .ok_or(DeserializationError::InvalidStringReference)?;
255                match self.string_refs.get(index as usize) {
256                    None => Err(DeserializationError::InvalidStringReference),
257                    Some(s) => Ok(LuaValue::String(s.clone())),
258                }
259            }
260            TypeTag::StrRef16 => {
261                let index = self
262                    .deserialize_int(2)?
263                    .checked_sub(1)
264                    .ok_or(DeserializationError::InvalidStringReference)?;
265                match self.string_refs.get(index as usize) {
266                    None => Err(DeserializationError::InvalidStringReference),
267                    Some(s) => Ok(LuaValue::String(s.clone())),
268                }
269            }
270            TypeTag::StrRef24 => {
271                let index = self
272                    .deserialize_int(3)?
273                    .checked_sub(1)
274                    .ok_or(DeserializationError::InvalidStringReference)?;
275                match self.string_refs.get(index as usize) {
276                    None => Err(DeserializationError::InvalidStringReference),
277                    Some(s) => Ok(LuaValue::String(s.clone())),
278                }
279            }
280
281            TypeTag::MapRef8 => {
282                let index = self
283                    .reader
284                    .read_u8()
285                    .ok_or(DeserializationError::UnexpectedEof)?
286                    .checked_sub(1)
287                    .ok_or(DeserializationError::InvalidMapReference)?;
288                match self.table_refs.get(index as usize) {
289                    None => Err(DeserializationError::InvalidMapReference),
290                    Some(v) => Ok(v.clone()),
291                }
292            }
293            TypeTag::MapRef16 => {
294                let index = self
295                    .deserialize_int(2)?
296                    .checked_sub(1)
297                    .ok_or(DeserializationError::InvalidMapReference)?;
298                match self.table_refs.get(index as usize) {
299                    None => Err(DeserializationError::InvalidMapReference),
300                    Some(v) => Ok(v.clone()),
301                }
302            }
303            TypeTag::MapRef24 => {
304                let index = self
305                    .deserialize_int(3)?
306                    .checked_sub(1)
307                    .ok_or(DeserializationError::InvalidMapReference)?;
308                match self.table_refs.get(index as usize) {
309                    None => Err(DeserializationError::InvalidMapReference),
310                    Some(v) => Ok(v.clone()),
311                }
312            }
313        }
314    }
315
316    fn deserialize_string(&mut self, len: usize) -> Result<LuaValue, DeserializationError> {
317        match self.reader.read_string(len) {
318            None => Err(DeserializationError::UnexpectedEof),
319            Some(s) => {
320                let s = s.into_owned();
321                if len > 2 {
322                    self.string_refs.push(s.clone());
323                }
324
325                Ok(LuaValue::String(s))
326            }
327        }
328    }
329
330    fn deserialize_f64(&mut self) -> Result<f64, DeserializationError> {
331        match self.reader.read_f64() {
332            None => Err(DeserializationError::UnexpectedEof),
333            Some(v) => Ok(v),
334        }
335    }
336
337    fn deserialize_f64_from_str(&mut self) -> Result<f64, DeserializationError> {
338        let len = self
339            .reader
340            .read_u8()
341            .ok_or(DeserializationError::UnexpectedEof)?;
342
343        match self.reader.read_bytes(len as usize) {
344            None => Err(DeserializationError::UnexpectedEof),
345            Some(bytes) => core::str::from_utf8(bytes)
346                .ok()
347                .and_then(|s| s.parse::<f64>().ok())
348                .ok_or(DeserializationError::InvalidFloatNumber),
349        }
350    }
351
352    fn deserialize_int(&mut self, bytes: usize) -> Result<u64, DeserializationError> {
353        match self.reader.read_int(bytes) {
354            None => Err(DeserializationError::UnexpectedEof),
355            Some(v) => Ok(v),
356        }
357    }
358
359    fn deserialize_map(&mut self, len: usize) -> Result<LuaValue, DeserializationError> {
360        let mut m = Map::new();
361
362        for _ in 0..len {
363            check_recursion!(self, DeserializationError, {
364                let (key, value) = (self.extract_value()?, self.extract_value()?);
365
366                m.insert(LuaMapKey::try_from(key)?, value);
367            });
368        }
369
370        let m = LuaValue::Map(m);
371        self.table_refs.push(m.clone());
372        Ok(m)
373    }
374
375    fn deserialize_array(&mut self, len: usize) -> Result<LuaValue, DeserializationError> {
376        let mut v = Vec::new();
377
378        for _ in 0..len {
379            check_recursion!(self, DeserializationError, {
380                v.push(self.extract_value()?);
381            });
382        }
383
384        let v = LuaValue::Array(v);
385        self.table_refs.push(v.clone());
386        Ok(v)
387    }
388
389    fn deserialize_mixed(
390        &mut self,
391        array_len: usize,
392        map_len: usize,
393    ) -> Result<LuaValue, DeserializationError> {
394        let mut m = Map::new();
395
396        for i in 1..=array_len {
397            check_recursion!(self, DeserializationError, {
398                let el = self.extract_value()?;
399                m.insert(LuaMapKey::try_from(LuaValue::Number(i as f64)).unwrap(), el);
400            });
401        }
402
403        for _ in 0..map_len {
404            check_recursion!(self, DeserializationError, {
405                let (key, value) = (self.extract_value()?, self.extract_value()?);
406
407                m.insert(LuaMapKey::try_from(key)?, value);
408            });
409        }
410
411        let m = LuaValue::Map(m);
412        self.table_refs.push(m.clone());
413        Ok(m)
414    }
415}