OSDN Git Service

Don't enable the SCO server socket when not necessary
[android-x86/external-bluetooth-bluez.git] / common / sdp-xml.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2005-2009  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 #define _GNU_SOURCE
29 #include <stdio.h>
30 #include <errno.h>
31 #include <ctype.h>
32 #include <string.h>
33 #include <limits.h>
34 #include <stdlib.h>
35
36 #include <bluetooth/sdp.h>
37 #include <bluetooth/sdp_lib.h>
38
39 #include "logging.h"
40 #include "sdp-xml.h"
41
42 #define STRBUFSIZE 1024
43 #define MAXINDENT 64
44
45 static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
46                 void *data, void (*appender)(void *, const char *))
47 {
48         int i, hex;
49         char buf[STRBUFSIZE];
50         char indent[MAXINDENT];
51         char next_indent[MAXINDENT];
52
53         if (!value)
54                 return;
55
56         if (indent_level >= MAXINDENT)
57                 indent_level = MAXINDENT - 2;
58
59         for (i = 0; i < indent_level; i++) {
60                 indent[i] = '\t';
61                 next_indent[i] = '\t';
62         }
63
64         indent[i] = '\0';
65         next_indent[i] = '\t';
66         next_indent[i + 1] = '\0';
67
68         buf[STRBUFSIZE - 1] = '\0';
69
70         switch (value->dtd) {
71         case SDP_DATA_NIL:
72                 appender(data, indent);
73                 appender(data, "<nil/>\n");
74                 break;
75
76         case SDP_BOOL:
77                 appender(data, indent);
78                 appender(data, "<boolean value=\"");
79                 appender(data, value->val.uint8 ? "true" : "false");
80                 appender(data, "\" />\n");
81                 break;
82
83         case SDP_UINT8:
84                 appender(data, indent);
85                 appender(data, "<uint8 value=\"");
86                 snprintf(buf, STRBUFSIZE - 1, "0x%02x", value->val.uint8);
87                 appender(data, buf);
88                 appender(data, "\" />\n");
89                 break;
90
91         case SDP_UINT16:
92                 appender(data, indent);
93                 appender(data, "<uint16 value=\"");
94                 snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uint16);
95                 appender(data, buf);
96                 appender(data, "\" />\n");
97                 break;
98
99         case SDP_UINT32:
100                 appender(data, indent);
101                 appender(data, "<uint32 value=\"");
102                 snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uint32);
103                 appender(data, buf);
104                 appender(data, "\" />\n");
105                 break;
106
107         case SDP_UINT64:
108                 appender(data, indent);
109                 appender(data, "<uint64 value=\"");
110                 snprintf(buf, STRBUFSIZE - 1, "0x%016jx", value->val.uint64);
111                 appender(data, buf);
112                 appender(data, "\" />\n");
113                 break;
114
115         case SDP_UINT128:
116                 appender(data, indent);
117                 appender(data, "<uint128 value=\"");
118
119                 for (i = 0; i < 16; i++) {
120                         sprintf(&buf[i * 2], "%02x",
121                                 (unsigned char) value->val.uint128.data[i]);
122                 }
123
124                 appender(data, buf);
125                 appender(data, "\" />\n");
126                 break;
127
128         case SDP_INT8:
129                 appender(data, indent);
130                 appender(data, "<int8 value=\"");
131                 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int8);
132                 appender(data, buf);
133                 appender(data, "\" />\n");
134                 break;
135
136         case SDP_INT16:
137                 appender(data, indent);
138                 appender(data, "<int16 value=\"");
139                 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int16);
140                 appender(data, buf);
141                 appender(data, "\" />\n");
142                 break;
143
144         case SDP_INT32:
145                 appender(data, indent);
146                 appender(data, "<int32 value=\"");
147                 snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int32);
148                 appender(data, buf);
149                 appender(data, "\" />\n");
150                 break;
151
152         case SDP_INT64:
153                 appender(data, indent);
154                 appender(data, "<int64 value=\"");
155                 snprintf(buf, STRBUFSIZE - 1, "%jd", value->val.int64);
156                 appender(data, buf);
157                 appender(data, "\" />\n");
158                 break;
159
160         case SDP_INT128:
161                 appender(data, indent);
162                 appender(data, "<int128 value=\"");
163
164                 for (i = 0; i < 16; i++) {
165                         sprintf(&buf[i * 2], "%02x",
166                                 (unsigned char) value->val.int128.data[i]);
167                 }
168                 appender(data, buf);
169
170                 appender(data, "\" />\n");
171                 break;
172
173         case SDP_UUID16:
174                 appender(data, indent);
175                 appender(data, "<uuid value=\"");
176                 snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uuid.value.uuid16);
177                 appender(data, buf);
178                 appender(data, "\" />\n");
179                 break;
180
181         case SDP_UUID32:
182                 appender(data, indent);
183                 appender(data, "<uuid value=\"");
184                 snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uuid.value.uuid32);
185                 appender(data, buf);
186                 appender(data, "\" />\n");
187                 break;
188
189         case SDP_UUID128:
190                 appender(data, indent);
191                 appender(data, "<uuid value=\"");
192
193                 snprintf(buf, STRBUFSIZE - 1,
194                          "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
195                          (unsigned char) value->val.uuid.value.
196                          uuid128.data[0],
197                          (unsigned char) value->val.uuid.value.
198                          uuid128.data[1],
199                          (unsigned char) value->val.uuid.value.
200                          uuid128.data[2],
201                          (unsigned char) value->val.uuid.value.
202                          uuid128.data[3],
203                          (unsigned char) value->val.uuid.value.
204                          uuid128.data[4],
205                          (unsigned char) value->val.uuid.value.
206                          uuid128.data[5],
207                          (unsigned char) value->val.uuid.value.
208                          uuid128.data[6],
209                          (unsigned char) value->val.uuid.value.
210                          uuid128.data[7],
211                          (unsigned char) value->val.uuid.value.
212                          uuid128.data[8],
213                          (unsigned char) value->val.uuid.value.
214                          uuid128.data[9],
215                          (unsigned char) value->val.uuid.value.
216                          uuid128.data[10],
217                          (unsigned char) value->val.uuid.value.
218                          uuid128.data[11],
219                          (unsigned char) value->val.uuid.value.
220                          uuid128.data[12],
221                          (unsigned char) value->val.uuid.value.
222                          uuid128.data[13],
223                          (unsigned char) value->val.uuid.value.
224                          uuid128.data[14],
225                          (unsigned char) value->val.uuid.value.
226                          uuid128.data[15]);
227
228                 appender(data, buf);
229                 appender(data, "\" />\n");
230                 break;
231
232         case SDP_TEXT_STR8:
233         case SDP_TEXT_STR16:
234         case SDP_TEXT_STR32:
235         {
236                 int num_chars_to_escape = 0;
237                 int length = value->unitSize - 1;
238                 char *strBuf = 0;
239
240                 hex = 0;
241
242                 for (i = 0; i < length; i++) {
243                         if (!isprint(value->val.str[i]) &&
244                                         value->val.str[i] != '\0') {
245                                 hex = 1;
246                                 break;
247                         }
248
249                         /* XML is evil, must do this... */
250                         if ((value->val.str[i] == '<') ||
251                                         (value->val.str[i] == '>') ||
252                                         (value->val.str[i] == '"') ||
253                                         (value->val.str[i] == '&'))
254                                 num_chars_to_escape++;
255                 }
256
257                 appender(data, indent);
258
259                 appender(data, "<text ");
260
261                 if (hex) {
262                         appender(data, "encoding=\"hex\" ");
263                         strBuf = (char *) malloc(sizeof(char)
264                                                  * ((value->unitSize-1) * 2 + 1));
265
266                         /* Unit Size seems to include the size for dtd
267                            It is thus off by 1
268                            This is safe for Normal strings, but not
269                            hex encoded data */
270                         for (i = 0; i < (value->unitSize-1); i++)
271                                 sprintf(&strBuf[i*sizeof(char)*2],
272                                         "%02x",
273                                         (unsigned char) value->val.str[i]);
274
275                         strBuf[(value->unitSize-1) * 2] = '\0';
276                 }
277                 else {
278                         int j;
279                         /* escape the XML disallowed chars */
280                         strBuf = (char *)
281                                 malloc(sizeof(char) *
282                                 (value->unitSize + 1 + num_chars_to_escape * 4));
283                         for (i = 0, j = 0; i < length; i++) {
284                                 if (value->val.str[i] == '&') {
285                                         strBuf[j++] = '&';
286                                         strBuf[j++] = 'a';
287                                         strBuf[j++] = 'm';
288                                         strBuf[j++] = 'p';
289                                 }
290                                 else if (value->val.str[i] == '<') {
291                                         strBuf[j++] = '&';
292                                         strBuf[j++] = 'l';
293                                         strBuf[j++] = 't';
294                                 }
295                                 else if (value->val.str[i] == '>') {
296                                         strBuf[j++] = '&';
297                                         strBuf[j++] = 'g';
298                                         strBuf[j++] = 't';
299                                 }
300                                 else if (value->val.str[i] == '"') {
301                                         strBuf[j++] = '&';
302                                         strBuf[j++] = 'q';
303                                         strBuf[j++] = 'u';
304                                         strBuf[j++] = 'o';
305                                         strBuf[j++] = 't';
306                                 }
307                                 else if (value->val.str[i] == '\0') {
308                                         strBuf[j++] = ' ';
309                                 } else {
310                                         strBuf[j++] = value->val.str[i];
311                                 }
312                         }
313
314                         strBuf[j] = '\0';
315                 }
316
317                 appender(data, "value=\"");
318                 appender(data, strBuf);
319                 appender(data, "\" />\n");
320                 free(strBuf);
321                 break;
322         }
323
324         case SDP_URL_STR8:
325         case SDP_URL_STR16:
326         case SDP_URL_STR32:
327         {
328                 char *strBuf;
329
330                 appender(data, indent);
331                 appender(data, "<url value=\"");
332                 strBuf = strndup(value->val.str, value->unitSize - 1);
333                 appender(data, strBuf);
334                 free(strBuf);
335                 appender(data, "\" />\n");
336                 break;
337         }
338
339         case SDP_SEQ8:
340         case SDP_SEQ16:
341         case SDP_SEQ32:
342                 appender(data, indent);
343                 appender(data, "<sequence>\n");
344
345                 convert_raw_data_to_xml(value->val.dataseq,
346                                         indent_level + 1, data, appender);
347
348                 appender(data, indent);
349                 appender(data, "</sequence>\n");
350
351                 break;
352
353         case SDP_ALT8:
354         case SDP_ALT16:
355         case SDP_ALT32:
356                 appender(data, indent);
357
358                 appender(data, "<alternate>\n");
359
360                 convert_raw_data_to_xml(value->val.dataseq,
361                                         indent_level + 1, data, appender);
362                 appender(data, indent);
363
364                 appender(data, "</alternate>\n");
365
366                 break;
367         }
368
369         convert_raw_data_to_xml(value->next, indent_level, data, appender);
370 }
371
372 struct conversion_data {
373         void *data;
374         void (*appender)(void *data, const char *);
375 };
376
377 static void convert_raw_attr_to_xml_func(void *val, void *data)
378 {
379         struct conversion_data *cd = (struct conversion_data *) data;
380         sdp_data_t *value = (sdp_data_t *) val;
381         char buf[STRBUFSIZE];
382
383         buf[STRBUFSIZE - 1] = '\0';
384         snprintf(buf, STRBUFSIZE - 1, "\t<attribute id=\"0x%04x\">\n",
385                  value->attrId);
386         cd->appender(cd->data, buf);
387
388         if (data)
389                 convert_raw_data_to_xml(value, 2, cd->data, cd->appender);
390         else
391                 cd->appender(cd->data, "\t\tNULL\n");
392
393         cd->appender(cd->data, "\t</attribute>\n");
394 }
395
396 /*
397  * Will convert the sdp record to XML.  The appender and data can be used
398  * to control where to output the record (e.g. file or a data buffer).  The
399  * appender will be called repeatedly with data and the character buffer
400  * (containing parts of the generated XML) to append.
401  */
402 void convert_sdp_record_to_xml(sdp_record_t *rec,
403                         void *data, void (*appender)(void *, const char *))
404 {
405         struct conversion_data cd;
406
407         cd.data = data;
408         cd.appender = appender;
409
410         if (rec && rec->attrlist) {
411                 appender(data, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n");
412                 appender(data, "<record>\n");
413                 sdp_list_foreach(rec->attrlist,
414                                  convert_raw_attr_to_xml_func, &cd);
415                 appender(data, "</record>\n");
416         }
417 }
418
419 static sdp_data_t *sdp_xml_parse_uuid128(const char *data)
420 {
421         uint128_t val;
422         unsigned int i, j;
423
424         char buf[3];
425
426         memset(&val, 0, sizeof(val));
427
428         buf[2] = '\0';
429
430         for (j = 0, i = 0; i < strlen(data);) {
431                 if (data[i] == '-') {
432                         i++;
433                         continue;
434                 }
435
436                 buf[0] = data[i];
437                 buf[1] = data[i + 1];
438
439                 val.data[j++] = strtoul(buf, 0, 16);
440                 i += 2;
441         }
442
443         return sdp_data_alloc(SDP_UUID128, &val);
444 }
445
446 sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record)
447 {
448         sdp_data_t *ret;
449         char *endptr;
450         uint32_t val;
451         uint16_t val2;
452         int len;
453
454         len = strlen(data);
455
456         if (len == 36) {
457                 ret = sdp_xml_parse_uuid128(data);
458                 goto result;
459         }
460
461         val = strtoll(data, &endptr, 16);
462
463         /* Couldn't parse */
464         if (*endptr != '\0')
465                 return NULL;
466
467         if (val > USHRT_MAX) {
468                 ret = sdp_data_alloc(SDP_UUID32, &val);
469                 goto result;
470         }
471
472         val2 = val;
473
474         ret = sdp_data_alloc(SDP_UUID16, &val2);
475
476 result:
477         if (record && ret)
478                 sdp_pattern_add_uuid(record, &ret->val.uuid);
479
480         return ret;
481 }
482
483 sdp_data_t *sdp_xml_parse_int(const char * data, uint8_t dtd)
484 {
485         char *endptr;
486         sdp_data_t *ret = NULL;
487
488         switch (dtd) {
489         case SDP_BOOL:
490         {
491                 uint8_t val = 0;
492
493                 if (!strcmp("true", data)) {
494                         val = 1;
495                 }
496
497                 else if (!strcmp("false", data)) {
498                         val = 0;
499                 }
500                 else {
501                         return NULL;
502                 }
503
504                 ret = sdp_data_alloc(dtd, &val);
505                 break;
506         }
507
508         case SDP_INT8:
509         {
510                 int8_t val = strtoul(data, &endptr, 0);
511
512                 /* Failed to parse */
513                 if ((endptr != data) && (*endptr != '\0'))
514                         return NULL;
515
516                 ret = sdp_data_alloc(dtd, &val);
517                 break;
518         }
519
520         case SDP_UINT8:
521         {
522                 uint8_t val = strtoul(data, &endptr, 0);
523
524                 /* Failed to parse */
525                 if ((endptr != data) && (*endptr != '\0'))
526                         return NULL;
527
528                 ret = sdp_data_alloc(dtd, &val);
529                 break;
530         }
531
532         case SDP_INT16:
533         {
534                 int16_t val = strtoul(data, &endptr, 0);
535
536                 /* Failed to parse */
537                 if ((endptr != data) && (*endptr != '\0'))
538                         return NULL;
539
540                 ret = sdp_data_alloc(dtd, &val);
541                 break;
542         }
543
544         case SDP_UINT16:
545         {
546                 uint16_t val = strtoul(data, &endptr, 0);
547
548                 /* Failed to parse */
549                 if ((endptr != data) && (*endptr != '\0'))
550                         return NULL;
551
552                 ret = sdp_data_alloc(dtd, &val);
553                 break;
554         }
555
556         case SDP_INT32:
557         {
558                 int32_t val = strtoul(data, &endptr, 0);
559
560                 /* Failed to parse */
561                 if ((endptr != data) && (*endptr != '\0'))
562                         return NULL;
563
564                 ret = sdp_data_alloc(dtd, &val);
565                 break;
566         }
567
568         case SDP_UINT32:
569         {
570                 uint32_t val = strtoul(data, &endptr, 0);
571
572                 /* Failed to parse */
573                 if ((endptr != data) && (*endptr != '\0'))
574                         return NULL;
575
576                 ret = sdp_data_alloc(dtd, &val);
577                 break;
578         }
579
580         case SDP_INT64:
581         {
582                 int64_t val = strtoull(data, &endptr, 0);
583
584                 /* Failed to parse */
585                 if ((endptr != data) && (*endptr != '\0'))
586                         return NULL;
587
588                 ret = sdp_data_alloc(dtd, &val);
589                 break;
590         }
591
592         case SDP_UINT64:
593         {
594                 uint64_t val = strtoull(data, &endptr, 0);
595
596                 /* Failed to parse */
597                 if ((endptr != data) && (*endptr != '\0'))
598                         return NULL;
599
600                 ret = sdp_data_alloc(dtd, &val);
601                 break;
602         }
603
604         case SDP_INT128:
605         case SDP_UINT128:
606         {
607                 uint128_t val;
608                 int i = 0;
609                 char buf[3];
610
611                 buf[2] = '\0';
612
613                 for (; i < 32; i += 2) {
614                         buf[0] = data[i];
615                         buf[1] = data[i + 1];
616
617                         val.data[i >> 1] = strtoul(buf, 0, 16);
618                 }
619
620                 ret = sdp_data_alloc(dtd, &val);
621                 break;
622         }
623
624         };
625
626         return ret;
627 }
628
629 static char *sdp_xml_parse_string_decode(const char *data, char encoding, uint32_t *length)
630 {
631         int len = strlen(data);
632         char *text;
633
634         if (encoding == SDP_XML_ENCODING_NORMAL) {
635                 text = strdup(data);
636                 *length = len;
637         } else {
638                 char buf[3], *decoded;
639                 int i;
640
641                 decoded = malloc((len >> 1) + 1);
642
643                 /* Ensure the string is a power of 2 */
644                 len = (len >> 1) << 1;
645
646                 buf[2] = '\0';
647
648                 for (i = 0; i < len; i += 2) {
649                         buf[0] = data[i];
650                         buf[1] = data[i + 1];
651
652                         decoded[i >> 1] = strtoul(buf, 0, 16);
653                 }
654
655                 decoded[len >> 1] = '\0';
656                 text = decoded;
657                 *length = len >> 1;
658         }
659
660         return text;
661 }
662
663 sdp_data_t *sdp_xml_parse_url(const char *data)
664 {
665         uint8_t dtd = SDP_URL_STR8;
666         char *url;
667         uint32_t length;
668         sdp_data_t *ret;
669
670         url = sdp_xml_parse_string_decode(data,
671                                 SDP_XML_ENCODING_NORMAL, &length);
672
673         if (length > UCHAR_MAX)
674                 dtd = SDP_URL_STR16;
675
676         ret = sdp_data_alloc_with_length(dtd, url, length);
677
678         debug("URL size %d length %d: -->%s<--", ret->unitSize, length, url);
679
680         free(url);
681
682         return ret;
683 }
684
685 sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
686 {
687         uint8_t dtd = SDP_TEXT_STR8;
688         char *text;
689         uint32_t length;
690         sdp_data_t *ret;
691
692         text = sdp_xml_parse_string_decode(data, encoding, &length);
693
694         if (length > UCHAR_MAX)
695                 dtd = SDP_TEXT_STR16;
696
697         ret = sdp_data_alloc_with_length(dtd, text, length);
698
699         debug("Text size %d length %d: -->%s<--", ret->unitSize, length, text);
700
701         free(text);
702
703         return ret;
704 }
705
706 sdp_data_t *sdp_xml_parse_nil(const char *data)
707 {
708         return sdp_data_alloc(SDP_DATA_NIL, 0);
709 }
710
711 #define DEFAULT_XML_DATA_SIZE 1024
712
713 struct sdp_xml_data *sdp_xml_data_alloc()
714 {
715         struct sdp_xml_data *elem;
716
717         elem = malloc(sizeof(struct sdp_xml_data));
718         if (!elem)
719                 return NULL;
720
721         memset(elem, 0, sizeof(struct sdp_xml_data));
722
723         /* Null terminate the text */
724         elem->size = DEFAULT_XML_DATA_SIZE;
725         elem->text = malloc(DEFAULT_XML_DATA_SIZE);
726         elem->text[0] = '\0';
727
728         return elem;
729 }
730
731 void sdp_xml_data_free(struct sdp_xml_data *elem)
732 {
733         if (elem->data)
734                 sdp_data_free(elem->data);
735
736         if (elem->name)
737                 free(elem->name);
738
739         if (elem->text)
740
741                 free(elem->text);
742         free(elem);
743 }
744
745 struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem)
746 {
747         char *newbuf;
748
749         newbuf = malloc(elem->size * 2);
750         if (!newbuf)
751                 return NULL;
752
753         memcpy(newbuf, elem->text, elem->size);
754         elem->size *= 2;
755         free(elem->text);
756
757         elem->text = newbuf;
758
759         return elem;
760 }
761
762 sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
763                                                         sdp_record_t *record)
764 {
765         const char *data = elem->text;
766
767         if (!strcmp(el, "boolean"))
768                 return sdp_xml_parse_int(data, SDP_BOOL);
769         else if (!strcmp(el, "uint8"))
770                 return sdp_xml_parse_int(data, SDP_UINT8);
771         else if (!strcmp(el, "uint16"))
772                 return sdp_xml_parse_int(data, SDP_UINT16);
773         else if (!strcmp(el, "uint32"))
774                 return sdp_xml_parse_int(data, SDP_UINT32);
775         else if (!strcmp(el, "uint64"))
776                 return sdp_xml_parse_int(data, SDP_UINT64);
777         else if (!strcmp(el, "uint128"))
778                 return sdp_xml_parse_int(data, SDP_UINT128);
779         else if (!strcmp(el, "int8"))
780                 return sdp_xml_parse_int(data, SDP_INT8);
781         else if (!strcmp(el, "int16"))
782                 return sdp_xml_parse_int(data, SDP_INT16);
783         else if (!strcmp(el, "int32"))
784                 return sdp_xml_parse_int(data, SDP_INT32);
785         else if (!strcmp(el, "int64"))
786                 return sdp_xml_parse_int(data, SDP_INT64);
787         else if (!strcmp(el, "int128"))
788                 return sdp_xml_parse_int(data, SDP_INT128);
789         else if (!strcmp(el, "uuid"))
790                 return sdp_xml_parse_uuid(data, record);
791         else if (!strcmp(el, "url"))
792                 return sdp_xml_parse_url(data);
793         else if (!strcmp(el, "text"))
794                 return sdp_xml_parse_text(data, elem->type);
795         else if (!strcmp(el, "nil"))
796                 return sdp_xml_parse_nil(data);
797
798         return NULL;
799 }