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