xref: /xiu/protocol/rtmp/src/amf0/amf0_reader.rs (revision 7adc8486)
1 use std::collections::HashMap;
2 
3 use super::amf0_markers;
4 use super::Amf0ReadError;
5 use super::Amf0ValueType;
6 use byteorder::BigEndian;
7 use bytes::BytesMut;
8 
9 // use super::define::UnOrderedMap;
10 
11 use super::errors::Amf0ReadErrorValue;
12 use netio::bytes_reader::BytesReader;
13 
14 pub struct Amf0Reader {
15     reader: BytesReader,
16 }
17 
18 impl Amf0Reader {
19     pub fn new(reader: BytesReader) -> Self {
20         Self { reader: reader }
21     }
22     pub fn read_all(&mut self) -> Result<Vec<Amf0ValueType>, Amf0ReadError> {
23         let mut results = vec![];
24 
25         loop {
26             let result = self.read_any()?;
27 
28             match result {
29                 Amf0ValueType::END => {
30                     break;
31                 }
32                 _ => {
33                     results.push(result);
34                 }
35             }
36         }
37 
38         Ok(results)
39     }
40     pub fn read_any(&mut self) -> Result<Amf0ValueType, Amf0ReadError> {
41         if self.reader.len() == 0 {
42             return Ok(Amf0ValueType::END);
43         }
44         let markers = self.reader.read_u8()?;
45 
46         if markers == amf0_markers::OBJECT_END {
47             return Ok(Amf0ValueType::END);
48         }
49 
50         match markers {
51             amf0_markers::NUMBER => self.read_number(),
52             amf0_markers::BOOLEAN => self.read_bool(),
53             amf0_markers::STRING => self.read_string(),
54             amf0_markers::OBJECT => self.read_object(),
55             amf0_markers::NULL => self.read_null(),
56             amf0_markers::ECMA_ARRAY => self.read_ecma_array(),
57             amf0_markers::LONG_STRING => self.read_long_string(),
58             _ => Err(Amf0ReadError {
59                 value: Amf0ReadErrorValue::UnknownMarker { marker: markers },
60             }),
61         }
62     }
63     pub fn read_with_type(&mut self, specified_marker: u8) -> Result<Amf0ValueType, Amf0ReadError> {
64         let marker = self.reader.advance_u8()?;
65 
66         if marker != specified_marker {
67             return Err(Amf0ReadError {
68                 value: Amf0ReadErrorValue::WrongType,
69             });
70         }
71 
72         return self.read_any();
73     }
74 
75     pub fn read_number(&mut self) -> Result<Amf0ValueType, Amf0ReadError> {
76         let number = self.reader.read_f64::<BigEndian>()?;
77         let value = Amf0ValueType::Number(number);
78         Ok(value)
79     }
80 
81     pub fn read_bool(&mut self) -> Result<Amf0ValueType, Amf0ReadError> {
82         let value = self.reader.read_u8()?;
83 
84         match value {
85             1 => Ok(Amf0ValueType::Boolean(true)),
86             _ => Ok(Amf0ValueType::Boolean(false)),
87         }
88     }
89 
90     pub fn read_raw_string(&mut self) -> Result<String, Amf0ReadError> {
91         let l = self.reader.read_u16::<BigEndian>()?;
92         // let mut buffer: Vec<u8> = vec![0_u8; l as usize];
93         let bytes = self.reader.read_bytes(l as usize)?;
94 
95         // let mut vec_bytes = bytes.to_vec();
96         // let length_before = vec_bytes.len();
97         // vec_bytes.retain(|&x| x <= 127);
98         // let length_after = vec_bytes.len();
99 
100         // let num = length_before - length_after;
101         // if num > 0 {
102         //     let mut bytes2 = self.reader.read_bytes(num)?;
103 
104         //     vec_bytes.append(&mut bytes2.to_vec());
105         // }
106 
107         let val = String::from_utf8(bytes.to_vec())?;
108 
109         Ok(val)
110     }
111 
112     pub fn read_string(&mut self) -> Result<Amf0ValueType, Amf0ReadError> {
113         let raw_string = self.read_raw_string()?;
114         Ok(Amf0ValueType::UTF8String(raw_string))
115     }
116 
117     pub fn read_null(&mut self) -> Result<Amf0ValueType, Amf0ReadError> {
118         Ok(Amf0ValueType::Null)
119     }
120 
121     pub fn is_read_object_eof(&mut self) -> Result<bool, Amf0ReadError> {
122         let marker = self.reader.advance_u24::<BigEndian>()?;
123         if marker == amf0_markers::OBJECT_END as u32 {
124             self.reader.read_u24::<BigEndian>()?;
125             return Ok(true);
126         }
127         Ok(false)
128     }
129 
130     pub fn read_object(&mut self) -> Result<Amf0ValueType, Amf0ReadError> {
131         let mut properties = HashMap::new();
132 
133         loop {
134             let is_eof = self.is_read_object_eof()?;
135 
136             if is_eof {
137                 break;
138             }
139 
140             let key = self.read_raw_string()?;
141             let val = self.read_any()?;
142 
143             properties.insert(key, val);
144         }
145 
146         Ok(Amf0ValueType::Object(properties))
147     }
148 
149     pub fn read_ecma_array(&mut self) -> Result<Amf0ValueType, Amf0ReadError> {
150         let len = self.reader.read_u32::<BigEndian>()?;
151 
152         let mut properties = HashMap::new();
153 
154         for _ in 0..len {
155             let key = self.read_raw_string()?;
156             let val = self.read_any()?;
157             properties.insert(key, val);
158         }
159 
160         self.is_read_object_eof()?;
161 
162         Ok(Amf0ValueType::Object(properties))
163     }
164 
165     pub fn read_long_string(&mut self) -> Result<Amf0ValueType, Amf0ReadError> {
166         let l = self.reader.read_u32::<BigEndian>()?;
167 
168         let buff = self.reader.read_bytes(l as usize)?;
169 
170         let val = String::from_utf8(buff.to_vec())?;
171         Ok(Amf0ValueType::LongUTF8String(val))
172     }
173 
174     pub fn get_remaining_bytes(&mut self) -> BytesMut {
175         return self.reader.get_remaining_bytes();
176     }
177 }
178 
179 #[cfg(test)]
180 mod tests {
181 
182     #[test]
183     fn test_byte_order() {
184         use byteorder::{BigEndian, ByteOrder};
185 
186         let phi = 1.6180339887;
187         let mut buf = [0; 8];
188         BigEndian::write_f64(&mut buf, phi);
189         assert_eq!(phi, BigEndian::read_f64(&buf));
190         println!("tsetstt")
191     }
192 
193     use super::amf0_markers;
194     use super::Amf0Reader;
195     use super::Amf0ValueType;
196     use bytes::BytesMut;
197     use netio::bytes_reader::BytesReader;
198     use std::collections::HashMap;
199 
200     #[test]
201     fn test_amf_reader() {
202         let data: [u8; 177] = [
203             2, 0, 7, 99, 111, 110, 110, 101, 99, 116, 0, 63, 240, 0, 0, 0, 0, 0, 0, //body
204             3, 0, 3, 97, 112, 112, 2, 0, 6, 104, 97, 114, 108, 97, 110, 0, 4, 116, 121, 112, 101,
205             2, 0, 10, 110, 111, 110, 112, 114, 105, 118, 97, 116, 101, 0, 8, 102, 108, 97, 115,
206             104, 86, 101, 114, 2, 0, 31, 70, 77, 76, 69, 47, 51, 46, 48, 32, 40, 99, 111, 109, 112,
207             97, 116, 105, 98, 108, 101, 59, 32, 70, 77, 83, 99, 47, 49, 46, 48, 41, 0, 6, 115, 119,
208             102, 85, 114, 108, 2, 0, 28, 114, 116, 109, 112, 58, 47, 47, 108, 111, 99, 97, 108,
209             104, 111, 115, 116, 58, 49, 57, 51, 53, 47, 104, 97, 114, 108, 97, 110, 0, 5, 116, 99,
210             85, 114, 108, 2, 0, 28, 114, 116, 109, 112, 58, 47, 47, 108, 111, 99, 97, 108, 104,
211             111, 115, 116, 58, 49, 57, 51, 53, 47, 104, 97, 114, 108, 97, 110, 0, 0, 9,
212         ];
213 
214         let mut bytes_reader = BytesReader::new(BytesMut::new());
215         bytes_reader.extend_from_slice(&data);
216         let mut amf_reader = Amf0Reader::new(bytes_reader);
217 
218         let command_name = amf_reader.read_with_type(amf0_markers::STRING).unwrap();
219         assert_eq!(
220             command_name,
221             Amf0ValueType::UTF8String(String::from("connect"))
222         );
223 
224         let transaction_id = amf_reader.read_with_type(amf0_markers::NUMBER).unwrap();
225         assert_eq!(transaction_id, Amf0ValueType::Number(1.0));
226 
227         let command_obj_raw = amf_reader.read_with_type(amf0_markers::OBJECT).unwrap();
228         let mut properties = HashMap::new();
229         properties.insert(
230             String::from("app"),
231             Amf0ValueType::UTF8String(String::from("harlan")),
232         );
233         properties.insert(
234             String::from("type"),
235             Amf0ValueType::UTF8String(String::from("nonprivate")),
236         );
237         properties.insert(
238             String::from("flashVer"),
239             Amf0ValueType::UTF8String(String::from("FMLE/3.0 (compatible; FMSc/1.0)")),
240         );
241         properties.insert(
242             String::from("swfUrl"),
243             Amf0ValueType::UTF8String(String::from("rtmp://localhost:1935/harlan")),
244         );
245         properties.insert(
246             String::from("tcUrl"),
247             Amf0ValueType::UTF8String(String::from("rtmp://localhost:1935/harlan")),
248         );
249         assert_eq!(command_obj_raw, Amf0ValueType::Object(properties));
250 
251         let others = amf_reader.read_all();
252 
253         print!("test")
254     }
255 
256     #[test]
257     fn test_player_connect_reader() {
258         // chunk header
259         // 0000   03 00 00 00 00 00 aa 14 00 00 00 00
260         //amf0 data
261         //                                            02 00 07 63  ...............c
262         // 0010   6f 6e 6e 65 63 74 00 3f f0 00 00 00 00 00 00 03  onnect.?........
263         // 0020   00 03 61 70 70 02 00 04 6c 69 76 65 00 05 74 63  ..app...live..tc
264         // 0030   55 72 6c 02 00 1a 72 74 6d 70 3a 2f 2f 6c 6f 63  Url...rtmp://loc
265         // 0040   61 6c 68 6f 73 74 3a 31 39 33 35 2f 6c 69 76 65  alhost:1935/live
266         // 0050   00 04 66 70 61 64 01 00 00 0c 63 61 70 61 62 69  ..fpad....capabi
267         // 0060   6c 69 74 69 65 73 00 40 2e 00 00 00 00 00 00 00  lities.@........
268         // 0070   0b 61 75 64 69 6f 43 6f 64 65 63 73 00 40 a8 ee  .audioCodecs.@..
269         // 0080   00 00 00 00 00 00 0b 76 69 64 65 6f 43 6f 64 65  .......videoCode 118 105
270         // 0090   63 73 00 40 6f 80 00 00 00 00 00 00 0d 76 69 64  [email protected]
271         // 00a0   65 6f 46 75 6e 63 74 69 6f 6e 00 3f f0 00 00 00  eoFunction.?....
272         // 0b00   00 00 00 00 00 09                                ......
273 
274         let data: [u8; 171] = [
275             2, 0, 7, 99, 111, 110, 110, 101, 99, 116, 0, 63, 240, 0, 0, 0, 0, 0, 0, 3, 0, 3, 97,
276             112, 112, 2, 0, 4, 108, 105, 118, 101, 0, 5, 116, 99, 85, 114, 108, 2, 0, 26, 114, 116,
277             109, 112, 58, 47, 47, 108, 111, 99, 97, 108, 104, 111, 115, 116, 58, 49, 57, 51, 53,
278             47, 108, 105, 118, 101, 0, 4, 102, 112, 97, 100, 1, 0, 0, 12, 99, 97, 112, 97, 98, 105,
279             108, 105, 116, 105, 101, 115, 0, 64, 46, 0, 0, 0, 0, 0, 0, 0, 11, 97, 117, 100, 105,
280             111, 67, 111, 100, 101, 99, 115, 0, 64, 168, 238, 0, 0, 0, 0, 0, 0, 11, 118, 105, 100,
281             101, 111, 195, 67, 111, 100, 101, 99, 115, 0, 64, 111, 128, 0, 0, 0, 0, 0, 0, 13, 118,
282             105, 100, 101, 111, 70, 117, 110, 99, 116, 105, 111, 110, 0, 63, 240, 0, 0, 0, 0, 0, 0,
283             0, 0, 9,
284         ];
285 
286         //76 69 64 65 6f 43 6f 64 65 63 73
287         // 118 105 100 101  111 67 111 100 101 99 115
288 
289         let mut bytes_reader = BytesReader::new(BytesMut::new());
290         bytes_reader.extend_from_slice(&data);
291         let mut amf_reader = Amf0Reader::new(bytes_reader);
292 
293         let command_name = amf_reader.read_with_type(amf0_markers::STRING).unwrap();
294         assert_eq!(
295             command_name,
296             Amf0ValueType::UTF8String(String::from("connect"))
297         );
298 
299         let transaction_id = amf_reader.read_with_type(amf0_markers::NUMBER).unwrap();
300         assert_eq!(transaction_id, Amf0ValueType::Number(1.0));
301 
302         let command_obj_raw = amf_reader.read_with_type(amf0_markers::OBJECT);
303         let mut properties = HashMap::new();
304         properties.insert(
305             String::from("app"),
306             Amf0ValueType::UTF8String(String::from("live")),
307         );
308         properties.insert(
309             String::from("tcUrl"),
310             Amf0ValueType::UTF8String(String::from("rtmp://localhost:1935/live")),
311         );
312         properties.insert(String::from("fpad"), Amf0ValueType::Boolean(false));
313         properties.insert(String::from("capabilities"), Amf0ValueType::Number(15.0));
314         properties.insert(String::from("audioCodecs"), Amf0ValueType::Number(3191.0));
315 
316         properties.insert(String::from("videoCodecs"), Amf0ValueType::Number(252.0));
317 
318         properties.insert(String::from("videoFunction"), Amf0ValueType::Number(1.0));
319 
320         assert_eq!(command_obj_raw.unwrap(), Amf0ValueType::Object(properties));
321     }
322 }
323