common/refcnt.h \
common/fragbuf.h \
common/json.h \
- common/transport.h
+ common/transport.h \
+ common/tlv.h \
+ common/native-types.h
libmurphy_common_la_REGULAR_SOURCES = \
common/log.c \
common/transport.c \
common/stream-transport.c \
common/internal-transport.c \
- common/dgram-transport.c
+ common/dgram-transport.c \
+ common/tlv.c \
+ common/native-types.c
libmurphy_common_la_SOURCES = \
$(libmurphy_common_la_REGULAR_SOURCES) \
--- /dev/null
+/*
+ * Copyright (c) 2012, 2013, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+
+#include <murphy/common/macros.h>
+#include <murphy/common/debug.h>
+#include <murphy/common/log.h>
+#include <murphy/common/mm.h>
+#include <murphy/common/list.h>
+#include <murphy/common/tlv.h>
+#include <murphy/common/native-types.h>
+
+
+/*
+ * TLV tags we use when encoding/decoding our native types
+ */
+
+typedef enum {
+ TAG_NONE = MRP_TLV_UNTAGGED, /* untagged data */
+ TAG_STRUCT, /* a native structure */
+ TAG_MEMBER, /* a native structure member */
+ TAG_ARRAY, /* an array */
+ TAG_NELEM, /* size of an array (in elements) */
+} tag_t;
+
+
+/*
+ * extra header we use to keep track of memory while decoding
+ */
+
+typedef struct {
+ mrp_list_hook_t hook; /* hook to chunk list */
+ char data[0]; /* user-visible data */
+} chunk_t;
+
+
+static int encode_struct(mrp_tlv_t *tlv, void *data, mrp_native_type_t *t,
+ mrp_typemap_t *idmap);
+static int decode_struct(mrp_tlv_t *tlv, mrp_list_hook_t **chunks,
+ void **datap, uint32_t *idp, mrp_typemap_t *idmap);
+static int print_struct(char **buf, size_t *size, int level,
+ void *data, mrp_native_type_t *t);
+static void free_native(mrp_native_type_t *t);
+
+static void *alloc_chunk(mrp_list_hook_t **chunks, size_t size);
+static void free_chunks(mrp_list_hook_t *chunks);
+
+
+/*
+ * list and table of registered native types
+ */
+
+static MRP_LIST_HOOK(types);
+static int ntype;
+
+static mrp_native_type_t **typetbl;
+
+
+static mrp_native_member_t *native_member(mrp_native_type_t *t, int idx)
+{
+ if (0 <= idx && idx < (int)t->nmember)
+ return t->members + idx;
+ else {
+ errno = EINVAL;
+ return NULL;
+ }
+}
+
+
+static int member_index(mrp_native_type_t *t, const char *name)
+{
+ mrp_native_member_t *m;
+ size_t i;
+
+ for (i = 0, m = t->members; i < t->nmember; i++, m++)
+ if (!strcmp(m->any.name, name))
+ return m - t->members;
+
+ return -1;
+}
+
+
+static int copy_member(mrp_native_type_t *t, mrp_native_member_t *m)
+{
+ mrp_native_member_t *tm;
+
+ if ((tm = native_member(t, member_index(t, m->any.name))) != NULL)
+ return tm - t->members;
+ else
+ tm = t->members + t->nmember;
+
+ *tm = *m;
+
+ if ((tm->any.name = mrp_strdup(m->any.name)) != 0) {
+ t->nmember++;
+ return tm - t->members;
+ }
+ else
+ return -1;
+}
+
+
+static mrp_native_type_t *find_type(const char *type_name)
+{
+ mrp_native_type_t *t;
+ mrp_list_hook_t *p, *n;
+
+ mrp_list_foreach(&types, p, n) {
+ t = mrp_list_entry(p, typeof(*t), hook);
+
+ if (!strcmp(t->name, type_name))
+ return t;
+ }
+
+ return NULL;
+}
+
+
+static mrp_native_type_t *lookup_type(uint32_t id)
+{
+ mrp_native_type_t *t;
+ mrp_list_hook_t *p, *n;
+
+ /* XXX TODO: turn this into a real lookup instead of linear search */
+
+ if (1 <= id && id <= (uint32_t)ntype)
+ if ((t = typetbl[id]) != NULL && t->id == id)
+ return t;
+
+ mrp_log_warning("Type lookup for %u failed, doing linear search...\n", id);
+
+ mrp_list_foreach(&types, p, n) {
+ t = mrp_list_entry(p, typeof(*t), hook);
+
+ if (t->id == id)
+ return t;
+ }
+
+ return NULL;
+}
+
+
+static mrp_native_type_t *member_type(mrp_native_member_t *m)
+{
+ mrp_native_type_t *t;
+
+ if (m->any.type != MRP_TYPE_STRUCT)
+ t = lookup_type(m->any.type);
+ else
+ t = lookup_type(m->strct.data_type.id);
+
+ if (t == NULL)
+ errno = EINVAL;
+
+ return t;
+}
+
+
+static inline uint32_t map_type(uint32_t id, mrp_typemap_t *idmap)
+{
+ uint32_t mapped = MRP_INVALID_TYPE;
+
+ if (id < MRP_TYPE_STRUCT || idmap == NULL)
+ mapped = id;
+ else {
+ while (idmap->typeid != MRP_INVALID_TYPE) {
+ if (idmap->typeid == id) {
+ mapped = MRP_TYPE_STRUCT + idmap->mapped;
+ break;
+ }
+ else
+ idmap++;
+ }
+ }
+
+ return mapped;
+}
+
+
+static inline uint32_t mapped_type(uint32_t mapped, mrp_typemap_t *idmap)
+{
+ uint32_t id = MRP_INVALID_TYPE;
+
+ if (mapped < MRP_TYPE_STRUCT || idmap == NULL)
+ id = mapped;
+ else {
+ while (idmap->typeid != MRP_INVALID_TYPE) {
+ if (MRP_TYPE_STRUCT + idmap->mapped == mapped) {
+ id = idmap->typeid;
+ break;
+ }
+ else
+ idmap++;
+ }
+ }
+
+ return id;
+}
+
+
+uint32_t mrp_type_id(const char *type_name)
+{
+ mrp_native_type_t *t;
+
+ if ((t = find_type(type_name)) != NULL)
+ return t->id;
+ else
+ return MRP_INVALID_TYPE;
+}
+
+
+static size_t type_size(uint32_t id)
+{
+ mrp_native_type_t *t = lookup_type(id);
+
+ if (t != NULL)
+ return t->size;
+ else
+ return 0;
+}
+
+
+static int matching_types(mrp_native_type_t *t1, mrp_native_type_t *t2)
+{
+ MRP_UNUSED(t1);
+ MRP_UNUSED(t2);
+
+ /* XXX TODO */
+ return 0;
+}
+
+
+static void register_default_types(void)
+{
+#define DEFAULT_NTYPE (MRP_TYPE_STRUCT + 1)
+
+#define DECLARE_TYPE(_ctype, _mtype) \
+ static mrp_native_type_t _mtype##_type = { \
+ .name = #_ctype, \
+ .id = MRP_TYPE_##_mtype, \
+ .size = sizeof(_ctype), \
+ .members = NULL, \
+ .nmember = 0, \
+ .hook = { NULL, NULL } \
+ }
+
+#define REGISTER_TYPE(_type) \
+ mrp_list_init(&(_type)->hook); \
+ mrp_list_append(&types, &(_type)->hook); \
+ typetbl[(_type)->id] = (_type)
+
+ if (mrp_reallocz(typetbl, 0, DEFAULT_NTYPE) == NULL) {
+ mrp_log_error("Failed to initialize native type table.");
+ abort();
+ }
+
+ DECLARE_TYPE( int8_t , INT8 );
+ DECLARE_TYPE(uint8_t , UINT8 );
+ DECLARE_TYPE(int16_t , INT16 );
+ DECLARE_TYPE(uint16_t, UINT16);
+ DECLARE_TYPE(int32_t , INT32 );
+ DECLARE_TYPE(uint32_t, UINT32);
+ DECLARE_TYPE(int64_t , INT64 );
+ DECLARE_TYPE(uint64_t, UINT64);
+ DECLARE_TYPE(float , FLOAT );
+ DECLARE_TYPE(double , DOUBLE);
+ DECLARE_TYPE(bool , BOOL );
+ DECLARE_TYPE(char * , STRING);
+ DECLARE_TYPE(void * , BLOB );
+ DECLARE_TYPE(void * , ARRAY );
+ DECLARE_TYPE(void * , STRUCT);
+
+
+ REGISTER_TYPE(&INT8_type);
+ REGISTER_TYPE(&UINT8_type);
+ REGISTER_TYPE(&INT16_type);
+ REGISTER_TYPE(&UINT16_type);
+ REGISTER_TYPE(&INT32_type);
+ REGISTER_TYPE(&UINT32_type);
+ REGISTER_TYPE(&INT64_type);
+ REGISTER_TYPE(&UINT64_type);
+ REGISTER_TYPE(&FLOAT_type);
+ REGISTER_TYPE(&DOUBLE_type);
+ REGISTER_TYPE(&BOOL_type);
+ REGISTER_TYPE(&STRING_type);
+ REGISTER_TYPE(&BLOB_type);
+ REGISTER_TYPE(&ARRAY_type);
+ REGISTER_TYPE(&STRUCT_type);
+
+ ntype = DEFAULT_NTYPE;
+
+#undef DECLARE_TYPE
+#undef REGISTER_TYPE
+}
+
+
+uint32_t mrp_register_native(mrp_native_type_t *type)
+{
+ mrp_native_type_t *existing = find_type(type->name);
+ mrp_native_type_t *t, *elemt;
+ mrp_native_member_t *s, *d, *m;
+ int idx;
+
+ (void)member_type;
+
+ if (existing != NULL && !matching_types(existing, type)) {
+ errno = EEXIST;
+ return MRP_INVALID_TYPE;
+ }
+
+ if (ntype == 0)
+ register_default_types();
+
+ if ((t = mrp_allocz(sizeof(*t))) == NULL)
+ return MRP_INVALID_TYPE;
+
+ mrp_list_init(&t->hook);
+ t->name = mrp_strdup(type->name);
+
+ if (t->name == NULL)
+ goto fail;
+
+ t->size = type->size;
+ t->members = mrp_allocz_array(mrp_native_member_t, type->nmember);
+
+ if (t->members == NULL && type->nmember != 0)
+ goto fail;
+
+ /*
+ * Notes:
+ *
+ * While we copy the members, we also take care of reordering them
+ * so that any member that another one depends on ('size' members)
+ * get registered (and consequently encoded and decoded) before the
+ * dependant members.
+ */
+
+ s = type->members;
+ d = t->members;
+ while (t->nmember < type->nmember) {
+ /* make sure there are no duplicate members */
+ if (native_member(type, member_index(type, s->any.name)) != s) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ /* skip already copied members */
+ while (member_index(t, s->any.name) >= 0)
+ s++;
+
+ switch (s->any.type) {
+ case MRP_TYPE_BLOB:
+ m = native_member(t, member_index(t, s->blob.size.name));
+
+ if (m == NULL) {
+ m = native_member(type,
+ member_index(type, s->blob.size.name));
+
+ if (m == NULL)
+ goto fail;
+ else
+ idx = copy_member(t, m);
+
+ if (idx < 0)
+ goto fail;
+ }
+ else
+ idx = m - t->members;
+
+ if (copy_member(t, s) < 0)
+ goto fail;
+
+ d = t->members + t->nmember;
+ d->blob.size.idx = idx;
+
+ break;
+
+ case MRP_TYPE_ARRAY:
+ if (s->array.kind == MRP_ARRAY_SIZE_EXPLICIT) {
+ m = native_member(t, member_index(t, s->array.size.name));
+
+ if (m == NULL) {
+ m = native_member(type,
+ member_index(type,
+ s->array.size.name));
+
+ if (m == NULL)
+ goto fail;
+ else
+ idx = copy_member(t, m);
+
+ if (idx < 0)
+ goto fail;
+
+ }
+ else
+ idx = m - t->members;
+
+ d = t->members + t->nmember;
+
+ if (copy_member(t, s) < 0)
+ goto fail;
+
+ d->array.size.idx = idx;
+ }
+ else {
+ d = t->members + t->nmember;
+
+ if (copy_member(t, s) < 0)
+ goto fail;
+ }
+
+ d->array.elem.id = mrp_type_id(d->array.elem.name);
+
+ if (d->array.elem.id == MRP_INVALID_TYPE)
+ goto fail;
+
+ if (s->array.kind == MRP_ARRAY_SIZE_GUARDED) {
+ elemt = lookup_type(d->array.elem.id);
+
+ if (elemt == NULL)
+ goto fail;
+
+ idx = member_index(elemt, s->array.size.name);
+
+ d->array.size.idx = member_index(elemt, s->array.size.name);
+
+ if (d->array.size.idx == (uint32_t)-1)
+ goto fail;
+ }
+
+ break;
+
+ case MRP_TYPE_STRUCT:
+ d = t->members + t->nmember;
+
+ if (copy_member(t, s) < 0)
+ goto fail;
+
+ d->strct.data_type.id = mrp_type_id(d->strct.data_type.name);
+
+ if (d->strct.data_type.id == MRP_INVALID_TYPE)
+ goto fail;
+ break;
+
+ default:
+ if (copy_member(t, s) < 0)
+ goto fail;
+ }
+ }
+
+ if (mrp_reallocz(typetbl, ntype, ntype + 1) == NULL)
+ goto fail;
+
+ t->id = ntype;
+ mrp_list_append(&types, &t->hook);
+ typetbl[ntype] = t;
+ ntype++;
+
+ return t->id;
+
+ fail:
+ free_native(t);
+
+ return MRP_INVALID_TYPE;
+}
+
+
+static void free_native(mrp_native_type_t *t)
+{
+ mrp_native_member_t *m;
+ size_t i;
+
+ if (t == NULL)
+ return;
+
+ mrp_list_delete(&t->hook);
+
+ mrp_free(t->name);
+ for (i = 0, m = t->members; i < t->nmember; i++, m++)
+ mrp_free(m->any.name);
+ mrp_free(t);
+}
+
+
+static int encode_basic(mrp_tlv_t *tlv, mrp_type_t type, mrp_value_t *v)
+{
+ switch (type) {
+ case MRP_TYPE_INT8: return mrp_tlv_push_int8 (tlv, TAG_NONE, v->s8);
+ case MRP_TYPE_UINT8: return mrp_tlv_push_uint8 (tlv, TAG_NONE, v->u8);
+ case MRP_TYPE_INT16: return mrp_tlv_push_int16 (tlv, TAG_NONE, v->s16);
+ case MRP_TYPE_UINT16: return mrp_tlv_push_uint16(tlv, TAG_NONE, v->u16);
+ case MRP_TYPE_INT32: return mrp_tlv_push_int32 (tlv, TAG_NONE, v->s32);
+ case MRP_TYPE_UINT32: return mrp_tlv_push_uint32(tlv, TAG_NONE, v->u32);
+ case MRP_TYPE_INT64: return mrp_tlv_push_int64 (tlv, TAG_NONE, v->s64);
+ case MRP_TYPE_UINT64: return mrp_tlv_push_uint64(tlv, TAG_NONE, v->u64);
+ case MRP_TYPE_FLOAT: return mrp_tlv_push_float (tlv, TAG_NONE, v->flt);
+ case MRP_TYPE_DOUBLE: return mrp_tlv_push_double(tlv, TAG_NONE, v->dbl);
+ case MRP_TYPE_BOOL: return mrp_tlv_push_bool (tlv, TAG_NONE, v->bln);
+ case MRP_TYPE_STRING: return mrp_tlv_push_string(tlv, TAG_NONE, v->str);
+ default: return -1;
+ }
+}
+
+
+static inline int get_blob_size(void *base, mrp_native_type_t *t,
+ mrp_native_blob_t *m, size_t *sizep)
+{
+ mrp_native_member_t *sizem;
+ mrp_value_t *v;
+
+ if ((sizem = native_member(t, m->size.idx)) == NULL)
+ return -1;
+
+ if (sizem->any.layout == MRP_LAYOUT_INDIRECT)
+ v = *(void **)base;
+ else
+ v = base;
+
+ switch (sizem->any.type) {
+ case MRP_TYPE_INT8: *sizep = v->s8; return 0;
+ case MRP_TYPE_UINT8: *sizep = v->u8; return 0;
+ case MRP_TYPE_INT16: *sizep = v->s16; return 0;
+ case MRP_TYPE_UINT16: *sizep = v->u16; return 0;
+ case MRP_TYPE_INT32: *sizep = v->s32; return 0;
+ case MRP_TYPE_UINT32: *sizep = v->u32; return 0;
+ case MRP_TYPE_INT64: *sizep = (size_t)v->s32; return 0;
+ case MRP_TYPE_UINT64: *sizep = (size_t)v->u32; return 0;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+
+static int guard_offset_and_size(mrp_native_array_t *m, size_t *offsp,
+ size_t *sizep)
+{
+ mrp_native_type_t *t = lookup_type(m->elem.id);
+ mrp_native_member_t *g;
+
+ if (t == NULL)
+ return -1;
+
+ switch (t->id) {
+ case MRP_TYPE_INT8:
+ case MRP_TYPE_UINT8:
+ case MRP_TYPE_INT16:
+ case MRP_TYPE_UINT16:
+ case MRP_TYPE_INT32:
+ case MRP_TYPE_UINT32:
+ case MRP_TYPE_INT64:
+ case MRP_TYPE_UINT64:
+ case MRP_TYPE_FLOAT:
+ case MRP_TYPE_DOUBLE:
+ case MRP_TYPE_BOOL:
+ case MRP_TYPE_STRING:
+ *offsp = 0;
+ *sizep = t->size;
+ return 0;
+
+ default:
+ if ((g = native_member(t, m->size.idx)) == NULL)
+ return -1;
+
+ *offsp = g->any.offs;
+ *sizep = type_size(g->any.type);
+ return 0;
+ }
+}
+
+
+static inline int get_explicit_array_size(void *base, mrp_native_type_t *t,
+ mrp_native_array_t *m)
+{
+ mrp_native_member_t *nelemm;
+ mrp_value_t *v;
+ int n;
+
+ if ((nelemm = native_member(t, m->size.idx)) == NULL)
+ return -1;
+ if (nelemm->any.layout == MRP_LAYOUT_INDIRECT)
+ v = *(void **)(base + nelemm->any.offs);
+ else
+ v = base + nelemm->any.offs;
+
+ switch (nelemm->any.type) {
+ case MRP_TYPE_INT8: n = v->s8; break;
+ case MRP_TYPE_UINT8: n = v->u8; break;
+ case MRP_TYPE_INT16: n = v->s16; break;
+ case MRP_TYPE_UINT16: n = v->u16; break;
+ case MRP_TYPE_INT32: n = v->s32; break;
+ case MRP_TYPE_UINT32: n = v->u32; break;
+ case MRP_TYPE_INT64: n = (int)v->s64; break;
+ case MRP_TYPE_UINT64: n = (int)v->u64; break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return n;
+}
+
+
+static inline int get_guarded_array_size(void *arrp, mrp_native_array_t *m)
+{
+ mrp_value_t *guard;
+ size_t goffs, gsize, esize;
+ int n;
+
+ if ((esize = type_size(m->elem.id)) == 0)
+ return -1;
+
+ if (guard_offset_and_size(m, &goffs, &gsize) < 0)
+ return -1;
+
+ guard = &m->sentinel;
+
+ for (n = 0; memcmp(arrp + n * esize + goffs, guard, gsize); n++)
+ ;
+ return n;
+}
+
+
+static int get_array_size(void *base, mrp_native_type_t *t, void *arrp,
+ mrp_native_array_t *m, size_t *nelemp,
+ size_t *esizep)
+{
+ int n;
+
+ if ((*esizep = type_size(m->elem.id)) == 0)
+ return -1;
+
+ switch (m->kind) {
+ case MRP_ARRAY_SIZE_FIXED:
+ *nelemp = m->size.nelem;
+ return 0;
+
+ case MRP_ARRAY_SIZE_EXPLICIT:
+ if ((n = get_explicit_array_size(base, t, m)) < 0)
+ return -1;
+
+ *nelemp = (size_t)n;
+ return 0;
+
+ case MRP_ARRAY_SIZE_GUARDED:
+ if ((n = get_guarded_array_size(arrp, m)) < 0)
+ return -1;
+
+ *nelemp = (size_t)n;
+ return 0;
+
+ default:
+ return -1;
+ }
+}
+
+
+static int terminate_guarded_array(void *elem, mrp_native_array_t *m,
+ mrp_native_type_t *mt)
+{
+ mrp_native_member_t *g;
+
+ if (m->elem.id <= MRP_TYPE_STRING)
+ memcpy(elem, &m->sentinel, mt->size);
+ else if (m->elem.id > MRP_TYPE_STRUCT) {
+ if ((g = native_member(mt, m->size.idx)) == NULL)
+ return -1;
+
+ memcpy(elem + g->any.offs, &m->sentinel, type_size(g->any.type));
+ }
+
+ return 0;
+}
+
+
+static int encode_array(mrp_tlv_t *tlv, void *arrp, mrp_native_array_t *m,
+ size_t nelem, size_t elem_size, mrp_typemap_t *idmap)
+{
+ mrp_native_type_t *t;
+ mrp_value_t *v;
+ void *elem;
+ size_t i;
+
+ if (mrp_tlv_push_uint32(tlv, TAG_ARRAY, map_type(m->elem.id, idmap)) < 0)
+ return -1;
+
+ if (mrp_tlv_push_uint32(tlv, TAG_NELEM, nelem) < 0)
+ return -1;
+
+ if ((t = lookup_type(m->elem.id)) == NULL)
+ return -1;
+
+ for (i = 0, elem = arrp; i < nelem; i++, elem += elem_size) {
+ v = elem;
+
+ switch (t->id) {
+ case MRP_TYPE_INT8:
+ case MRP_TYPE_UINT8:
+ case MRP_TYPE_INT16:
+ case MRP_TYPE_UINT16:
+ case MRP_TYPE_INT32:
+ case MRP_TYPE_UINT32:
+ case MRP_TYPE_INT64:
+ case MRP_TYPE_UINT64:
+ case MRP_TYPE_FLOAT:
+ case MRP_TYPE_DOUBLE:
+ case MRP_TYPE_BOOL:
+ case MRP_TYPE_STRING:
+ if (encode_basic(tlv, t->id, v) < 0)
+ return -1;
+ break;
+
+ case MRP_TYPE_BLOB: /* XXX TODO implement blobs */
+ return -1;
+
+ case MRP_TYPE_ARRAY:
+ return -1;
+
+ default:
+ /* an MRP_TYPE_STRUCT */
+ if (encode_struct(tlv, elem, t, idmap) < 0)
+ return -1;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+static int encode_struct(mrp_tlv_t *tlv, void *data, mrp_native_type_t *t,
+ mrp_typemap_t *idmap)
+{
+ mrp_native_member_t *m;
+ mrp_native_type_t *mt;
+ mrp_value_t *v;
+ uint32_t idx;
+ size_t size, nelem;
+
+ if (t == NULL)
+ return -1;
+
+ if (mrp_tlv_push_uint32(tlv, TAG_STRUCT, map_type(t->id, idmap)) < 0)
+ return -1;
+
+ for (idx = 0, m = t->members; idx < t->nmember; idx++, m++) {
+ if (mrp_tlv_push_uint32(tlv, TAG_MEMBER, idx) < 0)
+ return -1;
+
+ if (m->any.layout == MRP_LAYOUT_INDIRECT)
+ v = *(void **)(data + m->any.offs);
+ else
+ v = data + m->any.offs;
+
+ switch (m->any.type) {
+ case MRP_TYPE_INT8:
+ case MRP_TYPE_UINT8:
+ case MRP_TYPE_INT16:
+ case MRP_TYPE_UINT16:
+ case MRP_TYPE_INT32:
+ case MRP_TYPE_UINT32:
+ case MRP_TYPE_INT64:
+ case MRP_TYPE_UINT64:
+ case MRP_TYPE_FLOAT:
+ case MRP_TYPE_DOUBLE:
+ case MRP_TYPE_BOOL:
+ case MRP_TYPE_STRING:
+ if (encode_basic(tlv, m->any.type, v) < 0)
+ return -1;
+ break;
+
+ case MRP_TYPE_BLOB: /* XXX TODO implement blobs */
+ if (get_blob_size(data, t, &m->blob, &size) < 0)
+ return -1;
+ return -1;
+
+ case MRP_TYPE_ARRAY:
+ if (get_array_size(data, t, v->ptr, &m->array, &nelem, &size) < 0)
+ return -1;
+ if (encode_array(tlv, v->ptr, &m->array, nelem,
+ size, idmap) < 0)
+ return -1;
+ break;
+
+ case MRP_TYPE_STRUCT:
+ if ((mt = lookup_type(m->strct.data_type.id)) == NULL)
+ return -1;
+ if (encode_struct(tlv, v->ptr, mt, idmap) < 0)
+ return -1;
+ break;
+
+ default:
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+int mrp_encode_native(void *data, uint32_t id, size_t reserve, void **bufp,
+ size_t *sizep, mrp_typemap_t *idmap)
+{
+ mrp_native_type_t *t = lookup_type(id);
+ mrp_tlv_t tlv;
+
+ *bufp = NULL;
+ *sizep = 0;
+
+ if (t == NULL)
+ return -1;
+
+ if (mrp_tlv_setup_write(&tlv, reserve + 4096) < 0)
+ return -1;
+
+ if (reserve > 0)
+ if (mrp_tlv_reserve(&tlv, reserve, 1) == NULL)
+ goto fail;
+
+ if (encode_struct(&tlv, data, t, idmap) < 0)
+ goto fail;
+
+ mrp_tlv_trim(&tlv);
+ mrp_tlv_steal(&tlv, bufp, sizep);
+
+ return 0;
+
+ fail:
+ mrp_tlv_cleanup(&tlv);
+ return -1;
+}
+
+
+static void *allocate_indirect(mrp_list_hook_t **chunks, mrp_value_t *v,
+ mrp_native_member_t *m, mrp_typemap_t *idmap)
+{
+ size_t size;
+
+ switch (m->any.type) {
+ case MRP_TYPE_INT8:
+ case MRP_TYPE_UINT8:
+ return (v->ptr = alloc_chunk(chunks, sizeof(int8_t)));
+ case MRP_TYPE_INT16:
+ case MRP_TYPE_UINT16:
+ return (v->ptr = alloc_chunk(chunks, sizeof(int16_t)));
+ case MRP_TYPE_INT32:
+ case MRP_TYPE_UINT32:
+ return (v->ptr = alloc_chunk(chunks, sizeof(int32_t)));
+ case MRP_TYPE_INT64:
+ case MRP_TYPE_UINT64:
+ return (v->ptr = alloc_chunk(chunks, sizeof(int64_t)));
+ case MRP_TYPE_FLOAT:
+ return (v->ptr = alloc_chunk(chunks, sizeof(float)));
+ case MRP_TYPE_DOUBLE:
+ return (v->ptr = alloc_chunk(chunks, sizeof(double)));
+ case MRP_TYPE_BOOL:
+ return (v->ptr = alloc_chunk(chunks, sizeof(bool)));
+ case MRP_TYPE_STRING:
+ return v; /* will be allocated by TLV pull */
+ case MRP_TYPE_BLOB:
+ return v; /* will be allocated by decoder */
+ case MRP_TYPE_ARRAY:
+ return v; /* will be allocated by decoder */
+ case MRP_TYPE_STRUCT:
+ if ((size = type_size(mapped_type(m->strct.data_type.id, idmap))) == 0)
+ return NULL;
+ return (v->ptr = alloc_chunk(chunks, size));
+ default:
+ return NULL;
+ }
+}
+
+
+static void *alloc_str_chunk(size_t size, void *chunksp)
+{
+ return alloc_chunk((mrp_list_hook_t **)chunksp, size);
+}
+
+
+static int decode_basic(mrp_tlv_t *tlv, mrp_list_hook_t **chunks,
+ mrp_type_t type, mrp_value_t *v)
+{
+ switch (type) {
+ case MRP_TYPE_INT8: return mrp_tlv_pull_int8 (tlv, TAG_NONE, &v->s8);
+ case MRP_TYPE_UINT8: return mrp_tlv_pull_uint8 (tlv, TAG_NONE, &v->u8);
+ case MRP_TYPE_INT16: return mrp_tlv_pull_int16 (tlv, TAG_NONE, &v->s16);
+ case MRP_TYPE_UINT16: return mrp_tlv_pull_uint16(tlv, TAG_NONE, &v->u16);
+ case MRP_TYPE_INT32: return mrp_tlv_pull_int32 (tlv, TAG_NONE, &v->s32);
+ case MRP_TYPE_UINT32: return mrp_tlv_pull_uint32(tlv, TAG_NONE, &v->u32);
+ case MRP_TYPE_INT64: return mrp_tlv_pull_int64 (tlv, TAG_NONE, &v->s64);
+ case MRP_TYPE_UINT64: return mrp_tlv_pull_uint64(tlv, TAG_NONE, &v->u64);
+ case MRP_TYPE_FLOAT: return mrp_tlv_pull_float (tlv, TAG_NONE, &v->flt);
+ case MRP_TYPE_DOUBLE: return mrp_tlv_pull_double(tlv, TAG_NONE, &v->dbl);
+ case MRP_TYPE_BOOL: return mrp_tlv_pull_bool (tlv, TAG_NONE, &v->bln);
+ case MRP_TYPE_STRING: return mrp_tlv_pull_string(tlv, TAG_NONE, &v->strp,-1,
+ alloc_str_chunk, chunks);
+ default: return -1;
+ }
+}
+
+
+static int decode_array(mrp_tlv_t *tlv, mrp_list_hook_t **chunks,
+ void **arrp, mrp_native_array_t *m,
+ void *data, mrp_native_type_t *t,
+ mrp_typemap_t *idmap)
+{
+ mrp_native_type_t *mt;
+ mrp_value_t *v;
+ void *elem, *base;
+ size_t elem_size, i;
+ uint32_t id, nelem;
+ int n, guard;
+
+ if (mrp_tlv_pull_uint32(tlv, TAG_ARRAY, &id) < 0)
+ return -1;
+
+ if ((id = mapped_type(id, idmap)) != m->elem.id)
+ return -1;
+
+ if ((elem_size = type_size(id)) == 0)
+ return -1;
+
+ if (mrp_tlv_pull_uint32(tlv, TAG_NELEM, &nelem) < 0)
+ return -1;
+
+ if ((mt = lookup_type(m->elem.id)) == NULL)
+ return -1;
+
+ switch (m->kind) {
+ case MRP_ARRAY_SIZE_EXPLICIT:
+ if ((n = get_explicit_array_size(data, t, m)) < 0)
+ return -1;
+ guard = 0;
+ break;
+ case MRP_ARRAY_SIZE_FIXED:
+ n = m->size.nelem;
+ guard = 0;
+ break;
+ case MRP_ARRAY_SIZE_GUARDED:
+ n = nelem;
+ guard = 1;
+ break;
+ default:
+ return -1;
+ }
+
+ if (n != (int)nelem)
+ return -1;
+
+ switch (m->layout) {
+ case MRP_LAYOUT_INLINED:
+ base = (void *)arrp;
+ break;
+ case MRP_LAYOUT_INDIRECT:
+ case MRP_LAYOUT_DEFAULT:
+ if ((*arrp = alloc_chunk(chunks, (nelem + guard) * elem_size)) == NULL)
+ return (nelem + guard) ? -1 : 0;
+ base = *arrp;
+ break;
+ default:
+ return -1;
+ }
+
+ for (i = 0, elem = base; i < nelem; i++, elem += elem_size) {
+ v = elem;
+
+ switch (mt->id) {
+ case MRP_TYPE_INT8:
+ case MRP_TYPE_UINT8:
+ case MRP_TYPE_INT16:
+ case MRP_TYPE_UINT16:
+ case MRP_TYPE_INT32:
+ case MRP_TYPE_UINT32:
+ case MRP_TYPE_INT64:
+ case MRP_TYPE_UINT64:
+ case MRP_TYPE_FLOAT:
+ case MRP_TYPE_DOUBLE:
+ case MRP_TYPE_BOOL:
+ case MRP_TYPE_STRING:
+ if (decode_basic(tlv, chunks, mt->id, v) < 0)
+ return -1;
+ break;
+
+ case MRP_TYPE_BLOB: /* XXX TODO implement blobs */
+ return -1;
+
+ case MRP_TYPE_ARRAY:
+ return -1;
+
+ default:
+ /* an MRP_TYPE_STRUCT */
+ if (decode_struct(tlv, chunks, &elem, &id, idmap) < 0)
+ return -1;
+ }
+ }
+
+ if (guard) {
+ if (terminate_guarded_array(elem, m, mt) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int decode_struct(mrp_tlv_t *tlv, mrp_list_hook_t **chunks,
+ void **datap, uint32_t *idp, mrp_typemap_t *idmap)
+{
+ mrp_native_type_t *t;
+ mrp_native_member_t *m;
+ mrp_value_t *v;
+ char *str, **strp;
+ size_t max, i;
+ uint32_t idx, id;
+
+ if (datap == NULL) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ if (mrp_tlv_pull_uint32(tlv, TAG_STRUCT, &id) < 0)
+ return -1;
+ else
+ id = mapped_type(id, idmap);
+
+ if (*idp) {
+ if (*idp != id) {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ else
+ *idp = id;
+
+ if ((t = lookup_type(id)) == NULL)
+ return -1;
+
+ if (*datap == NULL)
+ if ((*datap = alloc_chunk(chunks, t->size)) == NULL)
+ return -1;
+
+ for (i = 0, m = t->members; i < t->nmember; i++, m++) {
+ if (mrp_tlv_pull_uint32(tlv, TAG_MEMBER, &idx) < 0)
+ return -1;
+
+ v = *datap + m->any.offs;
+
+ if (m->any.layout == MRP_LAYOUT_INDIRECT) {
+ if ((v = allocate_indirect(chunks, v, m, idmap)) == NULL)
+ return -1;
+ }
+
+ switch (m->any.type) {
+ case MRP_TYPE_INT8:
+ case MRP_TYPE_UINT8:
+ case MRP_TYPE_INT16:
+ case MRP_TYPE_UINT16:
+ case MRP_TYPE_INT32:
+ case MRP_TYPE_UINT32:
+ case MRP_TYPE_INT64:
+ case MRP_TYPE_UINT64:
+ case MRP_TYPE_FLOAT:
+ case MRP_TYPE_DOUBLE:
+ case MRP_TYPE_BOOL:
+ if (decode_basic(tlv, chunks, m->any.type, v) < 0)
+ return -1;
+ break;
+
+ case MRP_TYPE_STRING:
+ if (m->any.layout == MRP_LAYOUT_INLINED) {
+ max = m->str.size;
+ str = v->str;
+ strp = &str;
+ }
+ else {
+ max = (size_t)-1;
+ strp = &v->strp;
+ }
+ if (mrp_tlv_pull_string(tlv, TAG_NONE, strp, max,
+ alloc_str_chunk, chunks) < 0)
+ return -1;
+ break;
+
+ case MRP_TYPE_BLOB: /* XXX TODO implement blobs */
+ return -1;
+
+ case MRP_TYPE_ARRAY:
+ if (decode_array(tlv, chunks, &v->ptr, &m->array,
+ *datap, t, idmap) < 0)
+ return -1;
+ break;
+
+ case MRP_TYPE_STRUCT:
+ id = m->strct.data_type.id;
+ if (decode_struct(tlv, chunks, &v->ptr, &id, idmap) < 0)
+ return -1;
+ break;
+
+ default:
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+int mrp_decode_native(void **bufp, size_t *sizep, void **datap, uint32_t *idp,
+ mrp_typemap_t *idmap)
+{
+ mrp_tlv_t tlv;
+ mrp_list_hook_t *chunks;
+ void *data;
+ size_t diff;
+
+ chunks = NULL;
+ data = NULL;
+
+ if (mrp_tlv_setup_read(&tlv, *bufp, *sizep) < 0)
+ return -1;
+
+ if (decode_struct(&tlv, &chunks, &data, idp, idmap) == 0) {
+ diff = mrp_tlv_offset(&tlv);
+
+ if (diff <= *sizep) {
+ *bufp += diff;
+ *sizep -= diff;
+ *datap = data;
+
+ return 0;
+ }
+ }
+
+ free_chunks(chunks);
+
+ return -1;
+}
+
+
+void mrp_free_native(void *data, uint32_t id)
+{
+ mrp_list_hook_t *chunks;
+
+ MRP_UNUSED(id);
+
+ if (data != NULL) {
+ chunks = ((void *)data) - MRP_OFFSET(chunk_t, data);
+ free_chunks(chunks);
+ }
+}
+
+
+#define INDENT(_level, _fmt) "%*.*s"_fmt, _level * 4, _level * 4, ""
+
+#define PRINT(_l, _p, _size, fmt, args...) do { \
+ ssize_t _n; \
+ _n = snprintf((_p), (_size), INDENT(_l, fmt), ## args); \
+ if (_n >= (ssize_t)(_size)) \
+ return -1; \
+ (_p) += _n; \
+ (_size) -= _n; \
+ } while (0)
+
+
+static int print_basic(int level, char **bufp, size_t *sizep, int type,
+ const char *name, mrp_value_t *v)
+{
+#define NAME name ? name : "", name ? " = " : ""
+ char *p = *bufp;
+ size_t size = *sizep;
+
+ if (type >= MRP_TYPE_BLOB)
+ return -1;
+
+ switch (type) {
+ case MRP_TYPE_INT8:
+ PRINT(level, p, size, "%s%s%d\n", NAME, v->s8);
+ break;
+ case MRP_TYPE_UINT8:
+ PRINT(level, p, size, "%s%s%u\n", NAME, v->u8);
+ break;
+
+ case MRP_TYPE_INT16:
+ PRINT(level, p, size, "%s%s%d\n", NAME, v->s16);
+ break;
+ case MRP_TYPE_UINT16:
+ PRINT(level, p, size, "%s%s%u\n", NAME, v->u16);
+ break;
+
+ case MRP_TYPE_INT32:
+ PRINT(level, p, size, "%s%s%d\n", NAME, v->s32);
+ break;
+ case MRP_TYPE_UINT32:
+ PRINT(level, p, size, "%s%s%u\n", NAME, v->u32);
+ break;
+
+ case MRP_TYPE_INT64:
+ PRINT(level, p, size, "%s%s%lld\n", NAME, (long long)v->s64);
+ break;
+ case MRP_TYPE_UINT64:
+ PRINT(level, p, size, "%s%s%llu\n", NAME,
+ (unsigned long long)v->s64);
+ break;
+
+ case MRP_TYPE_FLOAT:
+ PRINT(level, p, size, "%s%s%f\n", NAME, v->flt);
+ break;
+ case MRP_TYPE_DOUBLE:
+ PRINT(level, p, size, "%s%s%f\n", NAME, v->dbl);
+ break;
+
+ case MRP_TYPE_BOOL:
+ PRINT(level, p, size, "%s%s%s\n", NAME,
+ v->bln ? "<true>" : "<false>");
+ break;
+
+ case MRP_TYPE_STRING:
+ PRINT(level, p, size, "%s%s%s\n", NAME,
+ v->str ? v->str : "<null>");
+ break;
+ }
+
+ *bufp = p;
+ *sizep = size;
+
+ return 0;
+
+#undef NAME
+}
+
+
+static int print_array(char **bufp, size_t *sizep, int level,
+ void *arrp, mrp_native_array_t *a, size_t nelem,
+ size_t elem_size)
+{
+ mrp_native_type_t *et;
+ mrp_value_t *v;
+ void *elem;
+ size_t i;
+ char *p;
+ size_t size;
+
+ p = *bufp;
+ size = *sizep;
+
+ if ((et = lookup_type(a->elem.id)) == NULL)
+ return -1;
+
+ PRINT(level, p, size, "%s = [%s", a->name, nelem == 0 ? "]" : "\n");
+ level++;
+
+ for (i = 0, elem = arrp; i < nelem; i++, elem += elem_size) {
+ v = elem;
+
+ switch (et->id) {
+ case MRP_TYPE_INT8:
+ case MRP_TYPE_UINT8:
+ case MRP_TYPE_INT16:
+ case MRP_TYPE_UINT16:
+ case MRP_TYPE_INT32:
+ case MRP_TYPE_UINT32:
+ case MRP_TYPE_INT64:
+ case MRP_TYPE_UINT64:
+ case MRP_TYPE_FLOAT:
+ case MRP_TYPE_DOUBLE:
+ case MRP_TYPE_BOOL:
+ case MRP_TYPE_STRING:
+ if (print_basic(level, &p, &size, et->id, NULL, v) < 0)
+ return -1;
+ break;
+
+ case MRP_TYPE_BLOB:
+ PRINT(level, p, size, "<blob>\n");
+ break;
+
+ case MRP_TYPE_ARRAY:
+ return -1;
+
+ default:
+ /* an MRP_TYPE_STRUCT */
+ if (print_struct(&p, &size, level, elem, et) < 0)
+ return -1;
+ break;
+ }
+ }
+
+ level--;
+ PRINT(level, p, size, "%s\n", nelem == 0 ? "" : "]");
+
+ *bufp = p;
+ *sizep = size;
+
+ return 0;
+}
+
+
+static int print_struct(char **bufp, size_t *sizep, int level,
+ void *data, mrp_native_type_t *t)
+{
+ mrp_native_member_t *m;
+ mrp_native_type_t *mt;
+ mrp_value_t *v;
+ uint32_t idx;
+ size_t esize, nelem;
+ char *p;
+ size_t size;
+
+ if (data == NULL) {
+ **bufp = '\0';
+
+ return 0;
+ }
+
+ if (t == NULL)
+ return -1;
+
+ p = *bufp;
+ size = *sizep;
+ PRINT(level, p, size, "{\n");
+ level++;
+
+ for (idx = 0, m = t->members; idx < t->nmember; idx++, m++) {
+ if (m->any.layout == MRP_LAYOUT_INDIRECT)
+ v = *(void **)(data + m->any.offs);
+ else
+ v = data + m->any.offs;
+
+ switch (m->any.type) {
+ case MRP_TYPE_INT8:
+ case MRP_TYPE_UINT8:
+ case MRP_TYPE_INT16:
+ case MRP_TYPE_UINT16:
+ case MRP_TYPE_INT32:
+ case MRP_TYPE_UINT32:
+ case MRP_TYPE_INT64:
+ case MRP_TYPE_UINT64:
+ case MRP_TYPE_FLOAT:
+ case MRP_TYPE_DOUBLE:
+ case MRP_TYPE_BOOL:
+ case MRP_TYPE_STRING:
+ if (print_basic(level, &p, &size, m->any.type, m->any.name, v) < 0)
+ return -1;
+ break;
+
+ case MRP_TYPE_BLOB: /* XXX TODO implement blobs */
+ PRINT(level, p, size, "%s = <blob>\n", m->any.name);
+ break;
+
+ case MRP_TYPE_ARRAY:
+ if (get_array_size(data, t, v->ptr, &m->array, &nelem, &esize) < 0)
+ return -1;
+ if (print_array(&p, &size, level, v->ptr, &m->array,
+ nelem, esize) < 0)
+ return -1;
+ break;
+
+ case MRP_TYPE_STRUCT:
+ if ((mt = lookup_type(m->strct.data_type.id)) == NULL)
+ return -1;
+ if (print_struct(&p, &size, level, v->ptr, mt) < 0)
+ return -1;
+ break;
+
+ default:
+ return -1;
+ }
+ }
+
+ level--;
+ PRINT(level, p, size, "}\n");
+
+ *bufp = p;
+ *sizep = size;
+
+ return 0;
+}
+
+
+ssize_t mrp_print_native(char *buf, size_t size, void *data, uint32_t id)
+{
+ mrp_native_type_t *t;
+ char *p;
+
+ p = buf;
+
+ if (id < MRP_TYPE_STRUCT || (t = lookup_type(id)) == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (print_struct(&p, &size, 0, data, t) == 0)
+ return (ssize_t)(p - buf);
+ else
+ return -1;
+}
+
+
+static inline size_t chunk_size(size_t size)
+{
+ return MRP_OFFSET(chunk_t, data[size]);
+}
+
+
+static void *alloc_chunk(mrp_list_hook_t **chunks, size_t size)
+{
+ chunk_t *chunk;
+
+ if (size == 0)
+ return NULL;
+
+ if (*chunks == NULL) {
+ if ((*chunks = mrp_allocz(sizeof(*chunks))) == NULL)
+ return NULL;
+ else
+ mrp_list_init(*chunks);
+ }
+
+ if ((chunk = mrp_allocz(chunk_size(size))) == NULL)
+ return NULL;
+
+ mrp_list_init(&chunk->hook);
+ mrp_list_append(*chunks, &chunk->hook);
+
+ return &chunk->data[0];
+}
+
+
+static void free_chunks(mrp_list_hook_t *chunks)
+{
+ mrp_list_hook_t *p, *n;
+
+ if (chunks != NULL) {
+ mrp_list_foreach(chunks, p, n) {
+ mrp_list_delete(p);
+
+ if (p != chunks)
+ mrp_free(p);
+ }
+
+ mrp_free(chunks);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2012, 2013, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MURPHY_COMMON_NATIVE_TYPES_H__
+#define __MURPHY_COMMON_NATIVE_TYPES_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <murphy/common/macros.h>
+#include <murphy/common/list.h>
+
+MRP_CDECL_BEGIN
+
+#define MRP_INVALID_TYPE ((uint32_t)-1)
+
+
+/**
+ * pre-defined native type ids
+ */
+
+typedef enum {
+ MRP_TYPE_UNKNOWN = 0,
+ MRP_TYPE_INT8,
+ MRP_TYPE_UINT8,
+ MRP_TYPE_INT16,
+ MRP_TYPE_UINT16,
+ MRP_TYPE_INT32,
+ MRP_TYPE_UINT32,
+ MRP_TYPE_INT64,
+ MRP_TYPE_UINT64,
+ MRP_TYPE_FLOAT,
+ MRP_TYPE_DOUBLE,
+ MRP_TYPE_BOOL,
+ MRP_TYPE_STRING,
+ MRP_TYPE_BLOB,
+ MRP_TYPE_ARRAY,
+ MRP_TYPE_STRUCT,
+ MRP_TYPE_MAX
+} mrp_type_t;
+
+
+/**
+ * data type values
+ */
+
+typedef union {
+ int8_t s8;
+ int8_t *s8p;
+ uint8_t u8;
+ uint8_t *u8p;
+ int16_t s16;
+ int16_t *s16p;
+ uint16_t u16;
+ uint16_t *u16p;
+ int32_t s32;
+ int32_t *s32p;
+ uint32_t u32;
+ uint32_t *u32p;
+ int64_t s64;
+ int64_t *s64p;
+ uint64_t u64;
+ uint64_t *u64p;
+ float flt;
+ float *fltp;
+ double dbl;
+ double *dblp;
+ bool bln;
+ bool *blnp;
+ void *blb;
+ char str[0];
+ char *strp;
+ void *ptr;
+ void **ptrp;
+} mrp_value_t;
+
+
+/**
+ * type id map (for transport-specific mapping of type ids)
+ */
+
+typedef struct {
+ uint32_t typeid; /* native type id */
+ uint32_t mapped; /* mapped type id */
+} mrp_typemap_t;
+
+
+/** Macro to initialize a typemap entry. */
+#define MRP_MAP_TYPE(_mapped_id, _type_id) \
+ (mrp_typemap_t) { .typeid = _type_id, .mapped = _mapped_id }
+
+/** Macro to set a typemap termination entry. */
+#define MRP_TYPEMAP_END \
+ (mrp_typemap_t) { MRP_INVALID_TYPE, MRP_INVALID_TYPE }
+
+/**
+ * type and member descriptors
+ */
+
+typedef enum {
+ MRP_LAYOUT_DEFAULT = 0, /* default, type-specific layout */
+ MRP_LAYOUT_INLINED, /* inlined/embedded layout */
+ MRP_LAYOUT_INDIRECT, /* indirect layout */
+} mrp_layout_t;
+
+#define MRP_NATIVE_COMMON_FIELDS /* fields common to all members */ \
+ char *name; /* name of this member */ \
+ uint32_t type; /* type id of this member */ \
+ size_t offs; /* offset from base pointer */ \
+ mrp_layout_t layout /* member layout */
+
+typedef struct {
+ MRP_NATIVE_COMMON_FIELDS; /* common fields to all members */
+} mrp_native_any_t;
+
+typedef struct { /* a blob member */
+ MRP_NATIVE_COMMON_FIELDS; /* common member fields */
+ union { /* size-indicating member */
+ char *name; /* name */
+ uint32_t idx; /* or index */
+ } size;
+} mrp_native_blob_t;
+
+typedef enum {
+ MRP_ARRAY_SIZE_EXPLICIT, /* explicitly sized array */
+ MRP_ARRAY_SIZE_GUARDED, /* sentinel-guarded array */
+ MRP_ARRAY_SIZE_FIXED, /* a fixed size array */
+} mrp_array_size_t;
+
+typedef struct {
+ MRP_NATIVE_COMMON_FIELDS; /* common member fields */
+ size_t size; /* inlined buffer size */
+} mrp_native_string_t;
+
+typedef struct { /* an array member */
+ MRP_NATIVE_COMMON_FIELDS; /* common member fields */
+ mrp_array_size_t kind; /* which kind of array */
+ union { /* contained element type */
+ char *name; /* name */
+ uint32_t id; /* or type id */
+ } elem;
+ union { /* size or guard member */
+ char *name; /* name */
+ uint32_t idx; /* or index */
+ size_t nelem; /* or number of elements */
+ } size;
+ mrp_value_t sentinel; /* sentinel value, if guarded */
+} mrp_native_array_t;
+
+typedef struct { /* member of type struct */
+ MRP_NATIVE_COMMON_FIELDS; /* common member fields */
+ union { /* struct type */
+ char *name; /* name */
+ uint32_t id; /* or type id */
+ } data_type;
+} mrp_native_struct_t;
+
+typedef union {
+ mrp_native_any_t any;
+ mrp_native_string_t str;
+ mrp_native_blob_t blob;
+ mrp_native_array_t array;
+ mrp_native_struct_t strct;
+} mrp_native_member_t;
+
+typedef struct {
+ char *name; /* name of this type */
+ uint32_t id; /* assigned id for this type */
+ size_t size; /* size of this type */
+ mrp_native_member_t *members; /* members of this type if any */
+ size_t nmember; /* number of members */
+ mrp_list_hook_t hook; /* to list of registered types */
+} mrp_native_type_t;
+
+
+/** Helper macro to initialize native member fields. */
+#define __MRP_MEMBER_INIT(_objtype, _member, _type) \
+ .name = #_member, \
+ .type = _type, \
+ .offs = MRP_OFFSET(_objtype, _member)
+
+/** Helper macro to declare a native member with a given type an layout. */
+#define __MRP_MEMBER(_objtype, _type, _member, _layout) \
+ { \
+ .any = { \
+ __MRP_MEMBER_INIT(_objtype, _member, _type), \
+ .layout = MRP_LAYOUT_##_layout, \
+ } \
+ }
+
+/** Declare an indirect string member of the native type. */
+#define MRP_INDIRECT_STRING(_objtype, _member, _size) \
+ __MRP_MEMBER(_objtype, _member, MRP_TYPE_STRING, INDIRECT)
+
+/** Declare an inlined string member of the native type. */
+#define MRP_INLINED_STRING(_objtype, _member, _size) \
+ { \
+ .str = { \
+ __MRP_MEMBER_INIT(_objtype, _member, MRP_TYPE_STRING), \
+ .layout = MRP_LAYOUT_INLINED, \
+ .size = _size, \
+ } \
+ }
+
+/** By default declare a string members indirect. */
+#define MRP_DEFAULT_STRING(_objtype, _member, _size) \
+ __MRP_MEMBER(_objtype, MRP_TYPE_STRING, _member, INDIRECT)
+
+/** Declare an explicitly sized array member of the native typet. */
+#define MRP_SIZED_ARRAY(_objtype, _member, _layout, _type, _size) \
+ { \
+ .array = { \
+ __MRP_MEMBER_INIT(_objtype, _member, MRP_TYPE_ARRAY), \
+ .layout = MRP_LAYOUT_##_layout, \
+ .kind = MRP_ARRAY_SIZE_EXPLICIT, \
+ .elem = { .name = #_type, }, \
+ .size = { .name = #_size, }, \
+ } \
+ }
+
+/** Declare a sentinel-guarded array member of the native type. */
+#define MRP_GUARDED_ARRAY(_objtype, _member, _layout, _type, _guard, \
+ ...) \
+ { \
+ .array = { \
+ __MRP_MEMBER_INIT(_objtype, _member, MRP_TYPE_ARRAY), \
+ .layout = MRP_LAYOUT_##_layout, \
+ .kind = MRP_ARRAY_SIZE_GUARDED, \
+ .elem = { .name = #_type, }, \
+ .size = { .name = #_guard, }, \
+ .sentinel = { __VA_ARGS__ }, \
+ } \
+ }
+
+/** Declare a fixed array member of the native type. */
+#define MRP_FIXED_ARRAY(_objtype, _member, _layout, _type) \
+ { \
+ .array = { \
+ __MRP_MEMBER_INIT(_objtype, _member, MRP_TYPE_ARRAY), \
+ .layout = MRP_LAYOUT_##_layout, \
+ .kind = MRP_ARRAY_SIZE_FIXED, \
+ .elem = { .name = #_type, }, \
+ .size = { \
+ .nelem = MRP_ARRAY_SIZE(((_objtype *)0x0)->_member) \
+ }, \
+ } \
+ }
+
+/** Declare a struct member of the native type. */
+#define MRP_STRUCT(_objtype, _member, _layout, _type) \
+ { \
+ .strct = { \
+ __MRP_MEMBER_INIT(_objtype, _member, MRP_TYPE_STRUCT), \
+ .data_type = { .name = #_type }, \
+ } \
+ }
+
+/** Macros for declaring basic members of the native type. */
+#define MRP_INT8(_ot, _m, _l) __MRP_MEMBER(_ot, MRP_TYPE_INT8 , _m, _l)
+#define MRP_UINT8(_ot, _m, _l) __MRP_MEMBER(_ot, MRP_TYPE_UINT8 , _m, _l)
+#define MRP_INT16(_ot, _m, _l) __MRP_MEMBER(_ot, MRP_TYPE_INT16 , _m, _l)
+#define MRP_UINT16(_ot, _m, _l) __MRP_MEMBER(_ot, MRP_TYPE_UINT16, _m, _l)
+#define MRP_INT32(_ot, _m, _l) __MRP_MEMBER(_ot, MRP_TYPE_INT32 , _m, _l)
+#define MRP_UINT32(_ot, _m, _l) __MRP_MEMBER(_ot, MRP_TYPE_UINT32, _m, _l)
+#define MRP_INT64(_ot, _m, _l) __MRP_MEMBER(_ot, MRP_TYPE_INT64 , _m, _l)
+#define MRP_UINT64(_ot, _m, _l) __MRP_MEMBER(_ot, MRP_TYPE_UINT64, _m, _l)
+#define MRP_FLOAT(_ot, _m, _l) __MRP_MEMBER(_ot, MRP_TYPE_FLOAT , _m, _l)
+#define MRP_DOUBLE(_ot, _m, _l) __MRP_MEMBER(_ot, MRP_TYPE_DOUBLE, _m, _l)
+#define MRP_BOOL(_ot, _m, _l) __MRP_MEMBER(_ot, MRP_TYPE_BOOL , _m, _l)
+
+/** Macro for declaring string members of the native type. */
+#define MRP_STRING(_objtype, _member, _layout) \
+ MRP_##_layout##_STRING(_objtype, _member, \
+ sizeof(((_objtype *)0x0)->_member))
+
+/** Macro for declaring array members of the native type. */
+#define MRP_ARRAY(_objtype, _member, _layout, _kind, ...) \
+ MRP_##_kind##_ARRAY(_objtype, _member, _layout, __VA_ARGS__)
+
+/** Macro to declare a native type. */
+#define MRP_NATIVE_TYPE(_var, _type, ...) \
+ mrp_native_member_t _var##_members[] = { \
+ __VA_ARGS__ \
+ }; \
+ mrp_native_type_t _var = { \
+ .id = -1, \
+ .name = #_type, \
+ .size = sizeof(_type), \
+ .members = _var##_members, \
+ .nmember = MRP_ARRAY_SIZE(_var##_members), \
+ .hook = { NULL, NULL }, \
+ }
+
+/** Declare and register the given native type. */
+uint32_t mrp_register_native(mrp_native_type_t *type);
+
+/** Look up the type id of the given native type name. */
+uint32_t mrp_native_id(const char *type_name);
+
+/** Encode data of the given native type. */
+int mrp_encode_native(void *data, uint32_t id, size_t reserve, void **bufp,
+ size_t *sizep, mrp_typemap_t *idmap);
+
+/** Decode data of (the given) native type (if specified). */
+int mrp_decode_native(void **bufp, size_t *sizep, void **datap, uint32_t *idp,
+ mrp_typemap_t *idmap);
+
+/** Free data of the given native type, obtained from mrp_decode_native. */
+void mrp_free_native(void *data, uint32_t id);
+
+/** Print data of the given native type. */
+ssize_t mrp_print_native(char *buf, size_t size, void *data, uint32_t id);
+
+MRP_CDECL_END
+
+#endif /* __MURPHY_COMMON_NATIVE_TYPES_H__ */
AM_CFLAGS = $(WARNING_CFLAGS) -I$(top_builddir)
noinst_PROGRAMS = mm-test hash-test msg-test transport-test \
- internal-transport-test process-watch-test
+ internal-transport-test process-watch-test native-test
if DBUS_ENABLED
noinst_PROGRAMS += mainloop-test dbus-test
endif
msg_test_CFLAGS = $(AM_CFLAGS)
msg_test_LDADD = ../../libmurphy-common.la
+# native type test
+native_test_SOURCES = native-test.c
+native_test_CFLAGS = $(AM_CFLAGS)
+native_test_LDADD = ../../libmurphy-common.la
+
# transport test
transport_test_SOURCES = transport-test.c
transport_test_CFLAGS = $(AM_CFLAGS)
dbus_test_LDADD = ../../libmurphy-dbus.la ../../libmurphy-common.la $(DBUS_LIBS)
endif
-## databuf test
-#databuf_test_SOURCES = databuf-test.c
-#databuf_test_CFLAGS = $(AM_CFLAGS)
-#databuf_test_LDADD = ../../libmurphy-common.la
-
# fragbuf test
fragbuf_test_SOURCES = fragbuf-test.c
fragbuf_test_CFLAGS = $(AM_CFLAGS)
--- /dev/null
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <murphy/common/macros.h>
+#include <murphy/common/debug.h>
+#include <murphy/common/log.h>
+#include <murphy/common/native-types.h>
+
+
+typedef enum {
+ MUSIC,
+ MOVIE,
+ BOOK,
+ PAINTING,
+} art_type_t;
+
+
+typedef struct {
+ art_type_t type;
+ char *artist;
+ char *title;
+ uint16_t year;
+ char *location;
+ double price;
+} art_t;
+
+
+typedef enum {
+ LEFT = 0,
+ RIGHT,
+ BOTH
+} hand_t;
+
+
+typedef enum {
+ MALE = 0,
+ FEMALE = 1,
+} gender_t;
+
+
+typedef struct {
+ char *name;
+ gender_t gender;
+ uint16_t age;
+ uint16_t height;
+ float weight;
+ char nationality[32];
+ hand_t hand;
+ bool glasses;
+ art_t *favourites;
+ uint32_t nfavourite;
+} person_t;
+
+
+typedef struct {
+ person_t *father;
+ person_t *mother;
+ person_t *children;
+} family_t;
+
+
+art_t paps_favourites[] = {
+ {
+ BOOK ,
+ "Douglas Adams", "Dirk Gently's Holistic Detective Agency",
+ 1987, "bookshelf", 9.5
+ },
+ {
+ MUSIC,
+ "Megadeth", "Sweating Bullets",
+ 1992, "pocket", 12.5
+ },
+ {
+ MUSIC,
+ "Sentenced", "Noose",
+ 1996, "phone", 12
+ },
+ {
+ MOVIE,
+ "Bananas", "Woody Allen",
+ 1971, "PVR", 20.5
+ }
+};
+
+
+person_t pap = {
+ .name = "Pap",
+ .gender = MALE,
+ .age = 30,
+ .height = 180,
+ .weight = 84.5,
+ .nationality = "martian",
+ .hand = RIGHT,
+ .glasses = false,
+ .favourites = paps_favourites,
+ .nfavourite = MRP_ARRAY_SIZE(paps_favourites),
+};
+
+
+art_t moms_favourites[] = {
+ {
+ BOOK ,
+ "Douglas Adams", "THHGTTG",
+ 1982, "bookshelf", 11.8
+ },
+ {
+ MUSIC,
+ "Megadeth", "Sweating Bullets",
+ 1992, "pocket", 12.5
+ },
+ {
+ MOVIE,
+ "Hottie Chick", "GGW-II",
+ 1996, "PVR", 0.5
+ },
+ {
+ BOOK ,
+ "Douglas Adams", "The Long Dark Tea-Time of the Soul",
+ 1988, "Kindle Touch", 8.50
+ }
+};
+
+
+person_t mom = {
+ .name = "Mom",
+ .gender = FEMALE,
+ .age = 28,
+ .height = 165,
+ .weight = 57.8,
+ .nationality = "venusian",
+ .hand = LEFT,
+ .glasses = true,
+ .favourites = moms_favourites,
+ .nfavourite = MRP_ARRAY_SIZE(moms_favourites),
+};
+
+
+person_t tom_dick_and_harry[] = {
+ {
+ .name = "Tom",
+ .gender = MALE,
+ .age = 10,
+ .height = 135,
+ .weight = 40.5,
+ .nationality = "UFO",
+ .hand = BOTH,
+ .glasses = false,
+ .favourites = NULL,
+ .nfavourite = 0,
+ },
+ {
+ .name = "Dick",
+ .gender = MALE,
+ .age = 12,
+ .height = 145,
+ .weight = 45.5,
+ .nationality = "UFO",
+ .hand = RIGHT,
+ .glasses = true,
+ .favourites = paps_favourites + 1,
+ .nfavourite = MRP_ARRAY_SIZE(paps_favourites) - 2,
+ },
+ {
+ .name = "Harry",
+ .gender = MALE,
+ .age = 14,
+ .height = 165,
+ .weight = 60.5,
+ .nationality = "UFO",
+ .hand = LEFT,
+ .glasses = false,
+ .favourites = moms_favourites + 1,
+ .nfavourite = MRP_ARRAY_SIZE(moms_favourites) - 2,
+ },
+ {
+ .name = NULL,
+ },
+};
+
+
+family_t family = { &pap, &mom, &tom_dick_and_harry[0] };
+
+
+int main(int argc, char *argv[])
+{
+ MRP_NATIVE_TYPE(art_type, art_t,
+ MRP_UINT32(art_t, type , DEFAULT),
+ MRP_STRING(art_t, artist , DEFAULT),
+ MRP_STRING(art_t, title , DEFAULT),
+ MRP_UINT16(art_t, year , DEFAULT),
+ MRP_STRING(art_t, location, DEFAULT),
+ MRP_DOUBLE(art_t, price , DEFAULT));
+ MRP_NATIVE_TYPE(person_type, person_t,
+ MRP_STRING(person_t, name , DEFAULT),
+ MRP_UINT32(person_t, gender , DEFAULT),
+ MRP_UINT16(person_t, age , DEFAULT),
+ MRP_UINT16(person_t, height , DEFAULT),
+ MRP_FLOAT (person_t, weight , DEFAULT),
+ MRP_STRING(person_t, nationality, INLINED),
+ MRP_UINT32(person_t, hand , DEFAULT),
+ MRP_BOOL (person_t, glasses , DEFAULT),
+ MRP_ARRAY (person_t, favourites , DEFAULT, SIZED,
+ art_t, nfavourite),
+ MRP_UINT32(person_t, nfavourite , DEFAULT));
+ MRP_NATIVE_TYPE(family_type, family_t,
+ MRP_STRUCT(family_t, father , DEFAULT, person_t),
+ MRP_STRUCT(family_t, mother , DEFAULT, person_t),
+ MRP_ARRAY (family_t, children, DEFAULT, GUARDED,
+ person_t, name, .strp = NULL));
+ mrp_typemap_t map[4];
+
+ uint32_t art_type_id, person_type_id, family_type_id;
+ void *ebuf;
+ size_t esize;
+ int fd;
+ void *dbuf;
+ family_t *decoded;
+ char dump[16 * 1024];
+
+ MRP_UNUSED(argc);
+ MRP_UNUSED(argv);
+
+ mrp_log_set_mask(MRP_LOG_UPTO(MRP_LOG_INFO));
+
+ art_type_id = mrp_register_native(&art_type);
+
+ if (art_type_id == MRP_INVALID_TYPE)
+ mrp_log_error("Failed to register art_t type.");
+ else
+ mrp_log_info("Type art_t sucessfully registered.");
+
+ person_type_id = mrp_register_native(&person_type);
+
+ if (person_type_id == MRP_INVALID_TYPE)
+ mrp_log_error("Failed to register person_t type.");
+ else
+ mrp_log_info("Type person_t sucessfully registered.");
+
+ family_type_id = mrp_register_native(&family_type);
+
+ if (family_type_id == MRP_INVALID_TYPE)
+ mrp_log_error("Failed to register family_t type.");
+ else
+ mrp_log_info("Type family_t sucessfully registered.");
+
+ ebuf = NULL;
+
+ map[0] = MRP_MAP_TYPE(1, art_type_id );
+ map[1] = MRP_MAP_TYPE(2, person_type_id);
+ map[2] = MRP_MAP_TYPE(3, family_type_id);
+ map[3] = MRP_TYPEMAP_END;
+
+ if (mrp_encode_native(&family, family_type_id, 0, &ebuf, &esize, map) < 0) {
+ mrp_log_error("Failed to encode test data.");
+ exit(1);
+ }
+ else
+ mrp_log_info("Test data successfully encoded (%zd bytes).", esize);
+
+ if ((fd = open("type-test.encoded",
+ O_CREAT | O_TRUNC | O_WRONLY, 0644)) >= 0) {
+ if (write(fd, ebuf, esize) != (ssize_t)esize)
+ mrp_log_error("Failed to write encoded data.");
+ close(fd);
+ }
+
+ if (mrp_decode_native(&ebuf, &esize, &dbuf, &family_type_id, map) < 0) {
+ mrp_log_error("Failed to decode test data.");
+ exit(1);
+ }
+ else
+ mrp_log_info("Test data sucessfully decoded.");
+
+ decoded = dbuf;
+
+ if (mrp_print_native(dump, sizeof(dump), decoded, family_type_id) >= 0)
+ mrp_log_info("dump of decoded data: %s", dump);
+ else
+ mrp_log_error("Failed to dump decoded data.");
+
+ mrp_free_native(dbuf, family_type_id);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2012, 2013, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+
+#include <murphy/common/macros.h>
+#include <murphy/common/debug.h>
+#include <murphy/common/log.h>
+#include <murphy/common/mm.h>
+#include <murphy/common/tlv.h>
+
+#define TLV_MIN_PREALLOC 4096
+#define TLV_MIN_CHUNK 64
+
+int mrp_tlv_setup_write(mrp_tlv_t *tlv, size_t prealloc)
+{
+ if (prealloc < TLV_MIN_PREALLOC)
+ prealloc = TLV_MIN_PREALLOC;
+
+ if ((tlv->buf = mrp_allocz(prealloc)) == NULL)
+ return -1;
+
+ tlv->size = prealloc;
+ tlv->p = tlv->buf;
+ tlv->write = 1;
+
+ return 0;
+}
+
+
+static inline size_t tlv_space(mrp_tlv_t *tlv)
+{
+ if (tlv->size > 0 && tlv->write)
+ return tlv->size - (tlv->p - tlv->buf);
+ else
+ return 0;
+}
+
+
+static inline size_t tlv_data(mrp_tlv_t *tlv)
+{
+ if (!tlv->write)
+ return tlv->size - (tlv->p - tlv->buf);
+ else
+ return tlv->p - tlv->buf;
+}
+
+
+int mrp_tlv_ensure(mrp_tlv_t *tlv, size_t size)
+{
+ size_t left, diff;
+
+ if (!tlv->write)
+ return -1;
+
+ if ((left = tlv_space(tlv)) < size) {
+ diff = size - left;
+
+ if (diff < TLV_MIN_CHUNK)
+ diff = TLV_MIN_CHUNK;
+
+ tlv->p -= (ptrdiff_t)tlv->buf;
+
+ if (mrp_realloc(tlv->buf, tlv->size + diff) == NULL) {
+ tlv->p += (ptrdiff_t)tlv->buf;
+
+ return -1;
+ }
+
+ memset(tlv->buf + tlv->size, 0, diff);
+
+ tlv->size += diff;
+ tlv->p += (ptrdiff_t)tlv->buf;
+ }
+
+ return 0;
+}
+
+
+void *mrp_tlv_reserve(mrp_tlv_t *tlv, size_t size, int align)
+{
+ void *reserved;
+ ptrdiff_t offs, pad;
+ size_t len;
+
+ offs = tlv->p - tlv->buf;
+
+ if (align > 1)
+ pad = align - (offs & (align - 1));
+ else
+ pad = 0;
+
+ len = size + pad;
+
+ if (mrp_tlv_ensure(tlv, len) < 0)
+ return NULL;
+
+ if (pad)
+ memset(tlv->p, 0, pad);
+
+ reserved = tlv->p + pad;
+ tlv->p += len;
+
+ return reserved;
+}
+
+
+int mrp_tlv_setup_read(mrp_tlv_t *tlv, void *buf, size_t size)
+{
+ tlv->buf = tlv->p = buf;
+ tlv->size = size;
+ tlv->write = 0;
+
+ return 0;
+}
+
+
+static void *tlv_consume(mrp_tlv_t *tlv, size_t size)
+{
+ char *p;
+
+ if (tlv_data(tlv) < size)
+ return NULL;
+
+ p = tlv->p;
+ tlv->p += size;
+
+ return p;
+}
+
+
+void mrp_tlv_trim(mrp_tlv_t *tlv)
+{
+ size_t left;
+
+ if (!tlv->write)
+ return;
+
+ if ((left = tlv_space(tlv)) == 0)
+ return;
+
+ tlv->p -= (ptrdiff_t)tlv->buf;
+
+ if (mrp_realloc(tlv->buf, tlv->size - left) != NULL) {
+ tlv->size -= left;
+ tlv->p += (ptrdiff_t)tlv->buf;
+ }
+}
+
+
+size_t mrp_tlv_offset(mrp_tlv_t *tlv)
+{
+ return (size_t)(tlv->p - tlv->buf);
+}
+
+
+void mrp_tlv_cleanup(mrp_tlv_t *tlv)
+{
+ if (tlv->write)
+ mrp_free(tlv->buf);
+
+ tlv->buf = tlv->p = NULL;
+ tlv->size = 0;
+}
+
+
+void mrp_tlv_steal(mrp_tlv_t *tlv, void **bufp, size_t *sizep)
+{
+ if (tlv->write) {
+ *bufp = tlv->buf;
+ *sizep = tlv->p - tlv->buf;
+
+ tlv->buf = tlv->p = NULL;
+ tlv->size = 0;
+ }
+ else {
+ *bufp = NULL;
+ *sizep = 0;
+ }
+}
+
+
+static inline int push_tag(mrp_tlv_t *tlv, uint32_t tag)
+{
+ uint32_t *tagp;
+
+ if (tag) {
+ if ((tagp = mrp_tlv_reserve(tlv, sizeof(*tagp), 1)) == NULL)
+ return -1;
+ else
+ *tagp = htobe32(tag);
+ }
+
+ return 0;
+}
+
+
+int mrp_tlv_push_int8(mrp_tlv_t *tlv, uint32_t tag, int8_t v)
+{
+ int8_t *p;
+
+ if (push_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = mrp_tlv_reserve(tlv, sizeof(*p), 1)) != NULL) {
+ *p = v;
+
+ return 0;
+ }
+
+ return -1;
+}
+
+
+int mrp_tlv_push_uint8(mrp_tlv_t *tlv, uint32_t tag, uint8_t v)
+{
+ uint8_t *p;
+
+ if (push_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = mrp_tlv_reserve(tlv, sizeof(*p), 1)) != NULL) {
+ *p = v;
+
+ return 0;
+ }
+
+ return -1;
+}
+
+
+int mrp_tlv_push_int16(mrp_tlv_t *tlv, uint32_t tag, int16_t v)
+{
+ int16_t *p;
+
+ if (push_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = mrp_tlv_reserve(tlv, sizeof(*p), 1)) != NULL) {
+ *p = htobe16(v);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+
+int mrp_tlv_push_uint16(mrp_tlv_t *tlv, uint32_t tag, uint16_t v)
+{
+ uint16_t *p;
+
+ if (push_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = mrp_tlv_reserve(tlv, sizeof(*p), 1)) != NULL) {
+ *p = htobe16(v);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+
+int mrp_tlv_push_int32(mrp_tlv_t *tlv, uint32_t tag, int32_t v)
+{
+ int32_t *p;
+
+ if (push_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = mrp_tlv_reserve(tlv, sizeof(*p), 1)) != NULL) {
+ *p = htobe32(v);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+
+int mrp_tlv_push_uint32(mrp_tlv_t *tlv, uint32_t tag, uint32_t v)
+{
+ uint32_t *p;
+
+ if (push_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = mrp_tlv_reserve(tlv, sizeof(*p), 1)) != NULL) {
+ *p = htobe32(v);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+
+int mrp_tlv_push_int64(mrp_tlv_t *tlv, uint32_t tag, int64_t v)
+{
+ int64_t *p;
+
+ if (push_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = mrp_tlv_reserve(tlv, sizeof(*p), 1)) != NULL) {
+ *p = htobe64(v);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+
+int mrp_tlv_push_uint64(mrp_tlv_t *tlv, uint32_t tag, uint64_t v)
+{
+ uint64_t *p;
+
+ if (push_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = mrp_tlv_reserve(tlv, sizeof(*p), 1)) != NULL) {
+ *p = htobe64(v);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+
+int mrp_tlv_push_float(mrp_tlv_t *tlv, uint32_t tag, float v)
+{
+ float *p;
+
+ if (push_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = mrp_tlv_reserve(tlv, sizeof(*p), 1)) != NULL) {
+ *p = v;
+
+ return 0;
+ }
+
+ return -1;
+}
+
+
+int mrp_tlv_push_double(mrp_tlv_t *tlv, uint32_t tag, double v)
+{
+ double *p;
+
+ if (push_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = mrp_tlv_reserve(tlv, sizeof(*p), 1)) != NULL) {
+ *p = v;
+
+ return 0;
+ }
+
+ return -1;
+}
+
+
+int mrp_tlv_push_bool(mrp_tlv_t *tlv, uint32_t tag, bool v)
+{
+ bool *p;
+
+ if (push_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = mrp_tlv_reserve(tlv, sizeof(*p), 1)) != NULL) {
+ *p = v;
+
+ return 0;
+ }
+
+ return -1;
+}
+
+
+int mrp_tlv_push_string(mrp_tlv_t *tlv, uint32_t tag, const char *str)
+{
+ uint32_t *sizep;
+ char *strp;
+ size_t len = str ? strlen(str) + 1 : 0;
+
+ if (push_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((sizep = mrp_tlv_reserve(tlv, sizeof(*sizep), 1)) == NULL)
+ return -1;
+
+ *sizep = htobe32((uint32_t)len);
+
+ if (len > 0) {
+ if ((strp = mrp_tlv_reserve(tlv, len, 1)) == NULL)
+ return -1;
+
+ strcpy(strp, str);
+ }
+
+ return 0;
+}
+
+
+int pull_tag(mrp_tlv_t *tlv, uint32_t tag)
+{
+ uint32_t *tagp;
+
+ if (tag) {
+ if ((tagp = tlv_consume(tlv, sizeof(*tagp))) == NULL)
+ return -1;
+
+ if (be32toh(*tagp) != tag)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int mrp_tlv_pull_int8(mrp_tlv_t *tlv, uint32_t tag, int8_t *v)
+{
+ int8_t *p;
+
+ if (pull_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = tlv_consume(tlv, sizeof(*p))) == NULL)
+ return -1;
+
+ *v = *p;
+
+ return 0;
+}
+
+
+int mrp_tlv_pull_uint8(mrp_tlv_t *tlv, uint32_t tag, uint8_t *v)
+{
+ uint8_t *p;
+
+ if (pull_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = tlv_consume(tlv, sizeof(*p))) == NULL)
+ return -1;
+
+ *v = *p;
+
+ return 0;
+}
+
+
+int mrp_tlv_pull_int16(mrp_tlv_t *tlv, uint32_t tag, int16_t *v)
+{
+ int16_t *p;
+
+ if (pull_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = tlv_consume(tlv, sizeof(*p))) == NULL)
+ return -1;
+
+ *v = be16toh(*p);
+
+ return 0;
+}
+
+
+int mrp_tlv_pull_uint16(mrp_tlv_t *tlv, uint32_t tag, uint16_t *v)
+{
+ uint16_t *p;
+
+ if (pull_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = tlv_consume(tlv, sizeof(*p))) == NULL)
+ return -1;
+
+ *v = be16toh(*p);
+
+ return 0;
+}
+
+
+int mrp_tlv_pull_int32(mrp_tlv_t *tlv, uint32_t tag, int32_t *v)
+{
+ int32_t *p;
+
+ if (pull_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = tlv_consume(tlv, sizeof(*p))) == NULL)
+ return -1;
+
+ *v = be32toh(*p);
+
+ return 0;
+}
+
+
+int mrp_tlv_pull_uint32(mrp_tlv_t *tlv, uint32_t tag, uint32_t *v)
+{
+ uint32_t *p;
+
+ if (pull_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = tlv_consume(tlv, sizeof(*p))) == NULL)
+ return -1;
+
+ *v = be32toh(*p);
+
+ return 0;
+}
+
+
+int mrp_tlv_pull_int64(mrp_tlv_t *tlv, uint32_t tag, int64_t *v)
+{
+ int64_t *p;
+
+ if (pull_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = tlv_consume(tlv, sizeof(*p))) == NULL)
+ return -1;
+
+ *v = be64toh(*p);
+
+ return 0;
+}
+
+
+int mrp_tlv_pull_uint64(mrp_tlv_t *tlv, uint32_t tag, uint64_t *v)
+{
+ uint64_t *p;
+
+ if (pull_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = tlv_consume(tlv, sizeof(*p))) == NULL)
+ return -1;
+
+ *v = be64toh(*p);
+
+ return 0;
+}
+
+
+int mrp_tlv_pull_float(mrp_tlv_t *tlv, uint32_t tag, float *v)
+{
+ float *p;
+
+ if (pull_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = tlv_consume(tlv, sizeof(*p))) == NULL)
+ return -1;
+
+ *v = *p;
+
+ return 0;
+}
+
+
+int mrp_tlv_pull_double(mrp_tlv_t *tlv, uint32_t tag, double *v)
+{
+ double *p;
+
+ if (pull_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = tlv_consume(tlv, sizeof(*p))) == NULL)
+ return -1;
+
+ *v = *p;
+
+ return 0;
+}
+
+
+int mrp_tlv_pull_bool(mrp_tlv_t *tlv, uint32_t tag, bool *v)
+{
+ bool *p;
+
+ if (pull_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((p = tlv_consume(tlv, sizeof(*p))) == NULL)
+ return -1;
+
+ *v = *p;
+
+ return 0;
+}
+
+
+int mrp_tlv_pull_string(mrp_tlv_t *tlv, uint32_t tag, char **v, size_t max,
+ void *(alloc)(size_t, void *), void *alloc_data)
+{
+ uint32_t *sizep, size;
+ char *str;
+
+ if (pull_tag(tlv, tag) < 0)
+ return -1;
+
+ if ((sizep = tlv_consume(tlv, sizeof(*sizep))) == NULL)
+ return -1;
+
+ size = be32toh(*sizep);
+
+ if (max != (size_t)-1 && max < size) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+
+ if (size > 0) {
+ if ((str = tlv_consume(tlv, size)) == NULL)
+ return -1;
+
+ if (*v == NULL)
+ if ((*v = alloc(size, alloc_data)) == NULL)
+ return -1;
+
+ strncpy(*v, str, size - 1);
+ (*v)[size - 1] = '\0';
+ }
+ else
+ *v = NULL;
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2012, 2013, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MRP_COMMON_TLV_H__
+#define __MRP_COMMON_TLV_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <murphy/common/macros.h>
+
+MRP_CDECL_BEGIN
+
+#define MRP_TLV_UNTAGGED 0
+
+/**
+ * a tagged-value-list encoding/decoding buffer
+ */
+
+typedef struct {
+ void *buf; /* actual data buffer */
+ size_t size; /* allocated buffer size */
+ void *p; /* encoding/decoding pointer */
+ int write : 1; /* whether set up for writing */
+} mrp_tlv_t;
+
+/** Set up the given TLV buffer for encoding. */
+int mrp_tlv_setup_write(mrp_tlv_t *tlv, size_t prealloc);
+
+/** Set up the given TLV buffer for decoding. */
+int mrp_tlv_setup_read(mrp_tlv_t *tlv, void *buf, size_t size);
+
+/** Clean up the given TLV buffer. */
+void mrp_tlv_cleanup(mrp_tlv_t *tlv);
+
+/** Ensure the given amount of space is available in the TLV buffer. */
+int mrp_tlv_ensure(mrp_tlv_t *tlv, size_t size);
+
+/** Reserve the given amount of buffer space from the TLV buffer. */
+void *mrp_tlv_reserve(mrp_tlv_t *tlv, size_t size, int align);
+
+/** Take ownership of the data buffer from the TLV buffer. */
+void mrp_tlv_steal(mrp_tlv_t *tlv, void **bufp, size_t *sizep);
+
+/** Trim the data buffer of the TLV buffer to current amount of data. */
+void mrp_tlv_trim(mrp_tlv_t *tlv);
+
+/** Get the current read/write offset from the TLV buffer. */
+size_t mrp_tlv_offset(mrp_tlv_t *tlv);
+
+/** Add an int8_t with an optional tag to the TLV buffer. */
+int mrp_tlv_push_int8(mrp_tlv_t *tlv, uint32_t tag, int8_t v);
+
+/** Add an uint8_t with an optional tag to the TLV buffer. */
+int mrp_tlv_push_uint8(mrp_tlv_t *tlv, uint32_t tag, uint8_t v);
+
+/** Add an int16_t with an optional tag to the TLV buffer. */
+int mrp_tlv_push_int16(mrp_tlv_t *tlv, uint32_t tag, int16_t v);
+
+/** Add an uint16_t with an optional tag to the TLV buffer. */
+int mrp_tlv_push_uint16(mrp_tlv_t *tlv, uint32_t tag, uint16_t v);
+
+/** Add an int32_t with an optional tag to the TLV buffer. */
+int mrp_tlv_push_int32(mrp_tlv_t *tlv, uint32_t tag, int32_t v);
+
+/** Add an uint32_t with an optional tag to the TLV buffer. */
+int mrp_tlv_push_uint32(mrp_tlv_t *tlv, uint32_t tag, uint32_t v);
+
+/** Add an int64_t with an optional tag to the TLV buffer. */
+int mrp_tlv_push_int64(mrp_tlv_t *tlv, uint32_t tag, int64_t v);
+
+/** Add an uint64_t with an optional tag to the TLV buffer. */
+int mrp_tlv_push_uint64(mrp_tlv_t *tlv, uint32_t tag, uint64_t v);
+
+/** Add an float with an optional tag to the TLV buffer. */
+int mrp_tlv_push_float(mrp_tlv_t *tlv, uint32_t tag, float v);
+
+/** Add an double with an optional tag to the TLV buffer. */
+int mrp_tlv_push_double(mrp_tlv_t *tlv, uint32_t tag, double v);
+
+/** Add a boolean with an optional tag to the TLV buffer. */
+int mrp_tlv_push_bool(mrp_tlv_t *tlv, uint32_t tag, bool v);
+
+/** Add a string with an optional tag to the TLV buffer. */
+int mrp_tlv_push_string(mrp_tlv_t *tlv, uint32_t tag, const char *str);
+
+
+int mrp_tlv_pull_int8(mrp_tlv_t *tlv, uint32_t tag, int8_t *v);
+int mrp_tlv_pull_uint8(mrp_tlv_t *tlv, uint32_t tag, uint8_t *v);
+int mrp_tlv_pull_int16(mrp_tlv_t *tlv, uint32_t tag, int16_t *v);
+int mrp_tlv_pull_uint16(mrp_tlv_t *tlv, uint32_t tag, uint16_t *v);
+int mrp_tlv_pull_int32(mrp_tlv_t *tlv, uint32_t tag, int32_t *v);
+int mrp_tlv_pull_uint32(mrp_tlv_t *tlv, uint32_t tag, uint32_t *v);
+int mrp_tlv_pull_int64(mrp_tlv_t *tlv, uint32_t tag, int64_t *v);
+int mrp_tlv_pull_uint64(mrp_tlv_t *tlv, uint32_t tag, uint64_t *v);
+int mrp_tlv_pull_float(mrp_tlv_t *tlv, uint32_t tag, float *v);
+int mrp_tlv_pull_double(mrp_tlv_t *tlv, uint32_t tag, double *v);
+int mrp_tlv_pull_bool(mrp_tlv_t *tlv, uint32_t tag, bool *v);
+int mrp_tlv_pull_string(mrp_tlv_t *tlv, uint32_t tag, char **v, size_t max,
+ void *(alloc)(size_t, void *), void *alloc_data);
+
+MRP_CDECL_END
+
+#endif /* __MRP_COMMON_TLV_H__ */