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