mirror of https://bitbucket.org/ausocean/av.git
amf.Decode and amf.PropDecode now return an error.
This commit is contained in:
parent
b79a035d0f
commit
1fe1849393
125
rtmp/amf/amf.go
125
rtmp/amf/amf.go
|
@ -90,6 +90,7 @@ var (
|
||||||
ErrUnimplemented = errors.New("amf: unimplemented feature")
|
ErrUnimplemented = errors.New("amf: unimplemented feature")
|
||||||
ErrDecodingName = errors.New("amf: name decoding error")
|
ErrDecodingName = errors.New("amf: name decoding error")
|
||||||
ErrDecodingString = errors.New("amf: string decoding error")
|
ErrDecodingString = errors.New("amf: string decoding error")
|
||||||
|
ErrUnexpectedEnd = errors.New("amf: unexpected end")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Basic decoding funcions.
|
// Basic decoding funcions.
|
||||||
|
@ -271,7 +272,6 @@ func PropGetObject(prop *Property, obj *Object) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PropEncode encodes a property.
|
// PropEncode encodes a property.
|
||||||
|
|
||||||
func PropEncode(p *Property, dst []byte) ([]byte, error) {
|
func PropEncode(p *Property, dst []byte) ([]byte, error) {
|
||||||
if p.dtype == typeInvalid {
|
if p.dtype == typeInvalid {
|
||||||
return nil, ErrShortBuffer
|
return nil, ErrShortBuffer
|
||||||
|
@ -314,128 +314,81 @@ func PropEncode(p *Property, dst []byte) ([]byte, error) {
|
||||||
return dst, err
|
return dst, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// PropDecode decodes a property, returning the number of bytes consumed from the data buffer.
|
// PropDecode decodes a property, returning the number of bytes consumed from the supplied buffer.
|
||||||
func PropDecode(prop *Property, data []byte, decodeName int32) int32 {
|
func PropDecode(prop *Property, data []byte, decodeName bool) (int, error) {
|
||||||
prop.name = ""
|
prop.name = ""
|
||||||
|
|
||||||
nOriginalSize := len(data)
|
sz := len(data)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
// TODO use new logger here
|
return 0, ErrEndOfBuffer
|
||||||
// RTMLog(RTMLOGDEBUG, "%s: Empty buffer/no buffer pointer!", __FUNCTION__);
|
|
||||||
return -1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if decodeName != 0 && len(data) < 4 {
|
if decodeName {
|
||||||
// at least name (length + at least 1 byte) and 1 byte of data
|
if len(data) < 4 {
|
||||||
// TODO use new logger here
|
return 0, ErrShortBuffer
|
||||||
// RTMLog(RTMLOGDEBUG, "%s: Not enough data for decoding with name, less than 4 bytes!",__FUNCTION__);
|
}
|
||||||
return -1
|
n := DecodeInt16(data[:2])
|
||||||
}
|
if int(n) > len(data)-2 {
|
||||||
|
return 0, ErrDecodingName
|
||||||
if decodeName != 0 {
|
|
||||||
nNameSize := DecodeInt16(data[:2])
|
|
||||||
if int(nNameSize) > len(data)-2 {
|
|
||||||
// TODO use new logger here
|
|
||||||
//RTMLog(RTMLOGDEBUG, "%s: Name size out of range: namesize (%d) > len (%d) - 2",__FUNCTION__, nNameSize, nSize);
|
|
||||||
return -1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prop.name = DecodeString(data)
|
prop.name = DecodeString(data)
|
||||||
data = data[2+nNameSize:]
|
data = data[2+n:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return -1
|
return 0, ErrEndOfBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
prop.dtype = uint8(data[0])
|
prop.dtype = uint8(data[0])
|
||||||
data = data[1:]
|
data = data[1:]
|
||||||
|
|
||||||
var nRes int32
|
|
||||||
switch prop.dtype {
|
switch prop.dtype {
|
||||||
case typeNumber:
|
case typeNumber:
|
||||||
if len(data) < 8 {
|
if len(data) < 8 {
|
||||||
return -1
|
return 0, ErrShortBuffer
|
||||||
}
|
}
|
||||||
prop.number = DecodeNumber(data[:8])
|
prop.number = DecodeNumber(data[:8])
|
||||||
data = data[8:]
|
data = data[8:]
|
||||||
|
|
||||||
case typeBoolean:
|
case typeBoolean:
|
||||||
panic("typeBoolean not supported")
|
return 0, ErrUnimplemented
|
||||||
|
|
||||||
case typeString:
|
case typeString:
|
||||||
nStringSize := DecodeInt16(data[:2])
|
n := DecodeInt16(data[:2])
|
||||||
if len(data) < int(nStringSize+2) {
|
if len(data) < int(n+2) {
|
||||||
return -1
|
return 0, ErrShortBuffer
|
||||||
}
|
}
|
||||||
prop.str = DecodeString(data)
|
prop.str = DecodeString(data)
|
||||||
data = data[2+nStringSize:]
|
data = data[2+n:]
|
||||||
|
|
||||||
case TypeObject:
|
case TypeObject:
|
||||||
nRes := Decode(&prop.obj, data, 1)
|
n, err := Decode(&prop.obj, data, true)
|
||||||
if nRes == -1 {
|
if err != nil {
|
||||||
return -1
|
return 0, err
|
||||||
}
|
}
|
||||||
data = data[nRes:]
|
data = data[n:]
|
||||||
|
|
||||||
case typeMovieClip:
|
|
||||||
// TODO use new logger here
|
|
||||||
// ??? log.Println("PropDecode: MAF_MOVIECLIP reserved!")
|
|
||||||
//RTMLog(RTMLOGERROR, "MovieClip reserved!");
|
|
||||||
return -1
|
|
||||||
|
|
||||||
case TypeNull, typeUndefined, typeUnsupported:
|
case TypeNull, typeUndefined, typeUnsupported:
|
||||||
prop.dtype = TypeNull
|
prop.dtype = TypeNull
|
||||||
|
|
||||||
case typeReference:
|
|
||||||
// TODO use new logger here
|
|
||||||
// ??? log.Println("PropDecode: Reference not supported!")
|
|
||||||
//RTMLog(RTMLOGERROR, "Reference not supported!");
|
|
||||||
return -1
|
|
||||||
|
|
||||||
case typeEcmaArray:
|
case typeEcmaArray:
|
||||||
// next comes the rest, mixed array has a final 0x000009 mark and names, so its an object
|
|
||||||
data = data[4:]
|
data = data[4:]
|
||||||
nRes = Decode(&prop.obj, data, 1)
|
n, err := Decode(&prop.obj, data, true)
|
||||||
if nRes == -1 {
|
if err != nil {
|
||||||
return -1
|
return 0, err
|
||||||
}
|
}
|
||||||
data = data[nRes:]
|
data = data[n:]
|
||||||
|
|
||||||
case TypeObjectEnd:
|
case TypeObjectEnd:
|
||||||
return -1
|
return 0, ErrUnexpectedEnd
|
||||||
|
|
||||||
case typeStrictArray:
|
|
||||||
panic("StrictArray not supported")
|
|
||||||
|
|
||||||
case typeDate:
|
|
||||||
panic("Date not supported")
|
|
||||||
|
|
||||||
case typeLongString, typeXmlDoc:
|
|
||||||
panic("typeLongString, XmlDoc not supported")
|
|
||||||
|
|
||||||
case typeRecordset:
|
|
||||||
// TODO use new logger here
|
|
||||||
// ??? log.Println("PropDecode: Recordset reserved!")
|
|
||||||
//RTMLog(RTMLOGERROR, "Recordset reserved!");
|
|
||||||
return -1
|
|
||||||
|
|
||||||
case typeTypedObject:
|
|
||||||
// TODO use new logger here
|
|
||||||
// RTMLog(RTMLOGERROR, "Typed_object not supported!")
|
|
||||||
return -1
|
|
||||||
|
|
||||||
case typeAvmplus:
|
|
||||||
panic("Avmplus not supported")
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// TODO use new logger here
|
return 0, ErrUnimplemented
|
||||||
//RTMLog(RTMLOGDEBUG, "%s - unknown datatype 0x%02x, @%p", __FUNCTION__,
|
|
||||||
//prop.dtype, pBuffer - 1);
|
|
||||||
return -1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return int32(nOriginalSize - len(data))
|
return sz - len(data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func PropReset(prop *Property) {
|
func PropReset(prop *Property) {
|
||||||
|
@ -516,8 +469,8 @@ func EncodeArray(obj *Object, dst []byte) ([]byte, error) {
|
||||||
return dst, nil
|
return dst, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Decode(obj *Object, data []byte, decodeName int32) int32 {
|
func Decode(obj *Object, data []byte, decodeName bool) (int, error) {
|
||||||
nOriginalSize := len(data)
|
sz := len(data)
|
||||||
|
|
||||||
obj.Props = obj.Props[:0]
|
obj.Props = obj.Props[:0]
|
||||||
for len(data) != 0 {
|
for len(data) != 0 {
|
||||||
|
@ -527,17 +480,15 @@ func Decode(obj *Object, data []byte, decodeName int32) int32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
var prop Property
|
var prop Property
|
||||||
nRes := PropDecode(&prop, data, decodeName)
|
n, err := PropDecode(&prop, data, decodeName)
|
||||||
// nRes = int32(C.PropDecode(&prop, (*byte)(unsafe.Pointer(pBuffer)),
|
if err != nil {
|
||||||
// int32(nSize), int32(decodeName)))
|
return 0, err
|
||||||
if nRes == -1 {
|
|
||||||
return -1
|
|
||||||
}
|
}
|
||||||
data = data[nRes:]
|
data = data[n:]
|
||||||
obj.Props = append(obj.Props, prop)
|
obj.Props = append(obj.Props, prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
return int32(nOriginalSize - len(data))
|
return sz - len(data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetProp(obj *Object, name string, idx int32) *Property {
|
func GetProp(obj *Object, name string, idx int32) *Property {
|
||||||
|
|
|
@ -107,12 +107,12 @@ func TestProperties(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
var n int32
|
|
||||||
prop := Property{}
|
prop := Property{}
|
||||||
dec := buf[:]
|
dec := buf[:]
|
||||||
for i, _ := range testNumbers {
|
for i, _ := range testNumbers {
|
||||||
n = PropDecode(&prop, dec, 0)
|
n, err := PropDecode(&prop, dec, false)
|
||||||
if n < 0 {
|
if err != nil {
|
||||||
t.Errorf("PropDecode of number failed")
|
t.Errorf("PropDecode of number failed")
|
||||||
}
|
}
|
||||||
if int32(prop.number) != testNumbers[i] {
|
if int32(prop.number) != testNumbers[i] {
|
||||||
|
@ -133,8 +133,8 @@ func TestProperties(t *testing.T) {
|
||||||
prop = Property{}
|
prop = Property{}
|
||||||
dec = buf[:]
|
dec = buf[:]
|
||||||
for i, _ := range testStrings {
|
for i, _ := range testStrings {
|
||||||
n = PropDecode(&prop, dec, 0)
|
n, err := PropDecode(&prop, dec, false)
|
||||||
if n < 0 {
|
if err != nil {
|
||||||
t.Errorf("PropDecode of string failed")
|
t.Errorf("PropDecode of string failed")
|
||||||
}
|
}
|
||||||
if prop.str != testStrings[i] {
|
if prop.str != testStrings[i] {
|
||||||
|
@ -181,8 +181,8 @@ func TestObject(t *testing.T) {
|
||||||
// Decode it
|
// Decode it
|
||||||
dec := buf[1:]
|
dec := buf[1:]
|
||||||
var dobj1 Object
|
var dobj1 Object
|
||||||
n := Decode(&dobj1, dec, 0)
|
_, err = Decode(&dobj1, dec, false)
|
||||||
if n < 0 {
|
if err != nil {
|
||||||
t.Errorf("Decode of object failed")
|
t.Errorf("Decode of object failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,8 +203,8 @@ func TestObject(t *testing.T) {
|
||||||
// Decode it.
|
// Decode it.
|
||||||
dec = buf[1:]
|
dec = buf[1:]
|
||||||
var dobj2 Object
|
var dobj2 Object
|
||||||
n = Decode(&dobj2, dec, 0)
|
_, err = Decode(&dobj2, dec, false)
|
||||||
if n < 0 {
|
if err != nil {
|
||||||
t.Errorf("Decode of object failed")
|
t.Errorf("Decode of object failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,6 @@ var (
|
||||||
errInvalidHeader = errors.New("rtmp: invalid header")
|
errInvalidHeader = errors.New("rtmp: invalid header")
|
||||||
errInvalidBody = errors.New("rtmp: invalid body")
|
errInvalidBody = errors.New("rtmp: invalid body")
|
||||||
errInvalidFlvTag = errors.New("rtmp: invalid FLV tag")
|
errInvalidFlvTag = errors.New("rtmp: invalid FLV tag")
|
||||||
errDecoding = errors.New("rtmp: decoding error")
|
|
||||||
errUnimplemented = errors.New("rtmp: unimplemented feature")
|
errUnimplemented = errors.New("rtmp: unimplemented feature")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -682,9 +681,9 @@ func handleInvoke(s *Session, body []byte) error {
|
||||||
return errInvalidBody
|
return errInvalidBody
|
||||||
}
|
}
|
||||||
var obj amf.Object
|
var obj amf.Object
|
||||||
nRes := amf.Decode(&obj, body, 0)
|
_, err := amf.Decode(&obj, body, false)
|
||||||
if nRes < 0 {
|
if err != nil {
|
||||||
return errDecoding
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
meth := amf.PropGetString(amf.GetProp(&obj, "", 0))
|
meth := amf.PropGetString(amf.GetProp(&obj, "", 0))
|
||||||
|
|
Loading…
Reference in New Issue