13c260e60Schristos /*
23c260e60Schristos * Generic XML helper functions
33c260e60Schristos * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
43c260e60Schristos *
53c260e60Schristos * This software may be distributed under the terms of the BSD license.
63c260e60Schristos * See README for more details.
73c260e60Schristos */
83c260e60Schristos
93c260e60Schristos #include "includes.h"
103c260e60Schristos
113c260e60Schristos #include "common.h"
123c260e60Schristos #include "xml-utils.h"
133c260e60Schristos
143c260e60Schristos
get_node_uri_iter(struct xml_node_ctx * ctx,xml_node_t * root,char * uri)153c260e60Schristos static xml_node_t * get_node_uri_iter(struct xml_node_ctx *ctx,
163c260e60Schristos xml_node_t *root, char *uri)
173c260e60Schristos {
183c260e60Schristos char *end;
193c260e60Schristos xml_node_t *node;
203c260e60Schristos const char *name;
213c260e60Schristos
223c260e60Schristos end = strchr(uri, '/');
233c260e60Schristos if (end)
243c260e60Schristos *end++ = '\0';
253c260e60Schristos
263c260e60Schristos node = root;
273c260e60Schristos xml_node_for_each_sibling(ctx, node) {
283c260e60Schristos xml_node_for_each_check(ctx, node);
293c260e60Schristos name = xml_node_get_localname(ctx, node);
303c260e60Schristos if (strcasecmp(name, uri) == 0)
313c260e60Schristos break;
323c260e60Schristos }
333c260e60Schristos
343c260e60Schristos if (node == NULL)
353c260e60Schristos return NULL;
363c260e60Schristos
373c260e60Schristos if (end) {
383c260e60Schristos return get_node_uri_iter(ctx, xml_node_first_child(ctx, node),
393c260e60Schristos end);
403c260e60Schristos }
413c260e60Schristos
423c260e60Schristos return node;
433c260e60Schristos }
443c260e60Schristos
453c260e60Schristos
get_node_uri(struct xml_node_ctx * ctx,xml_node_t * root,const char * uri)463c260e60Schristos xml_node_t * get_node_uri(struct xml_node_ctx *ctx, xml_node_t *root,
473c260e60Schristos const char *uri)
483c260e60Schristos {
493c260e60Schristos char *search;
503c260e60Schristos xml_node_t *node;
513c260e60Schristos
523c260e60Schristos search = os_strdup(uri);
533c260e60Schristos if (search == NULL)
543c260e60Schristos return NULL;
553c260e60Schristos
563c260e60Schristos node = get_node_uri_iter(ctx, root, search);
573c260e60Schristos
583c260e60Schristos os_free(search);
593c260e60Schristos return node;
603c260e60Schristos }
613c260e60Schristos
623c260e60Schristos
get_node_iter(struct xml_node_ctx * ctx,xml_node_t * root,const char * path)633c260e60Schristos static xml_node_t * get_node_iter(struct xml_node_ctx *ctx,
643c260e60Schristos xml_node_t *root, const char *path)
653c260e60Schristos {
663c260e60Schristos char *end;
673c260e60Schristos xml_node_t *node;
683c260e60Schristos const char *name;
693c260e60Schristos
703c260e60Schristos end = os_strchr(path, '/');
713c260e60Schristos if (end)
723c260e60Schristos *end++ = '\0';
733c260e60Schristos
743c260e60Schristos xml_node_for_each_child(ctx, node, root) {
753c260e60Schristos xml_node_for_each_check(ctx, node);
763c260e60Schristos name = xml_node_get_localname(ctx, node);
773c260e60Schristos if (os_strcasecmp(name, path) == 0)
783c260e60Schristos break;
793c260e60Schristos }
803c260e60Schristos
813c260e60Schristos if (node == NULL)
823c260e60Schristos return NULL;
833c260e60Schristos if (end)
843c260e60Schristos return get_node_iter(ctx, node, end);
853c260e60Schristos return node;
863c260e60Schristos }
873c260e60Schristos
883c260e60Schristos
get_node(struct xml_node_ctx * ctx,xml_node_t * root,const char * path)893c260e60Schristos xml_node_t * get_node(struct xml_node_ctx *ctx, xml_node_t *root,
903c260e60Schristos const char *path)
913c260e60Schristos {
923c260e60Schristos char *search;
933c260e60Schristos xml_node_t *node;
943c260e60Schristos
953c260e60Schristos search = os_strdup(path);
963c260e60Schristos if (search == NULL)
973c260e60Schristos return NULL;
983c260e60Schristos
993c260e60Schristos node = get_node_iter(ctx, root, search);
1003c260e60Schristos
1013c260e60Schristos os_free(search);
1023c260e60Schristos return node;
1033c260e60Schristos }
1043c260e60Schristos
1053c260e60Schristos
get_child_node(struct xml_node_ctx * ctx,xml_node_t * root,const char * path)1063c260e60Schristos xml_node_t * get_child_node(struct xml_node_ctx *ctx, xml_node_t *root,
1073c260e60Schristos const char *path)
1083c260e60Schristos {
1093c260e60Schristos xml_node_t *node;
1103c260e60Schristos xml_node_t *match;
1113c260e60Schristos
1123c260e60Schristos xml_node_for_each_child(ctx, node, root) {
1133c260e60Schristos xml_node_for_each_check(ctx, node);
1143c260e60Schristos match = get_node(ctx, node, path);
1153c260e60Schristos if (match)
1163c260e60Schristos return match;
1173c260e60Schristos }
1183c260e60Schristos
1193c260e60Schristos return NULL;
1203c260e60Schristos }
1213c260e60Schristos
1223c260e60Schristos
node_from_file(struct xml_node_ctx * ctx,const char * name)1233c260e60Schristos xml_node_t * node_from_file(struct xml_node_ctx *ctx, const char *name)
1243c260e60Schristos {
1253c260e60Schristos xml_node_t *node;
1263c260e60Schristos char *buf, *buf2, *start;
1273c260e60Schristos size_t len;
1283c260e60Schristos
1293c260e60Schristos buf = os_readfile(name, &len);
1303c260e60Schristos if (buf == NULL)
1313c260e60Schristos return NULL;
1323c260e60Schristos buf2 = os_realloc(buf, len + 1);
1333c260e60Schristos if (buf2 == NULL) {
1343c260e60Schristos os_free(buf);
1353c260e60Schristos return NULL;
1363c260e60Schristos }
1373c260e60Schristos buf = buf2;
1383c260e60Schristos buf[len] = '\0';
1393c260e60Schristos
1403c260e60Schristos start = os_strstr(buf, "<!DOCTYPE ");
1413c260e60Schristos if (start) {
1423c260e60Schristos char *pos = start + 1;
1433c260e60Schristos int count = 1;
1443c260e60Schristos while (*pos) {
1453c260e60Schristos if (*pos == '<')
1463c260e60Schristos count++;
1473c260e60Schristos else if (*pos == '>') {
1483c260e60Schristos count--;
1493c260e60Schristos if (count == 0) {
1503c260e60Schristos pos++;
1513c260e60Schristos break;
1523c260e60Schristos }
1533c260e60Schristos }
1543c260e60Schristos pos++;
1553c260e60Schristos }
1563c260e60Schristos if (count == 0) {
1573c260e60Schristos /* Remove DOCTYPE to allow the file to be parsed */
1583c260e60Schristos os_memset(start, ' ', pos - start);
1593c260e60Schristos }
1603c260e60Schristos }
1613c260e60Schristos
1623c260e60Schristos node = xml_node_from_buf(ctx, buf);
1633c260e60Schristos os_free(buf);
1643c260e60Schristos
1653c260e60Schristos return node;
1663c260e60Schristos }
1673c260e60Schristos
1683c260e60Schristos
node_to_file(struct xml_node_ctx * ctx,const char * fname,xml_node_t * node)1693c260e60Schristos int node_to_file(struct xml_node_ctx *ctx, const char *fname, xml_node_t *node)
1703c260e60Schristos {
1713c260e60Schristos FILE *f;
1723c260e60Schristos char *str;
1733c260e60Schristos
1743c260e60Schristos str = xml_node_to_str(ctx, node);
1753c260e60Schristos if (str == NULL)
1763c260e60Schristos return -1;
1773c260e60Schristos
1783c260e60Schristos f = fopen(fname, "w");
1793c260e60Schristos if (!f) {
1803c260e60Schristos os_free(str);
1813c260e60Schristos return -1;
1823c260e60Schristos }
1833c260e60Schristos
1843c260e60Schristos fprintf(f, "%s\n", str);
1853c260e60Schristos os_free(str);
1863c260e60Schristos fclose(f);
1873c260e60Schristos
1883c260e60Schristos return 0;
1893c260e60Schristos }
1903c260e60Schristos
1913c260e60Schristos
get_val(struct xml_node_ctx * ctx,xml_node_t * node)1923c260e60Schristos static char * get_val(struct xml_node_ctx *ctx, xml_node_t *node)
1933c260e60Schristos {
1943c260e60Schristos char *val, *pos;
1953c260e60Schristos
1963c260e60Schristos val = xml_node_get_text(ctx, node);
1973c260e60Schristos if (val == NULL)
1983c260e60Schristos return NULL;
1993c260e60Schristos pos = val;
2003c260e60Schristos while (*pos) {
2013c260e60Schristos if (*pos != ' ' && *pos != '\t' && *pos != '\r' && *pos != '\n')
2023c260e60Schristos return val;
2033c260e60Schristos pos++;
2043c260e60Schristos }
2053c260e60Schristos
2063c260e60Schristos return NULL;
2073c260e60Schristos }
2083c260e60Schristos
2093c260e60Schristos
add_path(const char * prev,const char * leaf)2103c260e60Schristos static char * add_path(const char *prev, const char *leaf)
2113c260e60Schristos {
2123c260e60Schristos size_t len;
2133c260e60Schristos char *new_uri;
2143c260e60Schristos
2153c260e60Schristos if (prev == NULL)
2163c260e60Schristos return NULL;
2173c260e60Schristos
2183c260e60Schristos len = os_strlen(prev) + 1 + os_strlen(leaf) + 1;
2193c260e60Schristos new_uri = os_malloc(len);
2203c260e60Schristos if (new_uri)
2213c260e60Schristos os_snprintf(new_uri, len, "%s/%s", prev, leaf);
2223c260e60Schristos
2233c260e60Schristos return new_uri;
2243c260e60Schristos }
2253c260e60Schristos
2263c260e60Schristos
node_to_tnds(struct xml_node_ctx * ctx,xml_node_t * out,xml_node_t * in,const char * uri)2273c260e60Schristos static void node_to_tnds(struct xml_node_ctx *ctx, xml_node_t *out,
2283c260e60Schristos xml_node_t *in, const char *uri)
2293c260e60Schristos {
2303c260e60Schristos xml_node_t *node;
2313c260e60Schristos xml_node_t *tnds;
2323c260e60Schristos const char *name;
2333c260e60Schristos char *val;
2343c260e60Schristos char *new_uri;
2353c260e60Schristos
2363c260e60Schristos xml_node_for_each_child(ctx, node, in) {
2373c260e60Schristos xml_node_for_each_check(ctx, node);
2383c260e60Schristos name = xml_node_get_localname(ctx, node);
2393c260e60Schristos
2403c260e60Schristos tnds = xml_node_create(ctx, out, NULL, "Node");
2413c260e60Schristos if (tnds == NULL)
2423c260e60Schristos return;
2433c260e60Schristos xml_node_create_text(ctx, tnds, NULL, "NodeName", name);
2443c260e60Schristos
2453c260e60Schristos if (uri)
2463c260e60Schristos xml_node_create_text(ctx, tnds, NULL, "Path", uri);
2473c260e60Schristos
2483c260e60Schristos val = get_val(ctx, node);
249*0a73ee0aSchristos if (val || !xml_node_first_child(ctx, node))
250*0a73ee0aSchristos xml_node_create_text(ctx, tnds, NULL, "Value",
251*0a73ee0aSchristos val ? val : "");
2523c260e60Schristos xml_node_get_text_free(ctx, val);
2533c260e60Schristos
2543c260e60Schristos new_uri = add_path(uri, name);
2553c260e60Schristos node_to_tnds(ctx, new_uri ? out : tnds, node, new_uri);
2563c260e60Schristos os_free(new_uri);
2573c260e60Schristos }
2583c260e60Schristos }
2593c260e60Schristos
2603c260e60Schristos
add_ddfname(struct xml_node_ctx * ctx,xml_node_t * parent,const char * urn)2613c260e60Schristos static int add_ddfname(struct xml_node_ctx *ctx, xml_node_t *parent,
2623c260e60Schristos const char *urn)
2633c260e60Schristos {
2643c260e60Schristos xml_node_t *node;
2653c260e60Schristos
2663c260e60Schristos node = xml_node_create(ctx, parent, NULL, "RTProperties");
2673c260e60Schristos if (node == NULL)
2683c260e60Schristos return -1;
2693c260e60Schristos node = xml_node_create(ctx, node, NULL, "Type");
2703c260e60Schristos if (node == NULL)
2713c260e60Schristos return -1;
2723c260e60Schristos xml_node_create_text(ctx, node, NULL, "DDFName", urn);
2733c260e60Schristos return 0;
2743c260e60Schristos }
2753c260e60Schristos
2763c260e60Schristos
mo_to_tnds(struct xml_node_ctx * ctx,xml_node_t * mo,int use_path,const char * urn,const char * ns_uri)2773c260e60Schristos xml_node_t * mo_to_tnds(struct xml_node_ctx *ctx, xml_node_t *mo,
2783c260e60Schristos int use_path, const char *urn, const char *ns_uri)
2793c260e60Schristos {
2803c260e60Schristos xml_node_t *root;
2813c260e60Schristos xml_node_t *node;
2823c260e60Schristos const char *name;
2833c260e60Schristos
2843c260e60Schristos root = xml_node_create_root(ctx, ns_uri, NULL, NULL, "MgmtTree");
2853c260e60Schristos if (root == NULL)
2863c260e60Schristos return NULL;
2873c260e60Schristos
2883c260e60Schristos xml_node_create_text(ctx, root, NULL, "VerDTD", "1.2");
2893c260e60Schristos
2903c260e60Schristos name = xml_node_get_localname(ctx, mo);
2913c260e60Schristos
2923c260e60Schristos node = xml_node_create(ctx, root, NULL, "Node");
2933c260e60Schristos if (node == NULL)
2943c260e60Schristos goto fail;
2953c260e60Schristos xml_node_create_text(ctx, node, NULL, "NodeName", name);
2963c260e60Schristos if (urn)
2973c260e60Schristos add_ddfname(ctx, node, urn);
2983c260e60Schristos
2993c260e60Schristos node_to_tnds(ctx, use_path ? root : node, mo, use_path ? name : NULL);
3003c260e60Schristos
3013c260e60Schristos return root;
3023c260e60Schristos
3033c260e60Schristos fail:
3043c260e60Schristos xml_node_free(ctx, root);
3053c260e60Schristos return NULL;
3063c260e60Schristos }
3073c260e60Schristos
3083c260e60Schristos
get_first_child_node(struct xml_node_ctx * ctx,xml_node_t * node,const char * name)3093c260e60Schristos static xml_node_t * get_first_child_node(struct xml_node_ctx *ctx,
3103c260e60Schristos xml_node_t *node,
3113c260e60Schristos const char *name)
3123c260e60Schristos {
3133c260e60Schristos const char *lname;
3143c260e60Schristos xml_node_t *child;
3153c260e60Schristos
3163c260e60Schristos xml_node_for_each_child(ctx, child, node) {
3173c260e60Schristos xml_node_for_each_check(ctx, child);
3183c260e60Schristos lname = xml_node_get_localname(ctx, child);
3193c260e60Schristos if (os_strcasecmp(lname, name) == 0)
3203c260e60Schristos return child;
3213c260e60Schristos }
3223c260e60Schristos
3233c260e60Schristos return NULL;
3243c260e60Schristos }
3253c260e60Schristos
3263c260e60Schristos
get_node_text(struct xml_node_ctx * ctx,xml_node_t * node,const char * node_name)3273c260e60Schristos static char * get_node_text(struct xml_node_ctx *ctx, xml_node_t *node,
3283c260e60Schristos const char *node_name)
3293c260e60Schristos {
3303c260e60Schristos node = get_first_child_node(ctx, node, node_name);
3313c260e60Schristos if (node == NULL)
3323c260e60Schristos return NULL;
3333c260e60Schristos return xml_node_get_text(ctx, node);
3343c260e60Schristos }
3353c260e60Schristos
3363c260e60Schristos
add_mo_node(struct xml_node_ctx * ctx,xml_node_t * root,xml_node_t * node,const char * uri)3373c260e60Schristos static xml_node_t * add_mo_node(struct xml_node_ctx *ctx, xml_node_t *root,
3383c260e60Schristos xml_node_t *node, const char *uri)
3393c260e60Schristos {
3403c260e60Schristos char *nodename, *value, *path;
3413c260e60Schristos xml_node_t *parent;
3423c260e60Schristos
3433c260e60Schristos nodename = get_node_text(ctx, node, "NodeName");
3443c260e60Schristos if (nodename == NULL)
3453c260e60Schristos return NULL;
3463c260e60Schristos value = get_node_text(ctx, node, "Value");
3473c260e60Schristos
3483c260e60Schristos if (root == NULL) {
3493c260e60Schristos root = xml_node_create_root(ctx, NULL, NULL, NULL,
3503c260e60Schristos nodename);
3513c260e60Schristos if (root && value)
3523c260e60Schristos xml_node_set_text(ctx, root, value);
3533c260e60Schristos } else {
3543c260e60Schristos if (uri == NULL) {
3553c260e60Schristos xml_node_get_text_free(ctx, nodename);
3563c260e60Schristos xml_node_get_text_free(ctx, value);
3573c260e60Schristos return NULL;
3583c260e60Schristos }
3593c260e60Schristos path = get_node_text(ctx, node, "Path");
3603c260e60Schristos if (path)
3613c260e60Schristos uri = path;
3623c260e60Schristos parent = get_node_uri(ctx, root, uri);
3633c260e60Schristos xml_node_get_text_free(ctx, path);
3643c260e60Schristos if (parent == NULL) {
3653c260e60Schristos printf("Could not find URI '%s'\n", uri);
3663c260e60Schristos xml_node_get_text_free(ctx, nodename);
3673c260e60Schristos xml_node_get_text_free(ctx, value);
3683c260e60Schristos return NULL;
3693c260e60Schristos }
3703c260e60Schristos if (value)
3713c260e60Schristos xml_node_create_text(ctx, parent, NULL, nodename,
3723c260e60Schristos value);
3733c260e60Schristos else
3743c260e60Schristos xml_node_create(ctx, parent, NULL, nodename);
3753c260e60Schristos }
3763c260e60Schristos
3773c260e60Schristos xml_node_get_text_free(ctx, nodename);
3783c260e60Schristos xml_node_get_text_free(ctx, value);
3793c260e60Schristos
3803c260e60Schristos return root;
3813c260e60Schristos }
3823c260e60Schristos
3833c260e60Schristos
tnds_to_mo_iter(struct xml_node_ctx * ctx,xml_node_t * root,xml_node_t * node,const char * uri)3843c260e60Schristos static xml_node_t * tnds_to_mo_iter(struct xml_node_ctx *ctx, xml_node_t *root,
3853c260e60Schristos xml_node_t *node, const char *uri)
3863c260e60Schristos {
3873c260e60Schristos xml_node_t *child;
3883c260e60Schristos const char *name;
3893c260e60Schristos char *nodename;
3903c260e60Schristos
3913c260e60Schristos xml_node_for_each_sibling(ctx, node) {
3923c260e60Schristos xml_node_for_each_check(ctx, node);
3933c260e60Schristos
3943c260e60Schristos nodename = get_node_text(ctx, node, "NodeName");
3953c260e60Schristos if (nodename == NULL)
3963c260e60Schristos return NULL;
3973c260e60Schristos
3983c260e60Schristos name = xml_node_get_localname(ctx, node);
3993c260e60Schristos if (strcmp(name, "Node") == 0) {
4003c260e60Schristos if (root && !uri) {
4013c260e60Schristos printf("Invalid TNDS tree structure - "
4023c260e60Schristos "multiple top level nodes\n");
4033c260e60Schristos xml_node_get_text_free(ctx, nodename);
4043c260e60Schristos return NULL;
4053c260e60Schristos }
4063c260e60Schristos root = add_mo_node(ctx, root, node, uri);
4073c260e60Schristos }
4083c260e60Schristos
4093c260e60Schristos child = get_first_child_node(ctx, node, "Node");
4103c260e60Schristos if (child) {
4113c260e60Schristos if (uri == NULL)
4123c260e60Schristos tnds_to_mo_iter(ctx, root, child, nodename);
4133c260e60Schristos else {
4143c260e60Schristos char *new_uri;
4153c260e60Schristos new_uri = add_path(uri, nodename);
4163c260e60Schristos tnds_to_mo_iter(ctx, root, child, new_uri);
4173c260e60Schristos os_free(new_uri);
4183c260e60Schristos }
4193c260e60Schristos }
4203c260e60Schristos xml_node_get_text_free(ctx, nodename);
4213c260e60Schristos }
4223c260e60Schristos
4233c260e60Schristos return root;
4243c260e60Schristos }
4253c260e60Schristos
4263c260e60Schristos
tnds_to_mo(struct xml_node_ctx * ctx,xml_node_t * tnds)4273c260e60Schristos xml_node_t * tnds_to_mo(struct xml_node_ctx *ctx, xml_node_t *tnds)
4283c260e60Schristos {
4293c260e60Schristos const char *name;
4303c260e60Schristos xml_node_t *node;
4313c260e60Schristos
4323c260e60Schristos name = xml_node_get_localname(ctx, tnds);
4333c260e60Schristos if (name == NULL || os_strcmp(name, "MgmtTree") != 0)
4343c260e60Schristos return NULL;
4353c260e60Schristos
4363c260e60Schristos node = get_first_child_node(ctx, tnds, "Node");
4373c260e60Schristos if (!node)
4383c260e60Schristos return NULL;
4393c260e60Schristos return tnds_to_mo_iter(ctx, NULL, node, NULL);
4403c260e60Schristos }
4413c260e60Schristos
4423c260e60Schristos
soap_build_envelope(struct xml_node_ctx * ctx,xml_node_t * node)4433c260e60Schristos xml_node_t * soap_build_envelope(struct xml_node_ctx *ctx, xml_node_t *node)
4443c260e60Schristos {
4453c260e60Schristos xml_node_t *envelope, *body;
4463c260e60Schristos xml_namespace_t *ns;
4473c260e60Schristos
4483c260e60Schristos envelope = xml_node_create_root(
4493c260e60Schristos ctx, "http://www.w3.org/2003/05/soap-envelope", "soap12", &ns,
4503c260e60Schristos "Envelope");
4513c260e60Schristos if (envelope == NULL)
4523c260e60Schristos return NULL;
4533c260e60Schristos body = xml_node_create(ctx, envelope, ns, "Body");
4543c260e60Schristos xml_node_add_child(ctx, body, node);
4553c260e60Schristos return envelope;
4563c260e60Schristos }
4573c260e60Schristos
4583c260e60Schristos
soap_get_body(struct xml_node_ctx * ctx,xml_node_t * soap)4593c260e60Schristos xml_node_t * soap_get_body(struct xml_node_ctx *ctx, xml_node_t *soap)
4603c260e60Schristos {
4613c260e60Schristos xml_node_t *body, *child;
4623c260e60Schristos
4633c260e60Schristos body = get_node_uri(ctx, soap, "Envelope/Body");
4643c260e60Schristos if (body == NULL)
4653c260e60Schristos return NULL;
4663c260e60Schristos xml_node_for_each_child(ctx, child, body) {
4673c260e60Schristos xml_node_for_each_check(ctx, child);
4683c260e60Schristos return child;
4693c260e60Schristos }
4703c260e60Schristos return NULL;
4713c260e60Schristos }
472