• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
convert_raw_data_to_xml(sdp_data_t * value,int indent_level,void * data,void (* appender)(void *,const char *))44 static 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 
364 struct conversion_data {
365 	void *data;
366 	void (*appender)(void *data, const char *);
367 };
368 
convert_raw_attr_to_xml_func(void * val,void * data)369 static 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  */
convert_sdp_record_to_xml(sdp_record_t * rec,void * data,void (* appender)(void *,const char *))394 void 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 
sdp_xml_parse_uuid128(const char * data)411 static 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 
sdp_xml_parse_uuid(const char * data,sdp_record_t * record)438 sdp_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 
468 result:
469 	if (record && ret)
470 		sdp_pattern_add_uuid(record, &ret->val.uuid);
471 
472 	return ret;
473 }
474 
sdp_xml_parse_int(const char * data,uint8_t dtd)475 sdp_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 
sdp_xml_parse_string_decode(const char * data,char encoding,uint32_t * length)621 static 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 
sdp_xml_parse_url(const char * data)655 sdp_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 
sdp_xml_parse_text(const char * data,char encoding)675 sdp_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 
sdp_xml_parse_nil(const char * data)694 sdp_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 
sdp_xml_data_alloc(void)701 struct 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 
sdp_xml_data_free(struct sdp_xml_data * elem)719 void 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 
sdp_xml_data_expand(struct sdp_xml_data * elem)729 struct 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 
sdp_xml_parse_datatype(const char * el,struct sdp_xml_data * elem,sdp_record_t * record)746 sdp_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