3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2005-2009 Marcel Holtmann <marcel@holtmann.org>
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.
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.
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
36 #include <bluetooth/sdp.h>
37 #include <bluetooth/sdp_lib.h>
42 #define STRBUFSIZE 1024
45 static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
46 void *data, void (*appender)(void *, const char *))
50 char indent[MAXINDENT];
51 char next_indent[MAXINDENT];
56 if (indent_level >= MAXINDENT)
57 indent_level = MAXINDENT - 2;
59 for (i = 0; i < indent_level; i++) {
61 next_indent[i] = '\t';
65 next_indent[i] = '\t';
66 next_indent[i + 1] = '\0';
68 buf[STRBUFSIZE - 1] = '\0';
72 appender(data, indent);
73 appender(data, "<nil/>\n");
77 appender(data, indent);
78 appender(data, "<boolean value=\"");
79 appender(data, value->val.uint8 ? "true" : "false");
80 appender(data, "\" />\n");
84 appender(data, indent);
85 appender(data, "<uint8 value=\"");
86 snprintf(buf, STRBUFSIZE - 1, "0x%02x", value->val.uint8);
88 appender(data, "\" />\n");
92 appender(data, indent);
93 appender(data, "<uint16 value=\"");
94 snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uint16);
96 appender(data, "\" />\n");
100 appender(data, indent);
101 appender(data, "<uint32 value=\"");
102 snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uint32);
104 appender(data, "\" />\n");
108 appender(data, indent);
109 appender(data, "<uint64 value=\"");
110 snprintf(buf, STRBUFSIZE - 1, "0x%016jx", value->val.uint64);
112 appender(data, "\" />\n");
116 appender(data, indent);
117 appender(data, "<uint128 value=\"");
119 for (i = 0; i < 16; i++) {
120 sprintf(&buf[i * 2], "%02x",
121 (unsigned char) value->val.uint128.data[i]);
125 appender(data, "\" />\n");
129 appender(data, indent);
130 appender(data, "<int8 value=\"");
131 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int8);
133 appender(data, "\" />\n");
137 appender(data, indent);
138 appender(data, "<int16 value=\"");
139 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int16);
141 appender(data, "\" />\n");
145 appender(data, indent);
146 appender(data, "<int32 value=\"");
147 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int32);
149 appender(data, "\" />\n");
153 appender(data, indent);
154 appender(data, "<int64 value=\"");
155 snprintf(buf, STRBUFSIZE - 1, "%jd", value->val.int64);
157 appender(data, "\" />\n");
161 appender(data, indent);
162 appender(data, "<int128 value=\"");
164 for (i = 0; i < 16; i++) {
165 sprintf(&buf[i * 2], "%02x",
166 (unsigned char) value->val.int128.data[i]);
170 appender(data, "\" />\n");
174 appender(data, indent);
175 appender(data, "<uuid value=\"");
176 snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uuid.value.uuid16);
178 appender(data, "\" />\n");
182 appender(data, indent);
183 appender(data, "<uuid value=\"");
184 snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uuid.value.uuid32);
186 appender(data, "\" />\n");
190 appender(data, indent);
191 appender(data, "<uuid value=\"");
193 snprintf(buf, STRBUFSIZE - 1,
194 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
195 (unsigned char) value->val.uuid.value.
197 (unsigned char) value->val.uuid.value.
199 (unsigned char) value->val.uuid.value.
201 (unsigned char) value->val.uuid.value.
203 (unsigned char) value->val.uuid.value.
205 (unsigned char) value->val.uuid.value.
207 (unsigned char) value->val.uuid.value.
209 (unsigned char) value->val.uuid.value.
211 (unsigned char) value->val.uuid.value.
213 (unsigned char) value->val.uuid.value.
215 (unsigned char) value->val.uuid.value.
217 (unsigned char) value->val.uuid.value.
219 (unsigned char) value->val.uuid.value.
221 (unsigned char) value->val.uuid.value.
223 (unsigned char) value->val.uuid.value.
225 (unsigned char) value->val.uuid.value.
229 appender(data, "\" />\n");
236 int num_chars_to_escape = 0;
237 int length = value->unitSize - 1;
242 for (i = 0; i < length; i++) {
243 if (!isprint(value->val.str[i]) &&
244 value->val.str[i] != '\0') {
249 /* XML is evil, must do this... */
250 if ((value->val.str[i] == '<') ||
251 (value->val.str[i] == '>') ||
252 (value->val.str[i] == '"') ||
253 (value->val.str[i] == '&'))
254 num_chars_to_escape++;
257 appender(data, indent);
259 appender(data, "<text ");
262 appender(data, "encoding=\"hex\" ");
263 strBuf = (char *) malloc(sizeof(char)
264 * ((value->unitSize-1) * 2 + 1));
266 /* Unit Size seems to include the size for dtd
268 This is safe for Normal strings, but not
270 for (i = 0; i < (value->unitSize-1); i++)
271 sprintf(&strBuf[i*sizeof(char)*2],
273 (unsigned char) value->val.str[i]);
275 strBuf[(value->unitSize-1) * 2] = '\0';
279 /* escape the XML disallowed chars */
281 malloc(sizeof(char) *
282 (value->unitSize + 1 + num_chars_to_escape * 4));
283 for (i = 0, j = 0; i < length; i++) {
284 if (value->val.str[i] == '&') {
290 else if (value->val.str[i] == '<') {
295 else if (value->val.str[i] == '>') {
300 else if (value->val.str[i] == '"') {
307 else if (value->val.str[i] == '\0') {
310 strBuf[j++] = value->val.str[i];
317 appender(data, "value=\"");
318 appender(data, strBuf);
319 appender(data, "\" />\n");
330 appender(data, indent);
331 appender(data, "<url value=\"");
332 strBuf = strndup(value->val.str, value->unitSize - 1);
333 appender(data, strBuf);
335 appender(data, "\" />\n");
342 appender(data, indent);
343 appender(data, "<sequence>\n");
345 convert_raw_data_to_xml(value->val.dataseq,
346 indent_level + 1, data, appender);
348 appender(data, indent);
349 appender(data, "</sequence>\n");
356 appender(data, indent);
358 appender(data, "<alternate>\n");
360 convert_raw_data_to_xml(value->val.dataseq,
361 indent_level + 1, data, appender);
362 appender(data, indent);
364 appender(data, "</alternate>\n");
369 convert_raw_data_to_xml(value->next, indent_level, data, appender);
372 struct conversion_data {
374 void (*appender)(void *data, const char *);
377 static void convert_raw_attr_to_xml_func(void *val, void *data)
379 struct conversion_data *cd = (struct conversion_data *) data;
380 sdp_data_t *value = (sdp_data_t *) val;
381 char buf[STRBUFSIZE];
383 buf[STRBUFSIZE - 1] = '\0';
384 snprintf(buf, STRBUFSIZE - 1, "\t<attribute id=\"0x%04x\">\n",
386 cd->appender(cd->data, buf);
389 convert_raw_data_to_xml(value, 2, cd->data, cd->appender);
391 cd->appender(cd->data, "\t\tNULL\n");
393 cd->appender(cd->data, "\t</attribute>\n");
397 * Will convert the sdp record to XML. The appender and data can be used
398 * to control where to output the record (e.g. file or a data buffer). The
399 * appender will be called repeatedly with data and the character buffer
400 * (containing parts of the generated XML) to append.
402 void convert_sdp_record_to_xml(sdp_record_t *rec,
403 void *data, void (*appender)(void *, const char *))
405 struct conversion_data cd;
408 cd.appender = appender;
410 if (rec && rec->attrlist) {
411 appender(data, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n");
412 appender(data, "<record>\n");
413 sdp_list_foreach(rec->attrlist,
414 convert_raw_attr_to_xml_func, &cd);
415 appender(data, "</record>\n");
419 static sdp_data_t *sdp_xml_parse_uuid128(const char *data)
426 memset(&val, 0, sizeof(val));
430 for (j = 0, i = 0; i < strlen(data);) {
431 if (data[i] == '-') {
437 buf[1] = data[i + 1];
439 val.data[j++] = strtoul(buf, 0, 16);
443 return sdp_data_alloc(SDP_UUID128, &val);
446 sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record)
457 ret = sdp_xml_parse_uuid128(data);
461 val = strtoll(data, &endptr, 16);
467 if (val > USHRT_MAX) {
468 ret = sdp_data_alloc(SDP_UUID32, &val);
474 ret = sdp_data_alloc(SDP_UUID16, &val2);
478 sdp_pattern_add_uuid(record, &ret->val.uuid);
483 sdp_data_t *sdp_xml_parse_int(const char * data, uint8_t dtd)
486 sdp_data_t *ret = NULL;
493 if (!strcmp("true", data)) {
497 else if (!strcmp("false", data)) {
504 ret = sdp_data_alloc(dtd, &val);
510 int8_t val = strtoul(data, &endptr, 0);
512 /* Failed to parse */
513 if ((endptr != data) && (*endptr != '\0'))
516 ret = sdp_data_alloc(dtd, &val);
522 uint8_t val = strtoul(data, &endptr, 0);
524 /* Failed to parse */
525 if ((endptr != data) && (*endptr != '\0'))
528 ret = sdp_data_alloc(dtd, &val);
534 int16_t val = strtoul(data, &endptr, 0);
536 /* Failed to parse */
537 if ((endptr != data) && (*endptr != '\0'))
540 ret = sdp_data_alloc(dtd, &val);
546 uint16_t val = strtoul(data, &endptr, 0);
548 /* Failed to parse */
549 if ((endptr != data) && (*endptr != '\0'))
552 ret = sdp_data_alloc(dtd, &val);
558 int32_t val = strtoul(data, &endptr, 0);
560 /* Failed to parse */
561 if ((endptr != data) && (*endptr != '\0'))
564 ret = sdp_data_alloc(dtd, &val);
570 uint32_t val = strtoul(data, &endptr, 0);
572 /* Failed to parse */
573 if ((endptr != data) && (*endptr != '\0'))
576 ret = sdp_data_alloc(dtd, &val);
582 int64_t val = strtoull(data, &endptr, 0);
584 /* Failed to parse */
585 if ((endptr != data) && (*endptr != '\0'))
588 ret = sdp_data_alloc(dtd, &val);
594 uint64_t val = strtoull(data, &endptr, 0);
596 /* Failed to parse */
597 if ((endptr != data) && (*endptr != '\0'))
600 ret = sdp_data_alloc(dtd, &val);
613 for (; i < 32; i += 2) {
615 buf[1] = data[i + 1];
617 val.data[i >> 1] = strtoul(buf, 0, 16);
620 ret = sdp_data_alloc(dtd, &val);
629 static char *sdp_xml_parse_string_decode(const char *data, char encoding, uint32_t *length)
631 int len = strlen(data);
634 if (encoding == SDP_XML_ENCODING_NORMAL) {
638 char buf[3], *decoded;
641 decoded = malloc((len >> 1) + 1);
643 /* Ensure the string is a power of 2 */
644 len = (len >> 1) << 1;
648 for (i = 0; i < len; i += 2) {
650 buf[1] = data[i + 1];
652 decoded[i >> 1] = strtoul(buf, 0, 16);
655 decoded[len >> 1] = '\0';
663 sdp_data_t *sdp_xml_parse_url(const char *data)
665 uint8_t dtd = SDP_URL_STR8;
670 url = sdp_xml_parse_string_decode(data,
671 SDP_XML_ENCODING_NORMAL, &length);
673 if (length > UCHAR_MAX)
676 ret = sdp_data_alloc_with_length(dtd, url, length);
678 debug("URL size %d length %d: -->%s<--", ret->unitSize, length, url);
685 sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
687 uint8_t dtd = SDP_TEXT_STR8;
692 text = sdp_xml_parse_string_decode(data, encoding, &length);
694 if (length > UCHAR_MAX)
695 dtd = SDP_TEXT_STR16;
697 ret = sdp_data_alloc_with_length(dtd, text, length);
699 debug("Text size %d length %d: -->%s<--", ret->unitSize, length, text);
706 sdp_data_t *sdp_xml_parse_nil(const char *data)
708 return sdp_data_alloc(SDP_DATA_NIL, 0);
711 #define DEFAULT_XML_DATA_SIZE 1024
713 struct sdp_xml_data *sdp_xml_data_alloc()
715 struct sdp_xml_data *elem;
717 elem = malloc(sizeof(struct sdp_xml_data));
721 memset(elem, 0, sizeof(struct sdp_xml_data));
723 /* Null terminate the text */
724 elem->size = DEFAULT_XML_DATA_SIZE;
725 elem->text = malloc(DEFAULT_XML_DATA_SIZE);
726 elem->text[0] = '\0';
731 void sdp_xml_data_free(struct sdp_xml_data *elem)
734 sdp_data_free(elem->data);
745 struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem)
749 newbuf = malloc(elem->size * 2);
753 memcpy(newbuf, elem->text, elem->size);
762 sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
763 sdp_record_t *record)
765 const char *data = elem->text;
767 if (!strcmp(el, "boolean"))
768 return sdp_xml_parse_int(data, SDP_BOOL);
769 else if (!strcmp(el, "uint8"))
770 return sdp_xml_parse_int(data, SDP_UINT8);
771 else if (!strcmp(el, "uint16"))
772 return sdp_xml_parse_int(data, SDP_UINT16);
773 else if (!strcmp(el, "uint32"))
774 return sdp_xml_parse_int(data, SDP_UINT32);
775 else if (!strcmp(el, "uint64"))
776 return sdp_xml_parse_int(data, SDP_UINT64);
777 else if (!strcmp(el, "uint128"))
778 return sdp_xml_parse_int(data, SDP_UINT128);
779 else if (!strcmp(el, "int8"))
780 return sdp_xml_parse_int(data, SDP_INT8);
781 else if (!strcmp(el, "int16"))
782 return sdp_xml_parse_int(data, SDP_INT16);
783 else if (!strcmp(el, "int32"))
784 return sdp_xml_parse_int(data, SDP_INT32);
785 else if (!strcmp(el, "int64"))
786 return sdp_xml_parse_int(data, SDP_INT64);
787 else if (!strcmp(el, "int128"))
788 return sdp_xml_parse_int(data, SDP_INT128);
789 else if (!strcmp(el, "uuid"))
790 return sdp_xml_parse_uuid(data, record);
791 else if (!strcmp(el, "url"))
792 return sdp_xml_parse_url(data);
793 else if (!strcmp(el, "text"))
794 return sdp_xml_parse_text(data, elem->type);
795 else if (!strcmp(el, "nil"))
796 return sdp_xml_parse_nil(data);