1use 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#[derive(Default)]
22pub struct AMF3Encoder {
23 string_reference_table: ElementCache<Vec<u8>>,
25 trait_reference_table: RefCell<Vec<ClassDefinition>>,
27 object_reference_table: ElementCache<Value>,
29 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 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| {
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 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| {
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 let len = Length::Size(children.len() as u32);
498
499 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(&[]), )),
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(&[]), 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 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}