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;
+}