1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
use cookie_factory::lib::std::fmt::Formatter;
use core::fmt;
use derive_try_from_primitive::TryFromPrimitive;
use enumset::EnumSet;
use enumset::EnumSetType;
use std::cell::RefCell;
use std::rc::Rc;

/// A container for sol files
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq)]
pub struct Sol {
    pub header: SolHeader,
    pub body: Vec<SolElement>,
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(TryFromPrimitive, Eq, PartialEq, Debug, Copy, Clone)]
#[repr(u8)]
pub enum AMFVersion {
    AMF0 = 0,
    AMF3 = 3,
}

impl fmt::Display for AMFVersion {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            AMFVersion::AMF0 => f.write_str("AMF0"),
            AMFVersion::AMF3 => f.write_str("AMF3"),
        }
    }
}

/// The header of a sol file
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq)]
pub struct SolHeader {
    pub length: u32,
    pub name: String,
    pub format_version: AMFVersion,
}

pub type Element = Rc<RefCell<SolValue>>;

/// Represent a named element
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq)]
pub struct SolElement {
    pub name: String,
    pub value: Element,
}

//TODO: should amf3 assoc arrays be their own type with a dense and assoc section
/// A single or compound value
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq)]
pub enum SolValue {
    /// Represent the type number (amf0) and double (amf3)
    Number(f64),
    /// Represents the type boolean (amf0) and both the true/false type (amf3)
    Bool(bool),
    /// Represent both the string (amf0/3) and long string type (amf0)
    String(String),
    Object(Vec<SolElement>, Option<ClassDefinition>),
    /// Represent the null type
    Null,
    /// Represent the undefined type
    Undefined,
    /// Represent ECMA-Arrays (amf0) and associative arrays (amf3, even if they contain a dense part)
    /// Final value represents the length of the array in amf0, this can differ from the actual number of elements
    ECMAArray(Vec<Element>, Vec<SolElement>, u32),
    /// Represent a strict array (amf0) or a dense array (amf3)
    StrictArray(Vec<Element>),
    /// Represent a timezone in the format (seconds since epoch, timezone or UTC if missing (amf3) )
    Date(f64, Option<u16>),
    /// Represent the unsupported type
    Unsupported,
    /// Represent the XML type, (value, is_string)
    XML(String, bool),
    /// Represent an amf3 element embedded in an AMF0 file
    AMF3(Element),
    // AMF3
    /// Represent the integer type (u29) (amf3)
    Integer(i32),
    /// Represent the bytearray type (amf3)
    ByteArray(Vec<u8>),
    /// Represent the int vector type (amf3)
    /// Format is (values, is_fixed_length)
    VectorInt(Vec<i32>, bool),
    /// Represent the unsigned int vector type (amf3)
    /// Format is (values, is_fixed_length)
    VectorUInt(Vec<u32>, bool),
    /// Represent the double vector type (amf3)
    /// Format is (values, is_fixed_length)
    VectorDouble(Vec<f64>, bool),
    /// Represent the object vector type (amf3)
    /// Format is (values, is_fixed_length)
    VectorObject(Vec<Element>, String, bool),
    /// Represent the dictionary type (amf3)
    /// Format is ((key, value), has_weak_keys)
    Dictionary(Vec<(Element, Element)>, bool),
    /// Represent a external object, such as from flex
    /// (custom_elements, regular elements, class def)
    Custom(Vec<SolElement>, Vec<SolElement>, Option<ClassDefinition>),
}

/// A class definition (trait) used in AMF3
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ClassDefinition {
    pub name: String,
    pub attributes: EnumSet<Attribute>,
    pub attribute_count: u32,
    pub static_properties: Vec<String>,
}

impl Default for ClassDefinition {
    fn default() -> Self {
        Self {
            name: "Object".to_string(),
            attributes: EnumSet::empty(),
            attribute_count: 0,
            static_properties: Vec::new(),
        }
    }
}

impl ClassDefinition {
    pub fn default_with_name(name: String) -> Self {
        Self {
            name,
            attributes: EnumSet::empty(),
            attribute_count: 0,
            static_properties: Vec::new(),
        }
    }
}

/// Encodes the possible attributes that can be given to a trait
/// If a trait is dynamic then the object may have additional properties other than the ones specified in the trait
/// If a trait is external then it requires custom serialization and deserialization support
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(EnumSetType, Debug)]
pub enum Attribute {
    DYNAMIC,
    EXTERNAL,
}

pub mod amf0 {
    use derive_try_from_primitive::TryFromPrimitive;

    /// Type markers used in AMF0
    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
    #[derive(TryFromPrimitive, Eq, PartialEq, Debug, Copy, Clone)]
    #[repr(u8)]
    pub enum TypeMarker {
        Number = 0,
        Boolean = 1,
        String = 2,
        Object = 3,
        MovieClip = 4,
        Null = 5,
        Undefined = 6,
        Reference = 7,
        MixedArrayStart = 8,
        ObjectEnd = 9,
        Array = 10,
        Date = 11,
        LongString = 12,
        Unsupported = 13,
        RecordSet = 14,
        XML = 15,
        TypedObject = 16,
        AMF3 = 17,
    }
}

pub mod amf3 {
    use derive_try_from_primitive::TryFromPrimitive;

    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
    #[derive(TryFromPrimitive, Eq, PartialEq, Debug, Copy, Clone)]
    #[repr(u8)]
    pub enum TypeMarker {
        Undefined = 0x00,
        Null = 0x01,
        False = 0x02,
        True = 0x03,
        Integer = 0x04,
        Number = 0x05,
        String = 0x06,
        XML = 0x07,
        Date = 0x08,
        Array = 0x09,
        Object = 0x0A,
        XmlString = 0x0B,
        ByteArray = 0x0C,
        VectorInt = 0x0D,
        VectorUInt = 0x0E,
        VectorDouble = 0x0F,
        VectorObject = 0x10,
        Dictionary = 0x11,
    }
}