// char* AMF_Encode(AMFObject* obj, char* pBuffer, char* pBufEnd); // char* AMF_EncodeEcmaArray(AMFObject* obj, char* pBuffer, char* pBufEnd); // char* AMF_EncodeArray(AMFObject* obj, char* pBuffer, char* pBufEnd); /// <summary> int AMF_Decode(AMFObject * obj, const char *pBuffer, int nSize, int bDecodeName); </summary> public static int AMF_Decode(AMFObject obj, byte[] buf, int pbuf, int nSize, bool bDecodeName) { int nOriginalSize = nSize; bool bError = false; /* if there is an error while decoding - try to at least find the end mark AMF_OBJECT_END */ obj.o_num = 0; obj.o_props = null; while (nSize > 0) { if (nSize >= 3) { if (AMF.AMF_DecodeInt24(buf, pbuf) == (uint)AMFDataType.AMF_OBJECT_END) { nSize -= 3; bError = false; break; } } if (bError) { Log.RTMP_Log(Log.RTMP_LogLevel.RTMP_LOGERROR, "DECODING ERROR, IGNORING BYTES UNTIL NEXT KNOWN PATTERN!"); nSize--; pbuf++; continue; } AMFObjectProperty prop = new AMFObjectProperty(); int nRes = AMFObjectProperty.AMFProp_Decode(prop, buf, pbuf, nSize, bDecodeName); if (nRes == -1) { bError = true; } else { nSize -= nRes; pbuf += nRes; AMF_AddProp(obj, prop); } } if (bError) { return(-1); } return(nOriginalSize - nSize); }
/// <summary> int AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, int bDecodeName)</summary> public static int AMFProp_Decode(AMFObjectProperty prop, byte[] buf, int pBuffer, int nSize, bool bDecodeName) { const string __FUNCTION__ = "AMFProp_Decode"; int nOriginalSize = nSize; prop.p_name = new AVal(); if (nSize == 0 || pBuffer > buf.Length) { Log.RTMP_Log(Log.RTMP_LogLevel.RTMP_LOGDEBUG, "{0}: Empty buffer/no buffer pointer!", __FUNCTION__); return(-1); } if (bDecodeName && nSize < 4) { /* at least name (length + at least 1 byte) and 1 byte of data */ Log.RTMP_Log(Log.RTMP_LogLevel.RTMP_LOGDEBUG, "{0}: Not enough data for decoding with name, less than 4 bytes!", __FUNCTION__); return(-1); } if (bDecodeName) { var nNameSize = AMF.AMF_DecodeInt16(buf, pBuffer); if (nNameSize > nSize - 2) { Log.RTMP_Log(Log.RTMP_LogLevel.RTMP_LOGDEBUG, "{0}: Name size out of range: namesize ({1}) > len ({2}) - 2", __FUNCTION__, nNameSize, nSize); return(-1); } AVal name; AMF.AMF_DecodeString(buf, pBuffer, out name); prop.p_name = name; nSize -= 2 + nNameSize; pBuffer += 2 + nNameSize; } if (nSize == 0) { return(-1); } nSize--; prop.p_type = (AMFDataType)buf[pBuffer++]; // *pBuffer++; switch (prop.p_type) { case AMFDataType.AMF_NUMBER: if (nSize < 8) { return(-1); } prop.p_number = AMF.AMF_DecodeNumber(buf, pBuffer); nSize -= 8; break; case AMFDataType.AMF_BOOLEAN: if (nSize < 1) { return(-1); } prop.p_number = AMF.AMF_DecodeBoolean(buf, pBuffer) ? 1 : 0; nSize--; break; case AMFDataType.AMF_STRING: { var nStringSize = AMF.AMF_DecodeInt16(buf, pBuffer); if (nSize < (long)nStringSize + 2) { return(-1); } AVal v; AMF.AMF_DecodeString(buf, pBuffer, out v); prop.p_aval = v; nSize -= (2 + nStringSize); break; } case AMFDataType.AMF_OBJECT: { int nRes = AMFObject.AMF_Decode(prop.p_object, buf, pBuffer, nSize, true); if (nRes == -1) { return(-1); } nSize -= nRes; break; } case AMFDataType.AMF_MOVIECLIP: Log.RTMP_Log(Log.RTMP_LogLevel.RTMP_LOGERROR, "AMF_MOVIECLIP reserved!"); return(-1); case AMFDataType.AMF_NULL: case AMFDataType.AMF_UNDEFINED: case AMFDataType.AMF_UNSUPPORTED: prop.p_type = AMFDataType.AMF_NULL; break; case AMFDataType.AMF_REFERENCE: Log.RTMP_Log(Log.RTMP_LogLevel.RTMP_LOGERROR, "AMF_REFERENCE not supported!"); return(-1); case AMFDataType.AMF_ECMA_ARRAY: { nSize -= 4; /* next comes the rest, mixed array has a final 0x000009 mark and names, so its an object */ var nRes = AMFObject.AMF_Decode(prop.p_object, buf, pBuffer + 4, nSize, true); if (nRes == -1) { return(-1); } nSize -= nRes; } break; case AMFDataType.AMF_OBJECT_END: return(-1); case AMFDataType.AMF_STRICT_ARRAY: { var nArrayLen = AMF.AMF_DecodeInt32(buf, pBuffer); nSize -= 4; var nRes = AMFObject.AMF_DecodeArray(prop.p_object, buf, pBuffer + 4, nSize, (int)nArrayLen, false); if (nRes == -1) { return(-1); } nSize -= nRes; } break; case AMFDataType.AMF_DATE: { Log.RTMP_Log(Log.RTMP_LogLevel.RTMP_LOGDEBUG, "AMF_DATE"); if (nSize < 10) { return(-1); } prop.p_number = AMF.AMF_DecodeNumber(buf, pBuffer); prop.p_UTCoffset = (short)AMF.AMF_DecodeInt16(buf, pBuffer + 8); nSize -= 10; break; } case AMFDataType.AMF_LONG_STRING: case AMFDataType.AMF_XML_DOC: { var nStringSize = AMF.AMF_DecodeInt32(buf, pBuffer); if (nSize < (long)nStringSize + 4) { return(-1); } AVal v; AMF.AMF_DecodeLongString(buf, pBuffer, out v); prop.p_aval = v; nSize -= (int)(4 + nStringSize); if (prop.p_type == AMFDataType.AMF_LONG_STRING) { prop.p_type = AMFDataType.AMF_STRING; } break; } case AMFDataType.AMF_RECORDSET: Log.RTMP_Log(Log.RTMP_LogLevel.RTMP_LOGERROR, "AMF_RECORDSET reserved!"); return(-1); case AMFDataType.AMF_TYPED_OBJECT: Log.RTMP_Log(Log.RTMP_LogLevel.RTMP_LOGERROR, "AMF_TYPED_OBJECT not supported!"); return(-1); case AMFDataType.AMF_AVMPLUS: { var nRes = AMFObject.AMF3_Decode(prop.p_object, buf, pBuffer, nSize, true); if (nRes == -1) { return(-1); } nSize -= nRes; prop.p_type = AMFDataType.AMF_OBJECT; break; } default: Log.RTMP_Log(Log.RTMP_LogLevel.RTMP_LOGDEBUG, "{0} - unknown datatype 0x{1:x2}, @{2}", __FUNCTION__, prop.p_type, pBuffer - 1); return(-1); } return(nOriginalSize - nSize); }