1 /*
2 *
3 * BlueZ - Bluetooth protocol stack for Linux
4 *
5 * Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org>
6 *
7 *
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.
12 *
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.
17 *
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
21 *
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #define _GNU_SOURCE
29 #include <stdio.h>
30 #include <errno.h>
31 #include <ctype.h>
32 #include <string.h>
33 #include <limits.h>
34 #include <stdlib.h>
35
36 #include <bluetooth/sdp.h>
37 #include <bluetooth/sdp_lib.h>
38
39 #include "sdp-xml.h"
40
41 #define STRBUFSIZE 1024
42 #define MAXINDENT 64
43
convert_raw_data_to_xml(sdp_data_t * value,int indent_level,void * data,void (* appender)(void *,const char *))44 static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
45 void *data, void (*appender)(void *, const char *))
46 {
47 int i, hex;
48 char buf[STRBUFSIZE];
49 char indent[MAXINDENT];
50
51 if (!value)
52 return;
53
54 if (indent_level >= MAXINDENT)
55 indent_level = MAXINDENT - 2;
56
57 for (i = 0; i < indent_level; i++)
58 indent[i] = '\t';
59
60 indent[i] = '\0';
61 buf[STRBUFSIZE - 1] = '\0';
62
63 switch (value->dtd) {
64 case SDP_DATA_NIL:
65 appender(data, indent);
66 appender(data, "<nil/>\n");
67 break;
68
69 case SDP_BOOL:
70 appender(data, indent);
71 appender(data, "<boolean value=\"");
72 appender(data, value->val.uint8 ? "true" : "false");
73 appender(data, "\" />\n");
74 break;
75
76 case SDP_UINT8:
77 appender(data, indent);
78 appender(data, "<uint8 value=\"");
79 snprintf(buf, STRBUFSIZE - 1, "0x%02x", value->val.uint8);
80 appender(data, buf);
81 appender(data, "\" />\n");
82 break;
83
84 case SDP_UINT16:
85 appender(data, indent);
86 appender(data, "<uint16 value=\"");
87 snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uint16);
88 appender(data, buf);
89 appender(data, "\" />\n");
90 break;
91
92 case SDP_UINT32:
93 appender(data, indent);
94 appender(data, "<uint32 value=\"");
95 snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uint32);
96 appender(data, buf);
97 appender(data, "\" />\n");
98 break;
99
100 case SDP_UINT64:
101 appender(data, indent);
102 appender(data, "<uint64 value=\"");
103 snprintf(buf, STRBUFSIZE - 1, "0x%016jx", value->val.uint64);
104 appender(data, buf);
105 appender(data, "\" />\n");
106 break;
107
108 case SDP_UINT128:
109 appender(data, indent);
110 appender(data, "<uint128 value=\"");
111
112 for (i = 0; i < 16; i++) {
113 sprintf(&buf[i * 2], "%02x",
114 (unsigned char) value->val.uint128.data[i]);
115 }
116
117 appender(data, buf);
118 appender(data, "\" />\n");
119 break;
120
121 case SDP_INT8:
122 appender(data, indent);
123 appender(data, "<int8 value=\"");
124 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int8);
125 appender(data, buf);
126 appender(data, "\" />\n");
127 break;
128
129 case SDP_INT16:
130 appender(data, indent);
131 appender(data, "<int16 value=\"");
132 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int16);
133 appender(data, buf);
134 appender(data, "\" />\n");
135 break;
136
137 case SDP_INT32:
138 appender(data, indent);
139 appender(data, "<int32 value=\"");
140 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int32);
141 appender(data, buf);
142 appender(data, "\" />\n");
143 break;
144
145 case SDP_INT64:
146 appender(data, indent);
147 appender(data, "<int64 value=\"");
148 snprintf(buf, STRBUFSIZE - 1, "%jd", value->val.int64);
149 appender(data, buf);
150 appender(data, "\" />\n");
151 break;
152
153 case SDP_INT128:
154 appender(data, indent);
155 appender(data, "<int128 value=\"");
156
157 for (i = 0; i < 16; i++) {
158 sprintf(&buf[i * 2], "%02x",
159 (unsigned char) value->val.int128.data[i]);
160 }
161 appender(data, buf);
162
163 appender(data, "\" />\n");
164 break;
165
166 case SDP_UUID16:
167 appender(data, indent);
168 appender(data, "<uuid value=\"");
169 snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uuid.value.uuid16);
170 appender(data, buf);
171 appender(data, "\" />\n");
172 break;
173
174 case SDP_UUID32:
175 appender(data, indent);
176 appender(data, "<uuid value=\"");
177 snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uuid.value.uuid32);
178 appender(data, buf);
179 appender(data, "\" />\n");
180 break;
181
182 case SDP_UUID128:
183 appender(data, indent);
184 appender(data, "<uuid value=\"");
185
186 snprintf(buf, STRBUFSIZE - 1,
187 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
188 (unsigned char) value->val.uuid.value.
189 uuid128.data[0],
190 (unsigned char) value->val.uuid.value.
191 uuid128.data[1],
192 (unsigned char) value->val.uuid.value.
193 uuid128.data[2],
194 (unsigned char) value->val.uuid.value.
195 uuid128.data[3],
196 (unsigned char) value->val.uuid.value.
197 uuid128.data[4],
198 (unsigned char) value->val.uuid.value.
199 uuid128.data[5],
200 (unsigned char) value->val.uuid.value.
201 uuid128.data[6],
202 (unsigned char) value->val.uuid.value.
203 uuid128.data[7],
204 (unsigned char) value->val.uuid.value.
205 uuid128.data[8],
206 (unsigned char) value->val.uuid.value.
207 uuid128.data[9],
208 (unsigned char) value->val.uuid.value.
209 uuid128.data[10],
210 (unsigned char) value->val.uuid.value.
211 uuid128.data[11],
212 (unsigned char) value->val.uuid.value.
213 uuid128.data[12],
214 (unsigned char) value->val.uuid.value.
215 uuid128.data[13],
216 (unsigned char) value->val.uuid.value.
217 uuid128.data[14],
218 (unsigned char) value->val.uuid.value.
219 uuid128.data[15]);
220
221 appender(data, buf);
222 appender(data, "\" />\n");
223 break;
224
225 case SDP_TEXT_STR8:
226 case SDP_TEXT_STR16:
227 case SDP_TEXT_STR32:
228 {
229 int num_chars_to_escape = 0;
230 int length = value->unitSize - 1;
231 char *strBuf = 0;
232
233 hex = 0;
234
235 for (i = 0; i < length; i++) {
236 if (!isprint(value->val.str[i]) &&
237 value->val.str[i] != '\0') {
238 hex = 1;
239 break;
240 }
241
242 /* XML is evil, must do this... */
243 if ((value->val.str[i] == '<') ||
244 (value->val.str[i] == '>') ||
245 (value->val.str[i] == '"') ||
246 (value->val.str[i] == '&'))
247 num_chars_to_escape++;
248 }
249
250 appender(data, indent);
251
252 appender(data, "<text ");
253
254 if (hex) {
255 appender(data, "encoding=\"hex\" ");
256 strBuf = malloc(sizeof(char)
257 * ((value->unitSize-1) * 2 + 1));
258
259 /* Unit Size seems to include the size for dtd
260 It is thus off by 1
261 This is safe for Normal strings, but not
262 hex encoded data */
263 for (i = 0; i < (value->unitSize-1); i++)
264 sprintf(&strBuf[i*sizeof(char)*2],
265 "%02x",
266 (unsigned char) value->val.str[i]);
267
268 strBuf[(value->unitSize-1) * 2] = '\0';
269 }
270 else {
271 int j;
272 /* escape the XML disallowed chars */
273 strBuf = malloc(sizeof(char) *
274 (value->unitSize + 1 + num_chars_to_escape * 4));
275 for (i = 0, j = 0; i < length; i++) {
276 if (value->val.str[i] == '&') {
277 strBuf[j++] = '&';
278 strBuf[j++] = 'a';
279 strBuf[j++] = 'm';
280 strBuf[j++] = 'p';
281 }
282 else if (value->val.str[i] == '<') {
283 strBuf[j++] = '&';
284 strBuf[j++] = 'l';
285 strBuf[j++] = 't';
286 }
287 else if (value->val.str[i] == '>') {
288 strBuf[j++] = '&';
289 strBuf[j++] = 'g';
290 strBuf[j++] = 't';
291 }
292 else if (value->val.str[i] == '"') {
293 strBuf[j++] = '&';
294 strBuf[j++] = 'q';
295 strBuf[j++] = 'u';
296 strBuf[j++] = 'o';
297 strBuf[j++] = 't';
298 }
299 else if (value->val.str[i] == '\0') {
300 strBuf[j++] = ' ';
301 } else {
302 strBuf[j++] = value->val.str[i];
303 }
304 }
305
306 strBuf[j] = '\0';
307 }
308
309 appender(data, "value=\"");
310 appender(data, strBuf);
311 appender(data, "\" />\n");
312 free(strBuf);
313 break;
314 }
315
316 case SDP_URL_STR8:
317 case SDP_URL_STR16:
318 case SDP_URL_STR32:
319 {
320 char *strBuf;
321
322 appender(data, indent);
323 appender(data, "<url value=\"");
324 strBuf = strndup(value->val.str, value->unitSize - 1);
325 appender(data, strBuf);
326 free(strBuf);
327 appender(data, "\" />\n");
328 break;
329 }
330
331 case SDP_SEQ8:
332 case SDP_SEQ16:
333 case SDP_SEQ32:
334 appender(data, indent);
335 appender(data, "<sequence>\n");
336
337 convert_raw_data_to_xml(value->val.dataseq,
338 indent_level + 1, data, appender);
339
340 appender(data, indent);
341 appender(data, "</sequence>\n");
342
343 break;
344
345 case SDP_ALT8:
346 case SDP_ALT16:
347 case SDP_ALT32:
348 appender(data, indent);
349
350 appender(data, "<alternate>\n");
351
352 convert_raw_data_to_xml(value->val.dataseq,
353 indent_level + 1, data, appender);
354 appender(data, indent);
355
356 appender(data, "</alternate>\n");
357
358 break;
359 }
360
361 convert_raw_data_to_xml(value->next, indent_level, data, appender);
362 }
363
364 struct conversion_data {
365 void *data;
366 void (*appender)(void *data, const char *);
367 };
368
convert_raw_attr_to_xml_func(void * val,void * data)369 static void convert_raw_attr_to_xml_func(void *val, void *data)
370 {
371 struct conversion_data *cd = data;
372 sdp_data_t *value = val;
373 char buf[STRBUFSIZE];
374
375 buf[STRBUFSIZE - 1] = '\0';
376 snprintf(buf, STRBUFSIZE - 1, "\t<attribute id=\"0x%04x\">\n",
377 value->attrId);
378 cd->appender(cd->data, buf);
379
380 if (data)
381 convert_raw_data_to_xml(value, 2, cd->data, cd->appender);
382 else
383 cd->appender(cd->data, "\t\tNULL\n");
384
385 cd->appender(cd->data, "\t</attribute>\n");
386 }
387
388 /*
389 * Will convert the sdp record to XML. The appender and data can be used
390 * to control where to output the record (e.g. file or a data buffer). The
391 * appender will be called repeatedly with data and the character buffer
392 * (containing parts of the generated XML) to append.
393 */
convert_sdp_record_to_xml(sdp_record_t * rec,void * data,void (* appender)(void *,const char *))394 void convert_sdp_record_to_xml(sdp_record_t *rec,
395 void *data, void (*appender)(void *, const char *))
396 {
397 struct conversion_data cd;
398
399 cd.data = data;
400 cd.appender = appender;
401
402 if (rec && rec->attrlist) {
403 appender(data, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n");
404 appender(data, "<record>\n");
405 sdp_list_foreach(rec->attrlist,
406 convert_raw_attr_to_xml_func, &cd);
407 appender(data, "</record>\n");
408 }
409 }
410
sdp_xml_parse_uuid128(const char * data)411 static sdp_data_t *sdp_xml_parse_uuid128(const char *data)
412 {
413 uint128_t val;
414 unsigned int i, j;
415
416 char buf[3];
417
418 memset(&val, 0, sizeof(val));
419
420 buf[2] = '\0';
421
422 for (j = 0, i = 0; i < strlen(data);) {
423 if (data[i] == '-') {
424 i++;
425 continue;
426 }
427
428 buf[0] = data[i];
429 buf[1] = data[i + 1];
430
431 val.data[j++] = strtoul(buf, 0, 16);
432 i += 2;
433 }
434
435 return sdp_data_alloc(SDP_UUID128, &val);
436 }
437
sdp_xml_parse_uuid(const char * data,sdp_record_t * record)438 sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record)
439 {
440 sdp_data_t *ret;
441 char *endptr;
442 uint32_t val;
443 uint16_t val2;
444 int len;
445
446 len = strlen(data);
447
448 if (len == 36) {
449 ret = sdp_xml_parse_uuid128(data);
450 goto result;
451 }
452
453 val = strtoll(data, &endptr, 16);
454
455 /* Couldn't parse */
456 if (*endptr != '\0')
457 return NULL;
458
459 if (val > USHRT_MAX) {
460 ret = sdp_data_alloc(SDP_UUID32, &val);
461 goto result;
462 }
463
464 val2 = val;
465
466 ret = sdp_data_alloc(SDP_UUID16, &val2);
467
468 result:
469 if (record && ret)
470 sdp_pattern_add_uuid(record, &ret->val.uuid);
471
472 return ret;
473 }
474
sdp_xml_parse_int(const char * data,uint8_t dtd)475 sdp_data_t *sdp_xml_parse_int(const char * data, uint8_t dtd)
476 {
477 char *endptr;
478 sdp_data_t *ret = NULL;
479
480 switch (dtd) {
481 case SDP_BOOL:
482 {
483 uint8_t val = 0;
484
485 if (!strcmp("true", data)) {
486 val = 1;
487 }
488
489 else if (!strcmp("false", data)) {
490 val = 0;
491 }
492 else {
493 return NULL;
494 }
495
496 ret = sdp_data_alloc(dtd, &val);
497 break;
498 }
499
500 case SDP_INT8:
501 {
502 int8_t val = strtoul(data, &endptr, 0);
503
504 /* Failed to parse */
505 if ((endptr != data) && (*endptr != '\0'))
506 return NULL;
507
508 ret = sdp_data_alloc(dtd, &val);
509 break;
510 }
511
512 case SDP_UINT8:
513 {
514 uint8_t val = strtoul(data, &endptr, 0);
515
516 /* Failed to parse */
517 if ((endptr != data) && (*endptr != '\0'))
518 return NULL;
519
520 ret = sdp_data_alloc(dtd, &val);
521 break;
522 }
523
524 case SDP_INT16:
525 {
526 int16_t val = strtoul(data, &endptr, 0);
527
528 /* Failed to parse */
529 if ((endptr != data) && (*endptr != '\0'))
530 return NULL;
531
532 ret = sdp_data_alloc(dtd, &val);
533 break;
534 }
535
536 case SDP_UINT16:
537 {
538 uint16_t val = strtoul(data, &endptr, 0);
539
540 /* Failed to parse */
541 if ((endptr != data) && (*endptr != '\0'))
542 return NULL;
543
544 ret = sdp_data_alloc(dtd, &val);
545 break;
546 }
547
548 case SDP_INT32:
549 {
550 int32_t val = strtoul(data, &endptr, 0);
551
552 /* Failed to parse */
553 if ((endptr != data) && (*endptr != '\0'))
554 return NULL;
555
556 ret = sdp_data_alloc(dtd, &val);
557 break;
558 }
559
560 case SDP_UINT32:
561 {
562 uint32_t val = strtoul(data, &endptr, 0);
563
564 /* Failed to parse */
565 if ((endptr != data) && (*endptr != '\0'))
566 return NULL;
567
568 ret = sdp_data_alloc(dtd, &val);
569 break;
570 }
571
572 case SDP_INT64:
573 {
574 int64_t val = strtoull(data, &endptr, 0);
575
576 /* Failed to parse */
577 if ((endptr != data) && (*endptr != '\0'))
578 return NULL;
579
580 ret = sdp_data_alloc(dtd, &val);
581 break;
582 }
583
584 case SDP_UINT64:
585 {
586 uint64_t val = strtoull(data, &endptr, 0);
587
588 /* Failed to parse */
589 if ((endptr != data) && (*endptr != '\0'))
590 return NULL;
591
592 ret = sdp_data_alloc(dtd, &val);
593 break;
594 }
595
596 case SDP_INT128:
597 case SDP_UINT128:
598 {
599 uint128_t val;
600 int i = 0;
601 char buf[3];
602
603 buf[2] = '\0';
604
605 for (; i < 32; i += 2) {
606 buf[0] = data[i];
607 buf[1] = data[i + 1];
608
609 val.data[i >> 1] = strtoul(buf, 0, 16);
610 }
611
612 ret = sdp_data_alloc(dtd, &val);
613 break;
614 }
615
616 };
617
618 return ret;
619 }
620
sdp_xml_parse_string_decode(const char * data,char encoding,uint32_t * length)621 static char *sdp_xml_parse_string_decode(const char *data, char encoding, uint32_t *length)
622 {
623 int len = strlen(data);
624 char *text;
625
626 if (encoding == SDP_XML_ENCODING_NORMAL) {
627 text = strdup(data);
628 *length = len;
629 } else {
630 char buf[3], *decoded;
631 int i;
632
633 decoded = malloc((len >> 1) + 1);
634
635 /* Ensure the string is a power of 2 */
636 len = (len >> 1) << 1;
637
638 buf[2] = '\0';
639
640 for (i = 0; i < len; i += 2) {
641 buf[0] = data[i];
642 buf[1] = data[i + 1];
643
644 decoded[i >> 1] = strtoul(buf, 0, 16);
645 }
646
647 decoded[len >> 1] = '\0';
648 text = decoded;
649 *length = len >> 1;
650 }
651
652 return text;
653 }
654
sdp_xml_parse_url(const char * data)655 sdp_data_t *sdp_xml_parse_url(const char *data)
656 {
657 uint8_t dtd = SDP_URL_STR8;
658 char *url;
659 uint32_t length;
660 sdp_data_t *ret;
661
662 url = sdp_xml_parse_string_decode(data,
663 SDP_XML_ENCODING_NORMAL, &length);
664
665 if (length > UCHAR_MAX)
666 dtd = SDP_URL_STR16;
667
668 ret = sdp_data_alloc_with_length(dtd, url, length);
669
670 free(url);
671
672 return ret;
673 }
674
sdp_xml_parse_text(const char * data,char encoding)675 sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
676 {
677 uint8_t dtd = SDP_TEXT_STR8;
678 char *text;
679 uint32_t length;
680 sdp_data_t *ret;
681
682 text = sdp_xml_parse_string_decode(data, encoding, &length);
683
684 if (length > UCHAR_MAX)
685 dtd = SDP_TEXT_STR16;
686
687 ret = sdp_data_alloc_with_length(dtd, text, length);
688
689 free(text);
690
691 return ret;
692 }
693
sdp_xml_parse_nil(const char * data)694 sdp_data_t *sdp_xml_parse_nil(const char *data)
695 {
696 return sdp_data_alloc(SDP_DATA_NIL, 0);
697 }
698
699 #define DEFAULT_XML_DATA_SIZE 1024
700
sdp_xml_data_alloc(void)701 struct sdp_xml_data *sdp_xml_data_alloc(void)
702 {
703 struct sdp_xml_data *elem;
704
705 elem = malloc(sizeof(struct sdp_xml_data));
706 if (!elem)
707 return NULL;
708
709 memset(elem, 0, sizeof(struct sdp_xml_data));
710
711 /* Null terminate the text */
712 elem->size = DEFAULT_XML_DATA_SIZE;
713 elem->text = malloc(DEFAULT_XML_DATA_SIZE);
714 elem->text[0] = '\0';
715
716 return elem;
717 }
718
sdp_xml_data_free(struct sdp_xml_data * elem)719 void sdp_xml_data_free(struct sdp_xml_data *elem)
720 {
721 if (elem->data)
722 sdp_data_free(elem->data);
723
724 free(elem->name);
725 free(elem->text);
726 free(elem);
727 }
728
sdp_xml_data_expand(struct sdp_xml_data * elem)729 struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem)
730 {
731 char *newbuf;
732
733 newbuf = malloc(elem->size * 2);
734 if (!newbuf)
735 return NULL;
736
737 memcpy(newbuf, elem->text, elem->size);
738 elem->size *= 2;
739 free(elem->text);
740
741 elem->text = newbuf;
742
743 return elem;
744 }
745
sdp_xml_parse_datatype(const char * el,struct sdp_xml_data * elem,sdp_record_t * record)746 sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
747 sdp_record_t *record)
748 {
749 const char *data = elem->text;
750
751 if (!strcmp(el, "boolean"))
752 return sdp_xml_parse_int(data, SDP_BOOL);
753 else if (!strcmp(el, "uint8"))
754 return sdp_xml_parse_int(data, SDP_UINT8);
755 else if (!strcmp(el, "uint16"))
756 return sdp_xml_parse_int(data, SDP_UINT16);
757 else if (!strcmp(el, "uint32"))
758 return sdp_xml_parse_int(data, SDP_UINT32);
759 else if (!strcmp(el, "uint64"))
760 return sdp_xml_parse_int(data, SDP_UINT64);
761 else if (!strcmp(el, "uint128"))
762 return sdp_xml_parse_int(data, SDP_UINT128);
763 else if (!strcmp(el, "int8"))
764 return sdp_xml_parse_int(data, SDP_INT8);
765 else if (!strcmp(el, "int16"))
766 return sdp_xml_parse_int(data, SDP_INT16);
767 else if (!strcmp(el, "int32"))
768 return sdp_xml_parse_int(data, SDP_INT32);
769 else if (!strcmp(el, "int64"))
770 return sdp_xml_parse_int(data, SDP_INT64);
771 else if (!strcmp(el, "int128"))
772 return sdp_xml_parse_int(data, SDP_INT128);
773 else if (!strcmp(el, "uuid"))
774 return sdp_xml_parse_uuid(data, record);
775 else if (!strcmp(el, "url"))
776 return sdp_xml_parse_url(data);
777 else if (!strcmp(el, "text"))
778 return sdp_xml_parse_text(data, elem->type);
779 else if (!strcmp(el, "nil"))
780 return sdp_xml_parse_nil(data);
781
782 return NULL;
783 }
784