amf/amf0/
decode.rs

1use super::marker;
2use super::Value;
3use crate::amf3;
4use crate::error::DecodeError;
5use crate::{DecodeResult, Pair};
6use byteorder::{BigEndian, ReadBytesExt};
7use std::io;
8use std::time;
9
10/// AMF0 decoder.
11#[derive(Debug)]
12pub struct Decoder<R> {
13    inner: R,
14    complexes: Vec<Value>,
15}
16impl<R> Decoder<R> {
17    /// Unwraps this `Decoder`, returning the underlying reader.
18    pub fn into_inner(self) -> R {
19        self.inner
20    }
21
22    /// Get the reference to the underlying reader.
23    pub fn inner(&self) -> &R {
24        &self.inner
25    }
26
27    /// Get the mutable reference to the underlying reader.
28    pub fn inner_mut(&mut self) -> &mut R {
29        &mut self.inner
30    }
31}
32impl<R> Decoder<R>
33where
34    R: io::Read,
35{
36    /// Makes a new instance.
37    pub fn new(inner: R) -> Self {
38        Decoder {
39            inner,
40            complexes: Vec::new(),
41        }
42    }
43
44    /// Decodes a AMF0 value.
45    pub fn decode(&mut self) -> DecodeResult<Value> {
46        self.decode_value()
47    }
48
49    /// Clear the reference table of this decoder.
50    ///
51    /// > Note that object reference indices are local to each message body.
52    /// > Serializers and deserializers must reset reference indices to 0 each time a new message is processed.
53    /// >
54    /// > [AMF 0 Specification: 4.1.3 AMF Message](http://download.macromedia.com/pub/labs/amf/amf0_spec_121207.pdf)
55    pub fn clear_reference_table(&mut self) {
56        self.complexes.clear();
57    }
58
59    fn decode_value(&mut self) -> DecodeResult<Value> {
60        let marker = self.inner.read_u8()?;
61        match marker {
62            marker::NUMBER => self.decode_number(),
63            marker::BOOLEAN => self.decode_boolean(),
64            marker::STRING => self.decode_string(),
65            marker::OBJECT => self.decode_object(),
66            marker::MOVIECLIP => Err(DecodeError::Unsupported { marker }),
67            marker::NULL => Ok(Value::Null),
68            marker::UNDEFINED => Ok(Value::Undefined),
69            marker::REFERENCE => self.decode_reference(),
70            marker::ECMA_ARRAY => self.decode_ecma_array(),
71            marker::OBJECT_END_MARKER => Err(DecodeError::UnexpectedObjectEnd),
72            marker::STRICT_ARRAY => self.decode_strict_array(),
73            marker::DATE => self.decode_date(),
74            marker::LONG_STRING => self.decode_long_string(),
75            marker::UNSUPPORTED => Err(DecodeError::Unsupported { marker }),
76            marker::RECORDSET => Err(DecodeError::Unsupported { marker }),
77            marker::XML_DOCUMENT => self.decode_xml_document(),
78            marker::TYPED_OBJECT => self.decode_typed_object(),
79            marker::AVMPLUS_OBJECT => self.decode_avmplus(),
80            _ => Err(DecodeError::Unknown { marker }),
81        }
82    }
83    fn decode_number(&mut self) -> DecodeResult<Value> {
84        let n = self.inner.read_f64::<BigEndian>()?;
85        Ok(Value::Number(n))
86    }
87    fn decode_boolean(&mut self) -> DecodeResult<Value> {
88        let b = self.inner.read_u8()? != 0;
89        Ok(Value::Boolean(b))
90    }
91    fn decode_string(&mut self) -> DecodeResult<Value> {
92        let len = self.inner.read_u16::<BigEndian>()? as usize;
93        self.read_utf8(len).map(Value::String)
94    }
95    fn decode_object(&mut self) -> DecodeResult<Value> {
96        self.decode_complex_type(|this| {
97            let entries = this.decode_pairs()?;
98            Ok(Value::Object {
99                class_name: None,
100                entries,
101            })
102        })
103    }
104    fn decode_reference(&mut self) -> DecodeResult<Value> {
105        let index = self.inner.read_u16::<BigEndian>()? as usize;
106        self.complexes
107            .get(index)
108            .ok_or(DecodeError::OutOfRangeReference { index })
109            .and_then(|v| {
110                if *v == Value::Null {
111                    Err(DecodeError::CircularReference { index })
112                } else {
113                    Ok(v.clone())
114                }
115            })
116    }
117    fn decode_ecma_array(&mut self) -> DecodeResult<Value> {
118        self.decode_complex_type(|this| {
119            let _count = this.inner.read_u32::<BigEndian>()? as usize;
120            let entries = this.decode_pairs()?;
121            Ok(Value::EcmaArray { entries })
122        })
123    }
124    fn decode_strict_array(&mut self) -> DecodeResult<Value> {
125        self.decode_complex_type(|this| {
126            let count = this.inner.read_u32::<BigEndian>()? as usize;
127            let entries = (0..count)
128                .map(|_| this.decode_value())
129                .collect::<DecodeResult<_>>()?;
130            Ok(Value::Array { entries })
131        })
132    }
133    fn decode_date(&mut self) -> DecodeResult<Value> {
134        let millis = self.inner.read_f64::<BigEndian>()?;
135        let time_zone = self.inner.read_i16::<BigEndian>()?;
136        if !(millis.is_finite() && millis.is_sign_positive()) {
137            Err(DecodeError::InvalidDate { millis })
138        } else {
139            Ok(Value::Date {
140                unix_time: time::Duration::from_millis(millis as u64),
141                time_zone,
142            })
143        }
144    }
145    fn decode_long_string(&mut self) -> DecodeResult<Value> {
146        let len = self.inner.read_u32::<BigEndian>()? as usize;
147        self.read_utf8(len).map(Value::String)
148    }
149    fn decode_xml_document(&mut self) -> DecodeResult<Value> {
150        let len = self.inner.read_u32::<BigEndian>()? as usize;
151        self.read_utf8(len).map(Value::XmlDocument)
152    }
153    fn decode_typed_object(&mut self) -> DecodeResult<Value> {
154        self.decode_complex_type(|this| {
155            let len = this.inner.read_u16::<BigEndian>()? as usize;
156            let class_name = this.read_utf8(len)?;
157            let entries = this.decode_pairs()?;
158            Ok(Value::Object {
159                class_name: Some(class_name),
160                entries,
161            })
162        })
163    }
164    fn decode_avmplus(&mut self) -> DecodeResult<Value> {
165        let value = amf3::Decoder::new(&mut self.inner).decode()?;
166        Ok(Value::AvmPlus(value))
167    }
168
169    fn read_utf8(&mut self, len: usize) -> DecodeResult<String> {
170        let mut buf = vec![0; len];
171        self.inner.read_exact(&mut buf)?;
172        let utf8 = String::from_utf8(buf)?;
173        Ok(utf8)
174    }
175    fn decode_pairs(&mut self) -> DecodeResult<Vec<Pair<String, Value>>> {
176        let mut entries = Vec::new();
177        loop {
178            let len = self.inner.read_u16::<BigEndian>()? as usize;
179            let key = self.read_utf8(len)?;
180            match self.decode_value() {
181                Ok(value) => {
182                    entries.push(Pair { key, value });
183                }
184                Err(DecodeError::UnexpectedObjectEnd) if key.is_empty() => break,
185                Err(e) => return Err(e),
186            }
187        }
188        Ok(entries)
189    }
190    fn decode_complex_type<F>(&mut self, f: F) -> DecodeResult<Value>
191    where
192        F: FnOnce(&mut Self) -> DecodeResult<Value>,
193    {
194        let index = self.complexes.len();
195        self.complexes.push(Value::Null);
196        let value = f(self)?;
197        self.complexes[index] = value.clone();
198        Ok(value)
199    }
200}
201
202#[cfg(test)]
203mod tests {
204    #![allow(clippy::approx_constant)]
205    use super::super::marker;
206    use super::super::Value;
207    use crate::amf3;
208    use crate::error::DecodeError;
209    use crate::Pair;
210    use std::f64;
211    use std::io;
212    use std::iter;
213    use std::time;
214
215    macro_rules! decode {
216        ($file:expr) => {{
217            let input = include_bytes!(concat!("../testdata/", $file));
218            Value::read_from(&mut &input[..])
219        }};
220    }
221    macro_rules! decode_eq {
222        ($file:expr, $expected: expr) => {{
223            let value = decode!($file).unwrap();
224            assert_eq!(value, $expected)
225        }};
226    }
227    macro_rules! decode_unexpected_eof {
228        ($file:expr) => {{
229            let result = decode!($file);
230            match result {
231                Err(DecodeError::Io(e)) => assert_eq!(e.kind(), io::ErrorKind::UnexpectedEof),
232                _ => assert!(false),
233            }
234        }};
235    }
236
237    #[test]
238    fn decodes_boolean() {
239        decode_eq!("amf0-boolean-true.bin", Value::Boolean(true));
240        decode_eq!("amf0-boolean-false.bin", Value::Boolean(false));
241        decode_unexpected_eof!("amf0-boolean-partial.bin");
242    }
243    #[test]
244    fn decodes_null() {
245        decode_eq!("amf0-null.bin", Value::Null);
246    }
247    #[test]
248    fn decodes_undefined() {
249        decode_eq!("amf0-undefined.bin", Value::Undefined);
250    }
251    #[test]
252    fn decodes_number() {
253        decode_eq!("amf0-number.bin", Value::Number(3.5));
254        decode_eq!(
255            "amf0-number-positive-infinity.bin",
256            Value::Number(f64::INFINITY)
257        );
258        decode_eq!(
259            "amf0-number-negative-infinity.bin",
260            Value::Number(f64::NEG_INFINITY)
261        );
262
263        let is_nan = |v| {
264            if let Value::Number(n) = v {
265                n.is_nan()
266            } else {
267                false
268            }
269        };
270        assert!(is_nan(decode!("amf0-number-quiet-nan.bin").unwrap()));
271        assert!(is_nan(decode!("amf0-number-signaling-nan.bin").unwrap()));
272
273        decode_unexpected_eof!("amf0-number-partial.bin");
274    }
275    #[test]
276    fn decodes_string() {
277        decode_eq!(
278            "amf0-string.bin",
279            Value::String("this is a テスト".to_string())
280        );
281        decode_eq!(
282            "amf0-complex-encoded-string.bin",
283            obj(
284                None,
285                &[
286                    ("utf", s("UTF テスト")),
287                    ("zed", n(5.0)),
288                    ("shift", s("Shift テスト"))
289                ][..]
290            )
291        );
292        decode_unexpected_eof!("amf0-string-partial.bin");
293    }
294    #[test]
295    fn decodes_long_string() {
296        decode_eq!(
297            "amf0-long-string.bin",
298            Value::String(iter::repeat('a').take(0x10013).collect())
299        );
300        decode_unexpected_eof!("amf0-long-string-partial.bin");
301    }
302    #[test]
303    fn decodes_xml_document() {
304        decode_eq!(
305            "amf0-xml-doc.bin",
306            Value::XmlDocument("<parent><child prop=\"test\" /></parent>".to_string())
307        );
308        decode_unexpected_eof!("amf0-xml-document-partial.bin");
309    }
310    #[test]
311    fn decodes_object() {
312        decode_eq!(
313            "amf0-object.bin",
314            obj(
315                None,
316                &[("", s("")), ("foo", s("baz")), ("bar", n(3.14))][..]
317            )
318        );
319        decode_eq!(
320            "amf0-untyped-object.bin",
321            obj(None, &[("foo", s("bar")), ("baz", Value::Null)][..])
322        );
323        assert_eq!(
324            decode!("amf0-bad-object-end.bin"),
325            Err(DecodeError::UnexpectedObjectEnd)
326        );
327        decode_unexpected_eof!("amf0-object-partial.bin");
328    }
329    #[test]
330    fn decodes_typed_object() {
331        decode_eq!(
332            "amf0-typed-object.bin",
333            obj(
334                Some("org.amf.ASClass"),
335                &[("foo", s("bar")), ("baz", Value::Null)]
336            )
337        );
338        decode_unexpected_eof!("amf0-typed-object-partial.bin");
339    }
340    #[test]
341    fn decodes_unsupported() {
342        assert_eq!(
343            decode!("amf0-movieclip.bin"),
344            Err(DecodeError::Unsupported {
345                marker: marker::MOVIECLIP
346            })
347        );
348        assert_eq!(
349            decode!("amf0-recordset.bin"),
350            Err(DecodeError::Unsupported {
351                marker: marker::RECORDSET
352            })
353        );
354        assert_eq!(
355            decode!("amf0-unsupported.bin"),
356            Err(DecodeError::Unsupported {
357                marker: marker::UNSUPPORTED
358            })
359        );
360    }
361    #[test]
362    fn decodes_ecma_array() {
363        let entries = es(&[("0", s("a")), ("1", s("b")), ("2", s("c")), ("3", s("d"))][..]);
364        decode_eq!(
365            "amf0-ecma-ordinal-array.bin",
366            Value::EcmaArray { entries: entries }
367        );
368        decode_unexpected_eof!("amf0-ecma-array-partial.bin");
369
370        let entries = es(&[("c", s("d")), ("a", s("b"))][..]);
371        decode_eq!("amf0-hash.bin", Value::EcmaArray { entries: entries });
372    }
373    #[test]
374    fn decodes_strict_array() {
375        decode_eq!(
376            "amf0-strict-array.bin",
377            Value::Array {
378                entries: vec![n(1.0), s("2"), n(3.0)]
379            }
380        );
381        decode_unexpected_eof!("amf0-strict-array-partial.bin");
382    }
383    #[test]
384    fn decodes_reference() {
385        let object = obj(None, &[("foo", s("baz")), ("bar", n(3.14))][..]);
386        let expected = obj(None, &[("0", object.clone()), ("1", object)][..]);
387        decode_eq!("amf0-ref-test.bin", expected);
388        decode_unexpected_eof!("amf0-reference-partial.bin");
389
390        assert_eq!(
391            decode!("amf0-bad-reference.bin"),
392            Err(DecodeError::OutOfRangeReference { index: 0 })
393        );
394        assert_eq!(
395            decode!("amf0-circular-reference.bin"),
396            Err(DecodeError::CircularReference { index: 0 })
397        );
398    }
399    #[test]
400    fn decodes_date() {
401        decode_eq!(
402            "amf0-date.bin",
403            Value::Date {
404                unix_time: time::Duration::from_millis(1_590_796_800_000),
405                time_zone: 0
406            }
407        );
408        decode_eq!(
409            "amf0-time.bin",
410            Value::Date {
411                unix_time: time::Duration::from_millis(1_045_112_400_000),
412                time_zone: 0
413            }
414        );
415        decode_unexpected_eof!("amf0-date-partial.bin");
416        assert_eq!(
417            decode!("amf0-date-minus.bin"),
418            Err(DecodeError::InvalidDate { millis: -1.0 })
419        );
420        assert_eq!(
421            decode!("amf0-date-invalid.bin"),
422            Err(DecodeError::InvalidDate {
423                millis: f64::INFINITY
424            })
425        );
426    }
427    #[test]
428    fn decodes_avmplus() {
429        let expected = amf3::Value::Array {
430            assoc_entries: vec![],
431            dense_entries: (1..4).map(amf3::Value::Integer).collect(),
432        };
433        decode_eq!("amf0-avmplus-object.bin", Value::AvmPlus(expected));
434    }
435    #[test]
436    fn other_errors() {
437        decode_unexpected_eof!("amf0-empty.bin");
438        assert_eq!(
439            decode!("amf0-unknown-marker.bin"),
440            Err(DecodeError::Unknown { marker: 97 })
441        );
442    }
443
444    fn s(s: &str) -> Value {
445        Value::String(s.to_string())
446    }
447    fn n(n: f64) -> Value {
448        Value::Number(n)
449    }
450    fn obj(name: Option<&str>, entries: &[(&str, Value)]) -> Value {
451        Value::Object {
452            class_name: name.map(|s| s.to_string()),
453            entries: es(entries),
454        }
455    }
456    fn es(entries: &[(&str, Value)]) -> Vec<Pair<String, Value>> {
457        entries
458            .iter()
459            .map(|e| Pair {
460                key: e.0.to_string(),
461                value: e.1.clone(),
462            })
463            .collect()
464    }
465}