1 /*
2 *
3 * BlueZ - Bluetooth protocol stack for Linux
4 *
5 * Copyright (C) 2005-2008 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 #include <stdio.h>
29 #include <errno.h>
30 #include <ctype.h>
31 #include <string.h>
32 #include <limits.h>
33 #include <stdlib.h>
34
35 #include <bluetooth/sdp.h>
36 #include <bluetooth/sdp_lib.h>
37
38 #include "logging.h"
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 hex = 0;
236
237 int num_chars_to_escape = 0;
238
239 for (i = 0; i < value->unitSize; i++) {
240 if (i == (value->unitSize - 1)
241 && value->val.str[i] == '\0')
242 break;
243 if (!isprint(value->val.str[i])) {
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 char *strBuf = 0;
261
262 if (hex) {
263 appender(data, "encoding=\"hex\" ");
264 strBuf = (char *) malloc(sizeof(char)
265 * ((value->unitSize-1) * 2 + 1));
266
267 /* Unit Size seems to include the size for dtd
268 It is thus off by 1
269 This is safe for Normal strings, but not
270 hex encoded data */
271 for (i = 0; i < (value->unitSize-1); i++)
272 sprintf(&strBuf[i*sizeof(char)*2],
273 "%02x",
274 (unsigned char) value->val.str[i]);
275
276 strBuf[(value->unitSize-1) * 2] = '\0';
277 }
278 else {
279 int j;
280 /* escape the XML disallowed chars */
281 strBuf = (char *)
282 malloc(sizeof(char) *
283 (value->unitSize + 1 + num_chars_to_escape * 4));
284 for (i = 0, j = 0; i < value->unitSize; i++) {
285 if (value->val.str[i] == '&') {
286 strBuf[j++] = '&';
287 strBuf[j++] = 'a';
288 strBuf[j++] = 'm';
289 strBuf[j++] = 'p';
290 }
291 else if (value->val.str[i] == '<') {
292 strBuf[j++] = '&';
293 strBuf[j++] = 'l';
294 strBuf[j++] = 't';
295 }
296 else if (value->val.str[i] == '>') {
297 strBuf[j++] = '&';
298 strBuf[j++] = 'g';
299 strBuf[j++] = 't';
300 }
301 else if (value->val.str[i] == '"') {
302 strBuf[j++] = '&';
303 strBuf[j++] = 'q';
304 strBuf[j++] = 'u';
305 strBuf[j++] = 'o';
306 strBuf[j++] = 't';
307 }
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 appender(data, indent);
327 appender(data, "<url value=\"");
328 appender(data, value->val.str);
329 appender(data, "\" />\n");
330 break;
331
332 case SDP_SEQ8:
333 case SDP_SEQ16:
334 case SDP_SEQ32:
335 appender(data, indent);
336 appender(data, "<sequence>\n");
337
338 convert_raw_data_to_xml(value->val.dataseq,
339 indent_level + 1, data, appender);
340
341 appender(data, indent);
342 appender(data, "</sequence>\n");
343
344 break;
345
346 case SDP_ALT8:
347 case SDP_ALT16:
348 case SDP_ALT32:
349 appender(data, indent);
350
351 appender(data, "<alternate>\n");
352
353 convert_raw_data_to_xml(value->val.dataseq,
354 indent_level + 1, data, appender);
355 appender(data, indent);
356
357 appender(data, "</alternate>\n");
358
359 break;
360 }
361
362 convert_raw_data_to_xml(value->next, indent_level, data, appender);
363 }
364
365 struct conversion_data {
366 void *data;
367 void (*appender)(void *data, const char *);
368 };
369
convert_raw_attr_to_xml_func(void * val,void * data)370 static void convert_raw_attr_to_xml_func(void *val, void *data)
371 {
372 struct conversion_data *cd = (struct conversion_data *) data;
373 sdp_data_t *value = (sdp_data_t *) val;
374 char buf[STRBUFSIZE];
375
376 buf[STRBUFSIZE - 1] = '\0';
377 snprintf(buf, STRBUFSIZE - 1, "\t<attribute id=\"0x%04x\">\n",
378 value->attrId);
379 cd->appender(cd->data, buf);
380
381 if (data)
382 convert_raw_data_to_xml(value, 2, cd->data, cd->appender);
383 else
384 cd->appender(cd->data, "\t\tNULL\n");
385
386 cd->appender(cd->data, "\t</attribute>\n");
387 }
388
389 /*
390 * Will convert the sdp record to XML. The appender and data can be used
391 * to control where to output the record (e.g. file or a data buffer). The
392 * appender will be called repeatedly with data and the character buffer
393 * (containing parts of the generated XML) to append.
394 */
convert_sdp_record_to_xml(sdp_record_t * rec,void * data,void (* appender)(void *,const char *))395 void convert_sdp_record_to_xml(sdp_record_t *rec,
396 void *data, void (*appender)(void *, const char *))
397 {
398 struct conversion_data cd;
399
400 cd.data = data;
401 cd.appender = appender;
402
403 if (rec && rec->attrlist) {
404 appender(data, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n");
405 appender(data, "<record>\n");
406 sdp_list_foreach(rec->attrlist,
407 convert_raw_attr_to_xml_func, &cd);
408 appender(data, "</record>\n");
409 }
410 }
411
sdp_xml_parse_uuid128(const char * data)412 static sdp_data_t *sdp_xml_parse_uuid128(const char *data)
413 {
414 uint128_t val;
415 int i;
416 int j;
417
418 char buf[3];
419
420 memset(&val, 0, sizeof(val));
421
422 buf[2] = '\0';
423
424 for (j = 0, i = 0; i < strlen(data);) {
425 if (data[i] == '-') {
426 i++;
427 continue;
428 }
429
430 buf[0] = data[i];
431 buf[1] = data[i + 1];
432
433 val.data[j++] = strtoul(buf, 0, 16);
434 i += 2;
435 }
436
437 return sdp_data_alloc(SDP_UUID128, &val);
438 }
439
sdp_xml_parse_uuid(const char * data,sdp_record_t * record)440 sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record)
441 {
442 sdp_data_t *ret;
443 char *endptr;
444 uint32_t val;
445 uint16_t val2;
446 int len;
447
448 len = strlen(data);
449
450 if (len == 36) {
451 ret = sdp_xml_parse_uuid128(data);
452 goto result;
453 }
454
455 val = strtoll(data, &endptr, 16);
456
457 /* Couldn't parse */
458 if (*endptr != '\0')
459 return NULL;
460
461 if (val > USHRT_MAX) {
462 ret = sdp_data_alloc(SDP_UUID32, &val);
463 goto result;
464 }
465
466 val2 = val;
467
468 ret = sdp_data_alloc(SDP_UUID16, &val2);
469
470 result:
471 if (record && ret)
472 sdp_pattern_add_uuid(record, &ret->val.uuid);
473
474 return ret;
475 }
476
sdp_xml_parse_int(const char * data,uint8_t dtd)477 sdp_data_t *sdp_xml_parse_int(const char * data, uint8_t dtd)
478 {
479 char *endptr;
480 sdp_data_t *ret = NULL;
481
482 switch (dtd) {
483 case SDP_BOOL:
484 {
485 uint8_t val = 0;
486
487 if (!strcmp("true", data)) {
488 val = 1;
489 }
490
491 else if (!strcmp("false", data)) {
492 val = 0;
493 }
494 else {
495 return NULL;
496 }
497
498 ret = sdp_data_alloc(dtd, &val);
499 break;
500 }
501
502 case SDP_INT8:
503 {
504 int8_t val = strtoul(data, &endptr, 0);
505
506 /* Failed to parse */
507 if ((endptr != data) && (*endptr != '\0'))
508 return NULL;
509
510 ret = sdp_data_alloc(dtd, &val);
511 break;
512 }
513
514 case SDP_UINT8:
515 {
516 uint8_t val = strtoul(data, &endptr, 0);
517
518 /* Failed to parse */
519 if ((endptr != data) && (*endptr != '\0'))
520 return NULL;
521
522 ret = sdp_data_alloc(dtd, &val);
523 break;
524 }
525
526 case SDP_INT16:
527 {
528 int16_t val = strtoul(data, &endptr, 0);
529
530 /* Failed to parse */
531 if ((endptr != data) && (*endptr != '\0'))
532 return NULL;
533
534 ret = sdp_data_alloc(dtd, &val);
535 break;
536 }
537
538 case SDP_UINT16:
539 {
540 uint16_t val = strtoul(data, &endptr, 0);
541
542 /* Failed to parse */
543 if ((endptr != data) && (*endptr != '\0'))
544 return NULL;
545
546 ret = sdp_data_alloc(dtd, &val);
547 break;
548 }
549
550 case SDP_INT32:
551 {
552 int32_t val = strtoul(data, &endptr, 0);
553
554 /* Failed to parse */
555 if ((endptr != data) && (*endptr != '\0'))
556 return NULL;
557
558 ret = sdp_data_alloc(dtd, &val);
559 break;
560 }
561
562 case SDP_UINT32:
563 {
564 uint32_t val = strtoul(data, &endptr, 0);
565
566 /* Failed to parse */
567 if ((endptr != data) && (*endptr != '\0'))
568 return NULL;
569
570 ret = sdp_data_alloc(dtd, &val);
571 break;
572 }
573
574 case SDP_INT64:
575 {
576 int64_t val = strtoull(data, &endptr, 0);
577
578 /* Failed to parse */
579 if ((endptr != data) && (*endptr != '\0'))
580 return NULL;
581
582 ret = sdp_data_alloc(dtd, &val);
583 break;
584 }
585
586 case SDP_UINT64:
587 {
588 uint64_t val = strtoull(data, &endptr, 0);
589
590 /* Failed to parse */
591 if ((endptr != data) && (*endptr != '\0'))
592 return NULL;
593
594 ret = sdp_data_alloc(dtd, &val);
595 break;
596 }
597
598 case SDP_INT128:
599 case SDP_UINT128:
600 {
601 uint128_t val;
602 int i = 0;
603 char buf[3];
604
605 buf[2] = '\0';
606
607 for (; i < 32; i += 2) {
608 buf[0] = data[i];
609 buf[1] = data[i + 1];
610
611 val.data[i >> 1] = strtoul(buf, 0, 16);
612 }
613
614 ret = sdp_data_alloc(dtd, &val);
615 break;
616 }
617
618 };
619
620 return ret;
621 }
622
sdp_xml_parse_string_decode(const char * data,char encoding,uint32_t * length)623 static char *sdp_xml_parse_string_decode(const char *data, char encoding, uint32_t *length)
624 {
625 int len = strlen(data);
626 char *text;
627
628 if (encoding == SDP_XML_ENCODING_NORMAL) {
629 text = strdup(data);
630 *length = len;
631 } else {
632 char buf[3], *decoded;
633 int i;
634
635 decoded = malloc((len >> 1) + 1);
636
637 /* Ensure the string is a power of 2 */
638 len = (len >> 1) << 1;
639
640 buf[2] = '\0';
641
642 for (i = 0; i < len; i += 2) {
643 buf[0] = data[i];
644 buf[1] = data[i + 1];
645
646 decoded[i >> 1] = strtoul(buf, 0, 16);
647 }
648
649 decoded[len >> 1] = '\0';
650 text = decoded;
651 *length = len >> 1;
652 }
653
654 return text;
655 }
656
sdp_xml_parse_url(const char * data)657 sdp_data_t *sdp_xml_parse_url(const char *data)
658 {
659 uint8_t dtd = SDP_URL_STR8;
660 char *url;
661 uint32_t length;
662 sdp_data_t *ret;
663
664 url = sdp_xml_parse_string_decode(data,
665 SDP_XML_ENCODING_NORMAL, &length);
666
667 if (length > UCHAR_MAX)
668 dtd = SDP_URL_STR16;
669
670 ret = sdp_data_alloc_with_length(dtd, url, length);
671
672 debug("URL size %d length %d: -->%s<--", ret->unitSize, length, url);
673
674 free(url);
675
676 return ret;
677 }
678
sdp_xml_parse_text(const char * data,char encoding)679 sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
680 {
681 uint8_t dtd = SDP_TEXT_STR8;
682 char *text;
683 uint32_t length;
684 sdp_data_t *ret;
685
686 text = sdp_xml_parse_string_decode(data, encoding, &length);
687
688 if (length > UCHAR_MAX)
689 dtd = SDP_TEXT_STR16;
690
691 ret = sdp_data_alloc_with_length(dtd, text, length);
692
693 debug("Text size %d length %d: -->%s<--", ret->unitSize, length, text);
694
695 free(text);
696
697 return ret;
698 }
699
sdp_xml_parse_nil(const char * data)700 sdp_data_t *sdp_xml_parse_nil(const char *data)
701 {
702 return sdp_data_alloc(SDP_DATA_NIL, 0);
703 }
704
705 #define DEFAULT_XML_DATA_SIZE 1024
706
sdp_xml_data_alloc()707 struct sdp_xml_data *sdp_xml_data_alloc()
708 {
709 struct sdp_xml_data *elem;
710
711 elem = malloc(sizeof(struct sdp_xml_data));
712 if (!elem)
713 return NULL;
714
715 memset(elem, 0, sizeof(struct sdp_xml_data));
716
717 /* Null terminate the text */
718 elem->size = DEFAULT_XML_DATA_SIZE;
719 elem->text = malloc(DEFAULT_XML_DATA_SIZE);
720 elem->text[0] = '\0';
721
722 return elem;
723 }
724
sdp_xml_data_free(struct sdp_xml_data * elem)725 void sdp_xml_data_free(struct sdp_xml_data *elem)
726 {
727 if (elem->data)
728 sdp_data_free(elem->data);
729
730 if (elem->name)
731 free(elem->name);
732
733 if (elem->text)
734
735 free(elem->text);
736 free(elem);
737 }
738
sdp_xml_data_expand(struct sdp_xml_data * elem)739 struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem)
740 {
741 char *newbuf;
742
743 newbuf = malloc(elem->size * 2);
744 if (!newbuf)
745 return NULL;
746
747 memcpy(newbuf, elem->text, elem->size);
748 elem->size *= 2;
749 free(elem->text);
750
751 elem->text = newbuf;
752
753 return elem;
754 }
755
sdp_xml_parse_datatype(const char * el,struct sdp_xml_data * elem,sdp_record_t * record)756 sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
757 sdp_record_t *record)
758 {
759 const char *data = elem->text;
760
761 if (!strcmp(el, "boolean"))
762 return sdp_xml_parse_int(data, SDP_BOOL);
763 else if (!strcmp(el, "uint8"))
764 return sdp_xml_parse_int(data, SDP_UINT8);
765 else if (!strcmp(el, "uint16"))
766 return sdp_xml_parse_int(data, SDP_UINT16);
767 else if (!strcmp(el, "uint32"))
768 return sdp_xml_parse_int(data, SDP_UINT32);
769 else if (!strcmp(el, "uint64"))
770 return sdp_xml_parse_int(data, SDP_UINT64);
771 else if (!strcmp(el, "uint128"))
772 return sdp_xml_parse_int(data, SDP_UINT128);
773 else if (!strcmp(el, "int8"))
774 return sdp_xml_parse_int(data, SDP_INT8);
775 else if (!strcmp(el, "int16"))
776 return sdp_xml_parse_int(data, SDP_INT16);
777 else if (!strcmp(el, "int32"))
778 return sdp_xml_parse_int(data, SDP_INT32);
779 else if (!strcmp(el, "int64"))
780 return sdp_xml_parse_int(data, SDP_INT64);
781 else if (!strcmp(el, "int128"))
782 return sdp_xml_parse_int(data, SDP_INT128);
783 else if (!strcmp(el, "uuid"))
784 return sdp_xml_parse_uuid(data, record);
785 else if (!strcmp(el, "url"))
786 return sdp_xml_parse_url(data);
787 else if (!strcmp(el, "text"))
788 return sdp_xml_parse_text(data, elem->type);
789 else if (!strcmp(el, "nil"))
790 return sdp_xml_parse_nil(data);
791
792 return NULL;
793 }
794