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