Home | History | Annotate | Download | only in utils
      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