parser/expat: provide memory handling suite for 1 ctx
Libstrophe doesn't override memory allocation functions in XML libraries and default allocators are used as result. Current patch solves this issue partially for expat module. The module caches 1st strophe context and overrides expat's allocator for parsers within this context. For all other contexts, fallback to default allocator. This is modified version of solution from UnrealEngine project.
This commit is contained in:
@@ -23,9 +23,6 @@
|
||||
#include "common.h"
|
||||
#include "parser.h"
|
||||
|
||||
/* Use the Unit Separator to delimit namespace and name in our XML*/
|
||||
#define NAMESPACE_SEP ('\x1F')
|
||||
|
||||
/* Allocate inner text by this number bytes more. Expat splits string
|
||||
* "new\nline" into 3 strings: "new" "\n" "line". Expecting this pattern,
|
||||
* we can leave few bytes in the inner_text for "\n". It should reduce
|
||||
@@ -48,6 +45,46 @@ struct _parser_t {
|
||||
int inner_text_used;
|
||||
};
|
||||
|
||||
/* Use the Unit Separator to delimit namespace and name in our XML */
|
||||
const XML_Char namespace_sep = '\x1F';
|
||||
|
||||
/*
|
||||
* Cached strophe ctx. It is used for memory suite.
|
||||
* Note, expat doesn't support userdata in memory suite, therefore,
|
||||
* we can support only one strophe context. If user creates more than one
|
||||
* context, this module will fallback to default library allocator for all
|
||||
* contexts other than mem_ctx.
|
||||
*/
|
||||
static xmpp_ctx_t *mem_ctx = NULL;
|
||||
|
||||
static void *parser_mem_malloc(size_t size)
|
||||
{
|
||||
if (mem_ctx != NULL)
|
||||
return xmpp_alloc(mem_ctx, size);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *parser_mem_realloc(void *ptr, size_t size)
|
||||
{
|
||||
if (mem_ctx != NULL)
|
||||
return xmpp_realloc(mem_ctx, ptr, size);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void parser_mem_free(void *ptr)
|
||||
{
|
||||
if (mem_ctx != NULL)
|
||||
xmpp_free(mem_ctx, ptr);
|
||||
}
|
||||
|
||||
static const XML_Memory_Handling_Suite parser_mem_suite = {
|
||||
.malloc_fcn = &parser_mem_malloc,
|
||||
.realloc_fcn = &parser_mem_realloc,
|
||||
.free_fcn = &parser_mem_free,
|
||||
};
|
||||
|
||||
/* return allocated string with the name from a delimited
|
||||
* namespace/name string */
|
||||
static char *_xml_name(xmpp_ctx_t *ctx, const char *nsname)
|
||||
@@ -56,7 +93,7 @@ static char *_xml_name(xmpp_ctx_t *ctx, const char *nsname)
|
||||
const char *c;
|
||||
size_t len;
|
||||
|
||||
c = strchr(nsname, NAMESPACE_SEP);
|
||||
c = strchr(nsname, namespace_sep);
|
||||
if (c == NULL) return xmpp_strdup(ctx, nsname);
|
||||
|
||||
c++;
|
||||
@@ -76,7 +113,7 @@ static char *_xml_namespace(xmpp_ctx_t *ctx, const char *nsname)
|
||||
char *result = NULL;
|
||||
const char *c;
|
||||
|
||||
c = strchr(nsname, NAMESPACE_SEP);
|
||||
c = strchr(nsname, namespace_sep);
|
||||
if (c != NULL) {
|
||||
result = xmpp_alloc(ctx, (c-nsname) + 1);
|
||||
if (result != NULL) {
|
||||
@@ -273,23 +310,38 @@ void parser_free(parser_t *parser)
|
||||
/* shuts down and restarts XML parser. true on success */
|
||||
int parser_reset(parser_t *parser)
|
||||
{
|
||||
if (parser->expat)
|
||||
XML_ParserFree(parser->expat);
|
||||
XML_Bool ret;
|
||||
const XML_Memory_Handling_Suite *mem = NULL;
|
||||
|
||||
if (parser->stanza)
|
||||
xmpp_stanza_release(parser->stanza);
|
||||
if (parser->expat) {
|
||||
ret = XML_ParserReset(parser->expat, NULL);
|
||||
if (ret != XML_TRUE) {
|
||||
XML_ParserFree(parser->expat);
|
||||
parser->expat = NULL;
|
||||
}
|
||||
} else {
|
||||
if (mem_ctx == NULL)
|
||||
mem_ctx = parser->ctx;
|
||||
if (parser->ctx == mem_ctx)
|
||||
mem = &parser_mem_suite;
|
||||
parser->expat = XML_ParserCreate_MM(NULL, mem, &namespace_sep);
|
||||
}
|
||||
|
||||
parser->expat = XML_ParserCreateNS(NULL, NAMESPACE_SEP);
|
||||
if (!parser->expat) return 0;
|
||||
|
||||
parser->depth = 0;
|
||||
parser->stanza = NULL;
|
||||
if (parser->stanza) {
|
||||
xmpp_stanza_release(parser->stanza);
|
||||
parser->stanza = NULL;
|
||||
}
|
||||
|
||||
if (parser->inner_text) {
|
||||
xmpp_free (parser->ctx, parser->inner_text);
|
||||
xmpp_free(parser->ctx, parser->inner_text);
|
||||
parser->inner_text = NULL;
|
||||
}
|
||||
|
||||
if (!parser->expat)
|
||||
return 0;
|
||||
|
||||
parser->depth = 0;
|
||||
|
||||
XML_SetUserData(parser->expat, parser);
|
||||
XML_SetElementHandler(parser->expat, _start_element, _end_element);
|
||||
XML_SetCharacterDataHandler(parser->expat, _characters);
|
||||
|
||||
Reference in New Issue
Block a user