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