amf.Decode and amf.PropDecode now return an error.

This commit is contained in:
scruzin 2019-01-12 14:55:12 +10:30
parent b79a035d0f
commit 1fe1849393
3 changed files with 50 additions and 100 deletions

View File

@ -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 decodeName != 0 { if int(n) > len(data)-2 {
nNameSize := DecodeInt16(data[:2]) return 0, ErrDecodingName
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 {

View File

@ -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")
} }
} }

View File

@ -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))