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