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
6 *
7 * This file is part of librtmp.
8 *
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.
13 *
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.
18 *
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
24 */
25
26 #include <string.h>
27 #include <assert.h>
28 #include <stdlib.h>
29
30 #include "rtmp_sys.h"
31 #include "amf.h"
32 #include "log.h"
33 #include "bytes.h"
34
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 };
38
39 /* Data is Big-Endian */
40 unsigned short
AMF_DecodeInt16(const char * data)41 AMF_DecodeInt16(const char *data)
42 {
43 unsigned char *c = (unsigned char *) data;
44 unsigned short val;
45 val = (c[0] << 8) | c[1];
46 return val;
47 }
48
49 unsigned int
AMF_DecodeInt24(const char * data)50 AMF_DecodeInt24(const char *data)
51 {
52 unsigned char *c = (unsigned char *) data;
53 unsigned int val;
54 val = (c[0] << 16) | (c[1] << 8) | c[2];
55 return val;
56 }
57
58 unsigned int
AMF_DecodeInt32(const char * data)59 AMF_DecodeInt32(const char *data)
60 {
61 unsigned char *c = (unsigned char *)data;
62 unsigned int val;
63 val = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
64 return val;
65 }
66
67 void
AMF_DecodeString(const char * data,AVal * bv)68 AMF_DecodeString(const char *data, AVal *bv)
69 {
70 bv->av_len = AMF_DecodeInt16(data);
71 bv->av_val = (bv->av_len > 0) ? (char *)data + 2 : NULL;
72 }
73
74 void
AMF_DecodeLongString(const char * data,AVal * bv)75 AMF_DecodeLongString(const char *data, AVal *bv)
76 {
77 bv->av_len = AMF_DecodeInt32(data);
78 bv->av_val = (bv->av_len > 0) ? (char *)data + 4 : NULL;
79 }
80
81 double
AMF_DecodeNumber(const char * data)82 AMF_DecodeNumber(const char *data)
83 {
84 double dVal;
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;
92 co[0] = ci[7];
93 co[1] = ci[6];
94 co[2] = ci[5];
95 co[3] = ci[4];
96 co[4] = ci[3];
97 co[5] = ci[2];
98 co[6] = ci[1];
99 co[7] = ci[0];
100 #endif
101 #else
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;
106 co[0] = ci[3];
107 co[1] = ci[2];
108 co[2] = ci[1];
109 co[3] = ci[0];
110 co[4] = ci[7];
111 co[5] = ci[6];
112 co[6] = ci[5];
113 co[7] = ci[4];
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;
118 co[0] = ci[4];
119 co[1] = ci[5];
120 co[2] = ci[6];
121 co[3] = ci[7];
122 co[4] = ci[0];
123 co[5] = ci[1];
124 co[6] = ci[2];
125 co[7] = ci[3];
126 #endif
127 #endif
128 return dVal;
129 }
130
131 int
AMF_DecodeBoolean(const char * data)132 AMF_DecodeBoolean(const char *data)
133 {
134 return *data != 0;
135 }
136
137 char *
AMF_EncodeInt16(char * output,char * outend,short nVal)138 AMF_EncodeInt16(char *output, char *outend, short nVal)
139 {
140 if (output+2 > outend)
141 return NULL;
142
143 output[1] = nVal & 0xff;
144 output[0] = nVal >> 8;
145 return output+2;
146 }
147
148 char *
AMF_EncodeInt24(char * output,char * outend,int nVal)149 AMF_EncodeInt24(char *output, char *outend, int nVal)
150 {
151 if (output+3 > outend)
152 return NULL;
153
154 output[2] = nVal & 0xff;
155 output[1] = nVal >> 8;
156 output[0] = nVal >> 16;
157 return output+3;
158 }
159
160 char *
AMF_EncodeInt32(char * output,char * outend,int nVal)161 AMF_EncodeInt32(char *output, char *outend, int nVal)
162 {
163 if (output+4 > outend)
164 return NULL;
165
166 output[3] = nVal & 0xff;
167 output[2] = nVal >> 8;
168 output[1] = nVal >> 16;
169 output[0] = nVal >> 24;
170 return output+4;
171 }
172
173 char *
AMF_EncodeString(char * output,char * outend,const AVal * bv)174 AMF_EncodeString(char *output, char *outend, const AVal *bv)
175 {
176 if ((bv->av_len < 65536 && output + 1 + 2 + bv->av_len > outend) ||
177 output + 1 + 4 + bv->av_len > outend)
178 return NULL;
179
180 if (bv->av_len < 65536)
181 {
182 *output++ = AMF_STRING;
183
184 output = AMF_EncodeInt16(output, outend, bv->av_len);
185 }
186 else
187 {
188 *output++ = AMF_LONG_STRING;
189
190 output = AMF_EncodeInt32(output, outend, bv->av_len);
191 }
192 memcpy(output, bv->av_val, bv->av_len);
193 output += bv->av_len;
194
195 return output;
196 }
197
198 char *
AMF_EncodeNumber(char * output,char * outend,double dVal)199 AMF_EncodeNumber(char *output, char *outend, double dVal)
200 {
201 if (output+1+8 > outend)
202 return NULL;
203
204 *output++ = AMF_NUMBER; /* type: Number */
205
206 #if __FLOAT_WORD_ORDER == __BYTE_ORDER
207 #if __BYTE_ORDER == __BIG_ENDIAN
208 memcpy(output, &dVal, 8);
209 #elif __BYTE_ORDER == __LITTLE_ENDIAN
210 {
211 unsigned char *ci, *co;
212 ci = (unsigned char *)&dVal;
213 co = (unsigned char *)output;
214 co[0] = ci[7];
215 co[1] = ci[6];
216 co[2] = ci[5];
217 co[3] = ci[4];
218 co[4] = ci[3];
219 co[5] = ci[2];
220 co[6] = ci[1];
221 co[7] = ci[0];
222 }
223 #endif
224 #else
225 #if __BYTE_ORDER == __LITTLE_ENDIAN /* __FLOAT_WORD_ORER == __BIG_ENDIAN */
226 {
227 unsigned char *ci, *co;
228 ci = (unsigned char *)&dVal;
229 co = (unsigned char *)output;
230 co[0] = ci[3];
231 co[1] = ci[2];
232 co[2] = ci[1];
233 co[3] = ci[0];
234 co[4] = ci[7];
235 co[5] = ci[6];
236 co[6] = ci[5];
237 co[7] = ci[4];
238 }
239 #else /* __BYTE_ORDER == __BIG_ENDIAN && __FLOAT_WORD_ORER == __LITTLE_ENDIAN */
240 {
241 unsigned char *ci, *co;
242 ci = (unsigned char *)&dVal;
243 co = (unsigned char *)output;
244 co[0] = ci[4];
245 co[1] = ci[5];
246 co[2] = ci[6];
247 co[3] = ci[7];
248 co[4] = ci[0];
249 co[5] = ci[1];
250 co[6] = ci[2];
251 co[7] = ci[3];
252 }
253 #endif
254 #endif
255
256 return output+8;
257 }
258
259 char *
AMF_EncodeBoolean(char * output,char * outend,int bVal)260 AMF_EncodeBoolean(char *output, char *outend, int bVal)
261 {
262 if (output+2 > outend)
263 return NULL;
264
265 *output++ = AMF_BOOLEAN;
266
267 *output++ = bVal ? 0x01 : 0x00;
268
269 return output;
270 }
271
272 char *
AMF_EncodeNamedString(char * output,char * outend,const AVal * strName,const AVal * strValue)273 AMF_EncodeNamedString(char *output, char *outend, const AVal *strName, const AVal *strValue)
274 {
275 if (output+2+strName->av_len > outend)
276 return NULL;
277 output = AMF_EncodeInt16(output, outend, strName->av_len);
278
279 memcpy(output, strName->av_val, strName->av_len);
280 output += strName->av_len;
281
282 return AMF_EncodeString(output, outend, strValue);
283 }
284
285 char *
AMF_EncodeNamedNumber(char * output,char * outend,const AVal * strName,double dVal)286 AMF_EncodeNamedNumber(char *output, char *outend, const AVal *strName, double dVal)
287 {
288 if (output+2+strName->av_len > outend)
289 return NULL;
290 output = AMF_EncodeInt16(output, outend, strName->av_len);
291
292 memcpy(output, strName->av_val, strName->av_len);
293 output += strName->av_len;
294
295 return AMF_EncodeNumber(output, outend, dVal);
296 }
297
298 char *
AMF_EncodeNamedBoolean(char * output,char * outend,const AVal * strName,int bVal)299 AMF_EncodeNamedBoolean(char *output, char *outend, const AVal *strName, int bVal)
300 {
301 if (output+2+strName->av_len > outend)
302 return NULL;
303 output = AMF_EncodeInt16(output, outend, strName->av_len);
304
305 memcpy(output, strName->av_val, strName->av_len);
306 output += strName->av_len;
307
308 return AMF_EncodeBoolean(output, outend, bVal);
309 }
310
311 void
AMFProp_GetName(AMFObjectProperty * prop,AVal * name)312 AMFProp_GetName(AMFObjectProperty *prop, AVal *name)
313 {
314 *name = prop->p_name;
315 }
316
317 void
AMFProp_SetName(AMFObjectProperty * prop,AVal * name)318 AMFProp_SetName(AMFObjectProperty *prop, AVal *name)
319 {
320 prop->p_name = *name;
321 }
322
323 AMFDataType
AMFProp_GetType(AMFObjectProperty * prop)324 AMFProp_GetType(AMFObjectProperty *prop)
325 {
326 return prop->p_type;
327 }
328
329 double
AMFProp_GetNumber(AMFObjectProperty * prop)330 AMFProp_GetNumber(AMFObjectProperty *prop)
331 {
332 return prop->p_vu.p_number;
333 }
334
335 int
AMFProp_GetBoolean(AMFObjectProperty * prop)336 AMFProp_GetBoolean(AMFObjectProperty *prop)
337 {
338 return prop->p_vu.p_number != 0;
339 }
340
341 void
AMFProp_GetString(AMFObjectProperty * prop,AVal * str)342 AMFProp_GetString(AMFObjectProperty *prop, AVal *str)
343 {
344 if (prop->p_type == AMF_STRING)
345 *str = prop->p_vu.p_aval;
346 else
347 *str = AV_empty;
348 }
349
350 void
AMFProp_GetObject(AMFObjectProperty * prop,AMFObject * obj)351 AMFProp_GetObject(AMFObjectProperty *prop, AMFObject *obj)
352 {
353 if (prop->p_type == AMF_OBJECT)
354 *obj = prop->p_vu.p_object;
355 else
356 *obj = AMFObj_Invalid;
357 }
358
359 int
AMFProp_IsValid(AMFObjectProperty * prop)360 AMFProp_IsValid(AMFObjectProperty *prop)
361 {
362 return prop->p_type != AMF_INVALID;
363 }
364
365 char *
AMFProp_Encode(AMFObjectProperty * prop,char * pBuffer,char * pBufEnd)366 AMFProp_Encode(AMFObjectProperty *prop, char *pBuffer, char *pBufEnd)
367 {
368 if (prop->p_type == AMF_INVALID)
369 return NULL;
370
371 if (prop->p_type != AMF_NULL && pBuffer + prop->p_name.av_len + 2 + 1 >= pBufEnd)
372 return NULL;
373
374 if (prop->p_type != AMF_NULL && prop->p_name.av_len)
375 {
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;
380 }
381
382 switch (prop->p_type)
383 {
384 case AMF_NUMBER:
385 pBuffer = AMF_EncodeNumber(pBuffer, pBufEnd, prop->p_vu.p_number);
386 break;
387
388 case AMF_BOOLEAN:
389 pBuffer = AMF_EncodeBoolean(pBuffer, pBufEnd, prop->p_vu.p_number != 0);
390 break;
391
392 case AMF_STRING:
393 pBuffer = AMF_EncodeString(pBuffer, pBufEnd, &prop->p_vu.p_aval);
394 break;
395
396 case AMF_NULL:
397 if (pBuffer+1 >= pBufEnd)
398 return NULL;
399 *pBuffer++ = AMF_NULL;
400 break;
401
402 case AMF_OBJECT:
403 pBuffer = AMF_Encode(&prop->p_vu.p_object, pBuffer, pBufEnd);
404 break;
405
406 case AMF_ECMA_ARRAY:
407 pBuffer = AMF_EncodeEcmaArray(&prop->p_vu.p_object, pBuffer, pBufEnd);
408 break;
409
410 case AMF_STRICT_ARRAY:
411 pBuffer = AMF_EncodeArray(&prop->p_vu.p_object, pBuffer, pBufEnd);
412 break;
413
414 default:
415 RTMP_Log(RTMP_LOGERROR, "%s, invalid type. %d", __FUNCTION__, prop->p_type);
416 pBuffer = NULL;
417 };
418
419 return pBuffer;
420 }
421
422 #define AMF3_INTEGER_MAX 268435455
423 #define AMF3_INTEGER_MIN -268435456
424
425 int
AMF3ReadInteger(const char * data,int32_t * valp)426 AMF3ReadInteger(const char *data, int32_t *valp)
427 {
428 int i = 0;
429 int32_t val = 0;
430
431 while (i <= 2)
432 { /* handle first 3 bytes */
433 if (data[i] & 0x80)
434 { /* byte used */
435 val <<= 7; /* shift up */
436 val |= (data[i] & 0x7f); /* add bits */
437 i++;
438 }
439 else
440 {
441 break;
442 }
443 }
444
445 if (i > 2)
446 { /* use 4th byte, all 8bits */
447 val <<= 8;
448 val |= data[3];
449
450 /* range check */
451 if (val > AMF3_INTEGER_MAX)
452 val -= (1 << 29);
453 }
454 else
455 { /* use 7bits of last unparsed byte (0xxxxxxx) */
456 val <<= 7;
457 val |= data[i];
458 }
459
460 *valp = val;
461
462 return i > 2 ? 4 : i + 1;
463 }
464
465 int
AMF3ReadString(const char * data,AVal * str)466 AMF3ReadString(const char *data, AVal *str)
467 {
468 int32_t ref = 0;
469 int len;
470 assert(str != 0);
471
472 len = AMF3ReadInteger(data, &ref);
473 data += len;
474
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);
481 str->av_val = NULL;
482 str->av_len = 0;
483 return len;
484 }
485 else
486 {
487 uint32_t nSize = (ref >> 1);
488
489 str->av_val = (char *)data;
490 str->av_len = nSize;
491
492 return len + nSize;
493 }
494 return len;
495 }
496
497 int
AMF3Prop_Decode(AMFObjectProperty * prop,const char * pBuffer,int nSize,int bDecodeName)498 AMF3Prop_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize,
499 int bDecodeName)
500 {
501 int nOriginalSize = nSize;
502 AMF3DataType type;
503
504 prop->p_name.av_len = 0;
505 prop->p_name.av_val = NULL;
506
507 if (nSize == 0 || !pBuffer)
508 {
509 RTMP_Log(RTMP_LOGDEBUG, "empty buffer/no buffer pointer!");
510 return -1;
511 }
512
513 /* decode name */
514 if (bDecodeName)
515 {
516 AVal name;
517 int nRes = AMF3ReadString(pBuffer, &name);
518
519 if (name.av_len <= 0)
520 return nRes;
521
522 nSize -= nRes;
523 if (nSize <= 0)
524 return -1;
525 prop->p_name = name;
526 pBuffer += nRes;
527 }
528
529 /* decode */
530 type = *pBuffer++;
531 nSize--;
532
533 switch (type)
534 {
535 case AMF3_UNDEFINED:
536 case AMF3_NULL:
537 prop->p_type = AMF_NULL;
538 break;
539 case AMF3_FALSE:
540 prop->p_type = AMF_BOOLEAN;
541 prop->p_vu.p_number = 0.0;
542 break;
543 case AMF3_TRUE:
544 prop->p_type = AMF_BOOLEAN;
545 prop->p_vu.p_number = 1.0;
546 break;
547 case AMF3_INTEGER:
548 {
549 int32_t res = 0;
550 int len = AMF3ReadInteger(pBuffer, &res);
551 prop->p_vu.p_number = (double)res;
552 prop->p_type = AMF_NUMBER;
553 nSize -= len;
554 break;
555 }
556 case AMF3_DOUBLE:
557 if (nSize < 8)
558 return -1;
559 prop->p_vu.p_number = AMF_DecodeNumber(pBuffer);
560 prop->p_type = AMF_NUMBER;
561 nSize -= 8;
562 break;
563 case AMF3_STRING:
564 case AMF3_XML_DOC:
565 case AMF3_XML:
566 {
567 int len = AMF3ReadString(pBuffer, &prop->p_vu.p_aval);
568 prop->p_type = AMF_STRING;
569 nSize -= len;
570 break;
571 }
572 case AMF3_DATE:
573 {
574 int32_t res = 0;
575 int len = AMF3ReadInteger(pBuffer, &res);
576
577 nSize -= len;
578 pBuffer += len;
579
580 if ((res & 0x1) == 0)
581 { /* reference */
582 uint32_t nIndex = (res >> 1);
583 RTMP_Log(RTMP_LOGDEBUG, "AMF3_DATE reference: %d, not supported!", nIndex);
584 }
585 else
586 {
587 if (nSize < 8)
588 return -1;
589
590 prop->p_vu.p_number = AMF_DecodeNumber(pBuffer);
591 nSize -= 8;
592 prop->p_type = AMF_NUMBER;
593 }
594 break;
595 }
596 case AMF3_OBJECT:
597 {
598 int nRes = AMF3_Decode(&prop->p_vu.p_object, pBuffer, nSize, TRUE);
599 if (nRes == -1)
600 return -1;
601 nSize -= nRes;
602 prop->p_type = AMF_OBJECT;
603 break;
604 }
605 case AMF3_ARRAY:
606 case AMF3_BYTE_ARRAY:
607 default:
608 RTMP_Log(RTMP_LOGDEBUG, "%s - AMF3 unknown/unsupported datatype 0x%02x, @%p",
609 __FUNCTION__, (unsigned char)(*pBuffer), pBuffer);
610 return -1;
611 }
612 if (nSize < 0)
613 return -1;
614
615 return nOriginalSize - nSize;
616 }
617
618 int
AMFProp_Decode(AMFObjectProperty * prop,const char * pBuffer,int nSize,int bDecodeName)619 AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize,
620 int bDecodeName)
621 {
622 int nOriginalSize = nSize;
623 int nRes;
624
625 prop->p_name.av_len = 0;
626 prop->p_name.av_val = NULL;
627
628 if (nSize == 0 || !pBuffer)
629 {
630 RTMP_Log(RTMP_LOGDEBUG, "%s: Empty buffer/no buffer pointer!", __FUNCTION__);
631 return -1;
632 }
633
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!",
638 __FUNCTION__);
639 return -1;
640 }
641
642 if (bDecodeName)
643 {
644 unsigned short nNameSize = AMF_DecodeInt16(pBuffer);
645 if (nNameSize > nSize - 2)
646 {
647 RTMP_Log(RTMP_LOGDEBUG,
648 "%s: Name size out of range: namesize (%d) > len (%d) - 2",
649 __FUNCTION__, nNameSize, nSize);
650 return -1;
651 }
652
653 AMF_DecodeString(pBuffer, &prop->p_name);
654 nSize -= 2 + nNameSize;
655 pBuffer += 2 + nNameSize;
656 }
657
658 if (nSize == 0)
659 {
660 return -1;
661 }
662
663 nSize--;
664
665 prop->p_type = *pBuffer++;
666 switch (prop->p_type)
667 {
668 case AMF_NUMBER:
669 if (nSize < 8)
670 return -1;
671 prop->p_vu.p_number = AMF_DecodeNumber(pBuffer);
672 nSize -= 8;
673 break;
674 case AMF_BOOLEAN:
675 if (nSize < 1)
676 return -1;
677 prop->p_vu.p_number = (double)AMF_DecodeBoolean(pBuffer);
678 nSize--;
679 break;
680 case AMF_STRING:
681 {
682 unsigned short nStringSize = AMF_DecodeInt16(pBuffer);
683
684 if (nSize < (long)nStringSize + 2)
685 return -1;
686 AMF_DecodeString(pBuffer, &prop->p_vu.p_aval);
687 nSize -= (2 + nStringSize);
688 break;
689 }
690 case AMF_OBJECT:
691 {
692 int nRes = AMF_Decode(&prop->p_vu.p_object, pBuffer, nSize, TRUE);
693 if (nRes == -1)
694 return -1;
695 nSize -= nRes;
696 break;
697 }
698 case AMF_MOVIECLIP:
699 {
700 RTMP_Log(RTMP_LOGERROR, "AMF_MOVIECLIP reserved!");
701 return -1;
702 break;
703 }
704 case AMF_NULL:
705 case AMF_UNDEFINED:
706 case AMF_UNSUPPORTED:
707 prop->p_type = AMF_NULL;
708 break;
709 case AMF_REFERENCE:
710 {
711 RTMP_Log(RTMP_LOGERROR, "AMF_REFERENCE not supported!");
712 return -1;
713 break;
714 }
715 case AMF_ECMA_ARRAY:
716 {
717 nSize -= 4;
718
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);
721 if (nRes == -1)
722 return -1;
723 nSize -= nRes;
724 break;
725 }
726 case AMF_OBJECT_END:
727 {
728 return -1;
729 break;
730 }
731 case AMF_STRICT_ARRAY:
732 {
733 unsigned int nArrayLen = AMF_DecodeInt32(pBuffer);
734 nSize -= 4;
735
736 nRes = AMF_DecodeArray(&prop->p_vu.p_object, pBuffer + 4, nSize,
737 nArrayLen, FALSE);
738 if (nRes == -1)
739 return -1;
740 nSize -= nRes;
741 break;
742 }
743 case AMF_DATE:
744 {
745 RTMP_Log(RTMP_LOGDEBUG, "AMF_DATE");
746
747 if (nSize < 10)
748 return -1;
749
750 prop->p_vu.p_number = AMF_DecodeNumber(pBuffer);
751 prop->p_UTCoffset = AMF_DecodeInt16(pBuffer + 8);
752
753 nSize -= 10;
754 break;
755 }
756 case AMF_LONG_STRING:
757 case AMF_XML_DOC:
758 {
759 unsigned int nStringSize = AMF_DecodeInt32(pBuffer);
760 if (nSize < (long)nStringSize + 4)
761 return -1;
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;
766 break;
767 }
768 case AMF_RECORDSET:
769 {
770 RTMP_Log(RTMP_LOGERROR, "AMF_RECORDSET reserved!");
771 return -1;
772 break;
773 }
774 case AMF_TYPED_OBJECT:
775 {
776 RTMP_Log(RTMP_LOGERROR, "AMF_TYPED_OBJECT not supported!");
777 return -1;
778 break;
779 }
780 case AMF_AVMPLUS:
781 {
782 int nRes = AMF3_Decode(&prop->p_vu.p_object, pBuffer, nSize, TRUE);
783 if (nRes == -1)
784 return -1;
785 nSize -= nRes;
786 prop->p_type = AMF_OBJECT;
787 break;
788 }
789 default:
790 RTMP_Log(RTMP_LOGDEBUG, "%s - unknown datatype 0x%02x, @%p", __FUNCTION__,
791 prop->p_type, pBuffer - 1);
792 return -1;
793 }
794
795 return nOriginalSize - nSize;
796 }
797
798 void
AMFProp_Dump(AMFObjectProperty * prop)799 AMFProp_Dump(AMFObjectProperty *prop)
800 {
801 char strRes[256];
802 char str[256];
803 AVal name;
804
805 if (prop->p_type == AMF_INVALID)
806 {
807 RTMP_Log(RTMP_LOGDEBUG, "Property: INVALID");
808 return;
809 }
810
811 if (prop->p_type == AMF_NULL)
812 {
813 RTMP_Log(RTMP_LOGDEBUG, "Property: NULL");
814 return;
815 }
816
817 if (prop->p_name.av_len)
818 {
819 name = prop->p_name;
820 }
821 else
822 {
823 name.av_val = "no-name.";
824 name.av_len = sizeof("no-name.") - 1;
825 }
826 if (name.av_len > 18)
827 name.av_len = 18;
828
829 snprintf(strRes, 255, "Name: %18.*s, ", name.av_len, name.av_val);
830
831 if (prop->p_type == AMF_OBJECT)
832 {
833 RTMP_Log(RTMP_LOGDEBUG, "Property: <%sOBJECT>", strRes);
834 AMF_Dump(&prop->p_vu.p_object);
835 return;
836 }
837 else if (prop->p_type == AMF_ECMA_ARRAY)
838 {
839 RTMP_Log(RTMP_LOGDEBUG, "Property: <%sECMA_ARRAY>", strRes);
840 AMF_Dump(&prop->p_vu.p_object);
841 return;
842 }
843 else if (prop->p_type == AMF_STRICT_ARRAY)
844 {
845 RTMP_Log(RTMP_LOGDEBUG, "Property: <%sSTRICT_ARRAY>", strRes);
846 AMF_Dump(&prop->p_vu.p_object);
847 return;
848 }
849
850 switch (prop->p_type)
851 {
852 case AMF_NUMBER:
853 snprintf(str, 255, "NUMBER:\t%.2f", prop->p_vu.p_number);
854 break;
855 case AMF_BOOLEAN:
856 snprintf(str, 255, "BOOLEAN:\t%s",
857 prop->p_vu.p_number != 0.0 ? "TRUE" : "FALSE");
858 break;
859 case AMF_STRING:
860 snprintf(str, 255, "STRING:\t%.*s", prop->p_vu.p_aval.av_len,
861 prop->p_vu.p_aval.av_val);
862 break;
863 case AMF_DATE:
864 snprintf(str, 255, "DATE:\ttimestamp: %.2f, UTC offset: %d",
865 prop->p_vu.p_number, prop->p_UTCoffset);
866 break;
867 default:
868 snprintf(str, 255, "INVALID TYPE 0x%02x", (unsigned char)prop->p_type);
869 }
870
871 RTMP_Log(RTMP_LOGDEBUG, "Property: <%s%s>", strRes, str);
872 }
873
874 void
AMFProp_Reset(AMFObjectProperty * prop)875 AMFProp_Reset(AMFObjectProperty *prop)
876 {
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);
880 else
881 {
882 prop->p_vu.p_aval.av_len = 0;
883 prop->p_vu.p_aval.av_val = NULL;
884 }
885 prop->p_type = AMF_INVALID;
886 }
887
888 /* AMFObject */
889
890 char *
AMF_Encode(AMFObject * obj,char * pBuffer,char * pBufEnd)891 AMF_Encode(AMFObject *obj, char *pBuffer, char *pBufEnd)
892 {
893 int i;
894
895 if (pBuffer+4 >= pBufEnd)
896 return NULL;
897
898 *pBuffer++ = AMF_OBJECT;
899
900 for (i = 0; i < obj->o_num; i++)
901 {
902 char *res = AMFProp_Encode(&obj->o_props[i], pBuffer, pBufEnd);
903 if (res == NULL)
904 {
905 RTMP_Log(RTMP_LOGERROR, "AMF_Encode - failed to encode property in index %d",
906 i);
907 break;
908 }
909 else
910 {
911 pBuffer = res;
912 }
913 }
914
915 if (pBuffer + 3 >= pBufEnd)
916 return NULL; /* no room for the end marker */
917
918 pBuffer = AMF_EncodeInt24(pBuffer, pBufEnd, AMF_OBJECT_END);
919
920 return pBuffer;
921 }
922
923 char *
AMF_EncodeEcmaArray(AMFObject * obj,char * pBuffer,char * pBufEnd)924 AMF_EncodeEcmaArray(AMFObject *obj, char *pBuffer, char *pBufEnd)
925 {
926 int i;
927
928 if (pBuffer+4 >= pBufEnd)
929 return NULL;
930
931 *pBuffer++ = AMF_ECMA_ARRAY;
932
933 pBuffer = AMF_EncodeInt32(pBuffer, pBufEnd, obj->o_num);
934
935 for (i = 0; i < obj->o_num; i++)
936 {
937 char *res = AMFProp_Encode(&obj->o_props[i], pBuffer, pBufEnd);
938 if (res == NULL)
939 {
940 RTMP_Log(RTMP_LOGERROR, "AMF_Encode - failed to encode property in index %d",
941 i);
942 break;
943 }
944 else
945 {
946 pBuffer = res;
947 }
948 }
949
950 if (pBuffer + 3 >= pBufEnd)
951 return NULL; /* no room for the end marker */
952
953 pBuffer = AMF_EncodeInt24(pBuffer, pBufEnd, AMF_OBJECT_END);
954
955 return pBuffer;
956 }
957
958 char *
AMF_EncodeArray(AMFObject * obj,char * pBuffer,char * pBufEnd)959 AMF_EncodeArray(AMFObject *obj, char *pBuffer, char *pBufEnd)
960 {
961 int i;
962
963 if (pBuffer+4 >= pBufEnd)
964 return NULL;
965
966 *pBuffer++ = AMF_STRICT_ARRAY;
967
968 pBuffer = AMF_EncodeInt32(pBuffer, pBufEnd, obj->o_num);
969
970 for (i = 0; i < obj->o_num; i++)
971 {
972 char *res = AMFProp_Encode(&obj->o_props[i], pBuffer, pBufEnd);
973 if (res == NULL)
974 {
975 RTMP_Log(RTMP_LOGERROR, "AMF_Encode - failed to encode property in index %d",
976 i);
977 break;
978 }
979 else
980 {
981 pBuffer = res;
982 }
983 }
984
985 //if (pBuffer + 3 >= pBufEnd)
986 // return NULL; /* no room for the end marker */
987
988 //pBuffer = AMF_EncodeInt24(pBuffer, pBufEnd, AMF_OBJECT_END);
989
990 return pBuffer;
991 }
992
993 int
AMF_DecodeArray(AMFObject * obj,const char * pBuffer,int nSize,int nArrayLen,int bDecodeName)994 AMF_DecodeArray(AMFObject *obj, const char *pBuffer, int nSize,
995 int nArrayLen, int bDecodeName)
996 {
997 int nOriginalSize = nSize;
998 int bError = FALSE;
999
1000 obj->o_num = 0;
1001 obj->o_props = NULL;
1002 while (nArrayLen > 0)
1003 {
1004 AMFObjectProperty prop;
1005 int nRes;
1006 nArrayLen--;
1007
1008 if (nSize <= 0)
1009 {
1010 bError = TRUE;
1011 break;
1012 }
1013 nRes = AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName);
1014 if (nRes == -1)
1015 {
1016 bError = TRUE;
1017 break;
1018 }
1019 else
1020 {
1021 nSize -= nRes;
1022 pBuffer += nRes;
1023 AMF_AddProp(obj, &prop);
1024 }
1025 }
1026 if (bError)
1027 return -1;
1028
1029 return nOriginalSize - nSize;
1030 }
1031
1032 int
AMF3_Decode(AMFObject * obj,const char * pBuffer,int nSize,int bAMFData)1033 AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData)
1034 {
1035 int nOriginalSize = nSize;
1036 int32_t ref;
1037 int len;
1038
1039 obj->o_num = 0;
1040 obj->o_props = NULL;
1041 if (bAMFData)
1042 {
1043 if (*pBuffer != AMF3_OBJECT)
1044 RTMP_Log(RTMP_LOGERROR,
1045 "AMF3 Object encapsulated in AMF stream does not start with AMF3_OBJECT!");
1046 pBuffer++;
1047 nSize--;
1048 }
1049
1050 ref = 0;
1051 len = AMF3ReadInteger(pBuffer, &ref);
1052 pBuffer += len;
1053 nSize -= len;
1054
1055 if ((ref & 1) == 0)
1056 { /* object reference, 0xxx */
1057 uint32_t objectIndex = (ref >> 1);
1058
1059 RTMP_Log(RTMP_LOGDEBUG, "Object reference, index: %d", objectIndex);
1060 }
1061 else /* object instance */
1062 {
1063 int32_t classRef = (ref >> 1);
1064
1065 AMF3ClassDef cd = { {0, 0}
1066 };
1067 AMFObjectProperty prop;
1068
1069 if ((classRef & 0x1) == 0)
1070 { /* class reference */
1071 uint32_t classIndex = (classRef >> 1);
1072 RTMP_Log(RTMP_LOGDEBUG, "Class reference: %d", classIndex);
1073 }
1074 else
1075 {
1076 int32_t classExtRef = (classRef >> 1);
1077 int i, cdnum;
1078
1079 cd.cd_externalizable = (classExtRef & 0x1) == 1;
1080 cd.cd_dynamic = ((classExtRef >> 1) & 0x1) == 1;
1081
1082 cdnum = classExtRef >> 2;
1083
1084 /* class name */
1085
1086 len = AMF3ReadString(pBuffer, &cd.cd_name);
1087 nSize -= len;
1088 pBuffer += len;
1089
1090 /*std::string str = className; */
1091
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,
1095 cd.cd_num);
1096
1097 for (i = 0; i < cdnum; i++)
1098 {
1099 AVal memberName;
1100 if (nSize <=0)
1101 {
1102 invalid:
1103 RTMP_Log(RTMP_LOGDEBUG, "%s, invalid class encoding!",
1104 __FUNCTION__);
1105 return nOriginalSize;
1106 }
1107 len = AMF3ReadString(pBuffer, &memberName);
1108 RTMP_Log(RTMP_LOGDEBUG, "Member: %s", memberName.av_val);
1109 AMF3CD_AddProp(&cd, &memberName);
1110 nSize -= len;
1111 pBuffer += len;
1112 }
1113 }
1114
1115 /* add as referencable object */
1116
1117 if (cd.cd_externalizable)
1118 {
1119 int nRes;
1120 AVal name = AVC("DEFAULT_ATTRIBUTE");
1121
1122 RTMP_Log(RTMP_LOGDEBUG, "Externalizable, TODO check");
1123
1124 nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, FALSE);
1125 if (nRes == -1)
1126 RTMP_Log(RTMP_LOGDEBUG, "%s, failed to decode AMF3 property!",
1127 __FUNCTION__);
1128 else
1129 {
1130 nSize -= nRes;
1131 pBuffer += nRes;
1132 }
1133
1134 AMFProp_SetName(&prop, &name);
1135 AMF_AddProp(obj, &prop);
1136 }
1137 else
1138 {
1139 int nRes, i;
1140 for (i = 0; i < cd.cd_num; i++) /* non-dynamic */
1141 {
1142 if (nSize <=0)
1143 goto invalid;
1144 nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, FALSE);
1145 if (nRes == -1)
1146 RTMP_Log(RTMP_LOGDEBUG, "%s, failed to decode AMF3 property!",
1147 __FUNCTION__);
1148
1149 AMFProp_SetName(&prop, AMF3CD_GetProp(&cd, i));
1150 AMF_AddProp(obj, &prop);
1151
1152 pBuffer += nRes;
1153 nSize -= nRes;
1154 }
1155 if (cd.cd_dynamic)
1156 {
1157 int len = 0;
1158
1159 do
1160 {
1161 if (nSize <=0)
1162 goto invalid;
1163 nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, TRUE);
1164 AMF_AddProp(obj, &prop);
1165
1166 pBuffer += nRes;
1167 nSize -= nRes;
1168
1169 len = prop.p_name.av_len;
1170 }
1171 while (len > 0);
1172 }
1173 }
1174 RTMP_Log(RTMP_LOGDEBUG, "class object!");
1175 }
1176 return nOriginalSize - nSize;
1177 }
1178
1179 int
AMF_Decode(AMFObject * obj,const char * pBuffer,int nSize,int bDecodeName)1180 AMF_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bDecodeName)
1181 {
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 */
1184
1185 obj->o_num = 0;
1186 obj->o_props = NULL;
1187 while (nSize > 0)
1188 {
1189 AMFObjectProperty prop;
1190 int nRes;
1191
1192 if (nSize >=3 && AMF_DecodeInt24(pBuffer) == AMF_OBJECT_END)
1193 {
1194 nSize -= 3;
1195 bError = FALSE;
1196 break;
1197 }
1198
1199 if (bError)
1200 {
1201 RTMP_Log(RTMP_LOGERROR,
1202 "DECODING ERROR, IGNORING BYTES UNTIL NEXT KNOWN PATTERN!");
1203 nSize--;
1204 pBuffer++;
1205 continue;
1206 }
1207
1208 nRes = AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName);
1209 if (nRes == -1)
1210 {
1211 bError = TRUE;
1212 break;
1213 }
1214 else
1215 {
1216 nSize -= nRes;
1217 if (nSize < 0)
1218 {
1219 bError = TRUE;
1220 break;
1221 }
1222 pBuffer += nRes;
1223 AMF_AddProp(obj, &prop);
1224 }
1225 }
1226
1227 if (bError)
1228 return -1;
1229
1230 return nOriginalSize - nSize;
1231 }
1232
1233 void
AMF_AddProp(AMFObject * obj,const AMFObjectProperty * prop)1234 AMF_AddProp(AMFObject *obj, const AMFObjectProperty *prop)
1235 {
1236 if (!(obj->o_num & 0x0f))
1237 obj->o_props =
1238 realloc(obj->o_props, (obj->o_num + 16) * sizeof(AMFObjectProperty));
1239 memcpy(&obj->o_props[obj->o_num++], prop, sizeof(AMFObjectProperty));
1240 }
1241
1242 int
AMF_CountProp(AMFObject * obj)1243 AMF_CountProp(AMFObject *obj)
1244 {
1245 return obj->o_num;
1246 }
1247
1248 AMFObjectProperty *
AMF_GetProp(AMFObject * obj,const AVal * name,int nIndex)1249 AMF_GetProp(AMFObject *obj, const AVal *name, int nIndex)
1250 {
1251 if (nIndex >= 0)
1252 {
1253 if (nIndex < obj->o_num)
1254 return &obj->o_props[nIndex];
1255 }
1256 else
1257 {
1258 int n;
1259 for (n = 0; n < obj->o_num; n++)
1260 {
1261 if (AVMATCH(&obj->o_props[n].p_name, name))
1262 return &obj->o_props[n];
1263 }
1264 }
1265
1266 return (AMFObjectProperty *)&AMFProp_Invalid;
1267 }
1268
1269 void
AMF_Dump(AMFObject * obj)1270 AMF_Dump(AMFObject *obj)
1271 {
1272 int n;
1273 RTMP_Log(RTMP_LOGDEBUG, "(object begin)");
1274 for (n = 0; n < obj->o_num; n++)
1275 {
1276 AMFProp_Dump(&obj->o_props[n]);
1277 }
1278 RTMP_Log(RTMP_LOGDEBUG, "(object end)");
1279 }
1280
1281 void
AMF_Reset(AMFObject * obj)1282 AMF_Reset(AMFObject *obj)
1283 {
1284 int n;
1285 for (n = 0; n < obj->o_num; n++)
1286 {
1287 AMFProp_Reset(&obj->o_props[n]);
1288 }
1289 free(obj->o_props);
1290 obj->o_props = NULL;
1291 obj->o_num = 0;
1292 }
1293
1294
1295 /* AMF3ClassDefinition */
1296
1297 void
AMF3CD_AddProp(AMF3ClassDef * cd,AVal * prop)1298 AMF3CD_AddProp(AMF3ClassDef *cd, AVal *prop)
1299 {
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;
1303 }
1304
1305 AVal *
AMF3CD_GetProp(AMF3ClassDef * cd,int nIndex)1306 AMF3CD_GetProp(AMF3ClassDef *cd, int nIndex)
1307 {
1308 if (nIndex >= cd->cd_num)
1309 return (AVal *)&AV_empty;
1310 return &cd->cd_props[nIndex];
1311 }
1312