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 		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