diff options
Diffstat (limited to 'common/sdp-glib.c')
| -rw-r--r-- | common/sdp-glib.c | 239 | 
1 files changed, 239 insertions, 0 deletions
diff --git a/common/sdp-glib.c b/common/sdp-glib.c new file mode 100644 index 00000000..bd27d822 --- /dev/null +++ b/common/sdp-glib.c @@ -0,0 +1,239 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2004-2008  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <limits.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 **err) +{ +	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, ctx_data->record); + +		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 **err) +{ +	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 = { +	element_start, element_end, NULL, NULL, NULL +}; + +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) { +		free(ctx_data); +		return NULL; +	} + +	memset(ctx_data, 0, sizeof(*ctx_data)); +	ctx_data->record = record; + +	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 record; +}  | 
