1 /*
2  * XML wrapper for libxml2
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 #define LIBXML_VALID_ENABLED
11 #include <libxml/tree.h>
12 #include <libxml/xmlschemastypes.h>
13 
14 #include "common.h"
15 #include "base64.h"
16 #include "xml-utils.h"
17 
18 
19 struct xml_node_ctx {
20 	void *ctx;
21 };
22 
23 
xml_node_free(struct xml_node_ctx * ctx,xml_node_t * node)24 void xml_node_free(struct xml_node_ctx *ctx, xml_node_t *node)
25 {
26 	xmlFreeNode((xmlNodePtr) node);
27 }
28 
29 
xml_node_from_buf(struct xml_node_ctx * ctx,const char * buf)30 xml_node_t * xml_node_from_buf(struct xml_node_ctx *ctx, const char *buf)
31 {
32 	xmlDocPtr doc;
33 	xmlNodePtr node;
34 
35 	doc = xmlParseMemory(buf, strlen(buf));
36 	if (doc == NULL)
37 		return NULL;
38 	node = xmlDocGetRootElement(doc);
39 	node = xmlCopyNode(node, 1);
40 	xmlFreeDoc(doc);
41 
42 	return (xml_node_t *) node;
43 }
44 
45 
xml_node_get_localname(struct xml_node_ctx * ctx,xml_node_t * node)46 const char * xml_node_get_localname(struct xml_node_ctx *ctx,
47 				    xml_node_t *node)
48 {
49 	return (const char *) ((xmlNodePtr) node)->name;
50 }
51 
52 
xml_node_to_str(struct xml_node_ctx * ctx,xml_node_t * node)53 char * xml_node_to_str(struct xml_node_ctx *ctx, xml_node_t *node)
54 {
55 	xmlChar *buf;
56 	int bufsiz;
57 	char *ret, *pos;
58 	xmlNodePtr n = (xmlNodePtr) node;
59 	xmlDocPtr doc;
60 
61 	doc = xmlNewDoc((xmlChar *) "1.0");
62 	n = xmlDocCopyNode(n, doc, 1);
63 	xmlDocSetRootElement(doc, n);
64 	xmlDocDumpFormatMemory(doc, &buf, &bufsiz, 0);
65 	xmlFreeDoc(doc);
66 	if (!buf)
67 		return NULL;
68 	pos = (char *) buf;
69 	if (strncmp(pos, "<?xml", 5) == 0) {
70 		pos = strchr(pos, '>');
71 		if (pos)
72 			pos++;
73 		while (pos && (*pos == '\r' || *pos == '\n'))
74 			pos++;
75 	}
76 	if (pos)
77 		ret = os_strdup(pos);
78 	else
79 		ret = NULL;
80 	xmlFree(buf);
81 
82 	if (ret) {
83 		pos = ret;
84 		if (pos[0]) {
85 			while (pos[1])
86 				pos++;
87 		}
88 		while (pos >= ret && *pos == '\n')
89 			*pos-- = '\0';
90 	}
91 
92 	return ret;
93 }
94 
95 
xml_node_create_root(struct xml_node_ctx * ctx,const char * ns_uri,const char * ns_prefix,xml_namespace_t ** ret_ns,const char * name)96 xml_node_t * xml_node_create_root(struct xml_node_ctx *ctx, const char *ns_uri,
97 				  const char *ns_prefix,
98 				  xml_namespace_t **ret_ns, const char *name)
99 {
100 	xmlNodePtr node;
101 	xmlNsPtr ns = NULL;
102 
103 	node = xmlNewNode(NULL, (const xmlChar *) name);
104 	if (node == NULL)
105 		return NULL;
106 	if (ns_uri) {
107 		ns = xmlNewNs(node, (const xmlChar *) ns_uri,
108 			      (const xmlChar *) ns_prefix);
109 		xmlSetNs(node, ns);
110 	}
111 
112 	if (ret_ns)
113 		*ret_ns = (xml_namespace_t *) ns;
114 
115 	return (xml_node_t *) node;
116 }
117 
118 
xml_node_create(struct xml_node_ctx * ctx,xml_node_t * parent,xml_namespace_t * ns,const char * name)119 xml_node_t * xml_node_create(struct xml_node_ctx *ctx, xml_node_t *parent,
120 			     xml_namespace_t *ns, const char *name)
121 {
122 	xmlNodePtr node;
123 	node = xmlNewChild((xmlNodePtr) parent, (xmlNsPtr) ns,
124 			   (const xmlChar *) name, NULL);
125 	return (xml_node_t *) node;
126 }
127 
128 
xml_node_create_text(struct xml_node_ctx * ctx,xml_node_t * parent,xml_namespace_t * ns,const char * name,const char * value)129 xml_node_t * xml_node_create_text(struct xml_node_ctx *ctx,
130 				  xml_node_t *parent, xml_namespace_t *ns,
131 				  const char *name, const char *value)
132 {
133 	xmlNodePtr node;
134 	node = xmlNewTextChild((xmlNodePtr) parent, (xmlNsPtr) ns,
135 			       (const xmlChar *) name, (const xmlChar *) value);
136 	return (xml_node_t *) node;
137 }
138 
139 
xml_node_create_text_ns(struct xml_node_ctx * ctx,xml_node_t * parent,const char * ns_uri,const char * name,const char * value)140 xml_node_t * xml_node_create_text_ns(struct xml_node_ctx *ctx,
141 				     xml_node_t *parent, const char *ns_uri,
142 				     const char *name, const char *value)
143 {
144 	xmlNodePtr node;
145 	xmlNsPtr ns;
146 
147 	node = xmlNewTextChild((xmlNodePtr) parent, NULL,
148 			       (const xmlChar *) name, (const xmlChar *) value);
149 	ns = xmlNewNs(node, (const xmlChar *) ns_uri, NULL);
150 	xmlSetNs(node, ns);
151 	return (xml_node_t *) node;
152 }
153 
154 
xml_node_set_text(struct xml_node_ctx * ctx,xml_node_t * node,const char * value)155 void xml_node_set_text(struct xml_node_ctx *ctx, xml_node_t *node,
156 		       const char *value)
157 {
158 	/* TODO: escape XML special chars in value */
159 	xmlNodeSetContent((xmlNodePtr) node, (xmlChar *) value);
160 }
161 
162 
xml_node_first_child(struct xml_node_ctx * ctx,xml_node_t * parent)163 xml_node_t * xml_node_first_child(struct xml_node_ctx *ctx,
164 				  xml_node_t *parent)
165 {
166 	return (xml_node_t *) ((xmlNodePtr) parent)->children;
167 }
168 
169 
xml_node_next_sibling(struct xml_node_ctx * ctx,xml_node_t * node)170 xml_node_t * xml_node_next_sibling(struct xml_node_ctx *ctx,
171 				   xml_node_t *node)
172 {
173 	return (xml_node_t *) ((xmlNodePtr) node)->next;
174 }
175 
176 
xml_node_is_element(struct xml_node_ctx * ctx,xml_node_t * node)177 int xml_node_is_element(struct xml_node_ctx *ctx, xml_node_t *node)
178 {
179 	return ((xmlNodePtr) node)->type == XML_ELEMENT_NODE;
180 }
181 
182 
xml_node_get_text(struct xml_node_ctx * ctx,xml_node_t * node)183 char * xml_node_get_text(struct xml_node_ctx *ctx, xml_node_t *node)
184 {
185 	if (xmlChildElementCount((xmlNodePtr) node) > 0)
186 		return NULL;
187 	return (char *) xmlNodeGetContent((xmlNodePtr) node);
188 }
189 
190 
xml_node_get_text_free(struct xml_node_ctx * ctx,char * val)191 void xml_node_get_text_free(struct xml_node_ctx *ctx, char *val)
192 {
193 	if (val)
194 		xmlFree((xmlChar *) val);
195 }
196 
197 
xml_node_get_base64_text(struct xml_node_ctx * ctx,xml_node_t * node,int * ret_len)198 char * xml_node_get_base64_text(struct xml_node_ctx *ctx, xml_node_t *node,
199 				int *ret_len)
200 {
201 	char *txt;
202 	unsigned char *ret;
203 	size_t len;
204 
205 	txt = xml_node_get_text(ctx, node);
206 	if (txt == NULL)
207 		return NULL;
208 
209 	ret = base64_decode(txt, strlen(txt), &len);
210 	if (ret_len)
211 		*ret_len = len;
212 	xml_node_get_text_free(ctx, txt);
213 	if (ret == NULL)
214 		return NULL;
215 	txt = os_malloc(len + 1);
216 	if (txt == NULL) {
217 		os_free(ret);
218 		return NULL;
219 	}
220 	os_memcpy(txt, ret, len);
221 	txt[len] = '\0';
222 	return txt;
223 }
224 
225 
xml_node_init_ctx(void * upper_ctx,const void * env)226 struct xml_node_ctx * xml_node_init_ctx(void *upper_ctx,
227 					const void *env)
228 {
229 	struct xml_node_ctx *xctx;
230 
231 	xctx = os_zalloc(sizeof(*xctx));
232 	if (xctx == NULL)
233 		return NULL;
234 	xctx->ctx = upper_ctx;
235 
236 	LIBXML_TEST_VERSION
237 
238 	return xctx;
239 }
240 
241 
xml_node_deinit_ctx(struct xml_node_ctx * ctx)242 void xml_node_deinit_ctx(struct xml_node_ctx *ctx)
243 {
244 	xmlSchemaCleanupTypes();
245 	xmlCleanupParser();
246 	xmlMemoryDump();
247 	os_free(ctx);
248 }
249