/* * Generic XML helper functions * Copyright (c) 2012-2013, Qualcomm Atheros, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #include "common.h" #include "xml-utils.h" static xml_node_t * get_node_uri_iter(struct xml_node_ctx *ctx, xml_node_t *root, char *uri) { char *end; xml_node_t *node; const char *name; end = strchr(uri, '/'); if (end) *end++ = '\0'; node = root; xml_node_for_each_sibling(ctx, node) { xml_node_for_each_check(ctx, node); name = xml_node_get_localname(ctx, node); if (strcasecmp(name, uri) == 0) break; } if (node == NULL) return NULL; if (end) { return get_node_uri_iter(ctx, xml_node_first_child(ctx, node), end); } return node; } xml_node_t * get_node_uri(struct xml_node_ctx *ctx, xml_node_t *root, const char *uri) { char *search; xml_node_t *node; search = os_strdup(uri); if (search == NULL) return NULL; node = get_node_uri_iter(ctx, root, search); os_free(search); return node; } static xml_node_t * get_node_iter(struct xml_node_ctx *ctx, xml_node_t *root, const char *path) { char *end; xml_node_t *node; const char *name; end = os_strchr(path, '/'); if (end) *end++ = '\0'; xml_node_for_each_child(ctx, node, root) { xml_node_for_each_check(ctx, node); name = xml_node_get_localname(ctx, node); if (os_strcasecmp(name, path) == 0) break; } if (node == NULL) return NULL; if (end) return get_node_iter(ctx, node, end); return node; } xml_node_t * get_node(struct xml_node_ctx *ctx, xml_node_t *root, const char *path) { char *search; xml_node_t *node; search = os_strdup(path); if (search == NULL) return NULL; node = get_node_iter(ctx, root, search); os_free(search); return node; } xml_node_t * get_child_node(struct xml_node_ctx *ctx, xml_node_t *root, const char *path) { xml_node_t *node; xml_node_t *match; xml_node_for_each_child(ctx, node, root) { xml_node_for_each_check(ctx, node); match = get_node(ctx, node, path); if (match) return match; } return NULL; } xml_node_t * node_from_file(struct xml_node_ctx *ctx, const char *name) { xml_node_t *node; char *buf, *buf2, *start; size_t len; buf = os_readfile(name, &len); if (buf == NULL) return NULL; buf2 = os_realloc(buf, len + 1); if (buf2 == NULL) { os_free(buf); return NULL; } buf = buf2; buf[len] = '\0'; start = os_strstr(buf, "<!DOCTYPE "); if (start) { char *pos = start + 1; int count = 1; while (*pos) { if (*pos == '<') count++; else if (*pos == '>') { count--; if (count == 0) { pos++; break; } } pos++; } if (count == 0) { /* Remove DOCTYPE to allow the file to be parsed */ os_memset(start, ' ', pos - start); } } node = xml_node_from_buf(ctx, buf); os_free(buf); return node; } int node_to_file(struct xml_node_ctx *ctx, const char *fname, xml_node_t *node) { FILE *f; char *str; str = xml_node_to_str(ctx, node); if (str == NULL) return -1; f = fopen(fname, "w"); if (!f) { os_free(str); return -1; } fprintf(f, "%s\n", str); os_free(str); fclose(f); return 0; } static char * get_val(struct xml_node_ctx *ctx, xml_node_t *node) { char *val, *pos; val = xml_node_get_text(ctx, node); if (val == NULL) return NULL; pos = val; while (*pos) { if (*pos != ' ' && *pos != '\t' && *pos != '\r' && *pos != '\n') return val; pos++; } return NULL; } static char * add_path(const char *prev, const char *leaf) { size_t len; char *new_uri; if (prev == NULL) return NULL; len = os_strlen(prev) + 1 + os_strlen(leaf) + 1; new_uri = os_malloc(len); if (new_uri) os_snprintf(new_uri, len, "%s/%s", prev, leaf); return new_uri; } static void node_to_tnds(struct xml_node_ctx *ctx, xml_node_t *out, xml_node_t *in, const char *uri) { xml_node_t *node; xml_node_t *tnds; const char *name; char *val; char *new_uri; xml_node_for_each_child(ctx, node, in) { xml_node_for_each_check(ctx, node); name = xml_node_get_localname(ctx, node); tnds = xml_node_create(ctx, out, NULL, "Node"); if (tnds == NULL) return; xml_node_create_text(ctx, tnds, NULL, "NodeName", name); if (uri) xml_node_create_text(ctx, tnds, NULL, "Path", uri); val = get_val(ctx, node); if (val) { xml_node_create_text(ctx, tnds, NULL, "Value", val); xml_node_get_text_free(ctx, val); } new_uri = add_path(uri, name); node_to_tnds(ctx, new_uri ? out : tnds, node, new_uri); os_free(new_uri); } } static int add_ddfname(struct xml_node_ctx *ctx, xml_node_t *parent, const char *urn) { xml_node_t *node; node = xml_node_create(ctx, parent, NULL, "RTProperties"); if (node == NULL) return -1; node = xml_node_create(ctx, node, NULL, "Type"); if (node == NULL) return -1; xml_node_create_text(ctx, node, NULL, "DDFName", urn); return 0; } xml_node_t * mo_to_tnds(struct xml_node_ctx *ctx, xml_node_t *mo, int use_path, const char *urn, const char *ns_uri) { xml_node_t *root; xml_node_t *node; const char *name; root = xml_node_create_root(ctx, ns_uri, NULL, NULL, "MgmtTree"); if (root == NULL) return NULL; xml_node_create_text(ctx, root, NULL, "VerDTD", "1.2"); name = xml_node_get_localname(ctx, mo); node = xml_node_create(ctx, root, NULL, "Node"); if (node == NULL) goto fail; xml_node_create_text(ctx, node, NULL, "NodeName", name); if (urn) add_ddfname(ctx, node, urn); node_to_tnds(ctx, use_path ? root : node, mo, use_path ? name : NULL); return root; fail: xml_node_free(ctx, root); return NULL; } static xml_node_t * get_first_child_node(struct xml_node_ctx *ctx, xml_node_t *node, const char *name) { const char *lname; xml_node_t *child; xml_node_for_each_child(ctx, child, node) { xml_node_for_each_check(ctx, child); lname = xml_node_get_localname(ctx, child); if (os_strcasecmp(lname, name) == 0) return child; } return NULL; } static char * get_node_text(struct xml_node_ctx *ctx, xml_node_t *node, const char *node_name) { node = get_first_child_node(ctx, node, node_name); if (node == NULL) return NULL; return xml_node_get_text(ctx, node); } static xml_node_t * add_mo_node(struct xml_node_ctx *ctx, xml_node_t *root, xml_node_t *node, const char *uri) { char *nodename, *value, *path; xml_node_t *parent; nodename = get_node_text(ctx, node, "NodeName"); if (nodename == NULL) return NULL; value = get_node_text(ctx, node, "Value"); if (root == NULL) { root = xml_node_create_root(ctx, NULL, NULL, NULL, nodename); if (root && value) xml_node_set_text(ctx, root, value); } else { if (uri == NULL) { xml_node_get_text_free(ctx, nodename); xml_node_get_text_free(ctx, value); return NULL; } path = get_node_text(ctx, node, "Path"); if (path) uri = path; parent = get_node_uri(ctx, root, uri); xml_node_get_text_free(ctx, path); if (parent == NULL) { printf("Could not find URI '%s'\n", uri); xml_node_get_text_free(ctx, nodename); xml_node_get_text_free(ctx, value); return NULL; } if (value) xml_node_create_text(ctx, parent, NULL, nodename, value); else xml_node_create(ctx, parent, NULL, nodename); } xml_node_get_text_free(ctx, nodename); xml_node_get_text_free(ctx, value); return root; } static xml_node_t * tnds_to_mo_iter(struct xml_node_ctx *ctx, xml_node_t *root, xml_node_t *node, const char *uri) { xml_node_t *child; const char *name; char *nodename; xml_node_for_each_sibling(ctx, node) { xml_node_for_each_check(ctx, node); nodename = get_node_text(ctx, node, "NodeName"); if (nodename == NULL) return NULL; name = xml_node_get_localname(ctx, node); if (strcmp(name, "Node") == 0) { if (root && !uri) { printf("Invalid TNDS tree structure - " "multiple top level nodes\n"); xml_node_get_text_free(ctx, nodename); return NULL; } root = add_mo_node(ctx, root, node, uri); } child = get_first_child_node(ctx, node, "Node"); if (child) { if (uri == NULL) tnds_to_mo_iter(ctx, root, child, nodename); else { char *new_uri; new_uri = add_path(uri, nodename); tnds_to_mo_iter(ctx, root, child, new_uri); os_free(new_uri); } } xml_node_get_text_free(ctx, nodename); } return root; } xml_node_t * tnds_to_mo(struct xml_node_ctx *ctx, xml_node_t *tnds) { const char *name; xml_node_t *node; name = xml_node_get_localname(ctx, tnds); if (name == NULL || os_strcmp(name, "MgmtTree") != 0) return NULL; node = get_first_child_node(ctx, tnds, "Node"); if (!node) return NULL; return tnds_to_mo_iter(ctx, NULL, node, NULL); } xml_node_t * soap_build_envelope(struct xml_node_ctx *ctx, xml_node_t *node) { xml_node_t *envelope, *body; xml_namespace_t *ns; envelope = xml_node_create_root( ctx, "http://www.w3.org/2003/05/soap-envelope", "soap12", &ns, "Envelope"); if (envelope == NULL) return NULL; body = xml_node_create(ctx, envelope, ns, "Body"); xml_node_add_child(ctx, body, node); return envelope; } xml_node_t * soap_get_body(struct xml_node_ctx *ctx, xml_node_t *soap) { xml_node_t *body, *child; body = get_node_uri(ctx, soap, "Envelope/Body"); if (body == NULL) return NULL; xml_node_for_each_child(ctx, child, body) { xml_node_for_each_check(ctx, child); return child; } return NULL; }