1/*
2 *
3 *  BlueZ - Bluetooth protocol stack for Linux
4 *
5 *  Copyright (C) 2005-2010  Marcel Holtmann <marcel@holtmann.org>
6 *
7 *
8 *  This program is free software; you can redistribute it and/or modify
9 *  it under the terms of the GNU General Public License as published by
10 *  the Free Software Foundation; either version 2 of the License, or
11 *  (at your option) any later version.
12 *
13 *  This program is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *  GNU General Public License for more details.
17 *
18 *  You should have received a copy of the GNU General Public License
19 *  along with this program; if not, write to the Free Software
20 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 *
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#define _GNU_SOURCE
29#include <stdio.h>
30#include <errno.h>
31#include <ctype.h>
32#include <string.h>
33#include <limits.h>
34#include <stdlib.h>
35
36#include <bluetooth/sdp.h>
37#include <bluetooth/sdp_lib.h>
38
39#include "sdp-xml.h"
40
41#define STRBUFSIZE 1024
42#define MAXINDENT 64
43
44static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
45		void *data, void (*appender)(void *, const char *))
46{
47	int i, hex;
48	char buf[STRBUFSIZE];
49	char indent[MAXINDENT];
50
51	if (!value)
52		return;
53
54	if (indent_level >= MAXINDENT)
55		indent_level = MAXINDENT - 2;
56
57	for (i = 0; i < indent_level; i++)
58		indent[i] = '\t';
59
60	indent[i] = '\0';
61	buf[STRBUFSIZE - 1] = '\0';
62
63	switch (value->dtd) {
64	case SDP_DATA_NIL:
65		appender(data, indent);
66		appender(data, "<nil/>\n");
67		break;
68
69	case SDP_BOOL:
70		appender(data, indent);
71		appender(data, "<boolean value=\"");
72		appender(data, value->val.uint8 ? "true" : "false");
73		appender(data, "\" />\n");
74		break;
75
76	case SDP_UINT8:
77		appender(data, indent);
78		appender(data, "<uint8 value=\"");
79		snprintf(buf, STRBUFSIZE - 1, "0x%02x", value->val.uint8);
80		appender(data, buf);
81		appender(data, "\" />\n");
82		break;
83
84	case SDP_UINT16:
85		appender(data, indent);
86		appender(data, "<uint16 value=\"");
87		snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uint16);
88		appender(data, buf);
89		appender(data, "\" />\n");
90		break;
91
92	case SDP_UINT32:
93		appender(data, indent);
94		appender(data, "<uint32 value=\"");
95		snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uint32);
96		appender(data, buf);
97		appender(data, "\" />\n");
98		break;
99
100	case SDP_UINT64:
101		appender(data, indent);
102		appender(data, "<uint64 value=\"");
103		snprintf(buf, STRBUFSIZE - 1, "0x%016jx", value->val.uint64);
104		appender(data, buf);
105		appender(data, "\" />\n");
106		break;
107
108	case SDP_UINT128:
109		appender(data, indent);
110		appender(data, "<uint128 value=\"");
111
112		for (i = 0; i < 16; i++) {
113			sprintf(&buf[i * 2], "%02x",
114				(unsigned char) value->val.uint128.data[i]);
115		}
116
117		appender(data, buf);
118		appender(data, "\" />\n");
119		break;
120
121	case SDP_INT8:
122		appender(data, indent);
123		appender(data, "<int8 value=\"");
124		snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int8);
125		appender(data, buf);
126		appender(data, "\" />\n");
127		break;
128
129	case SDP_INT16:
130		appender(data, indent);
131		appender(data, "<int16 value=\"");
132		snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int16);
133		appender(data, buf);
134		appender(data, "\" />\n");
135		break;
136
137	case SDP_INT32:
138		appender(data, indent);
139		appender(data, "<int32 value=\"");
140		snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int32);
141		appender(data, buf);
142		appender(data, "\" />\n");
143		break;
144
145	case SDP_INT64:
146		appender(data, indent);
147		appender(data, "<int64 value=\"");
148		snprintf(buf, STRBUFSIZE - 1, "%jd", value->val.int64);
149		appender(data, buf);
150		appender(data, "\" />\n");
151		break;
152
153	case SDP_INT128:
154		appender(data, indent);
155		appender(data, "<int128 value=\"");
156
157		for (i = 0; i < 16; i++) {
158			sprintf(&buf[i * 2], "%02x",
159				(unsigned char) value->val.int128.data[i]);
160		}
161		appender(data, buf);
162
163		appender(data, "\" />\n");
164		break;
165
166	case SDP_UUID16:
167		appender(data, indent);
168		appender(data, "<uuid value=\"");
169		snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uuid.value.uuid16);
170		appender(data, buf);
171		appender(data, "\" />\n");
172		break;
173
174	case SDP_UUID32:
175		appender(data, indent);
176		appender(data, "<uuid value=\"");
177		snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uuid.value.uuid32);
178		appender(data, buf);
179		appender(data, "\" />\n");
180		break;
181
182	case SDP_UUID128:
183		appender(data, indent);
184		appender(data, "<uuid value=\"");
185
186		snprintf(buf, STRBUFSIZE - 1,
187			 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
188			 (unsigned char) value->val.uuid.value.
189			 uuid128.data[0],
190			 (unsigned char) value->val.uuid.value.
191			 uuid128.data[1],
192			 (unsigned char) value->val.uuid.value.
193			 uuid128.data[2],
194			 (unsigned char) value->val.uuid.value.
195			 uuid128.data[3],
196			 (unsigned char) value->val.uuid.value.
197			 uuid128.data[4],
198			 (unsigned char) value->val.uuid.value.
199			 uuid128.data[5],
200			 (unsigned char) value->val.uuid.value.
201			 uuid128.data[6],
202			 (unsigned char) value->val.uuid.value.
203			 uuid128.data[7],
204			 (unsigned char) value->val.uuid.value.
205			 uuid128.data[8],
206			 (unsigned char) value->val.uuid.value.
207			 uuid128.data[9],
208			 (unsigned char) value->val.uuid.value.
209			 uuid128.data[10],
210			 (unsigned char) value->val.uuid.value.
211			 uuid128.data[11],
212			 (unsigned char) value->val.uuid.value.
213			 uuid128.data[12],
214			 (unsigned char) value->val.uuid.value.
215			 uuid128.data[13],
216			 (unsigned char) value->val.uuid.value.
217			 uuid128.data[14],
218			 (unsigned char) value->val.uuid.value.
219			 uuid128.data[15]);
220
221		appender(data, buf);
222		appender(data, "\" />\n");
223		break;
224
225	case SDP_TEXT_STR8:
226	case SDP_TEXT_STR16:
227	case SDP_TEXT_STR32:
228	{
229		int num_chars_to_escape = 0;
230		int length = value->unitSize - 1;
231		char *strBuf = 0;
232
233		hex = 0;
234
235		for (i = 0; i < length; i++) {
236			if (!isprint(value->val.str[i]) &&
237					value->val.str[i] != '\0') {
238				hex = 1;
239				break;
240			}
241
242			/* XML is evil, must do this... */
243			if ((value->val.str[i] == '<') ||
244					(value->val.str[i] == '>') ||
245					(value->val.str[i] == '"') ||
246					(value->val.str[i] == '&'))
247				num_chars_to_escape++;
248		}
249
250		appender(data, indent);
251
252		appender(data, "<text ");
253
254		if (hex) {
255			appender(data, "encoding=\"hex\" ");
256			strBuf = malloc(sizeof(char)
257						 * ((value->unitSize-1) * 2 + 1));
258
259			/* Unit Size seems to include the size for dtd
260			   It is thus off by 1
261			   This is safe for Normal strings, but not
262			   hex encoded data */
263			for (i = 0; i < (value->unitSize-1); i++)
264				sprintf(&strBuf[i*sizeof(char)*2],
265					"%02x",
266					(unsigned char) value->val.str[i]);
267
268			strBuf[(value->unitSize-1) * 2] = '\0';
269		}
270		else {
271			int j;
272			/* escape the XML disallowed chars */
273			strBuf = malloc(sizeof(char) *
274					(value->unitSize + 1 + num_chars_to_escape * 4));
275			for (i = 0, j = 0; i < length; i++) {
276				if (value->val.str[i] == '&') {
277					strBuf[j++] = '&';
278					strBuf[j++] = 'a';
279					strBuf[j++] = 'm';
280					strBuf[j++] = 'p';
281				}
282				else if (value->val.str[i] == '<') {
283					strBuf[j++] = '&';
284					strBuf[j++] = 'l';
285					strBuf[j++] = 't';
286				}
287				else if (value->val.str[i] == '>') {
288					strBuf[j++] = '&';
289					strBuf[j++] = 'g';
290					strBuf[j++] = 't';
291				}
292				else if (value->val.str[i] == '"') {
293					strBuf[j++] = '&';
294					strBuf[j++] = 'q';
295					strBuf[j++] = 'u';
296					strBuf[j++] = 'o';
297					strBuf[j++] = 't';
298				}
299				else if (value->val.str[i] == '\0') {
300					strBuf[j++] = ' ';
301				} else {
302					strBuf[j++] = value->val.str[i];
303				}
304			}
305
306			strBuf[j] = '\0';
307		}
308
309		appender(data, "value=\"");
310		appender(data, strBuf);
311		appender(data, "\" />\n");
312		free(strBuf);
313		break;
314	}
315
316	case SDP_URL_STR8:
317	case SDP_URL_STR16:
318	case SDP_URL_STR32:
319	{
320		char *strBuf;
321
322		appender(data, indent);
323		appender(data, "<url value=\"");
324		strBuf = strndup(value->val.str, value->unitSize - 1);
325		appender(data, strBuf);
326		free(strBuf);
327		appender(data, "\" />\n");
328		break;
329	}
330
331	case SDP_SEQ8:
332	case SDP_SEQ16:
333	case SDP_SEQ32:
334		appender(data, indent);
335		appender(data, "<sequence>\n");
336
337		convert_raw_data_to_xml(value->val.dataseq,
338					indent_level + 1, data, appender);
339
340		appender(data, indent);
341		appender(data, "</sequence>\n");
342
343		break;
344
345	case SDP_ALT8:
346	case SDP_ALT16:
347	case SDP_ALT32:
348		appender(data, indent);
349
350		appender(data, "<alternate>\n");
351
352		convert_raw_data_to_xml(value->val.dataseq,
353					indent_level + 1, data, appender);
354		appender(data, indent);
355
356		appender(data, "</alternate>\n");
357
358		break;
359	}
360
361	convert_raw_data_to_xml(value->next, indent_level, data, appender);
362}
363
364struct conversion_data {
365	void *data;
366	void (*appender)(void *data, const char *);
367};
368
369static void convert_raw_attr_to_xml_func(void *val, void *data)
370{
371	struct conversion_data *cd = data;
372	sdp_data_t *value = val;
373	char buf[STRBUFSIZE];
374
375	buf[STRBUFSIZE - 1] = '\0';
376	snprintf(buf, STRBUFSIZE - 1, "\t<attribute id=\"0x%04x\">\n",
377		 value->attrId);
378	cd->appender(cd->data, buf);
379
380	if (data)
381		convert_raw_data_to_xml(value, 2, cd->data, cd->appender);
382	else
383		cd->appender(cd->data, "\t\tNULL\n");
384
385	cd->appender(cd->data, "\t</attribute>\n");
386}
387
388/*
389 * Will convert the sdp record to XML.  The appender and data can be used
390 * to control where to output the record (e.g. file or a data buffer).  The
391 * appender will be called repeatedly with data and the character buffer
392 * (containing parts of the generated XML) to append.
393 */
394void convert_sdp_record_to_xml(sdp_record_t *rec,
395			void *data, void (*appender)(void *, const char *))
396{
397	struct conversion_data cd;
398
399	cd.data = data;
400	cd.appender = appender;
401
402	if (rec && rec->attrlist) {
403		appender(data, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n");
404		appender(data, "<record>\n");
405		sdp_list_foreach(rec->attrlist,
406				 convert_raw_attr_to_xml_func, &cd);
407		appender(data, "</record>\n");
408	}
409}
410
411static sdp_data_t *sdp_xml_parse_uuid128(const char *data)
412{
413	uint128_t val;
414	unsigned int i, j;
415
416	char buf[3];
417
418	memset(&val, 0, sizeof(val));
419
420	buf[2] = '\0';
421
422	for (j = 0, i = 0; i < strlen(data);) {
423		if (data[i] == '-') {
424			i++;
425			continue;
426		}
427
428		buf[0] = data[i];
429		buf[1] = data[i + 1];
430
431		val.data[j++] = strtoul(buf, 0, 16);
432		i += 2;
433	}
434
435	return sdp_data_alloc(SDP_UUID128, &val);
436}
437
438sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record)
439{
440	sdp_data_t *ret;
441	char *endptr;
442	uint32_t val;
443	uint16_t val2;
444	int len;
445
446	len = strlen(data);
447
448	if (len == 36) {
449		ret = sdp_xml_parse_uuid128(data);
450		goto result;
451	}
452
453	val = strtoll(data, &endptr, 16);
454
455	/* Couldn't parse */
456	if (*endptr != '\0')
457		return NULL;
458
459	if (val > USHRT_MAX) {
460		ret = sdp_data_alloc(SDP_UUID32, &val);
461		goto result;
462	}
463
464	val2 = val;
465
466	ret = sdp_data_alloc(SDP_UUID16, &val2);
467
468result:
469	if (record && ret)
470		sdp_pattern_add_uuid(record, &ret->val.uuid);
471
472	return ret;
473}
474
475sdp_data_t *sdp_xml_parse_int(const char * data, uint8_t dtd)
476{
477	char *endptr;
478	sdp_data_t *ret = NULL;
479
480	switch (dtd) {
481	case SDP_BOOL:
482	{
483		uint8_t val = 0;
484
485		if (!strcmp("true", data)) {
486			val = 1;
487		}
488
489		else if (!strcmp("false", data)) {
490			val = 0;
491		}
492		else {
493			return NULL;
494		}
495
496		ret = sdp_data_alloc(dtd, &val);
497		break;
498	}
499
500	case SDP_INT8:
501	{
502		int8_t val = strtoul(data, &endptr, 0);
503
504		/* Failed to parse */
505		if ((endptr != data) && (*endptr != '\0'))
506			return NULL;
507
508		ret = sdp_data_alloc(dtd, &val);
509		break;
510	}
511
512	case SDP_UINT8:
513	{
514		uint8_t val = strtoul(data, &endptr, 0);
515
516		/* Failed to parse */
517		if ((endptr != data) && (*endptr != '\0'))
518			return NULL;
519
520		ret = sdp_data_alloc(dtd, &val);
521		break;
522	}
523
524	case SDP_INT16:
525	{
526		int16_t val = strtoul(data, &endptr, 0);
527
528		/* Failed to parse */
529		if ((endptr != data) && (*endptr != '\0'))
530			return NULL;
531
532		ret = sdp_data_alloc(dtd, &val);
533		break;
534	}
535
536	case SDP_UINT16:
537	{
538		uint16_t val = strtoul(data, &endptr, 0);
539
540		/* Failed to parse */
541		if ((endptr != data) && (*endptr != '\0'))
542			return NULL;
543
544		ret = sdp_data_alloc(dtd, &val);
545		break;
546	}
547
548	case SDP_INT32:
549	{
550		int32_t val = strtoul(data, &endptr, 0);
551
552		/* Failed to parse */
553		if ((endptr != data) && (*endptr != '\0'))
554			return NULL;
555
556		ret = sdp_data_alloc(dtd, &val);
557		break;
558	}
559
560	case SDP_UINT32:
561	{
562		uint32_t val = strtoul(data, &endptr, 0);
563
564		/* Failed to parse */
565		if ((endptr != data) && (*endptr != '\0'))
566			return NULL;
567
568		ret = sdp_data_alloc(dtd, &val);
569		break;
570	}
571
572	case SDP_INT64:
573	{
574		int64_t val = strtoull(data, &endptr, 0);
575
576		/* Failed to parse */
577		if ((endptr != data) && (*endptr != '\0'))
578			return NULL;
579
580		ret = sdp_data_alloc(dtd, &val);
581		break;
582	}
583
584	case SDP_UINT64:
585	{
586		uint64_t val = strtoull(data, &endptr, 0);
587
588		/* Failed to parse */
589		if ((endptr != data) && (*endptr != '\0'))
590			return NULL;
591
592		ret = sdp_data_alloc(dtd, &val);
593		break;
594	}
595
596	case SDP_INT128:
597	case SDP_UINT128:
598	{
599		uint128_t val;
600		int i = 0;
601		char buf[3];
602
603		buf[2] = '\0';
604
605		for (; i < 32; i += 2) {
606			buf[0] = data[i];
607			buf[1] = data[i + 1];
608
609			val.data[i >> 1] = strtoul(buf, 0, 16);
610		}
611
612		ret = sdp_data_alloc(dtd, &val);
613		break;
614	}
615
616	};
617
618	return ret;
619}
620
621static char *sdp_xml_parse_string_decode(const char *data, char encoding, uint32_t *length)
622{
623	int len = strlen(data);
624	char *text;
625
626	if (encoding == SDP_XML_ENCODING_NORMAL) {
627		text = strdup(data);
628		*length = len;
629	} else {
630		char buf[3], *decoded;
631		int i;
632
633		decoded = malloc((len >> 1) + 1);
634
635		/* Ensure the string is a power of 2 */
636		len = (len >> 1) << 1;
637
638		buf[2] = '\0';
639
640		for (i = 0; i < len; i += 2) {
641			buf[0] = data[i];
642			buf[1] = data[i + 1];
643
644			decoded[i >> 1] = strtoul(buf, 0, 16);
645		}
646
647		decoded[len >> 1] = '\0';
648		text = decoded;
649		*length = len >> 1;
650	}
651
652	return text;
653}
654
655sdp_data_t *sdp_xml_parse_url(const char *data)
656{
657	uint8_t dtd = SDP_URL_STR8;
658	char *url;
659	uint32_t length;
660	sdp_data_t *ret;
661
662	url = sdp_xml_parse_string_decode(data,
663				SDP_XML_ENCODING_NORMAL, &length);
664
665	if (length > UCHAR_MAX)
666		dtd = SDP_URL_STR16;
667
668	ret = sdp_data_alloc_with_length(dtd, url, length);
669
670	free(url);
671
672	return ret;
673}
674
675sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
676{
677	uint8_t dtd = SDP_TEXT_STR8;
678	char *text;
679	uint32_t length;
680	sdp_data_t *ret;
681
682	text = sdp_xml_parse_string_decode(data, encoding, &length);
683
684	if (length > UCHAR_MAX)
685		dtd = SDP_TEXT_STR16;
686
687	ret = sdp_data_alloc_with_length(dtd, text, length);
688
689	free(text);
690
691	return ret;
692}
693
694sdp_data_t *sdp_xml_parse_nil(const char *data)
695{
696	return sdp_data_alloc(SDP_DATA_NIL, 0);
697}
698
699#define DEFAULT_XML_DATA_SIZE 1024
700
701struct sdp_xml_data *sdp_xml_data_alloc(void)
702{
703	struct sdp_xml_data *elem;
704
705	elem = malloc(sizeof(struct sdp_xml_data));
706	if (!elem)
707		return NULL;
708
709	memset(elem, 0, sizeof(struct sdp_xml_data));
710
711	/* Null terminate the text */
712	elem->size = DEFAULT_XML_DATA_SIZE;
713	elem->text = malloc(DEFAULT_XML_DATA_SIZE);
714	elem->text[0] = '\0';
715
716	return elem;
717}
718
719void sdp_xml_data_free(struct sdp_xml_data *elem)
720{
721	if (elem->data)
722		sdp_data_free(elem->data);
723
724	free(elem->name);
725	free(elem->text);
726	free(elem);
727}
728
729struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem)
730{
731	char *newbuf;
732
733	newbuf = malloc(elem->size * 2);
734	if (!newbuf)
735		return NULL;
736
737	memcpy(newbuf, elem->text, elem->size);
738	elem->size *= 2;
739	free(elem->text);
740
741	elem->text = newbuf;
742
743	return elem;
744}
745
746sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
747							sdp_record_t *record)
748{
749	const char *data = elem->text;
750
751	if (!strcmp(el, "boolean"))
752		return sdp_xml_parse_int(data, SDP_BOOL);
753	else if (!strcmp(el, "uint8"))
754		return sdp_xml_parse_int(data, SDP_UINT8);
755	else if (!strcmp(el, "uint16"))
756		return sdp_xml_parse_int(data, SDP_UINT16);
757	else if (!strcmp(el, "uint32"))
758		return sdp_xml_parse_int(data, SDP_UINT32);
759	else if (!strcmp(el, "uint64"))
760		return sdp_xml_parse_int(data, SDP_UINT64);
761	else if (!strcmp(el, "uint128"))
762		return sdp_xml_parse_int(data, SDP_UINT128);
763	else if (!strcmp(el, "int8"))
764		return sdp_xml_parse_int(data, SDP_INT8);
765	else if (!strcmp(el, "int16"))
766		return sdp_xml_parse_int(data, SDP_INT16);
767	else if (!strcmp(el, "int32"))
768		return sdp_xml_parse_int(data, SDP_INT32);
769	else if (!strcmp(el, "int64"))
770		return sdp_xml_parse_int(data, SDP_INT64);
771	else if (!strcmp(el, "int128"))
772		return sdp_xml_parse_int(data, SDP_INT128);
773	else if (!strcmp(el, "uuid"))
774		return sdp_xml_parse_uuid(data, record);
775	else if (!strcmp(el, "url"))
776		return sdp_xml_parse_url(data);
777	else if (!strcmp(el, "text"))
778		return sdp_xml_parse_text(data, elem->type);
779	else if (!strcmp(el, "nil"))
780		return sdp_xml_parse_nil(data);
781
782	return NULL;
783}
784