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);