More for input buffer checks
[rtmpdump.git] / librtmp / amf.c
blob1c5f99f2f9878816d231b143939456360883877c
1 /*
2 * Copyright (C) 2005-2008 Team XBMC
3 * http://www.xbmc.org
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
26 #include <string.h>
27 #include <assert.h>
28 #include <stdlib.h>
30 #include "rtmp_sys.h"
31 #include "amf.h"
32 #include "log.h"
33 #include "bytes.h"
35 static const AMFObjectProperty AMFProp_Invalid = { {0, 0}, AMF_INVALID };
36 static const AVal AV_empty = { 0, 0 };
38 /* Data is Big-Endian */
39 unsigned short
40 AMF_DecodeInt16(const char *data)
42 unsigned char *c = (unsigned char *) data;
43 unsigned short val;
44 val = (c[0] << 8) | c[1];
45 return val;
48 unsigned int
49 AMF_DecodeInt24(const char *data)
51 unsigned char *c = (unsigned char *) data;
52 unsigned int val;
53 val = (c[0] << 16) | (c[1] << 8) | c[2];
54 return val;
57 unsigned int
58 AMF_DecodeInt32(const char *data)
60 unsigned char *c = (unsigned char *)data;
61 unsigned int val;
62 val = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
63 return val;
66 void
67 AMF_DecodeString(const char *data, AVal *bv)
69 bv->av_len = AMF_DecodeInt16(data);
70 bv->av_val = (bv->av_len > 0) ? (char *)data + 2 : NULL;
73 void
74 AMF_DecodeLongString(const char *data, AVal *bv)
76 bv->av_len = AMF_DecodeInt32(data);
77 bv->av_val = (bv->av_len > 0) ? (char *)data + 4 : NULL;
80 double
81 AMF_DecodeNumber(const char *data)
83 double dVal;
84 #if __FLOAT_WORD_ORDER == __BYTE_ORDER
85 #if __BYTE_ORDER == __BIG_ENDIAN
86 memcpy(&dVal, data, 8);
87 #elif __BYTE_ORDER == __LITTLE_ENDIAN
88 unsigned char *ci, *co;
89 ci = (unsigned char *)data;
90 co = (unsigned char *)&dVal;
91 co[0] = ci[7];
92 co[1] = ci[6];
93 co[2] = ci[5];
94 co[3] = ci[4];
95 co[4] = ci[3];
96 co[5] = ci[2];
97 co[6] = ci[1];
98 co[7] = ci[0];
99 #endif
100 #else
101 #if __BYTE_ORDER == __LITTLE_ENDIAN /* __FLOAT_WORD_ORER == __BIG_ENDIAN */
102 unsigned char *ci, *co;
103 ci = (unsigned char *)data;
104 co = (unsigned char *)&dVal;
105 co[0] = ci[3];
106 co[1] = ci[2];
107 co[2] = ci[1];
108 co[3] = ci[0];
109 co[4] = ci[7];
110 co[5] = ci[6];
111 co[6] = ci[5];
112 co[7] = ci[4];
113 #else /* __BYTE_ORDER == __BIG_ENDIAN && __FLOAT_WORD_ORER == __LITTLE_ENDIAN */
114 unsigned char *ci, *co;
115 ci = (unsigned char *)data;
116 co = (unsigned char *)&dVal;
117 co[0] = ci[4];
118 co[1] = ci[5];
119 co[2] = ci[6];
120 co[3] = ci[7];
121 co[4] = ci[0];
122 co[5] = ci[1];
123 co[6] = ci[2];
124 co[7] = ci[3];
125 #endif
126 #endif
127 return dVal;
131 AMF_DecodeBoolean(const char *data)
133 return *data != 0;
136 char *
137 AMF_EncodeInt16(char *output, char *outend, short nVal)
139 if (output+2 > outend)
140 return NULL;
142 output[1] = nVal & 0xff;
143 output[0] = nVal >> 8;
144 return output+2;
147 char *
148 AMF_EncodeInt24(char *output, char *outend, int nVal)
150 if (output+3 > outend)
151 return NULL;
153 output[2] = nVal & 0xff;
154 output[1] = nVal >> 8;
155 output[0] = nVal >> 16;
156 return output+3;
159 char *
160 AMF_EncodeInt32(char *output, char *outend, int nVal)
162 if (output+4 > outend)
163 return NULL;
165 output[3] = nVal & 0xff;
166 output[2] = nVal >> 8;
167 output[1] = nVal >> 16;
168 output[0] = nVal >> 24;
169 return output+4;
172 char *
173 AMF_EncodeString(char *output, char *outend, const AVal *bv)
175 if ((bv->av_len < 65536 && output + 1 + 2 + bv->av_len > outend) ||
176 output + 1 + 4 + bv->av_len > outend)
177 return NULL;
179 if (bv->av_len < 65536)
181 *output++ = AMF_STRING;
183 output = AMF_EncodeInt16(output, outend, bv->av_len);
185 else
187 *output++ = AMF_LONG_STRING;
189 output = AMF_EncodeInt32(output, outend, bv->av_len);
191 memcpy(output, bv->av_val, bv->av_len);
192 output += bv->av_len;
194 return output;
197 char *
198 AMF_EncodeNumber(char *output, char *outend, double dVal)
200 if (output+1+8 > outend)
201 return NULL;
203 *output++ = AMF_NUMBER; /* type: Number */
205 #if __FLOAT_WORD_ORDER == __BYTE_ORDER
206 #if __BYTE_ORDER == __BIG_ENDIAN
207 memcpy(output, &dVal, 8);
208 #elif __BYTE_ORDER == __LITTLE_ENDIAN
210 unsigned char *ci, *co;
211 ci = (unsigned char *)&dVal;
212 co = (unsigned char *)output;
213 co[0] = ci[7];
214 co[1] = ci[6];
215 co[2] = ci[5];
216 co[3] = ci[4];
217 co[4] = ci[3];
218 co[5] = ci[2];
219 co[6] = ci[1];
220 co[7] = ci[0];
222 #endif
223 #else
224 #if __BYTE_ORDER == __LITTLE_ENDIAN /* __FLOAT_WORD_ORER == __BIG_ENDIAN */
226 unsigned char *ci, *co;
227 ci = (unsigned char *)&dVal;
228 co = (unsigned char *)output;
229 co[0] = ci[3];
230 co[1] = ci[2];
231 co[2] = ci[1];
232 co[3] = ci[0];
233 co[4] = ci[7];
234 co[5] = ci[6];
235 co[6] = ci[5];
236 co[7] = ci[4];
238 #else /* __BYTE_ORDER == __BIG_ENDIAN && __FLOAT_WORD_ORER == __LITTLE_ENDIAN */
240 unsigned char *ci, *co;
241 ci = (unsigned char *)&dVal;
242 co = (unsigned char *)output;
243 co[0] = ci[4];
244 co[1] = ci[5];
245 co[2] = ci[6];
246 co[3] = ci[7];
247 co[4] = ci[0];
248 co[5] = ci[1];
249 co[6] = ci[2];
250 co[7] = ci[3];
252 #endif
253 #endif
255 return output+8;
258 char *
259 AMF_EncodeBoolean(char *output, char *outend, int bVal)
261 if (output+2 > outend)
262 return NULL;
264 *output++ = AMF_BOOLEAN;
266 *output++ = bVal ? 0x01 : 0x00;
268 return output;
271 char *
272 AMF_EncodeNamedString(char *output, char *outend, const AVal *strName, const AVal *strValue)
274 if (output+2+strName->av_len > outend)
275 return NULL;
276 output = AMF_EncodeInt16(output, outend, strName->av_len);
278 memcpy(output, strName->av_val, strName->av_len);
279 output += strName->av_len;
281 return AMF_EncodeString(output, outend, strValue);
284 char *
285 AMF_EncodeNamedNumber(char *output, char *outend, const AVal *strName, double dVal)
287 if (output+2+strName->av_len > outend)
288 return NULL;
289 output = AMF_EncodeInt16(output, outend, strName->av_len);
291 memcpy(output, strName->av_val, strName->av_len);
292 output += strName->av_len;
294 return AMF_EncodeNumber(output, outend, dVal);
297 char *
298 AMF_EncodeNamedBoolean(char *output, char *outend, const AVal *strName, int bVal)
300 if (output+2+strName->av_len > outend)
301 return NULL;
302 output = AMF_EncodeInt16(output, outend, strName->av_len);
304 memcpy(output, strName->av_val, strName->av_len);
305 output += strName->av_len;
307 return AMF_EncodeBoolean(output, outend, bVal);
310 void
311 AMFProp_GetName(AMFObjectProperty *prop, AVal *name)
313 *name = prop->p_name;
316 void
317 AMFProp_SetName(AMFObjectProperty *prop, AVal *name)
319 prop->p_name = *name;
322 AMFDataType
323 AMFProp_GetType(AMFObjectProperty *prop)
325 return prop->p_type;
328 double
329 AMFProp_GetNumber(AMFObjectProperty *prop)
331 return prop->p_vu.p_number;
335 AMFProp_GetBoolean(AMFObjectProperty *prop)
337 return prop->p_vu.p_number != 0;
340 void
341 AMFProp_GetString(AMFObjectProperty *prop, AVal *str)
343 *str = prop->p_vu.p_aval;
346 void
347 AMFProp_GetObject(AMFObjectProperty *prop, AMFObject *obj)
349 *obj = prop->p_vu.p_object;
353 AMFProp_IsValid(AMFObjectProperty *prop)
355 return prop->p_type != AMF_INVALID;
358 char *
359 AMFProp_Encode(AMFObjectProperty *prop, char *pBuffer, char *pBufEnd)
361 if (prop->p_type == AMF_INVALID)
362 return NULL;
364 if (prop->p_type != AMF_NULL && pBuffer + prop->p_name.av_len + 2 + 1 >= pBufEnd)
365 return NULL;
367 if (prop->p_type != AMF_NULL && prop->p_name.av_len)
369 *pBuffer++ = prop->p_name.av_len >> 8;
370 *pBuffer++ = prop->p_name.av_len & 0xff;
371 memcpy(pBuffer, prop->p_name.av_val, prop->p_name.av_len);
372 pBuffer += prop->p_name.av_len;
375 switch (prop->p_type)
377 case AMF_NUMBER:
378 pBuffer = AMF_EncodeNumber(pBuffer, pBufEnd, prop->p_vu.p_number);
379 break;
381 case AMF_BOOLEAN:
382 pBuffer = AMF_EncodeBoolean(pBuffer, pBufEnd, prop->p_vu.p_number != 0);
383 break;
385 case AMF_STRING:
386 pBuffer = AMF_EncodeString(pBuffer, pBufEnd, &prop->p_vu.p_aval);
387 break;
389 case AMF_NULL:
390 if (pBuffer+1 >= pBufEnd)
391 return NULL;
392 *pBuffer++ = AMF_NULL;
393 break;
395 case AMF_OBJECT:
396 pBuffer = AMF_Encode(&prop->p_vu.p_object, pBuffer, pBufEnd);
397 break;
399 case AMF_ECMA_ARRAY:
400 pBuffer = AMF_EncodeEcmaArray(&prop->p_vu.p_object, pBuffer, pBufEnd);
401 break;
403 case AMF_STRICT_ARRAY:
404 pBuffer = AMF_EncodeArray(&prop->p_vu.p_object, pBuffer, pBufEnd);
405 break;
407 default:
408 RTMP_Log(RTMP_LOGERROR, "%s, invalid type. %d", __FUNCTION__, prop->p_type);
409 pBuffer = NULL;
412 return pBuffer;
415 #define AMF3_INTEGER_MAX 268435455
416 #define AMF3_INTEGER_MIN -268435456
419 AMF3ReadInteger(const char *data, int32_t *valp)
421 int i = 0;
422 int32_t val = 0;
424 while (i <= 2)
425 { /* handle first 3 bytes */
426 if (data[i] & 0x80)
427 { /* byte used */
428 val <<= 7; /* shift up */
429 val |= (data[i] & 0x7f); /* add bits */
430 i++;
432 else
434 break;
438 if (i > 2)
439 { /* use 4th byte, all 8bits */
440 val <<= 8;
441 val |= data[3];
443 /* range check */
444 if (val > AMF3_INTEGER_MAX)
445 val -= (1 << 29);
447 else
448 { /* use 7bits of last unparsed byte (0xxxxxxx) */
449 val <<= 7;
450 val |= data[i];
453 *valp = val;
455 return i > 2 ? 4 : i + 1;
459 AMF3ReadString(const char *data, AVal *str)
461 int32_t ref = 0;
462 int len;
463 assert(str != 0);
465 len = AMF3ReadInteger(data, &ref);
466 data += len;
468 if ((ref & 0x1) == 0)
469 { /* reference: 0xxx */
470 uint32_t refIndex = (ref >> 1);
471 RTMP_Log(RTMP_LOGDEBUG,
472 "%s, string reference, index: %d, not supported, ignoring!",
473 __FUNCTION__, refIndex);
474 str->av_val = NULL;
475 str->av_len = 0;
476 return len;
478 else
480 uint32_t nSize = (ref >> 1);
482 str->av_val = (char *)data;
483 str->av_len = nSize;
485 return len + nSize;
487 return len;
491 AMF3Prop_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize,
492 int bDecodeName)
494 int nOriginalSize = nSize;
495 AMF3DataType type;
497 prop->p_name.av_len = 0;
498 prop->p_name.av_val = NULL;
500 if (nSize == 0 || !pBuffer)
502 RTMP_Log(RTMP_LOGDEBUG, "empty buffer/no buffer pointer!");
503 return -1;
506 /* decode name */
507 if (bDecodeName)
509 AVal name;
510 int nRes = AMF3ReadString(pBuffer, &name);
512 if (name.av_len <= 0)
513 return nRes;
515 prop->p_name = name;
516 pBuffer += nRes;
517 nSize -= nRes;
520 /* decode */
521 type = *pBuffer++;
522 nSize--;
524 switch (type)
526 case AMF3_UNDEFINED:
527 case AMF3_NULL:
528 prop->p_type = AMF_NULL;
529 break;
530 case AMF3_FALSE:
531 prop->p_type = AMF_BOOLEAN;
532 prop->p_vu.p_number = 0.0;
533 break;
534 case AMF3_TRUE:
535 prop->p_type = AMF_BOOLEAN;
536 prop->p_vu.p_number = 1.0;
537 break;
538 case AMF3_INTEGER:
540 int32_t res = 0;
541 int len = AMF3ReadInteger(pBuffer, &res);
542 prop->p_vu.p_number = (double)res;
543 prop->p_type = AMF_NUMBER;
544 nSize -= len;
545 break;
547 case AMF3_DOUBLE:
548 if (nSize < 8)
549 return -1;
550 prop->p_vu.p_number = AMF_DecodeNumber(pBuffer);
551 prop->p_type = AMF_NUMBER;
552 nSize -= 8;
553 break;
554 case AMF3_STRING:
555 case AMF3_XML_DOC:
556 case AMF3_XML:
558 int len = AMF3ReadString(pBuffer, &prop->p_vu.p_aval);
559 prop->p_type = AMF_STRING;
560 nSize -= len;
561 break;
563 case AMF3_DATE:
565 int32_t res = 0;
566 int len = AMF3ReadInteger(pBuffer, &res);
568 nSize -= len;
569 pBuffer += len;
571 if ((res & 0x1) == 0)
572 { /* reference */
573 uint32_t nIndex = (res >> 1);
574 RTMP_Log(RTMP_LOGDEBUG, "AMF3_DATE reference: %d, not supported!", nIndex);
576 else
578 if (nSize < 8)
579 return -1;
581 prop->p_vu.p_number = AMF_DecodeNumber(pBuffer);
582 nSize -= 8;
583 prop->p_type = AMF_NUMBER;
585 break;
587 case AMF3_OBJECT:
589 int nRes = AMF3_Decode(&prop->p_vu.p_object, pBuffer, nSize, TRUE);
590 if (nRes == -1)
591 return -1;
592 nSize -= nRes;
593 prop->p_type = AMF_OBJECT;
594 break;
596 case AMF3_ARRAY:
597 case AMF3_BYTE_ARRAY:
598 default:
599 RTMP_Log(RTMP_LOGDEBUG, "%s - AMF3 unknown/unsupported datatype 0x%02x, @%p",
600 __FUNCTION__, (unsigned char)(*pBuffer), pBuffer);
601 return -1;
604 return nOriginalSize - nSize;
608 AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize,
609 int bDecodeName)
611 int nOriginalSize = nSize;
612 int nRes;
614 prop->p_name.av_len = 0;
615 prop->p_name.av_val = NULL;
617 if (nSize == 0 || !pBuffer)
619 RTMP_Log(RTMP_LOGDEBUG, "%s: Empty buffer/no buffer pointer!", __FUNCTION__);
620 return -1;
623 if (bDecodeName && nSize < 4)
624 { /* at least name (length + at least 1 byte) and 1 byte of data */
625 RTMP_Log(RTMP_LOGDEBUG,
626 "%s: Not enough data for decoding with name, less than 4 bytes!",
627 __FUNCTION__);
628 return -1;
631 if (bDecodeName)
633 unsigned short nNameSize = AMF_DecodeInt16(pBuffer);
634 if (nNameSize > nSize - 2)
636 RTMP_Log(RTMP_LOGDEBUG,
637 "%s: Name size out of range: namesize (%d) > len (%d) - 2",
638 __FUNCTION__, nNameSize, nSize);
639 return -1;
642 AMF_DecodeString(pBuffer, &prop->p_name);
643 nSize -= 2 + nNameSize;
644 pBuffer += 2 + nNameSize;
647 if (nSize == 0)
649 return -1;
652 nSize--;
654 prop->p_type = *pBuffer++;
655 switch (prop->p_type)
657 case AMF_NUMBER:
658 if (nSize < 8)
659 return -1;
660 prop->p_vu.p_number = AMF_DecodeNumber(pBuffer);
661 nSize -= 8;
662 break;
663 case AMF_BOOLEAN:
664 if (nSize < 1)
665 return -1;
666 prop->p_vu.p_number = (double)AMF_DecodeBoolean(pBuffer);
667 nSize--;
668 break;
669 case AMF_STRING:
671 unsigned short nStringSize = AMF_DecodeInt16(pBuffer);
673 if (nSize < (long)nStringSize + 2)
674 return -1;
675 AMF_DecodeString(pBuffer, &prop->p_vu.p_aval);
676 nSize -= (2 + nStringSize);
677 break;
679 case AMF_OBJECT:
681 int nRes = AMF_Decode(&prop->p_vu.p_object, pBuffer, nSize, TRUE);
682 if (nRes == -1)
683 return -1;
684 nSize -= nRes;
685 break;
687 case AMF_MOVIECLIP:
689 RTMP_Log(RTMP_LOGERROR, "AMF_MOVIECLIP reserved!");
690 return -1;
691 break;
693 case AMF_NULL:
694 case AMF_UNDEFINED:
695 case AMF_UNSUPPORTED:
696 prop->p_type = AMF_NULL;
697 break;
698 case AMF_REFERENCE:
700 RTMP_Log(RTMP_LOGERROR, "AMF_REFERENCE not supported!");
701 return -1;
702 break;
704 case AMF_ECMA_ARRAY:
706 nSize -= 4;
708 /* next comes the rest, mixed array has a final 0x000009 mark and names, so its an object */
709 nRes = AMF_Decode(&prop->p_vu.p_object, pBuffer + 4, nSize, TRUE);
710 if (nRes == -1)
711 return -1;
712 nSize -= nRes;
713 break;
715 case AMF_OBJECT_END:
717 return -1;
718 break;
720 case AMF_STRICT_ARRAY:
722 unsigned int nArrayLen = AMF_DecodeInt32(pBuffer);
723 nSize -= 4;
725 nRes = AMF_DecodeArray(&prop->p_vu.p_object, pBuffer + 4, nSize,
726 nArrayLen, FALSE);
727 if (nRes == -1)
728 return -1;
729 nSize -= nRes;
730 break;
732 case AMF_DATE:
734 RTMP_Log(RTMP_LOGDEBUG, "AMF_DATE");
736 if (nSize < 10)
737 return -1;
739 prop->p_vu.p_number = AMF_DecodeNumber(pBuffer);
740 prop->p_UTCoffset = AMF_DecodeInt16(pBuffer + 8);
742 nSize -= 10;
743 break;
745 case AMF_LONG_STRING:
746 case AMF_XML_DOC:
748 unsigned int nStringSize = AMF_DecodeInt32(pBuffer);
749 if (nSize < (long)nStringSize + 4)
750 return -1;
751 AMF_DecodeLongString(pBuffer, &prop->p_vu.p_aval);
752 nSize -= (4 + nStringSize);
753 if (prop->p_type == AMF_LONG_STRING)
754 prop->p_type = AMF_STRING;
755 break;
757 case AMF_RECORDSET:
759 RTMP_Log(RTMP_LOGERROR, "AMF_RECORDSET reserved!");
760 return -1;
761 break;
763 case AMF_TYPED_OBJECT:
765 RTMP_Log(RTMP_LOGERROR, "AMF_TYPED_OBJECT not supported!");
766 return -1;
767 break;
769 case AMF_AVMPLUS:
771 int nRes = AMF3_Decode(&prop->p_vu.p_object, pBuffer, nSize, TRUE);
772 if (nRes == -1)
773 return -1;
774 nSize -= nRes;
775 prop->p_type = AMF_OBJECT;
776 break;
778 default:
779 RTMP_Log(RTMP_LOGDEBUG, "%s - unknown datatype 0x%02x, @%p", __FUNCTION__,
780 prop->p_type, pBuffer - 1);
781 return -1;
784 return nOriginalSize - nSize;
787 void
788 AMFProp_Dump(AMFObjectProperty *prop)
790 char strRes[256];
791 char str[256];
792 AVal name;
794 if (prop->p_type == AMF_INVALID)
796 RTMP_Log(RTMP_LOGDEBUG, "Property: INVALID");
797 return;
800 if (prop->p_type == AMF_NULL)
802 RTMP_Log(RTMP_LOGDEBUG, "Property: NULL");
803 return;
806 if (prop->p_name.av_len)
808 name = prop->p_name;
810 else
812 name.av_val = "no-name.";
813 name.av_len = sizeof("no-name.") - 1;
815 if (name.av_len > 18)
816 name.av_len = 18;
818 snprintf(strRes, 255, "Name: %18.*s, ", name.av_len, name.av_val);
820 if (prop->p_type == AMF_OBJECT)
822 RTMP_Log(RTMP_LOGDEBUG, "Property: <%sOBJECT>", strRes);
823 AMF_Dump(&prop->p_vu.p_object);
824 return;
826 else if (prop->p_type == AMF_ECMA_ARRAY)
828 RTMP_Log(RTMP_LOGDEBUG, "Property: <%sECMA_ARRAY>", strRes);
829 AMF_Dump(&prop->p_vu.p_object);
830 return;
832 else if (prop->p_type == AMF_STRICT_ARRAY)
834 RTMP_Log(RTMP_LOGDEBUG, "Property: <%sSTRICT_ARRAY>", strRes);
835 AMF_Dump(&prop->p_vu.p_object);
836 return;
839 switch (prop->p_type)
841 case AMF_NUMBER:
842 snprintf(str, 255, "NUMBER:\t%.2f", prop->p_vu.p_number);
843 break;
844 case AMF_BOOLEAN:
845 snprintf(str, 255, "BOOLEAN:\t%s",
846 prop->p_vu.p_number != 0.0 ? "TRUE" : "FALSE");
847 break;
848 case AMF_STRING:
849 snprintf(str, 255, "STRING:\t%.*s", prop->p_vu.p_aval.av_len,
850 prop->p_vu.p_aval.av_val);
851 break;
852 case AMF_DATE:
853 snprintf(str, 255, "DATE:\ttimestamp: %.2f, UTC offset: %d",
854 prop->p_vu.p_number, prop->p_UTCoffset);
855 break;
856 default:
857 snprintf(str, 255, "INVALID TYPE 0x%02x", (unsigned char)prop->p_type);
860 RTMP_Log(RTMP_LOGDEBUG, "Property: <%s%s>", strRes, str);
863 void
864 AMFProp_Reset(AMFObjectProperty *prop)
866 if (prop->p_type == AMF_OBJECT || prop->p_type == AMF_ECMA_ARRAY ||
867 prop->p_type == AMF_STRICT_ARRAY)
868 AMF_Reset(&prop->p_vu.p_object);
869 else
871 prop->p_vu.p_aval.av_len = 0;
872 prop->p_vu.p_aval.av_val = NULL;
874 prop->p_type = AMF_INVALID;
877 /* AMFObject */
879 char *
880 AMF_Encode(AMFObject *obj, char *pBuffer, char *pBufEnd)
882 int i;
884 if (pBuffer+4 >= pBufEnd)
885 return NULL;
887 *pBuffer++ = AMF_OBJECT;
889 for (i = 0; i < obj->o_num; i++)
891 char *res = AMFProp_Encode(&obj->o_props[i], pBuffer, pBufEnd);
892 if (res == NULL)
894 RTMP_Log(RTMP_LOGERROR, "AMF_Encode - failed to encode property in index %d",
896 break;
898 else
900 pBuffer = res;
904 if (pBuffer + 3 >= pBufEnd)
905 return NULL; /* no room for the end marker */
907 pBuffer = AMF_EncodeInt24(pBuffer, pBufEnd, AMF_OBJECT_END);
909 return pBuffer;
912 char *
913 AMF_EncodeEcmaArray(AMFObject *obj, char *pBuffer, char *pBufEnd)
915 int i;
917 if (pBuffer+4 >= pBufEnd)
918 return NULL;
920 *pBuffer++ = AMF_ECMA_ARRAY;
922 pBuffer = AMF_EncodeInt32(pBuffer, pBufEnd, obj->o_num);
924 for (i = 0; i < obj->o_num; i++)
926 char *res = AMFProp_Encode(&obj->o_props[i], pBuffer, pBufEnd);
927 if (res == NULL)
929 RTMP_Log(RTMP_LOGERROR, "AMF_Encode - failed to encode property in index %d",
931 break;
933 else
935 pBuffer = res;
939 if (pBuffer + 3 >= pBufEnd)
940 return NULL; /* no room for the end marker */
942 pBuffer = AMF_EncodeInt24(pBuffer, pBufEnd, AMF_OBJECT_END);
944 return pBuffer;
947 char *
948 AMF_EncodeArray(AMFObject *obj, char *pBuffer, char *pBufEnd)
950 int i;
952 if (pBuffer+4 >= pBufEnd)
953 return NULL;
955 *pBuffer++ = AMF_STRICT_ARRAY;
957 pBuffer = AMF_EncodeInt32(pBuffer, pBufEnd, obj->o_num);
959 for (i = 0; i < obj->o_num; i++)
961 char *res = AMFProp_Encode(&obj->o_props[i], pBuffer, pBufEnd);
962 if (res == NULL)
964 RTMP_Log(RTMP_LOGERROR, "AMF_Encode - failed to encode property in index %d",
966 break;
968 else
970 pBuffer = res;
974 //if (pBuffer + 3 >= pBufEnd)
975 // return NULL; /* no room for the end marker */
977 //pBuffer = AMF_EncodeInt24(pBuffer, pBufEnd, AMF_OBJECT_END);
979 return pBuffer;
983 AMF_DecodeArray(AMFObject *obj, const char *pBuffer, int nSize,
984 int nArrayLen, int bDecodeName)
986 int nOriginalSize = nSize;
987 int bError = FALSE;
989 obj->o_num = 0;
990 obj->o_props = NULL;
991 while (nArrayLen > 0)
993 AMFObjectProperty prop;
994 int nRes;
995 nArrayLen--;
997 nRes = AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName);
998 if (nRes == -1)
999 bError = TRUE;
1000 else
1002 nSize -= nRes;
1003 pBuffer += nRes;
1004 AMF_AddProp(obj, &prop);
1007 if (bError)
1008 return -1;
1010 return nOriginalSize - nSize;
1014 AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData)
1016 int nOriginalSize = nSize;
1017 int32_t ref;
1018 int len;
1020 obj->o_num = 0;
1021 obj->o_props = NULL;
1022 if (bAMFData)
1024 if (*pBuffer != AMF3_OBJECT)
1025 RTMP_Log(RTMP_LOGERROR,
1026 "AMF3 Object encapsulated in AMF stream does not start with AMF3_OBJECT!");
1027 pBuffer++;
1028 nSize--;
1031 ref = 0;
1032 len = AMF3ReadInteger(pBuffer, &ref);
1033 pBuffer += len;
1034 nSize -= len;
1036 if ((ref & 1) == 0)
1037 { /* object reference, 0xxx */
1038 uint32_t objectIndex = (ref >> 1);
1040 RTMP_Log(RTMP_LOGDEBUG, "Object reference, index: %d", objectIndex);
1042 else /* object instance */
1044 int32_t classRef = (ref >> 1);
1046 AMF3ClassDef cd = { {0, 0}
1048 AMFObjectProperty prop;
1050 if ((classRef & 0x1) == 0)
1051 { /* class reference */
1052 uint32_t classIndex = (classRef >> 1);
1053 RTMP_Log(RTMP_LOGDEBUG, "Class reference: %d", classIndex);
1055 else
1057 int32_t classExtRef = (classRef >> 1);
1058 int i, cdnum;
1060 cd.cd_externalizable = (classExtRef & 0x1) == 1;
1061 cd.cd_dynamic = ((classExtRef >> 1) & 0x1) == 1;
1063 cdnum = classExtRef >> 2;
1065 /* class name */
1067 len = AMF3ReadString(pBuffer, &cd.cd_name);
1068 nSize -= len;
1069 pBuffer += len;
1071 /*std::string str = className; */
1073 RTMP_Log(RTMP_LOGDEBUG,
1074 "Class name: %s, externalizable: %d, dynamic: %d, classMembers: %d",
1075 cd.cd_name.av_val, cd.cd_externalizable, cd.cd_dynamic,
1076 cd.cd_num);
1078 for (i = 0; i < cdnum; i++)
1080 AVal memberName;
1081 if (nSize <=0)
1083 invalid:
1084 RTMP_Log(RTMP_LOGDEBUG, "%s, invalid class encoding!",
1085 __FUNCTION__);
1086 return nOriginalSize;
1088 len = AMF3ReadString(pBuffer, &memberName);
1089 RTMP_Log(RTMP_LOGDEBUG, "Member: %s", memberName.av_val);
1090 AMF3CD_AddProp(&cd, &memberName);
1091 nSize -= len;
1092 pBuffer += len;
1096 /* add as referencable object */
1098 if (cd.cd_externalizable)
1100 int nRes;
1101 AVal name = AVC("DEFAULT_ATTRIBUTE");
1103 RTMP_Log(RTMP_LOGDEBUG, "Externalizable, TODO check");
1105 nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, FALSE);
1106 if (nRes == -1)
1107 RTMP_Log(RTMP_LOGDEBUG, "%s, failed to decode AMF3 property!",
1108 __FUNCTION__);
1109 else
1111 nSize -= nRes;
1112 pBuffer += nRes;
1115 AMFProp_SetName(&prop, &name);
1116 AMF_AddProp(obj, &prop);
1118 else
1120 int nRes, i;
1121 for (i = 0; i < cd.cd_num; i++) /* non-dynamic */
1123 if (nSize <=0)
1124 goto invalid;
1125 nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, FALSE);
1126 if (nRes == -1)
1127 RTMP_Log(RTMP_LOGDEBUG, "%s, failed to decode AMF3 property!",
1128 __FUNCTION__);
1130 AMFProp_SetName(&prop, AMF3CD_GetProp(&cd, i));
1131 AMF_AddProp(obj, &prop);
1133 pBuffer += nRes;
1134 nSize -= nRes;
1136 if (cd.cd_dynamic)
1138 int len = 0;
1142 if (nSize <=0)
1143 goto invalid;
1144 nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, TRUE);
1145 AMF_AddProp(obj, &prop);
1147 pBuffer += nRes;
1148 nSize -= nRes;
1150 len = prop.p_name.av_len;
1152 while (len > 0);
1155 RTMP_Log(RTMP_LOGDEBUG, "class object!");
1157 return nOriginalSize - nSize;
1161 AMF_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bDecodeName)
1163 int nOriginalSize = nSize;
1164 int bError = FALSE; /* if there is an error while decoding - try to at least find the end mark AMF_OBJECT_END */
1166 obj->o_num = 0;
1167 obj->o_props = NULL;
1168 while (nSize > 0)
1170 AMFObjectProperty prop;
1171 int nRes;
1173 if (nSize >=3 && AMF_DecodeInt24(pBuffer) == AMF_OBJECT_END)
1175 nSize -= 3;
1176 bError = FALSE;
1177 break;
1180 if (bError)
1182 RTMP_Log(RTMP_LOGERROR,
1183 "DECODING ERROR, IGNORING BYTES UNTIL NEXT KNOWN PATTERN!");
1184 nSize--;
1185 pBuffer++;
1186 continue;
1189 nRes = AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName);
1190 if (nRes == -1)
1191 bError = TRUE;
1192 else
1194 nSize -= nRes;
1195 pBuffer += nRes;
1196 AMF_AddProp(obj, &prop);
1200 if (bError)
1201 return -1;
1203 return nOriginalSize - nSize;
1206 void
1207 AMF_AddProp(AMFObject *obj, const AMFObjectProperty *prop)
1209 if (!(obj->o_num & 0x0f))
1210 obj->o_props =
1211 realloc(obj->o_props, (obj->o_num + 16) * sizeof(AMFObjectProperty));
1212 memcpy(&obj->o_props[obj->o_num++], prop, sizeof(AMFObjectProperty));
1216 AMF_CountProp(AMFObject *obj)
1218 return obj->o_num;
1221 AMFObjectProperty *
1222 AMF_GetProp(AMFObject *obj, const AVal *name, int nIndex)
1224 if (nIndex >= 0)
1226 if (nIndex < obj->o_num)
1227 return &obj->o_props[nIndex];
1229 else
1231 int n;
1232 for (n = 0; n < obj->o_num; n++)
1234 if (AVMATCH(&obj->o_props[n].p_name, name))
1235 return &obj->o_props[n];
1239 return (AMFObjectProperty *)&AMFProp_Invalid;
1242 void
1243 AMF_Dump(AMFObject *obj)
1245 int n;
1246 RTMP_Log(RTMP_LOGDEBUG, "(object begin)");
1247 for (n = 0; n < obj->o_num; n++)
1249 AMFProp_Dump(&obj->o_props[n]);
1251 RTMP_Log(RTMP_LOGDEBUG, "(object end)");
1254 void
1255 AMF_Reset(AMFObject *obj)
1257 int n;
1258 for (n = 0; n < obj->o_num; n++)
1260 AMFProp_Reset(&obj->o_props[n]);
1262 free(obj->o_props);
1263 obj->o_props = NULL;
1264 obj->o_num = 0;
1268 /* AMF3ClassDefinition */
1270 void
1271 AMF3CD_AddProp(AMF3ClassDef *cd, AVal *prop)
1273 if (!(cd->cd_num & 0x0f))
1274 cd->cd_props = realloc(cd->cd_props, (cd->cd_num + 16) * sizeof(AVal));
1275 cd->cd_props[cd->cd_num++] = *prop;
1278 AVal *
1279 AMF3CD_GetProp(AMF3ClassDef *cd, int nIndex)
1281 if (nIndex >= cd->cd_num)
1282 return (AVal *)&AV_empty;
1283 return &cd->cd_props[nIndex];