1 /*
2  * libiio - Library for interfacing industrial I/O (IIO) devices
3  *
4  * Copyright (C) 2014 Analog Devices, Inc.
5  * Author: Paul Cercueil <paul.cercueil@analog.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * */
18 
19 #include "debug.h"
20 #include "iio-private.h"
21 
22 #include <errno.h>
23 #include <libxml/tree.h>
24 #include <string.h>
25 
add_attr_to_channel(struct iio_channel * chn,xmlNode * n)26 static int add_attr_to_channel(struct iio_channel *chn, xmlNode *n)
27 {
28 	xmlAttr *attr;
29 	char *name = NULL, *filename = NULL;
30 	struct iio_channel_attr *attrs;
31 
32 	for (attr = n->properties; attr; attr = attr->next) {
33 		if (!strcmp((char *) attr->name, "name")) {
34 			name = iio_strdup((char *) attr->children->content);
35 		} else if (!strcmp((char *) attr->name, "filename")) {
36 			filename = iio_strdup((char *) attr->children->content);
37 		} else {
38 			WARNING("Unknown field \'%s\' in channel %s\n",
39 					attr->name, chn->id);
40 		}
41 	}
42 
43 	if (!name) {
44 		ERROR("Incomplete attribute in channel %s\n", chn->id);
45 		goto err_free;
46 	}
47 
48 	if (!filename) {
49 		filename = iio_strdup(name);
50 		if (!filename)
51 			goto err_free;
52 	}
53 
54 	attrs = realloc(chn->attrs, (1 + chn->nb_attrs) *
55 			sizeof(struct iio_channel_attr));
56 	if (!attrs)
57 		goto err_free;
58 
59 	attrs[chn->nb_attrs].filename = filename;
60 	attrs[chn->nb_attrs++].name = name;
61 	chn->attrs = attrs;
62 	return 0;
63 
64 err_free:
65 	if (name)
66 		free(name);
67 	if (filename)
68 		free(filename);
69 	return -1;
70 }
71 
add_attr_to_device(struct iio_device * dev,xmlNode * n,enum iio_attr_type type)72 static int add_attr_to_device(struct iio_device *dev, xmlNode *n, enum iio_attr_type type)
73 {
74 	xmlAttr *attr;
75 	char **attrs, *name = NULL;
76 
77 	for (attr = n->properties; attr; attr = attr->next) {
78 		if (!strcmp((char *) attr->name, "name")) {
79 			name = iio_strdup((char *) attr->children->content);
80 		} else {
81 			WARNING("Unknown field \'%s\' in device %s\n",
82 					attr->name, dev->id);
83 		}
84 	}
85 
86 	if (!name) {
87 		ERROR("Incomplete attribute in device %s\n", dev->id);
88 		goto err_free;
89 	}
90 
91 	switch(type) {
92 		case IIO_ATTR_TYPE_DEBUG:
93 			attrs = realloc(dev->debug_attrs,
94 					(1 + dev->nb_debug_attrs) * sizeof(char *));
95 			break;
96 		case IIO_ATTR_TYPE_DEVICE:
97 			attrs = realloc(dev->attrs,
98 					(1 + dev->nb_attrs) * sizeof(char *));
99 			break;
100 		case IIO_ATTR_TYPE_BUFFER:
101 			attrs = realloc(dev->buffer_attrs,
102 					(1 + dev->nb_buffer_attrs) * sizeof(char *));
103 			break;
104 		default:
105 			attrs = NULL;
106 			break;
107 	}
108 	if (!attrs)
109 		goto err_free;
110 
111 	switch(type) {
112 		case IIO_ATTR_TYPE_DEBUG:
113 			attrs[dev->nb_debug_attrs++] = name;
114 			dev->debug_attrs = attrs;
115 			break;
116 		case IIO_ATTR_TYPE_DEVICE:
117 			attrs[dev->nb_attrs++] = name;
118 			dev->attrs = attrs;
119 			break;
120 		case IIO_ATTR_TYPE_BUFFER:
121 			attrs[dev->nb_buffer_attrs++] = name;
122 			dev->buffer_attrs = attrs;
123 			break;
124 	}
125 
126 	return 0;
127 
128 err_free:
129 	if (name)
130 		free(name);
131 	return -1;
132 }
133 
setup_scan_element(struct iio_channel * chn,xmlNode * n)134 static void setup_scan_element(struct iio_channel *chn, xmlNode *n)
135 {
136 	xmlAttr *attr;
137 
138 	for (attr = n->properties; attr; attr = attr->next) {
139 		const char *name = (const char *) attr->name,
140 		      *content = (const char *) attr->children->content;
141 		if (!strcmp(name, "index")) {
142 			chn->index = atol(content);
143 		} else if (!strcmp(name, "format")) {
144 			char e, s;
145 			if (strchr(content, 'X')) {
146 				sscanf(content, "%ce:%c%u/%uX%u>>%u", &e, &s,
147 					&chn->format.bits,
148 					&chn->format.length,
149 					&chn->format.repeat,
150 					&chn->format.shift);
151 			} else {
152 				chn->format.repeat = 1;
153 				sscanf(content, "%ce:%c%u/%u>>%u", &e, &s,
154 					&chn->format.bits,
155 					&chn->format.length,
156 					&chn->format.shift);
157 			}
158 			chn->format.is_be = e == 'b';
159 			chn->format.is_signed = (s == 's' || s == 'S');
160 			chn->format.is_fully_defined = (s == 'S' || s == 'U' ||
161 				chn->format.bits == chn->format.length);
162 		} else if (!strcmp(name, "scale")) {
163 			chn->format.with_scale = true;
164 			chn->format.scale = atof(content);
165 		} else {
166 			WARNING("Unknown attribute \'%s\' in <scan-element>\n",
167 					name);
168 		}
169 	}
170 }
171 
create_channel(struct iio_device * dev,xmlNode * n)172 static struct iio_channel * create_channel(struct iio_device *dev, xmlNode *n)
173 {
174 	xmlAttr *attr;
175 	struct iio_channel *chn = zalloc(sizeof(*chn));
176 	if (!chn)
177 		return NULL;
178 
179 	chn->dev = dev;
180 
181 	/* Set the default index value < 0 (== no index) */
182 	chn->index = -ENOENT;
183 
184 	for (attr = n->properties; attr; attr = attr->next) {
185 		const char *name = (const char *) attr->name,
186 		      *content = (const char *) attr->children->content;
187 		if (!strcmp(name, "name")) {
188 			chn->name = iio_strdup(content);
189 		} else if (!strcmp(name, "id")) {
190 			chn->id = iio_strdup(content);
191 		} else if (!strcmp(name, "type")) {
192 			if (!strcmp(content, "output"))
193 				chn->is_output = true;
194 			else if (strcmp(content, "input"))
195 				WARNING("Unknown channel type %s\n", content);
196 		} else {
197 			WARNING("Unknown attribute \'%s\' in <channel>\n",
198 					name);
199 		}
200 	}
201 
202 	if (!chn->id) {
203 		ERROR("Incomplete <attribute>\n");
204 		goto err_free_channel;
205 	}
206 
207 	for (n = n->children; n; n = n->next) {
208 		if (!strcmp((char *) n->name, "attribute")) {
209 			if (add_attr_to_channel(chn, n) < 0)
210 				goto err_free_channel;
211 		} else if (!strcmp((char *) n->name, "scan-element")) {
212 			chn->is_scan_element = true;
213 			setup_scan_element(chn, n);
214 		} else if (strcmp((char *) n->name, "text")) {
215 			WARNING("Unknown children \'%s\' in <channel>\n",
216 					n->name);
217 			continue;
218 		}
219 	}
220 
221 	iio_channel_init_finalize(chn);
222 
223 	return chn;
224 
225 err_free_channel:
226 	free_channel(chn);
227 	return NULL;
228 }
229 
create_device(struct iio_context * ctx,xmlNode * n)230 static struct iio_device * create_device(struct iio_context *ctx, xmlNode *n)
231 {
232 	xmlAttr *attr;
233 	struct iio_device *dev = zalloc(sizeof(*dev));
234 	if (!dev)
235 		return NULL;
236 
237 	dev->ctx = ctx;
238 
239 	for (attr = n->properties; attr; attr = attr->next) {
240 		if (!strcmp((char *) attr->name, "name")) {
241 			dev->name = iio_strdup(
242 					(char *) attr->children->content);
243 		} else if (!strcmp((char *) attr->name, "id")) {
244 			dev->id = iio_strdup((char *) attr->children->content);
245 		} else {
246 			WARNING("Unknown attribute \'%s\' in <device>\n",
247 					attr->name);
248 		}
249 	}
250 
251 	if (!dev->id) {
252 		ERROR("Unable to read device ID\n");
253 		goto err_free_device;
254 	}
255 
256 	for (n = n->children; n; n = n->next) {
257 		if (!strcmp((char *) n->name, "channel")) {
258 			struct iio_channel **chns,
259 					   *chn = create_channel(dev, n);
260 			if (!chn) {
261 				ERROR("Unable to create channel\n");
262 				goto err_free_device;
263 			}
264 
265 			chns = realloc(dev->channels, (1 + dev->nb_channels) *
266 					sizeof(struct iio_channel *));
267 			if (!chns) {
268 				ERROR("Unable to allocate memory\n");
269 				free(chn);
270 				goto err_free_device;
271 			}
272 
273 			chns[dev->nb_channels++] = chn;
274 			dev->channels = chns;
275 		} else if (!strcmp((char *) n->name, "attribute")) {
276 			if (add_attr_to_device(dev, n, IIO_ATTR_TYPE_DEVICE) < 0)
277 				goto err_free_device;
278 		} else if (!strcmp((char *) n->name, "debug-attribute")) {
279 			if (add_attr_to_device(dev, n, IIO_ATTR_TYPE_DEBUG) < 0)
280 				goto err_free_device;
281 		} else if (!strcmp((char *) n->name, "buffer-attribute")) {
282 			if (add_attr_to_device(dev, n, IIO_ATTR_TYPE_BUFFER) < 0)
283 				goto err_free_device;
284 		} else if (strcmp((char *) n->name, "text")) {
285 			WARNING("Unknown children \'%s\' in <device>\n",
286 					n->name);
287 			continue;
288 		}
289 	}
290 
291 	dev->words = (dev->nb_channels + 31) / 32;
292 	if (dev->words) {
293 		dev->mask = calloc(dev->words, sizeof(*dev->mask));
294 		if (!dev->mask) {
295 			errno = ENOMEM;
296 			goto err_free_device;
297 		}
298 	}
299 
300 	return dev;
301 
302 err_free_device:
303 	free_device(dev);
304 	return NULL;
305 }
306 
xml_clone(const struct iio_context * ctx)307 static struct iio_context * xml_clone(const struct iio_context *ctx)
308 {
309 	return xml_create_context_mem(ctx->xml, strlen(ctx->xml));
310 }
311 
312 static const struct iio_backend_ops xml_ops = {
313 	.clone = xml_clone,
314 };
315 
parse_context_attr(struct iio_context * ctx,xmlNode * n)316 static int parse_context_attr(struct iio_context *ctx, xmlNode *n)
317 {
318 	xmlAttr *attr;
319 	const char *name = NULL, *value = NULL;
320 
321 	for (attr = n->properties; attr; attr = attr->next) {
322 		if (!strcmp((const char *) attr->name, "name")) {
323 			name = (const char *) attr->children->content;
324 		} else if (!strcmp((const char *) attr->name, "value")) {
325 			value = (const char *) attr->children->content;
326 		}
327 	}
328 
329 	if (!name || !value)
330 		return -EINVAL;
331 	else
332 		return iio_context_add_attr(ctx, name, value);
333 }
334 
iio_create_xml_context_helper(xmlDoc * doc)335 static struct iio_context * iio_create_xml_context_helper(xmlDoc *doc)
336 {
337 	unsigned int i;
338 	xmlNode *root, *n;
339 	xmlAttr *attr;
340 	int err = -ENOMEM;
341 	struct iio_context *ctx = zalloc(sizeof(*ctx));
342 	if (!ctx)
343 		goto err_set_errno;
344 
345 	ctx->name = "xml";
346 	ctx->ops = &xml_ops;
347 
348 	root = xmlDocGetRootElement(doc);
349 	if (strcmp((char *) root->name, "context")) {
350 		ERROR("Unrecognized XML file\n");
351 		err = -EINVAL;
352 		goto err_free_ctx;
353 	}
354 
355 	for (attr = root->properties; attr; attr = attr->next) {
356 		if (!strcmp((char *) attr->name, "description"))
357 			ctx->description = iio_strdup(
358 					(char *) attr->children->content);
359 		else if (strcmp((char *) attr->name, "name"))
360 			WARNING("Unknown parameter \'%s\' in <context>\n",
361 					(char *) attr->children->content);
362 	}
363 
364 	for (n = root->children; n; n = n->next) {
365 		struct iio_device **devs, *dev;
366 
367 		if (!strcmp((char *) n->name, "context-attribute")) {
368 			err = parse_context_attr(ctx, n);
369 			if (err)
370 				goto err_free_devices;
371 			else
372 				continue;
373 		} else if (strcmp((char *) n->name, "device")) {
374 			if (strcmp((char *) n->name, "text"))
375 				WARNING("Unknown children \'%s\' in "
376 						"<context>\n", n->name);
377 			continue;
378 		}
379 
380 		dev = create_device(ctx, n);
381 		if (!dev) {
382 			ERROR("Unable to create device\n");
383 			goto err_free_devices;
384 		}
385 
386 		devs = realloc(ctx->devices, (1 + ctx->nb_devices) *
387 				sizeof(struct iio_device *));
388 		if (!devs) {
389 			ERROR("Unable to allocate memory\n");
390 			free(dev);
391 			goto err_free_devices;
392 		}
393 
394 		devs[ctx->nb_devices++] = dev;
395 		ctx->devices = devs;
396 	}
397 
398 	err = iio_context_init(ctx);
399 	if (err)
400 		goto err_free_devices;
401 
402 	return ctx;
403 
404 err_free_devices:
405 	for (i = 0; i < ctx->nb_devices; i++)
406 		free_device(ctx->devices[i]);
407 	if (ctx->nb_devices)
408 		free(ctx->devices);
409 	for (i = 0; i < ctx->nb_attrs; i++) {
410 		free(ctx->attrs[i]);
411 		free(ctx->values[i]);
412 	}
413 	free(ctx->attrs);
414 	free(ctx->values);
415 err_free_ctx:
416 	free(ctx);
417 err_set_errno:
418 	errno = -err;
419 	return NULL;
420 }
421 
xml_create_context(const char * xml_file)422 struct iio_context * xml_create_context(const char *xml_file)
423 {
424 	struct iio_context *ctx;
425 	xmlDoc *doc;
426 
427 	LIBXML_TEST_VERSION;
428 
429 	doc = xmlReadFile(xml_file, NULL, XML_PARSE_DTDVALID);
430 	if (!doc) {
431 		ERROR("Unable to parse XML file\n");
432 		errno = EINVAL;
433 		return NULL;
434 	}
435 
436 	ctx = iio_create_xml_context_helper(doc);
437 	xmlFreeDoc(doc);
438 	return ctx;
439 }
440 
xml_create_context_mem(const char * xml,size_t len)441 struct iio_context * xml_create_context_mem(const char *xml, size_t len)
442 {
443 	struct iio_context *ctx;
444 	xmlDoc *doc;
445 
446 	LIBXML_TEST_VERSION;
447 
448 	doc = xmlReadMemory(xml, (int) len, NULL, NULL, XML_PARSE_DTDVALID);
449 	if (!doc) {
450 		ERROR("Unable to parse XML file\n");
451 		errno = EINVAL;
452 		return NULL;
453 	}
454 
455 	ctx = iio_create_xml_context_helper(doc);
456 	xmlFreeDoc(doc);
457 	return ctx;
458 }
459