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 xml_node_create_text(ctx, tnds, NULL, "Value", val ? val : ""); 250 xml_node_get_text_free(ctx, val); 251 252 new_uri = add_path(uri, name); 253 node_to_tnds(ctx, new_uri ? out : tnds, node, new_uri); 254 os_free(new_uri); 255 } 256 } 257 258 259 static int add_ddfname(struct xml_node_ctx *ctx, xml_node_t *parent, 260 const char *urn) 261 { 262 xml_node_t *node; 263 264 node = xml_node_create(ctx, parent, NULL, "RTProperties"); 265 if (node == NULL) 266 return -1; 267 node = xml_node_create(ctx, node, NULL, "Type"); 268 if (node == NULL) 269 return -1; 270 xml_node_create_text(ctx, node, NULL, "DDFName", urn); 271 return 0; 272 } 273 274 275 xml_node_t * mo_to_tnds(struct xml_node_ctx *ctx, xml_node_t *mo, 276 int use_path, const char *urn, const char *ns_uri) 277 { 278 xml_node_t *root; 279 xml_node_t *node; 280 const char *name; 281 282 root = xml_node_create_root(ctx, ns_uri, NULL, NULL, "MgmtTree"); 283 if (root == NULL) 284 return NULL; 285 286 xml_node_create_text(ctx, root, NULL, "VerDTD", "1.2"); 287 288 name = xml_node_get_localname(ctx, mo); 289 290 node = xml_node_create(ctx, root, NULL, "Node"); 291 if (node == NULL) 292 goto fail; 293 xml_node_create_text(ctx, node, NULL, "NodeName", name); 294 if (urn) 295 add_ddfname(ctx, node, urn); 296 297 node_to_tnds(ctx, use_path ? root : node, mo, use_path ? name : NULL); 298 299 return root; 300 301 fail: 302 xml_node_free(ctx, root); 303 return NULL; 304 } 305 306 307 static xml_node_t * get_first_child_node(struct xml_node_ctx *ctx, 308 xml_node_t *node, 309 const char *name) 310 { 311 const char *lname; 312 xml_node_t *child; 313 314 xml_node_for_each_child(ctx, child, node) { 315 xml_node_for_each_check(ctx, child); 316 lname = xml_node_get_localname(ctx, child); 317 if (os_strcasecmp(lname, name) == 0) 318 return child; 319 } 320 321 return NULL; 322 } 323 324 325 static char * get_node_text(struct xml_node_ctx *ctx, xml_node_t *node, 326 const char *node_name) 327 { 328 node = get_first_child_node(ctx, node, node_name); 329 if (node == NULL) 330 return NULL; 331 return xml_node_get_text(ctx, node); 332 } 333 334 335 static xml_node_t * add_mo_node(struct xml_node_ctx *ctx, xml_node_t *root, 336 xml_node_t *node, const char *uri) 337 { 338 char *nodename, *value, *path; 339 xml_node_t *parent; 340 341 nodename = get_node_text(ctx, node, "NodeName"); 342 if (nodename == NULL) 343 return NULL; 344 value = get_node_text(ctx, node, "Value"); 345 346 if (root == NULL) { 347 root = xml_node_create_root(ctx, NULL, NULL, NULL, 348 nodename); 349 if (root && value) 350 xml_node_set_text(ctx, root, value); 351 } else { 352 if (uri == NULL) { 353 xml_node_get_text_free(ctx, nodename); 354 xml_node_get_text_free(ctx, value); 355 return NULL; 356 } 357 path = get_node_text(ctx, node, "Path"); 358 if (path) 359 uri = path; 360 parent = get_node_uri(ctx, root, uri); 361 xml_node_get_text_free(ctx, path); 362 if (parent == NULL) { 363 printf("Could not find URI '%s'\n", uri); 364 xml_node_get_text_free(ctx, nodename); 365 xml_node_get_text_free(ctx, value); 366 return NULL; 367 } 368 if (value) 369 xml_node_create_text(ctx, parent, NULL, nodename, 370 value); 371 else 372 xml_node_create(ctx, parent, NULL, nodename); 373 } 374 375 xml_node_get_text_free(ctx, nodename); 376 xml_node_get_text_free(ctx, value); 377 378 return root; 379 } 380 381 382 static xml_node_t * tnds_to_mo_iter(struct xml_node_ctx *ctx, xml_node_t *root, 383 xml_node_t *node, const char *uri) 384 { 385 xml_node_t *child; 386 const char *name; 387 char *nodename; 388 389 xml_node_for_each_sibling(ctx, node) { 390 xml_node_for_each_check(ctx, node); 391 392 nodename = get_node_text(ctx, node, "NodeName"); 393 if (nodename == NULL) 394 return NULL; 395 396 name = xml_node_get_localname(ctx, node); 397 if (strcmp(name, "Node") == 0) { 398 if (root && !uri) { 399 printf("Invalid TNDS tree structure - " 400 "multiple top level nodes\n"); 401 xml_node_get_text_free(ctx, nodename); 402 return NULL; 403 } 404 root = add_mo_node(ctx, root, node, uri); 405 } 406 407 child = get_first_child_node(ctx, node, "Node"); 408 if (child) { 409 if (uri == NULL) 410 tnds_to_mo_iter(ctx, root, child, nodename); 411 else { 412 char *new_uri; 413 new_uri = add_path(uri, nodename); 414 tnds_to_mo_iter(ctx, root, child, new_uri); 415 os_free(new_uri); 416 } 417 } 418 xml_node_get_text_free(ctx, nodename); 419 } 420 421 return root; 422 } 423 424 425 xml_node_t * tnds_to_mo(struct xml_node_ctx *ctx, xml_node_t *tnds) 426 { 427 const char *name; 428 xml_node_t *node; 429 430 name = xml_node_get_localname(ctx, tnds); 431 if (name == NULL || os_strcmp(name, "MgmtTree") != 0) 432 return NULL; 433 434 node = get_first_child_node(ctx, tnds, "Node"); 435 if (!node) 436 return NULL; 437 return tnds_to_mo_iter(ctx, NULL, node, NULL); 438 } 439 440 441 xml_node_t * soap_build_envelope(struct xml_node_ctx *ctx, xml_node_t *node) 442 { 443 xml_node_t *envelope, *body; 444 xml_namespace_t *ns; 445 446 envelope = xml_node_create_root( 447 ctx, "http://www.w3.org/2003/05/soap-envelope", "soap12", &ns, 448 "Envelope"); 449 if (envelope == NULL) 450 return NULL; 451 body = xml_node_create(ctx, envelope, ns, "Body"); 452 xml_node_add_child(ctx, body, node); 453 return envelope; 454 } 455 456 457 xml_node_t * soap_get_body(struct xml_node_ctx *ctx, xml_node_t *soap) 458 { 459 xml_node_t *body, *child; 460 461 body = get_node_uri(ctx, soap, "Envelope/Body"); 462 if (body == NULL) 463 return NULL; 464 xml_node_for_each_child(ctx, child, body) { 465 xml_node_for_each_check(ctx, child); 466 return child; 467 } 468 return NULL; 469 } 470