3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org>
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.
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.
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
38 #include "lib/sdp_lib.h"
42 #define DBG(...) (void)(0)
43 #define error(...) (void)(0)
45 #define SDP_XML_ENCODING_NORMAL 0
46 #define SDP_XML_ENCODING_HEX 1
48 #define STRBUFSIZE 1024
52 char *text; /* Pointer to the current buffer */
53 int size; /* Size of the current buffer */
54 sdp_data_t *data; /* The current item being built */
55 struct sdp_xml_data *next; /* Next item on the stack */
56 char type; /* 0 = Text or Hexadecimal */
57 char *name; /* Name, optional in the dtd */
58 /* TODO: What is it used for? */
64 struct sdp_xml_data *stack_head;
68 static int compute_seq_size(sdp_data_t *data)
70 int unit_size = data->unitSize;
71 sdp_data_t *seq = data->val.dataseq;
73 for (; seq; seq = seq->next)
74 unit_size += seq->unitSize;
79 #define DEFAULT_XML_DATA_SIZE 1024
81 static struct sdp_xml_data *sdp_xml_data_alloc(void)
83 struct sdp_xml_data *elem;
85 elem = malloc(sizeof(struct sdp_xml_data));
89 memset(elem, 0, sizeof(struct sdp_xml_data));
91 /* Null terminate the text */
92 elem->size = DEFAULT_XML_DATA_SIZE;
93 elem->text = malloc(DEFAULT_XML_DATA_SIZE);
103 static struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem)
107 newbuf = malloc(elem->size * 2);
111 memcpy(newbuf, elem->text, elem->size);
120 static sdp_data_t *sdp_xml_parse_uuid128(const char *data)
127 memset(&val, 0, sizeof(val));
131 for (j = 0, i = 0; i < strlen(data);) {
132 if (data[i] == '-') {
138 buf[1] = data[i + 1];
140 val.data[j++] = strtoul(buf, 0, 16);
144 return sdp_data_alloc(SDP_UUID128, &val);
147 static sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record)
158 ret = sdp_xml_parse_uuid128(data);
162 val = strtoll(data, &endptr, 16);
168 if (val > USHRT_MAX) {
169 ret = sdp_data_alloc(SDP_UUID32, &val);
175 ret = sdp_data_alloc(SDP_UUID16, &val2);
179 sdp_pattern_add_uuid(record, &ret->val.uuid);
184 static sdp_data_t *sdp_xml_parse_int(const char *data, uint8_t dtd)
187 sdp_data_t *ret = NULL;
194 if (!strcmp("true", data))
196 else if (!strcmp("false", data))
201 ret = sdp_data_alloc(dtd, &val);
207 int8_t val = strtoul(data, &endptr, 0);
209 /* Failed to parse */
210 if ((endptr != data) && (*endptr != '\0'))
213 ret = sdp_data_alloc(dtd, &val);
219 uint8_t val = strtoul(data, &endptr, 0);
221 /* Failed to parse */
222 if ((endptr != data) && (*endptr != '\0'))
225 ret = sdp_data_alloc(dtd, &val);
231 int16_t val = strtoul(data, &endptr, 0);
233 /* Failed to parse */
234 if ((endptr != data) && (*endptr != '\0'))
237 ret = sdp_data_alloc(dtd, &val);
243 uint16_t val = strtoul(data, &endptr, 0);
245 /* Failed to parse */
246 if ((endptr != data) && (*endptr != '\0'))
249 ret = sdp_data_alloc(dtd, &val);
255 int32_t val = strtoul(data, &endptr, 0);
257 /* Failed to parse */
258 if ((endptr != data) && (*endptr != '\0'))
261 ret = sdp_data_alloc(dtd, &val);
267 uint32_t val = strtoul(data, &endptr, 0);
269 /* Failed to parse */
270 if ((endptr != data) && (*endptr != '\0'))
273 ret = sdp_data_alloc(dtd, &val);
279 int64_t val = strtoull(data, &endptr, 0);
281 /* Failed to parse */
282 if ((endptr != data) && (*endptr != '\0'))
285 ret = sdp_data_alloc(dtd, &val);
291 uint64_t val = strtoull(data, &endptr, 0);
293 /* Failed to parse */
294 if ((endptr != data) && (*endptr != '\0'))
297 ret = sdp_data_alloc(dtd, &val);
310 for (; i < 32; i += 2) {
312 buf[1] = data[i + 1];
314 val.data[i >> 1] = strtoul(buf, 0, 16);
317 ret = sdp_data_alloc(dtd, &val);
326 static char *sdp_xml_parse_string_decode(const char *data, char encoding,
329 int len = strlen(data);
332 if (encoding == SDP_XML_ENCODING_NORMAL) {
336 char buf[3], *decoded;
339 decoded = malloc((len >> 1) + 1);
343 /* Ensure the string is a power of 2 */
344 len = (len >> 1) << 1;
348 for (i = 0; i < len; i += 2) {
350 buf[1] = data[i + 1];
352 decoded[i >> 1] = strtoul(buf, 0, 16);
355 decoded[len >> 1] = '\0';
363 static sdp_data_t *sdp_xml_parse_url(const char *data)
365 uint8_t dtd = SDP_URL_STR8;
370 url = sdp_xml_parse_string_decode(data,
371 SDP_XML_ENCODING_NORMAL, &length);
375 if (length > UCHAR_MAX)
378 ret = sdp_data_alloc_with_length(dtd, url, length);
385 static sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
387 uint8_t dtd = SDP_TEXT_STR8;
392 text = sdp_xml_parse_string_decode(data, encoding, &length);
396 if (length > UCHAR_MAX)
397 dtd = SDP_TEXT_STR16;
399 ret = sdp_data_alloc_with_length(dtd, text, length);
406 static sdp_data_t *sdp_xml_parse_nil(const char *data)
408 return sdp_data_alloc(SDP_DATA_NIL, 0);
411 static sdp_data_t *sdp_xml_parse_datatype(const char *el,
412 struct sdp_xml_data *elem,
413 sdp_record_t *record)
415 const char *data = elem->text;
417 if (!strcmp(el, "boolean"))
418 return sdp_xml_parse_int(data, SDP_BOOL);
419 else if (!strcmp(el, "uint8"))
420 return sdp_xml_parse_int(data, SDP_UINT8);
421 else if (!strcmp(el, "uint16"))
422 return sdp_xml_parse_int(data, SDP_UINT16);
423 else if (!strcmp(el, "uint32"))
424 return sdp_xml_parse_int(data, SDP_UINT32);
425 else if (!strcmp(el, "uint64"))
426 return sdp_xml_parse_int(data, SDP_UINT64);
427 else if (!strcmp(el, "uint128"))
428 return sdp_xml_parse_int(data, SDP_UINT128);
429 else if (!strcmp(el, "int8"))
430 return sdp_xml_parse_int(data, SDP_INT8);
431 else if (!strcmp(el, "int16"))
432 return sdp_xml_parse_int(data, SDP_INT16);
433 else if (!strcmp(el, "int32"))
434 return sdp_xml_parse_int(data, SDP_INT32);
435 else if (!strcmp(el, "int64"))
436 return sdp_xml_parse_int(data, SDP_INT64);
437 else if (!strcmp(el, "int128"))
438 return sdp_xml_parse_int(data, SDP_INT128);
439 else if (!strcmp(el, "uuid"))
440 return sdp_xml_parse_uuid(data, record);
441 else if (!strcmp(el, "url"))
442 return sdp_xml_parse_url(data);
443 else if (!strcmp(el, "text"))
444 return sdp_xml_parse_text(data, elem->type);
445 else if (!strcmp(el, "nil"))
446 return sdp_xml_parse_nil(data);
450 static void element_start(GMarkupParseContext *context,
451 const char *element_name, const char **attribute_names,
452 const char **attribute_values, gpointer user_data, GError **err)
454 struct context_data *ctx_data = user_data;
456 if (!strcmp(element_name, "record"))
459 if (!strcmp(element_name, "attribute")) {
461 for (i = 0; attribute_names[i]; i++) {
462 if (!strcmp(attribute_names[i], "id")) {
463 ctx_data->attr_id = strtol(attribute_values[i], 0, 0);
467 DBG("New attribute 0x%04x", ctx_data->attr_id);
471 if (ctx_data->stack_head) {
472 struct sdp_xml_data *newelem = sdp_xml_data_alloc();
473 newelem->next = ctx_data->stack_head;
474 ctx_data->stack_head = newelem;
476 ctx_data->stack_head = sdp_xml_data_alloc();
477 ctx_data->stack_head->next = NULL;
480 if (!strcmp(element_name, "sequence"))
481 ctx_data->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL);
482 else if (!strcmp(element_name, "alternate"))
483 ctx_data->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL);
486 /* Parse value, name, encoding */
487 for (i = 0; attribute_names[i]; i++) {
488 if (!strcmp(attribute_names[i], "value")) {
489 int curlen = strlen(ctx_data->stack_head->text);
490 int attrlen = strlen(attribute_values[i]);
492 /* Ensure we're big enough */
493 while ((curlen + 1 + attrlen) > ctx_data->stack_head->size)
494 sdp_xml_data_expand(ctx_data->stack_head);
496 memcpy(ctx_data->stack_head->text + curlen,
497 attribute_values[i], attrlen);
498 ctx_data->stack_head->text[curlen + attrlen] = '\0';
501 if (!strcmp(attribute_names[i], "encoding")) {
502 if (!strcmp(attribute_values[i], "hex"))
503 ctx_data->stack_head->type = 1;
506 if (!strcmp(attribute_names[i], "name"))
507 ctx_data->stack_head->name = strdup(attribute_values[i]);
510 ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name,
511 ctx_data->stack_head, ctx_data->record);
513 if (ctx_data->stack_head->data == NULL)
514 error("Can't parse element %s", element_name);
518 static void sdp_xml_data_free(struct sdp_xml_data *elem)
521 sdp_data_free(elem->data);
528 static void element_end(GMarkupParseContext *context,
529 const char *element_name, gpointer user_data, GError **err)
531 struct context_data *ctx_data = user_data;
532 struct sdp_xml_data *elem;
534 #ifdef __TIZEN_PATCH__
535 if (element_name == NULL)
539 if (!strcmp(element_name, "record"))
542 if (!strcmp(element_name, "attribute")) {
543 if (ctx_data->stack_head && ctx_data->stack_head->data) {
544 int ret = sdp_attr_add(ctx_data->record, ctx_data->attr_id,
545 ctx_data->stack_head->data);
547 DBG("Could not add attribute 0x%04x",
550 ctx_data->stack_head->data = NULL;
551 sdp_xml_data_free(ctx_data->stack_head);
552 ctx_data->stack_head = NULL;
554 DBG("No data for attribute 0x%04x", ctx_data->attr_id);
559 if (!ctx_data->stack_head || !ctx_data->stack_head->data) {
560 DBG("No data for %s", element_name);
564 if (!strcmp(element_name, "sequence")) {
565 ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
567 if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
568 ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
569 ctx_data->stack_head->data->dtd = SDP_SEQ32;
570 } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
571 ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
572 ctx_data->stack_head->data->dtd = SDP_SEQ16;
574 ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
576 } else if (!strcmp(element_name, "alternate")) {
577 ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
579 if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
580 ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
581 ctx_data->stack_head->data->dtd = SDP_ALT32;
582 } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
583 ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
584 ctx_data->stack_head->data->dtd = SDP_ALT16;
586 ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
590 if (ctx_data->stack_head->next && ctx_data->stack_head->data &&
591 ctx_data->stack_head->next->data) {
592 switch (ctx_data->stack_head->next->data->dtd) {
599 ctx_data->stack_head->next->data->val.dataseq =
600 sdp_seq_append(ctx_data->stack_head->next->data->val.dataseq,
601 ctx_data->stack_head->data);
602 ctx_data->stack_head->data = NULL;
606 elem = ctx_data->stack_head;
607 ctx_data->stack_head = ctx_data->stack_head->next;
609 sdp_xml_data_free(elem);
613 static GMarkupParser parser = {
614 element_start, element_end, NULL, NULL, NULL
617 sdp_record_t *sdp_xml_parse_record(const char *data, int size)
619 GMarkupParseContext *ctx;
620 struct context_data *ctx_data;
621 sdp_record_t *record;
623 ctx_data = malloc(sizeof(*ctx_data));
627 record = sdp_record_alloc();
633 memset(ctx_data, 0, sizeof(*ctx_data));
634 ctx_data->record = record;
636 ctx = g_markup_parse_context_new(&parser, 0, ctx_data, NULL);
638 if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) {
639 error("XML parsing error");
640 g_markup_parse_context_free(ctx);
641 sdp_record_free(record);
646 g_markup_parse_context_free(ctx);
654 static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
655 void *data, void (*appender)(void *, const char *))
658 char buf[STRBUFSIZE];
659 char indent[MAXINDENT];
664 if (indent_level >= MAXINDENT)
665 indent_level = MAXINDENT - 2;
667 for (i = 0; i < indent_level; i++)
671 buf[STRBUFSIZE - 1] = '\0';
673 switch (value->dtd) {
675 appender(data, indent);
676 appender(data, "<nil/>\n");
680 appender(data, indent);
681 appender(data, "<boolean value=\"");
682 appender(data, value->val.uint8 ? "true" : "false");
683 appender(data, "\" />\n");
687 appender(data, indent);
688 appender(data, "<uint8 value=\"");
689 snprintf(buf, STRBUFSIZE - 1, "0x%02x", value->val.uint8);
691 appender(data, "\" />\n");
695 appender(data, indent);
696 appender(data, "<uint16 value=\"");
697 snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uint16);
699 appender(data, "\" />\n");
703 appender(data, indent);
704 appender(data, "<uint32 value=\"");
705 snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uint32);
707 appender(data, "\" />\n");
711 appender(data, indent);
712 appender(data, "<uint64 value=\"");
713 snprintf(buf, STRBUFSIZE - 1, "0x%016jx", value->val.uint64);
715 appender(data, "\" />\n");
719 appender(data, indent);
720 appender(data, "<uint128 value=\"");
722 for (i = 0; i < 16; i++) {
723 sprintf(&buf[i * 2], "%02x",
724 (unsigned char) value->val.uint128.data[i]);
728 appender(data, "\" />\n");
732 appender(data, indent);
733 appender(data, "<int8 value=\"");
734 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int8);
736 appender(data, "\" />\n");
740 appender(data, indent);
741 appender(data, "<int16 value=\"");
742 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int16);
744 appender(data, "\" />\n");
748 appender(data, indent);
749 appender(data, "<int32 value=\"");
750 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int32);
752 appender(data, "\" />\n");
756 appender(data, indent);
757 appender(data, "<int64 value=\"");
758 snprintf(buf, STRBUFSIZE - 1, "%jd", value->val.int64);
760 appender(data, "\" />\n");
764 appender(data, indent);
765 appender(data, "<int128 value=\"");
767 for (i = 0; i < 16; i++) {
768 sprintf(&buf[i * 2], "%02x",
769 (unsigned char) value->val.int128.data[i]);
773 appender(data, "\" />\n");
777 appender(data, indent);
778 appender(data, "<uuid value=\"");
779 snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uuid.value.uuid16);
781 appender(data, "\" />\n");
785 appender(data, indent);
786 appender(data, "<uuid value=\"");
787 snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uuid.value.uuid32);
789 appender(data, "\" />\n");
793 appender(data, indent);
794 appender(data, "<uuid value=\"");
796 snprintf(buf, STRBUFSIZE - 1,
797 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
798 (unsigned char) value->val.uuid.value.
800 (unsigned char) value->val.uuid.value.
802 (unsigned char) value->val.uuid.value.
804 (unsigned char) value->val.uuid.value.
806 (unsigned char) value->val.uuid.value.
808 (unsigned char) value->val.uuid.value.
810 (unsigned char) value->val.uuid.value.
812 (unsigned char) value->val.uuid.value.
814 (unsigned char) value->val.uuid.value.
816 (unsigned char) value->val.uuid.value.
818 (unsigned char) value->val.uuid.value.
820 (unsigned char) value->val.uuid.value.
822 (unsigned char) value->val.uuid.value.
824 (unsigned char) value->val.uuid.value.
826 (unsigned char) value->val.uuid.value.
828 (unsigned char) value->val.uuid.value.
832 appender(data, "\" />\n");
839 int num_chars_to_escape = 0;
840 int length = value->unitSize - 1;
845 for (i = 0; i < length; i++) {
846 if (!isprint(value->val.str[i]) &&
847 value->val.str[i] != '\0') {
852 /* XML is evil, must do this... */
853 if ((value->val.str[i] == '<') ||
854 (value->val.str[i] == '>') ||
855 (value->val.str[i] == '"') ||
856 (value->val.str[i] == '&'))
857 num_chars_to_escape++;
860 appender(data, indent);
862 appender(data, "<text ");
865 appender(data, "encoding=\"hex\" ");
866 strBuf = malloc(sizeof(char)
867 * ((value->unitSize-1) * 2 + 1));
869 DBG("No memory to convert raw data to xml");
873 /* Unit Size seems to include the size for dtd
875 This is safe for Normal strings, but not
877 for (i = 0; i < (value->unitSize-1); i++)
878 sprintf(&strBuf[i*sizeof(char)*2],
880 (unsigned char) value->val.str[i]);
882 strBuf[(value->unitSize-1) * 2] = '\0';
885 /* escape the XML disallowed chars */
886 strBuf = malloc(sizeof(char) *
887 (value->unitSize + 1 + num_chars_to_escape * 4));
889 DBG("No memory to convert raw data to xml");
892 for (i = 0, j = 0; i < length; i++) {
893 if (value->val.str[i] == '&') {
898 } else if (value->val.str[i] == '<') {
902 } else if (value->val.str[i] == '>') {
906 } else if (value->val.str[i] == '"') {
912 } else if (value->val.str[i] == '\0') {
915 strBuf[j++] = value->val.str[i];
922 appender(data, "value=\"");
923 appender(data, strBuf);
924 appender(data, "\" />\n");
935 appender(data, indent);
936 appender(data, "<url value=\"");
937 strBuf = strndup(value->val.str, value->unitSize - 1);
938 appender(data, strBuf);
940 appender(data, "\" />\n");
947 appender(data, indent);
948 appender(data, "<sequence>\n");
950 convert_raw_data_to_xml(value->val.dataseq,
951 indent_level + 1, data, appender);
953 appender(data, indent);
954 appender(data, "</sequence>\n");
961 appender(data, indent);
963 appender(data, "<alternate>\n");
965 convert_raw_data_to_xml(value->val.dataseq,
966 indent_level + 1, data, appender);
967 appender(data, indent);
969 appender(data, "</alternate>\n");
974 convert_raw_data_to_xml(value->next, indent_level, data, appender);
977 struct conversion_data {
979 void (*appender)(void *data, const char *);
982 static void convert_raw_attr_to_xml_func(void *val, void *data)
984 struct conversion_data *cd = data;
985 sdp_data_t *value = val;
986 char buf[STRBUFSIZE];
988 buf[STRBUFSIZE - 1] = '\0';
989 snprintf(buf, STRBUFSIZE - 1, "\t<attribute id=\"0x%04x\">\n",
991 cd->appender(cd->data, buf);
993 convert_raw_data_to_xml(value, 2, cd->data, cd->appender);
995 cd->appender(cd->data, "\t</attribute>\n");
999 * Will convert the sdp record to XML. The appender and data can be used
1000 * to control where to output the record (e.g. file or a data buffer). The
1001 * appender will be called repeatedly with data and the character buffer
1002 * (containing parts of the generated XML) to append.
1004 void convert_sdp_record_to_xml(sdp_record_t *rec,
1005 void *data, void (*appender)(void *, const char *))
1007 struct conversion_data cd;
1010 cd.appender = appender;
1012 if (rec && rec->attrlist) {
1013 appender(data, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n");
1014 appender(data, "<record>\n");
1015 sdp_list_foreach(rec->attrlist,
1016 convert_raw_attr_to_xml_func, &cd);
1017 appender(data, "</record>\n");