amf/amf3/
encode.rs

1use super::marker;
2use super::Value;
3use crate::Pair;
4use byteorder::{BigEndian, WriteBytesExt};
5use std::io;
6use std::time;
7
8/// AMF3 encoder.
9#[derive(Debug)]
10pub struct Encoder<W> {
11    inner: W,
12}
13impl<W> Encoder<W> {
14    /// Unwraps this `Encoder`, returning the underlying writer.
15    pub fn into_inner(self) -> W {
16        self.inner
17    }
18    /// Returns an immutable reference to the underlying writer.
19    pub fn inner(&self) -> &W {
20        &self.inner
21    }
22    /// Returns a mutable reference to the underlying writer.
23    pub fn inner_mut(&mut self) -> &mut W {
24        &mut self.inner
25    }
26}
27impl<W> Encoder<W>
28where
29    W: io::Write,
30{
31    /// Makes a new instance.
32    pub fn new(inner: W) -> Self {
33        Encoder { inner }
34    }
35
36    /// Encodes a AMF3 value.
37    pub fn encode(&mut self, value: &Value) -> io::Result<()> {
38        match *value {
39            Value::Undefined => self.encode_undefined(),
40            Value::Null => self.encode_null(),
41            Value::Boolean(x) => self.encode_boolean(x),
42            Value::Integer(x) => self.encode_integer(x),
43            Value::Double(x) => self.encode_double(x),
44            Value::String(ref x) => self.encode_string(x),
45            Value::XmlDocument(ref x) => self.encode_xml_document(x),
46            Value::Date { unix_time } => self.encode_date(unix_time),
47            Value::Array {
48                ref assoc_entries,
49                ref dense_entries,
50            } => self.encode_array(assoc_entries, dense_entries),
51            Value::Object {
52                ref class_name,
53                sealed_count,
54                ref entries,
55            } => self.encode_object(class_name, sealed_count, entries),
56            Value::Xml(ref x) => self.encode_xml(x),
57            Value::ByteArray(ref x) => self.encode_byte_array(x),
58            Value::IntVector {
59                is_fixed,
60                ref entries,
61            } => self.encode_int_vector(is_fixed, entries),
62            Value::UintVector {
63                is_fixed,
64                ref entries,
65            } => self.encode_uint_vector(is_fixed, entries),
66            Value::DoubleVector {
67                is_fixed,
68                ref entries,
69            } => self.encode_double_vector(is_fixed, entries),
70            Value::ObjectVector {
71                ref class_name,
72                is_fixed,
73                ref entries,
74            } => self.encode_object_vector(class_name, is_fixed, entries),
75            Value::Dictionary {
76                is_weak,
77                ref entries,
78            } => self.encode_dictionary(is_weak, entries),
79        }
80    }
81
82    fn encode_undefined(&mut self) -> io::Result<()> {
83        self.inner.write_u8(marker::UNDEFINED)?;
84        Ok(())
85    }
86    fn encode_null(&mut self) -> io::Result<()> {
87        self.inner.write_u8(marker::NULL)?;
88        Ok(())
89    }
90    fn encode_boolean(&mut self, b: bool) -> io::Result<()> {
91        if b {
92            self.inner.write_u8(marker::TRUE)?;
93        } else {
94            self.inner.write_u8(marker::FALSE)?;
95        }
96        Ok(())
97    }
98    fn encode_integer(&mut self, i: i32) -> io::Result<()> {
99        self.inner.write_u8(marker::INTEGER)?;
100        let u29 = if i >= 0 {
101            i as u32
102        } else {
103            ((1 << 29) + i) as u32
104        };
105        self.encode_u29(u29)?;
106        Ok(())
107    }
108    fn encode_double(&mut self, d: f64) -> io::Result<()> {
109        self.inner.write_u8(marker::DOUBLE)?;
110        self.inner.write_f64::<BigEndian>(d)?;
111        Ok(())
112    }
113    fn encode_string(&mut self, s: &str) -> io::Result<()> {
114        self.inner.write_u8(marker::STRING)?;
115        self.encode_utf8(s)?;
116        Ok(())
117    }
118    fn encode_xml_document(&mut self, xml: &str) -> io::Result<()> {
119        self.inner.write_u8(marker::XML_DOC)?;
120        self.encode_utf8(xml)?;
121        Ok(())
122    }
123    fn encode_date(&mut self, unix_time: time::Duration) -> io::Result<()> {
124        let millis = unix_time.as_secs() * 1000 + (unix_time.subsec_nanos() as u64) / 1_000_000;
125        self.inner.write_u8(marker::DATE)?;
126        self.encode_size(0)?;
127        self.inner.write_f64::<BigEndian>(millis as f64)?;
128        Ok(())
129    }
130    fn encode_array(&mut self, assoc: &[Pair<String, Value>], dense: &[Value]) -> io::Result<()> {
131        self.inner.write_u8(marker::ARRAY)?;
132        self.encode_size(dense.len())?;
133        self.encode_pairs(assoc)?;
134        dense
135            .iter()
136            .map(|v| self.encode(v))
137            .collect::<io::Result<Vec<_>>>()?;
138        Ok(())
139    }
140    fn encode_object(
141        &mut self,
142        class_name: &Option<String>,
143        sealed_count: usize,
144        entries: &[Pair<String, Value>],
145    ) -> io::Result<()> {
146        self.inner.write_u8(marker::OBJECT)?;
147        self.encode_trait(class_name, sealed_count, entries)?;
148        for e in entries.iter().take(sealed_count) {
149            self.encode(&e.value)?;
150        }
151        if entries.len() > sealed_count {
152            self.encode_pairs(&entries[sealed_count..])?;
153        }
154        Ok(())
155    }
156    fn encode_xml(&mut self, xml: &str) -> io::Result<()> {
157        self.inner.write_u8(marker::XML)?;
158        self.encode_utf8(xml)?;
159        Ok(())
160    }
161    fn encode_byte_array(&mut self, bytes: &[u8]) -> io::Result<()> {
162        self.inner.write_u8(marker::BYTE_ARRAY)?;
163        self.encode_size(bytes.len())?;
164        self.inner.write_all(bytes)?;
165        Ok(())
166    }
167    fn encode_int_vector(&mut self, is_fixed: bool, vec: &[i32]) -> io::Result<()> {
168        self.inner.write_u8(marker::VECTOR_INT)?;
169        self.encode_size(vec.len())?;
170        self.inner.write_u8(is_fixed as u8)?;
171        for &x in vec {
172            self.inner.write_i32::<BigEndian>(x)?;
173        }
174        Ok(())
175    }
176    fn encode_uint_vector(&mut self, is_fixed: bool, vec: &[u32]) -> io::Result<()> {
177        self.inner.write_u8(marker::VECTOR_UINT)?;
178        self.encode_size(vec.len())?;
179        self.inner.write_u8(is_fixed as u8)?;
180        for &x in vec {
181            self.inner.write_u32::<BigEndian>(x)?;
182        }
183        Ok(())
184    }
185    fn encode_double_vector(&mut self, is_fixed: bool, vec: &[f64]) -> io::Result<()> {
186        self.inner.write_u8(marker::VECTOR_DOUBLE)?;
187        self.encode_size(vec.len())?;
188        self.inner.write_u8(is_fixed as u8)?;
189        for &x in vec {
190            self.inner.write_f64::<BigEndian>(x)?;
191        }
192        Ok(())
193    }
194    fn encode_object_vector(
195        &mut self,
196        class_name: &Option<String>,
197        is_fixed: bool,
198        vec: &[Value],
199    ) -> io::Result<()> {
200        self.inner.write_u8(marker::VECTOR_OBJECT)?;
201        self.encode_size(vec.len())?;
202        self.inner.write_u8(is_fixed as u8)?;
203        self.encode_utf8(class_name.as_ref().map_or("*", |s| s))?;
204        for x in vec {
205            self.encode(x)?;
206        }
207        Ok(())
208    }
209    fn encode_dictionary(
210        &mut self,
211        is_weak: bool,
212        entries: &[Pair<Value, Value>],
213    ) -> io::Result<()> {
214        self.inner.write_u8(marker::DICTIONARY)?;
215        self.encode_size(entries.len())?;
216        self.inner.write_u8(is_weak as u8)?;
217        for e in entries {
218            self.encode(&e.key)?;
219            self.encode(&e.value)?;
220        }
221        Ok(())
222    }
223    fn encode_trait(
224        &mut self,
225        class_name: &Option<String>,
226        sealed_count: usize,
227        entries: &[Pair<String, Value>],
228    ) -> io::Result<()> {
229        assert!(sealed_count <= entries.len());
230        let not_reference = 1;
231        let is_externalizable = false as usize;
232        let is_dynamic = (sealed_count < entries.len()) as usize;
233        let u28 =
234            (sealed_count << 3) | (is_dynamic << 2) | (is_externalizable << 1) | not_reference;
235        self.encode_size(u28)?;
236
237        let class_name = class_name.as_ref().map_or("", |s| s);
238        self.encode_utf8(class_name)?;
239        for e in entries.iter().take(sealed_count) {
240            self.encode_utf8(&e.key)?;
241        }
242        Ok(())
243    }
244    fn encode_size(&mut self, size: usize) -> io::Result<()> {
245        assert!(size < (1 << 28));
246        let not_reference = 1;
247        self.encode_u29(((size << 1) | not_reference) as u32)
248    }
249    #[allow(clippy::zero_prefixed_literal, clippy::identity_op)]
250    fn encode_u29(&mut self, u29: u32) -> io::Result<()> {
251        if u29 < 0x80 {
252            self.inner.write_u8(u29 as u8)?;
253        } else if u29 < 0x4000 {
254            let b1 = ((u29 >> 0) & 0b0111_1111) as u8;
255            let b2 = ((u29 >> 7) | 0b1000_0000) as u8;
256            for b in &[b2, b1] {
257                self.inner.write_u8(*b)?;
258            }
259        } else if u29 < 0x20_0000 {
260            let b1 = ((u29 >> 00) & 0b0111_1111) as u8;
261            let b2 = ((u29 >> 07) | 0b1000_0000) as u8;
262            let b3 = ((u29 >> 14) | 0b1000_0000) as u8;
263            for b in &[b3, b2, b1] {
264                self.inner.write_u8(*b)?;
265            }
266        } else if u29 < 0x4000_0000 {
267            let b1 = ((u29 >> 00) & 0b1111_1111) as u8;
268            let b2 = ((u29 >> 08) | 0b1000_0000) as u8;
269            let b3 = ((u29 >> 15) | 0b1000_0000) as u8;
270            let b4 = ((u29 >> 22) | 0b1000_0000) as u8;
271            for b in &[b4, b3, b2, b1] {
272                self.inner.write_u8(*b)?;
273            }
274        } else {
275            panic!("Too large number: {}", u29);
276        }
277        Ok(())
278    }
279    /// Encode an AMF3 string.
280    ///
281    /// Use this if you need to encode an AMF3 string outside of value context.
282    /// An example of this is writing keys in Local Shared Object file.
283    pub fn encode_utf8(&mut self, s: &str) -> io::Result<()> {
284        self.encode_size(s.len())?;
285        self.inner.write_all(s.as_bytes())?;
286        Ok(())
287    }
288    fn encode_pairs(&mut self, pairs: &[Pair<String, Value>]) -> io::Result<()> {
289        for p in pairs {
290            self.encode_utf8(&p.key)?;
291            self.encode(&p.value)?;
292        }
293        self.encode_utf8("")?;
294        Ok(())
295    }
296}
297
298#[cfg(test)]
299mod tests {
300    use super::super::Value;
301    use crate::Pair;
302    use std::time;
303
304    macro_rules! encode_eq {
305        ($value:expr, $file:expr) => {{
306            let expected = include_bytes!(concat!("../testdata/", $file));
307            let mut buf = Vec::new();
308            $value.write_to(&mut buf).unwrap();
309            assert_eq!(buf, &expected[..]);
310        }};
311    }
312    macro_rules! encode_and_decode {
313        ($value:expr) => {{
314            let v = $value;
315            let mut buf = Vec::new();
316            v.write_to(&mut buf).unwrap();
317            assert_eq!(v, Value::read_from(&mut &buf[..]).unwrap());
318        }};
319    }
320
321    #[test]
322    fn encodes_undefined() {
323        encode_eq!(Value::Undefined, "amf3-undefined.bin");
324    }
325    #[test]
326    fn encodes_null() {
327        encode_eq!(Value::Null, "amf3-null.bin");
328    }
329    #[test]
330    fn encodes_boolean() {
331        encode_eq!(Value::Boolean(true), "amf3-true.bin");
332        encode_eq!(Value::Boolean(false), "amf3-false.bin");
333    }
334    #[test]
335    fn encodes_integer() {
336        encode_eq!(Value::Integer(0), "amf3-0.bin");
337        encode_eq!(Value::Integer(0b1000_0000), "amf3-integer-2byte.bin");
338        encode_eq!(
339            Value::Integer(0b100_0000_0000_0000),
340            "amf3-integer-3byte.bin"
341        );
342        encode_eq!(Value::Integer(-0x1000_0000), "amf3-min.bin");
343        encode_eq!(Value::Integer(0xFFF_FFFF), "amf3-max.bin");
344    }
345    #[test]
346    fn encodes_double() {
347        encode_eq!(Value::Double(3.5), "amf3-float.bin");
348        encode_eq!(Value::Double(2f64.powf(1000f64)), "amf3-bignum.bin");
349        encode_eq!(Value::Double(-0x1000_0001 as f64), "amf3-large-min.bin");
350        encode_eq!(Value::Double(268_435_456_f64), "amf3-large-max.bin");
351    }
352    #[test]
353    fn encodes_string() {
354        encode_eq!(s("String . String"), "amf3-string.bin");
355        encode_eq!(
356            dense_array(&[i(5), s("Shift テスト"), s("UTF テスト"), i(5)][..]),
357            "amf3-complex-encoded-string-array.bin"
358        );
359    }
360    #[test]
361    fn encodes_array() {
362        encode_eq!(
363            dense_array(&[i(1), i(2), i(3), i(4), i(5)][..]),
364            "amf3-primitive-array.bin"
365        );
366        encode_and_decode!(Value::Array {
367            assoc_entries: [("2", s("bar3")), ("foo", s("bar")), ("asdf", s("fdsa"))]
368                .iter()
369                .map(|e| pair(e.0, e.1.clone()))
370                .collect(),
371            dense_entries: vec![s("bar"), s("bar1"), s("bar2")],
372        });
373    }
374    #[test]
375    fn encodes_object() {
376        encode_eq!(
377            typed_obj(
378                "org.amf.ASClass",
379                &[("foo", s("bar")), ("baz", Value::Null)][..]
380            ),
381            "amf3-typed-object.bin"
382        );
383        encode_eq!(
384            obj(&[("foo", s("bar")), ("answer", i(42))][..]),
385            "amf3-hash.bin"
386        );
387    }
388    #[test]
389    fn encodes_xml_doc() {
390        encode_eq!(
391            Value::XmlDocument("<parent><child prop=\"test\" /></parent>".to_string()),
392            "amf3-xml-doc.bin"
393        );
394    }
395    #[test]
396    fn encodes_xml() {
397        let xml = Value::Xml("<parent><child prop=\"test\"/></parent>".to_string());
398        encode_eq!(xml, "amf3-xml.bin");
399    }
400    #[test]
401    fn encodes_byte_array() {
402        encode_eq!(
403            Value::ByteArray(vec![
404                0, 3, 227, 129, 147, 227, 130, 140, 116, 101, 115, 116, 64
405            ]),
406            "amf3-byte-array.bin"
407        );
408    }
409    #[test]
410    fn encodes_date() {
411        let d = Value::Date {
412            unix_time: time::Duration::from_secs(0),
413        };
414        encode_eq!(d, "amf3-date.bin");
415    }
416    #[test]
417    fn encodes_dictionary() {
418        let entries = vec![
419            (s("bar"), s("asdf1")),
420            (
421                typed_obj(
422                    "org.amf.ASClass",
423                    &[("foo", s("baz")), ("baz", Value::Null)][..],
424                ),
425                s("asdf2"),
426            ),
427        ];
428        encode_and_decode!(dic(&entries));
429        encode_eq!(dic(&[][..]), "amf3-empty-dictionary.bin");
430    }
431    #[test]
432    fn encodes_vector() {
433        encode_eq!(
434            Value::IntVector {
435                is_fixed: false,
436                entries: vec![4, -20, 12],
437            },
438            "amf3-vector-int.bin"
439        );
440
441        encode_eq!(
442            Value::UintVector {
443                is_fixed: false,
444                entries: vec![4, 20, 12],
445            },
446            "amf3-vector-uint.bin"
447        );
448
449        encode_eq!(
450            Value::DoubleVector {
451                is_fixed: false,
452                entries: vec![4.3, -20.6],
453            },
454            "amf3-vector-double.bin"
455        );
456
457        let objects = vec![
458            typed_obj(
459                "org.amf.ASClass",
460                &[("foo", s("foo")), ("baz", Value::Null)][..],
461            ),
462            typed_obj(
463                "org.amf.ASClass",
464                &[("foo", s("bar")), ("baz", Value::Null)][..],
465            ),
466            typed_obj(
467                "org.amf.ASClass",
468                &[("foo", s("baz")), ("baz", Value::Null)][..],
469            ),
470        ];
471        encode_and_decode!(Value::ObjectVector {
472            class_name: Some("org.amf.ASClass".to_string()),
473            is_fixed: false,
474            entries: objects,
475        });
476    }
477
478    fn i(i: i32) -> Value {
479        Value::Integer(i)
480    }
481    fn s(s: &str) -> Value {
482        Value::String(s.to_string())
483    }
484    fn pair(key: &str, value: Value) -> Pair<String, Value> {
485        Pair {
486            key: key.to_string(),
487            value,
488        }
489    }
490    fn dense_array(entries: &[Value]) -> Value {
491        Value::Array {
492            assoc_entries: Vec::new(),
493            dense_entries: entries.to_vec(),
494        }
495    }
496    fn dic(entries: &[(Value, Value)]) -> Value {
497        Value::Dictionary {
498            is_weak: false,
499            entries: entries
500                .iter()
501                .map(|e| Pair {
502                    key: e.0.clone(),
503                    value: e.1.clone(),
504                })
505                .collect(),
506        }
507    }
508    fn obj(entries: &[(&str, Value)]) -> Value {
509        Value::Object {
510            class_name: None,
511            sealed_count: 0,
512            entries: entries.iter().map(|e| pair(e.0, e.1.clone())).collect(),
513        }
514    }
515    fn typed_obj(class: &str, entries: &[(&str, Value)]) -> Value {
516        Value::Object {
517            class_name: Some(class.to_string()),
518            sealed_count: entries.len(),
519            entries: entries.iter().map(|e| pair(e.0, e.1.clone())).collect(),
520        }
521    }
522}