1/* 2 * Generic XML helper functions 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 11#include "common.h" 12#include "xml-utils.h" 13 14 15static xml_node_t * get_node_uri_iter(struct xml_node_ctx *ctx, 16 xml_node_t *root, char *uri) 17{ 18 char *end; 19 xml_node_t *node; 20 const char *name; 21 22 end = strchr(uri, '/'); 23 if (end) 24 *end++ = '\0'; 25 26 node = root; 27 xml_node_for_each_sibling(ctx, node) { 28 xml_node_for_each_check(ctx, node); 29 name = xml_node_get_localname(ctx, node); 30 if (strcasecmp(name, uri) == 0) 31 break; 32 } 33 34 if (node == NULL) 35 return NULL; 36 37 if (end) { 38 return get_node_uri_iter(ctx, xml_node_first_child(ctx, node), 39 end); 40 } 41 42 return node; 43} 44 45 46xml_node_t * get_node_uri(struct xml_node_ctx *ctx, xml_node_t *root, 47 const char *uri) 48{ 49 char *search; 50 xml_node_t *node; 51 52 search = os_strdup(uri); 53 if (search == NULL) 54 return NULL; 55 56 node = get_node_uri_iter(ctx, root, search); 57 58 os_free(search); 59 return node; 60} 61 62 63static xml_node_t * get_node_iter(struct xml_node_ctx *ctx, 64 xml_node_t *root, const char *path) 65{ 66 char *end; 67 xml_node_t *node; 68 const char *name; 69 70 end = os_strchr(path, '/'); 71 if (end) 72 *end++ = '\0'; 73 74 xml_node_for_each_child(ctx, node, root) { 75 xml_node_for_each_check(ctx, node); 76 name = xml_node_get_localname(ctx, node); 77 if (os_strcasecmp(name, path) == 0) 78 break; 79 } 80 81 if (node == NULL) 82 return NULL; 83 if (end) 84 return get_node_iter(ctx, node, end); 85 return node; 86} 87 88 89xml_node_t * get_node(struct xml_node_ctx *ctx, xml_node_t *root, 90 const char *path) 91{ 92 char *search; 93 xml_node_t *node; 94 95 search = os_strdup(path); 96 if (search == NULL) 97 return NULL; 98 99 node = get_node_iter(ctx, root, search); 100 101 os_free(search); 102 return node; 103} 104 105 106xml_node_t * get_child_node(struct xml_node_ctx *ctx, xml_node_t *root, 107 const char *path) 108{ 109 xml_node_t *node; 110 xml_node_t *match; 111 112 xml_node_for_each_child(ctx, node, root) { 113 xml_node_for_each_check(ctx, node); 114 match = get_node(ctx, node, path); 115 if (match) 116 return match; 117 } 118 119 return NULL; 120} 121 122 123xml_node_t * node_from_file(struct xml_node_ctx *ctx, const char *name) 124{ 125 xml_node_t *node; 126 char *buf, *buf2, *start; 127 size_t len; 128 129 buf = os_readfile(name, &len); 130 if (buf == NULL) 131 return NULL; 132 buf2 = os_realloc(buf, len + 1); 133 if (buf2 == NULL) { 134 os_free(buf); 135 return NULL; 136 } 137 buf = buf2; 138 buf[len] = '\0'; 139 140 start = os_strstr(buf, "<!DOCTYPE "); 141 if (start) { 142 char *pos = start + 1; 143 int count = 1; 144 while (*pos) { 145 if (*pos == '<') 146 count++; 147 else if (*pos == '>') { 148 count--; 149 if (count == 0) { 150 pos++; 151 break; 152 } 153 } 154 pos++; 155 } 156 if (count == 0) { 157 /* Remove DOCTYPE to allow the file to be parsed */ 158 os_memset(start, ' ', pos - start); 159 } 160 } 161 162 node = xml_node_from_buf(ctx, buf); 163 os_free(buf); 164 165 return node; 166} 167 168 169int node_to_file(struct xml_node_ctx *ctx, const char *fname, xml_node_t *node) 170{ 171 FILE *f; 172 char *str; 173 174 str = xml_node_to_str(ctx, node); 175 if (str == NULL) 176 return -1; 177 178 f = fopen(fname, "w"); 179 if (!f) { 180 os_free(str); 181 return -1; 182 } 183 184 fprintf(f, "%s\n", str); 185 os_free(str); 186 fclose(f); 187 188 return 0; 189} 190 191 192static char * get_val(struct xml_node_ctx *ctx, xml_node_t *node) 193{ 194 char *val, *pos; 195 196 val = xml_node_get_text(ctx, node); 197 if (val == NULL) 198 return NULL; 199 pos = val; 200 while (*pos) { 201 if (*pos != ' ' && *pos != '\t' && *pos != '\r' && *pos != '\n') 202 return val; 203 pos++; 204 } 205 206 return NULL; 207} 208 209 210static char * add_path(const char *prev, const char *leaf) 211{ 212 size_t len; 213 char *new_uri; 214 215 if (prev == NULL) 216 return NULL; 217 218 len = os_strlen(prev) + 1 + os_strlen(leaf) + 1; 219 new_uri = os_malloc(len); 220 if (new_uri) 221 os_snprintf(new_uri, len, "%s/%s", prev, leaf); 222 223 return new_uri; 224} 225 226 227static void node_to_tnds(struct xml_node_ctx *ctx, xml_node_t *out, 228 xml_node_t *in, const char *uri) 229{ 230 xml_node_t *node; 231 xml_node_t *tnds; 232 const char *name; 233 char *val; 234 char *new_uri; 235 236 xml_node_for_each_child(ctx, node, in) { 237 xml_node_for_each_check(ctx, node); 238 name = xml_node_get_localname(ctx, node); 239 240 tnds = xml_node_create(ctx, out, NULL, "Node"); 241 if (tnds == NULL) 242 return; 243 xml_node_create_text(ctx, tnds, NULL, "NodeName", name); 244 245 if (uri) 246 xml_node_create_text(ctx, tnds, NULL, "Path", uri); 247 248 val = get_val(ctx, node); 249 if (val) { 250 xml_node_create_text(ctx, tnds, NULL, "Value", val); 251 xml_node_get_text_free(ctx, val); 252 } 253 254 new_uri = add_path(uri, name); 255 node_to_tnds(ctx, new_uri ? out : tnds, node, new_uri); 256 os_free(new_uri); 257 } 258} 259 260 261static int add_ddfname(struct xml_node_ctx *ctx, xml_node_t *parent, 262 const char *urn) 263{ 264 xml_node_t *node; 265 266 node = xml_node_create(ctx, parent, NULL, "RTProperties"); 267 if (node == NULL) 268 return -1; 269 node = xml_node_create(ctx, node, NULL, "Type"); 270 if (node == NULL) 271 return -1; 272 xml_node_create_text(ctx, node, NULL, "DDFName", urn); 273 return 0; 274} 275 276 277xml_node_t * mo_to_tnds(struct xml_node_ctx *ctx, xml_node_t *mo, 278 int use_path, const char *urn, const char *ns_uri) 279{ 280 xml_node_t *root; 281 xml_node_t *node; 282 const char *name; 283 284 root = xml_node_create_root(ctx, ns_uri, NULL, NULL, "MgmtTree"); 285 if (root == NULL) 286 return NULL; 287 288 xml_node_create_text(ctx, root, NULL, "VerDTD", "1.2"); 289 290 name = xml_node_get_localname(ctx, mo); 291 292 node = xml_node_create(ctx, root, NULL, "Node"); 293 if (node == NULL) 294 goto fail; 295 xml_node_create_text(ctx, node, NULL, "NodeName", name); 296 if (urn) 297 add_ddfname(ctx, node, urn); 298 299 node_to_tnds(ctx, use_path ? root : node, mo, use_path ? name : NULL); 300 301 return root; 302 303fail: 304 xml_node_free(ctx, root); 305 return NULL; 306} 307 308 309static xml_node_t * get_first_child_node(struct xml_node_ctx *ctx, 310 xml_node_t *node, 311 const char *name) 312{ 313 const char *lname; 314 xml_node_t *child; 315 316 xml_node_for_each_child(ctx, child, node) { 317 xml_node_for_each_check(ctx, child); 318 lname = xml_node_get_localname(ctx, child); 319 if (os_strcasecmp(lname, name) == 0) 320 return child; 321 } 322 323 return NULL; 324} 325 326 327static char * get_node_text(struct xml_node_ctx *ctx, xml_node_t *node, 328 const char *node_name) 329{ 330 node = get_first_child_node(ctx, node, node_name); 331 if (node == NULL) 332 return NULL; 333 return xml_node_get_text(ctx, node); 334} 335 336 337static xml_node_t * add_mo_node(struct xml_node_ctx *ctx, xml_node_t *root, 338 xml_node_t *node, const char *uri) 339{ 340 char *nodename, *value, *path; 341 xml_node_t *parent; 342 343 nodename = get_node_text(ctx, node, "NodeName"); 344 if (nodename == NULL) 345 return NULL; 346 value = get_node_text(ctx, node, "Value"); 347 348 if (root == NULL) { 349 root = xml_node_create_root(ctx, NULL, NULL, NULL, 350 nodename); 351 if (root && value) 352 xml_node_set_text(ctx, root, value); 353 } else { 354 if (uri == NULL) { 355 xml_node_get_text_free(ctx, nodename); 356 xml_node_get_text_free(ctx, value); 357 return NULL; 358 } 359 path = get_node_text(ctx, node, "Path"); 360 if (path) 361 uri = path; 362 parent = get_node_uri(ctx, root, uri); 363 xml_node_get_text_free(ctx, path); 364 if (parent == NULL) { 365 printf("Could not find URI '%s'\n", uri); 366 xml_node_get_text_free(ctx, nodename); 367 xml_node_get_text_free(ctx, value); 368 return NULL; 369 } 370 if (value) 371 xml_node_create_text(ctx, parent, NULL, nodename, 372 value); 373 else 374 xml_node_create(ctx, parent, NULL, nodename); 375 } 376 377 xml_node_get_text_free(ctx, nodename); 378 xml_node_get_text_free(ctx, value); 379 380 return root; 381} 382 383 384static xml_node_t * tnds_to_mo_iter(struct xml_node_ctx *ctx, xml_node_t *root, 385 xml_node_t *node, const char *uri) 386{ 387 xml_node_t *child; 388 const char *name; 389 char *nodename; 390 391 xml_node_for_each_sibling(ctx, node) { 392 xml_node_for_each_check(ctx, node); 393 394 nodename = get_node_text(ctx, node, "NodeName"); 395 if (nodename == NULL) 396 return NULL; 397 398 name = xml_node_get_localname(ctx, node); 399 if (strcmp(name, "Node") == 0) { 400 if (root && !uri) { 401 printf("Invalid TNDS tree structure - " 402 "multiple top level nodes\n"); 403 xml_node_get_text_free(ctx, nodename); 404 return NULL; 405 } 406 root = add_mo_node(ctx, root, node, uri); 407 } 408 409 child = get_first_child_node(ctx, node, "Node"); 410 if (child) { 411 if (uri == NULL) 412 tnds_to_mo_iter(ctx, root, child, nodename); 413 else { 414 char *new_uri; 415 new_uri = add_path(uri, nodename); 416 tnds_to_mo_iter(ctx, root, child, new_uri); 417 os_free(new_uri); 418 } 419 } 420 xml_node_get_text_free(ctx, nodename); 421 } 422 423 return root; 424} 425 426 427xml_node_t * tnds_to_mo(struct xml_node_ctx *ctx, xml_node_t *tnds) 428{ 429 const char *name; 430 xml_node_t *node; 431 432 name = xml_node_get_localname(ctx, tnds); 433 if (name == NULL || os_strcmp(name, "MgmtTree") != 0) 434 return NULL; 435 436 node = get_first_child_node(ctx, tnds, "Node"); 437 if (!node) 438 return NULL; 439 return tnds_to_mo_iter(ctx, NULL, node, NULL); 440} 441 442 443xml_node_t * soap_build_envelope(struct xml_node_ctx *ctx, xml_node_t *node) 444{ 445 xml_node_t *envelope, *body; 446 xml_namespace_t *ns; 447 448 envelope = xml_node_create_root( 449 ctx, "http://www.w3.org/2003/05/soap-envelope", "soap12", &ns, 450 "Envelope"); 451 if (envelope == NULL) 452 return NULL; 453 body = xml_node_create(ctx, envelope, ns, "Body"); 454 xml_node_add_child(ctx, body, node); 455 return envelope; 456} 457 458 459xml_node_t * soap_get_body(struct xml_node_ctx *ctx, xml_node_t *soap) 460{ 461 xml_node_t *body, *child; 462 463 body = get_node_uri(ctx, soap, "Envelope/Body"); 464 if (body == NULL) 465 return NULL; 466 xml_node_for_each_child(ctx, child, body) { 467 xml_node_for_each_check(ctx, child); 468 return child; 469 } 470 return NULL; 471} 472