1use bytes::{Buf, BufMut, Bytes, BytesMut};
29use std::collections::HashMap;
30
31use super::value::AmfValue;
32use crate::error::AmfError;
33
34const MARKER_NUMBER: u8 = 0x00;
36const MARKER_BOOLEAN: u8 = 0x01;
37const MARKER_STRING: u8 = 0x02;
38const MARKER_OBJECT: u8 = 0x03;
39const MARKER_NULL: u8 = 0x05;
40const MARKER_UNDEFINED: u8 = 0x06;
41const MARKER_REFERENCE: u8 = 0x07;
42const MARKER_ECMA_ARRAY: u8 = 0x08;
43const MARKER_OBJECT_END: u8 = 0x09;
44const MARKER_STRICT_ARRAY: u8 = 0x0A;
45const MARKER_DATE: u8 = 0x0B;
46const MARKER_LONG_STRING: u8 = 0x0C;
47const MARKER_UNSUPPORTED: u8 = 0x0D;
48const MARKER_XML_DOCUMENT: u8 = 0x0F;
49const MARKER_TYPED_OBJECT: u8 = 0x10;
50const MARKER_AVMPLUS: u8 = 0x11;
51
52const MAX_NESTING_DEPTH: usize = 64;
54
55pub struct Amf0Decoder {
57 references: Vec<AmfValue>,
59 lenient: bool,
61 depth: usize,
63}
64
65impl Amf0Decoder {
66 pub fn new() -> Self {
68 Self {
69 references: Vec::new(),
70 lenient: true, depth: 0,
72 }
73 }
74
75 pub fn with_lenient(lenient: bool) -> Self {
77 Self {
78 references: Vec::new(),
79 lenient,
80 depth: 0,
81 }
82 }
83
84 pub fn reset(&mut self) {
86 self.references.clear();
87 self.depth = 0;
88 }
89
90 pub fn decode(&mut self, buf: &mut Bytes) -> Result<AmfValue, AmfError> {
92 if buf.is_empty() {
93 return Err(AmfError::UnexpectedEof);
94 }
95
96 self.depth += 1;
97 if self.depth > MAX_NESTING_DEPTH {
98 return Err(AmfError::NestingTooDeep);
99 }
100
101 let marker = buf.get_u8();
102 let result = self.decode_value(marker, buf);
103 self.depth -= 1;
104 result
105 }
106
107 pub fn decode_all(&mut self, buf: &mut Bytes) -> Result<Vec<AmfValue>, AmfError> {
109 let mut values = Vec::new();
110 while buf.has_remaining() {
111 values.push(self.decode(buf)?);
112 }
113 Ok(values)
114 }
115
116 fn decode_value(&mut self, marker: u8, buf: &mut Bytes) -> Result<AmfValue, AmfError> {
117 match marker {
118 MARKER_NUMBER => self.decode_number(buf),
119 MARKER_BOOLEAN => self.decode_boolean(buf),
120 MARKER_STRING => self.decode_string(buf),
121 MARKER_OBJECT => self.decode_object(buf),
122 MARKER_NULL => Ok(AmfValue::Null),
123 MARKER_UNDEFINED => Ok(AmfValue::Undefined),
124 MARKER_REFERENCE => self.decode_reference(buf),
125 MARKER_ECMA_ARRAY => self.decode_ecma_array(buf),
126 MARKER_STRICT_ARRAY => self.decode_strict_array(buf),
127 MARKER_DATE => self.decode_date(buf),
128 MARKER_LONG_STRING => self.decode_long_string(buf),
129 MARKER_UNSUPPORTED => Ok(AmfValue::Undefined),
130 MARKER_XML_DOCUMENT => self.decode_xml(buf),
131 MARKER_TYPED_OBJECT => self.decode_typed_object(buf),
132 MARKER_AVMPLUS => {
133 Ok(AmfValue::Null)
136 }
137 _ => {
138 if self.lenient {
139 Ok(AmfValue::Undefined)
141 } else {
142 Err(AmfError::UnknownMarker(marker))
143 }
144 }
145 }
146 }
147
148 fn decode_number(&mut self, buf: &mut Bytes) -> Result<AmfValue, AmfError> {
149 if buf.remaining() < 8 {
150 return Err(AmfError::UnexpectedEof);
151 }
152 Ok(AmfValue::Number(buf.get_f64()))
153 }
154
155 fn decode_boolean(&mut self, buf: &mut Bytes) -> Result<AmfValue, AmfError> {
156 if buf.is_empty() {
157 return Err(AmfError::UnexpectedEof);
158 }
159 Ok(AmfValue::Boolean(buf.get_u8() != 0))
160 }
161
162 fn decode_string(&mut self, buf: &mut Bytes) -> Result<AmfValue, AmfError> {
163 let s = self.read_utf8(buf)?;
164 Ok(AmfValue::String(s))
165 }
166
167 fn decode_long_string(&mut self, buf: &mut Bytes) -> Result<AmfValue, AmfError> {
168 let s = self.read_utf8_long(buf)?;
169 Ok(AmfValue::String(s))
170 }
171
172 fn decode_object(&mut self, buf: &mut Bytes) -> Result<AmfValue, AmfError> {
173 let mut properties = HashMap::new();
174
175 let obj_index = self.references.len();
177 self.references.push(AmfValue::Null); loop {
180 let key = self.read_utf8(buf)?;
181
182 if key.is_empty() {
184 if buf.is_empty() {
185 if self.lenient {
186 break;
188 }
189 return Err(AmfError::UnexpectedEof);
190 }
191 let end_marker = buf.get_u8();
192 if end_marker == MARKER_OBJECT_END {
193 break;
194 } else if self.lenient {
195 break;
198 } else {
199 return Err(AmfError::InvalidObjectEnd);
200 }
201 }
202
203 let value = self.decode(buf)?;
204 properties.insert(key, value);
205 }
206
207 let obj = AmfValue::Object(properties);
208 self.references[obj_index] = obj.clone();
209 Ok(obj)
210 }
211
212 fn decode_ecma_array(&mut self, buf: &mut Bytes) -> Result<AmfValue, AmfError> {
213 if buf.remaining() < 4 {
214 return Err(AmfError::UnexpectedEof);
215 }
216
217 let _count = buf.get_u32();
219
220 let arr_index = self.references.len();
222 self.references.push(AmfValue::Null);
223
224 let mut properties = HashMap::new();
225
226 loop {
227 let key = self.read_utf8(buf)?;
228
229 if key.is_empty() {
230 if buf.is_empty() {
231 if self.lenient {
232 break;
233 }
234 return Err(AmfError::UnexpectedEof);
235 }
236 let end_marker = buf.get_u8();
237 if end_marker == MARKER_OBJECT_END {
238 break;
239 } else if self.lenient {
240 break;
241 } else {
242 return Err(AmfError::InvalidObjectEnd);
243 }
244 }
245
246 let value = self.decode(buf)?;
247 properties.insert(key, value);
248 }
249
250 let arr = AmfValue::EcmaArray(properties);
251 self.references[arr_index] = arr.clone();
252 Ok(arr)
253 }
254
255 fn decode_strict_array(&mut self, buf: &mut Bytes) -> Result<AmfValue, AmfError> {
256 if buf.remaining() < 4 {
257 return Err(AmfError::UnexpectedEof);
258 }
259
260 let count = buf.get_u32() as usize;
261
262 let arr_index = self.references.len();
264 self.references.push(AmfValue::Null);
265
266 let mut elements = Vec::with_capacity(count.min(1024)); for _ in 0..count {
268 elements.push(self.decode(buf)?);
269 }
270
271 let arr = AmfValue::Array(elements);
272 self.references[arr_index] = arr.clone();
273 Ok(arr)
274 }
275
276 fn decode_date(&mut self, buf: &mut Bytes) -> Result<AmfValue, AmfError> {
277 if buf.remaining() < 10 {
278 return Err(AmfError::UnexpectedEof);
279 }
280
281 let timestamp = buf.get_f64();
282 let _timezone = buf.get_i16(); Ok(AmfValue::Date(timestamp))
285 }
286
287 fn decode_reference(&mut self, buf: &mut Bytes) -> Result<AmfValue, AmfError> {
288 if buf.remaining() < 2 {
289 return Err(AmfError::UnexpectedEof);
290 }
291
292 let index = buf.get_u16() as usize;
293 if index >= self.references.len() {
294 return Err(AmfError::InvalidReference(index as u16));
295 }
296
297 Ok(self.references[index].clone())
298 }
299
300 fn decode_xml(&mut self, buf: &mut Bytes) -> Result<AmfValue, AmfError> {
301 let s = self.read_utf8_long(buf)?;
302 Ok(AmfValue::Xml(s))
303 }
304
305 fn decode_typed_object(&mut self, buf: &mut Bytes) -> Result<AmfValue, AmfError> {
306 let class_name = self.read_utf8(buf)?;
307
308 let obj_index = self.references.len();
310 self.references.push(AmfValue::Null);
311
312 let mut properties = HashMap::new();
313
314 loop {
315 let key = self.read_utf8(buf)?;
316
317 if key.is_empty() {
318 if buf.is_empty() {
319 if self.lenient {
320 break;
321 }
322 return Err(AmfError::UnexpectedEof);
323 }
324 let end_marker = buf.get_u8();
325 if end_marker == MARKER_OBJECT_END {
326 break;
327 } else if self.lenient {
328 break;
329 } else {
330 return Err(AmfError::InvalidObjectEnd);
331 }
332 }
333
334 let value = self.decode(buf)?;
335 properties.insert(key, value);
336 }
337
338 let obj = AmfValue::TypedObject {
339 class_name,
340 properties,
341 };
342 self.references[obj_index] = obj.clone();
343 Ok(obj)
344 }
345
346 fn read_utf8(&mut self, buf: &mut Bytes) -> Result<String, AmfError> {
348 if buf.remaining() < 2 {
349 return Err(AmfError::UnexpectedEof);
350 }
351
352 let len = buf.get_u16() as usize;
353 if buf.remaining() < len {
354 return Err(AmfError::UnexpectedEof);
355 }
356
357 let bytes = buf.copy_to_bytes(len);
358 String::from_utf8(bytes.to_vec()).map_err(|_| AmfError::InvalidUtf8)
359 }
360
361 fn read_utf8_long(&mut self, buf: &mut Bytes) -> Result<String, AmfError> {
363 if buf.remaining() < 4 {
364 return Err(AmfError::UnexpectedEof);
365 }
366
367 let len = buf.get_u32() as usize;
368 if buf.remaining() < len {
369 return Err(AmfError::UnexpectedEof);
370 }
371
372 let bytes = buf.copy_to_bytes(len);
373 String::from_utf8(bytes.to_vec()).map_err(|_| AmfError::InvalidUtf8)
374 }
375}
376
377impl Default for Amf0Decoder {
378 fn default() -> Self {
379 Self::new()
380 }
381}
382
383pub struct Amf0Encoder {
385 buf: BytesMut,
386}
387
388impl Amf0Encoder {
389 pub fn new() -> Self {
391 Self {
392 buf: BytesMut::with_capacity(256),
393 }
394 }
395
396 pub fn with_capacity(capacity: usize) -> Self {
398 Self {
399 buf: BytesMut::with_capacity(capacity),
400 }
401 }
402
403 pub fn finish(&mut self) -> Bytes {
405 self.buf.split().freeze()
406 }
407
408 pub fn len(&self) -> usize {
410 self.buf.len()
411 }
412
413 pub fn is_empty(&self) -> bool {
415 self.buf.is_empty()
416 }
417
418 pub fn encode(&mut self, value: &AmfValue) {
420 match value {
421 AmfValue::Null => {
422 self.buf.put_u8(MARKER_NULL);
423 }
424 AmfValue::Undefined => {
425 self.buf.put_u8(MARKER_UNDEFINED);
426 }
427 AmfValue::Boolean(b) => {
428 self.buf.put_u8(MARKER_BOOLEAN);
429 self.buf.put_u8(if *b { 1 } else { 0 });
430 }
431 AmfValue::Number(n) => {
432 self.buf.put_u8(MARKER_NUMBER);
433 self.buf.put_f64(*n);
434 }
435 AmfValue::Integer(i) => {
436 self.buf.put_u8(MARKER_NUMBER);
438 self.buf.put_f64(*i as f64);
439 }
440 AmfValue::String(s) => {
441 if s.len() > 0xFFFF {
442 self.buf.put_u8(MARKER_LONG_STRING);
444 self.buf.put_u32(s.len() as u32);
445 } else {
446 self.buf.put_u8(MARKER_STRING);
447 self.buf.put_u16(s.len() as u16);
448 }
449 self.buf.put_slice(s.as_bytes());
450 }
451 AmfValue::Object(props) => {
452 self.buf.put_u8(MARKER_OBJECT);
453 for (key, val) in props {
454 self.write_utf8(key);
455 self.encode(val);
456 }
457 self.buf.put_u16(0); self.buf.put_u8(MARKER_OBJECT_END);
460 }
461 AmfValue::EcmaArray(props) => {
462 self.buf.put_u8(MARKER_ECMA_ARRAY);
463 self.buf.put_u32(props.len() as u32);
464 for (key, val) in props {
465 self.write_utf8(key);
466 self.encode(val);
467 }
468 self.buf.put_u16(0);
469 self.buf.put_u8(MARKER_OBJECT_END);
470 }
471 AmfValue::Array(elements) => {
472 self.buf.put_u8(MARKER_STRICT_ARRAY);
473 self.buf.put_u32(elements.len() as u32);
474 for elem in elements {
475 self.encode(elem);
476 }
477 }
478 AmfValue::Date(timestamp) => {
479 self.buf.put_u8(MARKER_DATE);
480 self.buf.put_f64(*timestamp);
481 self.buf.put_i16(0); }
483 AmfValue::Xml(s) => {
484 self.buf.put_u8(MARKER_XML_DOCUMENT);
485 self.buf.put_u32(s.len() as u32);
486 self.buf.put_slice(s.as_bytes());
487 }
488 AmfValue::TypedObject {
489 class_name,
490 properties,
491 } => {
492 self.buf.put_u8(MARKER_TYPED_OBJECT);
493 self.write_utf8(class_name);
494 for (key, val) in properties {
495 self.write_utf8(key);
496 self.encode(val);
497 }
498 self.buf.put_u16(0);
499 self.buf.put_u8(MARKER_OBJECT_END);
500 }
501 AmfValue::ByteArray(_) => {
502 self.buf.put_u8(MARKER_NULL);
504 }
505 }
506 }
507
508 pub fn encode_all(&mut self, values: &[AmfValue]) {
510 for value in values {
511 self.encode(value);
512 }
513 }
514
515 fn write_utf8(&mut self, s: &str) {
517 let len = s.len().min(0xFFFF);
518 self.buf.put_u16(len as u16);
519 self.buf.put_slice(&s.as_bytes()[..len]);
520 }
521}
522
523impl Default for Amf0Encoder {
524 fn default() -> Self {
525 Self::new()
526 }
527}
528
529pub fn encode(value: &AmfValue) -> Bytes {
531 let mut encoder = Amf0Encoder::new();
532 encoder.encode(value);
533 encoder.finish()
534}
535
536pub fn encode_all(values: &[AmfValue]) -> Bytes {
538 let mut encoder = Amf0Encoder::new();
539 encoder.encode_all(values);
540 encoder.finish()
541}
542
543pub fn decode(data: &[u8]) -> Result<AmfValue, AmfError> {
545 let mut decoder = Amf0Decoder::new();
546 let mut buf = Bytes::copy_from_slice(data);
547 decoder.decode(&mut buf)
548}
549
550pub fn decode_all(data: &[u8]) -> Result<Vec<AmfValue>, AmfError> {
552 let mut decoder = Amf0Decoder::new();
553 let mut buf = Bytes::copy_from_slice(data);
554 decoder.decode_all(&mut buf)
555}
556
557#[cfg(test)]
558mod tests {
559 use super::*;
560
561 #[test]
562 fn test_number_roundtrip() {
563 let value = AmfValue::Number(42.5);
564 let encoded = encode(&value);
565 let decoded = decode(&encoded).unwrap();
566 assert_eq!(decoded, value);
567 }
568
569 #[test]
570 fn test_string_roundtrip() {
571 let value = AmfValue::String("hello world".into());
572 let encoded = encode(&value);
573 let decoded = decode(&encoded).unwrap();
574 assert_eq!(decoded, value);
575 }
576
577 #[test]
578 fn test_boolean_roundtrip() {
579 let value = AmfValue::Boolean(true);
580 let encoded = encode(&value);
581 let decoded = decode(&encoded).unwrap();
582 assert_eq!(decoded, value);
583 }
584
585 #[test]
586 fn test_null_roundtrip() {
587 let value = AmfValue::Null;
588 let encoded = encode(&value);
589 let decoded = decode(&encoded).unwrap();
590 assert_eq!(decoded, value);
591 }
592
593 #[test]
594 fn test_object_roundtrip() {
595 let mut props = HashMap::new();
596 props.insert("name".to_string(), AmfValue::String("test".into()));
597 props.insert("value".to_string(), AmfValue::Number(123.0));
598 let value = AmfValue::Object(props);
599
600 let encoded = encode(&value);
601 let decoded = decode(&encoded).unwrap();
602
603 if let (AmfValue::Object(orig), AmfValue::Object(dec)) = (&value, &decoded) {
605 assert_eq!(orig.len(), dec.len());
606 for (k, v) in orig {
607 assert_eq!(dec.get(k), Some(v));
608 }
609 } else {
610 panic!("Expected objects");
611 }
612 }
613
614 #[test]
615 fn test_array_roundtrip() {
616 let value = AmfValue::Array(vec![
617 AmfValue::Number(1.0),
618 AmfValue::String("two".into()),
619 AmfValue::Boolean(true),
620 ]);
621 let encoded = encode(&value);
622 let decoded = decode(&encoded).unwrap();
623 assert_eq!(decoded, value);
624 }
625
626 #[test]
627 fn test_multiple_values() {
628 let values = vec![
629 AmfValue::String("connect".into()),
630 AmfValue::Number(1.0),
631 AmfValue::Null,
632 ];
633
634 let encoded = encode_all(&values);
635 let decoded = decode_all(&encoded).unwrap();
636 assert_eq!(decoded, values);
637 }
638
639 #[test]
640 fn test_long_string() {
641 let long_str = "x".repeat(70000);
642 let value = AmfValue::String(long_str.clone());
643 let encoded = encode(&value);
644 let decoded = decode(&encoded).unwrap();
645 assert_eq!(decoded, AmfValue::String(long_str));
646 }
647
648 #[test]
649 fn test_undefined_roundtrip() {
650 let value = AmfValue::Undefined;
651 let encoded = encode(&value);
652 let decoded = decode(&encoded).unwrap();
653 assert_eq!(decoded, value);
654 }
655
656 #[test]
657 fn test_date_roundtrip() {
658 let timestamp = 1700000000000.0; let value = AmfValue::Date(timestamp);
660 let encoded = encode(&value);
661 let decoded = decode(&encoded).unwrap();
662 assert_eq!(decoded, AmfValue::Date(timestamp));
663 }
664
665 #[test]
666 fn test_ecma_array_roundtrip() {
667 let mut props = HashMap::new();
668 props.insert("width".to_string(), AmfValue::Number(1920.0));
669 props.insert("height".to_string(), AmfValue::Number(1080.0));
670 props.insert("codec".to_string(), AmfValue::String("h264".into()));
671 let value = AmfValue::EcmaArray(props);
672
673 let encoded = encode(&value);
674 let decoded = decode(&encoded).unwrap();
675
676 if let AmfValue::EcmaArray(dec_props) = decoded {
677 assert_eq!(dec_props.len(), 3);
678 assert_eq!(dec_props.get("width").unwrap().as_number(), Some(1920.0));
679 assert_eq!(dec_props.get("height").unwrap().as_number(), Some(1080.0));
680 assert_eq!(dec_props.get("codec").unwrap().as_str(), Some("h264"));
681 } else {
682 panic!("Expected EcmaArray");
683 }
684 }
685
686 #[test]
687 fn test_typed_object_roundtrip() {
688 let mut props = HashMap::new();
689 props.insert("x".to_string(), AmfValue::Number(100.0));
690 props.insert("y".to_string(), AmfValue::Number(200.0));
691 let value = AmfValue::TypedObject {
692 class_name: "Point".to_string(),
693 properties: props,
694 };
695
696 let encoded = encode(&value);
697 let decoded = decode(&encoded).unwrap();
698
699 if let AmfValue::TypedObject {
700 class_name,
701 properties,
702 } = decoded
703 {
704 assert_eq!(class_name, "Point");
705 assert_eq!(properties.len(), 2);
706 } else {
707 panic!("Expected TypedObject");
708 }
709 }
710
711 #[test]
712 fn test_xml_roundtrip() {
713 let xml = "<root><child>text</child></root>".to_string();
714 let value = AmfValue::Xml(xml.clone());
715 let encoded = encode(&value);
716 let decoded = decode(&encoded).unwrap();
717 assert_eq!(decoded, AmfValue::Xml(xml));
718 }
719
720 #[test]
721 fn test_nested_objects() {
722 let mut inner = HashMap::new();
723 inner.insert("key".to_string(), AmfValue::String("value".into()));
724
725 let mut outer = HashMap::new();
726 outer.insert("inner".to_string(), AmfValue::Object(inner));
727 outer.insert("count".to_string(), AmfValue::Number(5.0));
728
729 let value = AmfValue::Object(outer);
730 let encoded = encode(&value);
731 let decoded = decode(&encoded).unwrap();
732
733 if let AmfValue::Object(dec_outer) = decoded {
734 assert_eq!(dec_outer.len(), 2);
735 if let Some(AmfValue::Object(dec_inner)) = dec_outer.get("inner") {
736 assert_eq!(dec_inner.get("key").unwrap().as_str(), Some("value"));
737 } else {
738 panic!("Expected inner object");
739 }
740 } else {
741 panic!("Expected Object");
742 }
743 }
744
745 #[test]
746 fn test_integer_encoded_as_number() {
747 let value = AmfValue::Integer(42);
749 let encoded = encode(&value);
750 let decoded = decode(&encoded).unwrap();
751 assert_eq!(decoded, AmfValue::Number(42.0));
753 }
754
755 #[test]
756 fn test_byte_array_encoded_as_null() {
757 let value = AmfValue::ByteArray(vec![1, 2, 3, 4]);
759 let encoded = encode(&value);
760 let decoded = decode(&encoded).unwrap();
761 assert_eq!(decoded, AmfValue::Null);
762 }
763
764 #[test]
765 fn test_empty_string() {
766 let value = AmfValue::String(String::new());
767 let encoded = encode(&value);
768 let decoded = decode(&encoded).unwrap();
769 assert_eq!(decoded, AmfValue::String(String::new()));
770 }
771
772 #[test]
773 fn test_empty_object() {
774 let value = AmfValue::Object(HashMap::new());
775 let encoded = encode(&value);
776 let decoded = decode(&encoded).unwrap();
777 if let AmfValue::Object(props) = decoded {
778 assert!(props.is_empty());
779 } else {
780 panic!("Expected empty Object");
781 }
782 }
783
784 #[test]
785 fn test_empty_array() {
786 let value = AmfValue::Array(vec![]);
787 let encoded = encode(&value);
788 let decoded = decode(&encoded).unwrap();
789 if let AmfValue::Array(elems) = decoded {
790 assert!(elems.is_empty());
791 } else {
792 panic!("Expected empty Array");
793 }
794 }
795
796 #[test]
797 fn test_number_special_values() {
798 let value = AmfValue::Number(f64::NAN);
800 let encoded = encode(&value);
801 let decoded = decode(&encoded).unwrap();
802 if let AmfValue::Number(n) = decoded {
803 assert!(n.is_nan());
804 } else {
805 panic!("Expected Number");
806 }
807
808 let value = AmfValue::Number(f64::INFINITY);
810 let encoded = encode(&value);
811 let decoded = decode(&encoded).unwrap();
812 assert_eq!(decoded, AmfValue::Number(f64::INFINITY));
813
814 let value = AmfValue::Number(f64::NEG_INFINITY);
816 let encoded = encode(&value);
817 let decoded = decode(&encoded).unwrap();
818 assert_eq!(decoded, AmfValue::Number(f64::NEG_INFINITY));
819 }
820
821 #[test]
822 fn test_decoder_reset() {
823 let mut decoder = Amf0Decoder::new();
824
825 let value1 = AmfValue::String("test".into());
826 let mut buf1 = Bytes::copy_from_slice(&encode(&value1));
827 let _ = decoder.decode(&mut buf1).unwrap();
828
829 decoder.reset();
830
831 let value2 = AmfValue::Number(42.0);
832 let mut buf2 = Bytes::copy_from_slice(&encode(&value2));
833 let decoded = decoder.decode(&mut buf2).unwrap();
834 assert_eq!(decoded, value2);
835 }
836
837 #[test]
838 fn test_encoder_len_and_empty() {
839 let mut encoder = Amf0Encoder::new();
840 assert!(encoder.is_empty());
841 assert_eq!(encoder.len(), 0);
842
843 encoder.encode(&AmfValue::Null);
844 assert!(!encoder.is_empty());
845 assert!(encoder.len() > 0);
846 }
847
848 #[test]
849 fn test_encoder_with_capacity() {
850 let encoder = Amf0Encoder::with_capacity(1024);
851 assert!(encoder.is_empty());
852 }
853
854 #[test]
855 fn test_decode_empty_buffer() {
856 let result = decode(&[]);
857 assert!(matches!(result, Err(AmfError::UnexpectedEof)));
858 }
859
860 #[test]
861 fn test_decode_truncated_number() {
862 let data = [0x00, 0x40, 0x45]; let result = decode(&data);
865 assert!(matches!(result, Err(AmfError::UnexpectedEof)));
866 }
867
868 #[test]
869 fn test_decode_truncated_string() {
870 let data = [0x02, 0x00, 0x10]; let result = decode(&data);
873 assert!(matches!(result, Err(AmfError::UnexpectedEof)));
874 }
875
876 #[test]
877 fn test_lenient_mode_unknown_marker() {
878 let data = [0xFF]; let result = decode(&data).unwrap();
881 assert_eq!(result, AmfValue::Undefined);
882 }
883
884 #[test]
885 fn test_strict_mode_unknown_marker() {
886 let mut decoder = Amf0Decoder::with_lenient(false);
887 let mut buf = Bytes::from_static(&[0xFF]);
888 let result = decoder.decode(&mut buf);
889 assert!(matches!(result, Err(AmfError::UnknownMarker(0xFF))));
890 }
891
892 #[test]
893 fn test_nesting_depth_limit() {
894 let mut depth_test = AmfValue::Object(HashMap::new());
896 for _ in 0..70 {
897 let mut wrapper = HashMap::new();
898 wrapper.insert("nested".to_string(), depth_test);
899 depth_test = AmfValue::Object(wrapper);
900 }
901
902 let encoded = encode(&depth_test);
903 let result = decode(&encoded);
904 assert!(matches!(result, Err(AmfError::NestingTooDeep)));
905 }
906
907 #[test]
908 fn test_boolean_false() {
909 let value = AmfValue::Boolean(false);
910 let encoded = encode(&value);
911 let decoded = decode(&encoded).unwrap();
912 assert_eq!(decoded, AmfValue::Boolean(false));
913 }
914
915 #[test]
916 fn test_complex_rtmp_command() {
917 let mut cmd_obj = HashMap::new();
919 cmd_obj.insert("app".to_string(), AmfValue::String("live".into()));
920 cmd_obj.insert("type".to_string(), AmfValue::String("nonprivate".into()));
921 cmd_obj.insert("flashVer".to_string(), AmfValue::String("FMLE/3.0".into()));
922 cmd_obj.insert(
923 "tcUrl".to_string(),
924 AmfValue::String("rtmp://localhost/live".into()),
925 );
926 cmd_obj.insert("fpad".to_string(), AmfValue::Boolean(false));
927 cmd_obj.insert("audioCodecs".to_string(), AmfValue::Number(3575.0));
928 cmd_obj.insert("videoCodecs".to_string(), AmfValue::Number(252.0));
929 cmd_obj.insert("videoFunction".to_string(), AmfValue::Number(1.0));
930 cmd_obj.insert("objectEncoding".to_string(), AmfValue::Number(0.0));
931
932 let values = vec![
933 AmfValue::String("connect".into()),
934 AmfValue::Number(1.0),
935 AmfValue::Object(cmd_obj),
936 ];
937
938 let encoded = encode_all(&values);
939 let decoded = decode_all(&encoded).unwrap();
940
941 assert_eq!(decoded.len(), 3);
942 assert_eq!(decoded[0], AmfValue::String("connect".into()));
943 assert_eq!(decoded[1], AmfValue::Number(1.0));
944
945 if let AmfValue::Object(props) = &decoded[2] {
946 assert_eq!(props.get("app").unwrap().as_str(), Some("live"));
947 assert_eq!(props.get("audioCodecs").unwrap().as_number(), Some(3575.0));
948 } else {
949 panic!("Expected Object");
950 }
951 }
952}