1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-03-27 18:50:07 +03:00

buf: Move xmlBuffer code to buf.c

This commit is contained in:
Nick Wellnhofer 2024-07-07 11:35:54 +02:00
parent 92f30711de
commit 888f70c77e
2 changed files with 678 additions and 679 deletions

678
buf.c
View File

@ -694,3 +694,681 @@ xmlBufUpdateInput(xmlBufPtr buf, xmlParserInputPtr input, size_t pos) {
return(0);
}
/************************************************************************
* *
* Old buffer implementation *
* *
************************************************************************/
/**
* xmlSetBufferAllocationScheme:
* @scheme: allocation method to use
*
* Set the buffer allocation method. Types are
* XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
* XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
* improves performance
*/
void
xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
if ((scheme == XML_BUFFER_ALLOC_EXACT) ||
(scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
(scheme == XML_BUFFER_ALLOC_HYBRID))
xmlBufferAllocScheme = scheme;
}
/**
* xmlGetBufferAllocationScheme:
*
* Types are
* XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
* XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
* improves performance
* XML_BUFFER_ALLOC_HYBRID - use exact sizes on small strings to keep memory usage tight
* in normal usage, and doubleit on large strings to avoid
* pathological performance.
*
* Returns the current allocation scheme
*/
xmlBufferAllocationScheme
xmlGetBufferAllocationScheme(void) {
return(xmlBufferAllocScheme);
}
/**
* xmlBufferCreate:
*
* routine to create an XML buffer.
* returns the new structure.
*/
xmlBufferPtr
xmlBufferCreate(void) {
xmlBufferPtr ret;
ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
if (ret == NULL)
return(NULL);
ret->use = 0;
ret->size = xmlDefaultBufferSize;
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);
}
/**
* xmlBufferCreateSize:
* @size: initial size of buffer
*
* routine to create an XML buffer.
* returns the new structure.
*/
xmlBufferPtr
xmlBufferCreateSize(size_t size) {
xmlBufferPtr ret;
if (size >= UINT_MAX)
return(NULL);
ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
if (ret == NULL)
return(NULL);
ret->use = 0;
ret->alloc = xmlBufferAllocScheme;
ret->size = (size ? size + 1 : 0); /* +1 for ending null */
if (ret->size){
ret->content = (xmlChar *) xmlMallocAtomic(ret->size);
if (ret->content == NULL) {
xmlFree(ret);
return(NULL);
}
ret->content[0] = 0;
} else
ret->content = NULL;
ret->contentIO = NULL;
return(ret);
}
/**
* xmlBufferDetach:
* @buf: the buffer
*
* Remove the string contained in a buffer and gie it back to the
* caller. The buffer is reset to an empty content.
* This doesn't work with immutable buffers as they can't be reset.
*
* Returns the previous string contained by the buffer.
*/
xmlChar *
xmlBufferDetach(xmlBufferPtr buf) {
xmlChar *ret;
if (buf == NULL)
return(NULL);
ret = buf->content;
buf->content = NULL;
buf->size = 0;
buf->use = 0;
return ret;
}
/**
* xmlBufferCreateStatic:
* @mem: the memory area
* @size: the size in byte
*
* Returns an XML buffer initialized with bytes.
*/
xmlBufferPtr
xmlBufferCreateStatic(void *mem, size_t size) {
xmlBufferPtr buf = xmlBufferCreateSize(size);
xmlBufferAdd(buf, mem, size);
return(buf);
}
/**
* xmlBufferSetAllocationScheme:
* @buf: the buffer to tune
* @scheme: allocation scheme to use
*
* Sets the allocation scheme for this buffer
*/
void
xmlBufferSetAllocationScheme(xmlBufferPtr buf,
xmlBufferAllocationScheme scheme) {
if (buf == NULL) {
return;
}
if (buf->alloc == XML_BUFFER_ALLOC_IO) return;
if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
(scheme == XML_BUFFER_ALLOC_EXACT) ||
(scheme == XML_BUFFER_ALLOC_HYBRID))
buf->alloc = scheme;
}
/**
* xmlBufferFree:
* @buf: the buffer to free
*
* Frees an XML buffer. It frees both the content and the structure which
* encapsulate it.
*/
void
xmlBufferFree(xmlBufferPtr buf) {
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);
}
xmlFree(buf);
}
/**
* xmlBufferEmpty:
* @buf: the buffer
*
* empty a buffer.
*/
void
xmlBufferEmpty(xmlBufferPtr buf) {
if (buf == NULL) return;
if (buf->content == NULL) return;
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;
}
}
/**
* xmlBufferShrink:
* @buf: the buffer to dump
* @len: the number of xmlChar to remove
*
* Remove the beginning of an XML buffer.
*
* Returns the number of #xmlChar removed, or -1 in case of failure.
*/
int
xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
if (buf == NULL) return(-1);
if (len == 0) return(0);
if (len > buf->use) return(-1);
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;
/*
* 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;
}
return(len);
}
/**
* xmlBufferGrow:
* @buf: the buffer
* @len: the minimum free size to allocate
*
* Grow the available space of an XML buffer.
*
* Returns the new available space or -1 in case of error
*/
int
xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
unsigned int size;
xmlChar *newbuf;
if (buf == NULL) return(-1);
if (len < buf->size - buf->use)
return(0);
if (len >= UINT_MAX - buf->use)
return(-1);
if (buf->size > (size_t) len) {
size = buf->size > UINT_MAX / 2 ? UINT_MAX : buf->size * 2;
} else {
size = buf->use + len;
size = size > UINT_MAX - 100 ? UINT_MAX : size + 100;
}
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)
return(-1);
buf->contentIO = newbuf;
buf->content = newbuf + start_buf;
} else {
newbuf = (xmlChar *) xmlRealloc(buf->content, size);
if (newbuf == NULL)
return(-1);
buf->content = newbuf;
}
buf->size = size;
return(buf->size - buf->use - 1);
}
/**
* xmlBufferDump:
* @file: the file output
* @buf: the buffer to dump
*
* Dumps an XML buffer to a FILE *.
* Returns the number of #xmlChar written
*/
int
xmlBufferDump(FILE *file, xmlBufferPtr buf) {
size_t ret;
if (buf == NULL) {
return(0);
}
if (buf->content == NULL) {
return(0);
}
if (file == NULL)
file = stdout;
ret = fwrite(buf->content, 1, buf->use, file);
return(ret > INT_MAX ? INT_MAX : ret);
}
/**
* xmlBufferContent:
* @buf: the buffer
*
* Function to extract the content of a buffer
*
* Returns the internal content
*/
const xmlChar *
xmlBufferContent(const xmlBuffer *buf)
{
if(!buf)
return NULL;
return buf->content;
}
/**
* xmlBufferLength:
* @buf: the buffer
*
* Function to get the length of a buffer
*
* Returns the length of data in the internal content
*/
int
xmlBufferLength(const xmlBuffer *buf)
{
if(!buf)
return 0;
return buf->use;
}
/**
* xmlBufferResize:
* @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
xmlBufferResize(xmlBufferPtr buf, unsigned int size)
{
unsigned int newSize;
xmlChar* rebuf = NULL;
size_t start_buf;
if (buf == NULL)
return(0);
/* Don't resize if we don't have to */
if (size < buf->size)
return 1;
if (size > UINT_MAX - 10)
return 0;
/* 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 + 10;
else
newSize = buf->size;
while (size > newSize) {
if (newSize > UINT_MAX / 2)
return 0;
newSize *= 2;
}
break;
case XML_BUFFER_ALLOC_EXACT:
newSize = 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 > UINT_MAX / 2)
return 0;
newSize *= 2;
}
}
break;
default:
newSize = 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)
return 0;
buf->contentIO = rebuf;
buf->content = rebuf + start_buf;
}
} else {
if (buf->content == NULL) {
rebuf = (xmlChar *) xmlMallocAtomic(newSize);
buf->use = 0;
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)
return 0;
buf->content = rebuf;
}
buf->size = newSize;
return 1;
}
/**
* xmlBufferAdd:
* @buf: the buffer to dump
* @str: the #xmlChar string
* @len: the number of #xmlChar to add
*
* Add a string range to an XML buffer. if len == -1, the length of
* str is recomputed.
*
* Returns 0 successful, a positive error code number otherwise
* and -1 in case of internal or API error.
*/
int
xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
unsigned int needSize;
if ((str == NULL) || (buf == NULL)) {
return -1;
}
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 ((unsigned) len >= buf->size - buf->use) {
if ((unsigned) len >= UINT_MAX - buf->use)
return XML_ERR_NO_MEMORY;
needSize = buf->use + len + 1;
if (!xmlBufferResize(buf, needSize))
return XML_ERR_NO_MEMORY;
}
memmove(&buf->content[buf->use], str, len);
buf->use += len;
buf->content[buf->use] = 0;
return 0;
}
/**
* xmlBufferAddHead:
* @buf: the buffer
* @str: the #xmlChar string
* @len: the number of #xmlChar to add
*
* Add a string range to the beginning of an XML buffer.
* if len == -1, the length of @str is recomputed.
*
* Returns 0 successful, a positive error code number otherwise
* and -1 in case of internal or API error.
*/
int
xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
unsigned int needSize;
if (buf == NULL)
return(-1);
if (str == NULL) {
return -1;
}
if (len < -1) {
return -1;
}
if (len == 0) return 0;
if (len < 0)
len = xmlStrlen(str);
if (len <= 0) return -1;
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
size_t start_buf = buf->content - buf->contentIO;
if (start_buf > (unsigned int) len) {
/*
* We can add it in the space previously shrunk
*/
buf->content -= len;
memmove(&buf->content[0], str, len);
buf->use += len;
buf->size += len;
buf->content[buf->use] = 0;
return(0);
}
}
/* Note that both buf->size and buf->use can be zero here. */
if ((unsigned) len >= buf->size - buf->use) {
if ((unsigned) len >= UINT_MAX - buf->use)
return(-1);
needSize = buf->use + len + 1;
if (!xmlBufferResize(buf, needSize))
return(-1);
}
memmove(&buf->content[len], &buf->content[0], buf->use);
memmove(&buf->content[0], str, len);
buf->use += len;
buf->content[buf->use] = 0;
return 0;
}
/**
* xmlBufferCat:
* @buf: the buffer to add to
* @str: the #xmlChar string
*
* Append a zero terminated string to an XML buffer.
*
* Returns 0 successful, a positive error code number otherwise
* and -1 in case of internal or API error.
*/
int
xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
if (buf == NULL)
return(-1);
if (str == NULL) return -1;
return xmlBufferAdd(buf, str, -1);
}
/**
* xmlBufferCCat:
* @buf: the buffer to dump
* @str: the C char string
*
* Append a zero terminated C string to an XML buffer.
*
* Returns 0 successful, a positive error code number otherwise
* and -1 in case of internal or API error.
*/
int
xmlBufferCCat(xmlBufferPtr buf, const char *str) {
return xmlBufferCat(buf, (const xmlChar *) str);
}
/**
* xmlBufferWriteCHAR:
* @buf: the XML buffer
* @string: the string to add
*
* routine which manages and grows an output buffer. This one adds
* xmlChars at the end of the buffer.
*/
void
xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
if (buf == NULL)
return;
xmlBufferCat(buf, string);
}
/**
* xmlBufferWriteChar:
* @buf: the XML buffer output
* @string: the string to add
*
* routine which manage and grows an output buffer. This one add
* C chars at the end of the array.
*/
void
xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
if (buf == NULL)
return;
xmlBufferCCat(buf, string);
}
/**
* xmlBufferWriteQuotedString:
* @buf: the XML buffer output
* @string: the string to add
*
* routine which manage and grows an output buffer. This one writes
* a quoted or double quoted #xmlChar string, checking first if it holds
* quote or double-quotes internally
*/
void
xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
const xmlChar *cur, *base;
if (buf == NULL)
return;
if (xmlStrchr(string, '\"')) {
if (xmlStrchr(string, '\'')) {
xmlBufferCCat(buf, "\"");
base = cur = string;
while(*cur != 0){
if(*cur == '"'){
if (base != cur)
xmlBufferAdd(buf, base, cur - base);
xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
cur++;
base = cur;
}
else {
cur++;
}
}
if (base != cur)
xmlBufferAdd(buf, base, cur - base);
xmlBufferCCat(buf, "\"");
}
else{
xmlBufferCCat(buf, "\'");
xmlBufferCat(buf, string);
xmlBufferCCat(buf, "\'");
}
} else {
xmlBufferCCat(buf, "\"");
xmlBufferCat(buf, string);
xmlBufferCCat(buf, "\"");
}
}

679
tree.c
View File

@ -666,41 +666,6 @@ try_complex:
* *
************************************************************************/
/**
* xmlSetBufferAllocationScheme:
* @scheme: allocation method to use
*
* Set the buffer allocation method. Types are
* XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
* XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
* improves performance
*/
void
xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
if ((scheme == XML_BUFFER_ALLOC_EXACT) ||
(scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
(scheme == XML_BUFFER_ALLOC_HYBRID))
xmlBufferAllocScheme = scheme;
}
/**
* xmlGetBufferAllocationScheme:
*
* Types are
* XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
* XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
* improves performance
* XML_BUFFER_ALLOC_HYBRID - use exact sizes on small strings to keep memory usage tight
* in normal usage, and doubleit on large strings to avoid
* pathological performance.
*
* Returns the current allocation scheme
*/
xmlBufferAllocationScheme
xmlGetBufferAllocationScheme(void) {
return(xmlBufferAllocScheme);
}
/**
* xmlNewNs:
* @node: the element carrying the namespace (optional)
@ -7018,650 +6983,6 @@ xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
return(xmlTextAddContent(node, content, len));
}
/************************************************************************
* *
* Output : to a FILE or in memory *
* *
************************************************************************/
/**
* xmlBufferCreate:
*
* routine to create an XML buffer.
* returns the new structure.
*/
xmlBufferPtr
xmlBufferCreate(void) {
xmlBufferPtr ret;
ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
if (ret == NULL)
return(NULL);
ret->use = 0;
ret->size = xmlDefaultBufferSize;
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);
}
/**
* xmlBufferCreateSize:
* @size: initial size of buffer
*
* routine to create an XML buffer.
* returns the new structure.
*/
xmlBufferPtr
xmlBufferCreateSize(size_t size) {
xmlBufferPtr ret;
if (size >= UINT_MAX)
return(NULL);
ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
if (ret == NULL)
return(NULL);
ret->use = 0;
ret->alloc = xmlBufferAllocScheme;
ret->size = (size ? size + 1 : 0); /* +1 for ending null */
if (ret->size){
ret->content = (xmlChar *) xmlMallocAtomic(ret->size);
if (ret->content == NULL) {
xmlFree(ret);
return(NULL);
}
ret->content[0] = 0;
} else
ret->content = NULL;
ret->contentIO = NULL;
return(ret);
}
/**
* xmlBufferDetach:
* @buf: the buffer
*
* Remove the string contained in a buffer and gie it back to the
* caller. The buffer is reset to an empty content.
* This doesn't work with immutable buffers as they can't be reset.
*
* Returns the previous string contained by the buffer.
*/
xmlChar *
xmlBufferDetach(xmlBufferPtr buf) {
xmlChar *ret;
if (buf == NULL)
return(NULL);
ret = buf->content;
buf->content = NULL;
buf->size = 0;
buf->use = 0;
return ret;
}
/**
* xmlBufferCreateStatic:
* @mem: the memory area
* @size: the size in byte
*
* Returns an XML buffer initialized with bytes.
*/
xmlBufferPtr
xmlBufferCreateStatic(void *mem, size_t size) {
xmlBufferPtr buf = xmlBufferCreateSize(size);
xmlBufferAdd(buf, mem, size);
return(buf);
}
/**
* xmlBufferSetAllocationScheme:
* @buf: the buffer to tune
* @scheme: allocation scheme to use
*
* Sets the allocation scheme for this buffer
*/
void
xmlBufferSetAllocationScheme(xmlBufferPtr buf,
xmlBufferAllocationScheme scheme) {
if (buf == NULL) {
return;
}
if (buf->alloc == XML_BUFFER_ALLOC_IO) return;
if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
(scheme == XML_BUFFER_ALLOC_EXACT) ||
(scheme == XML_BUFFER_ALLOC_HYBRID))
buf->alloc = scheme;
}
/**
* xmlBufferFree:
* @buf: the buffer to free
*
* Frees an XML buffer. It frees both the content and the structure which
* encapsulate it.
*/
void
xmlBufferFree(xmlBufferPtr buf) {
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);
}
xmlFree(buf);
}
/**
* xmlBufferEmpty:
* @buf: the buffer
*
* empty a buffer.
*/
void
xmlBufferEmpty(xmlBufferPtr buf) {
if (buf == NULL) return;
if (buf->content == NULL) return;
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;
}
}
/**
* xmlBufferShrink:
* @buf: the buffer to dump
* @len: the number of xmlChar to remove
*
* Remove the beginning of an XML buffer.
*
* Returns the number of #xmlChar removed, or -1 in case of failure.
*/
int
xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
if (buf == NULL) return(-1);
if (len == 0) return(0);
if (len > buf->use) return(-1);
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;
/*
* 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;
}
return(len);
}
/**
* xmlBufferGrow:
* @buf: the buffer
* @len: the minimum free size to allocate
*
* Grow the available space of an XML buffer.
*
* Returns the new available space or -1 in case of error
*/
int
xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
unsigned int size;
xmlChar *newbuf;
if (buf == NULL) return(-1);
if (len < buf->size - buf->use)
return(0);
if (len >= UINT_MAX - buf->use)
return(-1);
if (buf->size > (size_t) len) {
size = buf->size > UINT_MAX / 2 ? UINT_MAX : buf->size * 2;
} else {
size = buf->use + len;
size = size > UINT_MAX - 100 ? UINT_MAX : size + 100;
}
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)
return(-1);
buf->contentIO = newbuf;
buf->content = newbuf + start_buf;
} else {
newbuf = (xmlChar *) xmlRealloc(buf->content, size);
if (newbuf == NULL)
return(-1);
buf->content = newbuf;
}
buf->size = size;
return(buf->size - buf->use - 1);
}
/**
* xmlBufferDump:
* @file: the file output
* @buf: the buffer to dump
*
* Dumps an XML buffer to a FILE *.
* Returns the number of #xmlChar written
*/
int
xmlBufferDump(FILE *file, xmlBufferPtr buf) {
size_t ret;
if (buf == NULL) {
return(0);
}
if (buf->content == NULL) {
return(0);
}
if (file == NULL)
file = stdout;
ret = fwrite(buf->content, 1, buf->use, file);
return(ret > INT_MAX ? INT_MAX : ret);
}
/**
* xmlBufferContent:
* @buf: the buffer
*
* Function to extract the content of a buffer
*
* Returns the internal content
*/
const xmlChar *
xmlBufferContent(const xmlBuffer *buf)
{
if(!buf)
return NULL;
return buf->content;
}
/**
* xmlBufferLength:
* @buf: the buffer
*
* Function to get the length of a buffer
*
* Returns the length of data in the internal content
*/
int
xmlBufferLength(const xmlBuffer *buf)
{
if(!buf)
return 0;
return buf->use;
}
/**
* xmlBufferResize:
* @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
xmlBufferResize(xmlBufferPtr buf, unsigned int size)
{
unsigned int newSize;
xmlChar* rebuf = NULL;
size_t start_buf;
if (buf == NULL)
return(0);
/* Don't resize if we don't have to */
if (size < buf->size)
return 1;
if (size > UINT_MAX - 10)
return 0;
/* 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 + 10;
else
newSize = buf->size;
while (size > newSize) {
if (newSize > UINT_MAX / 2)
return 0;
newSize *= 2;
}
break;
case XML_BUFFER_ALLOC_EXACT:
newSize = 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 > UINT_MAX / 2)
return 0;
newSize *= 2;
}
}
break;
default:
newSize = 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)
return 0;
buf->contentIO = rebuf;
buf->content = rebuf + start_buf;
}
} else {
if (buf->content == NULL) {
rebuf = (xmlChar *) xmlMallocAtomic(newSize);
buf->use = 0;
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)
return 0;
buf->content = rebuf;
}
buf->size = newSize;
return 1;
}
/**
* xmlBufferAdd:
* @buf: the buffer to dump
* @str: the #xmlChar string
* @len: the number of #xmlChar to add
*
* Add a string range to an XML buffer. if len == -1, the length of
* str is recomputed.
*
* Returns 0 successful, a positive error code number otherwise
* and -1 in case of internal or API error.
*/
int
xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
unsigned int needSize;
if ((str == NULL) || (buf == NULL)) {
return -1;
}
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 ((unsigned) len >= buf->size - buf->use) {
if ((unsigned) len >= UINT_MAX - buf->use)
return XML_ERR_NO_MEMORY;
needSize = buf->use + len + 1;
if (!xmlBufferResize(buf, needSize))
return XML_ERR_NO_MEMORY;
}
memmove(&buf->content[buf->use], str, len);
buf->use += len;
buf->content[buf->use] = 0;
return 0;
}
/**
* xmlBufferAddHead:
* @buf: the buffer
* @str: the #xmlChar string
* @len: the number of #xmlChar to add
*
* Add a string range to the beginning of an XML buffer.
* if len == -1, the length of @str is recomputed.
*
* Returns 0 successful, a positive error code number otherwise
* and -1 in case of internal or API error.
*/
int
xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
unsigned int needSize;
if (buf == NULL)
return(-1);
if (str == NULL) {
return -1;
}
if (len < -1) {
return -1;
}
if (len == 0) return 0;
if (len < 0)
len = xmlStrlen(str);
if (len <= 0) return -1;
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
size_t start_buf = buf->content - buf->contentIO;
if (start_buf > (unsigned int) len) {
/*
* We can add it in the space previously shrunk
*/
buf->content -= len;
memmove(&buf->content[0], str, len);
buf->use += len;
buf->size += len;
buf->content[buf->use] = 0;
return(0);
}
}
/* Note that both buf->size and buf->use can be zero here. */
if ((unsigned) len >= buf->size - buf->use) {
if ((unsigned) len >= UINT_MAX - buf->use)
return(-1);
needSize = buf->use + len + 1;
if (!xmlBufferResize(buf, needSize))
return(-1);
}
memmove(&buf->content[len], &buf->content[0], buf->use);
memmove(&buf->content[0], str, len);
buf->use += len;
buf->content[buf->use] = 0;
return 0;
}
/**
* xmlBufferCat:
* @buf: the buffer to add to
* @str: the #xmlChar string
*
* Append a zero terminated string to an XML buffer.
*
* Returns 0 successful, a positive error code number otherwise
* and -1 in case of internal or API error.
*/
int
xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
if (buf == NULL)
return(-1);
if (str == NULL) return -1;
return xmlBufferAdd(buf, str, -1);
}
/**
* xmlBufferCCat:
* @buf: the buffer to dump
* @str: the C char string
*
* Append a zero terminated C string to an XML buffer.
*
* Returns 0 successful, a positive error code number otherwise
* and -1 in case of internal or API error.
*/
int
xmlBufferCCat(xmlBufferPtr buf, const char *str) {
return xmlBufferCat(buf, (const xmlChar *) str);
}
/**
* xmlBufferWriteCHAR:
* @buf: the XML buffer
* @string: the string to add
*
* routine which manages and grows an output buffer. This one adds
* xmlChars at the end of the buffer.
*/
void
xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
if (buf == NULL)
return;
xmlBufferCat(buf, string);
}
/**
* xmlBufferWriteChar:
* @buf: the XML buffer output
* @string: the string to add
*
* routine which manage and grows an output buffer. This one add
* C chars at the end of the array.
*/
void
xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
if (buf == NULL)
return;
xmlBufferCCat(buf, string);
}
/**
* xmlBufferWriteQuotedString:
* @buf: the XML buffer output
* @string: the string to add
*
* routine which manage and grows an output buffer. This one writes
* a quoted or double quoted #xmlChar string, checking first if it holds
* quote or double-quotes internally
*/
void
xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
const xmlChar *cur, *base;
if (buf == NULL)
return;
if (xmlStrchr(string, '\"')) {
if (xmlStrchr(string, '\'')) {
xmlBufferCCat(buf, "\"");
base = cur = string;
while(*cur != 0){
if(*cur == '"'){
if (base != cur)
xmlBufferAdd(buf, base, cur - base);
xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
cur++;
base = cur;
}
else {
cur++;
}
}
if (base != cur)
xmlBufferAdd(buf, base, cur - base);
xmlBufferCCat(buf, "\"");
}
else{
xmlBufferCCat(buf, "\'");
xmlBufferCat(buf, string);
xmlBufferCCat(buf, "\'");
}
} else {
xmlBufferCCat(buf, "\"");
xmlBufferCat(buf, string);
xmlBufferCCat(buf, "\"");
}
}
/**
* xmlGetDocCompressMode:
* @doc: the document