#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::vec::Vec;
use core::str;
use nom::{
number::streaming::{be_f64, be_i16, be_u16, be_u32, be_u8},
IResult,
};
const SCRIPT_DATA_VALUE_STRING_TYPE: [u8; 1] = [0x02];
const OBJECT_END_MARKER: [u8; 3] = [0x00, 0x00, 0x09];
#[derive(Clone, Debug, PartialEq)]
pub struct ScriptTag<'a> {
pub name: &'a str,
pub value: ScriptDataValue<'a>,
}
impl<'a> ScriptTag<'a> {
pub fn parse(input: &'a [u8], _size: usize) -> IResult<&'a [u8], ScriptTag<'a>> {
do_parse!(
input,
tag!(SCRIPT_DATA_VALUE_STRING_TYPE) >>
name: call!(ScriptDataValue::parse_string) >>
value: call!(ScriptDataValue::parse) >>
(ScriptTag { name, value })
)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ScriptDataValue<'a> {
Number(f64),
Boolean(bool),
String(&'a str),
Object(Vec<ScriptDataObjectProperty<'a>>),
MovieClip,
Null,
Undefined,
Reference(u16),
ECMAArray(Vec<ScriptDataObjectProperty<'a>>),
StrictArray(Vec<ScriptDataValue<'a>>),
Date(ScriptDataDate),
LongString(&'a str),
}
impl<'a> ScriptDataValue<'a> {
pub fn parse(input: &'a [u8]) -> IResult<&'a [u8], ScriptDataValue<'a>> {
switch!(input,
be_u8,
0 => map!(Self::parse_number, ScriptDataValue::Number) |
1 => map!(Self::parse_boolean, |v| ScriptDataValue::Boolean(v != 0)) |
2 => map!(Self::parse_string, ScriptDataValue::String) |
3 => map!(Self::parse_object, ScriptDataValue::Object) |
4 => value!(ScriptDataValue::MovieClip) |
5 => value!(ScriptDataValue::Null) |
6 => value!(ScriptDataValue::Undefined) |
7 => map!(Self::parse_reference, ScriptDataValue::Reference) |
8 => map!(Self::parse_ecma_array, ScriptDataValue::ECMAArray) |
10 => map!(Self::parse_strict_array, ScriptDataValue::StrictArray) |
11 => map!(Self::parse_date, ScriptDataValue::Date) |
12 => map!(Self::parse_long_string, ScriptDataValue::LongString)
)
}
pub fn parse_number(input: &[u8]) -> IResult<&[u8], f64> {
be_f64(input)
}
pub fn parse_boolean(input: &[u8]) -> IResult<&[u8], u8> {
be_u8(input)
}
pub fn parse_string(input: &[u8]) -> IResult<&[u8], &str> {
map_res!(input, length_data!(be_u16), str::from_utf8)
}
pub fn parse_object(input: &'a [u8]) -> IResult<&'a [u8], Vec<ScriptDataObjectProperty<'a>>> {
terminated!(
input,
many0!(Self::parse_object_property),
call!(Self::parse_object_end_marker)
)
}
fn parse_object_property(input: &'a [u8]) -> IResult<&'a [u8], ScriptDataObjectProperty<'a>> {
do_parse!(
input,
name: call!(Self::parse_string) >>
value: call!(Self::parse) >>
(ScriptDataObjectProperty { name, value })
)
}
fn parse_object_end_marker(input: &[u8]) -> IResult<&[u8], &[u8]> {
tag!(input, OBJECT_END_MARKER)
}
pub fn parse_reference(input: &[u8]) -> IResult<&[u8], u16> {
be_u16(input)
}
pub fn parse_ecma_array(
input: &'a [u8],
) -> IResult<&'a [u8], Vec<ScriptDataObjectProperty<'a>>> {
do_parse!(
input,
_length: be_u32 >>
object: call!(Self::parse_object) >>
(object)
)
}
pub fn parse_strict_array(input: &'a [u8]) -> IResult<&'a [u8], Vec<ScriptDataValue<'a>>> {
do_parse!(
input,
length: be_u32 >>
value: count!(call!(Self::parse), length as usize) >>
(value)
)
}
pub fn parse_date(input: &[u8]) -> IResult<&[u8], ScriptDataDate> {
do_parse!(
input,
date_time: be_f64 >>
local_date_time_offset: be_i16 >>
(ScriptDataDate { date_time, local_date_time_offset })
)
}
pub fn parse_long_string(input: &[u8]) -> IResult<&[u8], &str> {
map_res!(input, length_data!(be_u32), str::from_utf8)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct ScriptDataObjectProperty<'a> {
pub name: &'a str,
pub value: ScriptDataValue<'a>,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct ScriptDataDate {
pub date_time: f64,
pub local_date_time_offset: i16,
}