2012-07-11 12:48:47 +04:00
/*
* buf . c : memory buffers for libxml2
*
2019-09-30 18:04:54 +03:00
* new buffer structures and entry points to simplify the maintenance
2012-07-11 12:48:47 +04:00
* of libxml2 and ensure we keep good control over memory allocations
* and stay 64 bits clean .
* The new entry point use the xmlBufPtr opaque structure and
* xmlBuf . . . ( ) counterparts to the old xmlBuf . . . ( ) functions
*
* See Copyright for the status of this software .
*
* daniel @ veillard . com
*/
# define IN_LIBXML
# include "libxml.h"
# include <string.h> /* for memset() only ! */
# include <limits.h>
# include <ctype.h>
# include <stdlib.h>
# include <libxml/tree.h>
2015-04-14 12:41:48 +03:00
# include <libxml/parserInternals.h> /* for XML_MAX_TEXT_LENGTH */
2022-08-26 02:22:33 +03:00
# include "private/buf.h"
# include "private/error.h"
2012-07-11 12:48:47 +04:00
2022-03-08 22:10:02 +03:00
# ifndef SIZE_MAX
# define SIZE_MAX ((size_t) -1)
# endif
2012-08-07 10:34:53 +04:00
# define WITH_BUFFER_COMPAT
2012-07-11 12:48:47 +04:00
/**
* xmlBuf :
*
2012-07-16 15:57:42 +04:00
* A buffer structure . The base of the structure is somehow compatible
* with struct _xmlBuffer to limit risks on application which accessed
* directly the input - > buf - > buffer structures .
2012-07-11 12:48:47 +04:00
*/
struct _xmlBuf {
xmlChar * content ; /* The buffer content UTF8 */
2012-07-16 15:57:42 +04:00
unsigned int compat_use ; /* for binary compatibility */
unsigned int compat_size ; /* for binary compatibility */
2012-07-11 12:48:47 +04:00
xmlBufferAllocationScheme alloc ; /* The realloc method */
xmlChar * contentIO ; /* in IO mode we may have a different base */
2012-07-16 15:57:42 +04:00
size_t use ; /* The buffer size used */
size_t size ; /* The buffer size */
2012-07-11 12:48:47 +04:00
xmlBufferPtr buffer ; /* wrapper for an old buffer */
2017-06-17 17:15:09 +03:00
int error ; /* an error code if a failure occurred */
2012-07-11 12:48:47 +04:00
} ;
2012-08-07 10:34:53 +04:00
# ifdef WITH_BUFFER_COMPAT
/*
* Macro for compatibility with xmlBuffer to be used after an xmlBuf
* is updated . This makes sure the compat fields are updated too .
*/
2012-08-06 06:16:41 +04:00
# define UPDATE_COMPAT(buf) \
if ( buf - > size < INT_MAX ) buf - > compat_size = buf - > size ; \
else buf - > compat_size = INT_MAX ; \
if ( buf - > use < INT_MAX ) buf - > compat_use = buf - > use ; \
else buf - > compat_use = INT_MAX ;
2012-08-07 10:34:53 +04:00
/*
* Macro for compatibility with xmlBuffer to be used in all the xmlBuf
* entry points , it checks that the compat fields have not been modified
* by direct call to xmlBuffer function from code compiled before 2.9 .0 .
*/
# define CHECK_COMPAT(buf) \
if ( buf - > size ! = ( size_t ) buf - > compat_size ) \
if ( buf - > compat_size < INT_MAX ) \
buf - > size = buf - > compat_size ; \
if ( buf - > use ! = ( size_t ) buf - > compat_use ) \
if ( buf - > compat_use < INT_MAX ) \
buf - > use = buf - > compat_use ;
# else /* ! WITH_BUFFER_COMPAT */
# define UPDATE_COMPAT(buf)
# define CHECK_COMPAT(buf)
# endif /* WITH_BUFFER_COMPAT */
2012-07-11 12:48:47 +04:00
/**
* xmlBufMemoryError :
2020-03-08 19:19:42 +03:00
* @ extra : extra information
2012-07-11 12:48:47 +04:00
*
* Handle an out of memory condition
* To be improved . . .
*/
static void
2023-12-10 17:18:55 +03:00
xmlBufMemoryError ( xmlBufPtr buf )
2012-07-11 12:48:47 +04:00
{
2023-12-10 17:18:55 +03:00
if ( buf - > error = = 0 )
2012-07-11 12:48:47 +04:00
buf - > error = XML_ERR_NO_MEMORY ;
}
/**
* xmlBufOverflowError :
2020-03-08 19:19:42 +03:00
* @ extra : extra information
2012-07-11 12:48:47 +04:00
*
* Handle a buffer overflow error
* To be improved . . .
*/
static void
2023-12-10 17:18:55 +03:00
xmlBufOverflowError ( xmlBufPtr buf )
2012-07-11 12:48:47 +04:00
{
2023-12-10 17:18:55 +03:00
if ( buf - > error = = 0 )
2012-07-11 12:48:47 +04:00
buf - > error = XML_BUF_OVERFLOW ;
}
/**
* xmlBufCreate :
*
* routine to create an XML buffer .
* returns the new structure .
*/
xmlBufPtr
xmlBufCreate ( void ) {
xmlBufPtr ret ;
ret = ( xmlBufPtr ) xmlMalloc ( sizeof ( xmlBuf ) ) ;
2023-12-10 17:18:55 +03:00
if ( ret = = NULL )
2012-07-11 12:48:47 +04:00
return ( NULL ) ;
ret - > use = 0 ;
ret - > error = 0 ;
ret - > buffer = NULL ;
ret - > size = xmlDefaultBufferSize ;
2022-04-08 22:16:51 +03:00
UPDATE_COMPAT ( ret ) ;
2012-07-11 12:48:47 +04:00
ret - > alloc = xmlBufferAllocScheme ;
2022-09-01 04:14:13 +03:00
ret - > content = ( xmlChar * ) xmlMallocAtomic ( ret - > size ) ;
2012-07-11 12:48:47 +04:00
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 ) {
xmlBufPtr ret ;
2022-03-08 22:10:02 +03:00
if ( size = = SIZE_MAX )
return ( NULL ) ;
2012-07-11 12:48:47 +04:00
ret = ( xmlBufPtr ) xmlMalloc ( sizeof ( xmlBuf ) ) ;
2023-12-10 17:18:55 +03:00
if ( ret = = NULL )
2012-07-11 12:48:47 +04:00
return ( NULL ) ;
ret - > use = 0 ;
ret - > error = 0 ;
ret - > buffer = NULL ;
ret - > alloc = xmlBufferAllocScheme ;
2022-03-08 22:10:02 +03:00
ret - > size = ( size ? size + 1 : 0 ) ; /* +1 for ending null */
2022-04-08 22:16:51 +03:00
UPDATE_COMPAT ( ret ) ;
2012-07-11 12:48:47 +04:00
if ( ret - > size ) {
2022-09-01 04:14:13 +03:00
ret - > content = ( xmlChar * ) xmlMallocAtomic ( ret - > size ) ;
2012-07-11 12:48:47 +04:00
if ( ret - > content = = NULL ) {
xmlFree ( ret ) ;
return ( NULL ) ;
}
ret - > content [ 0 ] = 0 ;
} else
ret - > content = NULL ;
ret - > contentIO = NULL ;
return ( ret ) ;
}
/**
* xmlBufDetach :
* @ buf : the buffer
*
2012-08-07 10:34:53 +04:00
* Remove the string contained in a buffer and give it back to the
2012-07-11 12:48:47 +04:00
* 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 *
xmlBufDetach ( xmlBufPtr buf ) {
xmlChar * ret ;
if ( buf = = NULL )
return ( NULL ) ;
if ( buf - > buffer ! = NULL )
return ( NULL ) ;
if ( buf - > error )
return ( NULL ) ;
2024-03-18 16:20:19 +03:00
if ( ( buf - > alloc = = XML_BUFFER_ALLOC_IO ) & &
( buf - > content ! = buf - > contentIO ) ) {
ret = xmlStrndup ( buf - > content , buf - > use ) ;
xmlFree ( buf - > contentIO ) ;
} else {
ret = buf - > content ;
}
2012-07-11 12:48:47 +04:00
buf - > content = NULL ;
2024-03-18 16:20:19 +03:00
buf - > contentIO = NULL ;
2012-07-11 12:48:47 +04:00
buf - > size = 0 ;
buf - > use = 0 ;
2022-04-08 22:16:51 +03:00
UPDATE_COMPAT ( buf ) ;
2012-07-11 12:48:47 +04:00
return ret ;
}
/**
2012-08-10 06:00:18 +04:00
* xmlBufGetAllocationScheme :
* @ buf : the buffer
2012-07-11 12:48:47 +04:00
*
2012-08-10 06:00:18 +04:00
* Get the buffer allocation scheme
2012-07-11 12:48:47 +04:00
*
2012-08-10 06:00:18 +04:00
* Returns the scheme or - 1 in case of error
2012-07-11 12:48:47 +04:00
*/
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 ) {
2012-07-16 15:57:42 +04:00
if ( ( buf = = NULL ) | | ( buf - > error ! = 0 ) ) {
2012-07-11 12:48:47 +04:00
return ( - 1 ) ;
}
2022-11-15 00:27:58 +03:00
if ( buf - > alloc = = XML_BUFFER_ALLOC_IO )
2012-07-11 12:48:47 +04:00
return ( - 1 ) ;
if ( ( scheme = = XML_BUFFER_ALLOC_DOUBLEIT ) | |
( scheme = = XML_BUFFER_ALLOC_EXACT ) | |
( scheme = = XML_BUFFER_ALLOC_HYBRID ) | |
2015-04-14 12:41:48 +03:00
( scheme = = XML_BUFFER_ALLOC_BOUNDED ) ) {
2012-07-11 12:48:47 +04:00
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
*
* Frees an XML buffer . It frees both the content and the structure which
* encapsulate it .
*/
void
xmlBufFree ( xmlBufPtr buf ) {
if ( buf = = NULL ) {
return ;
}
if ( ( buf - > alloc = = XML_BUFFER_ALLOC_IO ) & &
( buf - > contentIO ! = NULL ) ) {
xmlFree ( buf - > contentIO ) ;
2022-11-15 00:27:58 +03:00
} else if ( buf - > content ! = NULL ) {
2012-07-11 12:48:47 +04:00
xmlFree ( buf - > content ) ;
}
xmlFree ( buf ) ;
}
/**
* xmlBufEmpty :
* @ buf : the buffer
*
* empty a buffer .
*/
void
xmlBufEmpty ( xmlBufPtr buf ) {
2012-07-16 15:57:42 +04:00
if ( ( buf = = NULL ) | | ( buf - > error ! = 0 ) ) return ;
2012-07-11 12:48:47 +04:00
if ( buf - > content = = NULL ) return ;
2012-08-07 10:34:53 +04:00
CHECK_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
buf - > use = 0 ;
2022-11-15 00:27:58 +03:00
if ( ( buf - > alloc = = XML_BUFFER_ALLOC_IO ) & &
2012-07-11 12:48:47 +04:00
( 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 ;
}
2012-08-06 06:16:41 +04:00
UPDATE_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
}
/**
* xmlBufShrink :
* @ buf : the buffer to dump
* @ len : the number of xmlChar to remove
*
* Remove the beginning of an XML buffer .
* NOTE that this routine behaviour differs from xmlBufferShrink ( )
* as it will return 0 on error instead of - 1 due to size_t being
* used as the return type .
*
* Returns the number of byte removed or 0 in case of failure
*/
size_t
xmlBufShrink ( xmlBufPtr buf , size_t len ) {
2012-07-16 15:57:42 +04:00
if ( ( buf = = NULL ) | | ( buf - > error ! = 0 ) ) return ( 0 ) ;
2012-08-07 10:34:53 +04:00
CHECK_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
if ( len = = 0 ) return ( 0 ) ;
if ( len > buf - > use ) return ( 0 ) ;
buf - > use - = len ;
2022-11-15 00:27:58 +03:00
if ( ( buf - > alloc = = XML_BUFFER_ALLOC_IO ) & & ( buf - > contentIO ! = NULL ) ) {
2012-07-11 12:48:47 +04:00
/*
* we just move the content pointer , but also make sure
2019-09-30 18:04:54 +03:00
* the perceived buffer size has shrunk accordingly
2012-07-11 12:48:47 +04:00
*/
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 ;
}
2012-08-06 06:16:41 +04:00
UPDATE_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
return ( len ) ;
}
/**
* xmlBufGrowInternal :
* @ buf : the buffer
* @ 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
*/
static size_t
xmlBufGrowInternal ( xmlBufPtr buf , size_t len ) {
size_t size ;
xmlChar * newbuf ;
2012-07-16 15:57:42 +04:00
if ( ( buf = = NULL ) | | ( buf - > error ! = 0 ) ) return ( 0 ) ;
2012-08-07 10:34:53 +04:00
CHECK_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
2022-03-08 22:10:02 +03:00
if ( len < buf - > size - buf - > use )
2022-05-14 00:43:33 +03:00
return ( buf - > size - buf - > use - 1 ) ;
if ( len > = SIZE_MAX - buf - > use ) {
2023-12-10 17:18:55 +03:00
xmlBufMemoryError ( buf ) ;
2022-03-08 22:10:02 +03:00
return ( 0 ) ;
2022-05-14 00:43:33 +03:00
}
2012-07-11 12:48:47 +04:00
2022-03-08 22:10:02 +03:00
if ( buf - > size > ( size_t ) len ) {
size = buf - > size > SIZE_MAX / 2 ? SIZE_MAX : buf - > size * 2 ;
} else {
size = buf - > use + len ;
size = size > SIZE_MAX - 100 ? SIZE_MAX : size + 100 ;
}
2012-07-11 12:48:47 +04:00
2015-04-14 12:41:48 +03:00
if ( buf - > alloc = = XML_BUFFER_ALLOC_BOUNDED ) {
/*
* Used to provide parsing limits
*/
2022-05-14 00:43:33 +03:00
if ( ( buf - > use + len + 1 > = XML_MAX_TEXT_LENGTH ) | |
2015-04-14 12:41:48 +03:00
( buf - > size > = XML_MAX_TEXT_LENGTH ) ) {
2023-12-10 17:18:55 +03:00
xmlBufMemoryError ( buf ) ;
2015-04-14 12:41:48 +03:00
return ( 0 ) ;
}
if ( size > = XML_MAX_TEXT_LENGTH )
size = XML_MAX_TEXT_LENGTH ;
}
2012-07-11 12:48:47 +04:00
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 ) {
2023-12-10 17:18:55 +03:00
xmlBufMemoryError ( buf ) ;
2012-07-11 12:48:47 +04:00
return ( 0 ) ;
}
buf - > contentIO = newbuf ;
buf - > content = newbuf + start_buf ;
} else {
newbuf = ( xmlChar * ) xmlRealloc ( buf - > content , size ) ;
if ( newbuf = = NULL ) {
2023-12-10 17:18:55 +03:00
xmlBufMemoryError ( buf ) ;
2012-07-11 12:48:47 +04:00
return ( 0 ) ;
}
buf - > content = newbuf ;
}
buf - > size = size ;
2012-08-06 06:16:41 +04:00
UPDATE_COMPAT ( buf )
2022-05-14 00:43:33 +03:00
return ( buf - > size - buf - > use - 1 ) ;
2012-07-11 12:48:47 +04:00
}
/**
* xmlBufGrow :
* @ buf : the buffer
* @ len : the minimum free size to allocate
*
* 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
*/
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 )
return ( - 1 ) ;
2022-09-01 02:18:30 +03:00
return ( ret > INT_MAX ? INT_MAX : ret ) ;
2012-07-11 12:48:47 +04:00
}
/**
* 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 ;
2012-07-16 15:57:42 +04:00
if ( ( buf = = NULL ) | | ( buf - > error ! = 0 ) ) {
2012-07-11 12:48:47 +04:00
return ( 0 ) ;
}
if ( buf - > content = = NULL ) {
return ( 0 ) ;
}
2012-08-07 10:34:53 +04:00
CHECK_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
if ( file = = NULL )
file = stdout ;
2022-09-01 04:14:13 +03:00
ret = fwrite ( buf - > content , 1 , buf - > use , file ) ;
2012-07-11 12:48:47 +04:00
return ( ret ) ;
}
/**
* xmlBufContent :
* @ buf : the buffer
*
* Function to extract the content of a buffer
*
* Returns the internal content
*/
xmlChar *
2014-10-13 12:06:21 +04:00
xmlBufContent ( const xmlBuf * buf )
2012-07-11 12:48:47 +04:00
{
2012-07-16 15:57:42 +04:00
if ( ( ! buf ) | | ( buf - > error ) )
2012-07-11 12:48:47 +04:00
return NULL ;
return ( buf - > content ) ;
}
/**
* xmlBufEnd :
* @ buf : the buffer
*
* Function to extract the end of the content of a buffer
*
* Returns the end of the internal content or NULL in case of error
*/
xmlChar *
2014-10-13 12:06:21 +04:00
xmlBufEnd ( xmlBufPtr buf )
2012-07-11 12:48:47 +04:00
{
2012-07-16 15:57:42 +04:00
if ( ( ! buf ) | | ( buf - > error ) )
2012-07-11 12:48:47 +04:00
return NULL ;
2012-08-07 10:34:53 +04:00
CHECK_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
return ( & buf - > content [ buf - > use ] ) ;
}
/**
* xmlBufAddLen :
* @ buf : the buffer
* @ len : the size which were added at the end
*
* Sometime data may be added at the end of the buffer without
* using the xmlBuf APIs that is used to expand the used space
* and set the zero terminating at the end of the buffer
*
* Returns - 1 in case of error and 0 otherwise
*/
int
xmlBufAddLen ( xmlBufPtr buf , size_t len ) {
2012-08-07 10:34:53 +04:00
if ( ( buf = = NULL ) | | ( buf - > error ) )
return ( - 1 ) ;
CHECK_COMPAT ( buf )
2022-05-29 19:46:00 +03:00
if ( len > = ( buf - > size - buf - > use ) )
2012-07-11 12:48:47 +04:00
return ( - 1 ) ;
buf - > use + = len ;
2022-05-29 19:46:00 +03:00
buf - > content [ buf - > use ] = 0 ;
2012-08-06 06:16:41 +04:00
UPDATE_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
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 )
{
2012-07-16 15:57:42 +04:00
if ( ( ! buf ) | | ( buf - > error ) )
2012-07-11 12:48:47 +04:00
return 0 ;
2012-08-07 10:34:53 +04:00
CHECK_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
return ( buf - > use ) ;
}
/**
* xmlBufUse :
* @ buf : the buffer
*
* Function to get the length of a buffer
*
* Returns the length of data in the internal content
*/
size_t
xmlBufUse ( const xmlBufPtr buf )
{
2012-07-16 15:57:42 +04:00
if ( ( ! buf ) | | ( buf - > error ) )
2012-07-11 12:48:47 +04:00
return 0 ;
2012-08-07 10:34:53 +04:00
CHECK_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
return ( buf - > use ) ;
}
/**
* xmlBufAvail :
* @ buf : the buffer
*
* Function to find how much free space is allocated but not
2022-05-26 04:13:07 +03:00
* used in the buffer . It reserves one byte for the NUL
* terminator character that is usually needed , so there is
* no need to subtract 1 from the result anymore .
2012-07-11 12:48:47 +04:00
*
2022-05-26 04:13:07 +03:00
* Returns the amount , or 0 if none or if an error occurred .
2012-07-11 12:48:47 +04:00
*/
size_t
xmlBufAvail ( const xmlBufPtr buf )
{
2012-07-16 15:57:42 +04:00
if ( ( ! buf ) | | ( buf - > error ) )
2012-07-11 12:48:47 +04:00
return 0 ;
2012-08-07 10:34:53 +04:00
CHECK_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
2022-05-26 04:13:07 +03:00
return ( ( buf - > size > buf - > use ) ? ( buf - > size - buf - > use - 1 ) : 0 ) ;
2012-07-11 12:48:47 +04:00
}
/**
* xmlBufIsEmpty :
* @ buf : the buffer
*
* Tell if a buffer is empty
*
* Returns 0 if no , 1 if yes and - 1 in case of error
*/
int
xmlBufIsEmpty ( const xmlBufPtr buf )
{
2012-07-16 15:57:42 +04:00
if ( ( ! buf ) | | ( buf - > error ) )
2012-07-11 12:48:47 +04:00
return ( - 1 ) ;
2012-08-07 10:34:53 +04:00
CHECK_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
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 )
{
2022-03-08 22:10:02 +03:00
size_t newSize ;
2012-07-11 12:48:47 +04:00
xmlChar * rebuf = NULL ;
size_t start_buf ;
2012-07-16 15:57:42 +04:00
if ( ( buf = = NULL ) | | ( buf - > error ) )
2012-07-11 12:48:47 +04:00
return ( 0 ) ;
2012-08-07 10:34:53 +04:00
CHECK_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
2015-04-14 12:41:48 +03:00
if ( buf - > alloc = = XML_BUFFER_ALLOC_BOUNDED ) {
/*
* Used to provide parsing limits
*/
if ( size > = XML_MAX_TEXT_LENGTH ) {
2023-12-10 17:18:55 +03:00
xmlBufMemoryError ( buf ) ;
2015-04-14 12:41:48 +03:00
return ( 0 ) ;
}
}
2012-07-11 12:48:47 +04:00
/* 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*/
2022-03-08 22:10:02 +03:00
if ( buf - > size = = 0 ) {
newSize = ( size > SIZE_MAX - 10 ? SIZE_MAX : size + 10 ) ;
} else {
newSize = buf - > size ;
}
2012-07-11 12:48:47 +04:00
while ( size > newSize ) {
2022-03-08 22:10:02 +03:00
if ( newSize > SIZE_MAX / 2 ) {
2023-12-10 17:18:55 +03:00
xmlBufMemoryError ( buf ) ;
2012-07-11 12:48:47 +04:00
return 0 ;
}
newSize * = 2 ;
}
break ;
case XML_BUFFER_ALLOC_EXACT :
2022-03-08 22:10:02 +03:00
newSize = ( size > SIZE_MAX - 10 ? SIZE_MAX : size + 10 ) ;
2012-07-11 12:48:47 +04:00
break ;
case XML_BUFFER_ALLOC_HYBRID :
if ( buf - > use < BASE_BUFFER_SIZE )
newSize = size ;
else {
2022-03-08 22:10:02 +03:00
newSize = buf - > size ;
2012-07-11 12:48:47 +04:00
while ( size > newSize ) {
2022-03-08 22:10:02 +03:00
if ( newSize > SIZE_MAX / 2 ) {
2023-12-10 17:18:55 +03:00
xmlBufMemoryError ( buf ) ;
2012-07-11 12:48:47 +04:00
return 0 ;
}
newSize * = 2 ;
}
}
break ;
default :
2022-03-08 22:10:02 +03:00
newSize = ( size > SIZE_MAX - 10 ? SIZE_MAX : size + 10 ) ;
2012-07-11 12:48:47 +04:00
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 ) {
2023-12-10 17:18:55 +03:00
xmlBufMemoryError ( buf ) ;
2012-07-11 12:48:47 +04:00
return 0 ;
}
buf - > contentIO = rebuf ;
buf - > content = rebuf + start_buf ;
}
} else {
if ( buf - > content = = NULL ) {
rebuf = ( xmlChar * ) xmlMallocAtomic ( newSize ) ;
2022-05-29 19:46:00 +03:00
buf - > use = 0 ;
2023-01-22 15:20:15 +03:00
if ( rebuf ! = NULL )
rebuf [ buf - > use ] = 0 ;
2012-07-11 12:48:47 +04:00
} 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 ) {
2023-12-10 17:18:55 +03:00
xmlBufMemoryError ( buf ) ;
2012-07-11 12:48:47 +04:00
return 0 ;
}
buf - > content = rebuf ;
}
buf - > size = newSize ;
2012-08-06 06:16:41 +04:00
UPDATE_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
return 1 ;
}
/**
* xmlBufAdd :
* @ 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 .
*
2024-03-06 17:21:49 +03:00
* Returns 0 if successful , - 1 in case of error .
2012-07-11 12:48:47 +04:00
*/
int
xmlBufAdd ( xmlBufPtr buf , const xmlChar * str , int len ) {
2022-03-08 22:10:02 +03:00
size_t needSize ;
2012-07-11 12:48:47 +04:00
2012-08-07 10:34:53 +04:00
if ( ( str = = NULL ) | | ( buf = = NULL ) | | ( buf - > error ) )
2012-07-11 12:48:47 +04:00
return - 1 ;
2012-08-07 10:34:53 +04:00
CHECK_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
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 ;
2022-05-14 00:43:33 +03:00
/* Note that both buf->size and buf->use can be zero here. */
2022-03-08 22:10:02 +03:00
if ( ( size_t ) len > = buf - > size - buf - > use ) {
2022-05-14 00:43:33 +03:00
if ( ( size_t ) len > = SIZE_MAX - buf - > use ) {
2023-12-10 17:18:55 +03:00
xmlBufMemoryError ( buf ) ;
2022-03-08 22:10:02 +03:00
return ( - 1 ) ;
2022-05-14 00:43:33 +03:00
}
2022-03-08 22:10:02 +03:00
needSize = buf - > use + len + 1 ;
2015-04-14 12:41:48 +03:00
if ( buf - > alloc = = XML_BUFFER_ALLOC_BOUNDED ) {
/*
* Used to provide parsing limits
*/
if ( needSize > = XML_MAX_TEXT_LENGTH ) {
2023-12-10 17:18:55 +03:00
xmlBufMemoryError ( buf ) ;
2015-04-14 12:41:48 +03:00
return ( - 1 ) ;
}
}
2024-03-06 17:21:49 +03:00
if ( ! xmlBufResize ( buf , needSize ) )
return ( - 1 ) ;
2012-07-11 12:48:47 +04:00
}
2022-09-01 04:14:13 +03:00
memmove ( & buf - > content [ buf - > use ] , str , len ) ;
2012-07-11 12:48:47 +04:00
buf - > use + = len ;
buf - > content [ buf - > use ] = 0 ;
2012-08-06 06:16:41 +04:00
UPDATE_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
return 0 ;
}
/**
* xmlBufCat :
* @ 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
xmlBufCat ( xmlBufPtr buf , const xmlChar * str ) {
2012-07-16 15:57:42 +04:00
if ( ( buf = = NULL ) | | ( buf - > error ) )
2012-07-11 12:48:47 +04:00
return ( - 1 ) ;
2012-08-07 10:34:53 +04:00
CHECK_COMPAT ( buf )
2012-07-11 12:48:47 +04:00
if ( str = = NULL ) return - 1 ;
return xmlBufAdd ( buf , str , - 1 ) ;
}
/**
* xmlBufFromBuffer :
* @ buffer : incoming old buffer to convert to a new one
*
* Helper routine to switch from the old buffer structures in use
* in various APIs . It creates a wrapper xmlBufPtr which will be
* used for internal processing until the xmlBufBackToBuffer ( ) is
* issued .
*
* Returns a new xmlBufPtr unless the call failed and NULL is returned
*/
xmlBufPtr
xmlBufFromBuffer ( xmlBufferPtr buffer ) {
xmlBufPtr ret ;
if ( buffer = = NULL )
return ( NULL ) ;
ret = ( xmlBufPtr ) xmlMalloc ( sizeof ( xmlBuf ) ) ;
if ( ret = = NULL ) {
return ( NULL ) ;
}
ret - > use = buffer - > use ;
ret - > size = buffer - > size ;
2022-04-08 22:16:51 +03:00
UPDATE_COMPAT ( ret ) ;
2012-07-11 12:48:47 +04:00
ret - > error = 0 ;
ret - > buffer = buffer ;
ret - > alloc = buffer - > alloc ;
ret - > content = buffer - > content ;
ret - > contentIO = buffer - > contentIO ;
return ( ret ) ;
}
/**
* xmlBufBackToBuffer :
* @ buf : new buffer wrapping the old one
*
* Function to be called once internal processing had been done to
* update back the buffer provided by the user . This can lead to
* a failure in case the size accumulated in the xmlBuf is larger
* than what an xmlBuffer can support on 64 bits ( INT_MAX )
* The xmlBufPtr @ buf wrapper is deallocated by this call in any case .
*
* Returns the old xmlBufferPtr unless the call failed and NULL is returned
*/
xmlBufferPtr
xmlBufBackToBuffer ( xmlBufPtr buf ) {
xmlBufferPtr ret ;
2019-09-13 16:51:16 +03:00
if ( buf = = NULL )
2012-07-11 12:48:47 +04:00
return ( NULL ) ;
2012-08-07 10:34:53 +04:00
CHECK_COMPAT ( buf )
2024-03-04 03:25:46 +03:00
ret = buf - > buffer ;
if ( ( buf - > error ) | | ( ret = = NULL ) ) {
2012-07-11 12:48:47 +04:00
xmlBufFree ( buf ) ;
2024-03-04 03:25:46 +03:00
if ( ret ! = NULL ) {
ret - > content = NULL ;
ret - > contentIO = NULL ;
ret - > use = 0 ;
ret - > size = 0 ;
}
2012-07-11 12:48:47 +04:00
return ( NULL ) ;
}
/*
* 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 .
*/
2023-12-10 17:18:55 +03:00
xmlBufOverflowError ( buf ) ;
2012-07-11 12:48:47 +04:00
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 .
*/
2023-12-10 17:18:55 +03:00
xmlBufOverflowError ( buf ) ;
2022-09-01 02:18:30 +03:00
ret - > use = buf - > use ;
2012-07-11 12:48:47 +04:00
ret - > size = INT_MAX ;
2019-11-07 14:54:01 +03:00
} else {
2022-09-01 02:18:30 +03:00
ret - > use = buf - > use ;
ret - > size = buf - > size ;
2012-07-11 12:48:47 +04:00
}
ret - > alloc = buf - > alloc ;
ret - > content = buf - > content ;
ret - > contentIO = buf - > contentIO ;
xmlFree ( buf ) ;
return ( ret ) ;
}
2012-07-16 12:28:47 +04:00
/**
* xmlBufResetInput :
* @ buf : an xmlBufPtr
* @ input : an xmlParserInputPtr
*
* Update the input to use the current set of pointers from the buffer .
*
2012-07-16 14:03:01 +04:00
* Returns - 1 in case of error , 0 otherwise
2012-07-16 12:28:47 +04:00
*/
int
xmlBufResetInput ( xmlBufPtr buf , xmlParserInputPtr input ) {
2023-12-12 17:13:11 +03:00
return ( xmlBufUpdateInput ( buf , input , 0 ) ) ;
2012-07-16 12:28:47 +04:00
}
2012-07-16 14:03:01 +04:00
/**
2023-08-08 16:21:14 +03:00
* xmlBufUpdateInput :
2012-07-16 14:03:01 +04:00
* @ buf : an xmlBufPtr
* @ input : an xmlParserInputPtr
2023-08-08 16:21:14 +03:00
* @ pos : the cur value relative to the beginning of the buffer
2012-07-16 14:03:01 +04:00
*
* Update the input to use the base and cur relative to the buffer
* after a possible reallocation of its content
*
* Returns - 1 in case of error , 0 otherwise
*/
int
2023-08-08 16:21:14 +03:00
xmlBufUpdateInput ( xmlBufPtr buf , xmlParserInputPtr input , size_t pos ) {
2023-12-12 17:13:11 +03:00
if ( ( buf = = NULL ) | | ( input = = NULL ) )
2012-07-16 14:03:01 +04:00
return ( - 1 ) ;
2012-08-07 10:34:53 +04:00
CHECK_COMPAT ( buf )
2023-08-08 16:21:14 +03:00
input - > base = buf - > content ;
input - > cur = input - > base + pos ;
2012-07-16 14:03:01 +04:00
input - > end = & buf - > content [ buf - > use ] ;
return ( 0 ) ;
}
2012-09-12 02:32:11 +04:00