13c260e60Schristos /* 23c260e60Schristos * XML wrapper for libxml2 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 #define LIBXML_VALID_ENABLED 113c260e60Schristos #include <libxml/tree.h> 123c260e60Schristos #include <libxml/xmlschemastypes.h> 133c260e60Schristos 143c260e60Schristos #include "common.h" 153c260e60Schristos #include "base64.h" 163c260e60Schristos #include "xml-utils.h" 173c260e60Schristos 183c260e60Schristos 193c260e60Schristos struct xml_node_ctx { 203c260e60Schristos void *ctx; 213c260e60Schristos }; 223c260e60Schristos 233c260e60Schristos 243c260e60Schristos struct str_buf { 253c260e60Schristos char *buf; 263c260e60Schristos size_t len; 273c260e60Schristos }; 283c260e60Schristos 293c260e60Schristos #define MAX_STR 1000 303c260e60Schristos 313c260e60Schristos static void add_str(void *ctx_ptr, const char *fmt, ...) 323c260e60Schristos { 333c260e60Schristos struct str_buf *str = ctx_ptr; 343c260e60Schristos va_list ap; 353c260e60Schristos char *n; 363c260e60Schristos int len; 373c260e60Schristos 383c260e60Schristos n = os_realloc(str->buf, str->len + MAX_STR + 2); 393c260e60Schristos if (n == NULL) 403c260e60Schristos return; 413c260e60Schristos str->buf = n; 423c260e60Schristos 433c260e60Schristos va_start(ap, fmt); 443c260e60Schristos len = vsnprintf(str->buf + str->len, MAX_STR, fmt, ap); 453c260e60Schristos va_end(ap); 463c260e60Schristos if (len >= MAX_STR) 473c260e60Schristos len = MAX_STR - 1; 483c260e60Schristos str->len += len; 493c260e60Schristos str->buf[str->len] = '\0'; 503c260e60Schristos } 513c260e60Schristos 523c260e60Schristos 533c260e60Schristos int xml_validate(struct xml_node_ctx *ctx, xml_node_t *node, 543c260e60Schristos const char *xml_schema_fname, char **ret_err) 553c260e60Schristos { 563c260e60Schristos xmlDocPtr doc; 573c260e60Schristos xmlNodePtr n; 583c260e60Schristos xmlSchemaParserCtxtPtr pctx; 593c260e60Schristos xmlSchemaValidCtxtPtr vctx; 603c260e60Schristos xmlSchemaPtr schema; 613c260e60Schristos int ret; 623c260e60Schristos struct str_buf errors; 633c260e60Schristos 643c260e60Schristos if (ret_err) 653c260e60Schristos *ret_err = NULL; 663c260e60Schristos 673c260e60Schristos doc = xmlNewDoc((xmlChar *) "1.0"); 683c260e60Schristos if (doc == NULL) 693c260e60Schristos return -1; 703c260e60Schristos n = xmlDocCopyNode((xmlNodePtr) node, doc, 1); 713c260e60Schristos if (n == NULL) { 723c260e60Schristos xmlFreeDoc(doc); 733c260e60Schristos return -1; 743c260e60Schristos } 753c260e60Schristos xmlDocSetRootElement(doc, n); 763c260e60Schristos 773c260e60Schristos os_memset(&errors, 0, sizeof(errors)); 783c260e60Schristos 793c260e60Schristos pctx = xmlSchemaNewParserCtxt(xml_schema_fname); 803c260e60Schristos xmlSchemaSetParserErrors(pctx, (xmlSchemaValidityErrorFunc) add_str, 813c260e60Schristos (xmlSchemaValidityWarningFunc) add_str, 823c260e60Schristos &errors); 833c260e60Schristos schema = xmlSchemaParse(pctx); 843c260e60Schristos xmlSchemaFreeParserCtxt(pctx); 853c260e60Schristos 863c260e60Schristos vctx = xmlSchemaNewValidCtxt(schema); 873c260e60Schristos xmlSchemaSetValidErrors(vctx, (xmlSchemaValidityErrorFunc) add_str, 883c260e60Schristos (xmlSchemaValidityWarningFunc) add_str, 893c260e60Schristos &errors); 903c260e60Schristos 913c260e60Schristos ret = xmlSchemaValidateDoc(vctx, doc); 923c260e60Schristos xmlSchemaFreeValidCtxt(vctx); 933c260e60Schristos xmlFreeDoc(doc); 943c260e60Schristos xmlSchemaFree(schema); 953c260e60Schristos 963c260e60Schristos if (ret == 0) { 973c260e60Schristos os_free(errors.buf); 983c260e60Schristos return 0; 993c260e60Schristos } else if (ret > 0) { 1003c260e60Schristos if (ret_err) 1013c260e60Schristos *ret_err = errors.buf; 1023c260e60Schristos else 1033c260e60Schristos os_free(errors.buf); 1043c260e60Schristos return -1; 1053c260e60Schristos } else { 1063c260e60Schristos if (ret_err) 1073c260e60Schristos *ret_err = errors.buf; 1083c260e60Schristos else 1093c260e60Schristos os_free(errors.buf); 1103c260e60Schristos return -1; 1113c260e60Schristos } 1123c260e60Schristos } 1133c260e60Schristos 1143c260e60Schristos 1153c260e60Schristos int xml_validate_dtd(struct xml_node_ctx *ctx, xml_node_t *node, 1163c260e60Schristos const char *dtd_fname, char **ret_err) 1173c260e60Schristos { 1183c260e60Schristos xmlDocPtr doc; 1193c260e60Schristos xmlNodePtr n; 1203c260e60Schristos xmlValidCtxt vctx; 1213c260e60Schristos xmlDtdPtr dtd; 1223c260e60Schristos int ret; 1233c260e60Schristos struct str_buf errors; 1243c260e60Schristos 1253c260e60Schristos if (ret_err) 1263c260e60Schristos *ret_err = NULL; 1273c260e60Schristos 1283c260e60Schristos doc = xmlNewDoc((xmlChar *) "1.0"); 1293c260e60Schristos if (doc == NULL) 1303c260e60Schristos return -1; 1313c260e60Schristos n = xmlDocCopyNode((xmlNodePtr) node, doc, 1); 1323c260e60Schristos if (n == NULL) { 1333c260e60Schristos xmlFreeDoc(doc); 1343c260e60Schristos return -1; 1353c260e60Schristos } 1363c260e60Schristos xmlDocSetRootElement(doc, n); 1373c260e60Schristos 1383c260e60Schristos os_memset(&errors, 0, sizeof(errors)); 1393c260e60Schristos 1403c260e60Schristos dtd = xmlParseDTD(NULL, (const xmlChar *) dtd_fname); 1413c260e60Schristos if (dtd == NULL) { 1423c260e60Schristos xmlFreeDoc(doc); 1433c260e60Schristos return -1; 1443c260e60Schristos } 1453c260e60Schristos 1463c260e60Schristos os_memset(&vctx, 0, sizeof(vctx)); 1473c260e60Schristos vctx.userData = &errors; 1483c260e60Schristos vctx.error = add_str; 1493c260e60Schristos vctx.warning = add_str; 1503c260e60Schristos ret = xmlValidateDtd(&vctx, doc, dtd); 1513c260e60Schristos xmlFreeDoc(doc); 1523c260e60Schristos xmlFreeDtd(dtd); 1533c260e60Schristos 1543c260e60Schristos if (ret == 1) { 1553c260e60Schristos os_free(errors.buf); 1563c260e60Schristos return 0; 1573c260e60Schristos } else { 1583c260e60Schristos if (ret_err) 1593c260e60Schristos *ret_err = errors.buf; 1603c260e60Schristos else 1613c260e60Schristos os_free(errors.buf); 1623c260e60Schristos return -1; 1633c260e60Schristos } 1643c260e60Schristos } 1653c260e60Schristos 1663c260e60Schristos 1673c260e60Schristos void xml_node_free(struct xml_node_ctx *ctx, xml_node_t *node) 1683c260e60Schristos { 1693c260e60Schristos xmlFreeNode((xmlNodePtr) node); 1703c260e60Schristos } 1713c260e60Schristos 1723c260e60Schristos 1733c260e60Schristos xml_node_t * xml_node_get_parent(struct xml_node_ctx *ctx, xml_node_t *node) 1743c260e60Schristos { 1753c260e60Schristos return (xml_node_t *) ((xmlNodePtr) node)->parent; 1763c260e60Schristos } 1773c260e60Schristos 1783c260e60Schristos 1793c260e60Schristos xml_node_t * xml_node_from_buf(struct xml_node_ctx *ctx, const char *buf) 1803c260e60Schristos { 1813c260e60Schristos xmlDocPtr doc; 1823c260e60Schristos xmlNodePtr node; 1833c260e60Schristos 1843c260e60Schristos doc = xmlParseMemory(buf, strlen(buf)); 1853c260e60Schristos if (doc == NULL) 1863c260e60Schristos return NULL; 1873c260e60Schristos node = xmlDocGetRootElement(doc); 1883c260e60Schristos node = xmlCopyNode(node, 1); 1893c260e60Schristos xmlFreeDoc(doc); 1903c260e60Schristos 1913c260e60Schristos return (xml_node_t *) node; 1923c260e60Schristos } 1933c260e60Schristos 1943c260e60Schristos 1953c260e60Schristos const char * xml_node_get_localname(struct xml_node_ctx *ctx, 1963c260e60Schristos xml_node_t *node) 1973c260e60Schristos { 1983c260e60Schristos return (const char *) ((xmlNodePtr) node)->name; 1993c260e60Schristos } 2003c260e60Schristos 2013c260e60Schristos 2023c260e60Schristos char * xml_node_to_str(struct xml_node_ctx *ctx, xml_node_t *node) 2033c260e60Schristos { 2043c260e60Schristos xmlChar *buf; 2053c260e60Schristos int bufsiz; 2063c260e60Schristos char *ret, *pos; 2073c260e60Schristos xmlNodePtr n = (xmlNodePtr) node; 2083c260e60Schristos xmlDocPtr doc; 2093c260e60Schristos 2103c260e60Schristos doc = xmlNewDoc((xmlChar *) "1.0"); 2113c260e60Schristos n = xmlDocCopyNode(n, doc, 1); 2123c260e60Schristos xmlDocSetRootElement(doc, n); 2133c260e60Schristos xmlDocDumpFormatMemory(doc, &buf, &bufsiz, 0); 2143c260e60Schristos xmlFreeDoc(doc); 21536ebd06eSchristos if (!buf) 21636ebd06eSchristos return NULL; 2173c260e60Schristos pos = (char *) buf; 2183c260e60Schristos if (strncmp(pos, "<?xml", 5) == 0) { 2193c260e60Schristos pos = strchr(pos, '>'); 2203c260e60Schristos if (pos) 2213c260e60Schristos pos++; 2223c260e60Schristos while (pos && (*pos == '\r' || *pos == '\n')) 2233c260e60Schristos pos++; 2243c260e60Schristos } 2253c260e60Schristos if (pos) 2263c260e60Schristos ret = os_strdup(pos); 2273c260e60Schristos else 2283c260e60Schristos ret = NULL; 2293c260e60Schristos xmlFree(buf); 2303c260e60Schristos 2313c260e60Schristos if (ret) { 2323c260e60Schristos pos = ret; 2333c260e60Schristos if (pos[0]) { 2343c260e60Schristos while (pos[1]) 2353c260e60Schristos pos++; 2363c260e60Schristos } 2373c260e60Schristos while (pos >= ret && *pos == '\n') 2383c260e60Schristos *pos-- = '\0'; 2393c260e60Schristos } 2403c260e60Schristos 2413c260e60Schristos return ret; 2423c260e60Schristos } 2433c260e60Schristos 2443c260e60Schristos 2453c260e60Schristos void xml_node_detach(struct xml_node_ctx *ctx, xml_node_t *node) 2463c260e60Schristos { 2473c260e60Schristos xmlUnlinkNode((xmlNodePtr) node); 2483c260e60Schristos } 2493c260e60Schristos 2503c260e60Schristos 2513c260e60Schristos void xml_node_add_child(struct xml_node_ctx *ctx, xml_node_t *parent, 2523c260e60Schristos xml_node_t *child) 2533c260e60Schristos { 2543c260e60Schristos xmlAddChild((xmlNodePtr) parent, (xmlNodePtr) child); 2553c260e60Schristos } 2563c260e60Schristos 2573c260e60Schristos 2583c260e60Schristos xml_node_t * xml_node_create_root(struct xml_node_ctx *ctx, const char *ns_uri, 2593c260e60Schristos const char *ns_prefix, 2603c260e60Schristos xml_namespace_t **ret_ns, const char *name) 2613c260e60Schristos { 2623c260e60Schristos xmlNodePtr node; 2633c260e60Schristos xmlNsPtr ns = NULL; 2643c260e60Schristos 2653c260e60Schristos node = xmlNewNode(NULL, (const xmlChar *) name); 2663c260e60Schristos if (node == NULL) 2673c260e60Schristos return NULL; 2683c260e60Schristos if (ns_uri) { 2693c260e60Schristos ns = xmlNewNs(node, (const xmlChar *) ns_uri, 2703c260e60Schristos (const xmlChar *) ns_prefix); 2713c260e60Schristos xmlSetNs(node, ns); 2723c260e60Schristos } 2733c260e60Schristos 2743c260e60Schristos if (ret_ns) 2753c260e60Schristos *ret_ns = (xml_namespace_t *) ns; 2763c260e60Schristos 2773c260e60Schristos return (xml_node_t *) node; 2783c260e60Schristos } 2793c260e60Schristos 2803c260e60Schristos 2813c260e60Schristos xml_node_t * xml_node_create(struct xml_node_ctx *ctx, xml_node_t *parent, 2823c260e60Schristos xml_namespace_t *ns, const char *name) 2833c260e60Schristos { 2843c260e60Schristos xmlNodePtr node; 2853c260e60Schristos node = xmlNewChild((xmlNodePtr) parent, (xmlNsPtr) ns, 2863c260e60Schristos (const xmlChar *) name, NULL); 2873c260e60Schristos return (xml_node_t *) node; 2883c260e60Schristos } 2893c260e60Schristos 2903c260e60Schristos 2913c260e60Schristos xml_node_t * xml_node_create_text(struct xml_node_ctx *ctx, 2923c260e60Schristos xml_node_t *parent, xml_namespace_t *ns, 2933c260e60Schristos const char *name, const char *value) 2943c260e60Schristos { 2953c260e60Schristos xmlNodePtr node; 2963c260e60Schristos node = xmlNewTextChild((xmlNodePtr) parent, (xmlNsPtr) ns, 2973c260e60Schristos (const xmlChar *) name, (const xmlChar *) value); 2983c260e60Schristos return (xml_node_t *) node; 2993c260e60Schristos } 3003c260e60Schristos 3013c260e60Schristos 3023c260e60Schristos xml_node_t * xml_node_create_text_ns(struct xml_node_ctx *ctx, 3033c260e60Schristos xml_node_t *parent, const char *ns_uri, 3043c260e60Schristos const char *name, const char *value) 3053c260e60Schristos { 3063c260e60Schristos xmlNodePtr node; 3073c260e60Schristos xmlNsPtr ns; 3083c260e60Schristos 3093c260e60Schristos node = xmlNewTextChild((xmlNodePtr) parent, NULL, 3103c260e60Schristos (const xmlChar *) name, (const xmlChar *) value); 3113c260e60Schristos ns = xmlNewNs(node, (const xmlChar *) ns_uri, NULL); 3123c260e60Schristos xmlSetNs(node, ns); 3133c260e60Schristos return (xml_node_t *) node; 3143c260e60Schristos } 3153c260e60Schristos 3163c260e60Schristos 3173c260e60Schristos void xml_node_set_text(struct xml_node_ctx *ctx, xml_node_t *node, 3183c260e60Schristos const char *value) 3193c260e60Schristos { 3203c260e60Schristos /* TODO: escape XML special chars in value */ 3213c260e60Schristos xmlNodeSetContent((xmlNodePtr) node, (xmlChar *) value); 3223c260e60Schristos } 3233c260e60Schristos 3243c260e60Schristos 3253c260e60Schristos int xml_node_add_attr(struct xml_node_ctx *ctx, xml_node_t *node, 3263c260e60Schristos xml_namespace_t *ns, const char *name, const char *value) 3273c260e60Schristos { 3283c260e60Schristos xmlAttrPtr attr; 3293c260e60Schristos 3303c260e60Schristos if (ns) { 3313c260e60Schristos attr = xmlNewNsProp((xmlNodePtr) node, (xmlNsPtr) ns, 3323c260e60Schristos (const xmlChar *) name, 3333c260e60Schristos (const xmlChar *) value); 3343c260e60Schristos } else { 3353c260e60Schristos attr = xmlNewProp((xmlNodePtr) node, (const xmlChar *) name, 3363c260e60Schristos (const xmlChar *) value); 3373c260e60Schristos } 3383c260e60Schristos 3393c260e60Schristos return attr ? 0 : -1; 3403c260e60Schristos } 3413c260e60Schristos 3423c260e60Schristos 3433c260e60Schristos char * xml_node_get_attr_value(struct xml_node_ctx *ctx, xml_node_t *node, 3443c260e60Schristos char *name) 3453c260e60Schristos { 3463c260e60Schristos return (char *) xmlGetNoNsProp((xmlNodePtr) node, 3473c260e60Schristos (const xmlChar *) name); 3483c260e60Schristos } 3493c260e60Schristos 3503c260e60Schristos 3513c260e60Schristos char * xml_node_get_attr_value_ns(struct xml_node_ctx *ctx, xml_node_t *node, 3523c260e60Schristos const char *ns_uri, char *name) 3533c260e60Schristos { 3543c260e60Schristos return (char *) xmlGetNsProp((xmlNodePtr) node, (const xmlChar *) name, 3553c260e60Schristos (const xmlChar *) ns_uri); 3563c260e60Schristos } 3573c260e60Schristos 3583c260e60Schristos 3593c260e60Schristos void xml_node_get_attr_value_free(struct xml_node_ctx *ctx, char *val) 3603c260e60Schristos { 3613c260e60Schristos if (val) 3623c260e60Schristos xmlFree((xmlChar *) val); 3633c260e60Schristos } 3643c260e60Schristos 3653c260e60Schristos 3663c260e60Schristos xml_node_t * xml_node_first_child(struct xml_node_ctx *ctx, 3673c260e60Schristos xml_node_t *parent) 3683c260e60Schristos { 3693c260e60Schristos return (xml_node_t *) ((xmlNodePtr) parent)->children; 3703c260e60Schristos } 3713c260e60Schristos 3723c260e60Schristos 3733c260e60Schristos xml_node_t * xml_node_next_sibling(struct xml_node_ctx *ctx, 3743c260e60Schristos xml_node_t *node) 3753c260e60Schristos { 3763c260e60Schristos return (xml_node_t *) ((xmlNodePtr) node)->next; 3773c260e60Schristos } 3783c260e60Schristos 3793c260e60Schristos 3803c260e60Schristos int xml_node_is_element(struct xml_node_ctx *ctx, xml_node_t *node) 3813c260e60Schristos { 3823c260e60Schristos return ((xmlNodePtr) node)->type == XML_ELEMENT_NODE; 3833c260e60Schristos } 3843c260e60Schristos 3853c260e60Schristos 3863c260e60Schristos char * xml_node_get_text(struct xml_node_ctx *ctx, xml_node_t *node) 3873c260e60Schristos { 3883c260e60Schristos if (xmlChildElementCount((xmlNodePtr) node) > 0) 3893c260e60Schristos return NULL; 3903c260e60Schristos return (char *) xmlNodeGetContent((xmlNodePtr) node); 3913c260e60Schristos } 3923c260e60Schristos 3933c260e60Schristos 3943c260e60Schristos void xml_node_get_text_free(struct xml_node_ctx *ctx, char *val) 3953c260e60Schristos { 3963c260e60Schristos if (val) 3973c260e60Schristos xmlFree((xmlChar *) val); 3983c260e60Schristos } 3993c260e60Schristos 4003c260e60Schristos 4013c260e60Schristos char * xml_node_get_base64_text(struct xml_node_ctx *ctx, xml_node_t *node, 4023c260e60Schristos int *ret_len) 4033c260e60Schristos { 4043c260e60Schristos char *txt; 4053c260e60Schristos unsigned char *ret; 4063c260e60Schristos size_t len; 4073c260e60Schristos 4083c260e60Schristos txt = xml_node_get_text(ctx, node); 4093c260e60Schristos if (txt == NULL) 4103c260e60Schristos return NULL; 4113c260e60Schristos 412*bb618362Schristos ret = base64_decode(txt, strlen(txt), &len); 4133c260e60Schristos if (ret_len) 4143c260e60Schristos *ret_len = len; 4153c260e60Schristos xml_node_get_text_free(ctx, txt); 4163c260e60Schristos if (ret == NULL) 4173c260e60Schristos return NULL; 4183c260e60Schristos txt = os_malloc(len + 1); 4193c260e60Schristos if (txt == NULL) { 4203c260e60Schristos os_free(ret); 4213c260e60Schristos return NULL; 4223c260e60Schristos } 4233c260e60Schristos os_memcpy(txt, ret, len); 4243c260e60Schristos txt[len] = '\0'; 4253c260e60Schristos return txt; 4263c260e60Schristos } 4273c260e60Schristos 4283c260e60Schristos 4293c260e60Schristos xml_node_t * xml_node_copy(struct xml_node_ctx *ctx, xml_node_t *node) 4303c260e60Schristos { 4313c260e60Schristos if (node == NULL) 4323c260e60Schristos return NULL; 4333c260e60Schristos return (xml_node_t *) xmlCopyNode((xmlNodePtr) node, 1); 4343c260e60Schristos } 4353c260e60Schristos 4363c260e60Schristos 4373c260e60Schristos struct xml_node_ctx * xml_node_init_ctx(void *upper_ctx, 4383c260e60Schristos const void *env) 4393c260e60Schristos { 4403c260e60Schristos struct xml_node_ctx *xctx; 4413c260e60Schristos 4423c260e60Schristos xctx = os_zalloc(sizeof(*xctx)); 4433c260e60Schristos if (xctx == NULL) 4443c260e60Schristos return NULL; 4453c260e60Schristos xctx->ctx = upper_ctx; 4463c260e60Schristos 4473c260e60Schristos LIBXML_TEST_VERSION 4483c260e60Schristos 4493c260e60Schristos return xctx; 4503c260e60Schristos } 4513c260e60Schristos 4523c260e60Schristos 4533c260e60Schristos void xml_node_deinit_ctx(struct xml_node_ctx *ctx) 4543c260e60Schristos { 4553c260e60Schristos xmlSchemaCleanupTypes(); 4563c260e60Schristos xmlCleanupParser(); 4573c260e60Schristos xmlMemoryDump(); 4583c260e60Schristos os_free(ctx); 4593c260e60Schristos } 460