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#[derive(Debug)]
12pub struct Decoder<R> {
13 inner: R,
14 complexes: Vec<Value>,
15}
16impl<R> Decoder<R> {
17 pub fn into_inner(self) -> R {
19 self.inner
20 }
21
22 pub fn inner(&self) -> &R {
24 &self.inner
25 }
26
27 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 pub fn new(inner: R) -> Self {
38 Decoder {
39 inner,
40 complexes: Vec::new(),
41 }
42 }
43
44 pub fn decode(&mut self) -> DecodeResult<Value> {
46 self.decode_value()
47 }
48
49 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}