use byteorder::{BigEndian, ReadBytesExt};
use errors::Amf0DeserializationError;
use markers;
use std::collections::HashMap;
use std::io::Read;
use Amf0Value;
struct ObjectProperty {
label: String,
value: Amf0Value,
}
pub fn deserialize<R: Read>(bytes: &mut R) -> Result<Vec<Amf0Value>, Amf0DeserializationError> {
let mut results = vec![];
loop {
match read_next_value(bytes)? {
Some(x) => results.push(x),
None => break,
};
}
Ok(results)
}
fn read_next_value<R: Read>(bytes: &mut R) -> Result<Option<Amf0Value>, Amf0DeserializationError> {
let mut buffer: [u8; 1] = [0];
let bytes_read = bytes.read(&mut buffer)?;
if bytes_read == 0 {
return Ok(None);
}
if buffer[0] == markers::OBJECT_END_MARKER {
return Ok(None);
}
match buffer[0] {
markers::BOOLEAN_MARKER => parse_bool(bytes).map(Some),
markers::NULL_MARKER => parse_null().map(Some),
markers::UNDEFINED_MARKER => parse_undefined().map(Some),
markers::NUMBER_MARKER => parse_number(bytes).map(Some),
markers::OBJECT_MARKER => parse_object(bytes).map(Some),
markers::ECMA_ARRAY_MARKER => parse_ecma_array(bytes).map(Some),
markers::STRING_MARKER => parse_string(bytes).map(Some),
markers::STRICT_ARRAY_MARKER => parse_strict_array(bytes).map(Some),
_ => Err(Amf0DeserializationError::UnknownMarker { marker: buffer[0] }),
}
}
fn parse_number<R: Read>(bytes: &mut R) -> Result<Amf0Value, Amf0DeserializationError> {
let number = bytes.read_f64::<BigEndian>()?;
let value = Amf0Value::Number(number);
Ok(value)
}
fn parse_null() -> Result<Amf0Value, Amf0DeserializationError> {
Ok(Amf0Value::Null)
}
fn parse_undefined() -> Result<Amf0Value, Amf0DeserializationError> {
Ok(Amf0Value::Undefined)
}
fn parse_bool<R: Read>(bytes: &mut R) -> Result<Amf0Value, Amf0DeserializationError> {
let value = bytes.read_u8()?;
if value == 1 {
Ok(Amf0Value::Boolean(true))
} else {
Ok(Amf0Value::Boolean(false))
}
}
fn parse_string<R: Read>(bytes: &mut R) -> Result<Amf0Value, Amf0DeserializationError> {
let length = bytes.read_u16::<BigEndian>()?;
let mut buffer: Vec<u8> = vec![0_u8; length as usize];
bytes.read(&mut buffer)?;
let value = String::from_utf8(buffer)?;
Ok(Amf0Value::Utf8String(value))
}
fn parse_object<R: Read>(bytes: &mut R) -> Result<Amf0Value, Amf0DeserializationError> {
let mut properties = HashMap::new();
loop {
match parse_object_property(bytes)? {
Some(property) => properties.insert(property.label, property.value),
None => break,
};
}
let deserialized_value = Amf0Value::Object(properties);
Ok(deserialized_value)
}
fn parse_ecma_array<R: Read>(bytes: &mut R) -> Result<Amf0Value, Amf0DeserializationError> {
let _associative_count = bytes.read_u32::<BigEndian>()?;
parse_object(bytes)
}
fn parse_strict_array<R: Read>(bytes: &mut R) -> Result<Amf0Value, Amf0DeserializationError> {
let _array_count = bytes.read_u32::<BigEndian>()?;
let mut values: Vec<Amf0Value> = Vec::new();
for _ in 0.._array_count {
match read_next_value(bytes)? {
Some(value) => {
values.push(value);
}
None => break,
};
}
Ok(Amf0Value::StrictArray(values))
}
fn parse_object_property<R: Read>(
bytes: &mut R,
) -> Result<Option<ObjectProperty>, Amf0DeserializationError> {
let label_length = bytes.read_u16::<BigEndian>()?;
if label_length == 0 {
let byte = bytes.read_u8()?;
if byte != markers::OBJECT_END_MARKER {
return Err(Amf0DeserializationError::UnexpectedEmptyObjectPropertyName);
}
return Ok(None);
}
let mut label_buffer = vec![0; label_length as usize];
bytes.read(&mut label_buffer)?;
let label = String::from_utf8(label_buffer)?;
match read_next_value(bytes)? {
None => Err(Amf0DeserializationError::UnexpectedEof),
Some(property_value) => Ok(Some(ObjectProperty {
label,
value: property_value,
})),
}
}
#[cfg(test)]
mod tests {
use super::super::Amf0Value;
use super::deserialize;
use byteorder::{BigEndian, WriteBytesExt};
use markers;
use std::collections::HashMap;
use std::io::Cursor;
#[test]
fn can_deserialize_strict_array() {
let mut vector = vec![];
vector.push(markers::STRICT_ARRAY_MARKER);
vector.write_u32::<BigEndian>(2).unwrap();
vector.push(markers::NUMBER_MARKER);
vector.write_f64::<BigEndian>(1.0).unwrap();
vector.push(markers::NUMBER_MARKER);
vector.write_f64::<BigEndian>(2.0).unwrap();
let mut input = Cursor::new(vector);
let result = deserialize(&mut input).unwrap();
let mut array = Vec::new();
array.push(Amf0Value::Number(1.0));
array.push(Amf0Value::Number(2.0));
let expected = vec![Amf0Value::StrictArray(array)];
assert_eq!(result, expected);
}
#[test]
fn can_deserialize_number() {
let number: f64 = 332.0;
let mut vector = vec![];
vector.write_u8(markers::NUMBER_MARKER).unwrap();
vector.write_f64::<BigEndian>(number).unwrap();
let mut input = Cursor::new(vector);
let result = deserialize(&mut input).unwrap();
let expected = vec![Amf0Value::Number(number)];
assert_eq!(result, expected);
}
#[test]
fn can_deserialize_true_boolean() {
let mut vector = vec![];
vector.write_u8(markers::BOOLEAN_MARKER).unwrap();
vector.write_u8(1).unwrap();
let mut input = Cursor::new(vector);
let result = deserialize(&mut input).unwrap();
let expected = vec![Amf0Value::Boolean(true)];
assert_eq!(result, expected);
}
#[test]
fn can_deserialize_false_boolean() {
let mut vector = vec![];
vector.write_u8(markers::BOOLEAN_MARKER).unwrap();
vector.write_u8(0).unwrap();
let mut input = Cursor::new(vector);
let result = deserialize(&mut input).unwrap();
let expected = vec![Amf0Value::Boolean(false)];
assert_eq!(result, expected);
}
#[test]
fn can_deserialize_string() {
let value = "test";
let mut vector = vec![];
vector.write_u8(markers::STRING_MARKER).unwrap();
vector.write_u16::<BigEndian>(value.len() as u16).unwrap();
vector.extend(value.as_bytes());
let mut input = Cursor::new(vector);
let result = deserialize(&mut input).unwrap();
let expected = vec![Amf0Value::Utf8String(value.to_string())];
assert_eq!(result, expected);
}
#[test]
fn can_deserialize_null() {
let mut vector = vec![];
vector.write_u8(markers::NULL_MARKER).unwrap();
let mut input = Cursor::new(vector);
let result = deserialize(&mut input).unwrap();
let expected = vec![Amf0Value::Null];
assert_eq!(result, expected);
}
#[test]
fn can_deserialize_object() {
const NUMBER: f64 = 332.0;
let mut vector = vec![];
vector.push(markers::OBJECT_MARKER);
vector.write_u16::<BigEndian>(4).unwrap();
vector.extend("test".as_bytes());
vector.push(markers::NUMBER_MARKER);
vector.write_f64::<BigEndian>(NUMBER).unwrap();
vector
.write_u16::<BigEndian>(markers::UTF_8_EMPTY_MARKER)
.unwrap();
vector.push(markers::OBJECT_END_MARKER);
let mut input = Cursor::new(vector);
let result = deserialize(&mut input).unwrap();
let mut properties = HashMap::new();
properties.insert("test".to_string(), Amf0Value::Number(NUMBER));
let expected = vec![Amf0Value::Object(properties)];
assert_eq!(result, expected);
}
#[test]
fn can_deserialize_emca_array() {
let mut vector = vec![];
vector.push(markers::ECMA_ARRAY_MARKER);
vector.write_u32::<BigEndian>(2).unwrap();
vector.write_u16::<BigEndian>(5).unwrap();
vector.extend("test1".as_bytes());
vector.push(markers::NUMBER_MARKER);
vector.write_f64::<BigEndian>(1.0).unwrap();
vector.write_u16::<BigEndian>(5).unwrap();
vector.extend("test2".as_bytes());
vector.write_u8(markers::STRING_MARKER).unwrap();
vector.write_u16::<BigEndian>(6).unwrap();
vector.extend("second".as_bytes());
vector
.write_u16::<BigEndian>(markers::UTF_8_EMPTY_MARKER)
.unwrap();
vector.push(markers::OBJECT_END_MARKER);
let mut input = Cursor::new(vector);
let result = deserialize(&mut input).unwrap();
let mut properties = HashMap::new();
properties.insert("test1".to_string(), Amf0Value::Number(1.0));
properties.insert(
"test2".to_string(),
Amf0Value::Utf8String("second".to_string()),
);
let expected = vec![Amf0Value::Object(properties)];
assert_eq!(result, expected);
}
#[test]
fn can_deserialize_undefined() {
let mut vector = vec![];
vector.write_u8(markers::UNDEFINED_MARKER).unwrap();
let mut input = Cursor::new(vector);
let result = deserialize(&mut input).unwrap();
let expected = vec![Amf0Value::Undefined];
assert_eq!(result, expected);
}
}