• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2005-2008  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 #include <stdio.h>
29 #include <errno.h>
30 #include <ctype.h>
31 #include <string.h>
32 #include <limits.h>
33 #include <stdlib.h>
34 
35 #include <bluetooth/sdp.h>
36 #include <bluetooth/sdp_lib.h>
37 
38 #include "logging.h"
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 		hex = 0;
236 
237 		int num_chars_to_escape = 0;
238 
239 		for (i = 0; i < value->unitSize; i++) {
240 			if (i == (value->unitSize - 1)
241 			    && value->val.str[i] == '\0')
242 				break;
243 			if (!isprint(value->val.str[i])) {
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 		char *strBuf = 0;
261 
262 		if (hex) {
263 			appender(data, "encoding=\"hex\" ");
264 			strBuf = (char *) malloc(sizeof(char)
265 						 * ((value->unitSize-1) * 2 + 1));
266 
267 			/* Unit Size seems to include the size for dtd
268 			   It is thus off by 1
269 			   This is safe for Normal strings, but not
270 			   hex encoded data */
271 			for (i = 0; i < (value->unitSize-1); i++)
272 				sprintf(&strBuf[i*sizeof(char)*2],
273 					"%02x",
274 					(unsigned char) value->val.str[i]);
275 
276 			strBuf[(value->unitSize-1) * 2] = '\0';
277 		}
278 		else {
279 			int j;
280 			/* escape the XML disallowed chars */
281 			strBuf = (char *)
282 				malloc(sizeof(char) *
283 				(value->unitSize + 1 + num_chars_to_escape * 4));
284 			for (i = 0, j = 0; i < value->unitSize; i++) {
285 				if (value->val.str[i] == '&') {
286 					strBuf[j++] = '&';
287 					strBuf[j++] = 'a';
288 					strBuf[j++] = 'm';
289 					strBuf[j++] = 'p';
290 				}
291 				else if (value->val.str[i] == '<') {
292 					strBuf[j++] = '&';
293 					strBuf[j++] = 'l';
294 					strBuf[j++] = 't';
295 				}
296 				else if (value->val.str[i] == '>') {
297 					strBuf[j++] = '&';
298 					strBuf[j++] = 'g';
299 					strBuf[j++] = 't';
300 				}
301 				else if (value->val.str[i] == '"') {
302 					strBuf[j++] = '&';
303 					strBuf[j++] = 'q';
304 					strBuf[j++] = 'u';
305 					strBuf[j++] = 'o';
306 					strBuf[j++] = 't';
307 				}
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 		appender(data, indent);
327 		appender(data, "<url value=\"");
328 		appender(data, value->val.str);
329 		appender(data, "\" />\n");
330 		break;
331 
332 	case SDP_SEQ8:
333 	case SDP_SEQ16:
334 	case SDP_SEQ32:
335 		appender(data, indent);
336 		appender(data, "<sequence>\n");
337 
338 		convert_raw_data_to_xml(value->val.dataseq,
339 					indent_level + 1, data, appender);
340 
341 		appender(data, indent);
342 		appender(data, "</sequence>\n");
343 
344 		break;
345 
346 	case SDP_ALT8:
347 	case SDP_ALT16:
348 	case SDP_ALT32:
349 		appender(data, indent);
350 
351 		appender(data, "<alternate>\n");
352 
353 		convert_raw_data_to_xml(value->val.dataseq,
354 					indent_level + 1, data, appender);
355 		appender(data, indent);
356 
357 		appender(data, "</alternate>\n");
358 
359 		break;
360 	}
361 
362 	convert_raw_data_to_xml(value->next, indent_level, data, appender);
363 }
364 
365 struct conversion_data {
366 	void *data;
367 	void (*appender)(void *data, const char *);
368 };
369 
convert_raw_attr_to_xml_func(void * val,void * data)370 static void convert_raw_attr_to_xml_func(void *val, void *data)
371 {
372 	struct conversion_data *cd = (struct conversion_data *) data;
373 	sdp_data_t *value = (sdp_data_t *) val;
374 	char buf[STRBUFSIZE];
375 
376 	buf[STRBUFSIZE - 1] = '\0';
377 	snprintf(buf, STRBUFSIZE - 1, "\t<attribute id=\"0x%04x\">\n",
378 		 value->attrId);
379 	cd->appender(cd->data, buf);
380 
381 	if (data)
382 		convert_raw_data_to_xml(value, 2, cd->data, cd->appender);
383 	else
384 		cd->appender(cd->data, "\t\tNULL\n");
385 
386 	cd->appender(cd->data, "\t</attribute>\n");
387 }
388 
389 /*
390  * Will convert the sdp record to XML.  The appender and data can be used
391  * to control where to output the record (e.g. file or a data buffer).  The
392  * appender will be called repeatedly with data and the character buffer
393  * (containing parts of the generated XML) to append.
394  */
convert_sdp_record_to_xml(sdp_record_t * rec,void * data,void (* appender)(void *,const char *))395 void convert_sdp_record_to_xml(sdp_record_t *rec,
396 			void *data, void (*appender)(void *, const char *))
397 {
398 	struct conversion_data cd;
399 
400 	cd.data = data;
401 	cd.appender = appender;
402 
403 	if (rec && rec->attrlist) {
404 		appender(data, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n");
405 		appender(data, "<record>\n");
406 		sdp_list_foreach(rec->attrlist,
407 				 convert_raw_attr_to_xml_func, &cd);
408 		appender(data, "</record>\n");
409 	}
410 }
411 
sdp_xml_parse_uuid128(const char * data)412 static sdp_data_t *sdp_xml_parse_uuid128(const char *data)
413 {
414 	uint128_t val;
415 	int i;
416 	int j;
417 
418 	char buf[3];
419 
420 	memset(&val, 0, sizeof(val));
421 
422 	buf[2] = '\0';
423 
424 	for (j = 0, i = 0; i < strlen(data);) {
425 		if (data[i] == '-') {
426 			i++;
427 			continue;
428 		}
429 
430 		buf[0] = data[i];
431 		buf[1] = data[i + 1];
432 
433 		val.data[j++] = strtoul(buf, 0, 16);
434 		i += 2;
435 	}
436 
437 	return sdp_data_alloc(SDP_UUID128, &val);
438 }
439 
sdp_xml_parse_uuid(const char * data,sdp_record_t * record)440 sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record)
441 {
442 	sdp_data_t *ret;
443 	char *endptr;
444 	uint32_t val;
445 	uint16_t val2;
446 	int len;
447 
448 	len = strlen(data);
449 
450 	if (len == 36) {
451 		ret = sdp_xml_parse_uuid128(data);
452 		goto result;
453 	}
454 
455 	val = strtoll(data, &endptr, 16);
456 
457 	/* Couldn't parse */
458 	if (*endptr != '\0')
459 		return NULL;
460 
461 	if (val > USHRT_MAX) {
462 		ret = sdp_data_alloc(SDP_UUID32, &val);
463 		goto result;
464 	}
465 
466 	val2 = val;
467 
468 	ret = sdp_data_alloc(SDP_UUID16, &val2);
469 
470 result:
471 	if (record && ret)
472 		sdp_pattern_add_uuid(record, &ret->val.uuid);
473 
474 	return ret;
475 }
476 
sdp_xml_parse_int(const char * data,uint8_t dtd)477 sdp_data_t *sdp_xml_parse_int(const char * data, uint8_t dtd)
478 {
479 	char *endptr;
480 	sdp_data_t *ret = NULL;
481 
482 	switch (dtd) {
483 	case SDP_BOOL:
484 	{
485 		uint8_t val = 0;
486 
487 		if (!strcmp("true", data)) {
488 			val = 1;
489 		}
490 
491 		else if (!strcmp("false", data)) {
492 			val = 0;
493 		}
494 		else {
495 			return NULL;
496 		}
497 
498 		ret = sdp_data_alloc(dtd, &val);
499 		break;
500 	}
501 
502 	case SDP_INT8:
503 	{
504 		int8_t val = strtoul(data, &endptr, 0);
505 
506 		/* Failed to parse */
507 		if ((endptr != data) && (*endptr != '\0'))
508 			return NULL;
509 
510 		ret = sdp_data_alloc(dtd, &val);
511 		break;
512 	}
513 
514 	case SDP_UINT8:
515 	{
516 		uint8_t val = strtoul(data, &endptr, 0);
517 
518 		/* Failed to parse */
519 		if ((endptr != data) && (*endptr != '\0'))
520 			return NULL;
521 
522 		ret = sdp_data_alloc(dtd, &val);
523 		break;
524 	}
525 
526 	case SDP_INT16:
527 	{
528 		int16_t val = strtoul(data, &endptr, 0);
529 
530 		/* Failed to parse */
531 		if ((endptr != data) && (*endptr != '\0'))
532 			return NULL;
533 
534 		ret = sdp_data_alloc(dtd, &val);
535 		break;
536 	}
537 
538 	case SDP_UINT16:
539 	{
540 		uint16_t val = strtoul(data, &endptr, 0);
541 
542 		/* Failed to parse */
543 		if ((endptr != data) && (*endptr != '\0'))
544 			return NULL;
545 
546 		ret = sdp_data_alloc(dtd, &val);
547 		break;
548 	}
549 
550 	case SDP_INT32:
551 	{
552 		int32_t val = strtoul(data, &endptr, 0);
553 
554 		/* Failed to parse */
555 		if ((endptr != data) && (*endptr != '\0'))
556 			return NULL;
557 
558 		ret = sdp_data_alloc(dtd, &val);
559 		break;
560 	}
561 
562 	case SDP_UINT32:
563 	{
564 		uint32_t val = strtoul(data, &endptr, 0);
565 
566 		/* Failed to parse */
567 		if ((endptr != data) && (*endptr != '\0'))
568 			return NULL;
569 
570 		ret = sdp_data_alloc(dtd, &val);
571 		break;
572 	}
573 
574 	case SDP_INT64:
575 	{
576 		int64_t val = strtoull(data, &endptr, 0);
577 
578 		/* Failed to parse */
579 		if ((endptr != data) && (*endptr != '\0'))
580 			return NULL;
581 
582 		ret = sdp_data_alloc(dtd, &val);
583 		break;
584 	}
585 
586 	case SDP_UINT64:
587 	{
588 		uint64_t val = strtoull(data, &endptr, 0);
589 
590 		/* Failed to parse */
591 		if ((endptr != data) && (*endptr != '\0'))
592 			return NULL;
593 
594 		ret = sdp_data_alloc(dtd, &val);
595 		break;
596 	}
597 
598 	case SDP_INT128:
599 	case SDP_UINT128:
600 	{
601 		uint128_t val;
602 		int i = 0;
603 		char buf[3];
604 
605 		buf[2] = '\0';
606 
607 		for (; i < 32; i += 2) {
608 			buf[0] = data[i];
609 			buf[1] = data[i + 1];
610 
611 			val.data[i >> 1] = strtoul(buf, 0, 16);
612 		}
613 
614 		ret = sdp_data_alloc(dtd, &val);
615 		break;
616 	}
617 
618 	};
619 
620 	return ret;
621 }
622 
sdp_xml_parse_string_decode(const char * data,char encoding,uint32_t * length)623 static char *sdp_xml_parse_string_decode(const char *data, char encoding, uint32_t *length)
624 {
625 	int len = strlen(data);
626 	char *text;
627 
628 	if (encoding == SDP_XML_ENCODING_NORMAL) {
629 		text = strdup(data);
630 		*length = len;
631 	} else {
632 		char buf[3], *decoded;
633 		int i;
634 
635 		decoded = malloc((len >> 1) + 1);
636 
637 		/* Ensure the string is a power of 2 */
638 		len = (len >> 1) << 1;
639 
640 		buf[2] = '\0';
641 
642 		for (i = 0; i < len; i += 2) {
643 			buf[0] = data[i];
644 			buf[1] = data[i + 1];
645 
646 			decoded[i >> 1] = strtoul(buf, 0, 16);
647 		}
648 
649 		decoded[len >> 1] = '\0';
650 		text = decoded;
651 		*length = len >> 1;
652 	}
653 
654 	return text;
655 }
656 
sdp_xml_parse_url(const char * data)657 sdp_data_t *sdp_xml_parse_url(const char *data)
658 {
659 	uint8_t dtd = SDP_URL_STR8;
660 	char *url;
661 	uint32_t length;
662 	sdp_data_t *ret;
663 
664 	url = sdp_xml_parse_string_decode(data,
665 				SDP_XML_ENCODING_NORMAL, &length);
666 
667 	if (length > UCHAR_MAX)
668 		dtd = SDP_URL_STR16;
669 
670 	ret = sdp_data_alloc_with_length(dtd, url, length);
671 
672 	debug("URL size %d length %d: -->%s<--", ret->unitSize, length, url);
673 
674 	free(url);
675 
676 	return ret;
677 }
678 
sdp_xml_parse_text(const char * data,char encoding)679 sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
680 {
681 	uint8_t dtd = SDP_TEXT_STR8;
682 	char *text;
683 	uint32_t length;
684 	sdp_data_t *ret;
685 
686 	text = sdp_xml_parse_string_decode(data, encoding, &length);
687 
688 	if (length > UCHAR_MAX)
689 		dtd = SDP_TEXT_STR16;
690 
691 	ret = sdp_data_alloc_with_length(dtd, text, length);
692 
693 	debug("Text size %d length %d: -->%s<--", ret->unitSize, length, text);
694 
695 	free(text);
696 
697 	return ret;
698 }
699 
sdp_xml_parse_nil(const char * data)700 sdp_data_t *sdp_xml_parse_nil(const char *data)
701 {
702 	return sdp_data_alloc(SDP_DATA_NIL, 0);
703 }
704 
705 #define DEFAULT_XML_DATA_SIZE 1024
706 
sdp_xml_data_alloc()707 struct sdp_xml_data *sdp_xml_data_alloc()
708 {
709 	struct sdp_xml_data *elem;
710 
711 	elem = malloc(sizeof(struct sdp_xml_data));
712 	if (!elem)
713 		return NULL;
714 
715 	memset(elem, 0, sizeof(struct sdp_xml_data));
716 
717 	/* Null terminate the text */
718 	elem->size = DEFAULT_XML_DATA_SIZE;
719 	elem->text = malloc(DEFAULT_XML_DATA_SIZE);
720 	elem->text[0] = '\0';
721 
722 	return elem;
723 }
724 
sdp_xml_data_free(struct sdp_xml_data * elem)725 void sdp_xml_data_free(struct sdp_xml_data *elem)
726 {
727 	if (elem->data)
728 		sdp_data_free(elem->data);
729 
730 	if (elem->name)
731 		free(elem->name);
732 
733 	if (elem->text)
734 
735 		free(elem->text);
736 	free(elem);
737 }
738 
sdp_xml_data_expand(struct sdp_xml_data * elem)739 struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem)
740 {
741 	char *newbuf;
742 
743 	newbuf = malloc(elem->size * 2);
744 	if (!newbuf)
745 		return NULL;
746 
747 	memcpy(newbuf, elem->text, elem->size);
748 	elem->size *= 2;
749 	free(elem->text);
750 
751 	elem->text = newbuf;
752 
753 	return elem;
754 }
755 
sdp_xml_parse_datatype(const char * el,struct sdp_xml_data * elem,sdp_record_t * record)756 sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
757 							sdp_record_t *record)
758 {
759 	const char *data = elem->text;
760 
761 	if (!strcmp(el, "boolean"))
762 		return sdp_xml_parse_int(data, SDP_BOOL);
763 	else if (!strcmp(el, "uint8"))
764 		return sdp_xml_parse_int(data, SDP_UINT8);
765 	else if (!strcmp(el, "uint16"))
766 		return sdp_xml_parse_int(data, SDP_UINT16);
767 	else if (!strcmp(el, "uint32"))
768 		return sdp_xml_parse_int(data, SDP_UINT32);
769 	else if (!strcmp(el, "uint64"))
770 		return sdp_xml_parse_int(data, SDP_UINT64);
771 	else if (!strcmp(el, "uint128"))
772 		return sdp_xml_parse_int(data, SDP_UINT128);
773 	else if (!strcmp(el, "int8"))
774 		return sdp_xml_parse_int(data, SDP_INT8);
775 	else if (!strcmp(el, "int16"))
776 		return sdp_xml_parse_int(data, SDP_INT16);
777 	else if (!strcmp(el, "int32"))
778 		return sdp_xml_parse_int(data, SDP_INT32);
779 	else if (!strcmp(el, "int64"))
780 		return sdp_xml_parse_int(data, SDP_INT64);
781 	else if (!strcmp(el, "int128"))
782 		return sdp_xml_parse_int(data, SDP_INT128);
783 	else if (!strcmp(el, "uuid"))
784 		return sdp_xml_parse_uuid(data, record);
785 	else if (!strcmp(el, "url"))
786 		return sdp_xml_parse_url(data);
787 	else if (!strcmp(el, "text"))
788 		return sdp_xml_parse_text(data, elem->type);
789 	else if (!strcmp(el, "nil"))
790 		return sdp_xml_parse_nil(data);
791 
792 	return NULL;
793 }
794