mirror of https://github.com/gwuhaolin/livego.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
497 lines
12 KiB
497 lines
12 KiB
package amf |
|
|
|
import ( |
|
"encoding/binary" |
|
"fmt" |
|
"io" |
|
"time" |
|
) |
|
|
|
// amf3 polymorphic router |
|
func (d *Decoder) DecodeAmf3(r io.Reader) (interface{}, error) { |
|
marker, err := ReadMarker(r) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
switch marker { |
|
case AMF3_UNDEFINED_MARKER: |
|
return d.DecodeAmf3Undefined(r, false) |
|
case AMF3_NULL_MARKER: |
|
return d.DecodeAmf3Null(r, false) |
|
case AMF3_FALSE_MARKER: |
|
return d.DecodeAmf3False(r, false) |
|
case AMF3_TRUE_MARKER: |
|
return d.DecodeAmf3True(r, false) |
|
case AMF3_INTEGER_MARKER: |
|
return d.DecodeAmf3Integer(r, false) |
|
case AMF3_DOUBLE_MARKER: |
|
return d.DecodeAmf3Double(r, false) |
|
case AMF3_STRING_MARKER: |
|
return d.DecodeAmf3String(r, false) |
|
case AMF3_XMLDOC_MARKER: |
|
return d.DecodeAmf3Xml(r, false) |
|
case AMF3_DATE_MARKER: |
|
return d.DecodeAmf3Date(r, false) |
|
case AMF3_ARRAY_MARKER: |
|
return d.DecodeAmf3Array(r, false) |
|
case AMF3_OBJECT_MARKER: |
|
return d.DecodeAmf3Object(r, false) |
|
case AMF3_XMLSTRING_MARKER: |
|
return d.DecodeAmf3Xml(r, false) |
|
case AMF3_BYTEARRAY_MARKER: |
|
return d.DecodeAmf3ByteArray(r, false) |
|
} |
|
|
|
return nil, fmt.Errorf("decode amf3: unsupported type %d", marker) |
|
} |
|
|
|
// marker: 1 byte 0x00 |
|
// no additional data |
|
func (d *Decoder) DecodeAmf3Undefined(r io.Reader, decodeMarker bool) (result interface{}, err error) { |
|
err = AssertMarker(r, decodeMarker, AMF3_UNDEFINED_MARKER) |
|
return |
|
} |
|
|
|
// marker: 1 byte 0x01 |
|
// no additional data |
|
func (d *Decoder) DecodeAmf3Null(r io.Reader, decodeMarker bool) (result interface{}, err error) { |
|
err = AssertMarker(r, decodeMarker, AMF3_NULL_MARKER) |
|
return |
|
} |
|
|
|
// marker: 1 byte 0x02 |
|
// no additional data |
|
func (d *Decoder) DecodeAmf3False(r io.Reader, decodeMarker bool) (result bool, err error) { |
|
err = AssertMarker(r, decodeMarker, AMF3_FALSE_MARKER) |
|
result = false |
|
return |
|
} |
|
|
|
// marker: 1 byte 0x03 |
|
// no additional data |
|
func (d *Decoder) DecodeAmf3True(r io.Reader, decodeMarker bool) (result bool, err error) { |
|
err = AssertMarker(r, decodeMarker, AMF3_TRUE_MARKER) |
|
result = true |
|
return |
|
} |
|
|
|
// marker: 1 byte 0x04 |
|
func (d *Decoder) DecodeAmf3Integer(r io.Reader, decodeMarker bool) (result int32, err error) { |
|
if err = AssertMarker(r, decodeMarker, AMF3_INTEGER_MARKER); err != nil { |
|
return |
|
} |
|
|
|
var u29 uint32 |
|
u29, err = d.decodeU29(r) |
|
if err != nil { |
|
return |
|
} |
|
|
|
result = int32(u29) |
|
if result > 0xfffffff { |
|
result = int32(u29 - 0x20000000) |
|
} |
|
|
|
return |
|
} |
|
|
|
// marker: 1 byte 0x05 |
|
func (d *Decoder) DecodeAmf3Double(r io.Reader, decodeMarker bool) (result float64, err error) { |
|
if err = AssertMarker(r, decodeMarker, AMF3_DOUBLE_MARKER); err != nil { |
|
return |
|
} |
|
|
|
err = binary.Read(r, binary.BigEndian, &result) |
|
if err != nil { |
|
return float64(0), fmt.Errorf("amf3 decode: unable to read double: %s", err) |
|
} |
|
|
|
return |
|
} |
|
|
|
// marker: 1 byte 0x06 |
|
// format: |
|
// - u29 reference int. if reference, no more data. if not reference, |
|
// length value of bytes to read to complete string. |
|
func (d *Decoder) DecodeAmf3String(r io.Reader, decodeMarker bool) (result string, err error) { |
|
if err = AssertMarker(r, decodeMarker, AMF3_STRING_MARKER); err != nil { |
|
return |
|
} |
|
|
|
var isRef bool |
|
var refVal uint32 |
|
isRef, refVal, err = d.decodeReferenceInt(r) |
|
if err != nil { |
|
return "", fmt.Errorf("amf3 decode: unable to decode string reference and length: %s", err) |
|
} |
|
|
|
if isRef { |
|
result = d.stringRefs[refVal] |
|
return |
|
} |
|
|
|
buf := make([]byte, refVal) |
|
_, err = r.Read(buf) |
|
if err != nil { |
|
return "", fmt.Errorf("amf3 decode: unable to read string: %s", err) |
|
} |
|
|
|
result = string(buf) |
|
if result != "" { |
|
d.stringRefs = append(d.stringRefs, result) |
|
} |
|
|
|
return |
|
} |
|
|
|
// marker: 1 byte 0x08 |
|
// format: |
|
// - u29 reference int, if reference, no more data |
|
// - timestamp double |
|
func (d *Decoder) DecodeAmf3Date(r io.Reader, decodeMarker bool) (result time.Time, err error) { |
|
if err = AssertMarker(r, decodeMarker, AMF3_DATE_MARKER); err != nil { |
|
return |
|
} |
|
|
|
var isRef bool |
|
var refVal uint32 |
|
isRef, refVal, err = d.decodeReferenceInt(r) |
|
if err != nil { |
|
return result, fmt.Errorf("amf3 decode: unable to decode date reference and length: %s", err) |
|
} |
|
|
|
if isRef { |
|
res, ok := d.objectRefs[refVal].(time.Time) |
|
if ok != true { |
|
return result, fmt.Errorf("amf3 decode: unable to extract time from date object references") |
|
} |
|
|
|
return res, err |
|
} |
|
|
|
var u64 float64 |
|
err = binary.Read(r, binary.BigEndian, &u64) |
|
if err != nil { |
|
return result, fmt.Errorf("amf3 decode: unable to read double: %s", err) |
|
} |
|
|
|
result = time.Unix(int64(u64/1000), 0).UTC() |
|
|
|
d.objectRefs = append(d.objectRefs, result) |
|
|
|
return |
|
} |
|
|
|
// marker: 1 byte 0x09 |
|
// format: |
|
// - u29 reference int. if reference, no more data. |
|
// - string representing associative array if present |
|
// - n values (length of u29) |
|
func (d *Decoder) DecodeAmf3Array(r io.Reader, decodeMarker bool) (result Array, err error) { |
|
if err = AssertMarker(r, decodeMarker, AMF3_ARRAY_MARKER); err != nil { |
|
return |
|
} |
|
|
|
var isRef bool |
|
var refVal uint32 |
|
isRef, refVal, err = d.decodeReferenceInt(r) |
|
if err != nil { |
|
return result, fmt.Errorf("amf3 decode: unable to decode array reference and length: %s", err) |
|
} |
|
|
|
if isRef { |
|
objRefId := refVal >> 1 |
|
|
|
res, ok := d.objectRefs[objRefId].(Array) |
|
if ok != true { |
|
return result, fmt.Errorf("amf3 decode: unable to extract array from object references") |
|
} |
|
|
|
return res, err |
|
} |
|
|
|
var key string |
|
key, err = d.DecodeAmf3String(r, false) |
|
if err != nil { |
|
return result, fmt.Errorf("amf3 decode: unable to read key for array: %s", err) |
|
} |
|
|
|
if key != "" { |
|
return result, fmt.Errorf("amf3 decode: array key is not empty, can't handle associative array") |
|
} |
|
|
|
for i := uint32(0); i < refVal; i++ { |
|
tmp, err := d.DecodeAmf3(r) |
|
if err != nil { |
|
return result, fmt.Errorf("amf3 decode: array element could not be decoded: %s", err) |
|
} |
|
result = append(result, tmp) |
|
} |
|
|
|
d.objectRefs = append(d.objectRefs, result) |
|
|
|
return |
|
} |
|
|
|
// marker: 1 byte 0x09 |
|
// format: oh dear god |
|
func (d *Decoder) DecodeAmf3Object(r io.Reader, decodeMarker bool) (result interface{}, err error) { |
|
if err = AssertMarker(r, decodeMarker, AMF3_OBJECT_MARKER); err != nil { |
|
return nil, err |
|
} |
|
|
|
// decode the initial u29 |
|
isRef, refVal, err := d.decodeReferenceInt(r) |
|
if err != nil { |
|
return nil, fmt.Errorf("amf3 decode: unable to decode object reference and length: %s", err) |
|
} |
|
|
|
// if this is a object reference only, grab it and return it |
|
if isRef { |
|
objRefId := refVal >> 1 |
|
|
|
return d.objectRefs[objRefId], nil |
|
} |
|
|
|
// each type has traits that are cached, if the peer sent a reference |
|
// then we'll need to look it up and use it. |
|
var trait Trait |
|
|
|
traitIsRef := (refVal & 0x01) == 0 |
|
|
|
if traitIsRef { |
|
traitRef := refVal >> 1 |
|
trait = d.traitRefs[traitRef] |
|
|
|
} else { |
|
// build a new trait from what's left of the given u29 |
|
trait = *NewTrait() |
|
trait.Externalizable = (refVal & 0x02) != 0 |
|
trait.Dynamic = (refVal & 0x04) != 0 |
|
|
|
var cls string |
|
cls, err = d.DecodeAmf3String(r, false) |
|
if err != nil { |
|
return result, fmt.Errorf("amf3 decode: unable to read trait type for object: %s", err) |
|
} |
|
trait.Type = cls |
|
|
|
// traits have property keys, encoded as amf3 strings |
|
propLength := refVal >> 3 |
|
for i := uint32(0); i < propLength; i++ { |
|
tmp, err := d.DecodeAmf3String(r, false) |
|
if err != nil { |
|
return result, fmt.Errorf("amf3 decode: unable to read trait property for object: %s", err) |
|
} |
|
trait.Properties = append(trait.Properties, tmp) |
|
} |
|
|
|
d.traitRefs = append(d.traitRefs, trait) |
|
} |
|
|
|
d.objectRefs = append(d.objectRefs, result) |
|
|
|
// objects can be externalizable, meaning that the system has no concrete understanding of |
|
// their properties or how they are encoded. in that case, we need to find and delegate behavior |
|
// to the right object. |
|
if trait.Externalizable { |
|
switch trait.Type { |
|
case "DSA": // AsyncMessageExt |
|
result, err = d.decodeAsyncMessageExt(r) |
|
if err != nil { |
|
return result, fmt.Errorf("amf3 decode: unable to decode dsa: %s", err) |
|
} |
|
case "DSK": // AcknowledgeMessageExt |
|
result, err = d.decodeAcknowledgeMessageExt(r) |
|
if err != nil { |
|
return result, fmt.Errorf("amf3 decode: unable to decode dsk: %s", err) |
|
} |
|
case "flex.messaging.io.ArrayCollection": |
|
result, err = d.decodeArrayCollection(r) |
|
if err != nil { |
|
return result, fmt.Errorf("amf3 decode: unable to decode ac: %s", err) |
|
} |
|
|
|
// store an extra reference to array collection container |
|
d.objectRefs = append(d.objectRefs, result) |
|
|
|
default: |
|
fn, ok := d.externalHandlers[trait.Type] |
|
if ok { |
|
result, err = fn(d, r) |
|
if err != nil { |
|
return result, fmt.Errorf("amf3 decode: unable to call external decoder for type %s: %s", trait.Type, err) |
|
} |
|
} else { |
|
return result, fmt.Errorf("amf3 decode: unable to decode external type %s, no handler", trait.Type) |
|
} |
|
} |
|
|
|
return result, err |
|
} |
|
|
|
var key string |
|
var val interface{} |
|
var obj Object |
|
|
|
obj = make(Object) |
|
|
|
// non-externalizable objects have property keys in traits, iterate through them |
|
// and add the read values to the object |
|
for _, key = range trait.Properties { |
|
val, err = d.DecodeAmf3(r) |
|
if err != nil { |
|
return result, fmt.Errorf("amf3 decode: unable to decode object property: %s", err) |
|
} |
|
|
|
obj[key] = val |
|
} |
|
|
|
// if an object is dynamic, it can have extra key/value data at the end. in this case, |
|
// read keys until we get an empty one. |
|
if trait.Dynamic { |
|
for { |
|
key, err = d.DecodeAmf3String(r, false) |
|
if err != nil { |
|
return result, fmt.Errorf("amf3 decode: unable to decode dynamic key: %s", err) |
|
} |
|
if key == "" { |
|
break |
|
} |
|
val, err = d.DecodeAmf3(r) |
|
if err != nil { |
|
return result, fmt.Errorf("amf3 decode: unable to decode dynamic value: %s", err) |
|
} |
|
|
|
obj[key] = val |
|
} |
|
} |
|
|
|
result = obj |
|
|
|
return |
|
} |
|
|
|
// marker: 1 byte 0x07 or 0x0b |
|
// format: |
|
// - u29 reference int. if reference, no more data. if not reference, |
|
// length value of bytes to read to complete string. |
|
func (d *Decoder) DecodeAmf3Xml(r io.Reader, decodeMarker bool) (result string, err error) { |
|
if decodeMarker { |
|
var marker byte |
|
marker, err = ReadMarker(r) |
|
if err != nil { |
|
return "", err |
|
} |
|
|
|
if (marker != AMF3_XMLDOC_MARKER) && (marker != AMF3_XMLSTRING_MARKER) { |
|
return "", fmt.Errorf("decode assert marker failed: expected %v or %v, got %v", AMF3_XMLDOC_MARKER, AMF3_XMLSTRING_MARKER, marker) |
|
} |
|
} |
|
|
|
var isRef bool |
|
var refVal uint32 |
|
isRef, refVal, err = d.decodeReferenceInt(r) |
|
if err != nil { |
|
return "", fmt.Errorf("amf3 decode: unable to decode xml reference and length: %s", err) |
|
} |
|
|
|
if isRef { |
|
var ok bool |
|
buf := d.objectRefs[refVal] |
|
result, ok = buf.(string) |
|
if ok != true { |
|
return "", fmt.Errorf("amf3 decode: cannot coerce object reference into xml string") |
|
} |
|
|
|
return |
|
} |
|
|
|
buf := make([]byte, refVal) |
|
_, err = r.Read(buf) |
|
if err != nil { |
|
return "", fmt.Errorf("amf3 decode: unable to read xml string: %s", err) |
|
} |
|
|
|
result = string(buf) |
|
|
|
if result != "" { |
|
d.objectRefs = append(d.objectRefs, result) |
|
} |
|
|
|
return |
|
} |
|
|
|
// marker: 1 byte 0x0c |
|
// format: |
|
// - u29 reference int. if reference, no more data. if not reference, |
|
// length value of bytes to read. |
|
func (d *Decoder) DecodeAmf3ByteArray(r io.Reader, decodeMarker bool) (result []byte, err error) { |
|
if err = AssertMarker(r, decodeMarker, AMF3_BYTEARRAY_MARKER); err != nil { |
|
return |
|
} |
|
|
|
var isRef bool |
|
var refVal uint32 |
|
isRef, refVal, err = d.decodeReferenceInt(r) |
|
if err != nil { |
|
return result, fmt.Errorf("amf3 decode: unable to decode byte array reference and length: %s", err) |
|
} |
|
|
|
if isRef { |
|
var ok bool |
|
result, ok = d.objectRefs[refVal].([]byte) |
|
if ok != true { |
|
return result, fmt.Errorf("amf3 decode: unable to convert object ref to bytes") |
|
} |
|
|
|
return |
|
} |
|
|
|
result = make([]byte, refVal) |
|
_, err = r.Read(result) |
|
if err != nil { |
|
return result, fmt.Errorf("amf3 decode: unable to read bytearray: %s", err) |
|
} |
|
|
|
d.objectRefs = append(d.objectRefs, result) |
|
|
|
return |
|
} |
|
|
|
func (d *Decoder) decodeU29(r io.Reader) (result uint32, err error) { |
|
var b byte |
|
|
|
for i := 0; i < 3; i++ { |
|
b, err = ReadByte(r) |
|
if err != nil { |
|
return |
|
} |
|
result = (result << 7) + uint32(b&0x7F) |
|
if (b & 0x80) == 0 { |
|
return |
|
} |
|
} |
|
|
|
b, err = ReadByte(r) |
|
if err != nil { |
|
return |
|
} |
|
|
|
result = ((result << 8) + uint32(b)) |
|
|
|
return |
|
} |
|
|
|
func (d *Decoder) decodeReferenceInt(r io.Reader) (isRef bool, refVal uint32, err error) { |
|
u29, err := d.decodeU29(r) |
|
if err != nil { |
|
return false, 0, fmt.Errorf("amf3 decode: unable to decode reference int: %s", err) |
|
} |
|
|
|
isRef = u29&0x01 == 0 |
|
refVal = u29 >> 1 |
|
|
|
return |
|
}
|
|
|