1 /* 2 * XML wrapper for libxml2 3 * Copyright (c) 2012-2013, Qualcomm Atheros, Inc. 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "includes.h" 10 #define LIBXML_VALID_ENABLED 11 #include <libxml/tree.h> 12 #include <libxml/xmlschemastypes.h> 13 14 #include "common.h" 15 #include "base64.h" 16 #include "xml-utils.h" 17 18 19 struct xml_node_ctx { 20 void *ctx; 21 }; 22 23 24 struct str_buf { 25 char *buf; 26 size_t len; 27 }; 28 29 #define MAX_STR 1000 30 31 static void add_str(void *ctx_ptr, const char *fmt, ...) 32 { 33 struct str_buf *str = ctx_ptr; 34 va_list ap; 35 char *n; 36 int len; 37 38 n = os_realloc(str->buf, str->len + MAX_STR + 2); 39 if (n == NULL) 40 return; 41 str->buf = n; 42 43 va_start(ap, fmt); 44 len = vsnprintf(str->buf + str->len, MAX_STR, fmt, ap); 45 va_end(ap); 46 if (len >= MAX_STR) 47 len = MAX_STR - 1; 48 str->len += len; 49 str->buf[str->len] = '\0'; 50 } 51 52 53 int xml_validate(struct xml_node_ctx *ctx, xml_node_t *node, 54 const char *xml_schema_fname, char **ret_err) 55 { 56 xmlDocPtr doc; 57 xmlNodePtr n; 58 xmlSchemaParserCtxtPtr pctx; 59 xmlSchemaValidCtxtPtr vctx; 60 xmlSchemaPtr schema; 61 int ret; 62 struct str_buf errors; 63 64 if (ret_err) 65 *ret_err = NULL; 66 67 doc = xmlNewDoc((xmlChar *) "1.0"); 68 if (doc == NULL) 69 return -1; 70 n = xmlDocCopyNode((xmlNodePtr) node, doc, 1); 71 if (n == NULL) { 72 xmlFreeDoc(doc); 73 return -1; 74 } 75 xmlDocSetRootElement(doc, n); 76 77 os_memset(&errors, 0, sizeof(errors)); 78 79 pctx = xmlSchemaNewParserCtxt(xml_schema_fname); 80 xmlSchemaSetParserErrors(pctx, (xmlSchemaValidityErrorFunc) add_str, 81 (xmlSchemaValidityWarningFunc) add_str, 82 &errors); 83 schema = xmlSchemaParse(pctx); 84 xmlSchemaFreeParserCtxt(pctx); 85 86 vctx = xmlSchemaNewValidCtxt(schema); 87 xmlSchemaSetValidErrors(vctx, (xmlSchemaValidityErrorFunc) add_str, 88 (xmlSchemaValidityWarningFunc) add_str, 89 &errors); 90 91 ret = xmlSchemaValidateDoc(vctx, doc); 92 xmlSchemaFreeValidCtxt(vctx); 93 xmlFreeDoc(doc); 94 xmlSchemaFree(schema); 95 96 if (ret == 0) { 97 os_free(errors.buf); 98 return 0; 99 } else if (ret > 0) { 100 if (ret_err) 101 *ret_err = errors.buf; 102 else 103 os_free(errors.buf); 104 return -1; 105 } else { 106 if (ret_err) 107 *ret_err = errors.buf; 108 else 109 os_free(errors.buf); 110 return -1; 111 } 112 } 113 114 115 int xml_validate_dtd(struct xml_node_ctx *ctx, xml_node_t *node, 116 const char *dtd_fname, char **ret_err) 117 { 118 xmlDocPtr doc; 119 xmlNodePtr n; 120 xmlValidCtxt vctx; 121 xmlDtdPtr dtd; 122 int ret; 123 struct str_buf errors; 124 125 if (ret_err) 126 *ret_err = NULL; 127 128 doc = xmlNewDoc((xmlChar *) "1.0"); 129 if (doc == NULL) 130 return -1; 131 n = xmlDocCopyNode((xmlNodePtr) node, doc, 1); 132 if (n == NULL) { 133 xmlFreeDoc(doc); 134 return -1; 135 } 136 xmlDocSetRootElement(doc, n); 137 138 os_memset(&errors, 0, sizeof(errors)); 139 140 dtd = xmlParseDTD(NULL, (const xmlChar *) dtd_fname); 141 if (dtd == NULL) { 142 xmlFreeDoc(doc); 143 return -1; 144 } 145 146 os_memset(&vctx, 0, sizeof(vctx)); 147 vctx.userData = &errors; 148 vctx.error = add_str; 149 vctx.warning = add_str; 150 ret = xmlValidateDtd(&vctx, doc, dtd); 151 xmlFreeDoc(doc); 152 xmlFreeDtd(dtd); 153 154 if (ret == 1) { 155 os_free(errors.buf); 156 return 0; 157 } else { 158 if (ret_err) 159 *ret_err = errors.buf; 160 else 161 os_free(errors.buf); 162 return -1; 163 } 164 } 165 166 167 void xml_node_free(struct xml_node_ctx *ctx, xml_node_t *node) 168 { 169 xmlFreeNode((xmlNodePtr) node); 170 } 171 172 173 xml_node_t * xml_node_get_parent(struct xml_node_ctx *ctx, xml_node_t *node) 174 { 175 return (xml_node_t *) ((xmlNodePtr) node)->parent; 176 } 177 178 179 xml_node_t * xml_node_from_buf(struct xml_node_ctx *ctx, const char *buf) 180 { 181 xmlDocPtr doc; 182 xmlNodePtr node; 183 184 doc = xmlParseMemory(buf, strlen(buf)); 185 if (doc == NULL) 186 return NULL; 187 node = xmlDocGetRootElement(doc); 188 node = xmlCopyNode(node, 1); 189 xmlFreeDoc(doc); 190 191 return (xml_node_t *) node; 192 } 193 194 195 const char * xml_node_get_localname(struct xml_node_ctx *ctx, 196 xml_node_t *node) 197 { 198 return (const char *) ((xmlNodePtr) node)->name; 199 } 200 201 202 char * xml_node_to_str(struct xml_node_ctx *ctx, xml_node_t *node) 203 { 204 xmlChar *buf; 205 int bufsiz; 206 char *ret, *pos; 207 xmlNodePtr n = (xmlNodePtr) node; 208 xmlDocPtr doc; 209 210 doc = xmlNewDoc((xmlChar *) "1.0"); 211 n = xmlDocCopyNode(n, doc, 1); 212 xmlDocSetRootElement(doc, n); 213 xmlDocDumpFormatMemory(doc, &buf, &bufsiz, 0); 214 xmlFreeDoc(doc); 215 pos = (char *) buf; 216 if (strncmp(pos, "<?xml", 5) == 0) { 217 pos = strchr(pos, '>'); 218 if (pos) 219 pos++; 220 while (pos && (*pos == '\r' || *pos == '\n')) 221 pos++; 222 } 223 if (pos) 224 ret = os_strdup(pos); 225 else 226 ret = NULL; 227 xmlFree(buf); 228 229 if (ret) { 230 pos = ret; 231 if (pos[0]) { 232 while (pos[1]) 233 pos++; 234 } 235 while (pos >= ret && *pos == '\n') 236 *pos-- = '\0'; 237 } 238 239 return ret; 240 } 241 242 243 void xml_node_detach(struct xml_node_ctx *ctx, xml_node_t *node) 244 { 245 xmlUnlinkNode((xmlNodePtr) node); 246 } 247 248 249 void xml_node_add_child(struct xml_node_ctx *ctx, xml_node_t *parent, 250 xml_node_t *child) 251 { 252 xmlAddChild((xmlNodePtr) parent, (xmlNodePtr) child); 253 } 254 255 256 xml_node_t * xml_node_create_root(struct xml_node_ctx *ctx, const char *ns_uri, 257 const char *ns_prefix, 258 xml_namespace_t **ret_ns, const char *name) 259 { 260 xmlNodePtr node; 261 xmlNsPtr ns = NULL; 262 263 node = xmlNewNode(NULL, (const xmlChar *) name); 264 if (node == NULL) 265 return NULL; 266 if (ns_uri) { 267 ns = xmlNewNs(node, (const xmlChar *) ns_uri, 268 (const xmlChar *) ns_prefix); 269 xmlSetNs(node, ns); 270 } 271 272 if (ret_ns) 273 *ret_ns = (xml_namespace_t *) ns; 274 275 return (xml_node_t *) node; 276 } 277 278 279 xml_node_t * xml_node_create(struct xml_node_ctx *ctx, xml_node_t *parent, 280 xml_namespace_t *ns, const char *name) 281 { 282 xmlNodePtr node; 283 node = xmlNewChild((xmlNodePtr) parent, (xmlNsPtr) ns, 284 (const xmlChar *) name, NULL); 285 return (xml_node_t *) node; 286 } 287 288 289 xml_node_t * xml_node_create_text(struct xml_node_ctx *ctx, 290 xml_node_t *parent, xml_namespace_t *ns, 291 const char *name, const char *value) 292 { 293 xmlNodePtr node; 294 node = xmlNewTextChild((xmlNodePtr) parent, (xmlNsPtr) ns, 295 (const xmlChar *) name, (const xmlChar *) value); 296 return (xml_node_t *) node; 297 } 298 299 300 xml_node_t * xml_node_create_text_ns(struct xml_node_ctx *ctx, 301 xml_node_t *parent, const char *ns_uri, 302 const char *name, const char *value) 303 { 304 xmlNodePtr node; 305 xmlNsPtr ns; 306 307 node = xmlNewTextChild((xmlNodePtr) parent, NULL, 308 (const xmlChar *) name, (const xmlChar *) value); 309 ns = xmlNewNs(node, (const xmlChar *) ns_uri, NULL); 310 xmlSetNs(node, ns); 311 return (xml_node_t *) node; 312 } 313 314 315 void xml_node_set_text(struct xml_node_ctx *ctx, xml_node_t *node, 316 const char *value) 317 { 318 /* TODO: escape XML special chars in value */ 319 xmlNodeSetContent((xmlNodePtr) node, (xmlChar *) value); 320 } 321 322 323 int xml_node_add_attr(struct xml_node_ctx *ctx, xml_node_t *node, 324 xml_namespace_t *ns, const char *name, const char *value) 325 { 326 xmlAttrPtr attr; 327 328 if (ns) { 329 attr = xmlNewNsProp((xmlNodePtr) node, (xmlNsPtr) ns, 330 (const xmlChar *) name, 331 (const xmlChar *) value); 332 } else { 333 attr = xmlNewProp((xmlNodePtr) node, (const xmlChar *) name, 334 (const xmlChar *) value); 335 } 336 337 return attr ? 0 : -1; 338 } 339 340 341 char * xml_node_get_attr_value(struct xml_node_ctx *ctx, xml_node_t *node, 342 char *name) 343 { 344 return (char *) xmlGetNoNsProp((xmlNodePtr) node, 345 (const xmlChar *) name); 346 } 347 348 349 char * xml_node_get_attr_value_ns(struct xml_node_ctx *ctx, xml_node_t *node, 350 const char *ns_uri, char *name) 351 { 352 return (char *) xmlGetNsProp((xmlNodePtr) node, (const xmlChar *) name, 353 (const xmlChar *) ns_uri); 354 } 355 356 357 void xml_node_get_attr_value_free(struct xml_node_ctx *ctx, char *val) 358 { 359 if (val) 360 xmlFree((xmlChar *) val); 361 } 362 363 364 xml_node_t * xml_node_first_child(struct xml_node_ctx *ctx, 365 xml_node_t *parent) 366 { 367 return (xml_node_t *) ((xmlNodePtr) parent)->children; 368 } 369 370 371 xml_node_t * xml_node_next_sibling(struct xml_node_ctx *ctx, 372 xml_node_t *node) 373 { 374 return (xml_node_t *) ((xmlNodePtr) node)->next; 375 } 376 377 378 int xml_node_is_element(struct xml_node_ctx *ctx, xml_node_t *node) 379 { 380 return ((xmlNodePtr) node)->type == XML_ELEMENT_NODE; 381 } 382 383 384 char * xml_node_get_text(struct xml_node_ctx *ctx, xml_node_t *node) 385 { 386 if (xmlChildElementCount((xmlNodePtr) node) > 0) 387 return NULL; 388 return (char *) xmlNodeGetContent((xmlNodePtr) node); 389 } 390 391 392 void xml_node_get_text_free(struct xml_node_ctx *ctx, char *val) 393 { 394 if (val) 395 xmlFree((xmlChar *) val); 396 } 397 398 399 char * xml_node_get_base64_text(struct xml_node_ctx *ctx, xml_node_t *node, 400 int *ret_len) 401 { 402 char *txt; 403 unsigned char *ret; 404 size_t len; 405 406 txt = xml_node_get_text(ctx, node); 407 if (txt == NULL) 408 return NULL; 409 410 ret = base64_decode((unsigned char *) txt, strlen(txt), &len); 411 if (ret_len) 412 *ret_len = len; 413 xml_node_get_text_free(ctx, txt); 414 if (ret == NULL) 415 return NULL; 416 txt = os_malloc(len + 1); 417 if (txt == NULL) { 418 os_free(ret); 419 return NULL; 420 } 421 os_memcpy(txt, ret, len); 422 txt[len] = '\0'; 423 return txt; 424 } 425 426 427 xml_node_t * xml_node_copy(struct xml_node_ctx *ctx, xml_node_t *node) 428 { 429 if (node == NULL) 430 return NULL; 431 return (xml_node_t *) xmlCopyNode((xmlNodePtr) node, 1); 432 } 433 434 435 struct xml_node_ctx * xml_node_init_ctx(void *upper_ctx, 436 const void *env) 437 { 438 struct xml_node_ctx *xctx; 439 440 xctx = os_zalloc(sizeof(*xctx)); 441 if (xctx == NULL) 442 return NULL; 443 xctx->ctx = upper_ctx; 444 445 LIBXML_TEST_VERSION 446 447 return xctx; 448 } 449 450 451 void xml_node_deinit_ctx(struct xml_node_ctx *ctx) 452 { 453 xmlSchemaCleanupTypes(); 454 xmlCleanupParser(); 455 xmlMemoryDump(); 456 os_free(ctx); 457 } 458