diff options
Diffstat (limited to 'common/sdp-glib.c')
| -rw-r--r-- | common/sdp-glib.c | 187 | 
1 files changed, 180 insertions, 7 deletions
| diff --git a/common/sdp-glib.c b/common/sdp-glib.c index fa0e8a17..37c8580f 100644 --- a/common/sdp-glib.c +++ b/common/sdp-glib.c @@ -25,22 +25,176 @@  #include <config.h>  #endif +#include <stdlib.h> + +#include <bluetooth/sdp.h> +#include <bluetooth/sdp_lib.h> +  #include <glib.h>  #include "logging.h"  #include "sdp-xml.h" +static int compute_seq_size(sdp_data_t *data) +{ +	int unit_size = data->unitSize; +	sdp_data_t *seq = data->val.dataseq; + +	for (; seq; seq = seq->next) +		unit_size += seq->unitSize; + +	return unit_size; +} + +struct context_data { +	sdp_record_t *record; +	sdp_data_t attr_data; +	struct sdp_xml_data *stack_head; +	uint16_t attr_id; +}; +  static void element_start(GMarkupParseContext *context,  		const gchar *element_name, const gchar **attribute_names, -		const gchar **attribute_values, gpointer user_data, GError **error) +		const gchar **attribute_values, gpointer user_data, GError **err)  { -	debug("<%s>", element_name); +	struct context_data *ctx_data = user_data; + +	if (!strcmp(element_name, "record")) +		return; + +	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; +			} +		} +		debug("New attribute 0x%04x", ctx_data->attr_id); +		return; +	} + +	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; +	} + +	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]); + +				/* Ensure we're big enough */ +				while ((curlen + 1 + attrlen) > ctx_data->stack_head->size) { +					sdp_xml_data_expand(ctx_data->stack_head); +				} + +				memcpy(ctx_data->stack_head->text + curlen, +						attribute_values[i], attrlen); +				ctx_data->stack_head->text[curlen + attrlen] = '\0'; +			} + +			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]); +			} +		} + +		ctx_data->stack_head->data = +			sdp_xml_parse_datatype(element_name, ctx_data->stack_head); + +		if (ctx_data->stack_head->data == NULL) +			error("Can't parse element %s", element_name); +	}  }  static void element_end(GMarkupParseContext *context, -		const gchar *element_name, gpointer user_data, GError **error) +		const gchar *element_name, gpointer user_data, GError **err)  { -	debug("</%s>", element_name); +	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) +				debug("Trouble adding attribute\n"); + +			ctx_data->stack_head->data = NULL; +			sdp_xml_data_free(ctx_data->stack_head); +			ctx_data->stack_head = NULL; +		} else { +			debug("No data for attribute 0x%04x\n", ctx_data->attr_id); +		} +		return; +	} + +	if (!strcmp(element_name, "sequence")) { +		ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data); + +		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); + +		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); +		} +	} + +	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; +		} + +		elem = ctx_data->stack_head; +		ctx_data->stack_head = ctx_data->stack_head->next; + +		sdp_xml_data_free(elem); +	}  }  static GMarkupParser parser = { @@ -50,14 +204,33 @@ static GMarkupParser parser = {  sdp_record_t *sdp_xml_parse_record(const char *data, int size)  {  	GMarkupParseContext *ctx; +	struct context_data *ctx_data; +	sdp_record_t *record; + +	ctx_data = malloc(sizeof(*ctx_data)); +	if (!ctx_data) +		return NULL; + +	record = sdp_record_alloc(); +	if (!record) { +		sdp_record_free(record); +		return NULL; +	} + +	memset(ctx_data, 0, sizeof(*ctx_data)); +	ctx_data->record = record; -	ctx = g_markup_parse_context_new(&parser, 0, NULL, NULL); +	ctx = g_markup_parse_context_new(&parser, 0, ctx_data, NULL);  	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;  	} -	g_markup_parse_context_free(ctx); +	free(ctx_data); -	return NULL; +	return record;  } | 
