1281681Srpaulo/* 2281681Srpaulo * Generic XML helper functions 3281681Srpaulo * Copyright (c) 2012-2013, Qualcomm Atheros, Inc. 4281681Srpaulo * 5281681Srpaulo * This software may be distributed under the terms of the BSD license. 6281681Srpaulo * See README for more details. 7281681Srpaulo */ 8281681Srpaulo 9281681Srpaulo#include "includes.h" 10281681Srpaulo 11281681Srpaulo#include "common.h" 12281681Srpaulo#include "xml-utils.h" 13281681Srpaulo 14281681Srpaulo 15281681Srpaulostatic xml_node_t * get_node_uri_iter(struct xml_node_ctx *ctx, 16281681Srpaulo xml_node_t *root, char *uri) 17281681Srpaulo{ 18281681Srpaulo char *end; 19281681Srpaulo xml_node_t *node; 20281681Srpaulo const char *name; 21281681Srpaulo 22281681Srpaulo end = strchr(uri, '/'); 23281681Srpaulo if (end) 24281681Srpaulo *end++ = '\0'; 25281681Srpaulo 26281681Srpaulo node = root; 27281681Srpaulo xml_node_for_each_sibling(ctx, node) { 28281681Srpaulo xml_node_for_each_check(ctx, node); 29281681Srpaulo name = xml_node_get_localname(ctx, node); 30281681Srpaulo if (strcasecmp(name, uri) == 0) 31281681Srpaulo break; 32281681Srpaulo } 33281681Srpaulo 34281681Srpaulo if (node == NULL) 35281681Srpaulo return NULL; 36281681Srpaulo 37281681Srpaulo if (end) { 38281681Srpaulo return get_node_uri_iter(ctx, xml_node_first_child(ctx, node), 39281681Srpaulo end); 40281681Srpaulo } 41281681Srpaulo 42281681Srpaulo return node; 43281681Srpaulo} 44281681Srpaulo 45281681Srpaulo 46281681Srpauloxml_node_t * get_node_uri(struct xml_node_ctx *ctx, xml_node_t *root, 47281681Srpaulo const char *uri) 48281681Srpaulo{ 49281681Srpaulo char *search; 50281681Srpaulo xml_node_t *node; 51281681Srpaulo 52281681Srpaulo search = os_strdup(uri); 53281681Srpaulo if (search == NULL) 54281681Srpaulo return NULL; 55281681Srpaulo 56281681Srpaulo node = get_node_uri_iter(ctx, root, search); 57281681Srpaulo 58281681Srpaulo os_free(search); 59281681Srpaulo return node; 60281681Srpaulo} 61281681Srpaulo 62281681Srpaulo 63281681Srpaulostatic xml_node_t * get_node_iter(struct xml_node_ctx *ctx, 64281681Srpaulo xml_node_t *root, const char *path) 65281681Srpaulo{ 66281681Srpaulo char *end; 67281681Srpaulo xml_node_t *node; 68281681Srpaulo const char *name; 69281681Srpaulo 70281681Srpaulo end = os_strchr(path, '/'); 71281681Srpaulo if (end) 72281681Srpaulo *end++ = '\0'; 73281681Srpaulo 74281681Srpaulo xml_node_for_each_child(ctx, node, root) { 75281681Srpaulo xml_node_for_each_check(ctx, node); 76281681Srpaulo name = xml_node_get_localname(ctx, node); 77281681Srpaulo if (os_strcasecmp(name, path) == 0) 78281681Srpaulo break; 79281681Srpaulo } 80281681Srpaulo 81281681Srpaulo if (node == NULL) 82281681Srpaulo return NULL; 83281681Srpaulo if (end) 84281681Srpaulo return get_node_iter(ctx, node, end); 85281681Srpaulo return node; 86281681Srpaulo} 87281681Srpaulo 88281681Srpaulo 89281681Srpauloxml_node_t * get_node(struct xml_node_ctx *ctx, xml_node_t *root, 90281681Srpaulo const char *path) 91281681Srpaulo{ 92281681Srpaulo char *search; 93281681Srpaulo xml_node_t *node; 94281681Srpaulo 95281681Srpaulo search = os_strdup(path); 96281681Srpaulo if (search == NULL) 97281681Srpaulo return NULL; 98281681Srpaulo 99281681Srpaulo node = get_node_iter(ctx, root, search); 100281681Srpaulo 101281681Srpaulo os_free(search); 102281681Srpaulo return node; 103281681Srpaulo} 104281681Srpaulo 105281681Srpaulo 106281681Srpauloxml_node_t * get_child_node(struct xml_node_ctx *ctx, xml_node_t *root, 107281681Srpaulo const char *path) 108281681Srpaulo{ 109281681Srpaulo xml_node_t *node; 110281681Srpaulo xml_node_t *match; 111281681Srpaulo 112281681Srpaulo xml_node_for_each_child(ctx, node, root) { 113281681Srpaulo xml_node_for_each_check(ctx, node); 114281681Srpaulo match = get_node(ctx, node, path); 115281681Srpaulo if (match) 116281681Srpaulo return match; 117281681Srpaulo } 118281681Srpaulo 119281681Srpaulo return NULL; 120281681Srpaulo} 121281681Srpaulo 122281681Srpaulo 123281681Srpauloxml_node_t * node_from_file(struct xml_node_ctx *ctx, const char *name) 124281681Srpaulo{ 125281681Srpaulo xml_node_t *node; 126281681Srpaulo char *buf, *buf2, *start; 127281681Srpaulo size_t len; 128281681Srpaulo 129281681Srpaulo buf = os_readfile(name, &len); 130281681Srpaulo if (buf == NULL) 131281681Srpaulo return NULL; 132281681Srpaulo buf2 = os_realloc(buf, len + 1); 133281681Srpaulo if (buf2 == NULL) { 134281681Srpaulo os_free(buf); 135281681Srpaulo return NULL; 136281681Srpaulo } 137281681Srpaulo buf = buf2; 138281681Srpaulo buf[len] = '\0'; 139281681Srpaulo 140281681Srpaulo start = os_strstr(buf, "<!DOCTYPE "); 141281681Srpaulo if (start) { 142281681Srpaulo char *pos = start + 1; 143281681Srpaulo int count = 1; 144281681Srpaulo while (*pos) { 145281681Srpaulo if (*pos == '<') 146281681Srpaulo count++; 147281681Srpaulo else if (*pos == '>') { 148281681Srpaulo count--; 149281681Srpaulo if (count == 0) { 150281681Srpaulo pos++; 151281681Srpaulo break; 152281681Srpaulo } 153281681Srpaulo } 154281681Srpaulo pos++; 155281681Srpaulo } 156281681Srpaulo if (count == 0) { 157281681Srpaulo /* Remove DOCTYPE to allow the file to be parsed */ 158281681Srpaulo os_memset(start, ' ', pos - start); 159281681Srpaulo } 160281681Srpaulo } 161281681Srpaulo 162281681Srpaulo node = xml_node_from_buf(ctx, buf); 163281681Srpaulo os_free(buf); 164281681Srpaulo 165281681Srpaulo return node; 166281681Srpaulo} 167281681Srpaulo 168281681Srpaulo 169281681Srpauloint node_to_file(struct xml_node_ctx *ctx, const char *fname, xml_node_t *node) 170281681Srpaulo{ 171281681Srpaulo FILE *f; 172281681Srpaulo char *str; 173281681Srpaulo 174281681Srpaulo str = xml_node_to_str(ctx, node); 175281681Srpaulo if (str == NULL) 176281681Srpaulo return -1; 177281681Srpaulo 178281681Srpaulo f = fopen(fname, "w"); 179281681Srpaulo if (!f) { 180281681Srpaulo os_free(str); 181281681Srpaulo return -1; 182281681Srpaulo } 183281681Srpaulo 184281681Srpaulo fprintf(f, "%s\n", str); 185281681Srpaulo os_free(str); 186281681Srpaulo fclose(f); 187281681Srpaulo 188281681Srpaulo return 0; 189281681Srpaulo} 190281681Srpaulo 191281681Srpaulo 192281681Srpaulostatic char * get_val(struct xml_node_ctx *ctx, xml_node_t *node) 193281681Srpaulo{ 194281681Srpaulo char *val, *pos; 195281681Srpaulo 196281681Srpaulo val = xml_node_get_text(ctx, node); 197281681Srpaulo if (val == NULL) 198281681Srpaulo return NULL; 199281681Srpaulo pos = val; 200281681Srpaulo while (*pos) { 201281681Srpaulo if (*pos != ' ' && *pos != '\t' && *pos != '\r' && *pos != '\n') 202281681Srpaulo return val; 203281681Srpaulo pos++; 204281681Srpaulo } 205281681Srpaulo 206281681Srpaulo return NULL; 207281681Srpaulo} 208281681Srpaulo 209281681Srpaulo 210281681Srpaulostatic char * add_path(const char *prev, const char *leaf) 211281681Srpaulo{ 212281681Srpaulo size_t len; 213281681Srpaulo char *new_uri; 214281681Srpaulo 215281681Srpaulo if (prev == NULL) 216281681Srpaulo return NULL; 217281681Srpaulo 218281681Srpaulo len = os_strlen(prev) + 1 + os_strlen(leaf) + 1; 219281681Srpaulo new_uri = os_malloc(len); 220281681Srpaulo if (new_uri) 221281681Srpaulo os_snprintf(new_uri, len, "%s/%s", prev, leaf); 222281681Srpaulo 223281681Srpaulo return new_uri; 224281681Srpaulo} 225281681Srpaulo 226281681Srpaulo 227281681Srpaulostatic void node_to_tnds(struct xml_node_ctx *ctx, xml_node_t *out, 228281681Srpaulo xml_node_t *in, const char *uri) 229281681Srpaulo{ 230281681Srpaulo xml_node_t *node; 231281681Srpaulo xml_node_t *tnds; 232281681Srpaulo const char *name; 233281681Srpaulo char *val; 234281681Srpaulo char *new_uri; 235281681Srpaulo 236281681Srpaulo xml_node_for_each_child(ctx, node, in) { 237281681Srpaulo xml_node_for_each_check(ctx, node); 238281681Srpaulo name = xml_node_get_localname(ctx, node); 239281681Srpaulo 240281681Srpaulo tnds = xml_node_create(ctx, out, NULL, "Node"); 241281681Srpaulo if (tnds == NULL) 242281681Srpaulo return; 243281681Srpaulo xml_node_create_text(ctx, tnds, NULL, "NodeName", name); 244281681Srpaulo 245281681Srpaulo if (uri) 246281681Srpaulo xml_node_create_text(ctx, tnds, NULL, "Path", uri); 247281681Srpaulo 248281681Srpaulo val = get_val(ctx, node); 249281681Srpaulo if (val) { 250281681Srpaulo xml_node_create_text(ctx, tnds, NULL, "Value", val); 251281681Srpaulo xml_node_get_text_free(ctx, val); 252281681Srpaulo } 253281681Srpaulo 254281681Srpaulo new_uri = add_path(uri, name); 255281681Srpaulo node_to_tnds(ctx, new_uri ? out : tnds, node, new_uri); 256281681Srpaulo os_free(new_uri); 257281681Srpaulo } 258281681Srpaulo} 259281681Srpaulo 260281681Srpaulo 261281681Srpaulostatic int add_ddfname(struct xml_node_ctx *ctx, xml_node_t *parent, 262281681Srpaulo const char *urn) 263281681Srpaulo{ 264281681Srpaulo xml_node_t *node; 265281681Srpaulo 266281681Srpaulo node = xml_node_create(ctx, parent, NULL, "RTProperties"); 267281681Srpaulo if (node == NULL) 268281681Srpaulo return -1; 269281681Srpaulo node = xml_node_create(ctx, node, NULL, "Type"); 270281681Srpaulo if (node == NULL) 271281681Srpaulo return -1; 272281681Srpaulo xml_node_create_text(ctx, node, NULL, "DDFName", urn); 273281681Srpaulo return 0; 274281681Srpaulo} 275281681Srpaulo 276281681Srpaulo 277281681Srpauloxml_node_t * mo_to_tnds(struct xml_node_ctx *ctx, xml_node_t *mo, 278281681Srpaulo int use_path, const char *urn, const char *ns_uri) 279281681Srpaulo{ 280281681Srpaulo xml_node_t *root; 281281681Srpaulo xml_node_t *node; 282281681Srpaulo const char *name; 283281681Srpaulo 284281681Srpaulo root = xml_node_create_root(ctx, ns_uri, NULL, NULL, "MgmtTree"); 285281681Srpaulo if (root == NULL) 286281681Srpaulo return NULL; 287281681Srpaulo 288281681Srpaulo xml_node_create_text(ctx, root, NULL, "VerDTD", "1.2"); 289281681Srpaulo 290281681Srpaulo name = xml_node_get_localname(ctx, mo); 291281681Srpaulo 292281681Srpaulo node = xml_node_create(ctx, root, NULL, "Node"); 293281681Srpaulo if (node == NULL) 294281681Srpaulo goto fail; 295281681Srpaulo xml_node_create_text(ctx, node, NULL, "NodeName", name); 296281681Srpaulo if (urn) 297281681Srpaulo add_ddfname(ctx, node, urn); 298281681Srpaulo 299281681Srpaulo node_to_tnds(ctx, use_path ? root : node, mo, use_path ? name : NULL); 300281681Srpaulo 301281681Srpaulo return root; 302281681Srpaulo 303281681Srpaulofail: 304281681Srpaulo xml_node_free(ctx, root); 305281681Srpaulo return NULL; 306281681Srpaulo} 307281681Srpaulo 308281681Srpaulo 309281681Srpaulostatic xml_node_t * get_first_child_node(struct xml_node_ctx *ctx, 310281681Srpaulo xml_node_t *node, 311281681Srpaulo const char *name) 312281681Srpaulo{ 313281681Srpaulo const char *lname; 314281681Srpaulo xml_node_t *child; 315281681Srpaulo 316281681Srpaulo xml_node_for_each_child(ctx, child, node) { 317281681Srpaulo xml_node_for_each_check(ctx, child); 318281681Srpaulo lname = xml_node_get_localname(ctx, child); 319281681Srpaulo if (os_strcasecmp(lname, name) == 0) 320281681Srpaulo return child; 321281681Srpaulo } 322281681Srpaulo 323281681Srpaulo return NULL; 324281681Srpaulo} 325281681Srpaulo 326281681Srpaulo 327281681Srpaulostatic char * get_node_text(struct xml_node_ctx *ctx, xml_node_t *node, 328281681Srpaulo const char *node_name) 329281681Srpaulo{ 330281681Srpaulo node = get_first_child_node(ctx, node, node_name); 331281681Srpaulo if (node == NULL) 332281681Srpaulo return NULL; 333281681Srpaulo return xml_node_get_text(ctx, node); 334281681Srpaulo} 335281681Srpaulo 336281681Srpaulo 337281681Srpaulostatic xml_node_t * add_mo_node(struct xml_node_ctx *ctx, xml_node_t *root, 338281681Srpaulo xml_node_t *node, const char *uri) 339281681Srpaulo{ 340281681Srpaulo char *nodename, *value, *path; 341281681Srpaulo xml_node_t *parent; 342281681Srpaulo 343281681Srpaulo nodename = get_node_text(ctx, node, "NodeName"); 344281681Srpaulo if (nodename == NULL) 345281681Srpaulo return NULL; 346281681Srpaulo value = get_node_text(ctx, node, "Value"); 347281681Srpaulo 348281681Srpaulo if (root == NULL) { 349281681Srpaulo root = xml_node_create_root(ctx, NULL, NULL, NULL, 350281681Srpaulo nodename); 351281681Srpaulo if (root && value) 352281681Srpaulo xml_node_set_text(ctx, root, value); 353281681Srpaulo } else { 354281681Srpaulo if (uri == NULL) { 355281681Srpaulo xml_node_get_text_free(ctx, nodename); 356281681Srpaulo xml_node_get_text_free(ctx, value); 357281681Srpaulo return NULL; 358281681Srpaulo } 359281681Srpaulo path = get_node_text(ctx, node, "Path"); 360281681Srpaulo if (path) 361281681Srpaulo uri = path; 362281681Srpaulo parent = get_node_uri(ctx, root, uri); 363281681Srpaulo xml_node_get_text_free(ctx, path); 364281681Srpaulo if (parent == NULL) { 365281681Srpaulo printf("Could not find URI '%s'\n", uri); 366281681Srpaulo xml_node_get_text_free(ctx, nodename); 367281681Srpaulo xml_node_get_text_free(ctx, value); 368281681Srpaulo return NULL; 369281681Srpaulo } 370281681Srpaulo if (value) 371281681Srpaulo xml_node_create_text(ctx, parent, NULL, nodename, 372281681Srpaulo value); 373281681Srpaulo else 374281681Srpaulo xml_node_create(ctx, parent, NULL, nodename); 375281681Srpaulo } 376281681Srpaulo 377281681Srpaulo xml_node_get_text_free(ctx, nodename); 378281681Srpaulo xml_node_get_text_free(ctx, value); 379281681Srpaulo 380281681Srpaulo return root; 381281681Srpaulo} 382281681Srpaulo 383281681Srpaulo 384281681Srpaulostatic xml_node_t * tnds_to_mo_iter(struct xml_node_ctx *ctx, xml_node_t *root, 385281681Srpaulo xml_node_t *node, const char *uri) 386281681Srpaulo{ 387281681Srpaulo xml_node_t *child; 388281681Srpaulo const char *name; 389281681Srpaulo char *nodename; 390281681Srpaulo 391281681Srpaulo xml_node_for_each_sibling(ctx, node) { 392281681Srpaulo xml_node_for_each_check(ctx, node); 393281681Srpaulo 394281681Srpaulo nodename = get_node_text(ctx, node, "NodeName"); 395281681Srpaulo if (nodename == NULL) 396281681Srpaulo return NULL; 397281681Srpaulo 398281681Srpaulo name = xml_node_get_localname(ctx, node); 399281681Srpaulo if (strcmp(name, "Node") == 0) { 400281681Srpaulo if (root && !uri) { 401281681Srpaulo printf("Invalid TNDS tree structure - " 402281681Srpaulo "multiple top level nodes\n"); 403281681Srpaulo xml_node_get_text_free(ctx, nodename); 404281681Srpaulo return NULL; 405281681Srpaulo } 406281681Srpaulo root = add_mo_node(ctx, root, node, uri); 407281681Srpaulo } 408281681Srpaulo 409281681Srpaulo child = get_first_child_node(ctx, node, "Node"); 410281681Srpaulo if (child) { 411281681Srpaulo if (uri == NULL) 412281681Srpaulo tnds_to_mo_iter(ctx, root, child, nodename); 413281681Srpaulo else { 414281681Srpaulo char *new_uri; 415281681Srpaulo new_uri = add_path(uri, nodename); 416281681Srpaulo tnds_to_mo_iter(ctx, root, child, new_uri); 417281681Srpaulo os_free(new_uri); 418281681Srpaulo } 419281681Srpaulo } 420281681Srpaulo xml_node_get_text_free(ctx, nodename); 421281681Srpaulo } 422281681Srpaulo 423281681Srpaulo return root; 424281681Srpaulo} 425281681Srpaulo 426281681Srpaulo 427281681Srpauloxml_node_t * tnds_to_mo(struct xml_node_ctx *ctx, xml_node_t *tnds) 428281681Srpaulo{ 429281681Srpaulo const char *name; 430281681Srpaulo xml_node_t *node; 431281681Srpaulo 432281681Srpaulo name = xml_node_get_localname(ctx, tnds); 433281681Srpaulo if (name == NULL || os_strcmp(name, "MgmtTree") != 0) 434281681Srpaulo return NULL; 435281681Srpaulo 436281681Srpaulo node = get_first_child_node(ctx, tnds, "Node"); 437281681Srpaulo if (!node) 438281681Srpaulo return NULL; 439281681Srpaulo return tnds_to_mo_iter(ctx, NULL, node, NULL); 440281681Srpaulo} 441281681Srpaulo 442281681Srpaulo 443281681Srpauloxml_node_t * soap_build_envelope(struct xml_node_ctx *ctx, xml_node_t *node) 444281681Srpaulo{ 445281681Srpaulo xml_node_t *envelope, *body; 446281681Srpaulo xml_namespace_t *ns; 447281681Srpaulo 448281681Srpaulo envelope = xml_node_create_root( 449281681Srpaulo ctx, "http://www.w3.org/2003/05/soap-envelope", "soap12", &ns, 450281681Srpaulo "Envelope"); 451281681Srpaulo if (envelope == NULL) 452281681Srpaulo return NULL; 453281681Srpaulo body = xml_node_create(ctx, envelope, ns, "Body"); 454281681Srpaulo xml_node_add_child(ctx, body, node); 455281681Srpaulo return envelope; 456281681Srpaulo} 457281681Srpaulo 458281681Srpaulo 459281681Srpauloxml_node_t * soap_get_body(struct xml_node_ctx *ctx, xml_node_t *soap) 460281681Srpaulo{ 461281681Srpaulo xml_node_t *body, *child; 462281681Srpaulo 463281681Srpaulo body = get_node_uri(ctx, soap, "Envelope/Body"); 464281681Srpaulo if (body == NULL) 465281681Srpaulo return NULL; 466281681Srpaulo xml_node_for_each_child(ctx, child, body) { 467281681Srpaulo xml_node_for_each_check(ctx, child); 468281681Srpaulo return child; 469281681Srpaulo } 470281681Srpaulo return NULL; 471281681Srpaulo} 472