scuffle_amf0/
decoder.rs

1//! AMF0 decoder
2
3use std::io;
4
5use byteorder::{BigEndian, ReadBytesExt};
6use num_traits::FromPrimitive;
7use scuffle_bytes_util::StringCow;
8use scuffle_bytes_util::zero_copy::ZeroCopyReader;
9
10use crate::{Amf0Array, Amf0Error, Amf0Marker, Amf0Object, Amf0Value};
11
12/// AMF0 decoder.
13///
14/// Provides various functions to decode different types of AMF0 values.
15#[derive(Debug, Clone)]
16pub struct Amf0Decoder<R> {
17    pub(crate) reader: R,
18    pub(crate) next_marker: Option<Amf0Marker>,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub(crate) enum ObjectHeader<'a> {
23    Object,
24    TypedObject {
25        name: StringCow<'a>,
26    },
27    EcmaArray {
28        size: u32,
29    },
30}
31
32impl<B> Amf0Decoder<scuffle_bytes_util::zero_copy::BytesBuf<B>>
33where
34    B: bytes::Buf,
35{
36    /// Create a new deserializer from a buffer implementing [`bytes::Buf`].
37    pub fn from_buf(buf: B) -> Self {
38        Self {
39            reader: buf.into(),
40            next_marker: None,
41        }
42    }
43}
44
45impl<R> Amf0Decoder<scuffle_bytes_util::zero_copy::IoRead<R>>
46where
47    R: std::io::Read,
48{
49    /// Create a new deserializer from a reader implementing [`std::io::Read`].
50    pub fn from_reader(reader: R) -> Self {
51        Self {
52            reader: reader.into(),
53            next_marker: None,
54        }
55    }
56}
57
58impl<'a> Amf0Decoder<scuffle_bytes_util::zero_copy::Slice<'a>> {
59    /// Create a new deserializer from a byte slice.
60    pub fn from_slice(slice: &'a [u8]) -> Amf0Decoder<scuffle_bytes_util::zero_copy::Slice<'a>> {
61        Self {
62            reader: slice.into(),
63            next_marker: None,
64        }
65    }
66}
67
68impl<'a, R> Amf0Decoder<R>
69where
70    R: ZeroCopyReader<'a>,
71{
72    /// Decode a [`Amf0Value`] from the buffer.
73    pub fn decode_value(&mut self) -> Result<Amf0Value<'a>, Amf0Error> {
74        let marker = self.peek_marker()?;
75
76        match marker {
77            Amf0Marker::Boolean => self.decode_boolean().map(Into::into),
78            Amf0Marker::Number | Amf0Marker::Date => self.decode_number().map(Into::into),
79            Amf0Marker::String | Amf0Marker::LongString | Amf0Marker::XmlDocument => self.decode_string().map(Into::into),
80            Amf0Marker::Null | Amf0Marker::Undefined => self.decode_null().map(|_| Amf0Value::Null),
81            Amf0Marker::Object | Amf0Marker::TypedObject | Amf0Marker::EcmaArray => self.decode_object().map(Into::into),
82            Amf0Marker::StrictArray => self.decode_strict_array().map(Into::into),
83            _ => Err(Amf0Error::UnsupportedMarker(marker)),
84        }
85    }
86
87    /// Decode all values from the buffer until the end.
88    pub fn decode_all(&mut self) -> Result<Vec<Amf0Value<'a>>, Amf0Error> {
89        let mut values = Vec::new();
90
91        while self.has_remaining()? {
92            values.push(self.decode_value()?);
93        }
94
95        Ok(values)
96    }
97
98    /// Convert the decoder into an iterator over the values in the buffer.
99    pub fn stream(&mut self) -> Amf0DecoderStream<'_, 'a, R> {
100        Amf0DecoderStream {
101            decoder: self,
102            _marker: std::marker::PhantomData,
103        }
104    }
105
106    /// Check if there are any values left in the buffer.
107    pub fn has_remaining(&mut self) -> Result<bool, Amf0Error> {
108        match self.peek_marker() {
109            Ok(_) => Ok(true),
110            Err(Amf0Error::Io(e)) if e.kind() == io::ErrorKind::UnexpectedEof => Ok(false),
111            Err(err) => Err(err),
112        }
113    }
114
115    /// Peek the next marker in the buffer without consuming it.
116    pub fn peek_marker(&mut self) -> Result<Amf0Marker, Amf0Error> {
117        let marker = self.read_marker()?;
118        // Buffer the marker for the next read
119        self.next_marker = Some(marker);
120
121        Ok(marker)
122    }
123
124    fn read_marker(&mut self) -> Result<Amf0Marker, Amf0Error> {
125        if let Some(marker) = self.next_marker.take() {
126            return Ok(marker);
127        }
128
129        let marker = self.reader.as_std().read_u8()?;
130        let marker = Amf0Marker::from_u8(marker).ok_or(Amf0Error::UnknownMarker(marker))?;
131        Ok(marker)
132    }
133
134    fn expect_marker(&mut self, expect: &'static [Amf0Marker]) -> Result<Amf0Marker, Amf0Error> {
135        let marker = self.read_marker()?;
136
137        if !expect.contains(&marker) {
138            Err(Amf0Error::UnexpectedType {
139                expected: expect,
140                got: marker,
141            })
142        } else {
143            Ok(marker)
144        }
145    }
146
147    /// Decode a number from the buffer.
148    pub fn decode_number(&mut self) -> Result<f64, Amf0Error> {
149        let marker = self.expect_marker(&[Amf0Marker::Number, Amf0Marker::Date])?;
150
151        let number = self.reader.as_std().read_f64::<BigEndian>()?;
152
153        if marker == Amf0Marker::Date {
154            // Skip the timezone
155            self.reader.as_std().read_i16::<BigEndian>()?;
156        }
157
158        Ok(number)
159    }
160
161    /// Decode a boolean from the buffer.
162    pub fn decode_boolean(&mut self) -> Result<bool, Amf0Error> {
163        self.expect_marker(&[Amf0Marker::Boolean])?;
164        let value = self.reader.as_std().read_u8()?;
165        Ok(value != 0)
166    }
167
168    pub(crate) fn decode_normal_string(&mut self) -> Result<StringCow<'a>, Amf0Error> {
169        let len = self.reader.as_std().read_u16::<BigEndian>()? as usize;
170
171        let bytes = self.reader.try_read(len)?;
172        Ok(StringCow::from_bytes(bytes.into_bytes().try_into()?))
173    }
174
175    /// Decode a string from the buffer.
176    ///
177    /// This function can decode both normal strings and long strings.
178    pub fn decode_string(&mut self) -> Result<StringCow<'a>, Amf0Error> {
179        let marker = self.expect_marker(&[Amf0Marker::String, Amf0Marker::LongString, Amf0Marker::XmlDocument])?;
180
181        let len = if marker == Amf0Marker::String {
182            self.reader.as_std().read_u16::<BigEndian>()? as usize
183        } else {
184            // LongString or XmlDocument
185            self.reader.as_std().read_u32::<BigEndian>()? as usize
186        };
187
188        let bytes = self.reader.try_read(len)?;
189        Ok(StringCow::from_bytes(bytes.into_bytes().try_into()?))
190    }
191
192    /// Decode a null value from the buffer.
193    ///
194    /// This function can also decode undefined values.
195    pub fn decode_null(&mut self) -> Result<(), Amf0Error> {
196        self.expect_marker(&[Amf0Marker::Null, Amf0Marker::Undefined])?;
197        Ok(())
198    }
199
200    /// Deserialize a value from the buffer using [serde].
201    #[cfg(feature = "serde")]
202    pub fn deserialize<T>(&mut self) -> Result<T, Amf0Error>
203    where
204        T: serde::de::Deserialize<'a>,
205    {
206        T::deserialize(self)
207    }
208
209    /// Deserialize a stream of values from the buffer using [serde].
210    #[cfg(feature = "serde")]
211    pub fn deserialize_stream<T>(&mut self) -> crate::de::Amf0DeserializerStream<'_, R, T>
212    where
213        T: serde::de::Deserialize<'a>,
214    {
215        crate::de::Amf0DeserializerStream::new(self)
216    }
217
218    // --- Object and Ecma array ---
219
220    pub(crate) fn decode_object_header(&mut self) -> Result<ObjectHeader<'a>, Amf0Error> {
221        let marker = self.expect_marker(&[Amf0Marker::Object, Amf0Marker::TypedObject, Amf0Marker::EcmaArray])?;
222
223        if marker == Amf0Marker::Object {
224            Ok(ObjectHeader::Object)
225        } else if marker == Amf0Marker::TypedObject {
226            let name = self.decode_normal_string()?;
227            Ok(ObjectHeader::TypedObject { name })
228        } else {
229            // EcmaArray
230            let size = self.reader.as_std().read_u32::<BigEndian>()?;
231            Ok(ObjectHeader::EcmaArray { size })
232        }
233    }
234
235    pub(crate) fn decode_object_key(&mut self) -> Result<Option<StringCow<'a>>, Amf0Error> {
236        // Object keys are not preceeded with a marker and are always normal strings
237        let key = self.decode_normal_string()?;
238
239        // The object end marker is preceeded by an empty string
240        if key.as_str().is_empty() {
241            // Check if the next marker is an object end marker
242            if self.peek_marker()? == Amf0Marker::ObjectEnd {
243                // Clear the next marker buffer
244                self.next_marker = None;
245
246                return Ok(None);
247            }
248        }
249
250        Ok(Some(key))
251    }
252
253    /// Decode an object from the buffer.
254    ///
255    /// This function can decode normal objects, typed objects and ECMA arrays.
256    pub fn decode_object(&mut self) -> Result<Amf0Object<'a>, Amf0Error> {
257        let header = self.decode_object_header()?;
258
259        match header {
260            ObjectHeader::Object | ObjectHeader::TypedObject { .. } => {
261                let mut object = Amf0Object::new();
262
263                while let Some(key) = self.decode_object_key()? {
264                    let value = self.decode_value()?;
265                    object.insert(key, value);
266                }
267
268                Ok(object)
269            }
270            ObjectHeader::EcmaArray { size } => {
271                let mut object = Amf0Object::with_capacity(size as usize);
272
273                for _ in 0..size {
274                    // Object keys are not preceeded with a marker and are always normal strings
275                    let key = self.decode_normal_string()?;
276                    let value = self.decode_value()?;
277                    object.insert(key, value);
278                }
279
280                // There might be an object end marker after the last key
281                if self.has_remaining()? && self.peek_marker()? == Amf0Marker::ObjectEnd {
282                    // Clear the next marker buffer
283                    self.next_marker = None;
284                }
285
286                Ok(object)
287            }
288        }
289    }
290
291    // --- Strict array ---
292
293    pub(crate) fn decode_strict_array_header(&mut self) -> Result<u32, Amf0Error> {
294        self.expect_marker(&[Amf0Marker::StrictArray])?;
295        let size = self.reader.as_std().read_u32::<BigEndian>()?;
296
297        Ok(size)
298    }
299
300    /// Decode a strict array from the buffer.
301    pub fn decode_strict_array(&mut self) -> Result<Amf0Array<'a>, Amf0Error> {
302        let size = self.decode_strict_array_header()? as usize;
303
304        let mut array = Vec::with_capacity(size);
305
306        for _ in 0..size {
307            let value = self.decode_value()?;
308            array.push(value);
309        }
310
311        Ok(Amf0Array::from(array))
312    }
313}
314
315/// An iterator over the values in the buffer.
316///
317/// Yields values of type [`Amf0Value`] until the end of the buffer is reached.
318#[must_use = "Iterators are lazy and do nothing unless consumed"]
319pub struct Amf0DecoderStream<'a, 'de, R> {
320    decoder: &'a mut Amf0Decoder<R>,
321    _marker: std::marker::PhantomData<&'de ()>,
322}
323
324impl<'de, R: ZeroCopyReader<'de>> Iterator for Amf0DecoderStream<'_, 'de, R> {
325    type Item = Result<Amf0Value<'de>, Amf0Error>;
326
327    fn next(&mut self) -> Option<Self::Item> {
328        match self.decoder.has_remaining() {
329            Ok(true) => Some(self.decoder.decode_value()),
330            Ok(false) => None,
331            Err(err) => Some(Err(err)),
332        }
333    }
334}
335
336impl<'de, R> std::iter::FusedIterator for Amf0DecoderStream<'_, 'de, R> where R: ZeroCopyReader<'de> {}
337
338#[cfg(test)]
339#[cfg_attr(all(test, coverage_nightly), coverage(off))]
340mod tests {
341    use super::Amf0Decoder;
342    use crate::{Amf0Marker, Amf0Value};
343
344    #[test]
345    fn strict_array() {
346        #[rustfmt::skip]
347        let bytes = [
348            Amf0Marker::StrictArray as u8,
349            0, 0, 0, 2, // size
350            Amf0Marker::String as u8,
351            0, 3, b'v', b'a', b'l', // value
352            Amf0Marker::Boolean as u8,
353            1, // value
354        ];
355
356        let mut decoder = Amf0Decoder::from_slice(&bytes);
357        let array = decoder.decode_strict_array().unwrap();
358        assert_eq!(array.len(), 2);
359        assert_eq!(array[0], Amf0Value::String("val".into()));
360        assert_eq!(array[1], Amf0Value::Boolean(true));
361    }
362
363    #[test]
364    fn ecma_array() {
365        #[rustfmt::skip]
366        let bytes = [
367            Amf0Marker::EcmaArray as u8,
368            0, 0, 0, 2, // size
369            0, 3, b'a', b'b', b'c', // key
370            Amf0Marker::String as u8,
371            0, 3, b'v', b'a', b'l', // value
372            0, 4, b'd', b'e', b'f', b'g', // key
373            Amf0Marker::Boolean as u8,
374            1, // value
375        ];
376
377        let mut decoder = Amf0Decoder::from_slice(&bytes);
378        let object = decoder.decode_object().unwrap();
379        assert_eq!(object.len(), 2);
380        assert_eq!(*object.get(&"abc".into()).unwrap(), Amf0Value::String("val".into()));
381        assert_eq!(*object.get(&"defg".into()).unwrap(), Amf0Value::Boolean(true));
382    }
383
384    #[test]
385    fn decoder_stream() {
386        #[rustfmt::skip]
387        let bytes = [
388            Amf0Marker::Boolean as u8,
389            1, // value
390            Amf0Marker::String as u8,
391            0, 3, b'a', b'b', b'c', // value
392            Amf0Marker::Null as u8,
393        ];
394
395        let mut decoder = Amf0Decoder::from_slice(&bytes);
396        let mut stream = decoder.stream();
397        assert_eq!(stream.next().unwrap().unwrap(), Amf0Value::Boolean(true));
398        assert_eq!(stream.next().unwrap().unwrap(), Amf0Value::String("abc".into()));
399        assert_eq!(stream.next().unwrap().unwrap(), Amf0Value::Null);
400        assert!(stream.next().is_none());
401    }
402}