Squashed 'third_party/rawrtc/re/' content from commit f3163ce8b
Change-Id: I6a235e6ac0f03269d951026f9d195da05c40fdab
git-subtree-dir: third_party/rawrtc/re
git-subtree-split: f3163ce8b526a13b35ef71ce4dd6f43585064d8a
diff --git a/src/rtmp/amf_enc.c b/src/rtmp/amf_enc.c
new file mode 100644
index 0000000..0ba157d
--- /dev/null
+++ b/src/rtmp/amf_enc.c
@@ -0,0 +1,245 @@
+/**
+ * @file rtmp/amf_enc.c Real Time Messaging Protocol (RTMP) -- AMF Encoding
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <string.h>
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mem.h>
+#include <re_mbuf.h>
+#include <re_net.h>
+#include <re_sa.h>
+#include <re_list.h>
+#include <re_sys.h>
+#include <re_odict.h>
+#include <re_rtmp.h>
+#include "rtmp.h"
+
+
+static int rtmp_amf_encode_key(struct mbuf *mb, const char *key)
+{
+ size_t len;
+ int err;
+
+ len = str_len(key);
+
+ if (len > 65535)
+ return EOVERFLOW;
+
+ err = mbuf_write_u16(mb, htons((uint16_t)len));
+ err |= mbuf_write_str(mb, key);
+
+ return err;
+}
+
+
+static int rtmp_amf_encode_object_start(struct mbuf *mb)
+{
+ return mbuf_write_u8(mb, RTMP_AMF_TYPE_OBJECT);
+}
+
+
+static int rtmp_amf_encode_array_start(struct mbuf *mb,
+ uint8_t type, uint32_t length)
+{
+ int err;
+
+ err = mbuf_write_u8(mb, type);
+ err |= mbuf_write_u32(mb, htonl(length));
+
+ return err;
+}
+
+
+static int rtmp_amf_encode_object_end(struct mbuf *mb)
+{
+ int err;
+
+ err = mbuf_write_u16(mb, 0);
+ err |= mbuf_write_u8(mb, RTMP_AMF_TYPE_OBJECT_END);
+
+ return err;
+}
+
+
+static bool container_has_key(enum rtmp_amf_type type)
+{
+ switch (type) {
+
+ case RTMP_AMF_TYPE_OBJECT: return true;
+ case RTMP_AMF_TYPE_ECMA_ARRAY: return true;
+ case RTMP_AMF_TYPE_STRICT_ARRAY: return false;
+ default: return false;
+ }
+}
+
+
+int rtmp_amf_encode_number(struct mbuf *mb, double val)
+{
+ const union {
+ uint64_t i;
+ double f;
+ } num = {
+ .f = val
+ };
+ int err;
+
+ if (!mb)
+ return EINVAL;
+
+ err = mbuf_write_u8(mb, RTMP_AMF_TYPE_NUMBER);
+ err |= mbuf_write_u64(mb, sys_htonll(num.i));
+
+ return err;
+}
+
+
+int rtmp_amf_encode_boolean(struct mbuf *mb, bool boolean)
+{
+ int err;
+
+ if (!mb)
+ return EINVAL;
+
+ err = mbuf_write_u8(mb, RTMP_AMF_TYPE_BOOLEAN);
+ err |= mbuf_write_u8(mb, !!boolean);
+
+ return err;
+}
+
+
+int rtmp_amf_encode_string(struct mbuf *mb, const char *str)
+{
+ size_t len;
+ int err;
+
+ if (!mb || !str)
+ return EINVAL;
+
+ len = str_len(str);
+
+ if (len > 65535)
+ return EOVERFLOW;
+
+ err = mbuf_write_u8(mb, RTMP_AMF_TYPE_STRING);
+ err |= mbuf_write_u16(mb, htons((uint16_t)len));
+ err |= mbuf_write_str(mb, str);
+
+ return err;
+}
+
+
+int rtmp_amf_encode_null(struct mbuf *mb)
+{
+ if (!mb)
+ return EINVAL;
+
+ return mbuf_write_u8(mb, RTMP_AMF_TYPE_NULL);
+}
+
+
+/*
+ * NUMBER double
+ * BOOLEAN bool
+ * STRING const char *
+ * OBJECT const char *key sub-count
+ * NULL NULL
+ * ARRAY const char *key sub-count
+ */
+int rtmp_amf_vencode_object(struct mbuf *mb, enum rtmp_amf_type container,
+ unsigned propc, va_list *ap)
+{
+ bool encode_key;
+ unsigned i;
+ int err = 0;
+
+ if (!mb || !propc || !ap)
+ return EINVAL;
+
+ encode_key = container_has_key(container);
+
+ switch (container) {
+
+ case RTMP_AMF_TYPE_OBJECT:
+ err = rtmp_amf_encode_object_start(mb);
+ break;
+
+ case RTMP_AMF_TYPE_ECMA_ARRAY:
+ case RTMP_AMF_TYPE_STRICT_ARRAY:
+ err = rtmp_amf_encode_array_start(mb, container, propc);
+ break;
+
+ case RTMP_AMF_TYPE_ROOT:
+ break;
+
+ default:
+ return ENOTSUP;
+ }
+
+ if (err)
+ return err;
+
+ for (i=0; i<propc; i++) {
+
+ int type = va_arg(*ap, int);
+ const char *str;
+ int subcount;
+ double dbl;
+ bool b;
+
+ /* add key if ARRAY or OBJECT container */
+ if (encode_key) {
+ const char *key;
+
+ key = va_arg(*ap, const char *);
+ if (!key)
+ return EINVAL;
+
+ err = rtmp_amf_encode_key(mb, key);
+ if (err)
+ return err;
+ }
+
+ switch (type) {
+
+ case RTMP_AMF_TYPE_NUMBER:
+ dbl = va_arg(*ap, double);
+ err = rtmp_amf_encode_number(mb, dbl);
+ break;
+
+ case RTMP_AMF_TYPE_BOOLEAN:
+ b = va_arg(*ap, int);
+ err = rtmp_amf_encode_boolean(mb, b);
+ break;
+
+ case RTMP_AMF_TYPE_STRING:
+ str = va_arg(*ap, const char *);
+ err = rtmp_amf_encode_string(mb, str);
+ break;
+
+ case RTMP_AMF_TYPE_NULL:
+ err = rtmp_amf_encode_null(mb);
+ break;
+
+ case RTMP_AMF_TYPE_OBJECT:
+ case RTMP_AMF_TYPE_ECMA_ARRAY:
+ case RTMP_AMF_TYPE_STRICT_ARRAY:
+ /* recursive */
+ subcount = va_arg(*ap, int);
+ err = rtmp_amf_vencode_object(mb, type, subcount, ap);
+ break;
+
+ default:
+ return ENOTSUP;
+ }
+
+ if (err)
+ return err;
+ }
+
+ if (encode_key)
+ err = rtmp_amf_encode_object_end(mb);
+
+ return err;
+}