mirror of https://bitbucket.org/ausocean/av.git
779 lines
20 KiB
Go
779 lines
20 KiB
Go
/*
|
|
NAME
|
|
amf.go
|
|
|
|
DESCRIPTION
|
|
See Readme.md
|
|
|
|
AUTHORS
|
|
Saxon Nelson-Milton <saxon@ausocean.org>
|
|
Dan Kortschak <dan@ausocean.org>
|
|
Jake Lane <jake@ausocean.org>
|
|
|
|
LICENSE
|
|
amf.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean)
|
|
|
|
It is free software: you can redistribute it and/or modify them
|
|
under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation, either version 3 of the License, or (at your
|
|
option) any later version.
|
|
|
|
It is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with revid in gpl.txt. If not, see http://www.gnu.org/licenses.
|
|
|
|
Derived from librtmp under the GNU Lesser General Public License 2.1
|
|
Copyright (C) 2005-2008 Team XBMC http://www.xbmc.org
|
|
Copyright (C) 2008-2009 Andrej Stepanchuk
|
|
Copyright (C) 2009-2010 Howard Chu
|
|
*/
|
|
package rtmp
|
|
|
|
/*
|
|
#include <stdlib.h>
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"log"
|
|
"math"
|
|
"unsafe"
|
|
)
|
|
|
|
var (
|
|
AMFObj_Invalid C_AMFObject
|
|
AMFProp_Invalid = C_AMFObjectProperty{p_type: AMF_INVALID}
|
|
)
|
|
|
|
const (
|
|
AMF3_INTEGER_MAX = 268435455
|
|
AMF3_INTEGER_MIN = -268435456
|
|
)
|
|
|
|
func pp2b(b, e *byte) []byte {
|
|
if b == nil {
|
|
return nil
|
|
}
|
|
base := unsafe.Pointer(b)
|
|
len := uintptr(unsafe.Pointer(e)) - uintptr(base)
|
|
return (*[_Gi]byte)(base)[:len]
|
|
}
|
|
|
|
// unsigned short AMF_DecodeInt16(const char* data);
|
|
// amf.c +41
|
|
func C_AMF_DecodeInt16(data []byte) uint16 {
|
|
return uint16(data[0])<<8 | uint16(data[1])
|
|
}
|
|
|
|
// unsigned int AMF_DecodeInt24(const char* data);
|
|
// amf.c +50
|
|
func C_AMF_DecodeInt24(data []byte) uint32 {
|
|
return uint32(data[0])<<16 | uint32(data[1])<<8 | uint32(data[2])
|
|
}
|
|
|
|
// unsigned int AMF_DeocdeInt32(const char* data);
|
|
// amf.c +59
|
|
func C_AMF_DecodeInt32(data []byte) uint32 {
|
|
return uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
|
|
}
|
|
|
|
// void AMF_DecodeString(const char* data, C_AVal* bv);
|
|
// amf.c +68
|
|
func C_AMF_DecodeString(data []byte) string {
|
|
n := C_AMF_DecodeInt16(data)
|
|
return string(data[2 : 2+n])
|
|
}
|
|
|
|
// void AMF_DecodeLongString(const char *data, AVal *bv);
|
|
// amf.c +75
|
|
func C_AMF_DecodeLongString(data []byte) string {
|
|
n := C_AMF_DecodeInt32(data)
|
|
return string(data[2 : 2+n])
|
|
}
|
|
|
|
// double AMF_DecodeNumber(const char* data);
|
|
// amf.c +82
|
|
func C_AMF_DecodeNumber(data []byte) float64 {
|
|
return math.Float64frombits(binary.BigEndian.Uint64(data))
|
|
}
|
|
|
|
// int AMF_DecodeBoolean(const char *data);
|
|
// amf.c +132
|
|
func C_AMF_DecodeBoolean(data []byte) bool {
|
|
return data[0] != 0
|
|
}
|
|
|
|
// char* AMF_EncodeInt24(char* output, char* outend, int nVal);
|
|
// amf.c +149
|
|
func C_AMF_EncodeInt24(dst []byte, val int32) *byte {
|
|
if len(dst) < 3 {
|
|
return nil
|
|
}
|
|
_ = dst[2]
|
|
dst[0] = byte(val >> 16)
|
|
dst[1] = byte(val >> 8)
|
|
dst[2] = byte(val)
|
|
if len(dst) == 3 {
|
|
return nil
|
|
}
|
|
return &dst[3:][0]
|
|
}
|
|
|
|
// char* AMF_EncodeInt32(char* output, char* outend, int nVal);
|
|
// amf.c +160
|
|
func C_AMF_EncodeInt32(dst []byte, val int32) *byte {
|
|
if len(dst) < 4 {
|
|
return nil
|
|
}
|
|
binary.BigEndian.PutUint32(dst, uint32(val))
|
|
if len(dst) == 4 {
|
|
return nil
|
|
}
|
|
return &dst[4:][0]
|
|
}
|
|
|
|
// char* AMF_EncodeString(char* output, char* outend, const C_AVal* bv);
|
|
// amf.c +173
|
|
func C_AMF_EncodeString(dst []byte, val string) *byte {
|
|
const typeSize = 1
|
|
if len(val) < 65536 && len(val)+typeSize+binary.Size(int16(0)) > len(dst) {
|
|
return nil
|
|
}
|
|
if len(val)+typeSize+binary.Size(int32(0)) > len(dst) {
|
|
return nil
|
|
}
|
|
|
|
if len(val) < 65536 {
|
|
dst[0] = AMF_STRING
|
|
dst = dst[1:]
|
|
binary.BigEndian.PutUint16(dst[:2], uint16(len(val)))
|
|
dst = dst[2:]
|
|
copy(dst, val)
|
|
if len(dst) == len(val) {
|
|
return nil
|
|
}
|
|
return &dst[len(val):][0]
|
|
}
|
|
dst[0] = AMF_LONG_STRING
|
|
dst = dst[1:]
|
|
binary.BigEndian.PutUint32(dst[:4], uint32(len(val)))
|
|
dst = dst[4:]
|
|
copy(dst, val)
|
|
if len(dst) == len(val) {
|
|
return nil
|
|
}
|
|
return &dst[len(val):][0]
|
|
}
|
|
|
|
// char* AMF_EncodeNumber(char* output, char* outend, double dVal);
|
|
// amf.c +199
|
|
func C_AMF_EncodeNumber(dst []byte, val float64) *byte {
|
|
if len(dst) < 9 {
|
|
return nil
|
|
}
|
|
dst[0] = AMF_NUMBER
|
|
dst = dst[1:]
|
|
binary.BigEndian.PutUint64(dst, math.Float64bits(val))
|
|
return &dst[8:][0]
|
|
}
|
|
|
|
// char* AMF_EncodeBoolean(char* output, char* outend, int bVal);
|
|
// amf.c +260
|
|
func C_AMF_EncodeBoolean(dst []byte, val bool) *byte {
|
|
if len(dst) < 2 {
|
|
return nil
|
|
}
|
|
dst[0] = AMF_BOOLEAN
|
|
if val {
|
|
dst[1] = 1
|
|
}
|
|
if len(dst) == 2 {
|
|
return nil
|
|
}
|
|
return &dst[2:][0]
|
|
|
|
}
|
|
|
|
// char* AMF_EncodeNamedString(char* output, char* outend, const C_AVal* strName, const C_AVal* strValue);
|
|
// amf.c +273
|
|
func C_AMF_EncodeNamedString(dst []byte, key, val string) *byte {
|
|
if 2+len(key) > len(dst) {
|
|
return nil
|
|
}
|
|
binary.BigEndian.PutUint16(dst[:2], uint16(len(key)))
|
|
dst = dst[2:]
|
|
copy(dst, key)
|
|
if len(key) == len(dst) {
|
|
return nil
|
|
}
|
|
return C_AMF_EncodeString(dst[len(key):], val)
|
|
}
|
|
|
|
// char* AMF_EncodeNamedNumber(char* output, char* outend, const C_AVal* strName, double dVal);
|
|
// amf.c +286
|
|
func C_AMF_EncodeNamedNumber(dst []byte, key string, val float64) *byte {
|
|
if 2+len(key) > len(dst) {
|
|
return nil
|
|
}
|
|
binary.BigEndian.PutUint16(dst[:2], uint16(len(key)))
|
|
dst = dst[2:]
|
|
copy(dst, key)
|
|
if len(key) == len(dst) {
|
|
return nil
|
|
}
|
|
return C_AMF_EncodeNumber(dst[len(key):], val)
|
|
}
|
|
|
|
// char* AMF_EncodeNamedBoolean(char* output, char* outend, const C_AVal* strname, int bVal);
|
|
// amf.c +299
|
|
func C_AMF_EncodeNamedBoolean(dst []byte, key string, val bool) *byte {
|
|
if 2+len(key) > len(dst) {
|
|
return nil
|
|
}
|
|
binary.BigEndian.PutUint16(dst[:2], uint16(len(key)))
|
|
dst = dst[2:]
|
|
copy(dst, key)
|
|
if len(key) == len(dst) {
|
|
return nil
|
|
}
|
|
return C_AMF_EncodeBoolean(dst[len(key):], val)
|
|
}
|
|
|
|
// void AMFProp_SetName(AMFObjectProperty *prop, AVal *name);
|
|
// amf.c +318
|
|
func C_AMFProp_SetName(prop *C_AMFObjectProperty, name string) {
|
|
prop.p_name = name
|
|
}
|
|
|
|
// double AMFProp_GetNumber(AMFObjectProperty* prop);
|
|
// amf.c +330
|
|
func C_AMFProp_GetNumber(prop *C_AMFObjectProperty) float64 {
|
|
return prop.p_vu.p_number
|
|
}
|
|
|
|
// void AMFProp_GetString(AMFObjectProperty* prop, AVal* str);
|
|
// amf.c +341
|
|
func C_AMFProp_GetString(prop *C_AMFObjectProperty) string {
|
|
if prop.p_type == AMF_STRING {
|
|
return prop.p_vu.p_aval
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// void AMFProp_GetObject(AMFObjectProperty *prop, AMFObject *obj);
|
|
// amf.c +351
|
|
func C_AMFProp_GetObject(prop *C_AMFObjectProperty, obj *C_AMFObject) {
|
|
if prop.p_type == AMF_OBJECT {
|
|
*obj = prop.p_vu.p_object
|
|
} else {
|
|
*obj = AMFObj_Invalid
|
|
}
|
|
}
|
|
|
|
// char* AMFPropEncode(AMFOBjectProperty* prop, char* pBufer, char* pBufEnd);
|
|
// amf.c +366
|
|
func C_AMF_PropEncode(p *C_AMFObjectProperty, pBuffer *byte, pBufEnd *byte) *byte {
|
|
if p.p_type == AMF_INVALID {
|
|
return nil
|
|
}
|
|
|
|
buflen := int(uintptr(unsafe.Pointer(pBufEnd)) - uintptr(unsafe.Pointer(pBuffer)))
|
|
if p.p_type != AMF_NULL && len(p.p_name)+2+1 >= buflen {
|
|
return nil
|
|
}
|
|
|
|
if p.p_type != AMF_NULL && len(p.p_name) != 0 {
|
|
(*[_Gi]byte)(unsafe.Pointer(pBuffer))[0] = byte(len(p.p_name) >> 8)
|
|
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
|
|
(*[_Gi]byte)(unsafe.Pointer(pBuffer))[0] = byte(len(p.p_name) & 0xff)
|
|
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
|
|
copy((*[_Gi]byte)(unsafe.Pointer(pBuffer))[:], p.p_name)
|
|
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), len(p.p_name)))
|
|
}
|
|
|
|
switch p.p_type {
|
|
case AMF_NUMBER:
|
|
pBuffer = C_AMF_EncodeNumber(pp2b(pBuffer, pBufEnd), p.p_vu.p_number)
|
|
case AMF_BOOLEAN:
|
|
pBuffer = C_AMF_EncodeBoolean(pp2b(pBuffer, pBufEnd), p.p_vu.p_number != 0)
|
|
case AMF_STRING:
|
|
pBuffer = C_AMF_EncodeString(pp2b(pBuffer, pBufEnd), p.p_vu.p_aval)
|
|
case AMF_NULL:
|
|
buflen = int(uintptr(unsafe.Pointer(pBufEnd)) - uintptr(unsafe.Pointer(pBuffer)))
|
|
if 1 >= buflen {
|
|
return nil
|
|
}
|
|
*(*byte)(unsafe.Pointer(pBuffer)) = AMF_NULL
|
|
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
|
|
case AMF_OBJECT:
|
|
pBuffer = C_AMF_Encode(&p.p_vu.p_object, pBuffer, pBufEnd)
|
|
//pBuffer = (*byte)(unsafe.Pointer(C.AMF_Encode(&p.p_vu.p_object, (*byte)(
|
|
//unsafe.Pointer(pBuffer)), (*byte)(unsafe.Pointer(pBufEnd)))))
|
|
case AMF_ECMA_ARRAY:
|
|
pBuffer = C_AMF_EncodeEcmaArray(&p.p_vu.p_object, pBuffer, pBufEnd)
|
|
//pBuffer = (*byte)(unsafe.Pointer(C.AMF_EncodeEcmaArray(&p.p_vu.p_object, (*byte)(unsafe.Pointer(pBuffer)), (*byte)(unsafe.Pointer(pBufEnd)))))
|
|
case AMF_STRICT_ARRAY:
|
|
//pBuffer = (*byte)(unsafe.Pointer(C.AMF_EncodeArray(&p.p_vu.p_object, (*byte)(unsafe.Pointer(pBuffer)), (*byte)(unsafe.Pointer(pBufEnd)))))
|
|
pBuffer = C_AMF_EncodeArray(&p.p_vu.p_object, pBuffer, pBufEnd)
|
|
default:
|
|
log.Println("C_AMF_PropEncode: invalid type!")
|
|
pBuffer = nil
|
|
}
|
|
return pBuffer
|
|
}
|
|
|
|
// int AMF3ReadInteger(const char *data, int32_t *valp);
|
|
// amf.c +426
|
|
// TODO test
|
|
func C_AMF3ReadInteger(data *byte, valp *int32) int32 {
|
|
var i int
|
|
var val int32
|
|
|
|
for i <= 2 {
|
|
/* handle first 3 bytes */
|
|
if (*[_Gi]byte)(unsafe.Pointer(data))[i]&0x80 != 0 {
|
|
/* byte used */
|
|
val <<= 7 /* shift up */
|
|
val |= int32((*[_Gi]byte)(unsafe.Pointer(data))[i] & 0x7f) /* add bits */
|
|
i++
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
|
|
if i > 2 {
|
|
/* use 4th byte, all 8bits */
|
|
val <<= 8
|
|
val |= int32((*[_Gi]byte)(unsafe.Pointer(data))[3])
|
|
|
|
/* range check */
|
|
if val > AMF3_INTEGER_MAX {
|
|
val -= (1 << 29)
|
|
}
|
|
} else {
|
|
/* use 7bits of last unparsed byte (0xxxxxxx) */
|
|
val <<= 7
|
|
val |= int32((*[_Gi]byte)(unsafe.Pointer(data))[i])
|
|
}
|
|
|
|
*valp = val
|
|
|
|
if i > 2 {
|
|
return 4
|
|
}
|
|
return int32(i + 1)
|
|
}
|
|
|
|
// int AMF3ReadString(const char *data, AVal *str);
|
|
// amf.c +466
|
|
func C_AMF3ReadString(data *byte, str *string) int32 {
|
|
var ref int32
|
|
// assert elided - we will get a panic if it's nil.
|
|
|
|
len := C_AMF3ReadInteger(data, &ref)
|
|
data = (*byte)(sliceToPtr((*[_Gi]byte)(unsafe.Pointer(data))[len:]))
|
|
|
|
if ref&0x1 == 0 {
|
|
/* reference: 0xxx */
|
|
// TODO(kortschak) Logging.
|
|
// refIndex := (ref >> 1)
|
|
// RTMP_Log(RTMP_LOGDEBUG,
|
|
// "%s, string reference, index: %d, not supported, ignoring!",
|
|
// __FUNCTION__, refIndex);
|
|
*str = ""
|
|
return len
|
|
} else {
|
|
nSize := (ref >> 1)
|
|
*str = string((*[_Gi]byte)(unsafe.Pointer(data))[:nSize])
|
|
return len + nSize
|
|
}
|
|
return len
|
|
}
|
|
|
|
// int AMFProp_Decode(C_AMFObjectProperty* prop, const char* pBuffer, int nSize, int bDecodeName);
|
|
// amf.c +619
|
|
func C_AMFProp_Decode(prop *C_AMFObjectProperty, pBuffer *byte, nSize, bDecodeName int32) int32 {
|
|
|
|
var nOriginalSize int32 = nSize
|
|
var nRes int32
|
|
|
|
prop.p_name = ""
|
|
|
|
if nSize == 0 || pBuffer == nil {
|
|
// TODO use new logger here
|
|
// RTMP_Log(RTMP_LOGDEBUG, "%s: Empty buffer/no buffer pointer!", __FUNCTION__);
|
|
return -1
|
|
}
|
|
|
|
if bDecodeName != 0 && nSize < 4 {
|
|
// at least name (length + at least 1 byte) and 1 byte of data
|
|
// TODO use new logger here
|
|
// RTMP_Log(RTMP_LOGDEBUG, "%s: Not enough data for decoding with name, less than 4 bytes!",__FUNCTION__);
|
|
return -1
|
|
}
|
|
|
|
if bDecodeName != 0 {
|
|
nNameSize := C_AMF_DecodeInt16((*[_Gi]byte)(unsafe.Pointer(pBuffer))[:2])
|
|
if int32(nNameSize) > nSize-2 {
|
|
// TODO use new logger here
|
|
//RTMP_Log(RTMP_LOGDEBUG, "%s: Name size out of range: namesize (%d) > len (%d) - 2",__FUNCTION__, nNameSize, nSize);
|
|
return -1
|
|
}
|
|
|
|
prop.p_name = C_AMF_DecodeString((*[_Gi]byte)(unsafe.Pointer(pBuffer))[:nSize])
|
|
nSize -= int32(2 + nNameSize)
|
|
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(2+nNameSize)))
|
|
}
|
|
|
|
if nSize == 0 {
|
|
return -1
|
|
}
|
|
|
|
nSize--
|
|
|
|
prop.p_type = (C_AMFDataType)(int32(*pBuffer))
|
|
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
|
|
|
|
switch prop.p_type {
|
|
case AMF_NUMBER:
|
|
if nSize < 8 {
|
|
return -1
|
|
}
|
|
prop.p_vu.p_number = C_AMF_DecodeNumber((*[_Gi]byte)(unsafe.Pointer(pBuffer))[:nSize])
|
|
nSize -= 8
|
|
|
|
case AMF_BOOLEAN:
|
|
panic("AMF_BOOLEAN not supported")
|
|
|
|
case AMF_STRING:
|
|
var nStringSize = C_AMF_DecodeInt16((*[_Gi]byte)(unsafe.Pointer(pBuffer))[:2])
|
|
if int64(nSize) < int64(nStringSize)+2 {
|
|
return -1
|
|
}
|
|
prop.p_vu.p_aval = C_AMF_DecodeString((*[_Gi]byte)(unsafe.Pointer(pBuffer))[:nSize])
|
|
nSize -= int32(2 + nStringSize)
|
|
|
|
case AMF_OBJECT:
|
|
var nRes int32 = C_AMF_Decode(&prop.p_vu.p_object, pBuffer, nSize, 1)
|
|
if nRes == -1 {
|
|
return -1
|
|
}
|
|
nSize -= nRes
|
|
|
|
case AMF_MOVIECLIP:
|
|
// TODO use new logger here
|
|
log.Println("AMFProp_Decode: MAF_MOVIECLIP reserved!")
|
|
//RTMP_Log(RTMP_LOGERROR, "AMF_MOVIECLIP reserved!");
|
|
return -1
|
|
|
|
case AMF_NULL, AMF_UNDEFINED, AMF_UNSUPPORTED:
|
|
prop.p_type = AMF_NULL
|
|
|
|
case AMF_REFERENCE:
|
|
|
|
// TODO use new logger here
|
|
log.Println("AMFProp_Decode: AMF_REFERENCE not supported!")
|
|
//RTMP_Log(RTMP_LOGERROR, "AMF_REFERENCE not supported!");
|
|
return -1
|
|
|
|
case AMF_ECMA_ARRAY:
|
|
|
|
nSize -= 4
|
|
|
|
// next comes the rest, mixed array has a final 0x000009 mark and names, so its an object
|
|
nRes = C_AMF_Decode(&prop.p_vu.p_object, (*byte)(incBytePtr(
|
|
unsafe.Pointer(pBuffer), 4)), nSize, 1)
|
|
if nRes == -1 {
|
|
return -1
|
|
}
|
|
nSize -= nRes
|
|
|
|
case AMF_OBJECT_END:
|
|
|
|
return -1
|
|
|
|
case AMF_STRICT_ARRAY:
|
|
panic("AMF_STRICT_ARRAY not supported")
|
|
|
|
case AMF_DATE:
|
|
panic("AMF_DATE not supported")
|
|
|
|
case AMF_LONG_STRING, AMF_XML_DOC:
|
|
panic("AMF_LONG_STRING, AMF_XML_DOC not supported")
|
|
|
|
case AMF_RECORDSET:
|
|
// TODO use new logger here
|
|
log.Println("AMFProp_Decode: AMF_RECORDSET reserved!")
|
|
//RTMP_Log(RTMP_LOGERROR, "AMF_RECORDSET reserved!");
|
|
return -1
|
|
|
|
case AMF_TYPED_OBJECT:
|
|
|
|
// TODO use new logger here
|
|
// RTMP_Log(RTMP_LOGERROR, "AMF_TYPED_OBJECT not supported!")
|
|
return -1
|
|
|
|
case AMF_AVMPLUS:
|
|
panic("AMF_AVMPLUS not supported")
|
|
|
|
default:
|
|
// TODO use new logger here
|
|
//RTMP_Log(RTMP_LOGDEBUG, "%s - unknown datatype 0x%02x, @%p", __FUNCTION__,
|
|
//prop.p_type, pBuffer - 1);
|
|
return -1
|
|
}
|
|
|
|
return nOriginalSize - nSize
|
|
}
|
|
|
|
// void AMFProp_Reset(AMFObjectProperty* prop);
|
|
// amf.c +875
|
|
func C_AMFProp_Reset(prop *C_AMFObjectProperty) {
|
|
if prop.p_type == AMF_OBJECT || prop.p_type == AMF_ECMA_ARRAY ||
|
|
prop.p_type == AMF_STRICT_ARRAY {
|
|
C_AMF_Reset(&prop.p_vu.p_object)
|
|
} else {
|
|
prop.p_vu.p_aval = ""
|
|
}
|
|
prop.p_type = AMF_INVALID
|
|
}
|
|
|
|
// char* AMF_Encode(AMFObject* obj, char* pBuffer, char* pBufEnd);
|
|
// amf.c +891
|
|
func C_AMF_Encode(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte {
|
|
if uintptr(unsafe.Pointer(pBuffer))+uintptr(4) >= uintptr(unsafe.Pointer(pBufEnd)) {
|
|
return nil
|
|
}
|
|
|
|
*pBuffer = AMF_OBJECT
|
|
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
|
|
|
|
for i := 0; i < int(obj.o_num); i++ {
|
|
res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer(
|
|
obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd)
|
|
if res == nil {
|
|
log.Println("C_AMF_Encode: failed to encode property in index")
|
|
break
|
|
} else {
|
|
pBuffer = res
|
|
}
|
|
}
|
|
|
|
if uintptr(incBytePtr(unsafe.Pointer(pBuffer), 3)) >= uintptr(unsafe.Pointer(pBufEnd)) {
|
|
return nil
|
|
}
|
|
|
|
pBuffer = C_AMF_EncodeInt24(pp2b(pBuffer, pBufEnd), int32(AMF_OBJECT_END))
|
|
|
|
return pBuffer
|
|
}
|
|
|
|
// char* AMF_EncodeEcmaArray(AMFObject* obj, char* pBuffer, char* pBufEnd);
|
|
// amf.c +924
|
|
func C_AMF_EncodeEcmaArray(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte {
|
|
if int(uintptr(unsafe.Pointer(pBuffer)))+4 >= int(uintptr(unsafe.Pointer(pBufEnd))) {
|
|
return nil
|
|
}
|
|
|
|
*pBuffer = AMF_ECMA_ARRAY
|
|
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
|
|
|
|
pBuffer = C_AMF_EncodeInt32(pp2b(pBuffer, pBufEnd), obj.o_num)
|
|
|
|
for i := 0; i < int(obj.o_num); i++ {
|
|
res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer(
|
|
obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd)
|
|
if res == nil {
|
|
log.Println("C_AMF_EncodeEcmaArray: failed to encode property!")
|
|
break
|
|
} else {
|
|
pBuffer = res
|
|
}
|
|
}
|
|
|
|
if int(uintptr(unsafe.Pointer(pBuffer)))+3 >= int(uintptr(unsafe.Pointer(pBufEnd))) {
|
|
return nil
|
|
}
|
|
|
|
pBuffer = C_AMF_EncodeInt24(pp2b(pBuffer, pBufEnd), AMF_OBJECT_END)
|
|
|
|
return pBuffer
|
|
}
|
|
|
|
// char* AMF_EncodeArray(AMFObject* obj, char* pBuffer, char* pBufEnd);
|
|
// amf.c +959
|
|
func C_AMF_EncodeArray(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte {
|
|
if int(uintptr(unsafe.Pointer(pBuffer)))+4 >= int(uintptr(unsafe.Pointer(pBufEnd))) {
|
|
return nil
|
|
}
|
|
|
|
*pBuffer = AMF_STRICT_ARRAY
|
|
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
|
|
|
|
pBuffer = C_AMF_EncodeInt32(pp2b(pBuffer, pBufEnd), obj.o_num)
|
|
|
|
for i := 0; i < int(obj.o_num); i++ {
|
|
res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer(
|
|
obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd)
|
|
if res == nil {
|
|
log.Println("C_AMF_EncodeEcmaArray: failed to encode property!")
|
|
break
|
|
} else {
|
|
pBuffer = res
|
|
}
|
|
}
|
|
|
|
return pBuffer
|
|
}
|
|
|
|
// int AMF_DecodeArray(AMFObject *obj, const char *pBuffer, int nSize, int nArrayLen, int bDecodeName);
|
|
// amf.c +993
|
|
func C_AMF_DecodeArray(obj *C_AMFObject, pBuffer *byte, nSize, nArrayLen, bDecodeName int32) int32 {
|
|
nOriginalSize := nSize
|
|
var bError int32 = 0
|
|
|
|
obj.o_num = 0
|
|
obj.o_props = nil
|
|
for nArrayLen > 0 {
|
|
var prop C_AMFObjectProperty
|
|
var nRes int32
|
|
nArrayLen--
|
|
|
|
if nSize <= 0 {
|
|
bError = 1
|
|
break
|
|
}
|
|
nRes = C_AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName)
|
|
if nRes == -1 {
|
|
bError = 1
|
|
break
|
|
} else {
|
|
nSize -= nRes
|
|
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(nRes)))
|
|
C_AMF_AddProp(obj, &prop)
|
|
}
|
|
}
|
|
if bError != 0 {
|
|
return -1
|
|
}
|
|
|
|
return nOriginalSize - nSize
|
|
}
|
|
|
|
// int AMF_Decode(AMFObject *obj, const char* pBuffer, int nSize, int bDecodeName);
|
|
// amf.c +1180
|
|
func C_AMF_Decode(obj *C_AMFObject, pBuffer *byte, nSize, bDecodeName int32) int32 {
|
|
nOriginalSize := nSize
|
|
var bError int32
|
|
|
|
obj.o_num = 0
|
|
obj.o_props = nil
|
|
|
|
for nSize > 0 {
|
|
var prop C_AMFObjectProperty
|
|
var nRes int32
|
|
|
|
if nSize >= 3 && C_AMF_DecodeInt24((*[_Gi]byte)(unsafe.Pointer(pBuffer))[:3]) == AMF_OBJECT_END {
|
|
nSize -= 3
|
|
bError = 0
|
|
break
|
|
}
|
|
|
|
if bError != 0 {
|
|
// TODO use new logger here
|
|
log.Println("AMF_Decode: decoding error, ignoring bytes until next known pattern!")
|
|
nSize--
|
|
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
|
|
continue
|
|
}
|
|
// TODO port AMFProp_Decode
|
|
nRes = C_AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName)
|
|
// nRes = int32(C.AMFProp_Decode(&prop, (*byte)(unsafe.Pointer(pBuffer)),
|
|
// int32(nSize), int32(bDecodeName)))
|
|
if nRes == -1 {
|
|
bError = 1
|
|
break
|
|
} else {
|
|
nSize -= nRes
|
|
if nSize < 0 {
|
|
bError = 1
|
|
break
|
|
}
|
|
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(nRes)))
|
|
C_AMF_AddProp(obj, &prop)
|
|
}
|
|
}
|
|
|
|
if bError != 0 {
|
|
return -1
|
|
}
|
|
|
|
return nOriginalSize - nSize
|
|
}
|
|
|
|
// void AMF_AddProp(AMFObject* obj, const AMFObjectProperty* prop);
|
|
// amf.c + 1234
|
|
func C_AMF_AddProp(obj *C_AMFObject, prop *C_AMFObjectProperty) {
|
|
if (obj.o_num & 0x0f) == 0 {
|
|
//obj.o_props = (*C_AMFObjectProperty)(realloc(unsafe.Pointer(obj.o_props),
|
|
//uint32(int(obj.o_num+16)*int(unsafe.Sizeof(*obj.o_props)))))
|
|
obj.o_props = (*C_AMFObjectProperty)(C.realloc(unsafe.Pointer(obj.o_props),
|
|
C.size_t(int(obj.o_num+16)*int(unsafe.Sizeof(*obj.o_props)))))
|
|
}
|
|
memmove(unsafe.Pointer(&(*(*C_AMFObjectProperty)(incPtr(
|
|
unsafe.Pointer(obj.o_props), int(obj.o_num), int(unsafe.Sizeof(*obj.o_props)))))),
|
|
unsafe.Pointer(prop), unsafe.Sizeof(*obj.o_props))
|
|
obj.o_num++
|
|
}
|
|
|
|
// AMFObjectProperty* AMF_GetProp(AMFObject *obj, const AVal* name, int nIndex);
|
|
// amf.c + 1249
|
|
func C_AMF_GetProp(obj *C_AMFObject, name string, nIndex int32) *C_AMFObjectProperty {
|
|
if nIndex >= 0 {
|
|
if nIndex < obj.o_num {
|
|
return &(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props),
|
|
int(nIndex), int(unsafe.Sizeof(*obj.o_props)))))
|
|
}
|
|
} else {
|
|
for n := int32(0); n < obj.o_num; n++ {
|
|
p_name := (*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props),
|
|
int(n), int(unsafe.Sizeof(*obj.o_props))))).p_name
|
|
if p_name == name {
|
|
return &(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props),
|
|
int(n), int(unsafe.Sizeof(*obj.o_props)))))
|
|
}
|
|
}
|
|
}
|
|
return &AMFProp_Invalid
|
|
}
|
|
|
|
// void AMF_Reset(AMFObject* obj);
|
|
// amf.c +1282
|
|
func C_AMF_Reset(obj *C_AMFObject) {
|
|
var n int32
|
|
for n = 0; n < obj.o_num; n++ {
|
|
C_AMFProp_Reset(&(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props),
|
|
int(n), int(unsafe.Sizeof(*obj.o_props))))))
|
|
}
|
|
//C.free(unsafe.Pointer(obj.o_props))
|
|
obj.o_props = nil
|
|
obj.o_num = 0
|
|
}
|
|
|
|
/*
|
|
// void AMF3CD_AddProp(AMF3ClassDef *cd, AVal *prop);
|
|
// amf.c +1298
|
|
func AMF3CD_AddProp(cd *C.AMF3ClassDef, prop *C_AVal) {
|
|
if cd.cd_num&0x0f == 0 {
|
|
cd.cd_props = (*C_AVal)(realloc(unsafe.Pointer(cd.cd_props), int(uintptr(cd.cd_num+16)*unsafe.Sizeof(C_AVal{}))))
|
|
}
|
|
*(*C_AVal)(incPtr(unsafe.Pointer(cd.cd_props), int(cd.cd_num), int(unsafe.Sizeof(C_AVal{})))) = *prop
|
|
cd.cd_num++
|
|
}
|
|
*/
|