diff options
author | Felix Fietkau <nbd@openwrt.org> | 2010-10-13 23:17:51 +0400 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2010-10-13 23:29:08 +0400 |
commit | e82d74f89809c6c01f71168b3b8fdcf490e93fa7 (patch) | |
tree | b031179f224fda2ab77077fa64878fd37879655e /blobmsg.c |
Initial import
Diffstat (limited to 'blobmsg.c')
-rw-r--r-- | blobmsg.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/blobmsg.c b/blobmsg.c new file mode 100644 index 0000000..25b72ae --- /dev/null +++ b/blobmsg.c @@ -0,0 +1,148 @@ +/* + * blobmsg - library for generating/parsing structured blob messages + * + * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "blobmsg.h" + +int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len, + struct blob_attr **tb, void *data, int len) +{ + struct blobmsg_hdr *hdr; + struct blob_attr *attr; + uint8_t *pslen; + int i; + + memset(tb, 0, policy_len * sizeof(*tb)); + pslen = alloca(policy_len); + for (i = 0; i < policy_len; i++) { + if (!policy[i].name) + continue; + + pslen[i] = strlen(policy[i].name); + } + + __blob_for_each_attr(attr, data, len) { + hdr = blob_data(attr); + for (i = 0; i < policy_len; i++) { + if (!policy[i].name) + continue; + + if (policy[i].type != BLOBMSG_TYPE_UNSPEC && + blob_id(attr) != policy[i].type) + continue; + + if (hdr->namelen != pslen[i]) + continue; + + if (!hdr->namelen) + return -1; + + if (sizeof(*attr) + blobmsg_hdrlen(hdr->namelen) > blob_pad_len(attr)) + return -1; + + if (hdr->name[hdr->namelen] != 0) + return -1; + + if (tb[i]) + return -1; + + if (strcmp(policy[i].name, (char *) hdr->name) != 0) + continue; + + tb[i] = attr; + } + } + + return 0; +} + + +static struct blob_attr * +blobmsg_new(struct blob_buf *buf, int type, const char *name, int payload_len, void **data) +{ + struct blob_attr *attr; + struct blobmsg_hdr *hdr; + int attrlen, namelen; + + if (blob_id(buf->head) == BLOBMSG_TYPE_ARRAY && !name) { + attr = blob_new(buf, type, payload_len); + *data = blob_data(attr); + return attr; + } + + if (blob_id(buf->head) != BLOBMSG_TYPE_TABLE || !name) + return NULL; + + namelen = strlen(name); + attrlen = blobmsg_hdrlen(namelen) + payload_len; + attr = blob_new(buf, type, attrlen); + if (!attr) + return NULL; + + hdr = blob_data(attr); + hdr->namelen = namelen; + strcpy((char *) hdr->name, (const char *)name); + *data = blobmsg_data(attr); + + return attr; +} + +static inline int +attr_to_offset(struct blob_buf *buf, struct blob_attr *attr) +{ + return (char *)attr - (char *) buf->buf; +} + + +void * +blobmsg_open_nested(struct blob_buf *buf, const char *name, bool array) +{ + struct blob_attr *head = buf->head; + int type = array ? BLOBMSG_TYPE_ARRAY : BLOBMSG_TYPE_TABLE; + unsigned long offset = attr_to_offset(buf, buf->head); + void *data; + + if (blob_id(head) == BLOBMSG_TYPE_ARRAY && !name) + return blob_nest_start(buf, type); + + if (blob_id(head) == BLOBMSG_TYPE_TABLE && name) { + head = blobmsg_new(buf, type, name, 0, &data); + blob_set_raw_len(buf->head, blob_pad_len(buf->head) - blobmsg_hdrlen(strlen(name))); + buf->head = head; + return (void *)offset; + } + + return NULL; +} + +int +blobmsg_add_field(struct blob_buf *buf, int type, const char *name, + const void *data, int len) +{ + struct blob_attr *attr; + void *data_dest; + + if (type == BLOBMSG_TYPE_ARRAY || + type == BLOBMSG_TYPE_TABLE) + return -1; + + attr = blobmsg_new(buf, type, name, len, &data_dest); + if (!attr) + return -1; + + if (len > 0) + memcpy(data_dest, data, len); + + return 0; +} |