2 * Copyright (C) 2005-2008 Team XBMC
4 * Copyright (C) 2008-2009 Andrej Stepanchuk
5 * Copyright (C) 2009-2010 Howard Chu
7 * This file is part of librtmp.
9 * librtmp is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation; either version 2.1,
12 * or (at your option) any later version.
14 * librtmp is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with librtmp see the file COPYING. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 * http://www.gnu.org/copyleft/lgpl.html
35 static const AMFObjectProperty AMFProp_Invalid
= { {0, 0}, AMF_INVALID
};
36 static const AMFObject AMFObj_Invalid
= { 0, 0 };
37 static const AVal AV_empty
= { 0, 0 };
39 /* Data is Big-Endian */
41 AMF_DecodeInt16(const char *data
)
43 unsigned char *c
= (unsigned char *) data
;
45 val
= (c
[0] << 8) | c
[1];
50 AMF_DecodeInt24(const char *data
)
52 unsigned char *c
= (unsigned char *) data
;
54 val
= (c
[0] << 16) | (c
[1] << 8) | c
[2];
59 AMF_DecodeInt32(const char *data
)
61 unsigned char *c
= (unsigned char *)data
;
63 val
= (c
[0] << 24) | (c
[1] << 16) | (c
[2] << 8) | c
[3];
68 AMF_DecodeString(const char *data
, AVal
*bv
)
70 bv
->av_len
= AMF_DecodeInt16(data
);
71 bv
->av_val
= (bv
->av_len
> 0) ? (char *)data
+ 2 : NULL
;
75 AMF_DecodeLongString(const char *data
, AVal
*bv
)
77 bv
->av_len
= AMF_DecodeInt32(data
);
78 bv
->av_val
= (bv
->av_len
> 0) ? (char *)data
+ 4 : NULL
;
82 AMF_DecodeNumber(const char *data
)
85 #if __FLOAT_WORD_ORDER == __BYTE_ORDER
86 #if __BYTE_ORDER == __BIG_ENDIAN
87 memcpy(&dVal
, data
, 8);
88 #elif __BYTE_ORDER == __LITTLE_ENDIAN
89 unsigned char *ci
, *co
;
90 ci
= (unsigned char *)data
;
91 co
= (unsigned char *)&dVal
;
102 #if __BYTE_ORDER == __LITTLE_ENDIAN /* __FLOAT_WORD_ORER == __BIG_ENDIAN */
103 unsigned char *ci
, *co
;
104 ci
= (unsigned char *)data
;
105 co
= (unsigned char *)&dVal
;
114 #else /* __BYTE_ORDER == __BIG_ENDIAN && __FLOAT_WORD_ORER == __LITTLE_ENDIAN */
115 unsigned char *ci
, *co
;
116 ci
= (unsigned char *)data
;
117 co
= (unsigned char *)&dVal
;
132 AMF_DecodeBoolean(const char *data
)
138 AMF_EncodeInt16(char *output
, char *outend
, short nVal
)
140 if (output
+2 > outend
)
143 output
[1] = nVal
& 0xff;
144 output
[0] = nVal
>> 8;
149 AMF_EncodeInt24(char *output
, char *outend
, int nVal
)
151 if (output
+3 > outend
)
154 output
[2] = nVal
& 0xff;
155 output
[1] = nVal
>> 8;
156 output
[0] = nVal
>> 16;
161 AMF_EncodeInt32(char *output
, char *outend
, int nVal
)
163 if (output
+4 > outend
)
166 output
[3] = nVal
& 0xff;
167 output
[2] = nVal
>> 8;
168 output
[1] = nVal
>> 16;
169 output
[0] = nVal
>> 24;
174 AMF_EncodeString(char *output
, char *outend
, const AVal
*bv
)
176 if ((bv
->av_len
< 65536 && output
+ 1 + 2 + bv
->av_len
> outend
) ||
177 output
+ 1 + 4 + bv
->av_len
> outend
)
180 if (bv
->av_len
< 65536)
182 *output
++ = AMF_STRING
;
184 output
= AMF_EncodeInt16(output
, outend
, bv
->av_len
);
188 *output
++ = AMF_LONG_STRING
;
190 output
= AMF_EncodeInt32(output
, outend
, bv
->av_len
);
192 memcpy(output
, bv
->av_val
, bv
->av_len
);
193 output
+= bv
->av_len
;
199 AMF_EncodeNumber(char *output
, char *outend
, double dVal
)
201 if (output
+1+8 > outend
)
204 *output
++ = AMF_NUMBER
; /* type: Number */
206 #if __FLOAT_WORD_ORDER == __BYTE_ORDER
207 #if __BYTE_ORDER == __BIG_ENDIAN
208 memcpy(output
, &dVal
, 8);
209 #elif __BYTE_ORDER == __LITTLE_ENDIAN
211 unsigned char *ci
, *co
;
212 ci
= (unsigned char *)&dVal
;
213 co
= (unsigned char *)output
;
225 #if __BYTE_ORDER == __LITTLE_ENDIAN /* __FLOAT_WORD_ORER == __BIG_ENDIAN */
227 unsigned char *ci
, *co
;
228 ci
= (unsigned char *)&dVal
;
229 co
= (unsigned char *)output
;
239 #else /* __BYTE_ORDER == __BIG_ENDIAN && __FLOAT_WORD_ORER == __LITTLE_ENDIAN */
241 unsigned char *ci
, *co
;
242 ci
= (unsigned char *)&dVal
;
243 co
= (unsigned char *)output
;
260 AMF_EncodeBoolean(char *output
, char *outend
, int bVal
)
262 if (output
+2 > outend
)
265 *output
++ = AMF_BOOLEAN
;
267 *output
++ = bVal
? 0x01 : 0x00;
273 AMF_EncodeNamedString(char *output
, char *outend
, const AVal
*strName
, const AVal
*strValue
)
275 if (output
+2+strName
->av_len
> outend
)
277 output
= AMF_EncodeInt16(output
, outend
, strName
->av_len
);
279 memcpy(output
, strName
->av_val
, strName
->av_len
);
280 output
+= strName
->av_len
;
282 return AMF_EncodeString(output
, outend
, strValue
);
286 AMF_EncodeNamedNumber(char *output
, char *outend
, const AVal
*strName
, double dVal
)
288 if (output
+2+strName
->av_len
> outend
)
290 output
= AMF_EncodeInt16(output
, outend
, strName
->av_len
);
292 memcpy(output
, strName
->av_val
, strName
->av_len
);
293 output
+= strName
->av_len
;
295 return AMF_EncodeNumber(output
, outend
, dVal
);
299 AMF_EncodeNamedBoolean(char *output
, char *outend
, const AVal
*strName
, int bVal
)
301 if (output
+2+strName
->av_len
> outend
)
303 output
= AMF_EncodeInt16(output
, outend
, strName
->av_len
);
305 memcpy(output
, strName
->av_val
, strName
->av_len
);
306 output
+= strName
->av_len
;
308 return AMF_EncodeBoolean(output
, outend
, bVal
);
312 AMFProp_GetName(AMFObjectProperty
*prop
, AVal
*name
)
314 *name
= prop
->p_name
;
318 AMFProp_SetName(AMFObjectProperty
*prop
, AVal
*name
)
320 prop
->p_name
= *name
;
324 AMFProp_GetType(AMFObjectProperty
*prop
)
330 AMFProp_GetNumber(AMFObjectProperty
*prop
)
332 return prop
->p_vu
.p_number
;
336 AMFProp_GetBoolean(AMFObjectProperty
*prop
)
338 return prop
->p_vu
.p_number
!= 0;
342 AMFProp_GetString(AMFObjectProperty
*prop
, AVal
*str
)
344 if (prop
->p_type
== AMF_STRING
)
345 *str
= prop
->p_vu
.p_aval
;
351 AMFProp_GetObject(AMFObjectProperty
*prop
, AMFObject
*obj
)
353 if (prop
->p_type
== AMF_OBJECT
)
354 *obj
= prop
->p_vu
.p_object
;
356 *obj
= AMFObj_Invalid
;
360 AMFProp_IsValid(AMFObjectProperty
*prop
)
362 return prop
->p_type
!= AMF_INVALID
;
366 AMFProp_Encode(AMFObjectProperty
*prop
, char *pBuffer
, char *pBufEnd
)
368 if (prop
->p_type
== AMF_INVALID
)
371 if (prop
->p_type
!= AMF_NULL
&& pBuffer
+ prop
->p_name
.av_len
+ 2 + 1 >= pBufEnd
)
374 if (prop
->p_type
!= AMF_NULL
&& prop
->p_name
.av_len
)
376 *pBuffer
++ = prop
->p_name
.av_len
>> 8;
377 *pBuffer
++ = prop
->p_name
.av_len
& 0xff;
378 memcpy(pBuffer
, prop
->p_name
.av_val
, prop
->p_name
.av_len
);
379 pBuffer
+= prop
->p_name
.av_len
;
382 switch (prop
->p_type
)
385 pBuffer
= AMF_EncodeNumber(pBuffer
, pBufEnd
, prop
->p_vu
.p_number
);
389 pBuffer
= AMF_EncodeBoolean(pBuffer
, pBufEnd
, prop
->p_vu
.p_number
!= 0);
393 pBuffer
= AMF_EncodeString(pBuffer
, pBufEnd
, &prop
->p_vu
.p_aval
);
397 if (pBuffer
+1 >= pBufEnd
)
399 *pBuffer
++ = AMF_NULL
;
403 pBuffer
= AMF_Encode(&prop
->p_vu
.p_object
, pBuffer
, pBufEnd
);
407 pBuffer
= AMF_EncodeEcmaArray(&prop
->p_vu
.p_object
, pBuffer
, pBufEnd
);
410 case AMF_STRICT_ARRAY
:
411 pBuffer
= AMF_EncodeArray(&prop
->p_vu
.p_object
, pBuffer
, pBufEnd
);
415 RTMP_Log(RTMP_LOGERROR
, "%s, invalid type. %d", __FUNCTION__
, prop
->p_type
);
422 #define AMF3_INTEGER_MAX 268435455
423 #define AMF3_INTEGER_MIN -268435456
426 AMF3ReadInteger(const char *data
, int32_t *valp
)
432 { /* handle first 3 bytes */
435 val
<<= 7; /* shift up */
436 val
|= (data
[i
] & 0x7f); /* add bits */
446 { /* use 4th byte, all 8bits */
451 if (val
> AMF3_INTEGER_MAX
)
455 { /* use 7bits of last unparsed byte (0xxxxxxx) */
462 return i
> 2 ? 4 : i
+ 1;
466 AMF3ReadString(const char *data
, AVal
*str
)
472 len
= AMF3ReadInteger(data
, &ref
);
475 if ((ref
& 0x1) == 0)
476 { /* reference: 0xxx */
477 uint32_t refIndex
= (ref
>> 1);
478 RTMP_Log(RTMP_LOGDEBUG
,
479 "%s, string reference, index: %d, not supported, ignoring!",
480 __FUNCTION__
, refIndex
);
487 uint32_t nSize
= (ref
>> 1);
489 str
->av_val
= (char *)data
;
498 AMF3Prop_Decode(AMFObjectProperty
*prop
, const char *pBuffer
, int nSize
,
501 int nOriginalSize
= nSize
;
504 prop
->p_name
.av_len
= 0;
505 prop
->p_name
.av_val
= NULL
;
507 if (nSize
== 0 || !pBuffer
)
509 RTMP_Log(RTMP_LOGDEBUG
, "empty buffer/no buffer pointer!");
517 int nRes
= AMF3ReadString(pBuffer
, &name
);
519 if (name
.av_len
<= 0)
537 prop
->p_type
= AMF_NULL
;
540 prop
->p_type
= AMF_BOOLEAN
;
541 prop
->p_vu
.p_number
= 0.0;
544 prop
->p_type
= AMF_BOOLEAN
;
545 prop
->p_vu
.p_number
= 1.0;
550 int len
= AMF3ReadInteger(pBuffer
, &res
);
551 prop
->p_vu
.p_number
= (double)res
;
552 prop
->p_type
= AMF_NUMBER
;
559 prop
->p_vu
.p_number
= AMF_DecodeNumber(pBuffer
);
560 prop
->p_type
= AMF_NUMBER
;
567 int len
= AMF3ReadString(pBuffer
, &prop
->p_vu
.p_aval
);
568 prop
->p_type
= AMF_STRING
;
575 int len
= AMF3ReadInteger(pBuffer
, &res
);
580 if ((res
& 0x1) == 0)
582 uint32_t nIndex
= (res
>> 1);
583 RTMP_Log(RTMP_LOGDEBUG
, "AMF3_DATE reference: %d, not supported!", nIndex
);
590 prop
->p_vu
.p_number
= AMF_DecodeNumber(pBuffer
);
592 prop
->p_type
= AMF_NUMBER
;
598 int nRes
= AMF3_Decode(&prop
->p_vu
.p_object
, pBuffer
, nSize
, TRUE
);
602 prop
->p_type
= AMF_OBJECT
;
606 case AMF3_BYTE_ARRAY
:
608 RTMP_Log(RTMP_LOGDEBUG
, "%s - AMF3 unknown/unsupported datatype 0x%02x, @%p",
609 __FUNCTION__
, (unsigned char)(*pBuffer
), pBuffer
);
615 return nOriginalSize
- nSize
;
619 AMFProp_Decode(AMFObjectProperty
*prop
, const char *pBuffer
, int nSize
,
622 int nOriginalSize
= nSize
;
625 prop
->p_name
.av_len
= 0;
626 prop
->p_name
.av_val
= NULL
;
628 if (nSize
== 0 || !pBuffer
)
630 RTMP_Log(RTMP_LOGDEBUG
, "%s: Empty buffer/no buffer pointer!", __FUNCTION__
);
634 if (bDecodeName
&& nSize
< 4)
635 { /* at least name (length + at least 1 byte) and 1 byte of data */
636 RTMP_Log(RTMP_LOGDEBUG
,
637 "%s: Not enough data for decoding with name, less than 4 bytes!",
644 unsigned short nNameSize
= AMF_DecodeInt16(pBuffer
);
645 if (nNameSize
> nSize
- 2)
647 RTMP_Log(RTMP_LOGDEBUG
,
648 "%s: Name size out of range: namesize (%d) > len (%d) - 2",
649 __FUNCTION__
, nNameSize
, nSize
);
653 AMF_DecodeString(pBuffer
, &prop
->p_name
);
654 nSize
-= 2 + nNameSize
;
655 pBuffer
+= 2 + nNameSize
;
665 prop
->p_type
= *pBuffer
++;
666 switch (prop
->p_type
)
671 prop
->p_vu
.p_number
= AMF_DecodeNumber(pBuffer
);
677 prop
->p_vu
.p_number
= (double)AMF_DecodeBoolean(pBuffer
);
682 unsigned short nStringSize
= AMF_DecodeInt16(pBuffer
);
684 if (nSize
< (long)nStringSize
+ 2)
686 AMF_DecodeString(pBuffer
, &prop
->p_vu
.p_aval
);
687 nSize
-= (2 + nStringSize
);
692 int nRes
= AMF_Decode(&prop
->p_vu
.p_object
, pBuffer
, nSize
, TRUE
);
700 RTMP_Log(RTMP_LOGERROR
, "AMF_MOVIECLIP reserved!");
706 case AMF_UNSUPPORTED
:
707 prop
->p_type
= AMF_NULL
;
711 RTMP_Log(RTMP_LOGERROR
, "AMF_REFERENCE not supported!");
719 /* next comes the rest, mixed array has a final 0x000009 mark and names, so its an object */
720 nRes
= AMF_Decode(&prop
->p_vu
.p_object
, pBuffer
+ 4, nSize
, TRUE
);
731 case AMF_STRICT_ARRAY
:
733 unsigned int nArrayLen
= AMF_DecodeInt32(pBuffer
);
736 nRes
= AMF_DecodeArray(&prop
->p_vu
.p_object
, pBuffer
+ 4, nSize
,
745 RTMP_Log(RTMP_LOGDEBUG
, "AMF_DATE");
750 prop
->p_vu
.p_number
= AMF_DecodeNumber(pBuffer
);
751 prop
->p_UTCoffset
= AMF_DecodeInt16(pBuffer
+ 8);
756 case AMF_LONG_STRING
:
759 unsigned int nStringSize
= AMF_DecodeInt32(pBuffer
);
760 if (nSize
< (long)nStringSize
+ 4)
762 AMF_DecodeLongString(pBuffer
, &prop
->p_vu
.p_aval
);
763 nSize
-= (4 + nStringSize
);
764 if (prop
->p_type
== AMF_LONG_STRING
)
765 prop
->p_type
= AMF_STRING
;
770 RTMP_Log(RTMP_LOGERROR
, "AMF_RECORDSET reserved!");
774 case AMF_TYPED_OBJECT
:
776 RTMP_Log(RTMP_LOGERROR
, "AMF_TYPED_OBJECT not supported!");
782 int nRes
= AMF3_Decode(&prop
->p_vu
.p_object
, pBuffer
, nSize
, TRUE
);
786 prop
->p_type
= AMF_OBJECT
;
790 RTMP_Log(RTMP_LOGDEBUG
, "%s - unknown datatype 0x%02x, @%p", __FUNCTION__
,
791 prop
->p_type
, pBuffer
- 1);
795 return nOriginalSize
- nSize
;
799 AMFProp_Dump(AMFObjectProperty
*prop
)
805 if (prop
->p_type
== AMF_INVALID
)
807 RTMP_Log(RTMP_LOGDEBUG
, "Property: INVALID");
811 if (prop
->p_type
== AMF_NULL
)
813 RTMP_Log(RTMP_LOGDEBUG
, "Property: NULL");
817 if (prop
->p_name
.av_len
)
823 name
.av_val
= "no-name.";
824 name
.av_len
= sizeof("no-name.") - 1;
826 if (name
.av_len
> 18)
829 snprintf(strRes
, 255, "Name: %18.*s, ", name
.av_len
, name
.av_val
);
831 if (prop
->p_type
== AMF_OBJECT
)
833 RTMP_Log(RTMP_LOGDEBUG
, "Property: <%sOBJECT>", strRes
);
834 AMF_Dump(&prop
->p_vu
.p_object
);
837 else if (prop
->p_type
== AMF_ECMA_ARRAY
)
839 RTMP_Log(RTMP_LOGDEBUG
, "Property: <%sECMA_ARRAY>", strRes
);
840 AMF_Dump(&prop
->p_vu
.p_object
);
843 else if (prop
->p_type
== AMF_STRICT_ARRAY
)
845 RTMP_Log(RTMP_LOGDEBUG
, "Property: <%sSTRICT_ARRAY>", strRes
);
846 AMF_Dump(&prop
->p_vu
.p_object
);
850 switch (prop
->p_type
)
853 snprintf(str
, 255, "NUMBER:\t%.2f", prop
->p_vu
.p_number
);
856 snprintf(str
, 255, "BOOLEAN:\t%s",
857 prop
->p_vu
.p_number
!= 0.0 ? "TRUE" : "FALSE");
860 snprintf(str
, 255, "STRING:\t%.*s", prop
->p_vu
.p_aval
.av_len
,
861 prop
->p_vu
.p_aval
.av_val
);
864 snprintf(str
, 255, "DATE:\ttimestamp: %.2f, UTC offset: %d",
865 prop
->p_vu
.p_number
, prop
->p_UTCoffset
);
868 snprintf(str
, 255, "INVALID TYPE 0x%02x", (unsigned char)prop
->p_type
);
871 RTMP_Log(RTMP_LOGDEBUG
, "Property: <%s%s>", strRes
, str
);
875 AMFProp_Reset(AMFObjectProperty
*prop
)
877 if (prop
->p_type
== AMF_OBJECT
|| prop
->p_type
== AMF_ECMA_ARRAY
||
878 prop
->p_type
== AMF_STRICT_ARRAY
)
879 AMF_Reset(&prop
->p_vu
.p_object
);
882 prop
->p_vu
.p_aval
.av_len
= 0;
883 prop
->p_vu
.p_aval
.av_val
= NULL
;
885 prop
->p_type
= AMF_INVALID
;
891 AMF_Encode(AMFObject
*obj
, char *pBuffer
, char *pBufEnd
)
895 if (pBuffer
+4 >= pBufEnd
)
898 *pBuffer
++ = AMF_OBJECT
;
900 for (i
= 0; i
< obj
->o_num
; i
++)
902 char *res
= AMFProp_Encode(&obj
->o_props
[i
], pBuffer
, pBufEnd
);
905 RTMP_Log(RTMP_LOGERROR
, "AMF_Encode - failed to encode property in index %d",
915 if (pBuffer
+ 3 >= pBufEnd
)
916 return NULL
; /* no room for the end marker */
918 pBuffer
= AMF_EncodeInt24(pBuffer
, pBufEnd
, AMF_OBJECT_END
);
924 AMF_EncodeEcmaArray(AMFObject
*obj
, char *pBuffer
, char *pBufEnd
)
928 if (pBuffer
+4 >= pBufEnd
)
931 *pBuffer
++ = AMF_ECMA_ARRAY
;
933 pBuffer
= AMF_EncodeInt32(pBuffer
, pBufEnd
, obj
->o_num
);
935 for (i
= 0; i
< obj
->o_num
; i
++)
937 char *res
= AMFProp_Encode(&obj
->o_props
[i
], pBuffer
, pBufEnd
);
940 RTMP_Log(RTMP_LOGERROR
, "AMF_Encode - failed to encode property in index %d",
950 if (pBuffer
+ 3 >= pBufEnd
)
951 return NULL
; /* no room for the end marker */
953 pBuffer
= AMF_EncodeInt24(pBuffer
, pBufEnd
, AMF_OBJECT_END
);
959 AMF_EncodeArray(AMFObject
*obj
, char *pBuffer
, char *pBufEnd
)
963 if (pBuffer
+4 >= pBufEnd
)
966 *pBuffer
++ = AMF_STRICT_ARRAY
;
968 pBuffer
= AMF_EncodeInt32(pBuffer
, pBufEnd
, obj
->o_num
);
970 for (i
= 0; i
< obj
->o_num
; i
++)
972 char *res
= AMFProp_Encode(&obj
->o_props
[i
], pBuffer
, pBufEnd
);
975 RTMP_Log(RTMP_LOGERROR
, "AMF_Encode - failed to encode property in index %d",
985 //if (pBuffer + 3 >= pBufEnd)
986 // return NULL; /* no room for the end marker */
988 //pBuffer = AMF_EncodeInt24(pBuffer, pBufEnd, AMF_OBJECT_END);
994 AMF_DecodeArray(AMFObject
*obj
, const char *pBuffer
, int nSize
,
995 int nArrayLen
, int bDecodeName
)
997 int nOriginalSize
= nSize
;
1001 obj
->o_props
= NULL
;
1002 while (nArrayLen
> 0)
1004 AMFObjectProperty prop
;
1013 nRes
= AMFProp_Decode(&prop
, pBuffer
, nSize
, bDecodeName
);
1023 AMF_AddProp(obj
, &prop
);
1029 return nOriginalSize
- nSize
;
1033 AMF3_Decode(AMFObject
*obj
, const char *pBuffer
, int nSize
, int bAMFData
)
1035 int nOriginalSize
= nSize
;
1040 obj
->o_props
= NULL
;
1043 if (*pBuffer
!= AMF3_OBJECT
)
1044 RTMP_Log(RTMP_LOGERROR
,
1045 "AMF3 Object encapsulated in AMF stream does not start with AMF3_OBJECT!");
1051 len
= AMF3ReadInteger(pBuffer
, &ref
);
1056 { /* object reference, 0xxx */
1057 uint32_t objectIndex
= (ref
>> 1);
1059 RTMP_Log(RTMP_LOGDEBUG
, "Object reference, index: %d", objectIndex
);
1061 else /* object instance */
1063 int32_t classRef
= (ref
>> 1);
1065 AMF3ClassDef cd
= { {0, 0}
1067 AMFObjectProperty prop
;
1069 if ((classRef
& 0x1) == 0)
1070 { /* class reference */
1071 uint32_t classIndex
= (classRef
>> 1);
1072 RTMP_Log(RTMP_LOGDEBUG
, "Class reference: %d", classIndex
);
1076 int32_t classExtRef
= (classRef
>> 1);
1079 cd
.cd_externalizable
= (classExtRef
& 0x1) == 1;
1080 cd
.cd_dynamic
= ((classExtRef
>> 1) & 0x1) == 1;
1082 cdnum
= classExtRef
>> 2;
1086 len
= AMF3ReadString(pBuffer
, &cd
.cd_name
);
1090 /*std::string str = className; */
1092 RTMP_Log(RTMP_LOGDEBUG
,
1093 "Class name: %s, externalizable: %d, dynamic: %d, classMembers: %d",
1094 cd
.cd_name
.av_val
, cd
.cd_externalizable
, cd
.cd_dynamic
,
1097 for (i
= 0; i
< cdnum
; i
++)
1103 RTMP_Log(RTMP_LOGDEBUG
, "%s, invalid class encoding!",
1105 return nOriginalSize
;
1107 len
= AMF3ReadString(pBuffer
, &memberName
);
1108 RTMP_Log(RTMP_LOGDEBUG
, "Member: %s", memberName
.av_val
);
1109 AMF3CD_AddProp(&cd
, &memberName
);
1115 /* add as referencable object */
1117 if (cd
.cd_externalizable
)
1120 AVal name
= AVC("DEFAULT_ATTRIBUTE");
1122 RTMP_Log(RTMP_LOGDEBUG
, "Externalizable, TODO check");
1124 nRes
= AMF3Prop_Decode(&prop
, pBuffer
, nSize
, FALSE
);
1126 RTMP_Log(RTMP_LOGDEBUG
, "%s, failed to decode AMF3 property!",
1134 AMFProp_SetName(&prop
, &name
);
1135 AMF_AddProp(obj
, &prop
);
1140 for (i
= 0; i
< cd
.cd_num
; i
++) /* non-dynamic */
1144 nRes
= AMF3Prop_Decode(&prop
, pBuffer
, nSize
, FALSE
);
1146 RTMP_Log(RTMP_LOGDEBUG
, "%s, failed to decode AMF3 property!",
1149 AMFProp_SetName(&prop
, AMF3CD_GetProp(&cd
, i
));
1150 AMF_AddProp(obj
, &prop
);
1163 nRes
= AMF3Prop_Decode(&prop
, pBuffer
, nSize
, TRUE
);
1164 AMF_AddProp(obj
, &prop
);
1169 len
= prop
.p_name
.av_len
;
1174 RTMP_Log(RTMP_LOGDEBUG
, "class object!");
1176 return nOriginalSize
- nSize
;
1180 AMF_Decode(AMFObject
*obj
, const char *pBuffer
, int nSize
, int bDecodeName
)
1182 int nOriginalSize
= nSize
;
1183 int bError
= FALSE
; /* if there is an error while decoding - try to at least find the end mark AMF_OBJECT_END */
1186 obj
->o_props
= NULL
;
1189 AMFObjectProperty prop
;
1192 if (nSize
>=3 && AMF_DecodeInt24(pBuffer
) == AMF_OBJECT_END
)
1201 RTMP_Log(RTMP_LOGERROR
,
1202 "DECODING ERROR, IGNORING BYTES UNTIL NEXT KNOWN PATTERN!");
1208 nRes
= AMFProp_Decode(&prop
, pBuffer
, nSize
, bDecodeName
);
1223 AMF_AddProp(obj
, &prop
);
1230 return nOriginalSize
- nSize
;
1234 AMF_AddProp(AMFObject
*obj
, const AMFObjectProperty
*prop
)
1236 if (!(obj
->o_num
& 0x0f))
1238 realloc(obj
->o_props
, (obj
->o_num
+ 16) * sizeof(AMFObjectProperty
));
1239 memcpy(&obj
->o_props
[obj
->o_num
++], prop
, sizeof(AMFObjectProperty
));
1243 AMF_CountProp(AMFObject
*obj
)
1249 AMF_GetProp(AMFObject
*obj
, const AVal
*name
, int nIndex
)
1253 if (nIndex
< obj
->o_num
)
1254 return &obj
->o_props
[nIndex
];
1259 for (n
= 0; n
< obj
->o_num
; n
++)
1261 if (AVMATCH(&obj
->o_props
[n
].p_name
, name
))
1262 return &obj
->o_props
[n
];
1266 return (AMFObjectProperty
*)&AMFProp_Invalid
;
1270 AMF_Dump(AMFObject
*obj
)
1273 RTMP_Log(RTMP_LOGDEBUG
, "(object begin)");
1274 for (n
= 0; n
< obj
->o_num
; n
++)
1276 AMFProp_Dump(&obj
->o_props
[n
]);
1278 RTMP_Log(RTMP_LOGDEBUG
, "(object end)");
1282 AMF_Reset(AMFObject
*obj
)
1285 for (n
= 0; n
< obj
->o_num
; n
++)
1287 AMFProp_Reset(&obj
->o_props
[n
]);
1290 obj
->o_props
= NULL
;
1295 /* AMF3ClassDefinition */
1298 AMF3CD_AddProp(AMF3ClassDef
*cd
, AVal
*prop
)
1300 if (!(cd
->cd_num
& 0x0f))
1301 cd
->cd_props
= realloc(cd
->cd_props
, (cd
->cd_num
+ 16) * sizeof(AVal
));
1302 cd
->cd_props
[cd
->cd_num
++] = *prop
;
1306 AMF3CD_GetProp(AMF3ClassDef
*cd
, int nIndex
)
1308 if (nIndex
>= cd
->cd_num
)
1309 return (AVal
*)&AV_empty
;
1310 return &cd
->cd_props
[nIndex
];