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 15 static 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 46 xml_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 63 static 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 89 xml_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 106 xml_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 123 xml_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 169 int 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 192 static 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 210 static 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 227 static 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 261 static 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 277 xml_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 303 fail: 304 xml_node_free(ctx, root); 305 return NULL; 306 } 307 308 309 static 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 327 static 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 337 static 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 384 static 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 427 xml_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 443 xml_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 459 xml_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