diff --git a/src/utils/xml-utils.c b/src/utils/xml-utils.c new file mode 100644 index 000000000..4916d2976 --- /dev/null +++ b/src/utils/xml-utils.c @@ -0,0 +1,471 @@ +/* + * 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, "') { + 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; +} diff --git a/src/utils/xml-utils.h b/src/utils/xml-utils.h new file mode 100644 index 000000000..0d8e0cb82 --- /dev/null +++ b/src/utils/xml-utils.h @@ -0,0 +1,100 @@ +/* + * 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. + */ + +#ifndef XML_UTILS_H +#define XML_UTILS_H + +struct xml_node_ctx; +typedef struct xml_node xml_node_t; +typedef struct xml_namespace_foo xml_namespace_t; + +/* XML library wrappers */ + +int xml_validate(struct xml_node_ctx *ctx, xml_node_t *node, + const char *xml_schema_fname, char **ret_err); +int xml_validate_dtd(struct xml_node_ctx *ctx, xml_node_t *node, + const char *dtd_fname, char **ret_err); +void xml_node_free(struct xml_node_ctx *ctx, xml_node_t *node); +xml_node_t * xml_node_get_parent(struct xml_node_ctx *ctx, xml_node_t *node); +xml_node_t * xml_node_from_buf(struct xml_node_ctx *ctx, const char *buf); +const char * xml_node_get_localname(struct xml_node_ctx *ctx, + xml_node_t *node); +char * xml_node_to_str(struct xml_node_ctx *ctx, xml_node_t *node); +void xml_node_detach(struct xml_node_ctx *ctx, xml_node_t *node); +void xml_node_add_child(struct xml_node_ctx *ctx, xml_node_t *parent, + xml_node_t *child); +xml_node_t * xml_node_create_root(struct xml_node_ctx *ctx, const char *ns_uri, + const char *ns_prefix, + xml_namespace_t **ret_ns, const char *name); +xml_node_t * xml_node_create(struct xml_node_ctx *ctx, xml_node_t *parent, + xml_namespace_t *ns, const char *name); +xml_node_t * xml_node_create_text(struct xml_node_ctx *ctx, + xml_node_t *parent, xml_namespace_t *ns, + const char *name, const char *value); +xml_node_t * xml_node_create_text_ns(struct xml_node_ctx *ctx, + xml_node_t *parent, const char *ns_uri, + const char *name, const char *value); +void xml_node_set_text(struct xml_node_ctx *ctx, xml_node_t *node, + const char *value); +int xml_node_add_attr(struct xml_node_ctx *ctx, xml_node_t *node, + xml_namespace_t *ns, const char *name, const char *value); +char * xml_node_get_attr_value(struct xml_node_ctx *ctx, xml_node_t *node, + char *name); +char * xml_node_get_attr_value_ns(struct xml_node_ctx *ctx, xml_node_t *node, + const char *ns_uri, char *name); +void xml_node_get_attr_value_free(struct xml_node_ctx *ctx, char *val); +xml_node_t * xml_node_first_child(struct xml_node_ctx *ctx, + xml_node_t *parent); +xml_node_t * xml_node_next_sibling(struct xml_node_ctx *ctx, + xml_node_t *node); +int xml_node_is_element(struct xml_node_ctx *ctx, xml_node_t *node); +char * xml_node_get_text(struct xml_node_ctx *ctx, xml_node_t *node); +void xml_node_get_text_free(struct xml_node_ctx *ctx, char *val); +char * xml_node_get_base64_text(struct xml_node_ctx *ctx, xml_node_t *node, + int *ret_len); +xml_node_t * xml_node_copy(struct xml_node_ctx *ctx, xml_node_t *node); + +#define xml_node_for_each_child(ctx, child, parent) \ +for (child = xml_node_first_child(ctx, parent); \ + child; \ + child = xml_node_next_sibling(ctx, child)) + +#define xml_node_for_each_sibling(ctx, node) \ +for (; \ + node; \ + node = xml_node_next_sibling(ctx, node)) + +#define xml_node_for_each_check(ctx, child) \ +if (!xml_node_is_element(ctx, child)) \ + continue + +typedef void (*debug_print_func)(void *ctx, int print, const char *fmt, ...) + __attribute__ ((format (printf, 3, 4))); + + +struct xml_node_ctx * xml_node_init_ctx(void *upper_ctx, + const void *env); +void xml_node_deinit_ctx(struct xml_node_ctx *ctx); + + +xml_node_t * get_node_uri(struct xml_node_ctx *ctx, xml_node_t *root, + const char *uri); +xml_node_t * get_node(struct xml_node_ctx *ctx, xml_node_t *root, + const char *path); +xml_node_t * get_child_node(struct xml_node_ctx *ctx, xml_node_t *root, + const char *path); +xml_node_t * node_from_file(struct xml_node_ctx *ctx, const char *name); +int node_to_file(struct xml_node_ctx *ctx, const char *fname, xml_node_t *node); +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 * tnds_to_mo(struct xml_node_ctx *ctx, xml_node_t *tnds); + +xml_node_t * soap_build_envelope(struct xml_node_ctx *ctx, xml_node_t *node); +xml_node_t * soap_get_body(struct xml_node_ctx *ctx, xml_node_t *soap); + +#endif /* XML_UTILS_H */ diff --git a/src/utils/xml_libxml2.c b/src/utils/xml_libxml2.c new file mode 100644 index 000000000..c92839461 --- /dev/null +++ b/src/utils/xml_libxml2.c @@ -0,0 +1,457 @@ +/* + * XML wrapper for libxml2 + * 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" +#define LIBXML_VALID_ENABLED +#include +#include + +#include "common.h" +#include "base64.h" +#include "xml-utils.h" + + +struct xml_node_ctx { + void *ctx; +}; + + +struct str_buf { + char *buf; + size_t len; +}; + +#define MAX_STR 1000 + +static void add_str(void *ctx_ptr, const char *fmt, ...) +{ + struct str_buf *str = ctx_ptr; + va_list ap; + char *n; + int len; + + n = os_realloc(str->buf, str->len + MAX_STR + 2); + if (n == NULL) + return; + str->buf = n; + + va_start(ap, fmt); + len = vsnprintf(str->buf + str->len, MAX_STR, fmt, ap); + va_end(ap); + if (len >= MAX_STR) + len = MAX_STR - 1; + str->len += len; + str->buf[str->len] = '\0'; +} + + +int xml_validate(struct xml_node_ctx *ctx, xml_node_t *node, + const char *xml_schema_fname, char **ret_err) +{ + xmlDocPtr doc; + xmlNodePtr n; + xmlSchemaParserCtxtPtr pctx; + xmlSchemaValidCtxtPtr vctx; + xmlSchemaPtr schema; + int ret; + struct str_buf errors; + + if (ret_err) + *ret_err = NULL; + + doc = xmlNewDoc((xmlChar *) "1.0"); + if (doc == NULL) + return -1; + n = xmlDocCopyNode((xmlNodePtr) node, doc, 1); + if (n == NULL) { + xmlFreeDoc(doc); + return -1; + } + xmlDocSetRootElement(doc, n); + + os_memset(&errors, 0, sizeof(errors)); + + pctx = xmlSchemaNewParserCtxt(xml_schema_fname); + xmlSchemaSetParserErrors(pctx, (xmlSchemaValidityErrorFunc) add_str, + (xmlSchemaValidityWarningFunc) add_str, + &errors); + schema = xmlSchemaParse(pctx); + xmlSchemaFreeParserCtxt(pctx); + + vctx = xmlSchemaNewValidCtxt(schema); + xmlSchemaSetValidErrors(vctx, (xmlSchemaValidityErrorFunc) add_str, + (xmlSchemaValidityWarningFunc) add_str, + &errors); + + ret = xmlSchemaValidateDoc(vctx, doc); + xmlSchemaFreeValidCtxt(vctx); + xmlFreeDoc(doc); + xmlSchemaFree(schema); + + if (ret == 0) { + os_free(errors.buf); + return 0; + } else if (ret > 0) { + if (ret_err) + *ret_err = errors.buf; + else + os_free(errors.buf); + return -1; + } else { + if (ret_err) + *ret_err = errors.buf; + else + os_free(errors.buf); + return -1; + } +} + + +int xml_validate_dtd(struct xml_node_ctx *ctx, xml_node_t *node, + const char *dtd_fname, char **ret_err) +{ + xmlDocPtr doc; + xmlNodePtr n; + xmlValidCtxt vctx; + xmlDtdPtr dtd; + int ret; + struct str_buf errors; + + if (ret_err) + *ret_err = NULL; + + doc = xmlNewDoc((xmlChar *) "1.0"); + if (doc == NULL) + return -1; + n = xmlDocCopyNode((xmlNodePtr) node, doc, 1); + if (n == NULL) { + xmlFreeDoc(doc); + return -1; + } + xmlDocSetRootElement(doc, n); + + os_memset(&errors, 0, sizeof(errors)); + + dtd = xmlParseDTD(NULL, (const xmlChar *) dtd_fname); + if (dtd == NULL) { + xmlFreeDoc(doc); + return -1; + } + + os_memset(&vctx, 0, sizeof(vctx)); + vctx.userData = &errors; + vctx.error = add_str; + vctx.warning = add_str; + ret = xmlValidateDtd(&vctx, doc, dtd); + xmlFreeDoc(doc); + xmlFreeDtd(dtd); + + if (ret == 1) { + os_free(errors.buf); + return 0; + } else { + if (ret_err) + *ret_err = errors.buf; + else + os_free(errors.buf); + return -1; + } +} + + +void xml_node_free(struct xml_node_ctx *ctx, xml_node_t *node) +{ + xmlFreeNode((xmlNodePtr) node); +} + + +xml_node_t * xml_node_get_parent(struct xml_node_ctx *ctx, xml_node_t *node) +{ + return (xml_node_t *) ((xmlNodePtr) node)->parent; +} + + +xml_node_t * xml_node_from_buf(struct xml_node_ctx *ctx, const char *buf) +{ + xmlDocPtr doc; + xmlNodePtr node; + + doc = xmlParseMemory(buf, strlen(buf)); + if (doc == NULL) + return NULL; + node = xmlDocGetRootElement(doc); + node = xmlCopyNode(node, 1); + xmlFreeDoc(doc); + + return (xml_node_t *) node; +} + + +const char * xml_node_get_localname(struct xml_node_ctx *ctx, + xml_node_t *node) +{ + return (const char *) ((xmlNodePtr) node)->name; +} + + +char * xml_node_to_str(struct xml_node_ctx *ctx, xml_node_t *node) +{ + xmlChar *buf; + int bufsiz; + char *ret, *pos; + xmlNodePtr n = (xmlNodePtr) node; + xmlDocPtr doc; + + doc = xmlNewDoc((xmlChar *) "1.0"); + n = xmlDocCopyNode(n, doc, 1); + xmlDocSetRootElement(doc, n); + xmlDocDumpFormatMemory(doc, &buf, &bufsiz, 0); + xmlFreeDoc(doc); + pos = (char *) buf; + if (strncmp(pos, "'); + if (pos) + pos++; + while (pos && (*pos == '\r' || *pos == '\n')) + pos++; + } + if (pos) + ret = os_strdup(pos); + else + ret = NULL; + xmlFree(buf); + + if (ret) { + pos = ret; + if (pos[0]) { + while (pos[1]) + pos++; + } + while (pos >= ret && *pos == '\n') + *pos-- = '\0'; + } + + return ret; +} + + +void xml_node_detach(struct xml_node_ctx *ctx, xml_node_t *node) +{ + xmlUnlinkNode((xmlNodePtr) node); +} + + +void xml_node_add_child(struct xml_node_ctx *ctx, xml_node_t *parent, + xml_node_t *child) +{ + xmlAddChild((xmlNodePtr) parent, (xmlNodePtr) child); +} + + +xml_node_t * xml_node_create_root(struct xml_node_ctx *ctx, const char *ns_uri, + const char *ns_prefix, + xml_namespace_t **ret_ns, const char *name) +{ + xmlNodePtr node; + xmlNsPtr ns = NULL; + + node = xmlNewNode(NULL, (const xmlChar *) name); + if (node == NULL) + return NULL; + if (ns_uri) { + ns = xmlNewNs(node, (const xmlChar *) ns_uri, + (const xmlChar *) ns_prefix); + xmlSetNs(node, ns); + } + + if (ret_ns) + *ret_ns = (xml_namespace_t *) ns; + + return (xml_node_t *) node; +} + + +xml_node_t * xml_node_create(struct xml_node_ctx *ctx, xml_node_t *parent, + xml_namespace_t *ns, const char *name) +{ + xmlNodePtr node; + node = xmlNewChild((xmlNodePtr) parent, (xmlNsPtr) ns, + (const xmlChar *) name, NULL); + return (xml_node_t *) node; +} + + +xml_node_t * xml_node_create_text(struct xml_node_ctx *ctx, + xml_node_t *parent, xml_namespace_t *ns, + const char *name, const char *value) +{ + xmlNodePtr node; + node = xmlNewTextChild((xmlNodePtr) parent, (xmlNsPtr) ns, + (const xmlChar *) name, (const xmlChar *) value); + return (xml_node_t *) node; +} + + +xml_node_t * xml_node_create_text_ns(struct xml_node_ctx *ctx, + xml_node_t *parent, const char *ns_uri, + const char *name, const char *value) +{ + xmlNodePtr node; + xmlNsPtr ns; + + node = xmlNewTextChild((xmlNodePtr) parent, NULL, + (const xmlChar *) name, (const xmlChar *) value); + ns = xmlNewNs(node, (const xmlChar *) ns_uri, NULL); + xmlSetNs(node, ns); + return (xml_node_t *) node; +} + + +void xml_node_set_text(struct xml_node_ctx *ctx, xml_node_t *node, + const char *value) +{ + /* TODO: escape XML special chars in value */ + xmlNodeSetContent((xmlNodePtr) node, (xmlChar *) value); +} + + +int xml_node_add_attr(struct xml_node_ctx *ctx, xml_node_t *node, + xml_namespace_t *ns, const char *name, const char *value) +{ + xmlAttrPtr attr; + + if (ns) { + attr = xmlNewNsProp((xmlNodePtr) node, (xmlNsPtr) ns, + (const xmlChar *) name, + (const xmlChar *) value); + } else { + attr = xmlNewProp((xmlNodePtr) node, (const xmlChar *) name, + (const xmlChar *) value); + } + + return attr ? 0 : -1; +} + + +char * xml_node_get_attr_value(struct xml_node_ctx *ctx, xml_node_t *node, + char *name) +{ + return (char *) xmlGetNoNsProp((xmlNodePtr) node, + (const xmlChar *) name); +} + + +char * xml_node_get_attr_value_ns(struct xml_node_ctx *ctx, xml_node_t *node, + const char *ns_uri, char *name) +{ + return (char *) xmlGetNsProp((xmlNodePtr) node, (const xmlChar *) name, + (const xmlChar *) ns_uri); +} + + +void xml_node_get_attr_value_free(struct xml_node_ctx *ctx, char *val) +{ + if (val) + xmlFree((xmlChar *) val); +} + + +xml_node_t * xml_node_first_child(struct xml_node_ctx *ctx, + xml_node_t *parent) +{ + return (xml_node_t *) ((xmlNodePtr) parent)->children; +} + + +xml_node_t * xml_node_next_sibling(struct xml_node_ctx *ctx, + xml_node_t *node) +{ + return (xml_node_t *) ((xmlNodePtr) node)->next; +} + + +int xml_node_is_element(struct xml_node_ctx *ctx, xml_node_t *node) +{ + return ((xmlNodePtr) node)->type == XML_ELEMENT_NODE; +} + + +char * xml_node_get_text(struct xml_node_ctx *ctx, xml_node_t *node) +{ + if (xmlChildElementCount((xmlNodePtr) node) > 0) + return NULL; + return (char *) xmlNodeGetContent((xmlNodePtr) node); +} + + +void xml_node_get_text_free(struct xml_node_ctx *ctx, char *val) +{ + if (val) + xmlFree((xmlChar *) val); +} + + +char * xml_node_get_base64_text(struct xml_node_ctx *ctx, xml_node_t *node, + int *ret_len) +{ + char *txt; + unsigned char *ret; + size_t len; + + txt = xml_node_get_text(ctx, node); + if (txt == NULL) + return NULL; + + ret = base64_decode((unsigned char *) txt, strlen(txt), &len); + if (ret_len) + *ret_len = len; + xml_node_get_text_free(ctx, txt); + if (ret == NULL) + return NULL; + txt = os_malloc(len + 1); + if (txt == NULL) { + os_free(ret); + return NULL; + } + os_memcpy(txt, ret, len); + txt[len] = '\0'; + return txt; +} + + +xml_node_t * xml_node_copy(struct xml_node_ctx *ctx, xml_node_t *node) +{ + if (node == NULL) + return NULL; + return (xml_node_t *) xmlCopyNode((xmlNodePtr) node, 1); +} + + +struct xml_node_ctx * xml_node_init_ctx(void *upper_ctx, + const void *env) +{ + struct xml_node_ctx *xctx; + + xctx = os_zalloc(sizeof(*xctx)); + if (xctx == NULL) + return NULL; + xctx->ctx = upper_ctx; + + LIBXML_TEST_VERSION + + return xctx; +} + + +void xml_node_deinit_ctx(struct xml_node_ctx *ctx) +{ + xmlSchemaCleanupTypes(); + xmlCleanupParser(); + xmlMemoryDump(); + os_free(ctx); +}