Diff between 1ff99151e058947fe2e531084645e0eef7a1afed and 0a4f70772e3c2f968faae4ea96502f7d8aa9cc9b

Changed Files

File Additions Deletions Status
src/sdp-xml.c +717 -716 modified
src/sdp-xml.h +0 -23 modified

Full Patch

diff --git a/src/sdp-xml.c b/src/sdp-xml.c
index 7d5f626..262b8e7 100644
--- a/src/sdp-xml.c
+++ b/src/sdp-xml.c
@@ -45,6 +45,16 @@
 #define STRBUFSIZE 1024
 #define MAXINDENT 64
 
+struct sdp_xml_data {
+	char *text;			/* Pointer to the current buffer */
+	int size;			/* Size of the current buffer */
+	sdp_data_t *data;		/* The current item being built */
+	struct sdp_xml_data *next;	/* Next item on the stack */
+	char type;			/* 0 = Text or Hexadecimal */
+	char *name;			/* Name, optional in the dtd */
+	/* TODO: What is it used for? */
+};
+
 struct context_data {
 	sdp_record_t *record;
 	sdp_data_t attr_data;
@@ -63,931 +73,922 @@ static int compute_seq_size(sdp_data_t *data)
 	return unit_size;
 }
 
-static void element_start(GMarkupParseContext *context,
-		const gchar *element_name, const gchar **attribute_names,
-		const gchar **attribute_values, gpointer user_data, GError **err)
-{
-	struct context_data *ctx_data = user_data;
+#define DEFAULT_XML_DATA_SIZE 1024
 
-	if (!strcmp(element_name, "record"))
-		return;
+static struct sdp_xml_data *sdp_xml_data_alloc(void)
+{
+	struct sdp_xml_data *elem;
 
-	if (!strcmp(element_name, "attribute")) {
-		int i;
-		for (i = 0; attribute_names[i]; i++) {
-			if (!strcmp(attribute_names[i], "id")) {
-				ctx_data->attr_id = strtol(attribute_values[i], 0, 0);
-				break;
-			}
-		}
-		DBG("New attribute 0x%04x", ctx_data->attr_id);
-		return;
-	}
+	elem = malloc(sizeof(struct sdp_xml_data));
+	if (!elem)
+		return NULL;
 
-	if (ctx_data->stack_head) {
-		struct sdp_xml_data *newelem = sdp_xml_data_alloc();
-		newelem->next = ctx_data->stack_head;
-		ctx_data->stack_head = newelem;
-	} else {
-		ctx_data->stack_head = sdp_xml_data_alloc();
-		ctx_data->stack_head->next = NULL;
-	}
+	memset(elem, 0, sizeof(struct sdp_xml_data));
 
-	if (!strcmp(element_name, "sequence"))
-		ctx_data->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL);
-	else if (!strcmp(element_name, "alternate"))
-		ctx_data->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL);
-	else {
-		int i;
-		/* Parse value, name, encoding */
-		for (i = 0; attribute_names[i]; i++) {
-			if (!strcmp(attribute_names[i], "value")) {
-				int curlen = strlen(ctx_data->stack_head->text);
-				int attrlen = strlen(attribute_values[i]);
+	/* Null terminate the text */
+	elem->size = DEFAULT_XML_DATA_SIZE;
+	elem->text = malloc(DEFAULT_XML_DATA_SIZE);
+	elem->text[0] = '\0';
 
-				/* Ensure we're big enough */
-				while ((curlen + 1 + attrlen) > ctx_data->stack_head->size) {
-					sdp_xml_data_expand(ctx_data->stack_head);
-				}
+	return elem;
+}
 
-				memcpy(ctx_data->stack_head->text + curlen,
-						attribute_values[i], attrlen);
-				ctx_data->stack_head->text[curlen + attrlen] = '\0';
-			}
+static struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem)
+{
+	char *newbuf;
 
-			if (!strcmp(attribute_names[i], "encoding")) {
-				if (!strcmp(attribute_values[i], "hex"))
-					ctx_data->stack_head->type = 1;
-			}
+	newbuf = malloc(elem->size * 2);
+	if (!newbuf)
+		return NULL;
 
-			if (!strcmp(attribute_names[i], "name")) {
-				ctx_data->stack_head->name = strdup(attribute_values[i]);
-			}
-		}
+	memcpy(newbuf, elem->text, elem->size);
+	elem->size *= 2;
+	free(elem->text);
 
-		ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name,
-				ctx_data->stack_head, ctx_data->record);
+	elem->text = newbuf;
 
-		if (ctx_data->stack_head->data == NULL)
-			error("Can't parse element %s", element_name);
-	}
+	return elem;
 }
 
-static void element_end(GMarkupParseContext *context,
-		const gchar *element_name, gpointer user_data, GError **err)
+static sdp_data_t *sdp_xml_parse_uuid128(const char *data)
 {
-	struct context_data *ctx_data = user_data;
-	struct sdp_xml_data *elem;
-
-	if (!strcmp(element_name, "record"))
-		return;
-
-	if (!strcmp(element_name, "attribute")) {
-		if (ctx_data->stack_head && ctx_data->stack_head->data) {
-			int ret = sdp_attr_add(ctx_data->record, ctx_data->attr_id,
-							ctx_data->stack_head->data);
-			if (ret == -1)
-				DBG("Could not add attribute 0x%04x",
-							ctx_data->attr_id);
-
-			ctx_data->stack_head->data = NULL;
-			sdp_xml_data_free(ctx_data->stack_head);
-			ctx_data->stack_head = NULL;
-		} else {
-			DBG("No data for attribute 0x%04x", ctx_data->attr_id);
-		}
-		return;
-	}
-
-	if (!ctx_data->stack_head || !ctx_data->stack_head->data) {
-		DBG("No data for %s", element_name);
-		return;
-	}
+	uint128_t val;
+	unsigned int i, j;
 
-	if (!strcmp(element_name, "sequence")) {
-		ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
+	char buf[3];
 
-		if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
-			ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
-			ctx_data->stack_head->data->dtd = SDP_SEQ32;
-		} else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
-			ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
-			ctx_data->stack_head->data->dtd = SDP_SEQ16;
-		} else {
-			ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
-		}
-	} else if (!strcmp(element_name, "alternate")) {
-		ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
+	memset(&val, 0, sizeof(val));
 
-		if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
-			ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
-			ctx_data->stack_head->data->dtd = SDP_ALT32;
-		} else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
-			ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
-			ctx_data->stack_head->data->dtd = SDP_ALT16;
-		} else {
-			ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
-		}
-	}
+	buf[2] = '\0';
 
-	if (ctx_data->stack_head->next && ctx_data->stack_head->data &&
-					ctx_data->stack_head->next->data) {
-		switch (ctx_data->stack_head->next->data->dtd) {
-		case SDP_SEQ8:
-		case SDP_SEQ16:
-		case SDP_SEQ32:
-		case SDP_ALT8:
-		case SDP_ALT16:
-		case SDP_ALT32:
-			ctx_data->stack_head->next->data->val.dataseq =
-				sdp_seq_append(ctx_data->stack_head->next->data->val.dataseq,
-								ctx_data->stack_head->data);
-			ctx_data->stack_head->data = NULL;
-			break;
+	for (j = 0, i = 0; i < strlen(data);) {
+		if (data[i] == '-') {
+			i++;
+			continue;
 		}
 
-		elem = ctx_data->stack_head;
-		ctx_data->stack_head = ctx_data->stack_head->next;
+		buf[0] = data[i];
+		buf[1] = data[i + 1];
 
-		sdp_xml_data_free(elem);
+		val.data[j++] = strtoul(buf, 0, 16);
+		i += 2;
 	}
-}
 
-static GMarkupParser parser = {
-	element_start, element_end, NULL, NULL, NULL
-};
+	return sdp_data_alloc(SDP_UUID128, &val);
+}
 
-sdp_record_t *sdp_xml_parse_record(const char *data, int size)
+static sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record)
 {
-	GMarkupParseContext *ctx;
-	struct context_data *ctx_data;
-	sdp_record_t *record;
+	sdp_data_t *ret;
+	char *endptr;
+	uint32_t val;
+	uint16_t val2;
+	int len;
 
-	ctx_data = malloc(sizeof(*ctx_data));
-	if (!ctx_data)
-		return NULL;
+	len = strlen(data);
 
-	record = sdp_record_alloc();
-	if (!record) {
-		free(ctx_data);
-		return NULL;
+	if (len == 36) {
+		ret = sdp_xml_parse_uuid128(data);
+		goto result;
 	}
 
-	memset(ctx_data, 0, sizeof(*ctx_data));
-	ctx_data->record = record;
-
-	ctx = g_markup_parse_context_new(&parser, 0, ctx_data, NULL);
+	val = strtoll(data, &endptr, 16);
 
-	if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) {
-		error("XML parsing error");
-		g_markup_parse_context_free(ctx);
-		sdp_record_free(record);
-		free(ctx_data);
+	/* Couldn't parse */
+	if (*endptr != '\0')
 		return NULL;
+
+	if (val > USHRT_MAX) {
+		ret = sdp_data_alloc(SDP_UUID32, &val);
+		goto result;
 	}
 
-	g_markup_parse_context_free(ctx);
+	val2 = val;
 
-	free(ctx_data);
+	ret = sdp_data_alloc(SDP_UUID16, &val2);
 
-	return record;
-}
+result:
+	if (record && ret)
+		sdp_pattern_add_uuid(record, &ret->val.uuid);
 
+	return ret;
+}
 
-static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
-		void *data, void (*appender)(void *, const char *))
+static sdp_data_t *sdp_xml_parse_int(const char *data, uint8_t dtd)
 {
-	int i, hex;
-	char buf[STRBUFSIZE];
-	char indent[MAXINDENT];
+	char *endptr;
+	sdp_data_t *ret = NULL;
 
-	if (!value)
-		return;
+	switch (dtd) {
+	case SDP_BOOL:
+	{
+		uint8_t val = 0;
 
-	if (indent_level >= MAXINDENT)
-		indent_level = MAXINDENT - 2;
+		if (!strcmp("true", data))
+			val = 1;
+		else if (!strcmp("false", data))
+			val = 0;
+		else
+			return NULL;
 
-	for (i = 0; i < indent_level; i++)
-		indent[i] = '\t';
+		ret = sdp_data_alloc(dtd, &val);
+		break;
+	}
 
-	indent[i] = '\0';
-	buf[STRBUFSIZE - 1] = '\0';
+	case SDP_INT8:
+	{
+		int8_t val = strtoul(data, &endptr, 0);
 
-	switch (value->dtd) {
-	case SDP_DATA_NIL:
-		appender(data, indent);
-		appender(data, "<nil/>\n");
+		/* Failed to parse */
+		if ((endptr != data) && (*endptr != '\0'))
+			return NULL;
+
+		ret = sdp_data_alloc(dtd, &val);
 		break;
+	}
 
-	case SDP_BOOL:
-		appender(data, indent);
-		appender(data, "<boolean value=\"");
-		appender(data, value->val.uint8 ? "true" : "false");
-		appender(data, "\" />\n");
+	case SDP_UINT8:
+	{
+		uint8_t val = strtoul(data, &endptr, 0);
+
+		/* Failed to parse */
+		if ((endptr != data) && (*endptr != '\0'))
+			return NULL;
+
+		ret = sdp_data_alloc(dtd, &val);
 		break;
+	}
 
-	case SDP_UINT8:
-		appender(data, indent);
-		appender(data, "<uint8 value=\"");
-		snprintf(buf, STRBUFSIZE - 1, "0x%02x", value->val.uint8);
-		appender(data, buf);
-		appender(data, "\" />\n");
+	case SDP_INT16:
+	{
+		int16_t val = strtoul(data, &endptr, 0);
+
+		/* Failed to parse */
+		if ((endptr != data) && (*endptr != '\0'))
+			return NULL;
+
+		ret = sdp_data_alloc(dtd, &val);
 		break;
+	}
 
 	case SDP_UINT16:
-		appender(data, indent);
-		appender(data, "<uint16 value=\"");
-		snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uint16);
-		appender(data, buf);
-		appender(data, "\" />\n");
-		break;
+	{
+		uint16_t val = strtoul(data, &endptr, 0);
 
-	case SDP_UINT32:
-		appender(data, indent);
-		appender(data, "<uint32 value=\"");
-		snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uint32);
-		appender(data, buf);
-		appender(data, "\" />\n");
-		break;
+		/* Failed to parse */
+		if ((endptr != data) && (*endptr != '\0'))
+			return NULL;
 
-	case SDP_UINT64:
-		appender(data, indent);
-		appender(data, "<uint64 value=\"");
-		snprintf(buf, STRBUFSIZE - 1, "0x%016jx", value->val.uint64);
-		appender(data, buf);
-		appender(data, "\" />\n");
+		ret = sdp_data_alloc(dtd, &val);
 		break;
+	}
 
-	case SDP_UINT128:
-		appender(data, indent);
-		appender(data, "<uint128 value=\"");
+	case SDP_INT32:
+	{
+		int32_t val = strtoul(data, &endptr, 0);
 
-		for (i = 0; i < 16; i++) {
-			sprintf(&buf[i * 2], "%02x",
-				(unsigned char) value->val.uint128.data[i]);
-		}
+		/* Failed to parse */
+		if ((endptr != data) && (*endptr != '\0'))
+			return NULL;
 
-		appender(data, buf);
-		appender(data, "\" />\n");
+		ret = sdp_data_alloc(dtd, &val);
 		break;
+	}
 
-	case SDP_INT8:
-		appender(data, indent);
-		appender(data, "<int8 value=\"");
-		snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int8);
-		appender(data, buf);
-		appender(data, "\" />\n");
-		break;
+	case SDP_UINT32:
+	{
+		uint32_t val = strtoul(data, &endptr, 0);
 
-	case SDP_INT16:
-		appender(data, indent);
-		appender(data, "<int16 value=\"");
-		snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int16);
-		appender(data, buf);
-		appender(data, "\" />\n");
-		break;
+		/* Failed to parse */
+		if ((endptr != data) && (*endptr != '\0'))
+			return NULL;
 
-	case SDP_INT32:
-		appender(data, indent);
-		appender(data, "<int32 value=\"");
-		snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int32);
-		appender(data, buf);
-		appender(data, "\" />\n");
+		ret = sdp_data_alloc(dtd, &val);
 		break;
+	}
 
 	case SDP_INT64:
-		appender(data, indent);
-		appender(data, "<int64 value=\"");
-		snprintf(buf, STRBUFSIZE - 1, "%jd", value->val.int64);
-		appender(data, buf);
-		appender(data, "\" />\n");
+	{
+		int64_t val = strtoull(data, &endptr, 0);
+
+		/* Failed to parse */
+		if ((endptr != data) && (*endptr != '\0'))
+			return NULL;
+
+		ret = sdp_data_alloc(dtd, &val);
 		break;
+	}
 
-	case SDP_INT128:
-		appender(data, indent);
-		appender(data, "<int128 value=\"");
+	case SDP_UINT64:
+	{
+		uint64_t val = strtoull(data, &endptr, 0);
 
-		for (i = 0; i < 16; i++) {
-			sprintf(&buf[i * 2], "%02x",
-				(unsigned char) value->val.int128.data[i]);
-		}
-		appender(data, buf);
+		/* Failed to parse */
+		if ((endptr != data) && (*endptr != '\0'))
+			return NULL;
 
-		appender(data, "\" />\n");
+		ret = sdp_data_alloc(dtd, &val);
 		break;
+	}
 
-	case SDP_UUID16:
-		appender(data, indent);
-		appender(data, "<uuid value=\"");
-		snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uuid.value.uuid16);
-		appender(data, buf);
-		appender(data, "\" />\n");
-		break;
+	case SDP_INT128:
+	case SDP_UINT128:
+	{
+		uint128_t val;
+		int i = 0;
+		char buf[3];
 
-	case SDP_UUID32:
-		appender(data, indent);
-		appender(data, "<uuid value=\"");
-		snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uuid.value.uuid32);
-		appender(data, buf);
-		appender(data, "\" />\n");
-		break;
+		buf[2] = '\0';
 
-	case SDP_UUID128:
-		appender(data, indent);
-		appender(data, "<uuid value=\"");
+		for (; i < 32; i += 2) {
+			buf[0] = data[i];
+			buf[1] = data[i + 1];
 
-		snprintf(buf, STRBUFSIZE - 1,
-			 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
-			 (unsigned char) value->val.uuid.value.
-			 uuid128.data[0],
-			 (unsigned char) value->val.uuid.value.
-			 uuid128.data[1],
-			 (unsigned char) value->val.uuid.value.
-			 uuid128.data[2],
-			 (unsigned char) value->val.uuid.value.
-			 uuid128.data[3],
-			 (unsigned char) value->val.uuid.value.
-			 uuid128.data[4],
-			 (unsigned char) value->val.uuid.value.
-			 uuid128.data[5],
-			 (unsigned char) value->val.uuid.value.
-			 uuid128.data[6],
-			 (unsigned char) value->val.uuid.value.
-			 uuid128.data[7],
-			 (unsigned char) value->val.uuid.value.
-			 uuid128.data[8],
-			 (unsigned char) value->val.uuid.value.
-			 uuid128.data[9],
-			 (unsigned char) value->val.uuid.value.
-			 uuid128.data[10],
-			 (unsigned char) value->val.uuid.value.
-			 uuid128.data[11],
-			 (unsigned char) value->val.uuid.value.
-			 uuid128.data[12],
-			 (unsigned char) value->val.uuid.value.
-			 uuid128.data[13],
-			 (unsigned char) value->val.uuid.value.
-			 uuid128.data[14],
-			 (unsigned char) value->val.uuid.value.
-			 uuid128.data[15]);
+			val.data[i >> 1] = strtoul(buf, 0, 16);
+		}
 
-		appender(data, buf);
-		appender(data, "\" />\n");
+		ret = sdp_data_alloc(dtd, &val);
 		break;
+	}
 
-	case SDP_TEXT_STR8:
-	case SDP_TEXT_STR16:
-	case SDP_TEXT_STR32:
-	{
-		int num_chars_to_escape = 0;
-		int length = value->unitSize - 1;
-		char *strBuf = 0;
+	};
 
-		hex = 0;
+	return ret;
+}
 
-		for (i = 0; i < length; i++) {
-			if (!isprint(value->val.str[i]) &&
-					value->val.str[i] != '\0') {
-				hex = 1;
-				break;
-			}
+static char *sdp_xml_parse_string_decode(const char *data, char encoding,
+							uint32_t *length)
+{
+	int len = strlen(data);
+	char *text;
 
-			/* XML is evil, must do this... */
-			if ((value->val.str[i] == '<') ||
-					(value->val.str[i] == '>') ||
-					(value->val.str[i] == '"') ||
-					(value->val.str[i] == '&'))
-				num_chars_to_escape++;
-		}
+	if (encoding == SDP_XML_ENCODING_NORMAL) {
+		text = strdup(data);
+		*length = len;
+	} else {
+		char buf[3], *decoded;
+		int i;
 
-		appender(data, indent);
+		decoded = malloc((len >> 1) + 1);
 
-		appender(data, "<text ");
+		/* Ensure the string is a power of 2 */
+		len = (len >> 1) << 1;
 
-		if (hex) {
-			appender(data, "encoding=\"hex\" ");
-			strBuf = malloc(sizeof(char)
-						 * ((value->unitSize-1) * 2 + 1));
+		buf[2] = '\0';
 
-			/* Unit Size seems to include the size for dtd
-			   It is thus off by 1
-			   This is safe for Normal strings, but not
-			   hex encoded data */
-			for (i = 0; i < (value->unitSize-1); i++)
-				sprintf(&strBuf[i*sizeof(char)*2],
-					"%02x",
-					(unsigned char) value->val.str[i]);
+		for (i = 0; i < len; i += 2) {
+			buf[0] = data[i];
+			buf[1] = data[i + 1];
 
-			strBuf[(value->unitSize-1) * 2] = '\0';
-		}
-		else {
-			int j;
-			/* escape the XML disallowed chars */
-			strBuf = malloc(sizeof(char) *
-					(value->unitSize + 1 + num_chars_to_escape * 4));
-			for (i = 0, j = 0; i < length; i++) {
-				if (value->val.str[i] == '&') {
-					strBuf[j++] = '&';
-					strBuf[j++] = 'a';
-					strBuf[j++] = 'm';
-					strBuf[j++] = 'p';
-				}
-				else if (value->val.str[i] == '<') {
-					strBuf[j++] = '&';
-					strBuf[j++] = 'l';
-					strBuf[j++] = 't';
-				}
-				else if (value->val.str[i] == '>') {
-					strBuf[j++] = '&';
-					strBuf[j++] = 'g';
-					strBuf[j++] = 't';
-				}
-				else if (value->val.str[i] == '"') {
-					strBuf[j++] = '&';
-					strBuf[j++] = 'q';
-					strBuf[j++] = 'u';
-					strBuf[j++] = 'o';
-					strBuf[j++] = 't';
-				}
-				else if (value->val.str[i] == '\0') {
-					strBuf[j++] = ' ';
-				} else {
-					strBuf[j++] = value->val.str[i];
-				}
-			}
-
-			strBuf[j] = '\0';
+			decoded[i >> 1] = strtoul(buf, 0, 16);
 		}
 
-		appender(data, "value=\"");
-		appender(data, strBuf);
-		appender(data, "\" />\n");
-		free(strBuf);
-		break;
+		decoded[len >> 1] = '\0';
+		text = decoded;
+		*length = len >> 1;
 	}
 
-	case SDP_URL_STR8:
-	case SDP_URL_STR16:
-	case SDP_URL_STR32:
-	{
-		char *strBuf;
+	return text;
+}
 
-		appender(data, indent);
-		appender(data, "<url value=\"");
-		strBuf = strndup(value->val.str, value->unitSize - 1);
-		appender(data, strBuf);
-		free(strBuf);
-		appender(data, "\" />\n");
-		break;
-	}
+static sdp_data_t *sdp_xml_parse_url(const char *data)
+{
+	uint8_t dtd = SDP_URL_STR8;
+	char *url;
+	uint32_t length;
+	sdp_data_t *ret;
 
-	case SDP_SEQ8:
-	case SDP_SEQ16:
-	case SDP_SEQ32:
-		appender(data, indent);
-		appender(data, "<sequence>\n");
+	url = sdp_xml_parse_string_decode(data,
+				SDP_XML_ENCODING_NORMAL, &length);
 
-		convert_raw_data_to_xml(value->val.dataseq,
-					indent_level + 1, data, appender);
+	if (length > UCHAR_MAX)
+		dtd = SDP_URL_STR16;
 
-		appender(data, indent);
-		appender(data, "</sequence>\n");
+	ret = sdp_data_alloc_with_length(dtd, url, length);
 
-		break;
+	free(url);
 
-	case SDP_ALT8:
-	case SDP_ALT16:
-	case SDP_ALT32:
-		appender(data, indent);
+	return ret;
+}
 
-		appender(data, "<alternate>\n");
+static sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
+{
+	uint8_t dtd = SDP_TEXT_STR8;
+	char *text;
+	uint32_t length;
+	sdp_data_t *ret;
 
-		convert_raw_data_to_xml(value->val.dataseq,
-					indent_level + 1, data, appender);
-		appender(data, indent);
+	text = sdp_xml_parse_string_decode(data, encoding, &length);
 
-		appender(data, "</alternate>\n");
+	if (length > UCHAR_MAX)
+		dtd = SDP_TEXT_STR16;
 
-		break;
-	}
+	ret = sdp_data_alloc_with_length(dtd, text, length);
 
-	convert_raw_data_to_xml(value->next, indent_level, data, appender);
-}
+	free(text);
 
-struct conversion_data {
-	void *data;
-	void (*appender)(void *data, const char *);
-};
+	return ret;
+}
 
-static void convert_raw_attr_to_xml_func(void *val, void *data)
+static sdp_data_t *sdp_xml_parse_nil(const char *data)
 {
-	struct conversion_data *cd = data;
-	sdp_data_t *value = val;
-	char buf[STRBUFSIZE];
+	return sdp_data_alloc(SDP_DATA_NIL, 0);
+}
 
-	buf[STRBUFSIZE - 1] = '\0';
-	snprintf(buf, STRBUFSIZE - 1, "\t<attribute id=\"0x%04x\">\n",
-		 value->attrId);
-	cd->appender(cd->data, buf);
+static sdp_data_t *sdp_xml_parse_datatype(const char *el,
+						struct sdp_xml_data *elem,
+						sdp_record_t *record)
+{
+	const char *data = elem->text;
 
-	convert_raw_data_to_xml(value, 2, cd->data, cd->appender);
+	if (!strcmp(el, "boolean"))
+		return sdp_xml_parse_int(data, SDP_BOOL);
+	else if (!strcmp(el, "uint8"))
+		return sdp_xml_parse_int(data, SDP_UINT8);
+	else if (!strcmp(el, "uint16"))
+		return sdp_xml_parse_int(data, SDP_UINT16);
+	else if (!strcmp(el, "uint32"))
+		return sdp_xml_parse_int(data, SDP_UINT32);
+	else if (!strcmp(el, "uint64"))
+		return sdp_xml_parse_int(data, SDP_UINT64);
+	else if (!strcmp(el, "uint128"))
+		return sdp_xml_parse_int(data, SDP_UINT128);
+	else if (!strcmp(el, "int8"))
+		return sdp_xml_parse_int(data, SDP_INT8);
+	else if (!strcmp(el, "int16"))
+		return sdp_xml_parse_int(data, SDP_INT16);
+	else if (!strcmp(el, "int32"))
+		return sdp_xml_parse_int(data, SDP_INT32);
+	else if (!strcmp(el, "int64"))
+		return sdp_xml_parse_int(data, SDP_INT64);
+	else if (!strcmp(el, "int128"))
+		return sdp_xml_parse_int(data, SDP_INT128);
+	else if (!strcmp(el, "uuid"))
+		return sdp_xml_parse_uuid(data, record);
+	else if (!strcmp(el, "url"))
+		return sdp_xml_parse_url(data);
+	else if (!strcmp(el, "text"))
+		return sdp_xml_parse_text(data, elem->type);
+	else if (!strcmp(el, "nil"))
+		return sdp_xml_parse_nil(data);
 
-	cd->appender(cd->data, "\t</attribute>\n");
+	return NULL;
 }
-
-/*
- * Will convert the sdp record to XML.  The appender and data can be used
- * to control where to output the record (e.g. file or a data buffer).  The
- * appender will be called repeatedly with data and the character buffer
- * (containing parts of the generated XML) to append.
- */
-void convert_sdp_record_to_xml(sdp_record_t *rec,
-			void *data, void (*appender)(void *, const char *))
+static void element_start(GMarkupParseContext *context,
+		const gchar *element_name, const gchar **attribute_names,
+		const gchar **attribute_values, gpointer user_data, GError **err)
 {
-	struct conversion_data cd;
+	struct context_data *ctx_data = user_data;
 
-	cd.data = data;
-	cd.appender = appender;
+	if (!strcmp(element_name, "record"))
+		return;
 
-	if (rec && rec->attrlist) {
-		appender(data, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n");
-		appender(data, "<record>\n");
-		sdp_list_foreach(rec->attrlist,
-				 convert_raw_attr_to_xml_func, &cd);
-		appender(data, "</record>\n");
+	if (!strcmp(element_name, "attribute")) {
+		int i;
+		for (i = 0; attribute_names[i]; i++) {
+			if (!strcmp(attribute_names[i], "id")) {
+				ctx_data->attr_id = strtol(attribute_values[i], 0, 0);
+				break;
+			}
+		}
+		DBG("New attribute 0x%04x", ctx_data->attr_id);
+		return;
 	}
-}
 
-static sdp_data_t *sdp_xml_parse_uuid128(const char *data)
-{
-	uint128_t val;
-	unsigned int i, j;
+	if (ctx_data->stack_head) {
+		struct sdp_xml_data *newelem = sdp_xml_data_alloc();
+		newelem->next = ctx_data->stack_head;
+		ctx_data->stack_head = newelem;
+	} else {
+		ctx_data->stack_head = sdp_xml_data_alloc();
+		ctx_data->stack_head->next = NULL;
+	}
 
-	char buf[3];
+	if (!strcmp(element_name, "sequence"))
+		ctx_data->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL);
+	else if (!strcmp(element_name, "alternate"))
+		ctx_data->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL);
+	else {
+		int i;
+		/* Parse value, name, encoding */
+		for (i = 0; attribute_names[i]; i++) {
+			if (!strcmp(attribute_names[i], "value")) {
+				int curlen = strlen(ctx_data->stack_head->text);
+				int attrlen = strlen(attribute_values[i]);
 
-	memset(&val, 0, sizeof(val));
+				/* Ensure we're big enough */
+				while ((curlen + 1 + attrlen) > ctx_data->stack_head->size)
+					sdp_xml_data_expand(ctx_data->stack_head);
 
-	buf[2] = '\0';
+				memcpy(ctx_data->stack_head->text + curlen,
+						attribute_values[i], attrlen);
+				ctx_data->stack_head->text[curlen + attrlen] = '\0';
+			}
 
-	for (j = 0, i = 0; i < strlen(data);) {
-		if (data[i] == '-') {
-			i++;
-			continue;
+			if (!strcmp(attribute_names[i], "encoding")) {
+				if (!strcmp(attribute_values[i], "hex"))
+					ctx_data->stack_head->type = 1;
+			}
+
+			if (!strcmp(attribute_names[i], "name"))
+				ctx_data->stack_head->name = strdup(attribute_values[i]);
 		}
 
-		buf[0] = data[i];
-		buf[1] = data[i + 1];
+		ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name,
+				ctx_data->stack_head, ctx_data->record);
 
-		val.data[j++] = strtoul(buf, 0, 16);
-		i += 2;
+		if (ctx_data->stack_head->data == NULL)
+			error("Can't parse element %s", element_name);
 	}
-
-	return sdp_data_alloc(SDP_UUID128, &val);
 }
 
-sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record)
+static void sdp_xml_data_free(struct sdp_xml_data *elem)
 {
-	sdp_data_t *ret;
-	char *endptr;
-	uint32_t val;
-	uint16_t val2;
-	int len;
-
-	len = strlen(data);
+	if (elem->data)
+		sdp_data_free(elem->data);
 
-	if (len == 36) {
-		ret = sdp_xml_parse_uuid128(data);
-		goto result;
-	}
+	free(elem->name);
+	free(elem->text);
+	free(elem);
+}
 
-	val = strtoll(data, &endptr, 16);
-
-	/* Couldn't parse */
-	if (*endptr != '\0')
-		return NULL;
-
-	if (val > USHRT_MAX) {
-		ret = sdp_data_alloc(SDP_UUID32, &val);
-		goto result;
-	}
-
-	val2 = val;
+static void element_end(GMarkupParseContext *context,
+		const gchar *element_name, gpointer user_data, GError **err)
+{
+	struct context_data *ctx_data = user_data;
+	struct sdp_xml_data *elem;
 
-	ret = sdp_data_alloc(SDP_UUID16, &val2);
+	if (!strcmp(element_name, "record"))
+		return;
 
-result:
-	if (record && ret)
-		sdp_pattern_add_uuid(record, &ret->val.uuid);
+	if (!strcmp(element_name, "attribute")) {
+		if (ctx_data->stack_head && ctx_data->stack_head->data) {
+			int ret = sdp_attr_add(ctx_data->record, ctx_data->attr_id,
+							ctx_data->stack_head->data);
+			if (ret == -1)
+				DBG("Could not add attribute 0x%04x",
+							ctx_data->attr_id);
 
-	return ret;
-}
+			ctx_data->stack_head->data = NULL;
+			sdp_xml_data_free(ctx_data->stack_head);
+			ctx_data->stack_head = NULL;
+		} else {
+			DBG("No data for attribute 0x%04x", ctx_data->attr_id);
+		}
+		return;
+	}
 
-sdp_data_t *sdp_xml_parse_int(const char * data, uint8_t dtd)
-{
-	char *endptr;
-	sdp_data_t *ret = NULL;
+	if (!ctx_data->stack_head || !ctx_data->stack_head->data) {
+		DBG("No data for %s", element_name);
+		return;
+	}
 
-	switch (dtd) {
-	case SDP_BOOL:
-	{
-		uint8_t val = 0;
+	if (!strcmp(element_name, "sequence")) {
+		ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
 
-		if (!strcmp("true", data)) {
-			val = 1;
+		if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
+			ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
+			ctx_data->stack_head->data->dtd = SDP_SEQ32;
+		} else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
+			ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
+			ctx_data->stack_head->data->dtd = SDP_SEQ16;
+		} else {
+			ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
 		}
+	} else if (!strcmp(element_name, "alternate")) {
+		ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
 
-		else if (!strcmp("false", data)) {
-			val = 0;
-		}
-		else {
-			return NULL;
+		if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
+			ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
+			ctx_data->stack_head->data->dtd = SDP_ALT32;
+		} else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
+			ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
+			ctx_data->stack_head->data->dtd = SDP_ALT16;
+		} else {
+			ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
 		}
-
-		ret = sdp_data_alloc(dtd, &val);
-		break;
 	}
 
-	case SDP_INT8:
-	{
-		int8_t val = strtoul(data, &endptr, 0);
+	if (ctx_data->stack_head->next && ctx_data->stack_head->data &&
+					ctx_data->stack_head->next->data) {
+		switch (ctx_data->stack_head->next->data->dtd) {
+		case SDP_SEQ8:
+		case SDP_SEQ16:
+		case SDP_SEQ32:
+		case SDP_ALT8:
+		case SDP_ALT16:
+		case SDP_ALT32:
+			ctx_data->stack_head->next->data->val.dataseq =
+				sdp_seq_append(ctx_data->stack_head->next->data->val.dataseq,
+								ctx_data->stack_head->data);
+			ctx_data->stack_head->data = NULL;
+			break;
+		}
 
-		/* Failed to parse */
-		if ((endptr != data) && (*endptr != '\0'))
-			return NULL;
+		elem = ctx_data->stack_head;
+		ctx_data->stack_head = ctx_data->stack_head->next;
 
-		ret = sdp_data_alloc(dtd, &val);
-		break;
+		sdp_xml_data_free(elem);
 	}
+}
 
-	case SDP_UINT8:
-	{
-		uint8_t val = strtoul(data, &endptr, 0);
+static GMarkupParser parser = {
+	element_start, element_end, NULL, NULL, NULL
+};
 
-		/* Failed to parse */
-		if ((endptr != data) && (*endptr != '\0'))
-			return NULL;
+sdp_record_t *sdp_xml_parse_record(const char *data, int size)
+{
+	GMarkupParseContext *ctx;
+	struct context_data *ctx_data;
+	sdp_record_t *record;
 
-		ret = sdp_data_alloc(dtd, &val);
-		break;
+	ctx_data = malloc(sizeof(*ctx_data));
+	if (!ctx_data)
+		return NULL;
+
+	record = sdp_record_alloc();
+	if (!record) {
+		free(ctx_data);
+		return NULL;
 	}
 
-	case SDP_INT16:
-	{
-		int16_t val = strtoul(data, &endptr, 0);
+	memset(ctx_data, 0, sizeof(*ctx_data));
+	ctx_data->record = record;
 
-		/* Failed to parse */
-		if ((endptr != data) && (*endptr != '\0'))
-			return NULL;
+	ctx = g_markup_parse_context_new(&parser, 0, ctx_data, NULL);
 
-		ret = sdp_data_alloc(dtd, &val);
-		break;
+	if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) {
+		error("XML parsing error");
+		g_markup_parse_context_free(ctx);
+		sdp_record_free(record);
+		free(ctx_data);
+		return NULL;
 	}
 
-	case SDP_UINT16:
-	{
-		uint16_t val = strtoul(data, &endptr, 0);
+	g_markup_parse_context_free(ctx);
 
-		/* Failed to parse */
-		if ((endptr != data) && (*endptr != '\0'))
-			return NULL;
+	free(ctx_data);
 
-		ret = sdp_data_alloc(dtd, &val);
-		break;
-	}
+	return record;
+}
 
-	case SDP_INT32:
-	{
-		int32_t val = strtoul(data, &endptr, 0);
 
-		/* Failed to parse */
-		if ((endptr != data) && (*endptr != '\0'))
-			return NULL;
+static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
+		void *data, void (*appender)(void *, const char *))
+{
+	int i, hex;
+	char buf[STRBUFSIZE];
+	char indent[MAXINDENT];
 
-		ret = sdp_data_alloc(dtd, &val);
-		break;
-	}
+	if (!value)
+		return;
 
-	case SDP_UINT32:
-	{
-		uint32_t val = strtoul(data, &endptr, 0);
+	if (indent_level >= MAXINDENT)
+		indent_level = MAXINDENT - 2;
 
-		/* Failed to parse */
-		if ((endptr != data) && (*endptr != '\0'))
-			return NULL;
+	for (i = 0; i < indent_level; i++)
+		indent[i] = '\t';
 
-		ret = sdp_data_alloc(dtd, &val);
-		break;
-	}
+	indent[i] = '\0';
+	buf[STRBUFSIZE - 1] = '\0';
 
-	case SDP_INT64:
-	{
-		int64_t val = strtoull(data, &endptr, 0);
+	switch (value->dtd) {
+	case SDP_DATA_NIL:
+		appender(data, indent);
+		appender(data, "<nil/>\n");
+		break;
 
-		/* Failed to parse */
-		if ((endptr != data) && (*endptr != '\0'))
-			return NULL;
+	case SDP_BOOL:
+		appender(data, indent);
+		appender(data, "<boolean value=\"");
+		appender(data, value->val.uint8 ? "true" : "false");
+		appender(data, "\" />\n");
+		break;
 
-		ret = sdp_data_alloc(dtd, &val);
+	case SDP_UINT8:
+		appender(data, indent);
+		appender(data, "<uint8 value=\"");
+		snprintf(buf, STRBUFSIZE - 1, "0x%02x", value->val.uint8);
+		appender(data, buf);
+		appender(data, "\" />\n");
 		break;
-	}
 
-	case SDP_UINT64:
-	{
-		uint64_t val = strtoull(data, &endptr, 0);
+	case SDP_UINT16:
+		appender(data, indent);
+		appender(data, "<uint16 value=\"");
+		snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uint16);
+		appender(data, buf);
+		appender(data, "\" />\n");
+		break;
 
-		/* Failed to parse */
-		if ((endptr != data) && (*endptr != '\0'))
-			return NULL;
+	case SDP_UINT32:
+		appender(data, indent);
+		appender(data, "<uint32 value=\"");
+		snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uint32);
+		appender(data, buf);
+		appender(data, "\" />\n");
+		break;
 
-		ret = sdp_data_alloc(dtd, &val);
+	case SDP_UINT64:
+		appender(data, indent);
+		appender(data, "<uint64 value=\"");
+		snprintf(buf, STRBUFSIZE - 1, "0x%016jx", value->val.uint64);
+		appender(data, buf);
+		appender(data, "\" />\n");
 		break;
-	}
 
-	case SDP_INT128:
 	case SDP_UINT128:
-	{
-		uint128_t val;
-		int i = 0;
-		char buf[3];
+		appender(data, indent);
+		appender(data, "<uint128 value=\"");
 
-		buf[2] = '\0';
+		for (i = 0; i < 16; i++) {
+			sprintf(&buf[i * 2], "%02x",
+				(unsigned char) value->val.uint128.data[i]);
+		}
 
-		for (; i < 32; i += 2) {
-			buf[0] = data[i];
-			buf[1] = data[i + 1];
+		appender(data, buf);
+		appender(data, "\" />\n");
+		break;
 
-			val.data[i >> 1] = strtoul(buf, 0, 16);
-		}
+	case SDP_INT8:
+		appender(data, indent);
+		appender(data, "<int8 value=\"");
+		snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int8);
+		appender(data, buf);
+		appender(data, "\" />\n");
+		break;
 
-		ret = sdp_data_alloc(dtd, &val);
+	case SDP_INT16:
+		appender(data, indent);
+		appender(data, "<int16 value=\"");
+		snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int16);
+		appender(data, buf);
+		appender(data, "\" />\n");
 		break;
-	}
 
-	};
+	case SDP_INT32:
+		appender(data, indent);
+		appender(data, "<int32 value=\"");
+		snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int32);
+		appender(data, buf);
+		appender(data, "\" />\n");
+		break;
 
-	return ret;
-}
+	case SDP_INT64:
+		appender(data, indent);
+		appender(data, "<int64 value=\"");
+		snprintf(buf, STRBUFSIZE - 1, "%jd", value->val.int64);
+		appender(data, buf);
+		appender(data, "\" />\n");
+		break;
 
-static char *sdp_xml_parse_string_decode(const char *data, char encoding, uint32_t *length)
-{
-	int len = strlen(data);
-	char *text;
+	case SDP_INT128:
+		appender(data, indent);
+		appender(data, "<int128 value=\"");
 
-	if (encoding == SDP_XML_ENCODING_NORMAL) {
-		text = strdup(data);
-		*length = len;
-	} else {
-		char buf[3], *decoded;
-		int i;
+		for (i = 0; i < 16; i++) {
+			sprintf(&buf[i * 2], "%02x",
+				(unsigned char) value->val.int128.data[i]);
+		}
+		appender(data, buf);
 
-		decoded = malloc((len >> 1) + 1);
+		appender(data, "\" />\n");
+		break;
 
-		/* Ensure the string is a power of 2 */
-		len = (len >> 1) << 1;
+	case SDP_UUID16:
+		appender(data, indent);
+		appender(data, "<uuid value=\"");
+		snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uuid.value.uuid16);
+		appender(data, buf);
+		appender(data, "\" />\n");
+		break;
 
-		buf[2] = '\0';
+	case SDP_UUID32:
+		appender(data, indent);
+		appender(data, "<uuid value=\"");
+		snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uuid.value.uuid32);
+		appender(data, buf);
+		appender(data, "\" />\n");
+		break;
 
-		for (i = 0; i < len; i += 2) {
-			buf[0] = data[i];
-			buf[1] = data[i + 1];
+	case SDP_UUID128:
+		appender(data, indent);
+		appender(data, "<uuid value=\"");
 
-			decoded[i >> 1] = strtoul(buf, 0, 16);
-		}
+		snprintf(buf, STRBUFSIZE - 1,
+			 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+			 (unsigned char) value->val.uuid.value.
+			 uuid128.data[0],
+			 (unsigned char) value->val.uuid.value.
+			 uuid128.data[1],
+			 (unsigned char) value->val.uuid.value.
+			 uuid128.data[2],
+			 (unsigned char) value->val.uuid.value.
+			 uuid128.data[3],
+			 (unsigned char) value->val.uuid.value.
+			 uuid128.data[4],
+			 (unsigned char) value->val.uuid.value.
+			 uuid128.data[5],
+			 (unsigned char) value->val.uuid.value.
+			 uuid128.data[6],
+			 (unsigned char) value->val.uuid.value.
+			 uuid128.data[7],
+			 (unsigned char) value->val.uuid.value.
+			 uuid128.data[8],
+			 (unsigned char) value->val.uuid.value.
+			 uuid128.data[9],
+			 (unsigned char) value->val.uuid.value.
+			 uuid128.data[10],
+			 (unsigned char) value->val.uuid.value.
+			 uuid128.data[11],
+			 (unsigned char) value->val.uuid.value.
+			 uuid128.data[12],
+			 (unsigned char) value->val.uuid.value.
+			 uuid128.data[13],
+			 (unsigned char) value->val.uuid.value.
+			 uuid128.data[14],
+			 (unsigned char) value->val.uuid.value.
+			 uuid128.data[15]);
 
-		decoded[len >> 1] = '\0';
-		text = decoded;
-		*length = len >> 1;
-	}
+		appender(data, buf);
+		appender(data, "\" />\n");
+		break;
 
-	return text;
-}
+	case SDP_TEXT_STR8:
+	case SDP_TEXT_STR16:
+	case SDP_TEXT_STR32:
+	{
+		int num_chars_to_escape = 0;
+		int length = value->unitSize - 1;
+		char *strBuf = 0;
 
-sdp_data_t *sdp_xml_parse_url(const char *data)
-{
-	uint8_t dtd = SDP_URL_STR8;
-	char *url;
-	uint32_t length;
-	sdp_data_t *ret;
+		hex = 0;
 
-	url = sdp_xml_parse_string_decode(data,
-				SDP_XML_ENCODING_NORMAL, &length);
+		for (i = 0; i < length; i++) {
+			if (!isprint(value->val.str[i]) &&
+					value->val.str[i] != '\0') {
+				hex = 1;
+				break;
+			}
 
-	if (length > UCHAR_MAX)
-		dtd = SDP_URL_STR16;
+			/* XML is evil, must do this... */
+			if ((value->val.str[i] == '<') ||
+					(value->val.str[i] == '>') ||
+					(value->val.str[i] == '"') ||
+					(value->val.str[i] == '&'))
+				num_chars_to_escape++;
+		}
 
-	ret = sdp_data_alloc_with_length(dtd, url, length);
+		appender(data, indent);
 
-	free(url);
+		appender(data, "<text ");
 
-	return ret;
-}
+		if (hex) {
+			appender(data, "encoding=\"hex\" ");
+			strBuf = malloc(sizeof(char)
+						 * ((value->unitSize-1) * 2 + 1));
 
-sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
-{
-	uint8_t dtd = SDP_TEXT_STR8;
-	char *text;
-	uint32_t length;
-	sdp_data_t *ret;
+			/* Unit Size seems to include the size for dtd
+			   It is thus off by 1
+			   This is safe for Normal strings, but not
+			   hex encoded data */
+			for (i = 0; i < (value->unitSize-1); i++)
+				sprintf(&strBuf[i*sizeof(char)*2],
+					"%02x",
+					(unsigned char) value->val.str[i]);
 
-	text = sdp_xml_parse_string_decode(data, encoding, &length);
+			strBuf[(value->unitSize-1) * 2] = '\0';
+		} else {
+			int j;
+			/* escape the XML disallowed chars */
+			strBuf = malloc(sizeof(char) *
+					(value->unitSize + 1 + num_chars_to_escape * 4));
+			for (i = 0, j = 0; i < length; i++) {
+				if (value->val.str[i] == '&') {
+					strBuf[j++] = '&';
+					strBuf[j++] = 'a';
+					strBuf[j++] = 'm';
+					strBuf[j++] = 'p';
+				} else if (value->val.str[i] == '<') {
+					strBuf[j++] = '&';
+					strBuf[j++] = 'l';
+					strBuf[j++] = 't';
+				} else if (value->val.str[i] == '>') {
+					strBuf[j++] = '&';
+					strBuf[j++] = 'g';
+					strBuf[j++] = 't';
+				} else if (value->val.str[i] == '"') {
+					strBuf[j++] = '&';
+					strBuf[j++] = 'q';
+					strBuf[j++] = 'u';
+					strBuf[j++] = 'o';
+					strBuf[j++] = 't';
+				} else if (value->val.str[i] == '\0') {
+					strBuf[j++] = ' ';
+				} else {
+					strBuf[j++] = value->val.str[i];
+				}
+			}
 
-	if (length > UCHAR_MAX)
-		dtd = SDP_TEXT_STR16;
+			strBuf[j] = '\0';
+		}
 
-	ret = sdp_data_alloc_with_length(dtd, text, length);
+		appender(data, "value=\"");
+		appender(data, strBuf);
+		appender(data, "\" />\n");
+		free(strBuf);
+		break;
+	}
 
-	free(text);
+	case SDP_URL_STR8:
+	case SDP_URL_STR16:
+	case SDP_URL_STR32:
+	{
+		char *strBuf;
 
-	return ret;
-}
+		appender(data, indent);
+		appender(data, "<url value=\"");
+		strBuf = strndup(value->val.str, value->unitSize - 1);
+		appender(data, strBuf);
+		free(strBuf);
+		appender(data, "\" />\n");
+		break;
+	}
 
-sdp_data_t *sdp_xml_parse_nil(const char *data)
-{
-	return sdp_data_alloc(SDP_DATA_NIL, 0);
-}
+	case SDP_SEQ8:
+	case SDP_SEQ16:
+	case SDP_SEQ32:
+		appender(data, indent);
+		appender(data, "<sequence>\n");
 
-#define DEFAULT_XML_DATA_SIZE 1024
+		convert_raw_data_to_xml(value->val.dataseq,
+					indent_level + 1, data, appender);
 
-struct sdp_xml_data *sdp_xml_data_alloc(void)
-{
-	struct sdp_xml_data *elem;
+		appender(data, indent);
+		appender(data, "</sequence>\n");
 
-	elem = malloc(sizeof(struct sdp_xml_data));
-	if (!elem)
-		return NULL;
+		break;
 
-	memset(elem, 0, sizeof(struct sdp_xml_data));
+	case SDP_ALT8:
+	case SDP_ALT16:
+	case SDP_ALT32:
+		appender(data, indent);
 
-	/* Null terminate the text */
-	elem->size = DEFAULT_XML_DATA_SIZE;
-	elem->text = malloc(DEFAULT_XML_DATA_SIZE);
-	elem->text[0] = '\0';
+		appender(data, "<alternate>\n");
 
-	return elem;
-}
+		convert_raw_data_to_xml(value->val.dataseq,
+					indent_level + 1, data, appender);
+		appender(data, indent);
 
-void sdp_xml_data_free(struct sdp_xml_data *elem)
-{
-	if (elem->data)
-		sdp_data_free(elem->data);
+		appender(data, "</alternate>\n");
 
-	free(elem->name);
-	free(elem->text);
-	free(elem);
+		break;
+	}
+
+	convert_raw_data_to_xml(value->next, indent_level, data, appender);
 }
 
-struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem)
-{
-	char *newbuf;
+struct conversion_data {
+	void *data;
+	void (*appender)(void *data, const char *);
+};
 
-	newbuf = malloc(elem->size * 2);
-	if (!newbuf)
-		return NULL;
+static void convert_raw_attr_to_xml_func(void *val, void *data)
+{
+	struct conversion_data *cd = data;
+	sdp_data_t *value = val;
+	char buf[STRBUFSIZE];
 
-	memcpy(newbuf, elem->text, elem->size);
-	elem->size *= 2;
-	free(elem->text);
+	buf[STRBUFSIZE - 1] = '\0';
+	snprintf(buf, STRBUFSIZE - 1, "\t<attribute id=\"0x%04x\">\n",
+		 value->attrId);
+	cd->appender(cd->data, buf);
 
-	elem->text = newbuf;
+	convert_raw_data_to_xml(value, 2, cd->data, cd->appender);
 
-	return elem;
+	cd->appender(cd->data, "\t</attribute>\n");
 }
 
-sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
-							sdp_record_t *record)
+/*
+ * Will convert the sdp record to XML.  The appender and data can be used
+ * to control where to output the record (e.g. file or a data buffer).  The
+ * appender will be called repeatedly with data and the character buffer
+ * (containing parts of the generated XML) to append.
+ */
+void convert_sdp_record_to_xml(sdp_record_t *rec,
+			void *data, void (*appender)(void *, const char *))
 {
-	const char *data = elem->text;
+	struct conversion_data cd;
 
-	if (!strcmp(el, "boolean"))
-		return sdp_xml_parse_int(data, SDP_BOOL);
-	else if (!strcmp(el, "uint8"))
-		return sdp_xml_parse_int(data, SDP_UINT8);
-	else if (!strcmp(el, "uint16"))
-		return sdp_xml_parse_int(data, SDP_UINT16);
-	else if (!strcmp(el, "uint32"))
-		return sdp_xml_parse_int(data, SDP_UINT32);
-	else if (!strcmp(el, "uint64"))
-		return sdp_xml_parse_int(data, SDP_UINT64);
-	else if (!strcmp(el, "uint128"))
-		return sdp_xml_parse_int(data, SDP_UINT128);
-	else if (!strcmp(el, "int8"))
-		return sdp_xml_parse_int(data, SDP_INT8);
-	else if (!strcmp(el, "int16"))
-		return sdp_xml_parse_int(data, SDP_INT16);
-	else if (!strcmp(el, "int32"))
-		return sdp_xml_parse_int(data, SDP_INT32);
-	else if (!strcmp(el, "int64"))
-		return sdp_xml_parse_int(data, SDP_INT64);
-	else if (!strcmp(el, "int128"))
-		return sdp_xml_parse_int(data, SDP_INT128);
-	else if (!strcmp(el, "uuid"))
-		return sdp_xml_parse_uuid(data, record);
-	else if (!strcmp(el, "url"))
-		return sdp_xml_parse_url(data);
-	else if (!strcmp(el, "text"))
-		return sdp_xml_parse_text(data, elem->type);
-	else if (!strcmp(el, "nil"))
-		return sdp_xml_parse_nil(data);
+	cd.data = data;
+	cd.appender = appender;
 
-	return NULL;
+	if (rec && rec->attrlist) {
+		appender(data, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n");
+		appender(data, "<record>\n");
+		sdp_list_foreach(rec->attrlist,
+				 convert_raw_attr_to_xml_func, &cd);
+		appender(data, "</record>\n");
+	}
 }
+
diff --git a/src/sdp-xml.h b/src/sdp-xml.h
index 49efc39..d393f94 100644
--- a/src/sdp-xml.h
+++ b/src/sdp-xml.h
@@ -33,29 +33,6 @@
 void convert_sdp_record_to_xml(sdp_record_t *rec,
 		void *user_data, void (*append_func) (void *, const char *));
 
-sdp_data_t *sdp_xml_parse_nil(const char *data);
-sdp_data_t *sdp_xml_parse_text(const char *data, char encoding);
-sdp_data_t *sdp_xml_parse_url(const char *data);
-sdp_data_t *sdp_xml_parse_int(const char *data, uint8_t dtd);
-sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record);
-
-struct sdp_xml_data {
-	char *text;			/* Pointer to the current buffer */
-	int size;			/* Size of the current buffer */
-	sdp_data_t *data;		/* The current item being built */
-	struct sdp_xml_data *next;	/* Next item on the stack */
-	char type;			/* 0 = Text or Hexadecimal */
-	char *name;			/* Name, optional in the dtd */
-	/* TODO: What is it used for? */
-};
-
-struct sdp_xml_data *sdp_xml_data_alloc(void);
-void sdp_xml_data_free(struct sdp_xml_data *elem);
-struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem);
-
-sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
-							sdp_record_t *record);
-
 sdp_record_t *sdp_xml_parse_record(const char *data, int size);
 
 #endif /* __SDP_XML_H */