1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2005-2010 Marcel Holtmann <marcel (at) 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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