/* NAME amf.go DESCRIPTION See Readme.md AUTHORS Saxon Nelson-Milton Dan Kortschak Jake Lane 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 */ import "C" import ( "log" "unsafe" ) var ( AMFObj_Invalid C_AMFObject AMFProp_Invalid = C_AMFObjectProperty{p_type: AMF_INVALID} ) const ( AMF3_INTEGER_MAX = 268435455 AMF3_INTEGER_MIN = -268435456 ) // unsigned short AMF_DecodeInt16(const char* data); // amf.c +41 func C_AMF_DecodeInt16(data *byte) uint16 { c := unsafe.Pointer(data) return uint16(*(*uint8)(c)<<8 | *(*byte)(incBytePtr(c, 1))) } // unsigned int AMF_DecodeInt24(const char* data); // amf.c +50 func C_AMF_DecodeInt24(data *byte) uint32 { c := (*[3]byte)(unsafe.Pointer(data)) return (uint32(c[0]) << 16) | (uint32(c[1]) << 8) | uint32(c[2]) /* // TODO Understand logic and simplify c := (*uint8)(unsafe.Pointer(data)) dst := uint32(int32(*c) << 16) dst |= uint32(int32(*((*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + (uintptr)(int32(1))*unsafe.Sizeof(*c))))) << 8) dst |= uint32(int32(*((*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + (uintptr)(int32(2))*unsafe.Sizeof(*c)))))) return dst */ } // unsigned int AMF_DeocdeInt32(const char* data); // amf.c +59 func C_AMF_DecodeInt32(data *byte) uint32 { c := (*uint8)(data) val := uint32( int32(*c)<<24 | int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 1)))<<16 | int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 2)))<<8 | int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 3)))) return uint32(val) } // void AMF_DecodeString(const char* data, C_AVal* bv); // amf.c +68 func C_AMF_DecodeString(data *byte, bv *C_AVal) { dataPtr := unsafe.Pointer(data) //bv.av_len = int32(C.AMF_DecodeInt16((*byte)(dataPtr))) bv.av_len = int32(C_AMF_DecodeInt16((*byte)(dataPtr))) if bv.av_len > 0 { bv.av_val = (*byte)(incBytePtr(dataPtr, 2)) } else { bv.av_val = nil } } // void AMF_DecodeLongString(const char *data, AVal *bv); // amf.c +75 func C_AMF_DecodeLongString(data *byte, bv *C_AVal) { bv.av_len = int32(C_AMF_DecodeInt32(data)) if bv.av_len > 0 { bv.av_val = (*byte)(incBytePtr(unsafe.Pointer(data), 4)) } else { bv.av_val = nil } } // double AMF_DecodeNumber(const char* data); // amf.c +82 func C_AMF_DecodeNumber(data *byte) float64 { var dVal float64 var ci, co *uint8 ci = (*uint8)(unsafe.Pointer(data)) co = (*uint8)(unsafe.Pointer(&dVal)) for i := 0; i < 8; i++ { (*[_Gi]byte)(unsafe.Pointer(co))[i] = (*[_Gi]byte)(unsafe.Pointer(ci))[7-i] } return dVal } // int AMF_DecodeBoolean(const char *data); // amf.c +132 func C_AMF_DecodeBoolean(data *byte) int32 { if *data != 0 { return 1 } return 0 } // char* AMF_EncodeInt16(char* output, char* outend, short nVal); // amf.c +138 func C_AMF_EncodeInt16(output *byte, outend *byte, nVal int16) *byte { outputPtr := unsafe.Pointer(output) outendPtr := unsafe.Pointer(outend) if uintptr(outputPtr)+2 > uintptr(outendPtr) { // length < 2 return nil } // Assign output[1] second := (*byte)(incBytePtr(outputPtr, 1)) *second = (byte)(nVal & 0xff) // Assign output[0] *output = (byte)(nVal >> 8) return (*byte)(incBytePtr(outputPtr, 2)) } // char* AMF_EncodeInt24(char* output, char* outend, int nVal); // amf.c +149 func C_AMF_EncodeInt24(output *byte, outend *byte, nVal int32) *byte { outputPtr := unsafe.Pointer(output) outendPtr := unsafe.Pointer(outend) if uintptr(outputPtr)+3 > uintptr(outendPtr) { // length < 3 return nil } // Assign output[2] third := (*byte)(incBytePtr(outputPtr, 2)) *third = (byte)(nVal & 0xff) // Assign output[1] second := (*byte)(incBytePtr(outputPtr, 1)) *second = (byte)(nVal >> 8) // Assign output[0] *output = (byte)(nVal >> 16) return (*byte)(incBytePtr(outputPtr, 3)) } // char* AMF_EncodeInt32(char* output, char* outend, int nVal); // amf.c +161 func C_AMF_EncodeInt32(output *byte, outend *byte, nVal int32) *byte { outputPtr := unsafe.Pointer(output) outendPtr := unsafe.Pointer(outend) if uintptr(outputPtr)+4 > uintptr(outendPtr) { // length < 4 return nil } // Assign output[3] forth := (*byte)(incBytePtr(outputPtr, 3)) *forth = (byte)(nVal & 0xff) // Assign output[2] third := (*byte)(incBytePtr(outputPtr, 2)) *third = (byte)(nVal >> 8) // Assign output[1] second := (*byte)(incBytePtr(outputPtr, 1)) *second = (byte)(nVal >> 16) // Assign output[0] *output = (byte)(nVal >> 24) return (*byte)(incBytePtr(outputPtr, 4)) } // char* AMF_EncodeString(char* output, char* outend, const C_AVal* bv); // amf.c +174 func C_AMF_EncodeString(output *byte, outend *byte, bv *C_AVal) *byte { outputPtr := unsafe.Pointer(output) outendPtr := unsafe.Pointer(outend) if (bv.av_len < 65536 && uintptr(incBytePtr(outputPtr, 1+2+int(bv.av_len))) > uintptr(outendPtr)) || uintptr(incBytePtr(outputPtr, 1+4+int(bv.av_len))) > uintptr(outendPtr) { return nil } if bv.av_len < 65536 { *(*byte)(outputPtr) = AMF_STRING outputPtr = incBytePtr(outputPtr, 1) // TODO: port AMF_EncodeInt16 outputPtr = unsafe.Pointer(C_AMF_EncodeInt16((*byte)(outputPtr), (*byte)( outendPtr), int16(bv.av_len))) //outputPtr = unsafe.Pointer(C_AMF_EncodeInt16((*byte)(outputPtr), //(*byte)(outendPtr), (int16)(bv.av_len))) } else { *(*byte)(outputPtr) = AMF_LONG_STRING outputPtr = incBytePtr(outputPtr, 1) outputPtr = unsafe.Pointer(C_AMF_EncodeInt32((*byte)(outputPtr), (*byte)( outendPtr), int32(bv.av_len))) //outputPtr = unsafe.Pointer(C_AMF_EncodeInt32((*byte)(outputPtr), //(*byte)(outendPtr), (int32)(bv.av_len))) } memmove(unsafe.Pointer(outputPtr), unsafe.Pointer(bv.av_val), uintptr(bv.av_len)) //C.memcpy(unsafe.Pointer(outputPtr), unsafe.Pointer(bv.av_val), (C.size_t)(bv.av_len)) outputPtr = incBytePtr(outputPtr, int(bv.av_len)) return (*byte)(outputPtr) } // char* AMF_EncodeNumber(char* output, char* outend, double dVal); // amf.c +199 func C_AMF_EncodeNumber(output *byte, outend *byte, dVal float64) *byte { if int(uintptr(unsafe.Pointer(output)))+1+8 > int(uintptr(unsafe.Pointer(outend))) { return nil } // TODO: port this *(*byte)(unsafe.Pointer(output)) = AMF_NUMBER output = (*byte)(incBytePtr(unsafe.Pointer(output), 1)) // NOTE: here we are assuming little endian for both byte order and float // word order var ci, co *uint8 ci = (*uint8)(unsafe.Pointer(&dVal)) co = (*uint8)(unsafe.Pointer(output)) for i := 0; i < 8; i++ { (*[_Gi]byte)(unsafe.Pointer(co))[i] = (*[_Gi]byte)(unsafe.Pointer(ci))[7-i] } return (*byte)(incBytePtr(unsafe.Pointer(output), 8)) } // char* AMF_EncodeBoolean(char* output, char* outend, int bVal); // amf.c +260 func C_AMF_EncodeBoolean(output *byte, outend *byte, bVal int) *byte { if int(uintptr(unsafe.Pointer(output)))+2 > int(uintptr(unsafe.Pointer(outend))) { return nil } *(*byte)(unsafe.Pointer(output)) = AMF_BOOLEAN output = (*byte)(incBytePtr(unsafe.Pointer(output), 1)) val := byte(0x01) if bVal == 0 { val = byte(0x00) } *(*byte)(unsafe.Pointer(output)) = val output = (*byte)(incBytePtr(unsafe.Pointer(output), 1)) return output } // char* AMF_EncodeNamedString(char* output, char* outend, const C_AVal* strName, const C_AVal* strValue); // amf.c +273 func C_AMF_EncodeNamedString(output *byte, outend *byte, strName *C_AVal, strValue *C_AVal) *byte { if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) { return nil } output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len)) memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len)) output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len))) return C_AMF_EncodeString(output, outend, strValue) } // char* AMF_EncodeNamedNumber(char* output, char* outend, const C_AVal* strName, double dVal); // amf.c +286 func C_AMF_EncodeNamedNumber(output *byte, outend *byte, strName *C_AVal, dVal float64) *byte { if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) { return nil } output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len)) memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len)) output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len))) return C_AMF_EncodeNumber(output, outend, dVal) } // char* AMF_EncodeNamedBoolean(char* output, char* outend, const C_AVal* strname, int bVal); // amf.c +299 func C_AMF_EncodeNamedBoolean(output *byte, outend *byte, strName *C_AVal, bVal int) *byte { if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) { return nil } output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len)) memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len)) output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len))) return C_AMF_EncodeBoolean(output, outend, bVal) } // void AMFProp_SetName(AMFObjectProperty *prop, AVal *name); // amf.c +318 func C_AMFProp_SetName(prop *C_AMFObjectProperty, name *C_AVal) { prop.p_name = *name } // double AMFProp_GetNumber(AMFObjectProperty* prop); // amf.c +330 func C_AMFProp_GetNumber(prop *C_AMFObjectProperty) float64 { return float64(prop.p_vu.p_number) } // void AMFProp_GetString(AMFObjectProperty* prop, AVal* str); // amf.c +341 func C_AMFProp_GetString(prop *C_AMFObjectProperty, str *C_AVal) { if prop.p_type == AMF_STRING { *str = prop.p_vu.p_aval } else { *str = AV_empty } } // 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 } if p.p_type != AMF_NULL && int(uintptr(unsafe.Pointer(pBuffer)))+ int(p.p_name.av_len)+2+1 >= int( uintptr(unsafe.Pointer(pBufEnd))) { return nil } if p.p_type != AMF_NULL && p.p_name.av_len != 0 { (*[_Gi]byte)(unsafe.Pointer(pBuffer))[0] = byte(p.p_name.av_len >> 8) pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) (*[_Gi]byte)(unsafe.Pointer(pBuffer))[0] = byte(p.p_name.av_len & 0xff) pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1)) memmove(unsafe.Pointer(pBuffer), unsafe.Pointer(p.p_name.av_val), uintptr(p.p_name.av_len)) pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(p.p_name.av_len))) } switch p.p_type { case AMF_NUMBER: pBuffer = C_AMF_EncodeNumber(pBuffer, pBufEnd, float64(p.p_vu.p_number)) case AMF_BOOLEAN: val := 0 if p.p_vu.p_number != 0 { val = 1 } pBuffer = C_AMF_EncodeBoolean(pBuffer, pBufEnd, val) case AMF_STRING: pBuffer = C_AMF_EncodeString(pBuffer, pBufEnd, &p.p_vu.p_aval) case AMF_NULL: if uintptr(incBytePtr(unsafe.Pointer(pBuffer), 1)) >= uintptr(unsafe.Pointer( pBufEnd)) { 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 *C_AVal) 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.av_val = nil str.av_len = 0 return len } else { nSize := (ref >> 1) str.av_val = data str.av_len = int32(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.av_len = 0 prop.p_name.av_val = nil 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(pBuffer) 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 } C_AMF_DecodeString(pBuffer, &prop.p_name) 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 = float64(C_AMF_DecodeNumber(pBuffer)) nSize -= 8 case AMF_BOOLEAN: panic("AMF_BOOLEAN not supported") case AMF_STRING: var nStringSize = C_AMF_DecodeInt16(pBuffer) if int64(nSize) < int64(nStringSize)+2 { return -1 } C_AMF_DecodeString(pBuffer, &prop.p_vu.p_aval) nSize -= int32(2 + nStringSize) case AMF_OBJECT: var nRes int32 = 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.av_len = 0 prop.p_vu.p_aval.av_val = nil } 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(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(pBuffer, pBufEnd, int32(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(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(pBuffer, pBufEnd, int32(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 int32, bDecodeName int32) int32 { var nOriginalSize int32 = nSize var bError int32 = 0 obj.o_num = 0 obj.o_props = nil for nSize > 0 { var prop C_AMFObjectProperty var nRes int32 if nSize >= 3 && C_AMF_DecodeInt24(pBuffer) == 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 = int32(C_AMFProp_Decode(&prop, (*byte)(unsafe.Pointer(pBuffer)), int32(nSize), int32(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 *C_AVal, nIndex int32) *C_AMFObjectProperty { if nIndex >= 0 { if nIndex < int32(obj.o_num) { return &(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), int(nIndex), int(unsafe.Sizeof(*obj.o_props))))) //return &obj.o_props[nIndex] } } else { var n int32 for n = 0; n < int32(obj.o_num); n++ { if C_AVMATCH(&(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), int(n), int(unsafe.Sizeof(*obj.o_props))))).p_name, name) != 0 { return &(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props), int(n), int(unsafe.Sizeof(*obj.o_props))))) } } } return (*C_AMFObjectProperty)(&AMFProp_Invalid) } // void AMF_Reset(AMFObject* obj); // amf.c +1282 func C_AMF_Reset(obj *C_AMFObject) { var n int32 for n = 0; n < int32(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++ } */