flash_lso/amf3/
write.rs

1///! Handles encoding AMF3
2use crate::amf3::custom_encoder::CustomEncoder;
3use crate::amf3::element_cache::ElementCache;
4use crate::amf3::length::Length;
5use crate::amf3::type_marker::TypeMarker;
6use crate::nom_utils::either;
7use crate::types::{Attribute, ClassDefinition, Element, Value};
8use crate::PADDING;
9use cookie_factory::bytes::{be_f64, be_i32, be_u32, be_u8};
10use cookie_factory::combinator::{cond, slice};
11use cookie_factory::multi::all;
12use cookie_factory::sequence::tuple;
13use cookie_factory::{GenError, SerializeFn, WriteContext};
14use std::cell::RefCell;
15use std::collections::HashMap;
16use std::io::Write;
17use std::ops::Deref;
18use std::rc::Rc;
19
20/// Handles encoding AMF3
21#[derive(Default)]
22pub struct AMF3Encoder {
23    /// The table used to cache repeated byte strings
24    string_reference_table: ElementCache<Vec<u8>>,
25    /// The table used to cache repeated trait definitions
26    trait_reference_table: RefCell<Vec<ClassDefinition>>,
27    /// The table used to cache repeated objects
28    object_reference_table: ElementCache<Value>,
29    /// Encoders used for handling externalized types
30    pub external_encoders: HashMap<String, Box<dyn CustomEncoder>>,
31}
32
33#[cfg(test)]
34mod write_number_tests {
35    use crate::amf3::write::AMF3Encoder;
36    use cookie_factory::gen;
37
38    #[test]
39    fn test_write_1byte_number() {
40        let e = AMF3Encoder::default();
41        let v = vec![];
42        let (b1, _) = gen(e.write_int(0b00101011), v).unwrap();
43        assert_eq!(b1, &[0b00101011]);
44    }
45
46    #[test]
47    fn test_write_4byte_number() {
48        let e = AMF3Encoder::default();
49        let v = vec![];
50        let (b1, _) = gen(e.write_int(2097280), v).unwrap();
51        assert_eq!(b1, &[0b10000000, 0b11000000, 0b10000000, 0b10000000]);
52    }
53
54    #[test]
55    fn write_neg_number() {
56        let e = AMF3Encoder::default();
57        let v = vec![];
58        let (b1, _) = gen(e.write_int(-268435455), v).unwrap();
59        assert_eq!(b1, &[192, 128, 128, 1]);
60    }
61}
62
63impl AMF3Encoder {
64    #[allow(clippy::unusual_byte_groupings)]
65    pub(crate) fn write_int<'a, 'b: 'a, W: Write + 'a>(&self, i: i32) -> impl SerializeFn<W> + 'a {
66        let n = if i < 0 {
67            i + 0b001_0000000_0000000_0000000_00000000
68        } else {
69            i
70        };
71
72        either(
73            n > 0x1fffff,
74            tuple((
75                be_u8(((n >> (7 * 3 + 1)) | 0b10000000) as u8),
76                be_u8(((n >> (7 * 2 + 1)) | 0b10000000) as u8),
77                be_u8(((n >> (7 + 1)) | 0b10000000) as u8),
78                be_u8((n & 0b11111111) as u8),
79            )),
80            either(
81                n > 0x3fff,
82                tuple((
83                    be_u8(((n >> (7 * 2)) | 0b10000000) as u8),
84                    be_u8(((n >> 7) | 0b10000000) as u8),
85                    be_u8((n & 0b01111111) as u8),
86                )),
87                either(
88                    n > 0x7f,
89                    tuple((
90                        be_u8(((n >> 7) | 0b10000000) as u8),
91                        be_u8((n & 0b01111111) as u8),
92                    )),
93                    be_u8((n & 0b01111111) as u8),
94                ),
95            ),
96        )
97    }
98
99    fn write_byte_string<'a, 'b: 'a, W: Write + 'a>(
100        &self,
101        s: &'b [u8],
102    ) -> impl SerializeFn<W> + 'a {
103        let len = if !s.is_empty() {
104            self.string_reference_table
105                .to_length(s.to_vec(), s.len() as u32)
106        } else {
107            Length::Size(0)
108        };
109
110        let only_length = len.is_reference() && !s.is_empty();
111
112        if !s.is_empty() {
113            self.string_reference_table.store_slice(s);
114        }
115
116        either(
117            only_length,
118            len.write(&self),
119            tuple((len.write(&self), slice(s))),
120        )
121    }
122
123    fn write_string<'a, 'b: 'a, W: Write + 'a>(&self, s: &'b str) -> impl SerializeFn<W> + 'a {
124        self.write_byte_string(s.as_bytes())
125    }
126
127    fn write_type_marker<'a, 'b: 'a, W: Write + 'a>(
128        &self,
129        s: TypeMarker,
130    ) -> impl SerializeFn<W> + 'a {
131        be_u8(s as u8)
132    }
133
134    fn write_number_element<'a, 'b: 'a, W: Write + 'a>(&self, i: f64) -> impl SerializeFn<W> + 'a {
135        tuple((self.write_type_marker(TypeMarker::Number), be_f64(i)))
136    }
137
138    fn write_boolean_element<'a, 'b: 'a, W: Write + 'a>(
139        &self,
140        b: bool,
141    ) -> impl SerializeFn<W> + 'a {
142        either(
143            b,
144            self.write_type_marker(TypeMarker::True),
145            self.write_type_marker(TypeMarker::False),
146        )
147    }
148
149    fn write_string_element<'a, 'b: 'a, W: Write + 'a>(
150        &self,
151        s: &'b str,
152    ) -> impl SerializeFn<W> + 'a {
153        tuple((
154            self.write_type_marker(TypeMarker::String),
155            self.write_byte_string(s.as_bytes()),
156        ))
157    }
158
159    fn write_null_element<'a, 'b: 'a, W: Write + 'a>(&self) -> impl SerializeFn<W> + 'a {
160        self.write_type_marker(TypeMarker::Null)
161    }
162
163    fn write_undefined_element<'a, 'b: 'a, W: Write + 'a>(&self) -> impl SerializeFn<W> + 'a {
164        self.write_type_marker(TypeMarker::Undefined)
165    }
166
167    fn write_int_vector<'a, 'b: 'a, W: Write + 'a>(
168        &self,
169        items: &'b [i32],
170        fixed_length: bool,
171    ) -> impl SerializeFn<W> + 'a {
172        let len = self.object_reference_table.to_length_store(
173            Value::VectorInt(items.to_vec(), fixed_length),
174            items.len() as u32,
175        );
176
177        tuple((
178            self.write_type_marker(TypeMarker::VectorInt),
179            either(
180                len.is_reference(),
181                len.write(&self),
182                tuple((
183                    Length::Size(items.len() as u32).write(&self),
184                    be_u8(fixed_length as u8),
185                    all(items.iter().copied().map(be_i32)),
186                )),
187            ),
188        ))
189    }
190
191    fn write_uint_vector<'a, 'b: 'a, W: Write + 'a>(
192        &self,
193        items: &'b [u32],
194        fixed_length: bool,
195    ) -> impl SerializeFn<W> + 'a {
196        let len = self.object_reference_table.to_length_store(
197            Value::VectorUInt(items.to_vec(), fixed_length),
198            items.len() as u32,
199        );
200
201        tuple((
202            self.write_type_marker(TypeMarker::VectorUInt),
203            either(
204                len.is_reference(),
205                len.write(&self),
206                tuple((
207                    Length::Size(items.len() as u32).write(&self),
208                    be_u8(fixed_length as u8),
209                    all(items.iter().copied().map(be_u32)),
210                )),
211            ),
212        ))
213    }
214
215    fn write_number_vector<'a, 'b: 'a, W: Write + 'a>(
216        &self,
217        items: &'b [f64],
218        fixed_length: bool,
219    ) -> impl SerializeFn<W> + 'a {
220        let len = self.object_reference_table.to_length_store(
221            Value::VectorDouble(items.to_vec(), fixed_length),
222            items.len() as u32,
223        );
224
225        tuple((
226            self.write_type_marker(TypeMarker::VectorDouble),
227            either(
228                len.is_reference(),
229                len.write(&self),
230                tuple((
231                    Length::Size(items.len() as u32).write(&self),
232                    be_u8(fixed_length as u8),
233                    all(items.iter().copied().map(be_f64)),
234                )),
235            ),
236        ))
237    }
238
239    fn write_date_element<'a, 'b: 'a, W: Write + 'a>(&self, time: f64) -> impl SerializeFn<W> + 'a {
240        let len = self
241            .object_reference_table
242            .to_length_store(Value::Date(time, None), 0);
243
244        tuple((
245            self.write_type_marker(TypeMarker::Date),
246            len.write(&self),
247            cond(len.is_size(), be_f64(time)),
248        ))
249    }
250
251    fn write_integer_element<'a, 'b: 'a, W: Write + 'a>(&self, i: i32) -> impl SerializeFn<W> + 'a {
252        tuple((
253            self.write_type_marker(TypeMarker::Integer),
254            self.write_int(i),
255        ))
256    }
257
258    fn write_byte_array_element<'a, 'b: 'a, W: Write + 'a>(
259        &self,
260        bytes: &'b [u8],
261    ) -> impl SerializeFn<W> + 'a {
262        let len = self
263            .object_reference_table
264            .to_length_store(Value::ByteArray(bytes.to_vec()), bytes.len() as u32);
265
266        tuple((
267            self.write_type_marker(TypeMarker::ByteArray),
268            len.write(&self),
269            cond(len.is_size(), slice(bytes)),
270        ))
271    }
272
273    fn write_xml_element<'a, 'b: 'a, W: Write + 'a>(
274        &self,
275        bytes: &'b str,
276        string: bool,
277    ) -> impl SerializeFn<W> + 'a {
278        let len = Length::Size(bytes.len() as u32);
279
280        tuple((
281            either(
282                string,
283                self.write_type_marker(TypeMarker::XmlString),
284                self.write_type_marker(TypeMarker::XML),
285            ),
286            len.write(&self),
287            cond(len.is_size(), slice(bytes.as_bytes())),
288        ))
289    }
290
291    fn write_class_definition<'a, 'b: 'a, W: Write + 'a>(
292        &'a self,
293        class_def: &'b ClassDefinition,
294    ) -> impl SerializeFn<W> + 'a {
295        tuple((
296            self.write_byte_string(class_def.name.as_bytes()),
297            all(class_def
298                .static_properties
299                .iter()
300                .map(move |p| self.write_string(p))),
301        ))
302    }
303
304    //TODO: conds should be common somehwere
305    fn write_trait_reference<'a, 'b: 'a, W: Write + 'a>(
306        &'a self,
307        index: u32,
308        children: &'b [Element],
309        custom_props: Option<&'b [Element]>,
310        def: &'b ClassDefinition,
311    ) -> impl SerializeFn<W> + 'a {
312        #[allow(clippy::identity_op)]
313        let size = (((index << 1) | 0u32) << 1) | 1u32;
314
315        tuple((
316            self.write_int(size as i32),
317            cond(def.attributes.contains(Attribute::External), move |out| {
318                if let Some(encoder) = self.external_encoders.get(&def.name) {
319                    slice(encoder.encode(custom_props.unwrap(), &Some(def.clone()), self))(out)
320                } else {
321                    Err(GenError::NotYetImplemented)
322                }
323            }),
324            cond(
325                !def.attributes.contains(Attribute::External),
326                tuple((
327                    cond(
328                        def.attributes.is_empty(),
329                        all(children
330                            .iter()
331                            .filter(move |c| def.static_properties.contains(&c.name))
332                            .map(move |e| &e.value)
333                            .map(move |e| self.write_value_element(e))),
334                    ),
335                    cond(
336                        def.attributes.contains(Attribute::Dynamic),
337                        tuple((
338                            all(children
339                                .iter()
340                                .filter(move |c| def.static_properties.contains(&c.name))
341                                .map(move |e| &e.value)
342                                .map(move |e| self.write_value_element(e))),
343                            all(children
344                                .iter()
345                                .filter(move |c| !def.static_properties.contains(&c.name))
346                                // .map(move |e| &e.value)
347                                .map(move |e| {
348                                    tuple((
349                                        self.write_byte_string(e.name.as_bytes()),
350                                        self.write_value_element(&e.value),
351                                    ))
352                                })),
353                            self.write_byte_string(&[]),
354                        )),
355                    ),
356                )),
357            ),
358        ))
359    }
360
361    fn write_object_reference<'a, 'b: 'a, W: Write + 'a>(
362        &'a self,
363        index: u32,
364    ) -> impl SerializeFn<W> + 'a {
365        #[allow(clippy::identity_op)]
366        let size = (index << 1) | 0u32;
367        tuple((self.write_int(size as i32),))
368    }
369
370    fn write_object_full<'a, 'b: 'a, W: Write + 'a>(
371        &'a self,
372        custom_props: Option<&'b [Element]>,
373        children: &'b [Element],
374        def: &'b ClassDefinition,
375    ) -> impl SerializeFn<W> + 'a {
376        self.trait_reference_table.borrow_mut().push(def.clone());
377
378        let is_external = def.attributes.contains(Attribute::External);
379        let is_dynamic = def.attributes.contains(Attribute::Dynamic);
380
381        let mut encoding = 0b00;
382        if is_external {
383            encoding |= 0b01;
384        }
385        if is_dynamic {
386            encoding |= 0b10;
387        }
388
389        // Format attribute_count[:4] | encoding[4:2] | class_def_ref flag (1 bit) | class_ref flag (1 bit)
390        let size = ((((((def.static_properties.len() as u32) << 2) | (encoding & 0xff) as u32)
391            << 1)
392            | 1u32)
393            << 1)
394            | 1u32;
395
396        tuple((
397            self.write_int(size as i32),
398            self.write_class_definition(def),
399            cond(def.attributes.contains(Attribute::External), move |out| {
400                if let Some(encoder) = self.external_encoders.get(&def.name) {
401                    slice(encoder.encode(custom_props.unwrap(), &Some(def.clone()), self))(out)
402                } else {
403                    Err(GenError::NotYetImplemented)
404                }
405            }),
406            cond(
407                !def.attributes.contains(Attribute::External),
408                tuple((
409                    cond(
410                        def.attributes.is_empty(),
411                        all(children
412                            .iter()
413                            .filter(move |c| def.static_properties.contains(&c.name))
414                            .map(move |e| &e.value)
415                            .map(move |e| self.write_value_element(e))),
416                    ),
417                    cond(
418                        def.attributes.contains(Attribute::Dynamic),
419                        tuple((
420                            all(children
421                                .iter()
422                                .filter(move |c| def.static_properties.contains(&c.name))
423                                .map(move |e| &e.value)
424                                .map(move |e| self.write_value_element(e))),
425                            all(children
426                                .iter()
427                                .filter(move |c| !def.static_properties.contains(&c.name))
428                                // .map(move |e| &e.value)
429                                .map(move |e| {
430                                    tuple((
431                                        self.write_byte_string(e.name.as_bytes()),
432                                        self.write_value_element(&e.value),
433                                    ))
434                                })),
435                            self.write_byte_string(&[]),
436                        )),
437                    ),
438                )),
439            ),
440        ))
441    }
442
443    fn write_object_element<'a, 'b: 'a, W: Write + 'a>(
444        &'a self,
445        children: &'b [Element],
446        custom_props: Option<&'b [Element]>,
447        class_def: &'b Option<ClassDefinition>,
448    ) -> impl SerializeFn<W> + 'a {
449        let had_object = Length::Size(0);
450
451        self.object_reference_table
452            .store(Value::Object(children.to_vec(), class_def.clone()));
453
454        move |out| {
455            let def = class_def.clone().unwrap_or_default();
456            let def2 = def.clone();
457
458            let has_trait = self
459                .trait_reference_table
460                .borrow()
461                .iter()
462                .position(|cd| *cd == def);
463
464            let x = tuple((
465                self.write_type_marker(TypeMarker::Object),
466                cond(had_object.is_reference(), move |out| {
467                    self.write_object_reference(had_object.to_position().unwrap() as u32)(out)
468                }),
469                cond(
470                    !had_object.is_reference(),
471                    tuple((
472                        cond(has_trait.is_some(), move |out| {
473                            self.write_trait_reference(
474                                has_trait.unwrap() as u32,
475                                children,
476                                custom_props,
477                                &def2,
478                            )(out)
479                        }),
480                        cond(
481                            has_trait.is_none(),
482                            self.write_object_full(custom_props, children, &def),
483                        ),
484                    )),
485                ),
486            ))(out);
487
488            x
489        }
490    }
491
492    fn write_strict_array_element<'a, 'b: 'a, W: Write + 'a>(
493        &'a self,
494        children: &'b [Rc<Value>],
495    ) -> impl SerializeFn<W> + 'a {
496        //TODO: why is this not a reference
497        let len = Length::Size(children.len() as u32);
498
499        //TODO: why does this not offset the cache if StrictArray([]) is saved but always written as Size(0) instead of Ref(n)
500        either(
501            children.is_empty(),
502            tuple((
503                self.write_type_marker(TypeMarker::Array),
504                Length::Size(0).write(&self),
505                self.write_byte_string(&[]), // Empty key
506            )),
507            tuple((
508                self.write_type_marker(TypeMarker::Array),
509                len.write(&self),
510                cond(
511                    len.is_size(),
512                    tuple((
513                        self.write_byte_string(&[]), // Empty key
514                        all(children.iter().map(move |v| self.write_value_element(v))),
515                    )),
516                ),
517            )),
518        )
519    }
520
521    fn write_ecma_array_element<'a, 'b: 'a, W: Write + 'a>(
522        &'a self,
523        dense: &'b [Rc<Value>],
524        assoc: &'b [Element],
525    ) -> impl SerializeFn<W> + 'a {
526        let len = Length::Size(dense.len() as u32);
527
528        //TODO: would this also work for strict arrays if they have [] for assoc part?
529        tuple((
530            self.write_type_marker(TypeMarker::Array),
531            len.write(&self),
532            cond(
533                len.is_size(),
534                tuple((
535                    all(assoc.iter().map(move |out| self.write_element(out))),
536                    self.write_byte_string(&[]),
537                    all(dense.iter().map(move |out| self.write_value_element(out))),
538                )),
539            ),
540        ))
541    }
542
543    fn write_object_vector_element<'a, 'b: 'a, W: Write + 'a>(
544        &'a self,
545        items: &'b [Rc<Value>],
546        type_name: &'b str,
547        fixed_length: bool,
548    ) -> impl SerializeFn<W> + 'a {
549        let len = self.object_reference_table.to_length_store(
550            Value::VectorObject(items.to_vec(), type_name.to_string(), fixed_length),
551            items.len() as u32,
552        );
553
554        tuple((
555            self.write_type_marker(TypeMarker::VectorObject),
556            len.write(&self),
557            cond(
558                len.is_size(),
559                tuple((
560                    be_u8(fixed_length as u8),
561                    self.write_string(type_name),
562                    all(items.iter().map(move |i| self.write_value_element(i))),
563                )),
564            ),
565        ))
566    }
567
568    fn write_dictionary_element<'a, 'b: 'a, W: Write + 'a>(
569        &'a self,
570        items: &'b [(Rc<Value>, Rc<Value>)],
571        weak_keys: bool,
572    ) -> impl SerializeFn<W> + 'a {
573        let len = self.object_reference_table.to_length(
574            Value::Dictionary(items.to_vec(), weak_keys),
575            items.len() as u32,
576        );
577        self.object_reference_table
578            .store(Value::Dictionary(items.to_vec(), weak_keys));
579
580        tuple((
581            self.write_type_marker(TypeMarker::Dictionary),
582            len.write(&self),
583            cond(
584                len.is_size(),
585                tuple((
586                    be_u8(weak_keys as u8),
587                    all(items.iter().map(move |i| {
588                        tuple((
589                            self.write_value_element(&i.0),
590                            self.write_value_element(&i.1),
591                        ))
592                    })),
593                )),
594            ),
595        ))
596    }
597
598    pub(crate) fn write_value_element<'a, 'b: 'a, W: Write + 'a>(
599        &'b self,
600        s: &'b Rc<Value>,
601    ) -> impl SerializeFn<W> + 'a {
602        move |out| self.write_value(s.deref())(out)
603    }
604
605    fn write_value<'a, 'b: 'a, W: Write + 'a>(&'b self, s: &'b Value) -> impl SerializeFn<W> + 'a {
606        move |out: WriteContext<W>| match s {
607            Value::Number(x) => self.write_number_element(*x)(out),
608            Value::Bool(b) => self.write_boolean_element(*b)(out),
609            Value::String(s) => self.write_string_element(s)(out),
610            Value::Object(children, class_def) => {
611                self.write_object_element(children, None, class_def)(out)
612            }
613            Value::Null => self.write_null_element()(out),
614            Value::Undefined => self.write_undefined_element()(out),
615            Value::ECMAArray(dense, elements, _) => {
616                self.write_ecma_array_element(dense, elements)(out)
617            }
618            Value::StrictArray(children) => self.write_strict_array_element(children)(out),
619            Value::Date(time, _tz) => self.write_date_element(*time)(out),
620            Value::XML(content, string) => self.write_xml_element(content, *string)(out),
621            Value::Integer(i) => self.write_integer_element(*i)(out),
622            Value::ByteArray(bytes) => self.write_byte_array_element(bytes)(out),
623            Value::VectorInt(items, fixed_length) => {
624                self.write_int_vector(items, *fixed_length)(out)
625            }
626            Value::VectorUInt(items, fixed_length) => {
627                self.write_uint_vector(items, *fixed_length)(out)
628            }
629            Value::VectorDouble(items, fixed_length) => {
630                self.write_number_vector(items, *fixed_length)(out)
631            }
632            Value::VectorObject(items, type_name, fixed_length) => {
633                self.write_object_vector_element(items, type_name, *fixed_length)(out)
634            }
635            Value::Dictionary(kv, weak_keys) => self.write_dictionary_element(kv, *weak_keys)(out),
636
637            Value::Custom(elements, dynamic_elements, def) => {
638                self.write_object_element(dynamic_elements, Some(elements), def)(out)
639            }
640            Value::AMF3(e) => self.write_value_element(e)(out),
641            Value::Unsupported => self.write_undefined_element()(out),
642        }
643    }
644
645    fn write_element<'a, 'b: 'a, W: Write + 'a>(
646        &'b self,
647        element: &'b Element,
648    ) -> impl SerializeFn<W> + 'a {
649        tuple((
650            self.write_string(&element.name),
651            self.write_value_element(&element.value),
652        ))
653    }
654
655    fn write_element_and_padding<'a, 'b: 'a, W: Write + 'a>(
656        &'b self,
657        element: &'b Element,
658    ) -> impl SerializeFn<W> + 'a {
659        tuple((self.write_element(element), slice(PADDING)))
660    }
661
662    pub(crate) fn write_body<'a, 'b: 'a, W: Write + 'a>(
663        &'b self,
664        elements: &'b [Element],
665    ) -> impl SerializeFn<W> + 'a {
666        all(elements
667            .iter()
668            .map(move |e| self.write_element_and_padding(e)))
669    }
670}