1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * BlueZ - Bluetooth protocol stack for Linux
6 * Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org>
25 #include "lib/sdp_lib.h"
29 #define DBG(...) (void)(0)
30 #define error(...) (void)(0)
32 #define SDP_XML_ENCODING_NORMAL 0
33 #define SDP_XML_ENCODING_HEX 1
35 #define STRBUFSIZE 1024
39 char *text; /* Pointer to the current buffer */
40 int size; /* Size of the current buffer */
41 sdp_data_t *data; /* The current item being built */
42 struct sdp_xml_data *next; /* Next item on the stack */
43 char type; /* 0 = Text or Hexadecimal */
44 char *name; /* Name, optional in the dtd */
45 /* TODO: What is it used for? */
51 struct sdp_xml_data *stack_head;
55 static int compute_seq_size(sdp_data_t *data)
57 int unit_size = data->unitSize;
58 sdp_data_t *seq = data->val.dataseq;
60 for (; seq; seq = seq->next)
61 unit_size += seq->unitSize;
66 #define DEFAULT_XML_DATA_SIZE 1024
68 static struct sdp_xml_data *sdp_xml_data_alloc(void)
70 struct sdp_xml_data *elem;
72 elem = malloc(sizeof(struct sdp_xml_data));
76 memset(elem, 0, sizeof(struct sdp_xml_data));
78 /* Null terminate the text */
79 elem->size = DEFAULT_XML_DATA_SIZE;
80 elem->text = malloc(DEFAULT_XML_DATA_SIZE);
90 static struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem)
94 newbuf = malloc(elem->size * 2);
98 memcpy(newbuf, elem->text, elem->size);
107 static sdp_data_t *sdp_xml_parse_uuid128(const char *data)
114 memset(&val, 0, sizeof(val));
118 for (j = 0, i = 0; i < strlen(data);) {
119 if (data[i] == '-') {
125 buf[1] = data[i + 1];
127 val.data[j++] = strtoul(buf, 0, 16);
131 return sdp_data_alloc(SDP_UUID128, &val);
134 static sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record)
145 ret = sdp_xml_parse_uuid128(data);
149 val = strtoll(data, &endptr, 16);
155 if (val > USHRT_MAX) {
156 ret = sdp_data_alloc(SDP_UUID32, &val);
162 ret = sdp_data_alloc(SDP_UUID16, &val2);
166 sdp_pattern_add_uuid(record, &ret->val.uuid);
171 static sdp_data_t *sdp_xml_parse_int(const char *data, uint8_t dtd)
174 sdp_data_t *ret = NULL;
181 if (!strcmp("true", data))
183 else if (!strcmp("false", data))
188 ret = sdp_data_alloc(dtd, &val);
194 int8_t val = strtoul(data, &endptr, 0);
196 /* Failed to parse */
197 if ((endptr != data) && (*endptr != '\0'))
200 ret = sdp_data_alloc(dtd, &val);
206 uint8_t val = strtoul(data, &endptr, 0);
208 /* Failed to parse */
209 if ((endptr != data) && (*endptr != '\0'))
212 ret = sdp_data_alloc(dtd, &val);
218 int16_t val = strtoul(data, &endptr, 0);
220 /* Failed to parse */
221 if ((endptr != data) && (*endptr != '\0'))
224 ret = sdp_data_alloc(dtd, &val);
230 uint16_t val = strtoul(data, &endptr, 0);
232 /* Failed to parse */
233 if ((endptr != data) && (*endptr != '\0'))
236 ret = sdp_data_alloc(dtd, &val);
242 int32_t val = strtoul(data, &endptr, 0);
244 /* Failed to parse */
245 if ((endptr != data) && (*endptr != '\0'))
248 ret = sdp_data_alloc(dtd, &val);
254 uint32_t val = strtoul(data, &endptr, 0);
256 /* Failed to parse */
257 if ((endptr != data) && (*endptr != '\0'))
260 ret = sdp_data_alloc(dtd, &val);
266 int64_t val = strtoull(data, &endptr, 0);
268 /* Failed to parse */
269 if ((endptr != data) && (*endptr != '\0'))
272 ret = sdp_data_alloc(dtd, &val);
278 uint64_t val = strtoull(data, &endptr, 0);
280 /* Failed to parse */
281 if ((endptr != data) && (*endptr != '\0'))
284 ret = sdp_data_alloc(dtd, &val);
297 for (; i < 32; i += 2) {
299 buf[1] = data[i + 1];
301 val.data[i >> 1] = strtoul(buf, 0, 16);
304 ret = sdp_data_alloc(dtd, &val);
313 static char *sdp_xml_parse_string_decode(const char *data, char encoding,
316 int len = strlen(data);
319 if (encoding == SDP_XML_ENCODING_NORMAL) {
323 char buf[3], *decoded;
326 decoded = malloc((len >> 1) + 1);
330 /* Ensure the string is a power of 2 */
331 len = (len >> 1) << 1;
335 for (i = 0; i < len; i += 2) {
337 buf[1] = data[i + 1];
339 decoded[i >> 1] = strtoul(buf, 0, 16);
342 decoded[len >> 1] = '\0';
350 static sdp_data_t *sdp_xml_parse_url(const char *data)
352 uint8_t dtd = SDP_URL_STR8;
357 url = sdp_xml_parse_string_decode(data,
358 SDP_XML_ENCODING_NORMAL, &length);
362 if (length > UCHAR_MAX)
365 ret = sdp_data_alloc_with_length(dtd, url, length);
372 static sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
374 uint8_t dtd = SDP_TEXT_STR8;
379 text = sdp_xml_parse_string_decode(data, encoding, &length);
383 if (length > UCHAR_MAX)
384 dtd = SDP_TEXT_STR16;
386 ret = sdp_data_alloc_with_length(dtd, text, length);
393 static sdp_data_t *sdp_xml_parse_nil(const char *data)
395 return sdp_data_alloc(SDP_DATA_NIL, 0);
398 static sdp_data_t *sdp_xml_parse_datatype(const char *el,
399 struct sdp_xml_data *elem,
400 sdp_record_t *record)
402 const char *data = elem->text;
404 if (!strcmp(el, "boolean"))
405 return sdp_xml_parse_int(data, SDP_BOOL);
406 else if (!strcmp(el, "uint8"))
407 return sdp_xml_parse_int(data, SDP_UINT8);
408 else if (!strcmp(el, "uint16"))
409 return sdp_xml_parse_int(data, SDP_UINT16);
410 else if (!strcmp(el, "uint32"))
411 return sdp_xml_parse_int(data, SDP_UINT32);
412 else if (!strcmp(el, "uint64"))
413 return sdp_xml_parse_int(data, SDP_UINT64);
414 else if (!strcmp(el, "uint128"))
415 return sdp_xml_parse_int(data, SDP_UINT128);
416 else if (!strcmp(el, "int8"))
417 return sdp_xml_parse_int(data, SDP_INT8);
418 else if (!strcmp(el, "int16"))
419 return sdp_xml_parse_int(data, SDP_INT16);
420 else if (!strcmp(el, "int32"))
421 return sdp_xml_parse_int(data, SDP_INT32);
422 else if (!strcmp(el, "int64"))
423 return sdp_xml_parse_int(data, SDP_INT64);
424 else if (!strcmp(el, "int128"))
425 return sdp_xml_parse_int(data, SDP_INT128);
426 else if (!strcmp(el, "uuid"))
427 return sdp_xml_parse_uuid(data, record);
428 else if (!strcmp(el, "url"))
429 return sdp_xml_parse_url(data);
430 else if (!strcmp(el, "text"))
431 return sdp_xml_parse_text(data, elem->type);
432 else if (!strcmp(el, "nil"))
433 return sdp_xml_parse_nil(data);
437 static void element_start(GMarkupParseContext *context,
438 const char *element_name, const char **attribute_names,
439 const char **attribute_values, gpointer user_data, GError **err)
441 struct context_data *ctx_data = user_data;
443 if (!strcmp(element_name, "record"))
446 if (!strcmp(element_name, "attribute")) {
448 for (i = 0; attribute_names[i]; i++) {
449 if (!strcmp(attribute_names[i], "id")) {
450 ctx_data->attr_id = strtol(attribute_values[i], 0, 0);
454 DBG("New attribute 0x%04x", ctx_data->attr_id);
458 if (ctx_data->stack_head) {
459 struct sdp_xml_data *newelem = sdp_xml_data_alloc();
460 newelem->next = ctx_data->stack_head;
461 ctx_data->stack_head = newelem;
463 ctx_data->stack_head = sdp_xml_data_alloc();
464 ctx_data->stack_head->next = NULL;
467 if (!strcmp(element_name, "sequence"))
468 ctx_data->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL);
469 else if (!strcmp(element_name, "alternate"))
470 ctx_data->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL);
473 /* Parse value, name, encoding */
474 for (i = 0; attribute_names[i]; i++) {
475 if (!strcmp(attribute_names[i], "value")) {
476 int curlen = strlen(ctx_data->stack_head->text);
477 int attrlen = strlen(attribute_values[i]);
479 /* Ensure we're big enough */
480 while ((curlen + 1 + attrlen) > ctx_data->stack_head->size)
481 sdp_xml_data_expand(ctx_data->stack_head);
483 memcpy(ctx_data->stack_head->text + curlen,
484 attribute_values[i], attrlen);
485 ctx_data->stack_head->text[curlen + attrlen] = '\0';
488 if (!strcmp(attribute_names[i], "encoding")) {
489 if (!strcmp(attribute_values[i], "hex"))
490 ctx_data->stack_head->type = 1;
493 if (!strcmp(attribute_names[i], "name"))
494 ctx_data->stack_head->name = strdup(attribute_values[i]);
497 ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name,
498 ctx_data->stack_head, ctx_data->record);
500 if (ctx_data->stack_head->data == NULL)
501 error("Can't parse element %s", element_name);
505 static void sdp_xml_data_free(struct sdp_xml_data *elem)
508 sdp_data_free(elem->data);
515 static void element_end(GMarkupParseContext *context,
516 const char *element_name, gpointer user_data, GError **err)
518 struct context_data *ctx_data = user_data;
519 struct sdp_xml_data *elem;
521 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
522 if (element_name == NULL)
526 if (!strcmp(element_name, "record"))
529 if (!strcmp(element_name, "attribute")) {
530 if (ctx_data->stack_head && ctx_data->stack_head->data) {
531 int ret = sdp_attr_add(ctx_data->record, ctx_data->attr_id,
532 ctx_data->stack_head->data);
534 DBG("Could not add attribute 0x%04x",
537 ctx_data->stack_head->data = NULL;
538 sdp_xml_data_free(ctx_data->stack_head);
539 ctx_data->stack_head = NULL;
541 DBG("No data for attribute 0x%04x", ctx_data->attr_id);
546 if (!ctx_data->stack_head || !ctx_data->stack_head->data) {
547 DBG("No data for %s", element_name);
551 if (!strcmp(element_name, "sequence")) {
552 ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
554 if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
555 ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
556 ctx_data->stack_head->data->dtd = SDP_SEQ32;
557 } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
558 ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
559 ctx_data->stack_head->data->dtd = SDP_SEQ16;
561 ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
563 } else if (!strcmp(element_name, "alternate")) {
564 ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
566 if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
567 ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
568 ctx_data->stack_head->data->dtd = SDP_ALT32;
569 } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
570 ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
571 ctx_data->stack_head->data->dtd = SDP_ALT16;
573 ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
577 if (ctx_data->stack_head->next && ctx_data->stack_head->data &&
578 ctx_data->stack_head->next->data) {
579 switch (ctx_data->stack_head->next->data->dtd) {
586 ctx_data->stack_head->next->data->val.dataseq =
587 sdp_seq_append(ctx_data->stack_head->next->data->val.dataseq,
588 ctx_data->stack_head->data);
589 ctx_data->stack_head->data = NULL;
593 elem = ctx_data->stack_head;
594 ctx_data->stack_head = ctx_data->stack_head->next;
596 sdp_xml_data_free(elem);
600 static GMarkupParser parser = {
601 element_start, element_end, NULL, NULL, NULL
604 sdp_record_t *sdp_xml_parse_record(const char *data, int size)
606 GMarkupParseContext *ctx;
607 struct context_data *ctx_data;
608 sdp_record_t *record;
610 ctx_data = malloc(sizeof(*ctx_data));
614 record = sdp_record_alloc();
620 memset(ctx_data, 0, sizeof(*ctx_data));
621 ctx_data->record = record;
623 ctx = g_markup_parse_context_new(&parser, 0, ctx_data, NULL);
625 if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) {
626 error("XML parsing error");
627 g_markup_parse_context_free(ctx);
628 sdp_record_free(record);
633 g_markup_parse_context_free(ctx);
641 static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
642 void *data, void (*appender)(void *, const char *))
645 char buf[STRBUFSIZE];
646 char indent[MAXINDENT];
651 if (indent_level >= MAXINDENT)
652 indent_level = MAXINDENT - 2;
654 for (i = 0; i < indent_level; i++)
658 buf[STRBUFSIZE - 1] = '\0';
660 switch (value->dtd) {
662 appender(data, indent);
663 appender(data, "<nil/>\n");
667 appender(data, indent);
668 appender(data, "<boolean value=\"");
669 appender(data, value->val.uint8 ? "true" : "false");
670 appender(data, "\" />\n");
674 appender(data, indent);
675 appender(data, "<uint8 value=\"");
676 snprintf(buf, STRBUFSIZE - 1, "0x%02x", value->val.uint8);
678 appender(data, "\" />\n");
682 appender(data, indent);
683 appender(data, "<uint16 value=\"");
684 snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uint16);
686 appender(data, "\" />\n");
690 appender(data, indent);
691 appender(data, "<uint32 value=\"");
692 snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uint32);
694 appender(data, "\" />\n");
698 appender(data, indent);
699 appender(data, "<uint64 value=\"");
700 snprintf(buf, STRBUFSIZE - 1, "0x%016jx", value->val.uint64);
702 appender(data, "\" />\n");
706 appender(data, indent);
707 appender(data, "<uint128 value=\"");
709 for (i = 0; i < 16; i++) {
710 sprintf(&buf[i * 2], "%02x",
711 (unsigned char) value->val.uint128.data[i]);
715 appender(data, "\" />\n");
719 appender(data, indent);
720 appender(data, "<int8 value=\"");
721 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int8);
723 appender(data, "\" />\n");
727 appender(data, indent);
728 appender(data, "<int16 value=\"");
729 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int16);
731 appender(data, "\" />\n");
735 appender(data, indent);
736 appender(data, "<int32 value=\"");
737 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int32);
739 appender(data, "\" />\n");
743 appender(data, indent);
744 appender(data, "<int64 value=\"");
745 snprintf(buf, STRBUFSIZE - 1, "%jd", value->val.int64);
747 appender(data, "\" />\n");
751 appender(data, indent);
752 appender(data, "<int128 value=\"");
754 for (i = 0; i < 16; i++) {
755 sprintf(&buf[i * 2], "%02x",
756 (unsigned char) value->val.int128.data[i]);
760 appender(data, "\" />\n");
764 appender(data, indent);
765 appender(data, "<uuid value=\"");
766 snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uuid.value.uuid16);
768 appender(data, "\" />\n");
772 appender(data, indent);
773 appender(data, "<uuid value=\"");
774 snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uuid.value.uuid32);
776 appender(data, "\" />\n");
780 appender(data, indent);
781 appender(data, "<uuid value=\"");
783 snprintf(buf, STRBUFSIZE - 1,
784 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
785 (unsigned char) value->val.uuid.value.
787 (unsigned char) value->val.uuid.value.
789 (unsigned char) value->val.uuid.value.
791 (unsigned char) value->val.uuid.value.
793 (unsigned char) value->val.uuid.value.
795 (unsigned char) value->val.uuid.value.
797 (unsigned char) value->val.uuid.value.
799 (unsigned char) value->val.uuid.value.
801 (unsigned char) value->val.uuid.value.
803 (unsigned char) value->val.uuid.value.
805 (unsigned char) value->val.uuid.value.
807 (unsigned char) value->val.uuid.value.
809 (unsigned char) value->val.uuid.value.
811 (unsigned char) value->val.uuid.value.
813 (unsigned char) value->val.uuid.value.
815 (unsigned char) value->val.uuid.value.
819 appender(data, "\" />\n");
826 int num_chars_to_escape = 0;
827 int length = value->unitSize - 1;
832 for (i = 0; i < length; i++) {
833 if (!isprint(value->val.str[i]) &&
834 value->val.str[i] != '\0') {
839 /* XML is evil, must do this... */
840 if ((value->val.str[i] == '<') ||
841 (value->val.str[i] == '>') ||
842 (value->val.str[i] == '"') ||
843 (value->val.str[i] == '&'))
844 num_chars_to_escape++;
847 appender(data, indent);
849 appender(data, "<text ");
852 appender(data, "encoding=\"hex\" ");
853 strBuf = malloc(sizeof(char)
854 * ((value->unitSize-1) * 2 + 1));
856 DBG("No memory to convert raw data to xml");
860 /* Unit Size seems to include the size for dtd
862 This is safe for Normal strings, but not
864 for (i = 0; i < (value->unitSize-1); i++)
865 sprintf(&strBuf[i*sizeof(char)*2],
867 (unsigned char) value->val.str[i]);
869 strBuf[(value->unitSize-1) * 2] = '\0';
872 /* escape the XML disallowed chars */
873 strBuf = malloc(sizeof(char) *
874 (value->unitSize + 1 + num_chars_to_escape * 4));
876 DBG("No memory to convert raw data to xml");
879 for (i = 0, j = 0; i < length; i++) {
880 if (value->val.str[i] == '&') {
885 } else if (value->val.str[i] == '<') {
889 } else if (value->val.str[i] == '>') {
893 } else if (value->val.str[i] == '"') {
899 } else if (value->val.str[i] == '\0') {
902 strBuf[j++] = value->val.str[i];
909 appender(data, "value=\"");
910 appender(data, strBuf);
911 appender(data, "\" />\n");
922 appender(data, indent);
923 appender(data, "<url value=\"");
924 strBuf = strndup(value->val.str, value->unitSize - 1);
925 appender(data, strBuf);
927 appender(data, "\" />\n");
934 appender(data, indent);
935 appender(data, "<sequence>\n");
937 convert_raw_data_to_xml(value->val.dataseq,
938 indent_level + 1, data, appender);
940 appender(data, indent);
941 appender(data, "</sequence>\n");
948 appender(data, indent);
950 appender(data, "<alternate>\n");
952 convert_raw_data_to_xml(value->val.dataseq,
953 indent_level + 1, data, appender);
954 appender(data, indent);
956 appender(data, "</alternate>\n");
961 convert_raw_data_to_xml(value->next, indent_level, data, appender);
964 struct conversion_data {
966 void (*appender)(void *data, const char *);
969 static void convert_raw_attr_to_xml_func(void *val, void *data)
971 struct conversion_data *cd = data;
972 sdp_data_t *value = val;
973 char buf[STRBUFSIZE];
975 buf[STRBUFSIZE - 1] = '\0';
976 snprintf(buf, STRBUFSIZE - 1, "\t<attribute id=\"0x%04x\">\n",
978 cd->appender(cd->data, buf);
980 convert_raw_data_to_xml(value, 2, cd->data, cd->appender);
982 cd->appender(cd->data, "\t</attribute>\n");
986 * Will convert the sdp record to XML. The appender and data can be used
987 * to control where to output the record (e.g. file or a data buffer). The
988 * appender will be called repeatedly with data and the character buffer
989 * (containing parts of the generated XML) to append.
991 void convert_sdp_record_to_xml(sdp_record_t *rec,
992 void *data, void (*appender)(void *, const char *))
994 struct conversion_data cd;
997 cd.appender = appender;
999 if (rec && rec->attrlist) {
1000 appender(data, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n");
1001 appender(data, "<record>\n");
1002 sdp_list_foreach(rec->attrlist,
1003 convert_raw_attr_to_xml_func, &cd);
1004 appender(data, "</record>\n");