69c3768037cefe89af2ad8e0135deaf9399dd0de
[platform/upstream/gstreamer.git] / gst / rtmp2 / rtmp / amf.c
1 /* GStreamer RTMP Library
2  * Copyright (C) 2014 David Schleef <ds@schleef.org>
3  * Copyright (C) 2017 Make.TV, Inc. <info@make.tv>
4  *   Contact: Jan Alexander Steffens (heftig) <jsteffens@make.tv>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "amf.h"
27 #include "rtmputils.h"
28 #include <string.h>
29 #include <gst/gst.h>
30
31 #define MAX_RECURSION_DEPTH 16
32
33 GST_DEBUG_CATEGORY_STATIC (gst_rtmp_amf_debug_category);
34 #define GST_CAT_DEFAULT gst_rtmp_amf_debug_category
35
36 static GBytes *empty_bytes;
37
38 static void
39 init_static (void)
40 {
41   static volatile gsize done = 0;
42   if (g_once_init_enter (&done)) {
43     empty_bytes = g_bytes_new_static ("", 0);
44     GST_DEBUG_CATEGORY_INIT (gst_rtmp_amf_debug_category, "rtmpamf", 0,
45         "debug category for the amf parser");
46     g_once_init_leave (&done, 1);
47   }
48 }
49
50 const gchar *
51 gst_amf_type_get_nick (GstAmfType type)
52 {
53   switch (type) {
54     case GST_AMF_TYPE_INVALID:
55       return "invalid";
56     case GST_AMF_TYPE_NUMBER:
57       return "number";
58     case GST_AMF_TYPE_BOOLEAN:
59       return "boolean";
60     case GST_AMF_TYPE_STRING:
61       return "string";
62     case GST_AMF_TYPE_OBJECT:
63       return "object";
64     case GST_AMF_TYPE_MOVIECLIP:
65       return "movieclip";
66     case GST_AMF_TYPE_NULL:
67       return "null";
68     case GST_AMF_TYPE_UNDEFINED:
69       return "undefined";
70     case GST_AMF_TYPE_REFERENCE:
71       return "reference";
72     case GST_AMF_TYPE_ECMA_ARRAY:
73       return "ecma-array";
74     case GST_AMF_TYPE_OBJECT_END:
75       return "object-end";
76     case GST_AMF_TYPE_STRICT_ARRAY:
77       return "strict-array";
78     case GST_AMF_TYPE_DATE:
79       return "date";
80     case GST_AMF_TYPE_LONG_STRING:
81       return "long-string";
82     case GST_AMF_TYPE_UNSUPPORTED:
83       return "unsupported";
84     case GST_AMF_TYPE_RECORDSET:
85       return "recordset";
86     case GST_AMF_TYPE_XML_DOCUMENT:
87       return "xml-document";
88     case GST_AMF_TYPE_TYPED_OBJECT:
89       return "typed-object";
90     case GST_AMF_TYPE_AVMPLUS_OBJECT:
91       return "avmplus-object";
92     default:
93       return "unknown";
94   }
95 }
96
97 typedef struct
98 {
99   gchar *name;
100   GstAmfNode *value;
101 } AmfObjectField;
102
103 static void
104 amf_object_field_clear (gpointer ptr)
105 {
106   AmfObjectField *field = ptr;
107   g_clear_pointer (&field->name, g_free);
108   g_clear_pointer (&field->value, gst_amf_node_free);
109 }
110
111 struct _GstAmfNode
112 {
113   GstAmfType type;
114   union
115   {
116     gint v_int;
117     gdouble v_double;
118     GBytes *v_bytes;
119     GArray *v_fields;
120     GPtrArray *v_elements;
121   } value;
122 };
123
124 static inline const AmfObjectField *
125 get_field (const GstAmfNode * node, guint index)
126 {
127   return &g_array_index (node->value.v_fields, const AmfObjectField, index);
128 }
129
130 static inline void
131 append_field (GstAmfNode * node, gchar * name, GstAmfNode * value)
132 {
133   AmfObjectField field = {
134     .name = name,
135     .value = value,
136   };
137   g_array_append_val (node->value.v_fields, field);
138 }
139
140 static inline const GstAmfNode *
141 get_element (const GstAmfNode * node, guint index)
142 {
143   return g_ptr_array_index (node->value.v_elements, index);
144 }
145
146 static inline void
147 append_element (GstAmfNode * node, GstAmfNode * value)
148 {
149   g_ptr_array_add (node->value.v_elements, value);
150 }
151
152 static GstAmfNode *
153 node_new (GstAmfType type)
154 {
155   GstAmfNode *node;
156
157   init_static ();
158
159   node = g_slice_alloc0 (sizeof *node);
160   node->type = type;
161
162   switch (type) {
163     case GST_AMF_TYPE_STRING:
164     case GST_AMF_TYPE_LONG_STRING:
165       node->value.v_bytes = g_bytes_ref (empty_bytes);
166       break;
167
168     case GST_AMF_TYPE_OBJECT:
169     case GST_AMF_TYPE_ECMA_ARRAY:
170       node->value.v_fields =
171           g_array_new (FALSE, FALSE, sizeof (AmfObjectField));
172       g_array_set_clear_func (node->value.v_fields, amf_object_field_clear);
173       break;
174
175     case GST_AMF_TYPE_STRICT_ARRAY:
176       node->value.v_elements =
177           g_ptr_array_new_with_free_func (gst_amf_node_free);
178       break;
179
180     default:
181       break;
182   }
183
184   return node;
185 }
186
187 GstAmfNode *
188 gst_amf_node_new_null (void)
189 {
190   return node_new (GST_AMF_TYPE_NULL);
191 }
192
193 GstAmfNode *
194 gst_amf_node_new_boolean (gboolean value)
195 {
196   GstAmfNode *node = node_new (GST_AMF_TYPE_BOOLEAN);
197   node->value.v_int = ! !value;
198   return node;
199 }
200
201 GstAmfNode *
202 gst_amf_node_new_number (gdouble value)
203 {
204   GstAmfNode *node = node_new (GST_AMF_TYPE_NUMBER);
205   node->value.v_double = value;
206   return node;
207 }
208
209 GstAmfNode *
210 gst_amf_node_new_string (const gchar * value, gssize size)
211 {
212   GstAmfNode *node = node_new (GST_AMF_TYPE_STRING);
213   gst_amf_node_set_string (node, value, size);
214   return node;
215 }
216
217 GstAmfNode *
218 gst_amf_node_new_take_string (gchar * value, gssize size)
219 {
220   GstAmfNode *node = node_new (GST_AMF_TYPE_STRING);
221   gst_amf_node_take_string (node, value, size);
222   return node;
223 }
224
225 GstAmfNode *
226 gst_amf_node_new_object (void)
227 {
228   return node_new (GST_AMF_TYPE_OBJECT);
229 }
230
231 GstAmfNode *
232 gst_amf_node_copy (const GstAmfNode * node)
233 {
234   GstAmfNode *copy;
235
236   g_return_val_if_fail (node, NULL);
237
238   copy = node_new (node->type);
239
240   switch (node->type) {
241     case GST_AMF_TYPE_STRING:
242     case GST_AMF_TYPE_LONG_STRING:
243       copy->value.v_bytes = g_bytes_ref (node->value.v_bytes);
244       break;
245
246     case GST_AMF_TYPE_OBJECT:
247     case GST_AMF_TYPE_ECMA_ARRAY:{
248       guint i, len = gst_amf_node_get_num_fields (node);
249       for (i = 0; i < len; i++) {
250         const AmfObjectField *field = get_field (node, i);
251         append_field (copy, g_strdup (field->name),
252             gst_amf_node_copy (field->value));
253       }
254       break;
255     }
256
257     case GST_AMF_TYPE_STRICT_ARRAY:{
258       guint i, len = gst_amf_node_get_num_elements (node);
259       for (i = 0; i < len; i++) {
260         const GstAmfNode *elem = get_element (node, i);
261         append_element (copy, gst_amf_node_copy (elem));
262       }
263       break;
264     }
265
266     default:
267       copy->value = node->value;
268       break;
269   }
270
271   return copy;
272 }
273
274 void
275 gst_amf_node_free (gpointer ptr)
276 {
277   GstAmfNode *node = ptr;
278
279   switch (node->type) {
280     case GST_AMF_TYPE_STRING:
281     case GST_AMF_TYPE_LONG_STRING:
282       g_bytes_unref (node->value.v_bytes);
283       break;
284
285     case GST_AMF_TYPE_OBJECT:
286     case GST_AMF_TYPE_ECMA_ARRAY:
287       g_array_unref (node->value.v_fields);
288       break;
289
290     case GST_AMF_TYPE_STRICT_ARRAY:
291       g_ptr_array_unref (node->value.v_elements);
292       break;
293
294     default:
295       break;
296   }
297
298   g_slice_free (GstAmfNode, node);
299 }
300
301 GstAmfType
302 gst_amf_node_get_type (const GstAmfNode * node)
303 {
304   g_return_val_if_fail (node, GST_AMF_TYPE_INVALID);
305   return node->type;
306 }
307
308 gboolean
309 gst_amf_node_get_boolean (const GstAmfNode * node)
310 {
311   g_return_val_if_fail (gst_amf_node_get_type (node) == GST_AMF_TYPE_BOOLEAN,
312       FALSE);
313   return node->value.v_int;
314 }
315
316 gdouble
317 gst_amf_node_get_number (const GstAmfNode * node)
318 {
319   g_return_val_if_fail (gst_amf_node_get_type (node) == GST_AMF_TYPE_NUMBER,
320       FALSE);
321   return node->value.v_double;
322 }
323
324 gchar *
325 gst_amf_node_get_string (const GstAmfNode * node, gsize * out_size)
326 {
327   gsize size;
328   const gchar *data = gst_amf_node_peek_string (node, &size);
329
330   if (out_size) {
331     *out_size = size;
332     return g_memdup (data, size);
333   } else {
334     return g_strndup (data, size);
335   }
336 }
337
338 const gchar *
339 gst_amf_node_peek_string (const GstAmfNode * node, gsize * size)
340 {
341   GstAmfType type = gst_amf_node_get_type (node);
342   g_return_val_if_fail (type == GST_AMF_TYPE_STRING ||
343       type == GST_AMF_TYPE_LONG_STRING, FALSE);
344   return g_bytes_get_data (node->value.v_bytes, size);
345 }
346
347 const GstAmfNode *
348 gst_amf_node_get_field (const GstAmfNode * node, const gchar * name)
349 {
350   guint i, len = gst_amf_node_get_num_fields (node);
351
352   g_return_val_if_fail (name, NULL);
353
354   for (i = 0; i < len; i++) {
355     const AmfObjectField *field = get_field (node, i);
356     if (strcmp (field->name, name) == 0) {
357       return field->value;
358     }
359   }
360
361   return NULL;
362 }
363
364 const GstAmfNode *
365 gst_amf_node_get_field_by_index (const GstAmfNode * node, guint index)
366 {
367   guint len = gst_amf_node_get_num_fields (node);
368   g_return_val_if_fail (index < len, NULL);
369   return get_field (node, index)->value;
370 }
371
372 guint
373 gst_amf_node_get_num_fields (const GstAmfNode * node)
374 {
375   GstAmfType type = gst_amf_node_get_type (node);
376   g_return_val_if_fail (type == GST_AMF_TYPE_OBJECT ||
377       type == GST_AMF_TYPE_ECMA_ARRAY, 0);
378   return node->value.v_fields->len;
379 }
380
381 const GstAmfNode *
382 gst_amf_node_get_element (const GstAmfNode * node, guint index)
383 {
384   guint len = gst_amf_node_get_num_elements (node);
385   g_return_val_if_fail (index < len, NULL);
386   return get_element (node, index);
387 }
388
389 guint
390 gst_amf_node_get_num_elements (const GstAmfNode * node)
391 {
392   GstAmfType type = gst_amf_node_get_type (node);
393   g_return_val_if_fail (type == GST_AMF_TYPE_STRICT_ARRAY, 0);
394   return node->value.v_elements->len;
395 }
396
397 void
398 gst_amf_node_set_boolean (GstAmfNode * node, gboolean value)
399 {
400   g_return_if_fail (node->type == GST_AMF_TYPE_BOOLEAN);
401   node->value.v_int = ! !value;
402 }
403
404 void
405 gst_amf_node_set_number (GstAmfNode * node, gdouble value)
406 {
407   g_return_if_fail (node->type == GST_AMF_TYPE_NUMBER);
408   node->value.v_double = value;
409 }
410
411 void
412 gst_amf_node_take_string (GstAmfNode * node, gchar * value, gssize size)
413 {
414   g_return_if_fail (node->type == GST_AMF_TYPE_STRING ||
415       node->type == GST_AMF_TYPE_LONG_STRING);
416
417   g_return_if_fail (value);
418
419   if (size < 0) {
420     size = strlen (value);
421   }
422
423   if (size > G_MAXUINT32) {
424     GST_WARNING ("Long string too long (%" G_GSSIZE_FORMAT "), truncating",
425         size);
426     size = G_MAXUINT32;
427     value[size] = 0;
428   }
429
430   if (size > G_MAXUINT16) {
431     node->type = GST_AMF_TYPE_LONG_STRING;
432   }
433
434   g_bytes_unref (node->value.v_bytes);
435   node->value.v_bytes = g_bytes_new_take (value, size);
436 }
437
438 void
439 gst_amf_node_set_string (GstAmfNode * node, const gchar * value, gssize size)
440 {
441   gchar *copy;
442
443   g_return_if_fail (value);
444
445   if (size < 0) {
446     size = strlen (value);
447     copy = g_memdup (value, size + 1);
448   } else {
449     copy = g_memdup (value, size);
450   }
451
452   gst_amf_node_take_string (node, copy, size);
453 }
454
455 void
456 gst_amf_node_append_field (GstAmfNode * node, const gchar * name,
457     const GstAmfNode * value)
458 {
459   gst_amf_node_append_take_field (node, name, gst_amf_node_copy (value));
460 }
461
462 void
463 gst_amf_node_append_take_field (GstAmfNode * node, const gchar * name,
464     GstAmfNode * value)
465 {
466   g_return_if_fail (node->type == GST_AMF_TYPE_OBJECT ||
467       node->type == GST_AMF_TYPE_ECMA_ARRAY);
468   g_return_if_fail (name);
469   append_field (node, g_strdup (name), value);
470 }
471
472 void
473 gst_amf_node_append_field_number (GstAmfNode * node, const gchar * name,
474     gdouble value)
475 {
476   gst_amf_node_append_take_field (node, name, gst_amf_node_new_number (value));
477 }
478
479 void
480 gst_amf_node_append_field_boolean (GstAmfNode * node, const gchar * name,
481     gboolean value)
482 {
483   gst_amf_node_append_take_field (node, name, gst_amf_node_new_boolean (value));
484 }
485
486 void
487 gst_amf_node_append_field_string (GstAmfNode * node, const gchar * name,
488     const gchar * value, gssize size)
489 {
490   gst_amf_node_append_take_field (node, name,
491       gst_amf_node_new_string (value, size));
492 }
493
494 void
495 gst_amf_node_append_field_take_string (GstAmfNode * node, const gchar * name,
496     gchar * value, gssize size)
497 {
498   gst_amf_node_append_take_field (node, name,
499       gst_amf_node_new_take_string (value, size));
500 }
501
502 /* Dumper *******************************************************************/
503
504 static inline void
505 dump_indent (GString * string, gint indent, guint depth)
506 {
507   if (indent < 0) {
508     g_string_append_c (string, ' ');
509   } else {
510     guint i;
511     g_string_append_c (string, '\n');
512     for (i = 0; i < indent + depth * 2; i++) {
513       g_string_append_c (string, ' ');
514     }
515   }
516 }
517
518 static inline void
519 dump_bytes (GString * string, GBytes * value)
520 {
521   gsize size;
522   const gchar *data = g_bytes_get_data (value, &size);
523   gst_rtmp_string_print_escaped (string, data, size);
524 }
525
526 static void
527 dump_node (GString * string, const GstAmfNode * node, gint indent,
528     guint recursion_depth)
529 {
530   const gchar *object_delim = "{}";
531
532   switch (gst_amf_node_get_type (node)) {
533     case GST_AMF_TYPE_NUMBER:
534       g_string_append_printf (string, "%g", node->value.v_double);
535       break;
536
537     case GST_AMF_TYPE_BOOLEAN:
538       g_string_append (string, node->value.v_int ? "True" : "False");
539       break;
540
541     case GST_AMF_TYPE_LONG_STRING:
542       g_string_append_c (string, 'L');
543       /* no break */
544     case GST_AMF_TYPE_STRING:
545       dump_bytes (string, node->value.v_bytes);
546       break;
547
548     case GST_AMF_TYPE_ECMA_ARRAY:
549       object_delim = "[]";
550       /* no break */
551     case GST_AMF_TYPE_OBJECT:{
552       guint i, len = gst_amf_node_get_num_fields (node);
553       g_string_append_c (string, object_delim[0]);
554       if (len) {
555         for (i = 0; i < len; i++) {
556           const AmfObjectField *field = get_field (node, i);
557           dump_indent (string, indent, recursion_depth + 1);
558           gst_rtmp_string_print_escaped (string, field->name, -1);
559           g_string_append_c (string, ':');
560           g_string_append_c (string, ' ');
561           dump_node (string, field->value, indent, recursion_depth + 1);
562           if (i < len - 1) {
563             g_string_append_c (string, ',');
564           }
565         }
566         dump_indent (string, indent, recursion_depth);
567       }
568       g_string_append_c (string, object_delim[1]);
569       break;
570     }
571
572     case GST_AMF_TYPE_STRICT_ARRAY:{
573       guint i, len = gst_amf_node_get_num_elements (node);
574       g_string_append_c (string, '(');
575       if (len) {
576         for (i = 0; i < len; i++) {
577           const GstAmfNode *value = get_element (node, i);
578           dump_indent (string, indent, recursion_depth + 1);
579           dump_node (string, value, indent, recursion_depth + 1);
580           if (i < len - 1) {
581             g_string_append_c (string, ',');
582           }
583         }
584         dump_indent (string, indent, recursion_depth);
585       }
586       g_string_append_c (string, ')');
587       break;
588     }
589
590     default:
591       g_string_append (string, gst_amf_type_get_nick (node->type));
592       break;
593   }
594 }
595
596 void
597 gst_amf_node_dump (const GstAmfNode * node, gint indent, GString * string)
598 {
599   dump_node (string, node, indent, 0);
600 }
601
602 static void
603 dump_argument (const GstAmfNode * node, guint n)
604 {
605   if (G_UNLIKELY (GST_LEVEL_LOG <= _gst_debug_min) &&
606       GST_LEVEL_LOG <= gst_debug_category_get_threshold (GST_CAT_DEFAULT)) {
607     GString *string = g_string_new (NULL);
608     gst_amf_node_dump (node, -1, string);
609     GST_LOG ("Argument #%u: %s", n, string->str);
610     g_string_free (string, TRUE);
611   }
612 }
613
614 /* Parser *******************************************************************/
615
616 typedef struct
617 {
618   const guint8 *data;
619   gsize size, offset;
620   guint8 recursion_depth;
621 } AmfParser;
622
623 static GstAmfNode *parse_value (AmfParser * parser);
624
625 static inline guint8
626 parse_u8 (AmfParser * parser)
627 {
628   guint8 value;
629   value = parser->data[parser->offset];
630   parser->offset += sizeof value;
631   return value;
632 }
633
634 static inline guint16
635 parse_u16 (AmfParser * parser)
636 {
637   guint16 value;
638   value = GST_READ_UINT16_BE (parser->data + parser->offset);
639   parser->offset += sizeof value;
640   return value;
641 }
642
643 static inline guint32
644 parse_u32 (AmfParser * parser)
645 {
646   guint32 value;
647   value = GST_READ_UINT32_BE (parser->data + parser->offset);
648   parser->offset += sizeof value;
649   return value;
650 }
651
652 static gdouble
653 parse_number (AmfParser * parser)
654 {
655   gdouble value;
656
657   if (sizeof value > parser->size - parser->offset) {
658     GST_ERROR ("number too long");
659     return 0.0;
660   }
661
662   value = GST_READ_DOUBLE_BE (parser->data + parser->offset);
663   parser->offset += sizeof value;
664   return value;
665 }
666
667 static gboolean
668 parse_boolean (AmfParser * parser)
669 {
670   guint8 value;
671
672   if (sizeof value > parser->size - parser->offset) {
673     GST_ERROR ("boolean too long");
674     return FALSE;
675   }
676
677   value = parse_u8 (parser);
678   return ! !value;
679 }
680
681 static inline GBytes *
682 read_string (AmfParser * parser, gsize size)
683 {
684   gchar *string;
685
686   if (size == 0) {
687     return g_bytes_ref (empty_bytes);
688   }
689
690   if (size > parser->size - parser->offset) {
691     GST_ERROR ("string too long (%" G_GSIZE_FORMAT ")", size);
692     return NULL;
693   }
694
695   /* Null-terminate all incoming strings for internal safety */
696   if (parser->data[parser->offset + size - 1] == 0) {
697     string = g_malloc (size);
698   } else {
699     string = g_malloc (size + 1);
700     string[size] = 0;
701   }
702
703   memcpy (string, parser->data + parser->offset, size);
704
705   parser->offset += size;
706   return g_bytes_new_take (string, size);
707 }
708
709 static GBytes *
710 parse_string (AmfParser * parser)
711 {
712   guint16 size;
713
714   if (sizeof size > parser->size - parser->offset) {
715     GST_ERROR ("string size too long");
716     return NULL;
717   }
718
719   size = parse_u16 (parser);
720   return read_string (parser, size);
721 }
722
723 static GBytes *
724 parse_long_string (AmfParser * parser)
725 {
726   guint32 size;
727
728   if (sizeof size > parser->size - parser->offset) {
729     GST_ERROR ("long string size too long");
730     return NULL;
731   }
732
733   size = parse_u32 (parser);
734   return read_string (parser, size);
735 }
736
737 static guint32
738 parse_object (AmfParser * parser, GstAmfNode * node)
739 {
740   guint32 n_fields = 0;
741
742   while (TRUE) {
743     GBytes *name;
744     gsize size;
745     GstAmfNode *value;
746
747     name = parse_string (parser);
748     if (!name) {
749       GST_ERROR ("object too long");
750       break;
751     }
752
753     value = parse_value (parser);
754     if (!value) {
755       GST_ERROR ("object too long");
756       g_bytes_unref (name);
757       break;
758     }
759
760     if (gst_amf_node_get_type (value) == GST_AMF_TYPE_OBJECT_END) {
761       g_bytes_unref (name);
762       gst_amf_node_free (value);
763       break;
764     }
765
766     if (g_bytes_get_size (name) == 0) {
767       GST_ERROR ("empty object field name");
768       g_bytes_unref (name);
769       gst_amf_node_free (value);
770       break;
771     }
772
773     append_field (node, g_bytes_unref_to_data (name, &size), value);
774     n_fields++;
775   };
776
777   return n_fields;
778 }
779
780 static void
781 parse_ecma_array (AmfParser * parser, GstAmfNode * node)
782 {
783   guint32 n_elements, n_read;
784
785   if (sizeof n_elements > parser->size - parser->offset) {
786     GST_ERROR ("array size too long");
787     return;
788   }
789
790   n_elements = parse_u32 (parser);
791
792   /* FIXME This is weird.  The one time I've seen this, the encoded value
793    * was 0, but the number of elements was 1. */
794   if (n_elements == 0) {
795     GST_DEBUG ("Interpreting ECMA array length 0 as 1");
796     n_elements = 1;
797   }
798
799   n_read = parse_object (parser, node);
800
801   if (n_read != n_elements) {
802     GST_WARNING ("Expected array with %" G_GUINT32_FORMAT " elements,"
803         " but read %" G_GUINT32_FORMAT, n_elements, n_read);
804   }
805 }
806
807 static void
808 parse_strict_array (AmfParser * parser, GstAmfNode * node)
809 {
810   GstAmfNode *value = NULL;
811   guint32 n_elements, i;
812
813   if (sizeof n_elements > parser->size - parser->offset) {
814     GST_ERROR ("array size too long");
815     return;
816   }
817
818   n_elements = parse_u32 (parser);
819
820   for (i = 0; i < n_elements; i++) {
821     value = parse_value (parser);
822     if (!value) {
823       GST_ERROR ("array too long");
824       break;
825     }
826
827     append_element (node, value);
828   }
829 }
830
831 static GstAmfNode *
832 parse_value (AmfParser * parser)
833 {
834   GstAmfNode *node = NULL;
835   GstAmfType type;
836
837   if (1 > parser->size - parser->offset) {
838     GST_ERROR ("value too long");
839     return NULL;
840   }
841
842   type = parse_u8 (parser);
843   node = node_new (type);
844   GST_TRACE ("parsing AMF type %d (%s)", type, gst_amf_type_get_nick (type));
845
846   parser->recursion_depth++;
847   if (parser->recursion_depth > MAX_RECURSION_DEPTH) {
848     GST_ERROR ("maximum recursion depth %d reached", parser->recursion_depth);
849     return node;
850   }
851
852   switch (type) {
853     case GST_AMF_TYPE_NUMBER:
854       node->value.v_double = parse_number (parser);
855       break;
856     case GST_AMF_TYPE_BOOLEAN:
857       node->value.v_int = parse_boolean (parser);
858       break;
859     case GST_AMF_TYPE_STRING:
860       node->value.v_bytes = parse_string (parser);
861       break;
862     case GST_AMF_TYPE_LONG_STRING:
863       node->value.v_bytes = parse_long_string (parser);
864       break;
865     case GST_AMF_TYPE_OBJECT:
866       parse_object (parser, node);
867       break;
868     case GST_AMF_TYPE_ECMA_ARRAY:
869       parse_ecma_array (parser, node);
870       break;
871     case GST_AMF_TYPE_STRICT_ARRAY:
872       parse_strict_array (parser, node);
873       break;
874     case GST_AMF_TYPE_NULL:
875     case GST_AMF_TYPE_UNDEFINED:
876     case GST_AMF_TYPE_OBJECT_END:
877     case GST_AMF_TYPE_UNSUPPORTED:
878       break;
879     default:
880       GST_ERROR ("unimplemented AMF type %d (%s)", type,
881           gst_amf_type_get_nick (type));
882       break;
883   }
884
885   parser->recursion_depth--;
886   return node;
887 }
888
889 GstAmfNode *
890 gst_amf_node_parse (const guint8 * data, gsize size, guint8 ** endptr)
891 {
892   AmfParser parser = {
893     .data = data,
894     .size = size,
895   };
896   GstAmfNode *node;
897
898   g_return_val_if_fail (data, NULL);
899   g_return_val_if_fail (size, NULL);
900
901   init_static ();
902
903   GST_TRACE ("Starting parse with %" G_GSIZE_FORMAT " bytes", parser.size);
904
905   node = parse_value (&parser);
906   if (gst_amf_node_get_type (node) == GST_AMF_TYPE_INVALID) {
907     GST_ERROR ("invalid value");
908     goto out;
909   }
910
911   if (G_UNLIKELY (GST_LEVEL_LOG <= _gst_debug_min) &&
912       GST_LEVEL_LOG <= gst_debug_category_get_threshold (GST_CAT_DEFAULT)) {
913     GString *string = g_string_new (NULL);
914     gst_amf_node_dump (node, -1, string);
915     GST_LOG ("Parsed value: %s", string->str);
916     g_string_free (string, TRUE);
917   }
918
919   GST_TRACE ("Done parsing; consumed %" G_GSIZE_FORMAT " bytes and left %"
920       G_GSIZE_FORMAT " bytes", parser.offset, parser.size - parser.offset);
921
922 out:
923   if (endptr) {
924     *endptr = (guint8 *) parser.data + parser.offset;
925   }
926
927   return node;
928 }
929
930 GPtrArray *
931 gst_amf_parse_command (const guint8 * data, gsize size,
932     gdouble * transaction_id, gchar ** command_name)
933 {
934   AmfParser parser = {
935     .data = data,
936     .size = size,
937   };
938   GstAmfNode *node1 = NULL, *node2 = NULL;
939   GPtrArray *args = NULL;
940
941   g_return_val_if_fail (data, NULL);
942   g_return_val_if_fail (size, NULL);
943
944   init_static ();
945
946   GST_TRACE ("Starting parse with %" G_GSIZE_FORMAT " bytes", parser.size);
947
948   node1 = parse_value (&parser);
949   if (gst_amf_node_get_type (node1) != GST_AMF_TYPE_STRING) {
950     GST_ERROR ("no command name");
951     goto out;
952   }
953
954   node2 = parse_value (&parser);
955   if (gst_amf_node_get_type (node2) != GST_AMF_TYPE_NUMBER) {
956     GST_ERROR ("no transaction ID");
957     goto out;
958   }
959
960   GST_LOG ("Parsing command '%s', transid %.0f",
961       gst_amf_node_peek_string (node1, NULL), gst_amf_node_get_number (node2));
962
963   args = g_ptr_array_new_with_free_func (gst_amf_node_free);
964
965   while (parser.offset < parser.size) {
966     GstAmfNode *node = parse_value (&parser);
967     if (!node) {
968       break;
969     }
970
971     dump_argument (node, args->len);
972     g_ptr_array_add (args, node);
973   }
974
975   GST_TRACE ("Done parsing; consumed %" G_GSIZE_FORMAT " bytes and left %"
976       G_GSIZE_FORMAT " bytes", parser.offset, parser.size - parser.offset);
977
978   if (args->len == 0) {
979     GST_ERROR ("no command arguments");
980     g_clear_pointer (&args, g_ptr_array_unref);
981     goto out;
982   }
983
984   if (command_name) {
985     *command_name = gst_amf_node_get_string (node1, NULL);
986   }
987
988   if (transaction_id) {
989     *transaction_id = gst_amf_node_get_number (node2);
990   }
991
992 out:
993   g_clear_pointer (&node1, gst_amf_node_free);
994   g_clear_pointer (&node2, gst_amf_node_free);
995   return args;
996 }
997
998 /* Serializer ***************************************************************/
999
1000 static void serialize_value (GByteArray * array, const GstAmfNode * node);
1001
1002 static inline void
1003 serialize_u8 (GByteArray * array, guint8 value)
1004 {
1005   g_byte_array_append (array, (guint8 *) & value, sizeof value);
1006 }
1007
1008 static inline void
1009 serialize_u16 (GByteArray * array, guint16 value)
1010 {
1011   value = GUINT16_TO_BE (value);
1012   g_byte_array_append (array, (guint8 *) & value, sizeof value);
1013 }
1014
1015 static inline void
1016 serialize_u32 (GByteArray * array, guint32 value)
1017 {
1018   value = GUINT32_TO_BE (value);
1019   g_byte_array_append (array, (guint8 *) & value, sizeof value);
1020 }
1021
1022 static inline void
1023 serialize_number (GByteArray * array, gdouble value)
1024 {
1025   value = GDOUBLE_TO_BE (value);
1026   g_byte_array_append (array, (guint8 *) & value, sizeof value);
1027 }
1028
1029 static inline void
1030 serialize_boolean (GByteArray * array, gboolean value)
1031 {
1032   serialize_u8 (array, value);
1033 }
1034
1035 static void
1036 serialize_string (GByteArray * array, const gchar * string, gssize size)
1037 {
1038   if (size < 0) {
1039     size = strlen (string);
1040   }
1041
1042   if (size > G_MAXUINT16) {
1043     GST_WARNING ("String too long: %" G_GSSIZE_FORMAT, size);
1044     size = G_MAXUINT16;
1045   }
1046
1047   serialize_u16 (array, size);
1048   g_byte_array_append (array, (guint8 *) string, size);
1049 }
1050
1051 static void
1052 serialize_long_string (GByteArray * array, const gchar * string, gssize size)
1053 {
1054   if (size < 0) {
1055     size = strlen (string);
1056   }
1057
1058   if (size > G_MAXUINT32) {
1059     GST_WARNING ("Long string too long: %" G_GSSIZE_FORMAT, size);
1060     size = G_MAXUINT32;
1061   }
1062
1063   serialize_u32 (array, size);
1064   g_byte_array_append (array, (guint8 *) string, size);
1065 }
1066
1067 static inline void
1068 serialize_bytes (GByteArray * array, GBytes * bytes, gboolean long_string)
1069 {
1070   gsize size;
1071   const gchar *data = g_bytes_get_data (bytes, &size);
1072
1073   if (long_string) {
1074     serialize_long_string (array, data, size);
1075   } else {
1076     serialize_string (array, data, size);
1077   }
1078 }
1079
1080 static void
1081 serialize_object (GByteArray * array, const GstAmfNode * node)
1082 {
1083   guint i;
1084
1085   for (i = 0; i < gst_amf_node_get_num_fields (node); i++) {
1086     const AmfObjectField *field = get_field (node, i);
1087     serialize_string (array, field->name, -1);
1088     serialize_value (array, field->value);
1089   }
1090   serialize_u16 (array, 0);
1091   serialize_u8 (array, GST_AMF_TYPE_OBJECT_END);
1092 }
1093
1094 static void
1095 serialize_ecma_array (GByteArray * array, const GstAmfNode * node)
1096 {
1097   /* FIXME: Shouldn't this be the field count? */
1098   serialize_u32 (array, 0);
1099   serialize_object (array, node);
1100 }
1101
1102 static void
1103 serialize_value (GByteArray * array, const GstAmfNode * node)
1104 {
1105   serialize_u8 (array, node->type);
1106   switch (node->type) {
1107     case GST_AMF_TYPE_NUMBER:
1108       serialize_number (array, node->value.v_double);
1109       break;
1110     case GST_AMF_TYPE_BOOLEAN:
1111       serialize_boolean (array, node->value.v_int);
1112       break;
1113     case GST_AMF_TYPE_STRING:
1114       serialize_bytes (array, node->value.v_bytes, FALSE);
1115       break;
1116     case GST_AMF_TYPE_LONG_STRING:
1117       serialize_bytes (array, node->value.v_bytes, TRUE);
1118       break;
1119     case GST_AMF_TYPE_OBJECT:
1120       serialize_object (array, node);
1121       break;
1122     case GST_AMF_TYPE_ECMA_ARRAY:
1123       serialize_ecma_array (array, node);
1124       break;
1125     case GST_AMF_TYPE_NULL:
1126     case GST_AMF_TYPE_UNDEFINED:
1127     case GST_AMF_TYPE_OBJECT_END:
1128     case GST_AMF_TYPE_UNSUPPORTED:
1129       break;
1130     default:
1131       GST_ERROR ("unimplemented AMF type %d (%s)", node->type,
1132           gst_amf_type_get_nick (node->type));
1133       break;
1134   }
1135 }
1136
1137 GBytes *
1138 gst_amf_node_serialize (const GstAmfNode * node)
1139 {
1140   GByteArray *array = g_byte_array_new ();
1141
1142   g_return_val_if_fail (node, NULL);
1143
1144   init_static ();
1145
1146   if (G_UNLIKELY (GST_LEVEL_LOG <= _gst_debug_min) &&
1147       GST_LEVEL_LOG <= gst_debug_category_get_threshold (GST_CAT_DEFAULT)) {
1148     GString *string = g_string_new (NULL);
1149     gst_amf_node_dump (node, -1, string);
1150     GST_LOG ("Serializing value: %s", string->str);
1151     g_string_free (string, TRUE);
1152   }
1153
1154   serialize_value (array, node);
1155
1156   GST_TRACE ("Done serializing; produced %u bytes", array->len);
1157
1158   return g_byte_array_free_to_bytes (array);
1159 }
1160
1161 GBytes *
1162 gst_amf_serialize_command (gdouble transaction_id, const gchar * command_name,
1163     const GstAmfNode * argument, ...)
1164 {
1165   va_list ap;
1166   GBytes *ret;
1167
1168   va_start (ap, argument);
1169   ret = gst_amf_serialize_command_valist (transaction_id, command_name,
1170       argument, ap);
1171   va_end (ap);
1172
1173   return ret;
1174 }
1175
1176 GBytes *
1177 gst_amf_serialize_command_valist (gdouble transaction_id,
1178     const gchar * command_name, const GstAmfNode * argument, va_list var_args)
1179 {
1180   GByteArray *array = g_byte_array_new ();
1181   guint i = 0;
1182
1183   g_return_val_if_fail (command_name, NULL);
1184   g_return_val_if_fail (argument, NULL);
1185
1186   init_static ();
1187
1188   GST_LOG ("Serializing command '%s', transid %.0f", command_name,
1189       transaction_id);
1190
1191   serialize_u8 (array, GST_AMF_TYPE_STRING);
1192   serialize_string (array, command_name, -1);
1193   serialize_u8 (array, GST_AMF_TYPE_NUMBER);
1194   serialize_number (array, transaction_id);
1195
1196   while (argument) {
1197     serialize_value (array, argument);
1198     dump_argument (argument, i++);
1199
1200     argument = va_arg (var_args, const GstAmfNode *);
1201   }
1202
1203   GST_TRACE ("Done serializing; consumed %u args and produced %u bytes", i,
1204       array->len);
1205
1206   return g_byte_array_free_to_bytes (array);
1207 }