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
init_static(void)39 init_static (void)
40 {
41 static 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 *
gst_amf_type_get_nick(GstAmfType type)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
amf_object_field_clear(gpointer ptr)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 *
get_field(const GstAmfNode * node,guint index)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
append_field(GstAmfNode * node,gchar * name,GstAmfNode * value)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 *
get_element(const GstAmfNode * node,guint index)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
append_element(GstAmfNode * node,GstAmfNode * value)147 append_element (GstAmfNode * node, GstAmfNode * value)
148 {
149 g_ptr_array_add (node->value.v_elements, value);
150 }
151
152 static GstAmfNode *
node_new(GstAmfType type)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 *
gst_amf_node_new_null(void)188 gst_amf_node_new_null (void)
189 {
190 return node_new (GST_AMF_TYPE_NULL);
191 }
192
193 GstAmfNode *
gst_amf_node_new_boolean(gboolean value)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 *
gst_amf_node_new_number(gdouble value)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 *
gst_amf_node_new_string(const gchar * value,gssize size)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 *
gst_amf_node_new_take_string(gchar * value,gssize size)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 *
gst_amf_node_new_object(void)226 gst_amf_node_new_object (void)
227 {
228 return node_new (GST_AMF_TYPE_OBJECT);
229 }
230
231 GstAmfNode *
gst_amf_node_copy(const GstAmfNode * node)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
gst_amf_node_free(gpointer ptr)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
gst_amf_node_get_type(const GstAmfNode * node)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
gst_amf_node_get_boolean(const GstAmfNode * node)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
gst_amf_node_get_number(const GstAmfNode * node)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 *
gst_amf_node_get_string(const GstAmfNode * node,gsize * out_size)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_memdup2 (data, size);
333 } else {
334 return g_strndup (data, size);
335 }
336 }
337
338 const gchar *
gst_amf_node_peek_string(const GstAmfNode * node,gsize * size)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 *
gst_amf_node_get_field(const GstAmfNode * node,const gchar * name)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 *
gst_amf_node_get_field_by_index(const GstAmfNode * node,guint index)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
gst_amf_node_get_num_fields(const GstAmfNode * node)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 *
gst_amf_node_get_element(const GstAmfNode * node,guint index)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
gst_amf_node_get_num_elements(const GstAmfNode * node)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
gst_amf_node_set_boolean(GstAmfNode * node,gboolean value)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
gst_amf_node_set_number(GstAmfNode * node,gdouble value)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
gst_amf_node_take_string(GstAmfNode * node,gchar * value,gssize size)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
gst_amf_node_set_string(GstAmfNode * node,const gchar * value,gssize size)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_memdup2 (value, size + 1);
448 } else {
449 copy = g_memdup2 (value, size);
450 }
451
452 gst_amf_node_take_string (node, copy, size);
453 }
454
455 void
gst_amf_node_append_field(GstAmfNode * node,const gchar * name,const GstAmfNode * value)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
gst_amf_node_append_take_field(GstAmfNode * node,const gchar * name,GstAmfNode * value)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
gst_amf_node_append_field_number(GstAmfNode * node,const gchar * name,gdouble value)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
gst_amf_node_append_field_boolean(GstAmfNode * node,const gchar * name,gboolean value)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
gst_amf_node_append_field_string(GstAmfNode * node,const gchar * name,const gchar * value,gssize size)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
gst_amf_node_append_field_take_string(GstAmfNode * node,const gchar * name,gchar * value,gssize size)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
dump_indent(GString * string,gint indent,guint depth)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
dump_bytes(GString * string,GBytes * value)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
dump_node(GString * string,const GstAmfNode * node,gint indent,guint recursion_depth)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
gst_amf_node_dump(const GstAmfNode * node,gint indent,GString * string)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
dump_argument(const GstAmfNode * node,guint n)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
parse_u8(AmfParser * parser)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
parse_u16(AmfParser * parser)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
parse_u32(AmfParser * parser)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
parse_number(AmfParser * parser)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
parse_boolean(AmfParser * parser)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 *
read_string(AmfParser * parser,gsize size)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 *
parse_string(AmfParser * parser)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 *
parse_long_string(AmfParser * parser)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
parse_object(AmfParser * parser,GstAmfNode * node)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
parse_ecma_array(AmfParser * parser,GstAmfNode * node)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
parse_strict_array(AmfParser * parser,GstAmfNode * node)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 *
parse_value(AmfParser * parser)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 *
gst_amf_node_parse(const guint8 * data,gsize size,guint8 ** endptr)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 *
gst_amf_parse_command(const guint8 * data,gsize size,gdouble * transaction_id,gchar ** command_name)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
serialize_u8(GByteArray * array,guint8 value)1003 serialize_u8 (GByteArray * array, guint8 value)
1004 {
1005 g_byte_array_append (array, (guint8 *) & value, sizeof value);
1006 }
1007
1008 static inline void
serialize_u16(GByteArray * array,guint16 value)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
serialize_u32(GByteArray * array,guint32 value)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
serialize_number(GByteArray * array,gdouble value)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
serialize_boolean(GByteArray * array,gboolean value)1030 serialize_boolean (GByteArray * array, gboolean value)
1031 {
1032 serialize_u8 (array, value);
1033 }
1034
1035 static void
serialize_string(GByteArray * array,const gchar * string,gssize size)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
serialize_long_string(GByteArray * array,const gchar * string,gssize size)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
serialize_bytes(GByteArray * array,GBytes * bytes,gboolean long_string)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
serialize_object(GByteArray * array,const GstAmfNode * node)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
serialize_ecma_array(GByteArray * array,const GstAmfNode * node)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
serialize_value(GByteArray * array,const GstAmfNode * node)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 *
gst_amf_node_serialize(const GstAmfNode * node)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 *
gst_amf_serialize_command(gdouble transaction_id,const gchar * command_name,const GstAmfNode * argument,...)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 *
gst_amf_serialize_command_valist(gdouble transaction_id,const gchar * command_name,const GstAmfNode * argument,va_list var_args)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 }
1208