diff options
| author | Claudio Takahasi <claudio.takahasi@openbossa.org> | 2006-11-10 17:59:14 +0000 | 
|---|---|---|
| committer | Claudio Takahasi <claudio.takahasi@openbossa.org> | 2006-11-10 17:59:14 +0000 | 
| commit | e1046e6b02c2eef72ad63f2a61949e1ca606f63f (patch) | |
| tree | 9ca8d4936a0baa5df7d420289c1c34c18ef61264 | |
| parent | 326cf15e58c699fb2fb62181fcdd47339ec60c15 (diff) | |
Added raw service record to xml conversion functions
| -rw-r--r-- | common/Makefile.am | 2 | ||||
| -rw-r--r-- | common/sdp-xml.c | 400 | ||||
| -rw-r--r-- | common/sdp-xml.h | 35 | ||||
| -rw-r--r-- | hcid/dbus-adapter.c | 15 | ||||
| -rw-r--r-- | hcid/dbus-sdp.c | 142 | ||||
| -rw-r--r-- | hcid/dbus-sdp.h | 7 | ||||
| -rw-r--r-- | hcid/service-record.dtd | 29 | 
7 files changed, 606 insertions, 24 deletions
diff --git a/common/Makefile.am b/common/Makefile.am index 7249a51f..d71ca3b6 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -4,7 +4,7 @@ noinst_LIBRARIES = libhelper.a  libhelper_a_SOURCES = oui.h oui.c list.h list.c \  	textfile.h textfile.c helper.h helper.c \  	glib-ectomy.h glib-ectomy.c logging.h logging.c \ -	dbus.h dbus.c +	dbus.h dbus.c sdp-xml.h sdp-xml.c  noinst_PROGRAMS = test_textfile diff --git a/common/sdp-xml.c b/common/sdp-xml.c new file mode 100644 index 00000000..5c6dd877 --- /dev/null +++ b/common/sdp-xml.c @@ -0,0 +1,400 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2004-2006  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 "sdp-xml.h" + +#include <stdio.h> +#include <string.h> +#include <bluetooth/sdp_lib.h> +#include <malloc.h> +#include <limits.h> + +#define STRBUFSIZE 256 +#define MAXINDENT 64 + +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]; +	char next_indent[MAXINDENT]; + +	if (!value) +		return; + +	if (indent_level >= MAXINDENT) +		indent_level = MAXINDENT - 2; + +	for (i = 0; i < indent_level; i++) { +		indent[i] = '\t'; +		next_indent[i] = '\t'; +	} + +	indent[i] = '\0'; +	next_indent[i] = '\t'; +	next_indent[i + 1] = '\0'; + +	buf[STRBUFSIZE - 1] = '\0'; + +	switch (value->dtd) { +	case SDP_DATA_NIL: +		appender(data, indent); +		appender(data, "<nil/>\n"); +		break; +	case SDP_BOOL: +		appender(data, indent); +		appender(data, "<boolean value=\""); +		appender(data, value->val.uint8 ? "true" : "false"); +		appender(data, "\" />\n"); +		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"); +		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; +	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; +	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_UINT128: +		appender(data, indent); +		appender(data, "<uint128 value=\""); + +		for (i = 0; i < 16; i++) { +			sprintf(&buf[i * 2], "%02x", +				(unsigned char) value->val.uint128.data[i]); +		} + +		appender(data, buf); +		appender(data, "\" />\n"); +		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_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; +	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; +	case SDP_INT128: +		appender(data, indent); +		appender(data, "<int128 value=\""); + +		for (i = 0; i < 16; i++) { +			sprintf(&buf[i * 2], "%02x", +				(unsigned char) value->val.int128.data[i]); +		} +		appender(data, buf); + +		appender(data, "\" />\n"); +		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_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; +	case SDP_UUID128: +		appender(data, indent); +		appender(data, "<uuid value=\""); + +		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]); + +		appender(data, buf); +		appender(data, "\" />\n"); +		break; +	case SDP_TEXT_STR8: +	case SDP_TEXT_STR16: +	case SDP_TEXT_STR32: +	{ +		hex = 0; + +		int num_chars_to_escape = 0; +		 +		for (i = 0; i < value->unitSize; i++) { +			if (i == (value->unitSize - 1) +			    && value->val.str[i] == '\0') +				break; +			if (!isprint(value->val.str[i])) { +				hex = 1; +				break; +			} +			 +			/* 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++; +			 +		} +		 +		appender(data, indent); + +		appender(data, "<text "); + +		char *strBuf = 0; + +		if (hex) { +			appender(data, "encoding=\"hex\" "); +			strBuf = (char *) malloc(sizeof(char) +						 * (value->unitSize * 2 + 1)); + +			/* 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]); + +			strBuf[value->unitSize * 2] = '\0'; +		} +		else { +			int j; +			/* escape the XML disallowed chars */ +			strBuf = (char *) +				malloc(sizeof(char) * +				(value->unitSize + 1 + num_chars_to_escape * 4)); +			for (i = 0, j = 0; i < value->unitSize; 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 { +					strBuf[j++] = value->val.str[i]; +				} +			} + +			strBuf[j] = '\0'; +		} + +		appender(data, "value=\""); +		appender(data, strBuf); +		appender(data, "\" />\n"); +		free(strBuf); +		break; +	} +	case SDP_URL_STR8: +	case SDP_URL_STR16: +	case SDP_URL_STR32: +		appender(data, indent); +		appender(data, "<url value=\""); +		appender(data, value->val.str); +		appender(data, "\" />\n"); +		break; +	case SDP_SEQ8: +	case SDP_SEQ16: +	case SDP_SEQ32: +		appender(data, indent); +		appender(data, "<sequence>\n"); + +		convert_raw_data_to_xml(value->val.dataseq, +					indent_level + 1, data, +					appender); +					 +		appender(data, indent); +		appender(data, "</sequence>\n"); +		 +		break; +	case SDP_ALT8: +	case SDP_ALT16: +	case SDP_ALT32: +		appender(data, indent); + +		appender(data, "<alternate>\n"); + +		convert_raw_data_to_xml(value->val.dataseq, +					indent_level + 1, data, +					appender); +		appender(data, indent); + +		appender(data, "</alternate>\n"); +	        +		break; +	default: +		break; +	} + +	convert_raw_data_to_xml(value->next, indent_level, data, +				appender); +} + +struct conversion_data +{ +	void *data; +	void (*appender) (void *data, const char *); +}; + +static void convert_raw_attr_to_xml_func(void *val, void *data) +{ +	struct conversion_data *cd = (struct conversion_data *) data; +	sdp_data_t *value = (sdp_data_t *) val; +	char buf[STRBUFSIZE]; + +	buf[STRBUFSIZE - 1] = '\0'; +	snprintf(buf, STRBUFSIZE - 1, "\t<attribute id=\"0x%04x\">\n", +		 value->attrId); +	cd->appender(cd->data, buf); + +	if (data) +		convert_raw_data_to_xml(value, 2, cd->data, +					cd->appender); +	else +		cd->appender(cd->data, "\t\tNULL\n"); + +	cd->appender(cd->data, "\t</attribute>\n"); +} + +/* +    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 *)) +{ +	struct conversion_data cd; + +	cd.data = data; +	cd.appender = appender; + +	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/common/sdp-xml.h b/common/sdp-xml.h new file mode 100644 index 00000000..fe781f57 --- /dev/null +++ b/common/sdp-xml.h @@ -0,0 +1,35 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2004-2006  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 + * + */ + + +#ifndef __SDP_XML_H__ +#define __SDP_XML_H__ + +#include <ctype.h> +#include <bluetooth/sdp.h> + +void convert_sdp_record_to_xml(sdp_record_t * rec, +			       void *userData, +			       void (*appendFunc) (void *, const char *)); + +#endif /* __SDP_XML_H__ */ diff --git a/hcid/dbus-adapter.c b/hcid/dbus-adapter.c index 1aeccbc6..3edbabf2 100644 --- a/hcid/dbus-adapter.c +++ b/hcid/dbus-adapter.c @@ -1063,24 +1063,13 @@ static DBusHandlerResult adapter_set_name(DBusConnection *conn,  static DBusHandlerResult adapter_get_remote_svc(DBusConnection *conn,  						DBusMessage *msg, void *data)  { -	return get_remote_svc_rec(conn, msg, data); +	return get_remote_svc_rec(conn, msg, data, SDP_FORMAT_BINARY);  }  static DBusHandlerResult adapter_get_remote_svc_xml(DBusConnection *conn,  						DBusMessage *msg, void *data)  { -	DBusMessage *reply; -	const char *result = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" -				"<record></record>"; - -	reply = dbus_message_new_method_return(msg); -	if (!reply) -		return DBUS_HANDLER_RESULT_NEED_MEMORY; - -	dbus_message_append_args(reply, DBUS_TYPE_STRING, &result, -					DBUS_TYPE_INVALID); - -	return send_message_and_unref(conn, reply); +	return get_remote_svc_rec(conn, msg, data, SDP_FORMAT_XML);  }  static DBusHandlerResult adapter_get_remote_svc_handles(DBusConnection *conn, diff --git a/hcid/dbus-sdp.c b/hcid/dbus-sdp.c index f4f462f6..6ad33f3a 100644 --- a/hcid/dbus-sdp.c +++ b/hcid/dbus-sdp.c @@ -55,8 +55,10 @@  #include "dbus-adapter.h"  #include "dbus-error.h"  #include "dbus-sdp.h" +#include "sdp-xml.h"  #define MAX_IDENTIFIER_LEN	29	/* "XX:XX:XX:XX:XX:XX/0xYYYYYYYY\0" */ +#define DEFAULT_XML_BUFFER_SIZE 1024  struct service_provider {  	char *owner;	/* null for remote services or unique name if local */ @@ -98,6 +100,33 @@ typedef struct {  	char            *info_name;  } sdp_service_t; +typedef struct { +	int size; +	char *str; +} string_t; + +static void append_and_grow_string(void *data, const char *str) +{ +	string_t *string = (string_t *)data; +	char *newbuf; + +	int oldlen = strlen(string->str); +	int newlen = strlen(str); +	 +	if ((oldlen + newlen + 1) > string->size) { +		newbuf = (char *) malloc(string->size * 2); +		if (!newbuf) +			return; + +		memcpy(newbuf, string->str, oldlen+1); +		string->size *= 2; +		free(string->str); +		string->str = newbuf;		 +	} + +	strcat(string->str, str); +} +  /* FIXME:  move to a common file */  sdp_service_t sdp_service[] = {  	{ "vcp",	VIDEO_CONF_SVCLASS_ID,		"Video Conference"	}, @@ -610,6 +639,78 @@ failed:  	transaction_context_free(ctxt);  } +static void remote_svc_rec_completed_xml_cb(uint8_t type, uint16_t err, +						uint8_t *rsp, size_t size, +						void *udata) +{ +	struct transaction_context *ctxt = udata; +	sdp_record_t *rec = NULL; +	DBusMessage *reply; +	const char *dst; +	int scanned; +	string_t result; +	 +	if (!ctxt) +		return; + +	if (err == 0xffff) { +		/* Check for protocol error or I/O error */ +		int sdp_err = sdp_get_error(ctxt->session); +		if (sdp_err < 0) { +			error("search failed: Invalid session!"); +			error_failed(ctxt->conn, ctxt->rq, EINVAL); +			goto failed; +		} + +		error("search failed: %s (%d)", strerror(sdp_err), sdp_err); +		error_failed(ctxt->conn, ctxt->rq, sdp_err); +		goto failed; +	} + +	if (type == SDP_ERROR_RSP) { +		error_sdp_failed(ctxt->conn, ctxt->rq, err); +		goto failed; +	} + +	/* check response PDU ID */ +	if (type != SDP_SVC_ATTR_RSP) { +		error("SDP error: %s (%d)", strerror(EPROTO), EPROTO); +		error_failed(ctxt->conn, ctxt->rq, EPROTO); +		goto failed; +	} + +	dbus_message_get_args(ctxt->rq, NULL, +			DBUS_TYPE_STRING, &dst, +			DBUS_TYPE_INVALID); + +	reply = dbus_message_new_method_return(ctxt->rq); + +	result.str = 0; +	 +	rec = sdp_extract_pdu(rsp, &scanned); +	if (rec == NULL) { +		error("SVC REC is null"); +		goto done; +	} + +	result.str = malloc(sizeof(char) * DEFAULT_XML_BUFFER_SIZE); +	result.size = DEFAULT_XML_BUFFER_SIZE; +	 +	sdp_cache_append(NULL, dst, rec); + +	convert_sdp_record_to_xml(rec, &result, append_and_grow_string); + +	dbus_message_append_args(reply, +		DBUS_TYPE_STRING, &result.str, +		DBUS_TYPE_INVALID); + +done: +	send_message_and_unref(ctxt->conn, reply); +	free(result.str); +failed: +	transaction_context_free(ctxt); +} +  static void remote_svc_handles_completed_cb(uint8_t type, uint16_t err, uint8_t *rsp, size_t size, void *udata)  {  	struct transaction_context *ctxt = udata; @@ -900,12 +1001,45 @@ fail:  	return err;  } -DBusHandlerResult get_remote_svc_rec(DBusConnection *conn, DBusMessage *msg, void *data) +static int remote_svc_rec_conn_xml_cb(struct transaction_context *ctxt) +{ +	sdp_list_t *attrids = NULL; +	uint32_t range = 0x0000ffff; +	const char *dst; +	uint32_t handle; +	int err = 0; + +	if (sdp_set_notify(ctxt->session, remote_svc_rec_completed_xml_cb, ctxt) < 0) { +		err = -EINVAL; +		goto fail; +	} + +	dbus_message_get_args(ctxt->rq, NULL, +			DBUS_TYPE_STRING, &dst, +			DBUS_TYPE_UINT32, &handle, +			DBUS_TYPE_INVALID); + +	attrids = sdp_list_append(NULL, &range); +	/* Create/send the search request and set the callback to indicate the request completion */ +	if (sdp_service_attr_async(ctxt->session, handle, SDP_ATTR_REQ_RANGE, attrids) < 0) { +		err = -sdp_get_error(ctxt->session); +		goto fail; +	} + +fail: +	if (attrids) +		sdp_list_free(attrids, NULL); + +	return err; +} + +DBusHandlerResult get_remote_svc_rec(DBusConnection *conn, DBusMessage *msg, void *data, sdp_format_t format)  {  	struct adapter *adapter = data;  	const char *dst;  	uint32_t handle;  	int err = 0; +	connect_cb_t *cb;  	if (!dbus_message_get_args(msg, NULL,  			DBUS_TYPE_STRING, &dst, @@ -916,8 +1050,12 @@ DBusHandlerResult get_remote_svc_rec(DBusConnection *conn, DBusMessage *msg, voi  	if (find_pending_connect(dst))  		return error_service_search_in_progress(conn, msg); +	cb = remote_svc_rec_conn_cb; +	if (format == SDP_FORMAT_XML) +		cb = remote_svc_rec_conn_xml_cb; +  	if (!connect_request(conn, msg, adapter->dev_id, -				dst, remote_svc_rec_conn_cb, &err)) { +				dst, cb, &err)) {  		error("Search request failed: %s (%d)", strerror(err), err);  		return error_failed(conn, msg, err);  	} diff --git a/hcid/dbus-sdp.h b/hcid/dbus-sdp.h index 378a1456..4760c900 100644 --- a/hcid/dbus-sdp.h +++ b/hcid/dbus-sdp.h @@ -30,11 +30,16 @@  #define SDP_INTERFACE "org.bluez.SDP" +typedef enum { +	SDP_FORMAT_XML, +	SDP_FORMAT_BINARY +} sdp_format_t; +  DBusHandlerResult handle_sdp_method(DBusConnection *conn, DBusMessage *msg, void *data);  DBusHandlerResult get_remote_svc_handles(DBusConnection *conn, DBusMessage *msg, void *data); -DBusHandlerResult get_remote_svc_rec(DBusConnection *conn, DBusMessage *msg, void *data); +DBusHandlerResult get_remote_svc_rec(DBusConnection *conn, DBusMessage *msg, void *data, sdp_format_t format);  uint16_t sdp_str2svclass(const char *str); diff --git a/hcid/service-record.dtd b/hcid/service-record.dtd index 86b2bc43..000a5c37 100644 --- a/hcid/service-record.dtd +++ b/hcid/service-record.dtd @@ -1,14 +1,15 @@  <!ELEMENT record (attribute)*> -<!ELEMENT attribute (sequence|alternate|text|url|uuid|boolean|uint8|uint16|uint32|uint64|nil|data)+> +<!ELEMENT attribute (sequence|alternate|text|url|uuid|boolean|uint8|uint16|uint32|uint64|nil)+>  <!ATTLIST attribute id CDATA #REQUIRED> -<!ELEMENT sequence (sequence|alternate|text|url|uuid|boolean|uint8|uint16|uint32|uint64|nil|data)+> +<!ELEMENT sequence (sequence|alternate|text|url|uuid|boolean|uint8|uint16|uint32|uint64|uint128|int8|int16|int32|int64|int128|nil)+> -<!ELEMENT alternate (sequence|alternate|text|url|uuid|boolean|uint8|uint16|uint32|uint64|nil|data)+> +<!ELEMENT alternate (sequence|alternate|text|url|uuid|boolean|uint8|uint16|uint32|uint64|uint128|int8|int16|int32|int64|int128|nil)+>  <!ELEMENT text EMPTY>  <!ATTLIST text value CDATA #REQUIRED> +<!ATTLIST text encoding (normal|hex) "normal">  <!ELEMENT url EMPTY>  <!ATTLIST url value CDATA #REQUIRED> @@ -31,8 +32,22 @@  <!ELEMENT uint64 EMPTY>  <!ATTLIST uint64 value CDATA #REQUIRED> -<!ELEMENT nil EMPTY> +<!ELEMENT uint128 EMPTY> +<!ATTLIST uint128 value CDATA #REQUIRED> + +<!ELEMENT int8 EMPTY> +<!ATTLIST int8 value CDATA #REQUIRED> + +<!ELEMENT int16 EMPTY> +<!ATTLIST int16 value CDATA #REQUIRED> + +<!ELEMENT int32 EMPTY> +<!ATTLIST int32 value CDATA #REQUIRED> -<!ELEMENT data EMPTY> -<!ATTLIST data type CDATA #REQUIRED> -<!ATTLIST data value CDATA #REQUIRED> +<!ELEMENT int64 EMPTY> +<!ATTLIST int64 value CDATA #REQUIRED> + +<!ELEMENT int128 EMPTY> +<!ATTLIST int128 value CDATA #REQUIRED> + +<!ELEMENT nil EMPTY>  | 
