From 0a4f70772e3c2f968faae4ea96502f7d8aa9cc9b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Dec 2012 11:31:30 +0200 Subject: [PATCH] core: Make sdp-xml functions private that aren't used publically --- src/sdp-xml.c | 1433 +++++++++++++++++++++++++------------------------ src/sdp-xml.h | 23 - 2 files changed, 717 insertions(+), 739 deletions(-) diff --git a/src/sdp-xml.c b/src/sdp-xml.c index 7d5f6264f..262b8e763 100644 --- a/src/sdp-xml.c +++ b/src/sdp-xml.c @@ -45,6 +45,16 @@ #define STRBUFSIZE 1024 #define MAXINDENT 64 +struct sdp_xml_data { + char *text; /* Pointer to the current buffer */ + int size; /* Size of the current buffer */ + sdp_data_t *data; /* The current item being built */ + struct sdp_xml_data *next; /* Next item on the stack */ + char type; /* 0 = Text or Hexadecimal */ + char *name; /* Name, optional in the dtd */ + /* TODO: What is it used for? */ +}; + struct context_data { sdp_record_t *record; sdp_data_t attr_data; @@ -63,931 +73,922 @@ static int compute_seq_size(sdp_data_t *data) return unit_size; } -static void element_start(GMarkupParseContext *context, - const gchar *element_name, const gchar **attribute_names, - const gchar **attribute_values, gpointer user_data, GError **err) -{ - struct context_data *ctx_data = user_data; +#define DEFAULT_XML_DATA_SIZE 1024 - if (!strcmp(element_name, "record")) - return; +static struct sdp_xml_data *sdp_xml_data_alloc(void) +{ + struct sdp_xml_data *elem; - if (!strcmp(element_name, "attribute")) { - int i; - for (i = 0; attribute_names[i]; i++) { - if (!strcmp(attribute_names[i], "id")) { - ctx_data->attr_id = strtol(attribute_values[i], 0, 0); - break; - } - } - DBG("New attribute 0x%04x", ctx_data->attr_id); - return; - } + elem = malloc(sizeof(struct sdp_xml_data)); + if (!elem) + return NULL; - if (ctx_data->stack_head) { - struct sdp_xml_data *newelem = sdp_xml_data_alloc(); - newelem->next = ctx_data->stack_head; - ctx_data->stack_head = newelem; - } else { - ctx_data->stack_head = sdp_xml_data_alloc(); - ctx_data->stack_head->next = NULL; - } + memset(elem, 0, sizeof(struct sdp_xml_data)); - if (!strcmp(element_name, "sequence")) - ctx_data->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL); - else if (!strcmp(element_name, "alternate")) - ctx_data->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL); - else { - int i; - /* Parse value, name, encoding */ - for (i = 0; attribute_names[i]; i++) { - if (!strcmp(attribute_names[i], "value")) { - int curlen = strlen(ctx_data->stack_head->text); - int attrlen = strlen(attribute_values[i]); + /* Null terminate the text */ + elem->size = DEFAULT_XML_DATA_SIZE; + elem->text = malloc(DEFAULT_XML_DATA_SIZE); + elem->text[0] = '\0'; - /* Ensure we're big enough */ - while ((curlen + 1 + attrlen) > ctx_data->stack_head->size) { - sdp_xml_data_expand(ctx_data->stack_head); - } + return elem; +} - memcpy(ctx_data->stack_head->text + curlen, - attribute_values[i], attrlen); - ctx_data->stack_head->text[curlen + attrlen] = '\0'; - } +static struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem) +{ + char *newbuf; - if (!strcmp(attribute_names[i], "encoding")) { - if (!strcmp(attribute_values[i], "hex")) - ctx_data->stack_head->type = 1; - } + newbuf = malloc(elem->size * 2); + if (!newbuf) + return NULL; - if (!strcmp(attribute_names[i], "name")) { - ctx_data->stack_head->name = strdup(attribute_values[i]); - } - } + memcpy(newbuf, elem->text, elem->size); + elem->size *= 2; + free(elem->text); - ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name, - ctx_data->stack_head, ctx_data->record); + elem->text = newbuf; - if (ctx_data->stack_head->data == NULL) - error("Can't parse element %s", element_name); - } + return elem; } -static void element_end(GMarkupParseContext *context, - const gchar *element_name, gpointer user_data, GError **err) +static sdp_data_t *sdp_xml_parse_uuid128(const char *data) { - struct context_data *ctx_data = user_data; - struct sdp_xml_data *elem; - - if (!strcmp(element_name, "record")) - return; - - if (!strcmp(element_name, "attribute")) { - if (ctx_data->stack_head && ctx_data->stack_head->data) { - int ret = sdp_attr_add(ctx_data->record, ctx_data->attr_id, - ctx_data->stack_head->data); - if (ret == -1) - DBG("Could not add attribute 0x%04x", - ctx_data->attr_id); - - ctx_data->stack_head->data = NULL; - sdp_xml_data_free(ctx_data->stack_head); - ctx_data->stack_head = NULL; - } else { - DBG("No data for attribute 0x%04x", ctx_data->attr_id); - } - return; - } - - if (!ctx_data->stack_head || !ctx_data->stack_head->data) { - DBG("No data for %s", element_name); - return; - } + uint128_t val; + unsigned int i, j; - if (!strcmp(element_name, "sequence")) { - ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data); + char buf[3]; - if (ctx_data->stack_head->data->unitSize > USHRT_MAX) { - ctx_data->stack_head->data->unitSize += sizeof(uint32_t); - ctx_data->stack_head->data->dtd = SDP_SEQ32; - } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) { - ctx_data->stack_head->data->unitSize += sizeof(uint16_t); - ctx_data->stack_head->data->dtd = SDP_SEQ16; - } else { - ctx_data->stack_head->data->unitSize += sizeof(uint8_t); - } - } else if (!strcmp(element_name, "alternate")) { - ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data); + memset(&val, 0, sizeof(val)); - if (ctx_data->stack_head->data->unitSize > USHRT_MAX) { - ctx_data->stack_head->data->unitSize += sizeof(uint32_t); - ctx_data->stack_head->data->dtd = SDP_ALT32; - } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) { - ctx_data->stack_head->data->unitSize += sizeof(uint16_t); - ctx_data->stack_head->data->dtd = SDP_ALT16; - } else { - ctx_data->stack_head->data->unitSize += sizeof(uint8_t); - } - } + buf[2] = '\0'; - if (ctx_data->stack_head->next && ctx_data->stack_head->data && - ctx_data->stack_head->next->data) { - switch (ctx_data->stack_head->next->data->dtd) { - case SDP_SEQ8: - case SDP_SEQ16: - case SDP_SEQ32: - case SDP_ALT8: - case SDP_ALT16: - case SDP_ALT32: - ctx_data->stack_head->next->data->val.dataseq = - sdp_seq_append(ctx_data->stack_head->next->data->val.dataseq, - ctx_data->stack_head->data); - ctx_data->stack_head->data = NULL; - break; + for (j = 0, i = 0; i < strlen(data);) { + if (data[i] == '-') { + i++; + continue; } - elem = ctx_data->stack_head; - ctx_data->stack_head = ctx_data->stack_head->next; + buf[0] = data[i]; + buf[1] = data[i + 1]; - sdp_xml_data_free(elem); + val.data[j++] = strtoul(buf, 0, 16); + i += 2; } -} -static GMarkupParser parser = { - element_start, element_end, NULL, NULL, NULL -}; + return sdp_data_alloc(SDP_UUID128, &val); +} -sdp_record_t *sdp_xml_parse_record(const char *data, int size) +static sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record) { - GMarkupParseContext *ctx; - struct context_data *ctx_data; - sdp_record_t *record; + sdp_data_t *ret; + char *endptr; + uint32_t val; + uint16_t val2; + int len; - ctx_data = malloc(sizeof(*ctx_data)); - if (!ctx_data) - return NULL; + len = strlen(data); - record = sdp_record_alloc(); - if (!record) { - free(ctx_data); - return NULL; + if (len == 36) { + ret = sdp_xml_parse_uuid128(data); + goto result; } - memset(ctx_data, 0, sizeof(*ctx_data)); - ctx_data->record = record; - - ctx = g_markup_parse_context_new(&parser, 0, ctx_data, NULL); + val = strtoll(data, &endptr, 16); - if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) { - error("XML parsing error"); - g_markup_parse_context_free(ctx); - sdp_record_free(record); - free(ctx_data); + /* Couldn't parse */ + if (*endptr != '\0') return NULL; + + if (val > USHRT_MAX) { + ret = sdp_data_alloc(SDP_UUID32, &val); + goto result; } - g_markup_parse_context_free(ctx); + val2 = val; - free(ctx_data); + ret = sdp_data_alloc(SDP_UUID16, &val2); - return record; -} +result: + if (record && ret) + sdp_pattern_add_uuid(record, &ret->val.uuid); + return ret; +} -static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level, - void *data, void (*appender)(void *, const char *)) +static sdp_data_t *sdp_xml_parse_int(const char *data, uint8_t dtd) { - int i, hex; - char buf[STRBUFSIZE]; - char indent[MAXINDENT]; + char *endptr; + sdp_data_t *ret = NULL; - if (!value) - return; + switch (dtd) { + case SDP_BOOL: + { + uint8_t val = 0; - if (indent_level >= MAXINDENT) - indent_level = MAXINDENT - 2; + if (!strcmp("true", data)) + val = 1; + else if (!strcmp("false", data)) + val = 0; + else + return NULL; - for (i = 0; i < indent_level; i++) - indent[i] = '\t'; + ret = sdp_data_alloc(dtd, &val); + break; + } - indent[i] = '\0'; - buf[STRBUFSIZE - 1] = '\0'; + case SDP_INT8: + { + int8_t val = strtoul(data, &endptr, 0); - switch (value->dtd) { - case SDP_DATA_NIL: - appender(data, indent); - appender(data, "\n"); + /* Failed to parse */ + if ((endptr != data) && (*endptr != '\0')) + return NULL; + + ret = sdp_data_alloc(dtd, &val); break; + } - case SDP_BOOL: - appender(data, indent); - appender(data, "val.uint8 ? "true" : "false"); - appender(data, "\" />\n"); + case SDP_UINT8: + { + uint8_t val = strtoul(data, &endptr, 0); + + /* Failed to parse */ + if ((endptr != data) && (*endptr != '\0')) + return NULL; + + ret = sdp_data_alloc(dtd, &val); break; + } - case SDP_UINT8: - appender(data, indent); - appender(data, "val.uint8); - appender(data, buf); - appender(data, "\" />\n"); + case SDP_INT16: + { + int16_t val = strtoul(data, &endptr, 0); + + /* Failed to parse */ + if ((endptr != data) && (*endptr != '\0')) + return NULL; + + ret = sdp_data_alloc(dtd, &val); break; + } case SDP_UINT16: - appender(data, indent); - appender(data, "val.uint16); - appender(data, buf); - appender(data, "\" />\n"); - break; + { + uint16_t val = strtoul(data, &endptr, 0); - case SDP_UINT32: - appender(data, indent); - appender(data, "val.uint32); - appender(data, buf); - appender(data, "\" />\n"); - break; + /* Failed to parse */ + if ((endptr != data) && (*endptr != '\0')) + return NULL; - case SDP_UINT64: - appender(data, indent); - appender(data, "val.uint64); - appender(data, buf); - appender(data, "\" />\n"); + ret = sdp_data_alloc(dtd, &val); break; + } - case SDP_UINT128: - appender(data, indent); - appender(data, "val.uint128.data[i]); - } + /* Failed to parse */ + if ((endptr != data) && (*endptr != '\0')) + return NULL; - appender(data, buf); - appender(data, "\" />\n"); + ret = sdp_data_alloc(dtd, &val); break; + } - case SDP_INT8: - appender(data, indent); - appender(data, "val.int8); - appender(data, buf); - appender(data, "\" />\n"); - break; + case SDP_UINT32: + { + uint32_t val = strtoul(data, &endptr, 0); - case SDP_INT16: - appender(data, indent); - appender(data, "val.int16); - appender(data, buf); - appender(data, "\" />\n"); - break; + /* Failed to parse */ + if ((endptr != data) && (*endptr != '\0')) + return NULL; - case SDP_INT32: - appender(data, indent); - appender(data, "val.int32); - appender(data, buf); - appender(data, "\" />\n"); + ret = sdp_data_alloc(dtd, &val); break; + } case SDP_INT64: - appender(data, indent); - appender(data, "val.int64); - appender(data, buf); - appender(data, "\" />\n"); + { + int64_t val = strtoull(data, &endptr, 0); + + /* Failed to parse */ + if ((endptr != data) && (*endptr != '\0')) + return NULL; + + ret = sdp_data_alloc(dtd, &val); break; + } - case SDP_INT128: - appender(data, indent); - appender(data, "val.int128.data[i]); - } - appender(data, buf); + /* Failed to parse */ + if ((endptr != data) && (*endptr != '\0')) + return NULL; - appender(data, "\" />\n"); + ret = sdp_data_alloc(dtd, &val); break; + } - case SDP_UUID16: - appender(data, indent); - appender(data, "val.uuid.value.uuid16); - appender(data, buf); - appender(data, "\" />\n"); - break; + case SDP_INT128: + case SDP_UINT128: + { + uint128_t val; + int i = 0; + char buf[3]; - case SDP_UUID32: - appender(data, indent); - appender(data, "val.uuid.value.uuid32); - appender(data, buf); - appender(data, "\" />\n"); - break; + buf[2] = '\0'; - case SDP_UUID128: - appender(data, indent); - appender(data, "val.uuid.value. - uuid128.data[0], - (unsigned char) value->val.uuid.value. - uuid128.data[1], - (unsigned char) value->val.uuid.value. - uuid128.data[2], - (unsigned char) value->val.uuid.value. - uuid128.data[3], - (unsigned char) value->val.uuid.value. - uuid128.data[4], - (unsigned char) value->val.uuid.value. - uuid128.data[5], - (unsigned char) value->val.uuid.value. - uuid128.data[6], - (unsigned char) value->val.uuid.value. - uuid128.data[7], - (unsigned char) value->val.uuid.value. - uuid128.data[8], - (unsigned char) value->val.uuid.value. - uuid128.data[9], - (unsigned char) value->val.uuid.value. - uuid128.data[10], - (unsigned char) value->val.uuid.value. - uuid128.data[11], - (unsigned char) value->val.uuid.value. - uuid128.data[12], - (unsigned char) value->val.uuid.value. - uuid128.data[13], - (unsigned char) value->val.uuid.value. - uuid128.data[14], - (unsigned char) value->val.uuid.value. - uuid128.data[15]); + val.data[i >> 1] = strtoul(buf, 0, 16); + } - appender(data, buf); - appender(data, "\" />\n"); + ret = sdp_data_alloc(dtd, &val); break; + } - case SDP_TEXT_STR8: - case SDP_TEXT_STR16: - case SDP_TEXT_STR32: - { - int num_chars_to_escape = 0; - int length = value->unitSize - 1; - char *strBuf = 0; + }; - hex = 0; + return ret; +} - for (i = 0; i < length; i++) { - if (!isprint(value->val.str[i]) && - value->val.str[i] != '\0') { - hex = 1; - break; - } +static char *sdp_xml_parse_string_decode(const char *data, char encoding, + uint32_t *length) +{ + int len = strlen(data); + char *text; - /* XML is evil, must do this... */ - if ((value->val.str[i] == '<') || - (value->val.str[i] == '>') || - (value->val.str[i] == '"') || - (value->val.str[i] == '&')) - num_chars_to_escape++; - } + if (encoding == SDP_XML_ENCODING_NORMAL) { + text = strdup(data); + *length = len; + } else { + char buf[3], *decoded; + int i; - appender(data, indent); + decoded = malloc((len >> 1) + 1); - appender(data, "> 1) << 1; - if (hex) { - appender(data, "encoding=\"hex\" "); - strBuf = malloc(sizeof(char) - * ((value->unitSize-1) * 2 + 1)); + buf[2] = '\0'; - /* Unit Size seems to include the size for dtd - It is thus off by 1 - This is safe for Normal strings, but not - hex encoded data */ - for (i = 0; i < (value->unitSize-1); i++) - sprintf(&strBuf[i*sizeof(char)*2], - "%02x", - (unsigned char) value->val.str[i]); + for (i = 0; i < len; i += 2) { + buf[0] = data[i]; + buf[1] = data[i + 1]; - strBuf[(value->unitSize-1) * 2] = '\0'; - } - else { - int j; - /* escape the XML disallowed chars */ - strBuf = malloc(sizeof(char) * - (value->unitSize + 1 + num_chars_to_escape * 4)); - for (i = 0, j = 0; i < length; i++) { - if (value->val.str[i] == '&') { - strBuf[j++] = '&'; - strBuf[j++] = 'a'; - strBuf[j++] = 'm'; - strBuf[j++] = 'p'; - } - else if (value->val.str[i] == '<') { - strBuf[j++] = '&'; - strBuf[j++] = 'l'; - strBuf[j++] = 't'; - } - else if (value->val.str[i] == '>') { - strBuf[j++] = '&'; - strBuf[j++] = 'g'; - strBuf[j++] = 't'; - } - else if (value->val.str[i] == '"') { - strBuf[j++] = '&'; - strBuf[j++] = 'q'; - strBuf[j++] = 'u'; - strBuf[j++] = 'o'; - strBuf[j++] = 't'; - } - else if (value->val.str[i] == '\0') { - strBuf[j++] = ' '; - } else { - strBuf[j++] = value->val.str[i]; - } - } - - strBuf[j] = '\0'; + decoded[i >> 1] = strtoul(buf, 0, 16); } - appender(data, "value=\""); - appender(data, strBuf); - appender(data, "\" />\n"); - free(strBuf); - break; + decoded[len >> 1] = '\0'; + text = decoded; + *length = len >> 1; } - case SDP_URL_STR8: - case SDP_URL_STR16: - case SDP_URL_STR32: - { - char *strBuf; + return text; +} - appender(data, indent); - appender(data, "val.str, value->unitSize - 1); - appender(data, strBuf); - free(strBuf); - appender(data, "\" />\n"); - break; - } +static sdp_data_t *sdp_xml_parse_url(const char *data) +{ + uint8_t dtd = SDP_URL_STR8; + char *url; + uint32_t length; + sdp_data_t *ret; - case SDP_SEQ8: - case SDP_SEQ16: - case SDP_SEQ32: - appender(data, indent); - appender(data, "\n"); + url = sdp_xml_parse_string_decode(data, + SDP_XML_ENCODING_NORMAL, &length); - convert_raw_data_to_xml(value->val.dataseq, - indent_level + 1, data, appender); + if (length > UCHAR_MAX) + dtd = SDP_URL_STR16; - appender(data, indent); - appender(data, "\n"); + ret = sdp_data_alloc_with_length(dtd, url, length); - break; + free(url); - case SDP_ALT8: - case SDP_ALT16: - case SDP_ALT32: - appender(data, indent); + return ret; +} - appender(data, "\n"); +static sdp_data_t *sdp_xml_parse_text(const char *data, char encoding) +{ + uint8_t dtd = SDP_TEXT_STR8; + char *text; + uint32_t length; + sdp_data_t *ret; - convert_raw_data_to_xml(value->val.dataseq, - indent_level + 1, data, appender); - appender(data, indent); + text = sdp_xml_parse_string_decode(data, encoding, &length); - appender(data, "\n"); + if (length > UCHAR_MAX) + dtd = SDP_TEXT_STR16; - break; - } + ret = sdp_data_alloc_with_length(dtd, text, length); - convert_raw_data_to_xml(value->next, indent_level, data, appender); -} + free(text); -struct conversion_data { - void *data; - void (*appender)(void *data, const char *); -}; + return ret; +} -static void convert_raw_attr_to_xml_func(void *val, void *data) +static sdp_data_t *sdp_xml_parse_nil(const char *data) { - struct conversion_data *cd = data; - sdp_data_t *value = val; - char buf[STRBUFSIZE]; + return sdp_data_alloc(SDP_DATA_NIL, 0); +} - buf[STRBUFSIZE - 1] = '\0'; - snprintf(buf, STRBUFSIZE - 1, "\t\n", - value->attrId); - cd->appender(cd->data, buf); +static sdp_data_t *sdp_xml_parse_datatype(const char *el, + struct sdp_xml_data *elem, + sdp_record_t *record) +{ + const char *data = elem->text; - convert_raw_data_to_xml(value, 2, cd->data, cd->appender); + if (!strcmp(el, "boolean")) + return sdp_xml_parse_int(data, SDP_BOOL); + else if (!strcmp(el, "uint8")) + return sdp_xml_parse_int(data, SDP_UINT8); + else if (!strcmp(el, "uint16")) + return sdp_xml_parse_int(data, SDP_UINT16); + else if (!strcmp(el, "uint32")) + return sdp_xml_parse_int(data, SDP_UINT32); + else if (!strcmp(el, "uint64")) + return sdp_xml_parse_int(data, SDP_UINT64); + else if (!strcmp(el, "uint128")) + return sdp_xml_parse_int(data, SDP_UINT128); + else if (!strcmp(el, "int8")) + return sdp_xml_parse_int(data, SDP_INT8); + else if (!strcmp(el, "int16")) + return sdp_xml_parse_int(data, SDP_INT16); + else if (!strcmp(el, "int32")) + return sdp_xml_parse_int(data, SDP_INT32); + else if (!strcmp(el, "int64")) + return sdp_xml_parse_int(data, SDP_INT64); + else if (!strcmp(el, "int128")) + return sdp_xml_parse_int(data, SDP_INT128); + else if (!strcmp(el, "uuid")) + return sdp_xml_parse_uuid(data, record); + else if (!strcmp(el, "url")) + return sdp_xml_parse_url(data); + else if (!strcmp(el, "text")) + return sdp_xml_parse_text(data, elem->type); + else if (!strcmp(el, "nil")) + return sdp_xml_parse_nil(data); - cd->appender(cd->data, "\t\n"); + return NULL; } - -/* - * Will convert the sdp record to XML. The appender and data can be used - * to control where to output the record (e.g. file or a data buffer). The - * appender will be called repeatedly with data and the character buffer - * (containing parts of the generated XML) to append. - */ -void convert_sdp_record_to_xml(sdp_record_t *rec, - void *data, void (*appender)(void *, const char *)) +static void element_start(GMarkupParseContext *context, + const gchar *element_name, const gchar **attribute_names, + const gchar **attribute_values, gpointer user_data, GError **err) { - struct conversion_data cd; + struct context_data *ctx_data = user_data; - cd.data = data; - cd.appender = appender; + if (!strcmp(element_name, "record")) + return; - if (rec && rec->attrlist) { - appender(data, "\n\n"); - appender(data, "\n"); - sdp_list_foreach(rec->attrlist, - convert_raw_attr_to_xml_func, &cd); - appender(data, "\n"); + if (!strcmp(element_name, "attribute")) { + int i; + for (i = 0; attribute_names[i]; i++) { + if (!strcmp(attribute_names[i], "id")) { + ctx_data->attr_id = strtol(attribute_values[i], 0, 0); + break; + } + } + DBG("New attribute 0x%04x", ctx_data->attr_id); + return; } -} -static sdp_data_t *sdp_xml_parse_uuid128(const char *data) -{ - uint128_t val; - unsigned int i, j; + if (ctx_data->stack_head) { + struct sdp_xml_data *newelem = sdp_xml_data_alloc(); + newelem->next = ctx_data->stack_head; + ctx_data->stack_head = newelem; + } else { + ctx_data->stack_head = sdp_xml_data_alloc(); + ctx_data->stack_head->next = NULL; + } - char buf[3]; + if (!strcmp(element_name, "sequence")) + ctx_data->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL); + else if (!strcmp(element_name, "alternate")) + ctx_data->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL); + else { + int i; + /* Parse value, name, encoding */ + for (i = 0; attribute_names[i]; i++) { + if (!strcmp(attribute_names[i], "value")) { + int curlen = strlen(ctx_data->stack_head->text); + int attrlen = strlen(attribute_values[i]); - memset(&val, 0, sizeof(val)); + /* Ensure we're big enough */ + while ((curlen + 1 + attrlen) > ctx_data->stack_head->size) + sdp_xml_data_expand(ctx_data->stack_head); - buf[2] = '\0'; + memcpy(ctx_data->stack_head->text + curlen, + attribute_values[i], attrlen); + ctx_data->stack_head->text[curlen + attrlen] = '\0'; + } - for (j = 0, i = 0; i < strlen(data);) { - if (data[i] == '-') { - i++; - continue; + if (!strcmp(attribute_names[i], "encoding")) { + if (!strcmp(attribute_values[i], "hex")) + ctx_data->stack_head->type = 1; + } + + if (!strcmp(attribute_names[i], "name")) + ctx_data->stack_head->name = strdup(attribute_values[i]); } - buf[0] = data[i]; - buf[1] = data[i + 1]; + ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name, + ctx_data->stack_head, ctx_data->record); - val.data[j++] = strtoul(buf, 0, 16); - i += 2; + if (ctx_data->stack_head->data == NULL) + error("Can't parse element %s", element_name); } - - return sdp_data_alloc(SDP_UUID128, &val); } -sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record) +static void sdp_xml_data_free(struct sdp_xml_data *elem) { - sdp_data_t *ret; - char *endptr; - uint32_t val; - uint16_t val2; - int len; - - len = strlen(data); + if (elem->data) + sdp_data_free(elem->data); - if (len == 36) { - ret = sdp_xml_parse_uuid128(data); - goto result; - } + free(elem->name); + free(elem->text); + free(elem); +} - val = strtoll(data, &endptr, 16); - - /* Couldn't parse */ - if (*endptr != '\0') - return NULL; - - if (val > USHRT_MAX) { - ret = sdp_data_alloc(SDP_UUID32, &val); - goto result; - } - - val2 = val; +static void element_end(GMarkupParseContext *context, + const gchar *element_name, gpointer user_data, GError **err) +{ + struct context_data *ctx_data = user_data; + struct sdp_xml_data *elem; - ret = sdp_data_alloc(SDP_UUID16, &val2); + if (!strcmp(element_name, "record")) + return; -result: - if (record && ret) - sdp_pattern_add_uuid(record, &ret->val.uuid); + if (!strcmp(element_name, "attribute")) { + if (ctx_data->stack_head && ctx_data->stack_head->data) { + int ret = sdp_attr_add(ctx_data->record, ctx_data->attr_id, + ctx_data->stack_head->data); + if (ret == -1) + DBG("Could not add attribute 0x%04x", + ctx_data->attr_id); - return ret; -} + ctx_data->stack_head->data = NULL; + sdp_xml_data_free(ctx_data->stack_head); + ctx_data->stack_head = NULL; + } else { + DBG("No data for attribute 0x%04x", ctx_data->attr_id); + } + return; + } -sdp_data_t *sdp_xml_parse_int(const char * data, uint8_t dtd) -{ - char *endptr; - sdp_data_t *ret = NULL; + if (!ctx_data->stack_head || !ctx_data->stack_head->data) { + DBG("No data for %s", element_name); + return; + } - switch (dtd) { - case SDP_BOOL: - { - uint8_t val = 0; + if (!strcmp(element_name, "sequence")) { + ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data); - if (!strcmp("true", data)) { - val = 1; + if (ctx_data->stack_head->data->unitSize > USHRT_MAX) { + ctx_data->stack_head->data->unitSize += sizeof(uint32_t); + ctx_data->stack_head->data->dtd = SDP_SEQ32; + } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) { + ctx_data->stack_head->data->unitSize += sizeof(uint16_t); + ctx_data->stack_head->data->dtd = SDP_SEQ16; + } else { + ctx_data->stack_head->data->unitSize += sizeof(uint8_t); } + } else if (!strcmp(element_name, "alternate")) { + ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data); - else if (!strcmp("false", data)) { - val = 0; - } - else { - return NULL; + if (ctx_data->stack_head->data->unitSize > USHRT_MAX) { + ctx_data->stack_head->data->unitSize += sizeof(uint32_t); + ctx_data->stack_head->data->dtd = SDP_ALT32; + } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) { + ctx_data->stack_head->data->unitSize += sizeof(uint16_t); + ctx_data->stack_head->data->dtd = SDP_ALT16; + } else { + ctx_data->stack_head->data->unitSize += sizeof(uint8_t); } - - ret = sdp_data_alloc(dtd, &val); - break; } - case SDP_INT8: - { - int8_t val = strtoul(data, &endptr, 0); + if (ctx_data->stack_head->next && ctx_data->stack_head->data && + ctx_data->stack_head->next->data) { + switch (ctx_data->stack_head->next->data->dtd) { + case SDP_SEQ8: + case SDP_SEQ16: + case SDP_SEQ32: + case SDP_ALT8: + case SDP_ALT16: + case SDP_ALT32: + ctx_data->stack_head->next->data->val.dataseq = + sdp_seq_append(ctx_data->stack_head->next->data->val.dataseq, + ctx_data->stack_head->data); + ctx_data->stack_head->data = NULL; + break; + } - /* Failed to parse */ - if ((endptr != data) && (*endptr != '\0')) - return NULL; + elem = ctx_data->stack_head; + ctx_data->stack_head = ctx_data->stack_head->next; - ret = sdp_data_alloc(dtd, &val); - break; + sdp_xml_data_free(elem); } +} - case SDP_UINT8: - { - uint8_t val = strtoul(data, &endptr, 0); +static GMarkupParser parser = { + element_start, element_end, NULL, NULL, NULL +}; - /* Failed to parse */ - if ((endptr != data) && (*endptr != '\0')) - return NULL; +sdp_record_t *sdp_xml_parse_record(const char *data, int size) +{ + GMarkupParseContext *ctx; + struct context_data *ctx_data; + sdp_record_t *record; - ret = sdp_data_alloc(dtd, &val); - break; + ctx_data = malloc(sizeof(*ctx_data)); + if (!ctx_data) + return NULL; + + record = sdp_record_alloc(); + if (!record) { + free(ctx_data); + return NULL; } - case SDP_INT16: - { - int16_t val = strtoul(data, &endptr, 0); + memset(ctx_data, 0, sizeof(*ctx_data)); + ctx_data->record = record; - /* Failed to parse */ - if ((endptr != data) && (*endptr != '\0')) - return NULL; + ctx = g_markup_parse_context_new(&parser, 0, ctx_data, NULL); - ret = sdp_data_alloc(dtd, &val); - break; + if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) { + error("XML parsing error"); + g_markup_parse_context_free(ctx); + sdp_record_free(record); + free(ctx_data); + return NULL; } - case SDP_UINT16: - { - uint16_t val = strtoul(data, &endptr, 0); + g_markup_parse_context_free(ctx); - /* Failed to parse */ - if ((endptr != data) && (*endptr != '\0')) - return NULL; + free(ctx_data); - ret = sdp_data_alloc(dtd, &val); - break; - } + return record; +} - case SDP_INT32: - { - int32_t val = strtoul(data, &endptr, 0); - /* Failed to parse */ - if ((endptr != data) && (*endptr != '\0')) - return NULL; +static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level, + void *data, void (*appender)(void *, const char *)) +{ + int i, hex; + char buf[STRBUFSIZE]; + char indent[MAXINDENT]; - ret = sdp_data_alloc(dtd, &val); - break; - } + if (!value) + return; - case SDP_UINT32: - { - uint32_t val = strtoul(data, &endptr, 0); + if (indent_level >= MAXINDENT) + indent_level = MAXINDENT - 2; - /* Failed to parse */ - if ((endptr != data) && (*endptr != '\0')) - return NULL; + for (i = 0; i < indent_level; i++) + indent[i] = '\t'; - ret = sdp_data_alloc(dtd, &val); - break; - } + indent[i] = '\0'; + buf[STRBUFSIZE - 1] = '\0'; - case SDP_INT64: - { - int64_t val = strtoull(data, &endptr, 0); + switch (value->dtd) { + case SDP_DATA_NIL: + appender(data, indent); + appender(data, "\n"); + break; - /* Failed to parse */ - if ((endptr != data) && (*endptr != '\0')) - return NULL; + case SDP_BOOL: + appender(data, indent); + appender(data, "val.uint8 ? "true" : "false"); + appender(data, "\" />\n"); + break; - ret = sdp_data_alloc(dtd, &val); + case SDP_UINT8: + appender(data, indent); + appender(data, "val.uint8); + appender(data, buf); + appender(data, "\" />\n"); break; - } - case SDP_UINT64: - { - uint64_t val = strtoull(data, &endptr, 0); + case SDP_UINT16: + appender(data, indent); + appender(data, "val.uint16); + appender(data, buf); + appender(data, "\" />\n"); + break; - /* Failed to parse */ - if ((endptr != data) && (*endptr != '\0')) - return NULL; + case SDP_UINT32: + appender(data, indent); + appender(data, "val.uint32); + appender(data, buf); + appender(data, "\" />\n"); + break; - ret = sdp_data_alloc(dtd, &val); + case SDP_UINT64: + appender(data, indent); + appender(data, "val.uint64); + appender(data, buf); + appender(data, "\" />\n"); break; - } - case SDP_INT128: case SDP_UINT128: - { - uint128_t val; - int i = 0; - char buf[3]; + appender(data, indent); + appender(data, "val.uint128.data[i]); + } - for (; i < 32; i += 2) { - buf[0] = data[i]; - buf[1] = data[i + 1]; + appender(data, buf); + appender(data, "\" />\n"); + break; - val.data[i >> 1] = strtoul(buf, 0, 16); - } + case SDP_INT8: + appender(data, indent); + appender(data, "val.int8); + appender(data, buf); + appender(data, "\" />\n"); + break; - ret = sdp_data_alloc(dtd, &val); + case SDP_INT16: + appender(data, indent); + appender(data, "val.int16); + appender(data, buf); + appender(data, "\" />\n"); break; - } - }; + case SDP_INT32: + appender(data, indent); + appender(data, "val.int32); + appender(data, buf); + appender(data, "\" />\n"); + break; - return ret; -} + case SDP_INT64: + appender(data, indent); + appender(data, "val.int64); + appender(data, buf); + appender(data, "\" />\n"); + break; -static char *sdp_xml_parse_string_decode(const char *data, char encoding, uint32_t *length) -{ - int len = strlen(data); - char *text; + case SDP_INT128: + appender(data, indent); + appender(data, "val.int128.data[i]); + } + appender(data, buf); - decoded = malloc((len >> 1) + 1); + appender(data, "\" />\n"); + break; - /* Ensure the string is a power of 2 */ - len = (len >> 1) << 1; + case SDP_UUID16: + appender(data, indent); + appender(data, "val.uuid.value.uuid16); + appender(data, buf); + appender(data, "\" />\n"); + break; - buf[2] = '\0'; + case SDP_UUID32: + appender(data, indent); + appender(data, "val.uuid.value.uuid32); + appender(data, buf); + appender(data, "\" />\n"); + break; - for (i = 0; i < len; i += 2) { - buf[0] = data[i]; - buf[1] = data[i + 1]; + case SDP_UUID128: + appender(data, indent); + appender(data, "> 1] = strtoul(buf, 0, 16); - } + snprintf(buf, STRBUFSIZE - 1, + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (unsigned char) value->val.uuid.value. + uuid128.data[0], + (unsigned char) value->val.uuid.value. + uuid128.data[1], + (unsigned char) value->val.uuid.value. + uuid128.data[2], + (unsigned char) value->val.uuid.value. + uuid128.data[3], + (unsigned char) value->val.uuid.value. + uuid128.data[4], + (unsigned char) value->val.uuid.value. + uuid128.data[5], + (unsigned char) value->val.uuid.value. + uuid128.data[6], + (unsigned char) value->val.uuid.value. + uuid128.data[7], + (unsigned char) value->val.uuid.value. + uuid128.data[8], + (unsigned char) value->val.uuid.value. + uuid128.data[9], + (unsigned char) value->val.uuid.value. + uuid128.data[10], + (unsigned char) value->val.uuid.value. + uuid128.data[11], + (unsigned char) value->val.uuid.value. + uuid128.data[12], + (unsigned char) value->val.uuid.value. + uuid128.data[13], + (unsigned char) value->val.uuid.value. + uuid128.data[14], + (unsigned char) value->val.uuid.value. + uuid128.data[15]); - decoded[len >> 1] = '\0'; - text = decoded; - *length = len >> 1; - } + appender(data, buf); + appender(data, "\" />\n"); + break; - return text; -} + case SDP_TEXT_STR8: + case SDP_TEXT_STR16: + case SDP_TEXT_STR32: + { + int num_chars_to_escape = 0; + int length = value->unitSize - 1; + char *strBuf = 0; -sdp_data_t *sdp_xml_parse_url(const char *data) -{ - uint8_t dtd = SDP_URL_STR8; - char *url; - uint32_t length; - sdp_data_t *ret; + hex = 0; - url = sdp_xml_parse_string_decode(data, - SDP_XML_ENCODING_NORMAL, &length); + for (i = 0; i < length; i++) { + if (!isprint(value->val.str[i]) && + value->val.str[i] != '\0') { + hex = 1; + break; + } - if (length > UCHAR_MAX) - dtd = SDP_URL_STR16; + /* XML is evil, must do this... */ + if ((value->val.str[i] == '<') || + (value->val.str[i] == '>') || + (value->val.str[i] == '"') || + (value->val.str[i] == '&')) + num_chars_to_escape++; + } - ret = sdp_data_alloc_with_length(dtd, url, length); + appender(data, indent); - free(url); + appender(data, "unitSize-1) * 2 + 1)); -sdp_data_t *sdp_xml_parse_text(const char *data, char encoding) -{ - uint8_t dtd = SDP_TEXT_STR8; - char *text; - uint32_t length; - sdp_data_t *ret; + /* Unit Size seems to include the size for dtd + It is thus off by 1 + This is safe for Normal strings, but not + hex encoded data */ + for (i = 0; i < (value->unitSize-1); i++) + sprintf(&strBuf[i*sizeof(char)*2], + "%02x", + (unsigned char) value->val.str[i]); - text = sdp_xml_parse_string_decode(data, encoding, &length); + strBuf[(value->unitSize-1) * 2] = '\0'; + } else { + int j; + /* escape the XML disallowed chars */ + strBuf = malloc(sizeof(char) * + (value->unitSize + 1 + num_chars_to_escape * 4)); + for (i = 0, j = 0; i < length; i++) { + if (value->val.str[i] == '&') { + strBuf[j++] = '&'; + strBuf[j++] = 'a'; + strBuf[j++] = 'm'; + strBuf[j++] = 'p'; + } else if (value->val.str[i] == '<') { + strBuf[j++] = '&'; + strBuf[j++] = 'l'; + strBuf[j++] = 't'; + } else if (value->val.str[i] == '>') { + strBuf[j++] = '&'; + strBuf[j++] = 'g'; + strBuf[j++] = 't'; + } else if (value->val.str[i] == '"') { + strBuf[j++] = '&'; + strBuf[j++] = 'q'; + strBuf[j++] = 'u'; + strBuf[j++] = 'o'; + strBuf[j++] = 't'; + } else if (value->val.str[i] == '\0') { + strBuf[j++] = ' '; + } else { + strBuf[j++] = value->val.str[i]; + } + } - if (length > UCHAR_MAX) - dtd = SDP_TEXT_STR16; + strBuf[j] = '\0'; + } - ret = sdp_data_alloc_with_length(dtd, text, length); + appender(data, "value=\""); + appender(data, strBuf); + appender(data, "\" />\n"); + free(strBuf); + break; + } - free(text); + case SDP_URL_STR8: + case SDP_URL_STR16: + case SDP_URL_STR32: + { + char *strBuf; - return ret; -} + appender(data, indent); + appender(data, "val.str, value->unitSize - 1); + appender(data, strBuf); + free(strBuf); + appender(data, "\" />\n"); + break; + } -sdp_data_t *sdp_xml_parse_nil(const char *data) -{ - return sdp_data_alloc(SDP_DATA_NIL, 0); -} + case SDP_SEQ8: + case SDP_SEQ16: + case SDP_SEQ32: + appender(data, indent); + appender(data, "\n"); -#define DEFAULT_XML_DATA_SIZE 1024 + convert_raw_data_to_xml(value->val.dataseq, + indent_level + 1, data, appender); -struct sdp_xml_data *sdp_xml_data_alloc(void) -{ - struct sdp_xml_data *elem; + appender(data, indent); + appender(data, "\n"); - elem = malloc(sizeof(struct sdp_xml_data)); - if (!elem) - return NULL; + break; - memset(elem, 0, sizeof(struct sdp_xml_data)); + case SDP_ALT8: + case SDP_ALT16: + case SDP_ALT32: + appender(data, indent); - /* Null terminate the text */ - elem->size = DEFAULT_XML_DATA_SIZE; - elem->text = malloc(DEFAULT_XML_DATA_SIZE); - elem->text[0] = '\0'; + appender(data, "\n"); - return elem; -} + convert_raw_data_to_xml(value->val.dataseq, + indent_level + 1, data, appender); + appender(data, indent); -void sdp_xml_data_free(struct sdp_xml_data *elem) -{ - if (elem->data) - sdp_data_free(elem->data); + appender(data, "\n"); - free(elem->name); - free(elem->text); - free(elem); + break; + } + + convert_raw_data_to_xml(value->next, indent_level, data, appender); } -struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem) -{ - char *newbuf; +struct conversion_data { + void *data; + void (*appender)(void *data, const char *); +}; - newbuf = malloc(elem->size * 2); - if (!newbuf) - return NULL; +static void convert_raw_attr_to_xml_func(void *val, void *data) +{ + struct conversion_data *cd = data; + sdp_data_t *value = val; + char buf[STRBUFSIZE]; - memcpy(newbuf, elem->text, elem->size); - elem->size *= 2; - free(elem->text); + buf[STRBUFSIZE - 1] = '\0'; + snprintf(buf, STRBUFSIZE - 1, "\t\n", + value->attrId); + cd->appender(cd->data, buf); - elem->text = newbuf; + convert_raw_data_to_xml(value, 2, cd->data, cd->appender); - return elem; + cd->appender(cd->data, "\t\n"); } -sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem, - sdp_record_t *record) +/* + * Will convert the sdp record to XML. The appender and data can be used + * to control where to output the record (e.g. file or a data buffer). The + * appender will be called repeatedly with data and the character buffer + * (containing parts of the generated XML) to append. + */ +void convert_sdp_record_to_xml(sdp_record_t *rec, + void *data, void (*appender)(void *, const char *)) { - const char *data = elem->text; + struct conversion_data cd; - if (!strcmp(el, "boolean")) - return sdp_xml_parse_int(data, SDP_BOOL); - else if (!strcmp(el, "uint8")) - return sdp_xml_parse_int(data, SDP_UINT8); - else if (!strcmp(el, "uint16")) - return sdp_xml_parse_int(data, SDP_UINT16); - else if (!strcmp(el, "uint32")) - return sdp_xml_parse_int(data, SDP_UINT32); - else if (!strcmp(el, "uint64")) - return sdp_xml_parse_int(data, SDP_UINT64); - else if (!strcmp(el, "uint128")) - return sdp_xml_parse_int(data, SDP_UINT128); - else if (!strcmp(el, "int8")) - return sdp_xml_parse_int(data, SDP_INT8); - else if (!strcmp(el, "int16")) - return sdp_xml_parse_int(data, SDP_INT16); - else if (!strcmp(el, "int32")) - return sdp_xml_parse_int(data, SDP_INT32); - else if (!strcmp(el, "int64")) - return sdp_xml_parse_int(data, SDP_INT64); - else if (!strcmp(el, "int128")) - return sdp_xml_parse_int(data, SDP_INT128); - else if (!strcmp(el, "uuid")) - return sdp_xml_parse_uuid(data, record); - else if (!strcmp(el, "url")) - return sdp_xml_parse_url(data); - else if (!strcmp(el, "text")) - return sdp_xml_parse_text(data, elem->type); - else if (!strcmp(el, "nil")) - return sdp_xml_parse_nil(data); + cd.data = data; + cd.appender = appender; - return NULL; + if (rec && rec->attrlist) { + appender(data, "\n\n"); + appender(data, "\n"); + sdp_list_foreach(rec->attrlist, + convert_raw_attr_to_xml_func, &cd); + appender(data, "\n"); + } } + diff --git a/src/sdp-xml.h b/src/sdp-xml.h index 49efc3986..d393f94b1 100644 --- a/src/sdp-xml.h +++ b/src/sdp-xml.h @@ -33,29 +33,6 @@ void convert_sdp_record_to_xml(sdp_record_t *rec, void *user_data, void (*append_func) (void *, const char *)); -sdp_data_t *sdp_xml_parse_nil(const char *data); -sdp_data_t *sdp_xml_parse_text(const char *data, char encoding); -sdp_data_t *sdp_xml_parse_url(const char *data); -sdp_data_t *sdp_xml_parse_int(const char *data, uint8_t dtd); -sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record); - -struct sdp_xml_data { - char *text; /* Pointer to the current buffer */ - int size; /* Size of the current buffer */ - sdp_data_t *data; /* The current item being built */ - struct sdp_xml_data *next; /* Next item on the stack */ - char type; /* 0 = Text or Hexadecimal */ - char *name; /* Name, optional in the dtd */ - /* TODO: What is it used for? */ -}; - -struct sdp_xml_data *sdp_xml_data_alloc(void); -void sdp_xml_data_free(struct sdp_xml_data *elem); -struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem); - -sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem, - sdp_record_t *record); - sdp_record_t *sdp_xml_parse_record(const char *data, int size); #endif /* __SDP_XML_H */ -- 2.47.3