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.
336 lines
9.1 KiB
336 lines
9.1 KiB
package amf |
|
|
|
import ( |
|
"encoding/binary" |
|
"fmt" |
|
"io" |
|
) |
|
|
|
// amf0 polymorphic router |
|
func (d *Decoder) DecodeAmf0(r io.Reader) (interface{}, error) { |
|
marker, err := ReadMarker(r) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
switch marker { |
|
case AMF0_NUMBER_MARKER: |
|
return d.DecodeAmf0Number(r, false) |
|
case AMF0_BOOLEAN_MARKER: |
|
return d.DecodeAmf0Boolean(r, false) |
|
case AMF0_STRING_MARKER: |
|
return d.DecodeAmf0String(r, false) |
|
case AMF0_OBJECT_MARKER: |
|
return d.DecodeAmf0Object(r, false) |
|
case AMF0_MOVIECLIP_MARKER: |
|
return nil, fmt.Errorf("decode amf0: unsupported type movieclip") |
|
case AMF0_NULL_MARKER: |
|
return d.DecodeAmf0Null(r, false) |
|
case AMF0_UNDEFINED_MARKER: |
|
return d.DecodeAmf0Undefined(r, false) |
|
case AMF0_REFERENCE_MARKER: |
|
return nil, fmt.Errorf("decode amf0: unsupported type reference") |
|
case AMF0_ECMA_ARRAY_MARKER: |
|
return d.DecodeAmf0EcmaArray(r, false) |
|
case AMF0_STRICT_ARRAY_MARKER: |
|
return d.DecodeAmf0StrictArray(r, false) |
|
case AMF0_DATE_MARKER: |
|
return d.DecodeAmf0Date(r, false) |
|
case AMF0_LONG_STRING_MARKER: |
|
return d.DecodeAmf0LongString(r, false) |
|
case AMF0_UNSUPPORTED_MARKER: |
|
return d.DecodeAmf0Unsupported(r, false) |
|
case AMF0_RECORDSET_MARKER: |
|
return nil, fmt.Errorf("decode amf0: unsupported type recordset") |
|
case AMF0_XML_DOCUMENT_MARKER: |
|
return d.DecodeAmf0XmlDocument(r, false) |
|
case AMF0_TYPED_OBJECT_MARKER: |
|
return d.DecodeAmf0TypedObject(r, false) |
|
case AMF0_ACMPLUS_OBJECT_MARKER: |
|
return d.DecodeAmf3(r) |
|
} |
|
|
|
return nil, fmt.Errorf("decode amf0: unsupported type %d", marker) |
|
} |
|
|
|
// marker: 1 byte 0x00 |
|
// format: 8 byte big endian float64 |
|
func (d *Decoder) DecodeAmf0Number(r io.Reader, decodeMarker bool) (result float64, err error) { |
|
if err = AssertMarker(r, decodeMarker, AMF0_NUMBER_MARKER); err != nil { |
|
return |
|
} |
|
|
|
err = binary.Read(r, binary.BigEndian, &result) |
|
if err != nil { |
|
return float64(0), fmt.Errorf("amf0 decode: unable to read number: %s", err) |
|
} |
|
|
|
return |
|
} |
|
|
|
// marker: 1 byte 0x01 |
|
// format: 1 byte, 0x00 = false, 0x01 = true |
|
func (d *Decoder) DecodeAmf0Boolean(r io.Reader, decodeMarker bool) (result bool, err error) { |
|
if err = AssertMarker(r, decodeMarker, AMF0_BOOLEAN_MARKER); err != nil { |
|
return |
|
} |
|
|
|
var b byte |
|
if b, err = ReadByte(r); err != nil { |
|
return |
|
} |
|
|
|
if b == AMF0_BOOLEAN_FALSE { |
|
return false, nil |
|
} else if b == AMF0_BOOLEAN_TRUE { |
|
return true, nil |
|
} |
|
|
|
return false, fmt.Errorf("decode amf0: unexpected value %v for boolean", b) |
|
} |
|
|
|
// marker: 1 byte 0x02 |
|
// format: |
|
// - 2 byte big endian uint16 header to determine size |
|
// - n (size) byte utf8 string |
|
func (d *Decoder) DecodeAmf0String(r io.Reader, decodeMarker bool) (result string, err error) { |
|
if err = AssertMarker(r, decodeMarker, AMF0_STRING_MARKER); err != nil { |
|
return |
|
} |
|
|
|
var length uint16 |
|
err = binary.Read(r, binary.BigEndian, &length) |
|
if err != nil { |
|
return "", fmt.Errorf("decode amf0: unable to decode string length: %s", err) |
|
} |
|
|
|
var bytes = make([]byte, length) |
|
if bytes, err = ReadBytes(r, int(length)); err != nil { |
|
return "", fmt.Errorf("decode amf0: unable to decode string value: %s", err) |
|
} |
|
|
|
return string(bytes), nil |
|
} |
|
|
|
// marker: 1 byte 0x03 |
|
// format: |
|
// - loop encoded string followed by encoded value |
|
// - terminated with empty string followed by 1 byte 0x09 |
|
func (d *Decoder) DecodeAmf0Object(r io.Reader, decodeMarker bool) (Object, error) { |
|
if err := AssertMarker(r, decodeMarker, AMF0_OBJECT_MARKER); err != nil { |
|
return nil, err |
|
} |
|
|
|
result := make(Object) |
|
d.refCache = append(d.refCache, result) |
|
|
|
for { |
|
key, err := d.DecodeAmf0String(r, false) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
if key == "" { |
|
if err = AssertMarker(r, true, AMF0_OBJECT_END_MARKER); err != nil { |
|
return nil, fmt.Errorf("decode amf0: expected object end marker: %s", err) |
|
} |
|
|
|
break |
|
} |
|
|
|
value, err := d.DecodeAmf0(r) |
|
if err != nil { |
|
return nil, fmt.Errorf("decode amf0: unable to decode object value: %s", err) |
|
} |
|
|
|
result[key] = value |
|
} |
|
|
|
return result, nil |
|
|
|
} |
|
|
|
// marker: 1 byte 0x05 |
|
// no additional data |
|
func (d *Decoder) DecodeAmf0Null(r io.Reader, decodeMarker bool) (result interface{}, err error) { |
|
err = AssertMarker(r, decodeMarker, AMF0_NULL_MARKER) |
|
return |
|
} |
|
|
|
// marker: 1 byte 0x06 |
|
// no additional data |
|
func (d *Decoder) DecodeAmf0Undefined(r io.Reader, decodeMarker bool) (result interface{}, err error) { |
|
err = AssertMarker(r, decodeMarker, AMF0_UNDEFINED_MARKER) |
|
return |
|
} |
|
|
|
// marker: 1 byte 0x07 |
|
// format: 2 byte big endian uint16 |
|
/* |
|
func (d *Decoder) DecodeAmf0Reference(r io.Reader, decodeMarker bool) (interface{}, error) { |
|
if err := AssertMarker(r, decodeMarker, AMF0_REFERENCE_MARKER); err != nil { |
|
return nil, err |
|
} |
|
|
|
var err error |
|
var ref uint16 |
|
|
|
err = binary.Read(r, binary.BigEndian, &ref) |
|
if err != nil { |
|
return nil, fmt.Errorf("decode amf0: unable to decode reference id: %s", err) |
|
} |
|
|
|
if int(ref) > len(d.refCache) { |
|
return nil, fmt.Errorf("decode amf0: bad reference %d (current length %d)", ref, len(d.refCache)) |
|
} |
|
|
|
result := d.refCache[ref] |
|
|
|
return result, nil |
|
} |
|
*/ |
|
|
|
// marker: 1 byte 0x08 |
|
// format: |
|
// - 4 byte big endian uint32 with length of associative array |
|
// - normal object format: |
|
// - loop encoded string followed by encoded value |
|
// - terminated with empty string followed by 1 byte 0x09 |
|
func (d *Decoder) DecodeAmf0EcmaArray(r io.Reader, decodeMarker bool) (Object, error) { |
|
if err := AssertMarker(r, decodeMarker, AMF0_ECMA_ARRAY_MARKER); err != nil { |
|
return nil, err |
|
} |
|
|
|
var length uint32 |
|
err := binary.Read(r, binary.BigEndian, &length) |
|
|
|
result, err := d.DecodeAmf0Object(r, false) |
|
if err != nil { |
|
return nil, fmt.Errorf("decode amf0: unable to decode ecma array object: %s", err) |
|
} |
|
|
|
return result, nil |
|
} |
|
|
|
// marker: 1 byte 0x0a |
|
// format: |
|
// - 4 byte big endian uint32 to determine length of associative array |
|
// - n (length) encoded values |
|
func (d *Decoder) DecodeAmf0StrictArray(r io.Reader, decodeMarker bool) (result Array, err error) { |
|
if err := AssertMarker(r, decodeMarker, AMF0_STRICT_ARRAY_MARKER); err != nil { |
|
return nil, err |
|
} |
|
|
|
var length uint32 |
|
err = binary.Read(r, binary.BigEndian, &length) |
|
if err != nil { |
|
return nil, fmt.Errorf("decode amf0: unable to decode strict array length: %s", err) |
|
} |
|
|
|
d.refCache = append(d.refCache, result) |
|
|
|
for i := uint32(0); i < length; i++ { |
|
tmp, err := d.DecodeAmf0(r) |
|
if err != nil { |
|
return nil, fmt.Errorf("decode amf0: unable to decode strict array object: %s", err) |
|
} |
|
result = append(result, tmp) |
|
} |
|
|
|
return result, nil |
|
} |
|
|
|
// marker: 1 byte 0x0b |
|
// format: |
|
// - normal number format: |
|
// - 8 byte big endian float64 |
|
// - 2 byte unused |
|
func (d *Decoder) DecodeAmf0Date(r io.Reader, decodeMarker bool) (result float64, err error) { |
|
if err = AssertMarker(r, decodeMarker, AMF0_DATE_MARKER); err != nil { |
|
return |
|
} |
|
|
|
if result, err = d.DecodeAmf0Number(r, false); err != nil { |
|
return float64(0), fmt.Errorf("decode amf0: unable to decode float in date: %s", err) |
|
} |
|
|
|
if _, err = ReadBytes(r, 2); err != nil { |
|
return float64(0), fmt.Errorf("decode amf0: unable to read 2 trail bytes in date: %s", err) |
|
} |
|
|
|
return |
|
} |
|
|
|
// marker: 1 byte 0x0c |
|
// format: |
|
// - 4 byte big endian uint32 header to determine size |
|
// - n (size) byte utf8 string |
|
func (d *Decoder) DecodeAmf0LongString(r io.Reader, decodeMarker bool) (result string, err error) { |
|
if err = AssertMarker(r, decodeMarker, AMF0_LONG_STRING_MARKER); err != nil { |
|
return |
|
} |
|
|
|
var length uint32 |
|
err = binary.Read(r, binary.BigEndian, &length) |
|
if err != nil { |
|
return "", fmt.Errorf("decode amf0: unable to decode long string length: %s", err) |
|
} |
|
|
|
var bytes = make([]byte, length) |
|
if bytes, err = ReadBytes(r, int(length)); err != nil { |
|
return "", fmt.Errorf("decode amf0: unable to decode long string value: %s", err) |
|
} |
|
|
|
return string(bytes), nil |
|
} |
|
|
|
// marker: 1 byte 0x0d |
|
// no additional data |
|
func (d *Decoder) DecodeAmf0Unsupported(r io.Reader, decodeMarker bool) (result interface{}, err error) { |
|
err = AssertMarker(r, decodeMarker, AMF0_UNSUPPORTED_MARKER) |
|
return |
|
} |
|
|
|
// marker: 1 byte 0x0f |
|
// format: |
|
// - normal long string format |
|
// - 4 byte big endian uint32 header to determine size |
|
// - n (size) byte utf8 string |
|
func (d *Decoder) DecodeAmf0XmlDocument(r io.Reader, decodeMarker bool) (result string, err error) { |
|
if err = AssertMarker(r, decodeMarker, AMF0_XML_DOCUMENT_MARKER); err != nil { |
|
return |
|
} |
|
|
|
return d.DecodeAmf0LongString(r, false) |
|
} |
|
|
|
// marker: 1 byte 0x10 |
|
// format: |
|
// - normal string format: |
|
// - 2 byte big endian uint16 header to determine size |
|
// - n (size) byte utf8 string |
|
// - normal object format: |
|
// - loop encoded string followed by encoded value |
|
// - terminated with empty string followed by 1 byte 0x09 |
|
func (d *Decoder) DecodeAmf0TypedObject(r io.Reader, decodeMarker bool) (TypedObject, error) { |
|
result := *new(TypedObject) |
|
|
|
err := AssertMarker(r, decodeMarker, AMF0_TYPED_OBJECT_MARKER) |
|
if err != nil { |
|
return result, err |
|
} |
|
|
|
d.refCache = append(d.refCache, result) |
|
|
|
result.Type, err = d.DecodeAmf0String(r, false) |
|
if err != nil { |
|
return result, fmt.Errorf("decode amf0: typed object unable to determine type: %s", err) |
|
} |
|
|
|
result.Object, err = d.DecodeAmf0Object(r, false) |
|
if err != nil { |
|
return result, fmt.Errorf("decode amf0: typed object unable to determine object: %s", err) |
|
} |
|
|
|
return result, nil |
|
}
|
|
|