From 7148b778209aaaf684c156c5e2e40d6e477f13f7 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Sun, 7 Jul 2024 16:11:08 +0200 Subject: [PATCH] parser: Optimize memory buffer I/O Reenable zero-copy IO for zero-terminated static memory buffers. Don't stream zero-terminated dynamic memory buffers on top of creating a copy. --- parser.c | 8 +++- xmlIO.c | 118 ++++++++++++++++++++----------------------------------- 2 files changed, 49 insertions(+), 77 deletions(-) diff --git a/parser.c b/parser.c index b35e804e..49dfa7e4 100644 --- a/parser.c +++ b/parser.c @@ -7988,13 +7988,17 @@ xmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) { } length = xmlBufUse(input->buf->buffer); - content = xmlBufDetach(input->buf->buffer); - if (length > INT_MAX) { xmlErrMemory(ctxt); goto error; } + content = xmlStrndup(xmlBufContent(input->buf->buffer), length); + if (content == NULL) { + xmlErrMemory(ctxt); + goto error; + } + for (i = 0; i < length; ) { int clen = length - i; int c = xmlGetUTF8Char(content + i, &clen); diff --git a/xmlIO.c b/xmlIO.c index 8df36a69..e8a9ae7f 100644 --- a/xmlIO.c +++ b/xmlIO.c @@ -1748,7 +1748,6 @@ xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) { } typedef struct { - char *mem; const char *cur; size_t size; } xmlMemIOCtxt; @@ -1771,8 +1770,6 @@ static int xmlMemClose(void *vctxt) { xmlMemIOCtxt *ctxt = vctxt; - if (ctxt->mem != NULL) - xmlFree(ctxt->mem); xmlFree(ctxt); return(0); } @@ -1792,42 +1789,46 @@ xmlParserInputBufferPtr xmlNewInputBufferMemory(const void *mem, size_t size, int flags, xmlCharEncoding enc) { xmlParserInputBufferPtr ret; - xmlMemIOCtxt *ctxt; - char *copy = NULL; - if ((flags & XML_INPUT_BUF_STATIC) == 0) { - if (size + 1 == 0) + if ((flags & XML_INPUT_BUF_STATIC) && + ((flags & XML_INPUT_BUF_ZERO_TERMINATED) == 0)) { + xmlMemIOCtxt *ctxt; + + /* + * Static buffer without zero terminator. + * Stream memory to avoid a copy. + */ + ret = xmlAllocParserInputBuffer(enc); + if (ret == NULL) return(NULL); - copy = xmlMalloc(size + 1); - if (copy == NULL) + + ctxt = xmlMalloc(sizeof(*ctxt)); + if (ctxt == NULL) { + xmlFreeParserInputBuffer(ret); return(NULL); - memcpy(copy, mem, size); - copy[size] = 0; + } - mem = copy; + ctxt->cur = mem; + ctxt->size = size; + + ret->context = ctxt; + ret->readcallback = xmlMemRead; + ret->closecallback = xmlMemClose; + } else { + ret = xmlMalloc(sizeof(*ret)); + if (ret == NULL) + return(NULL); + memset(ret, 0, sizeof(xmlParserInputBuffer)); + ret->compressed = -1; + + ret->buffer = xmlBufCreateMem((const xmlChar *) mem, size, + (flags & XML_INPUT_BUF_STATIC ? 1 : 0)); + if (ret->buffer == NULL) { + xmlFree(ret); + return(NULL); + } } - ret = xmlAllocParserInputBuffer(enc); - if (ret == NULL) { - xmlFree(copy); - return(NULL); - } - - ctxt = xmlMalloc(sizeof(*ctxt)); - if (ctxt == NULL) { - xmlFreeParserInputBuffer(ret); - xmlFree(copy); - return(NULL); - } - - ctxt->mem = copy; - ctxt->cur = mem; - ctxt->size = size; - - ret->context = ctxt; - ret->readcallback = xmlMemRead; - ret->closecallback = xmlMemClose; - return(ret); } @@ -1889,31 +1890,6 @@ xmlParserInputBufferCreateStatic(const char *mem, int size, return(xmlNewInputBufferMemory(mem, size, XML_INPUT_BUF_STATIC, enc)); } -typedef struct { - const char *str; -} xmlStringIOCtxt; - -static int -xmlStringRead(void *vctxt, char *buf, int size) { - xmlStringIOCtxt *ctxt = vctxt; - const char *zero; - size_t len; - - zero = memchr(ctxt->str, 0, size); - len = zero ? zero - ctxt->str : size; - - memcpy(buf, ctxt->str, len); - ctxt->str += len; - - return(len); -} - -static int -xmlStringClose(void *vctxt) { - xmlFree(vctxt); - return(0); -} - /** * xmlNewInputBufferString: * @str: C string @@ -1926,28 +1902,20 @@ xmlStringClose(void *vctxt) { xmlParserInputBufferPtr xmlNewInputBufferString(const char *str, int flags) { xmlParserInputBufferPtr ret; - xmlStringIOCtxt *ctxt; - if ((flags & XML_INPUT_BUF_STATIC) == 0) - return(xmlNewInputBufferMemory(str, strlen(str), flags, - XML_CHAR_ENCODING_NONE)); - - ret = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE); + ret = xmlMalloc(sizeof(*ret)); if (ret == NULL) - return(NULL); + return(NULL); + memset(ret, 0, sizeof(xmlParserInputBuffer)); + ret->compressed = -1; - ctxt = xmlMalloc(sizeof(*ctxt)); - if (ctxt == NULL) { - xmlFreeParserInputBuffer(ret); - return(NULL); + ret->buffer = xmlBufCreateMem((const xmlChar *) str, strlen(str), + (flags & XML_INPUT_BUF_STATIC ? 1 : 0)); + if (ret->buffer == NULL) { + xmlFree(ret); + return(NULL); } - ctxt->str = str; - - ret->context = ctxt; - ret->readcallback = xmlStringRead; - ret->closecallback = xmlStringClose; - return(ret); }