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/mbuf/mbuf.c b/src/mbuf/mbuf.c
new file mode 100644
index 0000000..6fe47bd
--- /dev/null
+++ b/src/mbuf/mbuf.c
@@ -0,0 +1,608 @@
+/**
+ * @file mbuf.c  Memory buffers
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <string.h>
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mem.h>
+#include <re_mbuf.h>
+
+
+#define DEBUG_MODULE "mbuf"
+#define DEBUG_LEVEL 4
+#include <re_dbg.h>
+
+
+enum {DEFAULT_SIZE=512};
+
+
+static void mbuf_destructor(void *data)
+{
+	struct mbuf *mb = data;
+
+	mem_deref(mb->buf);
+}
+
+
+/**
+ * Allocate a new memory buffer
+ *
+ * @param size Initial buffer size
+ *
+ * @return New memory buffer, NULL if no memory
+ */
+struct mbuf *mbuf_alloc(size_t size)
+{
+	struct mbuf *mb;
+
+	mb = mem_zalloc(sizeof(*mb), mbuf_destructor);
+	if (!mb)
+		return NULL;
+
+	if (mbuf_resize(mb, size ? size : DEFAULT_SIZE))
+		return mem_deref(mb);
+
+	return mb;
+}
+
+
+/**
+ * Allocate a new memory buffer with a reference to another mbuf
+ *
+ * @param mbr Memory buffer to reference
+ *
+ * @return New memory buffer, NULL if no memory
+ */
+struct mbuf *mbuf_alloc_ref(struct mbuf *mbr)
+{
+	struct mbuf *mb;
+
+	if (!mbr)
+		return NULL;
+
+	mb = mem_zalloc(sizeof(*mb), mbuf_destructor);
+	if (!mb)
+		return NULL;
+
+	mb->buf  = mem_ref(mbr->buf);
+	mb->size = mbr->size;
+	mb->pos  = mbr->pos;
+	mb->end  = mbr->end;
+
+	return mb;
+}
+
+
+/**
+ * Initialize a memory buffer
+ *
+ * @param mb Memory buffer to initialize
+ */
+void mbuf_init(struct mbuf *mb)
+{
+	if (!mb)
+		return;
+
+	mb->buf  = NULL;
+	mb->size = 0;
+	mb->pos  = 0;
+	mb->end  = 0;
+}
+
+
+/**
+ * Reset a memory buffer
+ *
+ * @param mb Memory buffer to reset
+ */
+void mbuf_reset(struct mbuf *mb)
+{
+	if (!mb)
+		return;
+
+	mb->buf = mem_deref(mb->buf);
+	mbuf_init(mb);
+}
+
+
+/**
+ * Resize a memory buffer
+ *
+ * @param mb   Memory buffer to resize
+ * @param size New buffer size
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mbuf_resize(struct mbuf *mb, size_t size)
+{
+	uint8_t *buf;
+
+	if (!mb)
+		return EINVAL;
+
+	buf = mb->buf ? mem_realloc(mb->buf, size) : mem_alloc(size, NULL);
+	if (!buf)
+		return ENOMEM;
+
+	mb->buf  = buf;
+	mb->size = size;
+
+	return 0;
+}
+
+
+/**
+ * Trim unused trailing bytes in a memory buffer, resize if necessary
+ *
+ * @param mb   Memory buffer to trim
+ */
+void mbuf_trim(struct mbuf *mb)
+{
+	int err;
+
+	if (!mb || !mb->end || mb->end == mb->size)
+		return;
+
+	/* We shrink - this cannot fail */
+	err = mbuf_resize(mb, mb->end);
+	if (err) {
+		DEBUG_WARNING("trim: resize failed (%m)\n", err);
+	}
+}
+
+
+/**
+ * Shift mbuf content position
+ *
+ * @param mb    Memory buffer to shift
+ * @param shift Shift offset count
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mbuf_shift(struct mbuf *mb, ssize_t shift)
+{
+	size_t rsize;
+	uint8_t *p;
+
+	if (!mb)
+		return EINVAL;
+
+	if (((ssize_t)mb->pos + shift) < 0 ||
+	    ((ssize_t)mb->end + shift) < 0)
+		return ERANGE;
+
+	rsize = mb->end + shift;
+
+	if (rsize > mb->size) {
+
+		int err;
+
+		err = mbuf_resize(mb, rsize);
+		if (err)
+			return err;
+	}
+
+	p = mbuf_buf(mb);
+
+	memmove(p + shift, p, mbuf_get_left(mb));
+
+	mb->pos += shift;
+	mb->end += shift;
+
+	return 0;
+}
+
+
+/**
+ * Write a block of memory to a memory buffer
+ *
+ * @param mb   Memory buffer
+ * @param buf  Memory block to write
+ * @param size Number of bytes to write
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mbuf_write_mem(struct mbuf *mb, const uint8_t *buf, size_t size)
+{
+	size_t rsize;
+
+	if (!mb || !buf)
+		return EINVAL;
+
+	rsize = mb->pos + size;
+
+	if (rsize > mb->size) {
+		const size_t dsize = mb->size ? (mb->size * 2)
+			: DEFAULT_SIZE;
+		int err;
+
+		err = mbuf_resize(mb, MAX(rsize, dsize));
+		if (err)
+			return err;
+	}
+
+	memcpy(mb->buf + mb->pos, buf, size);
+
+	mb->pos += size;
+	mb->end  = MAX(mb->end, mb->pos);
+
+	return 0;
+}
+
+
+/**
+ * Write an 8-bit value to a memory buffer
+ *
+ * @param mb Memory buffer
+ * @param v  8-bit value to write
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mbuf_write_u8(struct mbuf *mb, uint8_t v)
+{
+	return mbuf_write_mem(mb, (uint8_t *)&v, sizeof(v));
+}
+
+
+/**
+ * Write a 16-bit value to a memory buffer
+ *
+ * @param mb Memory buffer
+ * @param v  16-bit value to write
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mbuf_write_u16(struct mbuf *mb, uint16_t v)
+{
+	return mbuf_write_mem(mb, (uint8_t *)&v, sizeof(v));
+}
+
+
+/**
+ * Write a 32-bit value to a memory buffer
+ *
+ * @param mb Memory buffer
+ * @param v  32-bit value to write
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mbuf_write_u32(struct mbuf *mb, uint32_t v)
+{
+	return mbuf_write_mem(mb, (uint8_t *)&v, sizeof(v));
+}
+
+
+/**
+ * Write a 64-bit value to a memory buffer
+ *
+ * @param mb Memory buffer
+ * @param v  64-bit value to write
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mbuf_write_u64(struct mbuf *mb, uint64_t v)
+{
+	return mbuf_write_mem(mb, (uint8_t *)&v, sizeof(v));
+}
+
+
+/**
+ * Write a null-terminated string to a memory buffer
+ *
+ * @param mb  Memory buffer
+ * @param str Null terminated string to write
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mbuf_write_str(struct mbuf *mb, const char *str)
+{
+	if (!str)
+		return EINVAL;
+
+	return mbuf_write_mem(mb, (const uint8_t *)str, strlen(str));
+}
+
+
+/**
+ * Write a pointer-length string to a memory buffer
+ *
+ * @param mb  Memory buffer
+ * @param pl  Pointer-length string
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mbuf_write_pl(struct mbuf *mb, const struct pl *pl)
+{
+	if (!pl)
+		return EINVAL;
+
+	return mbuf_write_mem(mb, (const uint8_t *)pl->p, pl->l);
+}
+
+
+/**
+ * Read a block of memory from a memory buffer
+ *
+ * @param mb   Memory buffer
+ * @param buf  Buffer to read data to
+ * @param size Size of buffer
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mbuf_read_mem(struct mbuf *mb, uint8_t *buf, size_t size)
+{
+	if (!mb || !buf)
+		return EINVAL;
+
+	if (size > mbuf_get_left(mb)) {
+		DEBUG_WARNING("tried to read beyond mbuf end (%u > %u)\n",
+			      size, mbuf_get_left(mb));
+		return EOVERFLOW;
+	}
+
+	memcpy(buf, mb->buf + mb->pos, size);
+
+	mb->pos += size;
+
+	return 0;
+}
+
+
+/**
+ * Read an 8-bit value from a memory buffer
+ *
+ * @param mb Memory buffer
+ *
+ * @return 8-bit value
+ */
+uint8_t mbuf_read_u8(struct mbuf *mb)
+{
+	uint8_t v;
+
+	return (0 == mbuf_read_mem(mb, &v, sizeof(v))) ? v : 0;
+}
+
+
+/**
+ * Read a 16-bit value from a memory buffer
+ *
+ * @param mb Memory buffer
+ *
+ * @return 16-bit value
+ */
+uint16_t mbuf_read_u16(struct mbuf *mb)
+{
+	uint16_t v;
+
+	return (0 == mbuf_read_mem(mb, (uint8_t *)&v, sizeof(v))) ? v : 0;
+}
+
+
+/**
+ * Read a 32-bit value from a memory buffer
+ *
+ * @param mb Memory buffer
+ *
+ * @return 32-bit value
+ */
+uint32_t mbuf_read_u32(struct mbuf *mb)
+{
+	uint32_t v;
+
+	return (0 == mbuf_read_mem(mb, (uint8_t *)&v, sizeof(v))) ? v : 0;
+}
+
+
+/**
+ * Read a 64-bit value from a memory buffer
+ *
+ * @param mb Memory buffer
+ *
+ * @return 64-bit value
+ */
+uint64_t mbuf_read_u64(struct mbuf *mb)
+{
+	uint64_t v;
+
+	return (0 == mbuf_read_mem(mb, (uint8_t *)&v, sizeof(v))) ? v : 0;
+}
+
+
+/**
+ * Read a string from a memory buffer
+ *
+ * @param mb   Memory buffer
+ * @param str  Buffer to read string to
+ * @param size Size of buffer
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mbuf_read_str(struct mbuf *mb, char *str, size_t size)
+{
+	if (!mb || !str)
+		return EINVAL;
+
+	while (size--) {
+		const uint8_t c = mbuf_read_u8(mb);
+		*str++ = c;
+		if ('\0' == c)
+			break;
+	}
+
+	return 0;
+}
+
+
+/**
+ * Duplicate a null-terminated string from a memory buffer
+ *
+ * @param mb   Memory buffer
+ * @param strp Pointer to destination string; allocated and set
+ * @param len  Length of string
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mbuf_strdup(struct mbuf *mb, char **strp, size_t len)
+{
+	char *str;
+	int err;
+
+	if (!mb || !strp)
+		return EINVAL;
+
+	str = mem_alloc(len + 1, NULL);
+	if (!str)
+		return ENOMEM;
+
+	err = mbuf_read_mem(mb, (uint8_t *)str, len);
+	if (err)
+		goto out;
+
+	str[len] = '\0';
+
+ out:
+	if (err)
+		mem_deref(str);
+	else
+		*strp = str;
+
+	return err;
+}
+
+
+static int vprintf_handler(const char *p, size_t size, void *arg)
+{
+	struct mbuf *mb = arg;
+
+	return mbuf_write_mem(mb, (const uint8_t *)p, size);
+}
+
+
+/**
+ * Print a formatted variable argument list to a memory buffer
+ *
+ * @param mb  Memory buffer
+ * @param fmt Formatted string
+ * @param ap  Variable argument list
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mbuf_vprintf(struct mbuf *mb, const char *fmt, va_list ap)
+{
+	return re_vhprintf(fmt, ap, vprintf_handler, mb);
+}
+
+
+/**
+ * Print a formatted string to a memory buffer
+ *
+ * @param mb  Memory buffer
+ * @param fmt Formatted string
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mbuf_printf(struct mbuf *mb, const char *fmt, ...)
+{
+	int err = 0;
+	va_list ap;
+
+	va_start(ap, fmt);
+	err = re_vhprintf(fmt, ap, vprintf_handler, mb);
+	va_end(ap);
+
+	return err;
+}
+
+
+/**
+ * Write a pointer-length string to a memory buffer, excluding a section
+ *
+ * @param mb   Memory buffer
+ * @param pl   Pointer-length string
+ * @param skip Part of pl to exclude
+ *
+ * @return 0 if success, otherwise errorcode
+ *
+ * @todo: create substf variante
+ */
+int mbuf_write_pl_skip(struct mbuf *mb, const struct pl *pl,
+		       const struct pl *skip)
+{
+	struct pl r;
+	int err;
+
+	if (!pl || !skip)
+		return EINVAL;
+
+	if (pl->p > skip->p || (skip->p + skip->l) > (pl->p + pl->l))
+		return ERANGE;
+
+	r.p = pl->p;
+	r.l = skip->p - pl->p;
+
+	err = mbuf_write_mem(mb, (const uint8_t *)r.p, r.l);
+	if (err)
+		return err;
+
+	r.p = skip->p + skip->l;
+	r.l = pl->p + pl->l - r.p;
+
+	return mbuf_write_mem(mb, (const uint8_t *)r.p, r.l);
+}
+
+
+/**
+ * Write n bytes of value 'c' to a memory buffer
+ *
+ * @param mb   Memory buffer
+ * @param c    Value to write
+ * @param n    Number of bytes to write
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mbuf_fill(struct mbuf *mb, uint8_t c, size_t n)
+{
+	size_t rsize;
+
+	if (!mb || !n)
+		return EINVAL;
+
+	rsize = mb->pos + n;
+
+	if (rsize > mb->size) {
+		const size_t dsize = mb->size ? (mb->size * 2)
+			: DEFAULT_SIZE;
+		int err;
+
+		err = mbuf_resize(mb, MAX(rsize, dsize));
+		if (err)
+			return err;
+	}
+
+	memset(mb->buf + mb->pos, c, n);
+
+	mb->pos += n;
+	mb->end  = MAX(mb->end, mb->pos);
+
+	return 0;
+}
+
+
+/**
+ * Debug the memory buffer
+ *
+ * @param pf Print handler
+ * @param mb Memory buffer
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int mbuf_debug(struct re_printf *pf, const struct mbuf *mb)
+{
+	if (!mb)
+		return 0;
+
+	return re_hprintf(pf, "buf=%p pos=%zu end=%zu size=%zu",
+			  mb->buf, mb->pos, mb->end, mb->size);
+}