1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-03-24 06:50:08 +03:00

buf: Rework xmlBuf code

Always use what the old implementation called the "IO" allocation
scheme, allowing to move the content pointer past the initial
allocation. This is inexpensive and allows efficient shrinking.

Optimize xmlBufGrow, reusing shrunken memory as much as possible.

Simplify xmlBufAdd.

Make xmlBufBackToBuffer return an error on overflow.

Make "size" exclude the terminating NULL byte.

Always provide an initial size.

Reintroduce static buffers.

Remove xmlBufResize and several other functions.
This commit is contained in:
Nick Wellnhofer 2024-07-07 03:01:51 +02:00
parent 2adcde3920
commit a221cd7849
11 changed files with 277 additions and 576 deletions

View File

@ -460,7 +460,8 @@ htmlBufNodeDumpFormat(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur,
int
htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur) {
xmlBufPtr buffer;
size_t ret;
size_t ret1;
int ret2;
if ((buf == NULL) || (cur == NULL))
return(-1);
@ -470,14 +471,13 @@ htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur) {
if (buffer == NULL)
return(-1);
xmlBufSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT);
ret = htmlBufNodeDumpFormat(buffer, doc, cur, 1);
ret1 = htmlBufNodeDumpFormat(buffer, doc, cur, 1);
xmlBufBackToBuffer(buffer);
ret2 = xmlBufBackToBuffer(buffer, buf);
if (ret > INT_MAX)
if ((ret1 == (size_t) -1) || (ret2 < 0))
return(-1);
return((int) ret);
return(ret1 > INT_MAX ? INT_MAX : ret1);
}
/**

719
buf.c
View File

@ -15,16 +15,13 @@
#define IN_LIBXML
#include "libxml.h"
#include <string.h> /* for memset() only ! */
#include <string.h>
#include <limits.h>
#include <ctype.h>
#include <stdlib.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/parserInternals.h> /* for XML_MAX_TEXT_LENGTH */
#include "private/buf.h"
#include "private/error.h"
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t) -1)
@ -32,6 +29,13 @@
#define WITH_BUFFER_COMPAT
#define BUF_FLAG_OOM (1u << 0)
#define BUF_FLAG_OVERFLOW (1u << 1)
#define BUF_FLAG_STATIC (1u << 2)
#define BUF_ERROR(buf) ((buf)->flags & (BUF_FLAG_OOM | BUF_FLAG_OVERFLOW))
#define BUF_STATIC(buf) ((buf)->flags & BUF_FLAG_STATIC)
/**
* xmlBuf:
*
@ -42,14 +46,15 @@
struct _xmlBuf {
xmlChar *content; /* The buffer content UTF8 */
#ifdef WITH_BUFFER_COMPAT
unsigned int compat_use; /* for binary compatibility */
unsigned int compat_size; /* for binary compatibility */
xmlBufferAllocationScheme alloc; /* The realloc method */
xmlChar *contentIO; /* in IO mode we may have a different base */
#endif
xmlChar *mem; /* Start of the allocation */
size_t use; /* The buffer size used */
size_t size; /* The buffer size */
xmlBufferPtr buffer; /* wrapper for an old buffer */
int error; /* an error code if a failure occurred */
size_t maxSize; /* The maximum buffer size */
unsigned flags; /* flags */
};
#ifdef WITH_BUFFER_COMPAT
@ -91,8 +96,8 @@ struct _xmlBuf {
static void
xmlBufMemoryError(xmlBufPtr buf)
{
if (buf->error == 0)
buf->error = XML_ERR_NO_MEMORY;
if (!BUF_ERROR(buf))
buf->flags |= BUF_FLAG_OOM;
}
/**
@ -105,72 +110,96 @@ xmlBufMemoryError(xmlBufPtr buf)
static void
xmlBufOverflowError(xmlBufPtr buf)
{
if (buf->error == 0)
buf->error = XML_ERR_RESOURCE_LIMIT;
if (!BUF_ERROR(buf))
buf->flags |= BUF_FLAG_OVERFLOW;
}
/**
* xmlBufCreate:
*
* routine to create an XML buffer.
* returns the new structure.
*/
xmlBufPtr
xmlBufCreate(void) {
xmlBufPtr ret;
ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
if (ret == NULL)
return(NULL);
ret->use = 0;
ret->error = 0;
ret->buffer = NULL;
ret->size = xmlDefaultBufferSize;
UPDATE_COMPAT(ret);
ret->alloc = xmlBufferAllocScheme;
ret->content = (xmlChar *) xmlMallocAtomic(ret->size);
if (ret->content == NULL) {
xmlFree(ret);
return(NULL);
}
ret->content[0] = 0;
ret->contentIO = NULL;
return(ret);
}
/**
* xmlBufCreateSize:
* @size: initial size of buffer
*
* routine to create an XML buffer.
* returns the new structure.
*/
xmlBufPtr
xmlBufCreateSize(size_t size) {
xmlBufCreate(size_t size) {
xmlBufPtr ret;
if (size == SIZE_MAX)
return(NULL);
ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
ret = xmlMalloc(sizeof(*ret));
if (ret == NULL)
return(NULL);
ret->use = 0;
ret->error = 0;
ret->buffer = NULL;
ret->alloc = xmlBufferAllocScheme;
ret->size = (size ? size + 1 : 0); /* +1 for ending null */
ret->flags = 0;
ret->size = size;
ret->maxSize = SIZE_MAX;
ret->mem = xmlMalloc(ret->size + 1);
if (ret->mem == NULL) {
xmlFree(ret);
return(NULL);
}
ret->content = ret->mem;
ret->content[0] = 0;
UPDATE_COMPAT(ret);
if (ret->size){
ret->content = (xmlChar *) xmlMallocAtomic(ret->size);
if (ret->content == NULL) {
return(ret);
}
/**
* xmlBufCreateMem:
* @mem: a memory area
* @size: size of the buffer excluding terminator
* @isStatic: whether the memory area is static
*
* Create a buffer initialized with memory.
*
* If @isStatic is set, uses the memory area directly as backing store.
* The memory must be zero-terminated and not be modified for the
* lifetime of the buffer. A static buffer can't be grown, modified or
* detached, but it can be shrunk.
*
* Returns a new buffer.
*/
xmlBufPtr
xmlBufCreateMem(const xmlChar *mem, size_t size, int isStatic) {
xmlBufPtr ret;
if (mem == NULL)
return(NULL);
ret = xmlMalloc(sizeof(*ret));
if (ret == NULL)
return(NULL);
if (isStatic) {
/* Check that memory is zero-terminated */
if (mem[size] != 0) {
xmlFree(ret);
return(NULL);
}
ret->content[0] = 0;
} else
ret->content = NULL;
ret->contentIO = NULL;
ret->flags = BUF_FLAG_STATIC;
ret->mem = (xmlChar *) mem;
} else {
ret->flags = 0;
ret->mem = xmlMalloc(size + 1);
if (ret->mem == NULL) {
xmlFree(ret);
return(NULL);
}
memcpy(ret->mem, mem, size);
ret->mem[size] = 0;
}
ret->use = size;
ret->size = size;
ret->maxSize = SIZE_MAX;
ret->content = ret->mem;
UPDATE_COMPAT(ret);
return(ret);
}
@ -188,83 +217,25 @@ xmlChar *
xmlBufDetach(xmlBufPtr buf) {
xmlChar *ret;
if (buf == NULL)
return(NULL);
if (buf->buffer != NULL)
return(NULL);
if (buf->error)
if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
return(NULL);
if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
(buf->content != buf->contentIO)) {
if (buf->content != buf->mem) {
ret = xmlStrndup(buf->content, buf->use);
xmlFree(buf->contentIO);
xmlFree(buf->mem);
} else {
ret = buf->content;
ret = buf->mem;
}
buf->content = NULL;
buf->contentIO = NULL;
buf->mem = NULL;
buf->size = 0;
buf->use = 0;
UPDATE_COMPAT(buf);
return ret;
}
/**
* xmlBufGetAllocationScheme:
* @buf: the buffer
*
* Get the buffer allocation scheme
*
* Returns the scheme or -1 in case of error
*/
int
xmlBufGetAllocationScheme(xmlBufPtr buf) {
if (buf == NULL) {
return(-1);
}
return(buf->alloc);
}
/**
* xmlBufSetAllocationScheme:
* @buf: the buffer to tune
* @scheme: allocation scheme to use
*
* Sets the allocation scheme for this buffer
*
* returns 0 in case of success and -1 in case of failure
*/
int
xmlBufSetAllocationScheme(xmlBufPtr buf,
xmlBufferAllocationScheme scheme) {
if ((buf == NULL) || (buf->error != 0)) {
return(-1);
}
if (buf->alloc == XML_BUFFER_ALLOC_IO)
return(-1);
if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
(scheme == XML_BUFFER_ALLOC_EXACT) ||
(scheme == XML_BUFFER_ALLOC_HYBRID) ||
(scheme == XML_BUFFER_ALLOC_BOUNDED)) {
buf->alloc = scheme;
if (buf->buffer)
buf->buffer->alloc = scheme;
return(0);
}
/*
* Switching a buffer ALLOC_IO has the side effect of initializing
* the contentIO field with the current content
*/
if (scheme == XML_BUFFER_ALLOC_IO) {
buf->alloc = XML_BUFFER_ALLOC_IO;
buf->contentIO = buf->content;
}
return(-1);
}
/**
* xmlBufFree:
* @buf: the buffer to free
@ -274,16 +245,11 @@ xmlBufSetAllocationScheme(xmlBufPtr buf,
*/
void
xmlBufFree(xmlBufPtr buf) {
if (buf == NULL) {
if (buf == NULL)
return;
}
if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
(buf->contentIO != NULL)) {
xmlFree(buf->contentIO);
} else if (buf->content != NULL) {
xmlFree(buf->content);
}
if (!BUF_STATIC(buf))
xmlFree(buf->mem);
xmlFree(buf);
}
@ -295,20 +261,17 @@ xmlBufFree(xmlBufPtr buf) {
*/
void
xmlBufEmpty(xmlBufPtr buf) {
if ((buf == NULL) || (buf->error != 0)) return;
if (buf->content == NULL) return;
if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
return;
if (buf->mem == NULL)
return;
CHECK_COMPAT(buf)
buf->use = 0;
if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
(buf->contentIO != NULL)) {
size_t start_buf = buf->content - buf->contentIO;
buf->size += start_buf;
buf->content = buf->contentIO;
buf->content[0] = 0;
} else {
buf->content[0] = 0;
}
buf->use = 0;
buf->size += buf->content - buf->mem;
buf->content = buf->mem;
buf->content[0] = 0;
UPDATE_COMPAT(buf)
}
@ -326,37 +289,19 @@ xmlBufEmpty(xmlBufPtr buf) {
*/
size_t
xmlBufShrink(xmlBufPtr buf, size_t len) {
if ((buf == NULL) || (buf->error != 0)) return(0);
if ((buf == NULL) || (BUF_ERROR(buf)))
return(0);
if (len == 0)
return(0);
CHECK_COMPAT(buf)
if (len == 0) return(0);
if (len > buf->use) return(0);
if (len > buf->use)
return(0);
buf->use -= len;
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
/*
* we just move the content pointer, but also make sure
* the perceived buffer size has shrunk accordingly
*/
buf->content += len;
buf->size -= len;
buf->content += len;
buf->size -= len;
/*
* sometimes though it maybe be better to really shrink
* on IO buffers
*/
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
size_t start_buf = buf->content - buf->contentIO;
if (start_buf >= buf->size) {
memmove(buf->contentIO, &buf->content[0], buf->use);
buf->content = buf->contentIO;
buf->content[buf->use] = 0;
buf->size += start_buf;
}
}
} else {
memmove(buf->content, &buf->content[len], buf->use);
buf->content[buf->use] = 0;
}
UPDATE_COMPAT(buf)
return(len);
}
@ -367,66 +312,65 @@ xmlBufShrink(xmlBufPtr buf, size_t len) {
* @len: the minimum free size to allocate
*
* Grow the available space of an XML buffer, @len is the target value
* Error checking should be done on buf->error since using the return
* value doesn't work that well
*
* Returns 0 in case of error or the length made available otherwise
* Returns 0 on success, -1 in case of error
*/
static size_t
static int
xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
size_t size;
size_t start;
xmlChar *newbuf;
if ((buf == NULL) || (buf->error != 0)) return(0);
CHECK_COMPAT(buf)
if (len < buf->size - buf->use)
return(buf->size - buf->use - 1);
if (len >= SIZE_MAX - buf->use) {
xmlBufMemoryError(buf);
/*
* If there's enough space at the start of the buffer,
* move the contents.
*/
start = buf->content - buf->mem;
if (len <= start + buf->size - buf->use) {
memmove(buf->mem, buf->content, buf->use + 1);
buf->size += start;
buf->content = buf->mem;
return(0);
}
if (len >= buf->maxSize - buf->use) {
xmlBufOverflowError(buf);
return(-1);
}
if (buf->size > (size_t) len) {
size = buf->size > SIZE_MAX / 2 ? SIZE_MAX : buf->size * 2;
if (buf->size <= SIZE_MAX / 2)
size = buf->size * 2;
else
size = buf->use + len;
} else {
size = buf->use + len;
size = size > SIZE_MAX - 100 ? SIZE_MAX : size + 100;
if (size < SIZE_MAX - 100)
size += 100;
}
if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
/*
* Used to provide parsing limits
*/
if ((buf->use + len + 1 >= XML_MAX_TEXT_LENGTH) ||
(buf->size >= XML_MAX_TEXT_LENGTH)) {
xmlBufMemoryError(buf);
return(0);
}
if (size >= XML_MAX_TEXT_LENGTH)
size = XML_MAX_TEXT_LENGTH;
}
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
size_t start_buf = buf->content - buf->contentIO;
newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
if (newbuf == NULL) {
xmlBufMemoryError(buf);
return(0);
}
buf->contentIO = newbuf;
buf->content = newbuf + start_buf;
if (buf->content == buf->mem) {
newbuf = xmlRealloc(buf->mem, size + 1);
if (newbuf == NULL) {
xmlBufMemoryError(buf);
return(-1);
}
} else {
newbuf = (xmlChar *) xmlRealloc(buf->content, size);
if (newbuf == NULL) {
xmlBufMemoryError(buf);
return(0);
}
buf->content = newbuf;
newbuf = xmlMalloc(size + 1);
if (newbuf == NULL) {
xmlBufMemoryError(buf);
return(-1);
}
if (buf->content != NULL)
memcpy(newbuf, buf->content, buf->use + 1);
xmlFree(buf->mem);
}
buf->mem = newbuf;
buf->content = newbuf;
buf->size = size;
UPDATE_COMPAT(buf)
return(buf->size - buf->use - 1);
return(0);
}
/**
@ -437,44 +381,22 @@ xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
* Grow the available space of an XML buffer, @len is the target value
* This is been kept compatible with xmlBufferGrow() as much as possible
*
* Returns -1 in case of error or the length made available otherwise
* Returns 0 on succes, -1 in case of error
*/
int
xmlBufGrow(xmlBufPtr buf, int len) {
size_t ret;
if ((buf == NULL) || (len < 0)) return(-1);
if (len == 0)
return(0);
ret = xmlBufGrowInternal(buf, len);
if (buf->error != 0)
xmlBufGrow(xmlBufPtr buf, size_t len) {
if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
return(-1);
return(ret > INT_MAX ? INT_MAX : ret);
}
/**
* xmlBufDump:
* @file: the file output
* @buf: the buffer to dump
*
* Dumps an XML buffer to a FILE *.
* Returns the number of #xmlChar written
*/
size_t
xmlBufDump(FILE *file, xmlBufPtr buf) {
size_t ret;
if ((buf == NULL) || (buf->error != 0)) {
return(0);
}
if (buf->content == NULL) {
return(0);
}
CHECK_COMPAT(buf)
if (file == NULL)
file = stdout;
ret = fwrite(buf->content, 1, buf->use, file);
return(ret);
if (len <= buf->size - buf->use)
return(0);
if (xmlBufGrowInternal(buf, len) < 0)
return(-1);
UPDATE_COMPAT(buf)
return(0);
}
/**
@ -489,7 +411,7 @@ xmlBufDump(FILE *file, xmlBufPtr buf) {
xmlChar *
xmlBufContent(const xmlBuf *buf)
{
if ((!buf) || (buf->error))
if ((!buf) || (BUF_ERROR(buf)))
return NULL;
return(buf->content);
@ -507,7 +429,7 @@ xmlBufContent(const xmlBuf *buf)
xmlChar *
xmlBufEnd(xmlBufPtr buf)
{
if ((!buf) || (buf->error))
if ((!buf) || (BUF_ERROR(buf)))
return NULL;
CHECK_COMPAT(buf)
@ -527,10 +449,10 @@ xmlBufEnd(xmlBufPtr buf)
*/
int
xmlBufAddLen(xmlBufPtr buf, size_t len) {
if ((buf == NULL) || (buf->error))
if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
return(-1);
CHECK_COMPAT(buf)
if (len >= (buf->size - buf->use))
if (len > buf->size - buf->use)
return(-1);
buf->use += len;
buf->content[buf->use] = 0;
@ -538,25 +460,6 @@ xmlBufAddLen(xmlBufPtr buf, size_t len) {
return(0);
}
/**
* xmlBufLength:
* @buf: the buffer
*
* Function to get the length of a buffer
*
* Returns the length of data in the internal content
*/
size_t
xmlBufLength(const xmlBufPtr buf)
{
if ((!buf) || (buf->error))
return 0;
CHECK_COMPAT(buf)
return(buf->use);
}
/**
* xmlBufUse:
* @buf: the buffer
@ -569,7 +472,7 @@ xmlBufLength(const xmlBufPtr buf)
size_t
xmlBufUse(const xmlBufPtr buf)
{
if ((!buf) || (buf->error))
if ((!buf) || (BUF_ERROR(buf)))
return 0;
CHECK_COMPAT(buf)
@ -591,11 +494,11 @@ xmlBufUse(const xmlBufPtr buf)
size_t
xmlBufAvail(const xmlBufPtr buf)
{
if ((!buf) || (buf->error))
if ((!buf) || (BUF_ERROR(buf)))
return 0;
CHECK_COMPAT(buf)
return((buf->size > buf->use) ? (buf->size - buf->use - 1) : 0);
return(buf->size - buf->use);
}
/**
@ -609,139 +512,13 @@ xmlBufAvail(const xmlBufPtr buf)
int
xmlBufIsEmpty(const xmlBufPtr buf)
{
if ((!buf) || (buf->error))
if ((!buf) || (BUF_ERROR(buf)))
return(-1);
CHECK_COMPAT(buf)
return(buf->use == 0);
}
/**
* xmlBufResize:
* @buf: the buffer to resize
* @size: the desired size
*
* Resize a buffer to accommodate minimum size of @size.
*
* Returns 0 in case of problems, 1 otherwise
*/
int
xmlBufResize(xmlBufPtr buf, size_t size)
{
size_t newSize;
xmlChar* rebuf = NULL;
size_t start_buf;
if ((buf == NULL) || (buf->error))
return(0);
CHECK_COMPAT(buf)
if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
/*
* Used to provide parsing limits
*/
if (size >= XML_MAX_TEXT_LENGTH) {
xmlBufMemoryError(buf);
return(0);
}
}
/* Don't resize if we don't have to */
if (size < buf->size)
return 1;
/* figure out new size */
switch (buf->alloc){
case XML_BUFFER_ALLOC_IO:
case XML_BUFFER_ALLOC_DOUBLEIT:
/*take care of empty case*/
if (buf->size == 0) {
newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
} else {
newSize = buf->size;
}
while (size > newSize) {
if (newSize > SIZE_MAX / 2) {
xmlBufMemoryError(buf);
return 0;
}
newSize *= 2;
}
break;
case XML_BUFFER_ALLOC_EXACT:
newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
break;
case XML_BUFFER_ALLOC_HYBRID:
if (buf->use < BASE_BUFFER_SIZE)
newSize = size;
else {
newSize = buf->size;
while (size > newSize) {
if (newSize > SIZE_MAX / 2) {
xmlBufMemoryError(buf);
return 0;
}
newSize *= 2;
}
}
break;
default:
newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
break;
}
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
start_buf = buf->content - buf->contentIO;
if (start_buf > newSize) {
/* move data back to start */
memmove(buf->contentIO, buf->content, buf->use);
buf->content = buf->contentIO;
buf->content[buf->use] = 0;
buf->size += start_buf;
} else {
rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
if (rebuf == NULL) {
xmlBufMemoryError(buf);
return 0;
}
buf->contentIO = rebuf;
buf->content = rebuf + start_buf;
}
} else {
if (buf->content == NULL) {
rebuf = (xmlChar *) xmlMallocAtomic(newSize);
buf->use = 0;
if (rebuf != NULL)
rebuf[buf->use] = 0;
} else if (buf->size - buf->use < 100) {
rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
} else {
/*
* if we are reallocating a buffer far from being full, it's
* better to make a new allocation and copy only the used range
* and free the old one.
*/
rebuf = (xmlChar *) xmlMallocAtomic(newSize);
if (rebuf != NULL) {
memcpy(rebuf, buf->content, buf->use);
xmlFree(buf->content);
rebuf[buf->use] = 0;
}
}
if (rebuf == NULL) {
xmlBufMemoryError(buf);
return 0;
}
buf->content = rebuf;
}
buf->size = newSize;
UPDATE_COMPAT(buf)
return 1;
}
/**
* xmlBufAdd:
* @buf: the buffer to dump
@ -754,49 +531,26 @@ xmlBufResize(xmlBufPtr buf, size_t size)
* Returns 0 if successful, -1 in case of error.
*/
int
xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
size_t needSize;
if ((str == NULL) || (buf == NULL) || (buf->error))
return -1;
xmlBufAdd(xmlBufPtr buf, const xmlChar *str, size_t len) {
if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
return(-1);
if (len == 0)
return(0);
if (str == NULL)
return(-1);
CHECK_COMPAT(buf)
if (len < -1) {
return -1;
}
if (len == 0) return 0;
if (len < 0)
len = xmlStrlen(str);
if (len < 0) return -1;
if (len == 0) return 0;
/* Note that both buf->size and buf->use can be zero here. */
if ((size_t) len >= buf->size - buf->use) {
if ((size_t) len >= SIZE_MAX - buf->use) {
xmlBufMemoryError(buf);
return(-1);
}
needSize = buf->use + len + 1;
if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
/*
* Used to provide parsing limits
*/
if (needSize >= XML_MAX_TEXT_LENGTH) {
xmlBufMemoryError(buf);
return(-1);
}
}
if (!xmlBufResize(buf, needSize))
if (len > buf->size - buf->use) {
if (xmlBufGrowInternal(buf, len) < 0)
return(-1);
}
memmove(&buf->content[buf->use], str, len);
buf->use += len;
buf->content[buf->use] = 0;
UPDATE_COMPAT(buf)
return 0;
return(0);
}
/**
@ -811,11 +565,7 @@ xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
*/
int
xmlBufCat(xmlBufPtr buf, const xmlChar *str) {
if ((buf == NULL) || (buf->error))
return(-1);
CHECK_COMPAT(buf)
if (str == NULL) return -1;
return xmlBufAdd(buf, str, -1);
return(xmlBufAdd(buf, str, strlen((const char *) str)));
}
/**
@ -836,19 +586,32 @@ xmlBufFromBuffer(xmlBufferPtr buffer) {
if (buffer == NULL)
return(NULL);
ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
if (ret == NULL) {
ret = xmlMalloc(sizeof(xmlBuf));
if (ret == NULL)
return(NULL);
}
ret->use = buffer->use;
ret->size = buffer->size;
UPDATE_COMPAT(ret);
ret->error = 0;
ret->buffer = buffer;
ret->alloc = buffer->alloc;
ret->content = buffer->content;
ret->contentIO = buffer->contentIO;
ret->use = buffer->use;
ret->flags = 0;
ret->maxSize = SIZE_MAX;
if (buffer->content == NULL) {
ret->size = 50;
ret->mem = xmlMalloc(ret->size + 1);
ret->content = ret->mem;
if (ret->mem == NULL)
xmlBufMemoryError(ret);
else
ret->content[0] = 0;
} else {
ret->size = buffer->size - 1;
ret->content = buffer->content;
if (buffer->alloc == XML_BUFFER_ALLOC_IO)
ret->mem = buffer->contentIO;
else
ret->mem = buffer->content;
}
UPDATE_COMPAT(ret);
return(ret);
}
@ -864,57 +627,35 @@ xmlBufFromBuffer(xmlBufferPtr buffer) {
*
* Returns the old xmlBufferPtr unless the call failed and NULL is returned
*/
xmlBufferPtr
xmlBufBackToBuffer(xmlBufPtr buf) {
xmlBufferPtr ret;
if (buf == NULL)
return(NULL);
int
xmlBufBackToBuffer(xmlBufPtr buf, xmlBufferPtr ret) {
if (ret == NULL)
return(-1);
CHECK_COMPAT(buf)
ret = buf->buffer;
if ((buf->error) || (ret == NULL)) {
xmlBufFree(buf);
if (ret != NULL) {
ret->content = NULL;
ret->contentIO = NULL;
ret->use = 0;
ret->size = 0;
}
return(NULL);
if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)) ||
(buf->use >= INT_MAX)) {
if (!BUF_STATIC(buf))
xmlBufFree(buf);
ret->content = NULL;
ret->contentIO = NULL;
ret->use = 0;
ret->size = 0;
return(-1);
}
/*
* What to do in case of error in the buffer ???
*/
if (buf->use > INT_MAX) {
/*
* Worse case, we really allocated and used more than the
* maximum allowed memory for an xmlBuffer on this architecture.
* Keep the buffer but provide a truncated size value.
*/
xmlBufOverflowError(buf);
ret->use = INT_MAX;
ret->size = INT_MAX;
} else if (buf->size > INT_MAX) {
/*
* milder case, we allocated more than the maximum allowed memory
* for an xmlBuffer on this architecture, but used less than the
* limit.
* Keep the buffer but provide a truncated size value.
*/
xmlBufOverflowError(buf);
ret->use = buf->use;
ret->use = buf->use;
if (buf->size >= INT_MAX) {
/* Keep the buffer but provide a truncated size value. */
ret->size = INT_MAX;
} else {
ret->use = buf->use;
ret->size = buf->size;
ret->size = buf->size + 1;
}
ret->alloc = buf->alloc;
ret->alloc = XML_BUFFER_ALLOC_IO;
ret->content = buf->content;
ret->contentIO = buf->contentIO;
ret->contentIO = buf->mem;
xmlFree(buf);
return(ret);
return(0);
}
/**

View File

@ -1,57 +1,41 @@
#ifndef XML_BUF_H_PRIVATE__
#define XML_BUF_H_PRIVATE__
#include <libxml/parser.h>
#include <libxml/tree.h>
XML_HIDDEN xmlBufPtr
xmlBufCreate(void);
xmlBufCreate(size_t size);
XML_HIDDEN xmlBufPtr
xmlBufCreateSize(size_t size);
XML_HIDDEN int
xmlBufSetAllocationScheme(xmlBufPtr buf, xmlBufferAllocationScheme scheme);
XML_HIDDEN int
xmlBufGetAllocationScheme(xmlBufPtr buf);
xmlBufCreateMem(const xmlChar *mem, size_t size, int isStatic);
XML_HIDDEN void
xmlBufFree(xmlBufPtr buf);
XML_HIDDEN void
xmlBufEmpty(xmlBufPtr buf);
/* size_t xmlBufShrink(xmlBufPtr buf, size_t len); */
XML_HIDDEN int
xmlBufGrow(xmlBufPtr buf, int len);
XML_HIDDEN int
xmlBufResize(xmlBufPtr buf, size_t len);
xmlBufGrow(xmlBufPtr buf, size_t len);
XML_HIDDEN int
xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len);
xmlBufAdd(xmlBufPtr buf, const xmlChar *str, size_t len);
XML_HIDDEN int
xmlBufCat(xmlBufPtr buf, const xmlChar *str);
XML_HIDDEN size_t
xmlBufAvail(const xmlBufPtr buf);
XML_HIDDEN size_t
xmlBufLength(const xmlBufPtr buf);
/* size_t xmlBufUse(const xmlBufPtr buf); */
XML_HIDDEN int
xmlBufIsEmpty(const xmlBufPtr buf);
XML_HIDDEN int
xmlBufAddLen(xmlBufPtr buf, size_t len);
/* const xmlChar * xmlBufContent(const xmlBuf *buf); */
/* const xmlChar * xmlBufEnd(xmlBufPtr buf); */
XML_HIDDEN xmlChar *
xmlBufDetach(xmlBufPtr buf);
XML_HIDDEN size_t
xmlBufDump(FILE *file, xmlBufPtr buf);
XML_HIDDEN xmlBufPtr
xmlBufFromBuffer(xmlBufferPtr buffer);
XML_HIDDEN xmlBufferPtr
xmlBufBackToBuffer(xmlBufPtr buf);
XML_HIDDEN int
xmlBufBackToBuffer(xmlBufPtr buf, xmlBufferPtr ret);
XML_HIDDEN int
xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input);

View File

@ -1335,7 +1335,7 @@ xmlInputSetEncodingHandler(xmlParserInputPtr input,
return(XML_ERR_OK);
}
buf = xmlBufCreate();
buf = xmlBufCreate(INPUT_CHUNK + 4000 /* MINLEN */ + LINE_LEN);
if (buf == NULL) {
xmlCharEncCloseFunc(handler);
return(XML_ERR_NO_MEMORY);

16
tree.c
View File

@ -1219,10 +1219,9 @@ xmlNodeParseContentInternal(const xmlDoc *doc, xmlNodePtr parent,
cur = value;
buf = xmlBufCreateSize(64);
buf = xmlBufCreate(50);
if (buf == NULL)
return(-1);
xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
q = cur;
while ((remaining > 0) && (*cur != 0)) {
@ -1543,7 +1542,7 @@ xmlNodeListGetStringInternal(xmlDocPtr doc, const xmlNode *node, int escMode) {
return(xmlStrdup(node->content));
}
buf = xmlBufCreateSize(64);
buf = xmlBufCreate(50);
if (buf == NULL)
return(NULL);
@ -5456,13 +5455,13 @@ int
xmlNodeBufGetContent(xmlBufferPtr buffer, const xmlNode *cur)
{
xmlBufPtr buf;
int ret;
int ret1, ret2;
if ((cur == NULL) || (buffer == NULL)) return(-1);
buf = xmlBufFromBuffer(buffer);
ret = xmlBufGetNodeContent(buf, cur);
buffer = xmlBufBackToBuffer(buf);
if ((ret < 0) || (buffer == NULL))
ret1 = xmlBufGetNodeContent(buf, cur);
ret2 = xmlBufBackToBuffer(buf, buffer);
if ((ret1 < 0) || (ret2 < 0))
return(-1);
return(0);
}
@ -5644,10 +5643,9 @@ xmlNodeGetContent(const xmlNode *cur)
return(NULL);
}
buf = xmlBufCreateSize(64);
buf = xmlBufCreate(50);
if (buf == NULL)
return (NULL);
xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
xmlBufGetNodeContent(buf, cur);
ret = xmlBufDetach(buf);
xmlBufFree(buf);

View File

@ -1445,7 +1445,7 @@ xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) {
}
content = xmlBufContent(buf->buffer);
len = xmlBufLength(buf->buffer);
len = xmlBufUse(buf->buffer);
for (i = 0; i < len;) {
int cur;
int l;

26
xmlIO.c
View File

@ -1201,12 +1201,11 @@ xmlAllocParserInputBuffer(xmlCharEncoding enc) {
return(NULL);
}
memset(ret, 0, sizeof(xmlParserInputBuffer));
ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize);
ret->buffer = xmlBufCreate(INPUT_CHUNK + MINLEN + 80 /* LINE_LEN */);
if (ret->buffer == NULL) {
xmlFree(ret);
return(NULL);
}
xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
if (enc != XML_CHAR_ENCODING_NONE) {
if (xmlLookupCharEncodingHandler(enc, &ret->encoder) != 0) {
/* We can't handle errors properly here. */
@ -1215,7 +1214,7 @@ xmlAllocParserInputBuffer(xmlCharEncoding enc) {
}
}
if (ret->encoder != NULL)
ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
ret->raw = xmlBufCreate(MINLEN);
else
ret->raw = NULL;
ret->readcallback = NULL;
@ -1245,16 +1244,15 @@ xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
return(NULL);
}
memset(ret, 0, sizeof(xmlOutputBuffer));
ret->buffer = xmlBufCreate();
ret->buffer = xmlBufCreate(MINLEN);
if (ret->buffer == NULL) {
xmlFree(ret);
return(NULL);
}
xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
ret->encoder = encoder;
if (encoder != NULL) {
ret->conv = xmlBufCreateSize(4000);
ret->conv = xmlBufCreate(MINLEN);
if (ret->conv == NULL) {
xmlBufFree(ret->buffer);
xmlFree(ret);
@ -1292,21 +1290,15 @@ xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
return(NULL);
}
memset(ret, 0, sizeof(xmlOutputBuffer));
ret->buffer = xmlBufCreate();
ret->buffer = xmlBufCreate(MINLEN);
if (ret->buffer == NULL) {
xmlFree(ret);
return(NULL);
}
/*
* For conversion buffers we use the special IO handling
*/
xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
ret->encoder = encoder;
if (encoder != NULL) {
ret->conv = xmlBufCreateSize(4000);
ret->conv = xmlBufCreate(MINLEN);
if (ret->conv == NULL) {
xmlBufFree(ret->buffer);
xmlFree(ret);
@ -2123,7 +2115,7 @@ xmlParserInputBufferPush(xmlParserInputBufferPtr in,
* Store the data in the incoming raw buffer
*/
if (in->raw == NULL) {
in->raw = xmlBufCreate();
in->raw = xmlBufCreate(50);
if (in->raw == NULL) {
in->error = XML_ERR_NO_MEMORY;
return(-1);
@ -2195,7 +2187,7 @@ xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
buf = in->buffer;
} else {
if (in->raw == NULL) {
in->raw = xmlBufCreate();
in->raw = xmlBufCreate(MINLEN);
}
buf = in->raw;
}
@ -2308,7 +2300,7 @@ xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *data) {
* Store the data in the incoming raw buffer
*/
if (out->conv == NULL) {
out->conv = xmlBufCreate();
out->conv = xmlBufCreate(MINLEN);
if (out->conv == NULL) {
out->error = XML_ERR_NO_MEMORY;
return(-1);

View File

@ -1766,12 +1766,11 @@ xmlTextReaderReadString(xmlTextReaderPtr reader)
break;
}
buf = xmlBufCreateSize(30);
buf = xmlBufCreate(50);
if (buf == NULL) {
xmlTextReaderErrMemory(reader);
return(NULL);
}
xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
cur = node;
while (cur != NULL) {
@ -2015,14 +2014,11 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
ret->entMax = 0;
ret->entNr = 0;
ret->input = input;
ret->buffer = xmlBufCreateSize(100);
ret->buffer = xmlBufCreate(50);
if (ret->buffer == NULL) {
xmlFree(ret);
return(NULL);
}
/* no operation on a reader should require a huge buffer */
xmlBufSetAllocationScheme(ret->buffer,
XML_BUFFER_ALLOC_DOUBLEIT);
ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
if (ret->sax == NULL) {
xmlBufFree(ret->buffer);
@ -3583,11 +3579,9 @@ xmlTextReaderConstValue(xmlTextReaderPtr reader) {
return(attr->children->content);
else {
if (reader->buffer == NULL) {
reader->buffer = xmlBufCreateSize(100);
reader->buffer = xmlBufCreate(50);
if (reader->buffer == NULL)
return (NULL);
xmlBufSetAllocationScheme(reader->buffer,
XML_BUFFER_ALLOC_DOUBLEIT);
} else
xmlBufEmpty(reader->buffer);
xmlBufGetNodeContent(reader->buffer, node);
@ -3596,9 +3590,7 @@ xmlTextReaderConstValue(xmlTextReaderPtr reader) {
xmlTextReaderErrMemory(reader);
/* error on the buffer best to reallocate */
xmlBufFree(reader->buffer);
reader->buffer = xmlBufCreateSize(100);
xmlBufSetAllocationScheme(reader->buffer,
XML_BUFFER_ALLOC_DOUBLEIT);
reader->buffer = xmlBufCreate(50);
}
return(ret);
}
@ -4848,13 +4840,10 @@ xmlTextReaderSetup(xmlTextReaderPtr reader,
reader->allocs |= XML_TEXTREADER_INPUT;
}
if (reader->buffer == NULL)
reader->buffer = xmlBufCreateSize(100);
reader->buffer = xmlBufCreate(50);
if (reader->buffer == NULL) {
return (-1);
}
/* no operation on a reader should require a huge buffer */
xmlBufSetAllocationScheme(reader->buffer,
XML_BUFFER_ALLOC_DOUBLEIT);
if (reader->sax == NULL)
reader->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
if (reader->sax == NULL) {

View File

@ -783,7 +783,7 @@ static int xmlSaveSwitchEncoding(xmlSaveCtxtPtr ctxt, const char *encoding) {
xmlSaveErr(buf, res, NULL, encoding);
return(-1);
}
buf->conv = xmlBufCreate();
buf->conv = xmlBufCreate(4000 /* MINLEN */);
if (buf->conv == NULL) {
xmlCharEncCloseFunc(handler);
xmlSaveErrMemory(buf);
@ -2324,7 +2324,8 @@ xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
int format)
{
xmlBufPtr buffer;
size_t ret;
size_t ret1;
int ret2;
if ((buf == NULL) || (cur == NULL))
return(-1);
@ -2335,11 +2336,11 @@ xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
buffer = xmlBufFromBuffer(buf);
if (buffer == NULL)
return(-1);
ret = xmlBufNodeDump(buffer, doc, cur, level, format);
xmlBufBackToBuffer(buffer);
if (ret > INT_MAX)
ret1 = xmlBufNodeDump(buffer, doc, cur, level, format);
ret2 = xmlBufBackToBuffer(buffer, buf);
if ((ret1 == (size_t) -1) || (ret2 < 0))
return(-1);
return(ret);
return(ret1 > INT_MAX ? INT_MAX : ret1);
}
/**
@ -2365,7 +2366,6 @@ xmlBufNodeDump(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
size_t use;
size_t ret;
xmlOutputBufferPtr outbuf;
int oldalloc;
xmlInitParser();
@ -2389,10 +2389,7 @@ xmlBufNodeDump(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
outbuf->written = 0;
use = xmlBufUse(buf);
oldalloc = xmlBufGetAllocationScheme(buf);
xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
xmlBufSetAllocationScheme(buf, oldalloc);
if (outbuf->error)
ret = (size_t) -1;
else

View File

@ -535,7 +535,7 @@ xmlTextWriterStartDocument(xmlTextWriterPtr writer, const char *version,
writer->out->encoder = encoder;
if (encoder != NULL) {
if (writer->out->conv == NULL) {
writer->out->conv = xmlBufCreateSize(4000);
writer->out->conv = xmlBufCreate(4000);
}
xmlCharEncOutput(writer->out, 1);
if ((writer->doc != NULL) && (writer->doc->encoding == NULL))

View File

@ -8069,7 +8069,7 @@ xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
}
}
target = xmlBufCreateSize(64);
target = xmlBufCreate(50);
if (target == NULL) {
xmlXPathPErrMemory(ctxt);
goto error;
@ -12784,7 +12784,7 @@ xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
CAST_TO_STRING;
str = valuePop(ctxt);
target = xmlBufCreateSize(64);
target = xmlBufCreate(50);
escape[0] = '%';
escape[3] = 0;