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 
     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 
    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  */
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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