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