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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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