#include "sdp-xml.h" #include #include #include #include #include #define STRBUFSIZE 256 #define MAXINDENT 64 static void convert_raw_data_to_xml(sdp_data_t * data, int indentLevel, void *userData, void (*appendFunc) (void *, const char *)) { int i, hex; char buf[STRBUFSIZE]; char indent[MAXINDENT]; char indentPlusOne[MAXINDENT]; if (!data) return; if (indentLevel >= MAXINDENT) indentLevel = MAXINDENT - 2; for (i = 0; i < indentLevel; i++) { indent[i] = '\t'; indentPlusOne[i] = '\t'; } indent[i] = '\0'; indentPlusOne[i] = '\t'; indentPlusOne[i + 1] = '\0'; buf[STRBUFSIZE - 1] = '\0'; switch (data->dtd) { case SDP_DATA_NIL: appendFunc(userData, indent); appendFunc(userData, "\n"); break; case SDP_BOOL: appendFunc(userData, indent); appendFunc(userData, "val.uint8 ? "True" : "False"); appendFunc(userData, "\" />\n"); break; case SDP_UINT8: appendFunc(userData, indent); appendFunc(userData, "val.uint8); appendFunc(userData, buf); appendFunc(userData, "\" />\n"); break; case SDP_UINT16: appendFunc(userData, indent); appendFunc(userData, "val.uint16); appendFunc(userData, buf); appendFunc(userData, "\" />\n"); break; case SDP_UINT32: appendFunc(userData, indent); appendFunc(userData, "val.uint32); appendFunc(userData, buf); appendFunc(userData, "\" />\n"); break; case SDP_UINT64: appendFunc(userData, indent); appendFunc(userData, "val.uint64); appendFunc(userData, buf); appendFunc(userData, "\" />\n"); break; case SDP_UINT128: appendFunc(userData, indent); appendFunc(userData, "val.uint128.data[i]); } appendFunc(userData, buf); appendFunc(userData, "\" />\n"); break; case SDP_INT8: appendFunc(userData, indent); appendFunc(userData, "val.int8); appendFunc(userData, buf); appendFunc(userData, "\" />\n"); break; case SDP_INT16: appendFunc(userData, indent); appendFunc(userData, "val.int16); appendFunc(userData, buf); appendFunc(userData, "\" />\n"); break; case SDP_INT32: appendFunc(userData, indent); appendFunc(userData, "val.int32); appendFunc(userData, buf); appendFunc(userData, "\" />\n"); break; case SDP_INT64: appendFunc(userData, indent); appendFunc(userData, "val.int64); appendFunc(userData, buf); appendFunc(userData, "\" />\n"); break; case SDP_INT128: appendFunc(userData, indent); appendFunc(userData, "val.int128.data[i]); } appendFunc(userData, buf); appendFunc(userData, "\" />\n"); break; case SDP_UUID16: appendFunc(userData, indent); appendFunc(userData, "val.uuid.value.uuid16); appendFunc(userData, buf); appendFunc(userData, "\" />\n"); break; case SDP_UUID32: appendFunc(userData, indent); appendFunc(userData, "val.uuid.value.uuid32); appendFunc(userData, buf); appendFunc(userData, "\" />\n"); break; case SDP_UUID128: appendFunc(userData, indent); appendFunc(userData, "val.uuid.value. uuid128.data[0], (unsigned char) data->val.uuid.value. uuid128.data[1], (unsigned char) data->val.uuid.value. uuid128.data[2], (unsigned char) data->val.uuid.value. uuid128.data[3], (unsigned char) data->val.uuid.value. uuid128.data[4], (unsigned char) data->val.uuid.value. uuid128.data[5], (unsigned char) data->val.uuid.value. uuid128.data[6], (unsigned char) data->val.uuid.value. uuid128.data[7], (unsigned char) data->val.uuid.value. uuid128.data[8], (unsigned char) data->val.uuid.value. uuid128.data[9], (unsigned char) data->val.uuid.value. uuid128.data[10], (unsigned char) data->val.uuid.value. uuid128.data[11], (unsigned char) data->val.uuid.value. uuid128.data[12], (unsigned char) data->val.uuid.value. uuid128.data[13], (unsigned char) data->val.uuid.value. uuid128.data[14], (unsigned char) data->val.uuid.value. uuid128.data[15]); appendFunc(userData, "\" />\n"); break; case SDP_TEXT_STR8: case SDP_TEXT_STR16: case SDP_TEXT_STR32: { hex = 0; for (i = 0; i < data->unitSize; i++) { if (i == (data->unitSize - 1) && data->val.str[i] == '\0') break; if (!isalnum(data->val.str[i]) && (data->val.str[i] != ' ')) { hex = 1; break; } } appendFunc(userData, indent); appendFunc(userData, "dtd) { case SDP_TEXT_STR8: appendFunc(userData, "type=\"text8\" "); break; case SDP_TEXT_STR16: appendFunc(userData, "type=\"text16\" "); break; case SDP_TEXT_STR32: appendFunc(userData, "type=\"text32\" "); break; }; char *strBuf = 0; if (hex) { appendFunc(userData, "encoding=\"hex\" "); strBuf = (char *) malloc(sizeof(char) * (data->unitSize * 2 + 1)); // 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 < (data->unitSize-1); i++) sprintf(&strBuf[i * sizeof (char) * 2], "%02x", (unsigned char) data->val.str[i]); strBuf[data->unitSize * 2] = '\0'; } else { strBuf = (char *) malloc(sizeof(char) * (data->unitSize + 1)); memcpy(strBuf, data->val.str, data->unitSize); strBuf[data->unitSize] = '\0'; } appendFunc(userData, "value=\""); appendFunc(userData, strBuf); appendFunc(userData, "\" />\n"); free(strBuf); break; } case SDP_URL_STR8: appendFunc(userData, indent); appendFunc(userData, "val.str); appendFunc(userData, "\" />\n"); break; case SDP_URL_STR16: appendFunc(userData, indent); appendFunc(userData, "val.str); appendFunc(userData, "\" />\n"); case SDP_URL_STR32: appendFunc(userData, indent); appendFunc(userData, "val.str); appendFunc(userData, "\" />\n"); break; case SDP_SEQ8: case SDP_SEQ16: case SDP_SEQ32: appendFunc(userData, indent); switch(data->dtd) { case SDP_SEQ8: appendFunc(userData, "\n"); break; case SDP_SEQ16: appendFunc(userData, "\n"); break; case SDP_SEQ32: appendFunc(userData, "\n"); break; }; convert_raw_data_to_xml(data->val.dataseq, indentLevel + 1, userData, appendFunc); appendFunc(userData, indent); switch(data->dtd) { case SDP_SEQ8: appendFunc(userData, "\n"); break; case SDP_SEQ16: appendFunc(userData, "\n"); break; case SDP_SEQ32: appendFunc(userData, "\n"); break; }; break; case SDP_ALT8: case SDP_ALT16: case SDP_ALT32: appendFunc(userData, indent); switch(data->dtd) { case SDP_ALT8: appendFunc(userData, "\n"); break; case SDP_ALT16: appendFunc(userData, "\n"); break; case SDP_ALT32: appendFunc(userData, "\n"); break; }; convert_raw_data_to_xml(data->val.dataseq, indentLevel + 1, userData, appendFunc); appendFunc(userData, indent); switch(data->dtd) { case SDP_ALT8: appendFunc(userData, "\n"); break; case SDP_ALT16: appendFunc(userData, "\n"); break; case SDP_ALT32: appendFunc(userData, "\n"); break; }; break; default: break; } convert_raw_data_to_xml(data->next, indentLevel, userData, appendFunc); } struct conversion_data { void *userData; void (*appendFunc) (void *userData, const char *); }; static void convert_raw_attr_to_xml_func(void *value, void *userData) { struct conversion_data *cd = (struct conversion_data *) userData; sdp_data_t *data = (sdp_data_t *) value; char buf[STRBUFSIZE]; buf[STRBUFSIZE - 1] = '\0'; snprintf(buf, STRBUFSIZE - 1, "\t\n", data->attrId); cd->appendFunc(cd->userData, buf); if (data) convert_raw_data_to_xml(data, 2, cd->userData, cd->appendFunc); else cd->appendFunc(cd->userData, "\t\tNULL\n"); cd->appendFunc(cd->userData, "\t\n"); } /* Will convert the sdp record to XML. The appendFunc and userData can be used to control where to output the record (e.g. file or a data buffer). The appendFunc will be called repeatedly with userData and the character buffer (containing parts of the generated XML) to append. */ void convert_sdp_record_to_xml(sdp_record_t * rec, void *userData, void (*appendFunc) (void *, const char *)) { struct conversion_data data; data.userData = userData; data.appendFunc = appendFunc; if (rec && rec->attrlist) { appendFunc(userData, "\n"); sdp_list_foreach(rec->attrlist, convert_raw_attr_to_xml_func, &data); appendFunc(userData, "\n"); } } #define DEFAULT_XML_DATA_SIZE 64 static sdp_xml_data_t *sdp_xml_data_alloc() { sdp_xml_data_t *elem; elem = (sdp_xml_data_t *) malloc(sizeof(sdp_xml_data_t)); /* Null terminate the text */ elem->size = DEFAULT_XML_DATA_SIZE; elem->text = (char *) malloc(sizeof(char) * DEFAULT_XML_DATA_SIZE); elem->text[0] = '\0'; elem->next = 0; elem->data = 0; elem->type = 0; return elem; } static void sdp_xml_data_free(sdp_xml_data_t * elem) { if (elem->data) sdp_data_free(elem->data); free(elem->text); free(elem); } static sdp_xml_data_t *sdp_xml_data_expand(sdp_xml_data_t * elem) { char *newbuf; newbuf = (char *) malloc(elem->size * 2); if (!newbuf) return NULL; memcpy(newbuf, elem->text, elem->size); elem->size *= 2; free(elem->text); elem->text = newbuf; return elem; } static void sdp_xml_parse_uuid16(sdp_xml_context * data) { uint16_t val; val = strtol(data->stack_head->text, 0, 16); data->stack_head->data = sdp_data_alloc(SDP_UUID16, &val); } static void sdp_xml_parse_uuid32(sdp_xml_context * data) { uint32_t val; val = strtoll(data->stack_head->text, 0, 16); data->stack_head->data = sdp_data_alloc(SDP_UUID32, &val); } static void sdp_xml_parse_uuid128(sdp_xml_context * data) { uint128_t val; int i; int j; char buf[3]; buf[2] = '\0'; for (j = 0, i = 0; i < strlen(data->stack_head->text); j++) { if (data->stack_head->text[i] == '-') { i++; continue; } buf[0] = data->stack_head->text[i]; buf[1] = data->stack_head->text[i + 1]; val.data[i] = strtoul(buf, 0, 16); i += 2; } data->stack_head->data = sdp_data_alloc(SDP_UUID128, &val); } static void sdp_xml_parse_uuid(sdp_xml_context *data) { int len; len = strlen(data->stack_head->text); if (len == 36) { sdp_xml_parse_uuid128(data); } else { uint32_t val; val = strtoll(data->stack_head->text, 0, 16); if (val > USHRT_MAX) { data->stack_head->data = sdp_data_alloc(SDP_UUID32, &val); } else { uint16_t val2 = val; data->stack_head->data = sdp_data_alloc(SDP_UUID16, &val2); } } } static void sdp_xml_parse_int(sdp_xml_context * data, uint8_t dtd) { switch (dtd) { case SDP_BOOL: { uint8_t val = 0; if (!strcmp("True", data->stack_head->text)) { val = 1; } data->stack_head->data = sdp_data_alloc(dtd, &val); break; } case SDP_INT8: { int8_t val = strtoul(data->stack_head->text, 0, 10); data->stack_head->data = sdp_data_alloc(dtd, &val); break; } case SDP_UINT8: { uint8_t val = strtoul(data->stack_head->text, 0, 16); data->stack_head->data = sdp_data_alloc(dtd, &val); break; } case SDP_INT16: { int16_t val = strtoul(data->stack_head->text, 0, 10); data->stack_head->data = sdp_data_alloc(dtd, &val); break; } case SDP_UINT16: { uint16_t val = strtoul(data->stack_head->text, 0, 16); data->stack_head->data = sdp_data_alloc(dtd, &val); break; } case SDP_INT32: { int32_t val = strtoul(data->stack_head->text, 0, 10); data->stack_head->data = sdp_data_alloc(dtd, &val); break; } case SDP_UINT32: { uint32_t val = strtoul(data->stack_head->text, 0, 16); data->stack_head->data = sdp_data_alloc(dtd, &val); break; } case SDP_INT64: { int64_t val = strtoull(data->stack_head->text, 0, 10); data->stack_head->data = sdp_data_alloc(dtd, &val); break; } case SDP_UINT64: { uint64_t val = strtoull(data->stack_head->text, 0, 16); data->stack_head->data = sdp_data_alloc(dtd, &val); break; } case SDP_INT128: case SDP_UINT128: { uint128_t val; int i = 0; char buf[3]; buf[2] = '\0'; for (; i < 32; i += 2) { buf[0] = data->stack_head->text[i]; buf[1] = data->stack_head->text[i + 1]; val.data[i] = strtoul(buf, 0, 16); } data->stack_head->data = sdp_data_alloc(dtd, &val); break; } }; } static void sdp_xml_parse_url_with_size(sdp_xml_context * data, uint8_t dtd) { data->stack_head->data = sdp_data_alloc(dtd, data->stack_head->text); } static void sdp_xml_parse_url(sdp_xml_context * data) { uint8_t dtd = SDP_URL_STR8; if (strlen(data->stack_head->text) > UCHAR_MAX) { dtd = SDP_URL_STR16; } sdp_xml_parse_url_with_size(data, dtd); } static char * sdp_xml_parse_text_decode(sdp_xml_context *data, char *shouldFree, uint32_t *length) { char *text; if (data->stack_head->type == 0) { text = data->stack_head->text; *length = strlen(text); } else { int len = strlen(data->stack_head->text); char buf[3]; int i; char *decoded = (char *) malloc(sizeof(char) * ((len >> 1) + 1)); fprintf(stderr, "Got a stack_head->text len of: %d(%s)\n", len, data->stack_head->text); fprintf(stderr, "len >> 1 = %d\n", len >> 1); buf[2] = '\0'; for (i = 0; i < len; i += 2) { buf[0] = data->stack_head->text[i]; buf[1] = data->stack_head->text[i + 1]; decoded[i >> 1] = strtoul(buf, 0, 16); fprintf(stderr, "Putting at %d\n", i>>1); } decoded[len >> 1] = '\0'; text = decoded; *shouldFree = 1; *length = len >> 1; } return text; } static void sdp_xml_parse_text_with_size(sdp_xml_context * data, uint8_t dtd) { char shouldFree = 0; char *text; uint32_t length; text = sdp_xml_parse_text_decode(data, &shouldFree, &length); data->stack_head->data = sdp_data_alloc_with_length(dtd, text, length); fprintf(stderr, "Got text of length %d: -->%s<--\n", length, text); fprintf(stderr, "Unit size was: %d\n", data->stack_head->data->unitSize); if (shouldFree) free(text); } static void sdp_xml_parse_text(sdp_xml_context * data) { uint8_t dtd = SDP_TEXT_STR8; char shouldFree = 0; char *text; uint32_t length; text = sdp_xml_parse_text_decode(data, &shouldFree, &length); if (length > UCHAR_MAX) { dtd = SDP_TEXT_STR16; } fprintf(stderr, "Got text of length %d: -->%s<--\n", length, text); fprintf(stderr, "Unit size was: %d\n", data->stack_head->data->unitSize); data->stack_head->data = sdp_data_alloc(dtd, text); if (shouldFree) free(text); } static void sdp_xml_parse_nil(sdp_xml_context * data) { data->stack_head->data = sdp_data_alloc(SDP_DATA_NIL, 0); } static void sdp_xml_parse_datatype(sdp_xml_context * context, const char *el) { if (!strcmp(el, "bool")) { sdp_xml_parse_int(context, SDP_BOOL); } else if (!strcmp(el, "uint8")) { sdp_xml_parse_int(context, SDP_UINT8); } else if (!strcmp(el, "uint16")) { sdp_xml_parse_int(context, SDP_UINT16); } else if (!strcmp(el, "uint32")) { sdp_xml_parse_int(context, SDP_UINT32); } else if (!strcmp(el, "uint64")) { sdp_xml_parse_int(context, SDP_UINT64); } else if (!strcmp(el, "uint128")) { sdp_xml_parse_int(context, SDP_UINT128); } else if (!strcmp(el, "int8")) { sdp_xml_parse_int(context, SDP_INT8); } else if (!strcmp(el, "int16")) { sdp_xml_parse_int(context, SDP_INT16); } else if (!strcmp(el, "int32")) { sdp_xml_parse_int(context, SDP_INT32); } else if (!strcmp(el, "int64")) { sdp_xml_parse_int(context, SDP_INT64); } else if (!strcmp(el, "int128")) { sdp_xml_parse_int(context, SDP_INT128); } else if (!strcmp(el, "uuid16")) { sdp_xml_parse_uuid16(context); } else if (!strcmp(el, "uuid32")) { sdp_xml_parse_uuid32(context); } else if (!strcmp(el, "uuid128")) { sdp_xml_parse_uuid128(context); } else if (!strcmp(el, "uuid")) { sdp_xml_parse_uuid(context); } else if (!strcmp(el, "url")) { sdp_xml_parse_url(context); } else if (!strcmp(el, "url8")) { sdp_xml_parse_url_with_size(context, SDP_URL_STR8); } else if (!strcmp(el, "url16")) { sdp_xml_parse_url_with_size(context, SDP_URL_STR16); } else if (!strcmp(el, "url32")) { sdp_xml_parse_url_with_size(context, SDP_URL_STR32); } else if (!strcmp(el, "text")) { sdp_xml_parse_text(context); } else if (!strcmp(el, "text8")) { sdp_xml_parse_text_with_size(context, SDP_TEXT_STR8); } else if (!strcmp(el, "text16")) { sdp_xml_parse_text_with_size(context, SDP_TEXT_STR16); } else if (!strcmp(el, "text32")) { sdp_xml_parse_text_with_size(context, SDP_TEXT_STR32); } else if (!strcmp(el, "nil")) { sdp_xml_parse_nil(context); } else { printf("Can't parse element: %s\n", el); printf("Gathered data: %s\n", context->stack_head->text); } } static void convert_xml_to_sdp_start(void *data, const char *el, const char **attr) { int i; sdp_xml_context *context = (sdp_xml_context *) data; if (!strcmp(el, "record")) return; if (!strcmp(el, "attribute")) { /* Get the ID */ for (i = 0; attr[i]; i += 1) { if (!strcmp(attr[i], "id")) { context->attrId = strtol(attr[i + 1], 0, 0); break; } } return; } /* Assume every other tag is an element of some sort */ if (context->stack_head) { sdp_xml_data_t *newElem = sdp_xml_data_alloc(); newElem->next = context->stack_head; context->stack_head = newElem; } else { context->stack_head = sdp_xml_data_alloc(); context->stack_head->next = 0; } if (!strcmp(el, "sequence")) { context->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL); } else if (!strcmp(el, "sequence8")) { context->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL); } else if (!strcmp(el, "sequence16")) { context->stack_head->data = sdp_data_alloc(SDP_SEQ16, NULL); } else if (!strcmp(el, "sequence32")) { context->stack_head->data = sdp_data_alloc(SDP_SEQ32, NULL); } else if (!strcmp(el, "alternate")) { context->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL); } else if (!strcmp(el, "alternate8")) { context->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL); } else { const char *type; /* Parse value, datatype, encoding */ for (i = 0; attr[i]; i += 2) { if (!strcmp(attr[i], "type")) { type = attr[i+1]; } if (!strcmp(attr[i], "value")) { int curlen = strlen(context->stack_head->text); int attrlen = strlen(attr[i+1]); /* Ensure we're big enough */ while ((curlen + 1 + attrlen) > context->stack_head->size) { fprintf(stderr, "Growing text\n"); sdp_xml_data_expand(context->stack_head); } memcpy(&context->stack_head->text[curlen], attr[i+1], attrlen); context->stack_head->text[curlen + attrlen] = '\0'; fprintf(stderr, "Text is now: -->%s<--\n", context->stack_head->text); } if (!strcmp(attr[i], "encoding")) { if (!strcmp(attr[i+1], "hex")) context->stack_head->type = 1; } } sdp_xml_parse_datatype(context, type); } } static int compute_seq_size(sdp_data_t *data) { int unitSize = data->unitSize; sdp_data_t *seq = data->val.dataseq; fprintf(stderr, "seq unitSize is: %d\n", unitSize); for (; seq; seq = seq->next) unitSize += seq->unitSize; fprintf(stderr, "seq unitSize is now: %d\n", unitSize); return unitSize; } static void convert_xml_to_sdp_end(void *data, const char *el) { sdp_xml_context *context = (sdp_xml_context *) data; sdp_xml_data_t *elem; if (!strcmp(el, "record")) return; if (!strcmp(el, "attribute")) { if (context->stack_head && context->stack_head->data) { int ret = sdp_attr_add(context->sdprec, context->attrId, context->stack_head->data); if (ret == -1) fprintf(stderr, "Trouble adding attribute\n"); context->stack_head->data = 0; sdp_xml_data_free(context->stack_head); context->stack_head = 0; } else { fprintf(stderr, "No Data for attribute: %d\n", context->attrId); } return; } else if (!strcmp(el, "sequence")) { context->stack_head->data->unitSize = compute_seq_size(context->stack_head->data); if (context->stack_head->data->unitSize > USHRT_MAX) { context->stack_head->data->unitSize += sizeof(uint32_t); context->stack_head->data->dtd = SDP_SEQ32; } else if (context->stack_head->data->unitSize > UCHAR_MAX) { context->stack_head->data->unitSize += sizeof(uint16_t); context->stack_head->data->dtd = SDP_SEQ16; } else { context->stack_head->data->unitSize += sizeof(uint8_t); } } else if (!strcmp(el, "sequence8")) { context->stack_head->data->unitSize = compute_seq_size(context->stack_head->data); context->stack_head->data->unitSize += sizeof(uint8_t); } else if (!strcmp(el, "sequence16")) { context->stack_head->data->unitSize = compute_seq_size(context->stack_head->data); context->stack_head->data->unitSize += sizeof(uint16_t); } else if (!strcmp(el, "sequence32")) { context->stack_head->data->unitSize = compute_seq_size(context->stack_head->data); context->stack_head->data->unitSize += sizeof(uint32_t); } else if (!strcmp(el, "alternate")) { context->stack_head->data->unitSize = compute_seq_size(context->stack_head->data); if (context->stack_head->data->unitSize > USHRT_MAX) { context->stack_head->data->unitSize += sizeof(uint32_t); context->stack_head->data->dtd = SDP_ALT32; } else if (context->stack_head->data->unitSize > UCHAR_MAX) { context->stack_head->data->unitSize += sizeof(uint16_t); context->stack_head->data->dtd = SDP_ALT16; } else { context->stack_head->data->unitSize += sizeof(uint8_t); } } else if (!strcmp(el, "alternate8")) { context->stack_head->data->unitSize = compute_seq_size(context->stack_head->data); context->stack_head->data->unitSize += sizeof(uint8_t); } else if (!strcmp(el, "alternate16")) { context->stack_head->data->unitSize = compute_seq_size(context->stack_head->data); context->stack_head->data->unitSize += sizeof(uint16_t); } else if (!strcmp(el, "alternate32")) { context->stack_head->data->unitSize = compute_seq_size(context->stack_head->data); context->stack_head->data->unitSize += sizeof(uint32_t); } /* If we're not inside a seq or alt, then we're inside an attribute which will be taken care of later */ if (context->stack_head->next && context->stack_head->data && context->stack_head->next->data) { switch (context->stack_head->next->data->dtd) { case SDP_SEQ8: case SDP_SEQ16: case SDP_SEQ32: case SDP_ALT8: case SDP_ALT16: case SDP_ALT32: context->stack_head->next->data->val. dataseq = sdp_seq_append(context-> stack_head-> next->data-> val.dataseq, context->stack_head->data); context->stack_head->data = 0; break; } elem = context->stack_head; context->stack_head = context->stack_head->next; sdp_xml_data_free(elem); } } sdp_xml_context *sdp_xml_init_context() { sdp_xml_context *context = 0; context = (sdp_xml_context *) malloc(sizeof(sdp_xml_context)); if (!context) return NULL; context->parser = 0; context->sdprec = 0; context->stack_head = 0; context->parser = XML_ParserCreate(NULL); XML_SetElementHandler(context->parser, convert_xml_to_sdp_start, convert_xml_to_sdp_end); XML_SetUserData(context->parser, context); if (!context->parser) goto fail; context->sdprec = sdp_record_alloc(); if (!context->sdprec) goto fail; return context; fail: fprintf(stderr, "Failed to allocated context\n"); if (context->parser) free(context->parser); if (context->sdprec) sdp_record_free(context->sdprec); if (context) free(context); return NULL; } /* Should be called after sdp_xml_parse_chunk has been called with the final flag set Returns the resulting sdp_record_t. The returned value will need to be freed by the caller by usig sdp_record_free. */ sdp_record_t *sdp_xml_get_record(sdp_xml_context * context) { sdp_record_t *rec = context->sdprec; context->sdprec = 0; return rec; } /* Frees all data except the sdp_record if the sdp_xml_get_record was called. Otherwise everything is freed. */ void sdp_xml_free_context(sdp_xml_context * context) { sdp_xml_data_t *elem; /* Free the stack */ while (context->stack_head) { elem = context->stack_head; context->stack_head = elem->next; sdp_xml_data_free(elem); } if (context->sdprec) sdp_record_free(context->sdprec); XML_ParserFree(context->parser); free(context); } /* parses an XML chunk. Returns -1 if a parse error occured, and 0 if successful pass final as 1 if the chunk is the final chunk */ int sdp_xml_parse_chunk(sdp_xml_context * context, const char *data, int size, int final) { if (!XML_Parse(context->parser, data, size, final)) { fprintf(stderr, "Parse error at line %d:\n%s\n", XML_GetCurrentLineNumber(context->parser), XML_ErrorString(XML_GetErrorCode(context->parser))); return -1; } return 0; }