Home | History | Annotate | Download | only in src
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2005-2010  Marcel Holtmann <marcel (at) 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 
     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 
    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  */
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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