Fix Crash issue
[platform/upstream/bluez.git] / src / sdp-xml.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *
4  *  BlueZ - Bluetooth protocol stack for Linux
5  *
6  *  Copyright (C) 2005-2010  Marcel Holtmann <marcel@holtmann.org>
7  *
8  *
9  */
10
11 #ifdef HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #include <stdio.h>
16 #include <errno.h>
17 #include <ctype.h>
18 #include <string.h>
19 #include <limits.h>
20 #include <stdlib.h>
21
22 #include <glib.h>
23
24 #include "lib/sdp.h"
25 #include "lib/sdp_lib.h"
26
27 #include "sdp-xml.h"
28
29 #define DBG(...) (void)(0)
30 #define error(...) (void)(0)
31
32 #define SDP_XML_ENCODING_NORMAL 0
33 #define SDP_XML_ENCODING_HEX    1
34
35 #define STRBUFSIZE 1024
36 #define MAXINDENT 64
37
38 struct sdp_xml_data {
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? */
46 };
47
48 struct context_data {
49         sdp_record_t *record;
50         sdp_data_t attr_data;
51         struct sdp_xml_data *stack_head;
52         uint16_t attr_id;
53 };
54
55 static int compute_seq_size(sdp_data_t *data)
56 {
57         int unit_size = data->unitSize;
58         sdp_data_t *seq = data->val.dataseq;
59
60         for (; seq; seq = seq->next)
61                 unit_size += seq->unitSize;
62
63         return unit_size;
64 }
65
66 #define DEFAULT_XML_DATA_SIZE 1024
67
68 static struct sdp_xml_data *sdp_xml_data_alloc(void)
69 {
70         struct sdp_xml_data *elem;
71
72         elem = malloc(sizeof(struct sdp_xml_data));
73         if (!elem)
74                 return NULL;
75
76         memset(elem, 0, sizeof(struct sdp_xml_data));
77
78         /* Null terminate the text */
79         elem->size = DEFAULT_XML_DATA_SIZE;
80         elem->text = malloc(DEFAULT_XML_DATA_SIZE);
81         if (!elem->text) {
82                 free(elem);
83                 return NULL;
84         }
85         elem->text[0] = '\0';
86
87         return elem;
88 }
89
90 static struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem)
91 {
92         char *newbuf;
93
94         newbuf = malloc(elem->size * 2);
95         if (!newbuf)
96                 return NULL;
97
98         memcpy(newbuf, elem->text, elem->size);
99         elem->size *= 2;
100         free(elem->text);
101
102         elem->text = newbuf;
103
104         return elem;
105 }
106
107 static sdp_data_t *sdp_xml_parse_uuid128(const char *data)
108 {
109         uint128_t val;
110         unsigned int i, j;
111
112         char buf[3];
113
114         memset(&val, 0, sizeof(val));
115
116         buf[2] = '\0';
117
118         for (j = 0, i = 0; i < strlen(data);) {
119                 if (data[i] == '-') {
120                         i++;
121                         continue;
122                 }
123
124                 buf[0] = data[i];
125                 buf[1] = data[i + 1];
126
127                 val.data[j++] = strtoul(buf, 0, 16);
128                 i += 2;
129         }
130
131         return sdp_data_alloc(SDP_UUID128, &val);
132 }
133
134 static sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record)
135 {
136         sdp_data_t *ret;
137         char *endptr;
138         uint32_t val;
139         uint16_t val2;
140         int len;
141
142         len = strlen(data);
143
144         if (len == 36) {
145                 ret = sdp_xml_parse_uuid128(data);
146                 goto result;
147         }
148
149         val = strtoll(data, &endptr, 16);
150
151         /* Couldn't parse */
152         if (*endptr != '\0')
153                 return NULL;
154
155         if (val > USHRT_MAX) {
156                 ret = sdp_data_alloc(SDP_UUID32, &val);
157                 goto result;
158         }
159
160         val2 = val;
161
162         ret = sdp_data_alloc(SDP_UUID16, &val2);
163
164 result:
165         if (record && ret)
166                 sdp_pattern_add_uuid(record, &ret->val.uuid);
167
168         return ret;
169 }
170
171 static sdp_data_t *sdp_xml_parse_int(const char *data, uint8_t dtd)
172 {
173         char *endptr;
174         sdp_data_t *ret = NULL;
175
176         switch (dtd) {
177         case SDP_BOOL:
178         {
179                 uint8_t val = 0;
180
181                 if (!strcmp("true", data))
182                         val = 1;
183                 else if (!strcmp("false", data))
184                         val = 0;
185                 else
186                         return NULL;
187
188                 ret = sdp_data_alloc(dtd, &val);
189                 break;
190         }
191
192         case SDP_INT8:
193         {
194                 int8_t val = strtoul(data, &endptr, 0);
195
196                 /* Failed to parse */
197                 if ((endptr != data) && (*endptr != '\0'))
198                         return NULL;
199
200                 ret = sdp_data_alloc(dtd, &val);
201                 break;
202         }
203
204         case SDP_UINT8:
205         {
206                 uint8_t val = strtoul(data, &endptr, 0);
207
208                 /* Failed to parse */
209                 if ((endptr != data) && (*endptr != '\0'))
210                         return NULL;
211
212                 ret = sdp_data_alloc(dtd, &val);
213                 break;
214         }
215
216         case SDP_INT16:
217         {
218                 int16_t val = strtoul(data, &endptr, 0);
219
220                 /* Failed to parse */
221                 if ((endptr != data) && (*endptr != '\0'))
222                         return NULL;
223
224                 ret = sdp_data_alloc(dtd, &val);
225                 break;
226         }
227
228         case SDP_UINT16:
229         {
230                 uint16_t val = strtoul(data, &endptr, 0);
231
232                 /* Failed to parse */
233                 if ((endptr != data) && (*endptr != '\0'))
234                         return NULL;
235
236                 ret = sdp_data_alloc(dtd, &val);
237                 break;
238         }
239
240         case SDP_INT32:
241         {
242                 int32_t val = strtoul(data, &endptr, 0);
243
244                 /* Failed to parse */
245                 if ((endptr != data) && (*endptr != '\0'))
246                         return NULL;
247
248                 ret = sdp_data_alloc(dtd, &val);
249                 break;
250         }
251
252         case SDP_UINT32:
253         {
254                 uint32_t val = strtoul(data, &endptr, 0);
255
256                 /* Failed to parse */
257                 if ((endptr != data) && (*endptr != '\0'))
258                         return NULL;
259
260                 ret = sdp_data_alloc(dtd, &val);
261                 break;
262         }
263
264         case SDP_INT64:
265         {
266                 int64_t val = strtoull(data, &endptr, 0);
267
268                 /* Failed to parse */
269                 if ((endptr != data) && (*endptr != '\0'))
270                         return NULL;
271
272                 ret = sdp_data_alloc(dtd, &val);
273                 break;
274         }
275
276         case SDP_UINT64:
277         {
278                 uint64_t val = strtoull(data, &endptr, 0);
279
280                 /* Failed to parse */
281                 if ((endptr != data) && (*endptr != '\0'))
282                         return NULL;
283
284                 ret = sdp_data_alloc(dtd, &val);
285                 break;
286         }
287
288         case SDP_INT128:
289         case SDP_UINT128:
290         {
291                 uint128_t val;
292                 int i = 0;
293                 char buf[3];
294
295                 buf[2] = '\0';
296
297                 for (; i < 32; i += 2) {
298                         buf[0] = data[i];
299                         buf[1] = data[i + 1];
300
301                         val.data[i >> 1] = strtoul(buf, 0, 16);
302                 }
303
304                 ret = sdp_data_alloc(dtd, &val);
305                 break;
306         }
307
308         };
309
310         return ret;
311 }
312
313 static char *sdp_xml_parse_string_decode(const char *data, char encoding,
314                                                         uint32_t *length)
315 {
316         int len = strlen(data);
317         char *text;
318
319         if (encoding == SDP_XML_ENCODING_NORMAL) {
320                 text = strdup(data);
321                 *length = len;
322         } else {
323                 char buf[3], *decoded;
324                 int i;
325
326                 decoded = malloc((len >> 1) + 1);
327                 if (!decoded)
328                         return NULL;
329
330                 /* Ensure the string is a power of 2 */
331                 len = (len >> 1) << 1;
332
333                 buf[2] = '\0';
334
335                 for (i = 0; i < len; i += 2) {
336                         buf[0] = data[i];
337                         buf[1] = data[i + 1];
338
339                         decoded[i >> 1] = strtoul(buf, 0, 16);
340                 }
341
342                 decoded[len >> 1] = '\0';
343                 text = decoded;
344                 *length = len >> 1;
345         }
346
347         return text;
348 }
349
350 static sdp_data_t *sdp_xml_parse_url(const char *data)
351 {
352         uint8_t dtd = SDP_URL_STR8;
353         char *url;
354         uint32_t length;
355         sdp_data_t *ret;
356
357         url = sdp_xml_parse_string_decode(data,
358                                 SDP_XML_ENCODING_NORMAL, &length);
359         if (!url)
360                 return NULL;
361
362         if (length > UCHAR_MAX)
363                 dtd = SDP_URL_STR16;
364
365         ret = sdp_data_alloc_with_length(dtd, url, length);
366
367         free(url);
368
369         return ret;
370 }
371
372 static sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
373 {
374         uint8_t dtd = SDP_TEXT_STR8;
375         char *text;
376         uint32_t length;
377         sdp_data_t *ret;
378
379         text = sdp_xml_parse_string_decode(data, encoding, &length);
380         if (!text)
381                 return NULL;
382
383         if (length > UCHAR_MAX)
384                 dtd = SDP_TEXT_STR16;
385
386         ret = sdp_data_alloc_with_length(dtd, text, length);
387
388         free(text);
389
390         return ret;
391 }
392
393 static sdp_data_t *sdp_xml_parse_nil(const char *data)
394 {
395         return sdp_data_alloc(SDP_DATA_NIL, 0);
396 }
397
398 static sdp_data_t *sdp_xml_parse_datatype(const char *el,
399                                                 struct sdp_xml_data *elem,
400                                                 sdp_record_t *record)
401 {
402         const char *data = elem->text;
403
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);
434
435         return NULL;
436 }
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)
440 {
441         struct context_data *ctx_data = user_data;
442
443         if (!strcmp(element_name, "record"))
444                 return;
445
446         if (!strcmp(element_name, "attribute")) {
447                 int i;
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);
451                                 break;
452                         }
453                 }
454                 DBG("New attribute 0x%04x", ctx_data->attr_id);
455                 return;
456         }
457
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;
462         } else {
463                 ctx_data->stack_head = sdp_xml_data_alloc();
464                 ctx_data->stack_head->next = NULL;
465         }
466
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);
471         else {
472                 int i;
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]);
478
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);
482
483                                 memcpy(ctx_data->stack_head->text + curlen,
484                                                 attribute_values[i], attrlen);
485                                 ctx_data->stack_head->text[curlen + attrlen] = '\0';
486                         }
487
488                         if (!strcmp(attribute_names[i], "encoding")) {
489                                 if (!strcmp(attribute_values[i], "hex"))
490                                         ctx_data->stack_head->type = 1;
491                         }
492
493                         if (!strcmp(attribute_names[i], "name"))
494                                 ctx_data->stack_head->name = strdup(attribute_values[i]);
495                 }
496
497                 ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name,
498                                 ctx_data->stack_head, ctx_data->record);
499
500                 if (ctx_data->stack_head->data == NULL)
501                         error("Can't parse element %s", element_name);
502         }
503 }
504
505 static void sdp_xml_data_free(struct sdp_xml_data *elem)
506 {
507         if (elem->data)
508                 sdp_data_free(elem->data);
509
510         free(elem->name);
511         free(elem->text);
512         free(elem);
513 }
514
515 static void element_end(GMarkupParseContext *context,
516                 const char *element_name, gpointer user_data, GError **err)
517 {
518         struct context_data *ctx_data = user_data;
519         struct sdp_xml_data *elem;
520
521 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
522         if (element_name == NULL)
523                 return;
524 #endif
525
526         if (!strcmp(element_name, "record"))
527                 return;
528
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);
533                         if (ret == -1)
534                                 DBG("Could not add attribute 0x%04x",
535                                                         ctx_data->attr_id);
536
537                         ctx_data->stack_head->data = NULL;
538                         sdp_xml_data_free(ctx_data->stack_head);
539                         ctx_data->stack_head = NULL;
540                 } else {
541                         DBG("No data for attribute 0x%04x", ctx_data->attr_id);
542                 }
543                 return;
544         }
545
546         if (!ctx_data->stack_head || !ctx_data->stack_head->data) {
547                 DBG("No data for %s", element_name);
548                 return;
549         }
550
551         if (!strcmp(element_name, "sequence")) {
552                 ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
553
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;
560                 } else {
561                         ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
562                 }
563         } else if (!strcmp(element_name, "alternate")) {
564                 ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
565
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;
572                 } else {
573                         ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
574                 }
575         }
576
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) {
580                 case SDP_SEQ8:
581                 case SDP_SEQ16:
582                 case SDP_SEQ32:
583                 case SDP_ALT8:
584                 case SDP_ALT16:
585                 case SDP_ALT32:
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;
590                         break;
591                 }
592
593                 elem = ctx_data->stack_head;
594                 ctx_data->stack_head = ctx_data->stack_head->next;
595
596                 sdp_xml_data_free(elem);
597         }
598 }
599
600 static GMarkupParser parser = {
601         element_start, element_end, NULL, NULL, NULL
602 };
603
604 sdp_record_t *sdp_xml_parse_record(const char *data, int size)
605 {
606         GMarkupParseContext *ctx;
607         struct context_data *ctx_data;
608         sdp_record_t *record;
609
610         ctx_data = malloc(sizeof(*ctx_data));
611         if (!ctx_data)
612                 return NULL;
613
614         record = sdp_record_alloc();
615         if (!record) {
616                 free(ctx_data);
617                 return NULL;
618         }
619
620         memset(ctx_data, 0, sizeof(*ctx_data));
621         ctx_data->record = record;
622
623         ctx = g_markup_parse_context_new(&parser, 0, ctx_data, NULL);
624
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);
629                 free(ctx_data);
630                 return NULL;
631         }
632
633         g_markup_parse_context_free(ctx);
634
635         free(ctx_data);
636
637         return record;
638 }
639
640
641 static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
642                 void *data, void (*appender)(void *, const char *))
643 {
644         int i, hex;
645         char buf[STRBUFSIZE];
646         char indent[MAXINDENT];
647
648         if (!value)
649                 return;
650
651         if (indent_level >= MAXINDENT)
652                 indent_level = MAXINDENT - 2;
653
654         for (i = 0; i < indent_level; i++)
655                 indent[i] = '\t';
656
657         indent[i] = '\0';
658         buf[STRBUFSIZE - 1] = '\0';
659
660         switch (value->dtd) {
661         case SDP_DATA_NIL:
662                 appender(data, indent);
663                 appender(data, "<nil/>\n");
664                 break;
665
666         case SDP_BOOL:
667                 appender(data, indent);
668                 appender(data, "<boolean value=\"");
669                 appender(data, value->val.uint8 ? "true" : "false");
670                 appender(data, "\" />\n");
671                 break;
672
673         case SDP_UINT8:
674                 appender(data, indent);
675                 appender(data, "<uint8 value=\"");
676                 snprintf(buf, STRBUFSIZE - 1, "0x%02x", value->val.uint8);
677                 appender(data, buf);
678                 appender(data, "\" />\n");
679                 break;
680
681         case SDP_UINT16:
682                 appender(data, indent);
683                 appender(data, "<uint16 value=\"");
684                 snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uint16);
685                 appender(data, buf);
686                 appender(data, "\" />\n");
687                 break;
688
689         case SDP_UINT32:
690                 appender(data, indent);
691                 appender(data, "<uint32 value=\"");
692                 snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uint32);
693                 appender(data, buf);
694                 appender(data, "\" />\n");
695                 break;
696
697         case SDP_UINT64:
698                 appender(data, indent);
699                 appender(data, "<uint64 value=\"");
700                 snprintf(buf, STRBUFSIZE - 1, "0x%016jx", value->val.uint64);
701                 appender(data, buf);
702                 appender(data, "\" />\n");
703                 break;
704
705         case SDP_UINT128:
706                 appender(data, indent);
707                 appender(data, "<uint128 value=\"");
708
709                 for (i = 0; i < 16; i++) {
710                         sprintf(&buf[i * 2], "%02x",
711                                 (unsigned char) value->val.uint128.data[i]);
712                 }
713
714                 appender(data, buf);
715                 appender(data, "\" />\n");
716                 break;
717
718         case SDP_INT8:
719                 appender(data, indent);
720                 appender(data, "<int8 value=\"");
721                 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int8);
722                 appender(data, buf);
723                 appender(data, "\" />\n");
724                 break;
725
726         case SDP_INT16:
727                 appender(data, indent);
728                 appender(data, "<int16 value=\"");
729                 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int16);
730                 appender(data, buf);
731                 appender(data, "\" />\n");
732                 break;
733
734         case SDP_INT32:
735                 appender(data, indent);
736                 appender(data, "<int32 value=\"");
737                 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int32);
738                 appender(data, buf);
739                 appender(data, "\" />\n");
740                 break;
741
742         case SDP_INT64:
743                 appender(data, indent);
744                 appender(data, "<int64 value=\"");
745                 snprintf(buf, STRBUFSIZE - 1, "%jd", value->val.int64);
746                 appender(data, buf);
747                 appender(data, "\" />\n");
748                 break;
749
750         case SDP_INT128:
751                 appender(data, indent);
752                 appender(data, "<int128 value=\"");
753
754                 for (i = 0; i < 16; i++) {
755                         sprintf(&buf[i * 2], "%02x",
756                                 (unsigned char) value->val.int128.data[i]);
757                 }
758                 appender(data, buf);
759
760                 appender(data, "\" />\n");
761                 break;
762
763         case SDP_UUID16:
764                 appender(data, indent);
765                 appender(data, "<uuid value=\"");
766                 snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uuid.value.uuid16);
767                 appender(data, buf);
768                 appender(data, "\" />\n");
769                 break;
770
771         case SDP_UUID32:
772                 appender(data, indent);
773                 appender(data, "<uuid value=\"");
774                 snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uuid.value.uuid32);
775                 appender(data, buf);
776                 appender(data, "\" />\n");
777                 break;
778
779         case SDP_UUID128:
780                 appender(data, indent);
781                 appender(data, "<uuid value=\"");
782
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.
786                          uuid128.data[0],
787                          (unsigned char) value->val.uuid.value.
788                          uuid128.data[1],
789                          (unsigned char) value->val.uuid.value.
790                          uuid128.data[2],
791                          (unsigned char) value->val.uuid.value.
792                          uuid128.data[3],
793                          (unsigned char) value->val.uuid.value.
794                          uuid128.data[4],
795                          (unsigned char) value->val.uuid.value.
796                          uuid128.data[5],
797                          (unsigned char) value->val.uuid.value.
798                          uuid128.data[6],
799                          (unsigned char) value->val.uuid.value.
800                          uuid128.data[7],
801                          (unsigned char) value->val.uuid.value.
802                          uuid128.data[8],
803                          (unsigned char) value->val.uuid.value.
804                          uuid128.data[9],
805                          (unsigned char) value->val.uuid.value.
806                          uuid128.data[10],
807                          (unsigned char) value->val.uuid.value.
808                          uuid128.data[11],
809                          (unsigned char) value->val.uuid.value.
810                          uuid128.data[12],
811                          (unsigned char) value->val.uuid.value.
812                          uuid128.data[13],
813                          (unsigned char) value->val.uuid.value.
814                          uuid128.data[14],
815                          (unsigned char) value->val.uuid.value.
816                          uuid128.data[15]);
817
818                 appender(data, buf);
819                 appender(data, "\" />\n");
820                 break;
821
822         case SDP_TEXT_STR8:
823         case SDP_TEXT_STR16:
824         case SDP_TEXT_STR32:
825         {
826                 int num_chars_to_escape = 0;
827                 int length = value->unitSize - 1;
828                 char *strBuf;
829
830                 hex = 0;
831
832                 for (i = 0; i < length; i++) {
833                         if (!isprint(value->val.str[i]) &&
834                                         value->val.str[i] != '\0') {
835                                 hex = 1;
836                                 break;
837                         }
838
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++;
845                 }
846
847                 appender(data, indent);
848
849                 appender(data, "<text ");
850
851                 if (hex) {
852                         appender(data, "encoding=\"hex\" ");
853                         strBuf = malloc(sizeof(char)
854                                                  * ((value->unitSize-1) * 2 + 1));
855                         if (!strBuf) {
856                                 DBG("No memory to convert raw data to xml");
857                                 return;
858                         }
859
860                         /* Unit Size seems to include the size for dtd
861                            It is thus off by 1
862                            This is safe for Normal strings, but not
863                            hex encoded data */
864                         for (i = 0; i < (value->unitSize-1); i++)
865                                 sprintf(&strBuf[i*sizeof(char)*2],
866                                         "%02x",
867                                         (unsigned char) value->val.str[i]);
868
869                         strBuf[(value->unitSize-1) * 2] = '\0';
870                 } else {
871                         int j;
872                         /* escape the XML disallowed chars */
873                         strBuf = malloc(sizeof(char) *
874                                         (value->unitSize + 1 + num_chars_to_escape * 4));
875                         if (!strBuf) {
876                                 DBG("No memory to convert raw data to xml");
877                                 return;
878                         }
879                         for (i = 0, j = 0; i < length; i++) {
880                                 if (value->val.str[i] == '&') {
881                                         strBuf[j++] = '&';
882                                         strBuf[j++] = 'a';
883                                         strBuf[j++] = 'm';
884                                         strBuf[j++] = 'p';
885                                 } else if (value->val.str[i] == '<') {
886                                         strBuf[j++] = '&';
887                                         strBuf[j++] = 'l';
888                                         strBuf[j++] = 't';
889                                 } else if (value->val.str[i] == '>') {
890                                         strBuf[j++] = '&';
891                                         strBuf[j++] = 'g';
892                                         strBuf[j++] = 't';
893                                 } else if (value->val.str[i] == '"') {
894                                         strBuf[j++] = '&';
895                                         strBuf[j++] = 'q';
896                                         strBuf[j++] = 'u';
897                                         strBuf[j++] = 'o';
898                                         strBuf[j++] = 't';
899                                 } else if (value->val.str[i] == '\0') {
900                                         strBuf[j++] = ' ';
901                                 } else {
902                                         strBuf[j++] = value->val.str[i];
903                                 }
904                         }
905
906                         strBuf[j] = '\0';
907                 }
908
909                 appender(data, "value=\"");
910                 appender(data, strBuf);
911                 appender(data, "\" />\n");
912                 free(strBuf);
913                 break;
914         }
915
916         case SDP_URL_STR8:
917         case SDP_URL_STR16:
918         case SDP_URL_STR32:
919         {
920                 char *strBuf;
921
922                 appender(data, indent);
923                 appender(data, "<url value=\"");
924                 strBuf = strndup(value->val.str, value->unitSize - 1);
925                 appender(data, strBuf);
926                 free(strBuf);
927                 appender(data, "\" />\n");
928                 break;
929         }
930
931         case SDP_SEQ8:
932         case SDP_SEQ16:
933         case SDP_SEQ32:
934                 appender(data, indent);
935                 appender(data, "<sequence>\n");
936
937                 convert_raw_data_to_xml(value->val.dataseq,
938                                         indent_level + 1, data, appender);
939
940                 appender(data, indent);
941                 appender(data, "</sequence>\n");
942
943                 break;
944
945         case SDP_ALT8:
946         case SDP_ALT16:
947         case SDP_ALT32:
948                 appender(data, indent);
949
950                 appender(data, "<alternate>\n");
951
952                 convert_raw_data_to_xml(value->val.dataseq,
953                                         indent_level + 1, data, appender);
954                 appender(data, indent);
955
956                 appender(data, "</alternate>\n");
957
958                 break;
959         }
960
961         convert_raw_data_to_xml(value->next, indent_level, data, appender);
962 }
963
964 struct conversion_data {
965         void *data;
966         void (*appender)(void *data, const char *);
967 };
968
969 static void convert_raw_attr_to_xml_func(void *val, void *data)
970 {
971         struct conversion_data *cd = data;
972         sdp_data_t *value = val;
973         char buf[STRBUFSIZE];
974
975         buf[STRBUFSIZE - 1] = '\0';
976         snprintf(buf, STRBUFSIZE - 1, "\t<attribute id=\"0x%04x\">\n",
977                  value->attrId);
978         cd->appender(cd->data, buf);
979
980         convert_raw_data_to_xml(value, 2, cd->data, cd->appender);
981
982         cd->appender(cd->data, "\t</attribute>\n");
983 }
984
985 /*
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.
990  */
991 void convert_sdp_record_to_xml(sdp_record_t *rec,
992                         void *data, void (*appender)(void *, const char *))
993 {
994         struct conversion_data cd;
995
996         cd.data = data;
997         cd.appender = appender;
998
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");
1005         }
1006 }