2012-07-11 16:48:47 +08:00
/*
* buf . c : memory buffers for libxml2
*
2019-09-30 17:04:54 +02:00
* new buffer structures and entry points to simplify the maintenance
2012-07-11 16:48:47 +08: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>
# include <libxml/globals.h>
# include <libxml/tree.h>
2015-04-14 17:41:48 +08:00
# include <libxml/parserInternals.h> /* for XML_MAX_TEXT_LENGTH */
2022-08-26 01:22:33 +02:00
# include "private/buf.h"
# include "private/error.h"
2012-07-11 16:48:47 +08:00
2022-03-08 20:10:02 +01:00
# ifndef SIZE_MAX
# define SIZE_MAX ((size_t) -1)
# endif
2012-08-07 14:34:53 +08:00
# define WITH_BUFFER_COMPAT
2012-07-11 16:48:47 +08:00
/**
* xmlBuf :
*
2012-07-16 19:57:42 +08: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 16:48:47 +08:00
*/
struct _xmlBuf {
xmlChar * content ; /* The buffer content UTF8 */
2012-07-16 19:57:42 +08:00
unsigned int compat_use ; /* for binary compatibility */
unsigned int compat_size ; /* for binary compatibility */
2012-07-11 16:48:47 +08:00
xmlBufferAllocationScheme alloc ; /* The realloc method */
xmlChar * contentIO ; /* in IO mode we may have a different base */
2012-07-16 19:57:42 +08:00
size_t use ; /* The buffer size used */
size_t size ; /* The buffer size */
2012-07-11 16:48:47 +08:00
xmlBufferPtr buffer ; /* wrapper for an old buffer */
2017-06-17 16:15:09 +02:00
int error ; /* an error code if a failure occurred */
2012-07-11 16:48:47 +08:00
} ;
2012-08-07 14:34:53 +08: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 10:16:41 +08: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 14:34:53 +08: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 16:48:47 +08:00
/**
* xmlBufMemoryError :
2020-03-08 17:19:42 +01:00
* @ extra : extra information
2012-07-11 16:48:47 +08:00
*
* Handle an out of memory condition
* To be improved . . .
*/
static void
xmlBufMemoryError ( xmlBufPtr buf , const char * extra )
{
__xmlSimpleError ( XML_FROM_BUFFER , XML_ERR_NO_MEMORY , NULL , NULL , extra ) ;
if ( ( buf ) & & ( buf - > error = = 0 ) )
buf - > error = XML_ERR_NO_MEMORY ;
}
/**
* xmlBufOverflowError :
2020-03-08 17:19:42 +01:00
* @ extra : extra information
2012-07-11 16:48:47 +08:00
*
* Handle a buffer overflow error
* To be improved . . .
*/
static void
xmlBufOverflowError ( xmlBufPtr buf , const char * extra )
{
__xmlSimpleError ( XML_FROM_BUFFER , XML_BUF_OVERFLOW , NULL , NULL , extra ) ;
if ( ( buf ) & & ( buf - > error = = 0 ) )
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 ) ) ;
if ( ret = = NULL ) {
xmlBufMemoryError ( NULL , " creating buffer " ) ;
return ( NULL ) ;
}
ret - > use = 0 ;
ret - > error = 0 ;
ret - > buffer = NULL ;
ret - > size = xmlDefaultBufferSize ;
2022-04-08 12:16:51 -07:00
UPDATE_COMPAT ( ret ) ;
2012-07-11 16:48:47 +08:00
ret - > alloc = xmlBufferAllocScheme ;
2022-09-01 03:14:13 +02:00
ret - > content = ( xmlChar * ) xmlMallocAtomic ( ret - > size ) ;
2012-07-11 16:48:47 +08:00
if ( ret - > content = = NULL ) {
xmlBufMemoryError ( ret , " creating buffer " ) ;
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 20:10:02 +01:00
if ( size = = SIZE_MAX )
return ( NULL ) ;
2012-07-11 16:48:47 +08:00
ret = ( xmlBufPtr ) xmlMalloc ( sizeof ( xmlBuf ) ) ;
if ( ret = = NULL ) {
xmlBufMemoryError ( NULL , " creating buffer " ) ;
return ( NULL ) ;
}
ret - > use = 0 ;
ret - > error = 0 ;
ret - > buffer = NULL ;
ret - > alloc = xmlBufferAllocScheme ;
2022-03-08 20:10:02 +01:00
ret - > size = ( size ? size + 1 : 0 ) ; /* +1 for ending null */
2022-04-08 12:16:51 -07:00
UPDATE_COMPAT ( ret ) ;
2012-07-11 16:48:47 +08:00
if ( ret - > size ) {
2022-09-01 03:14:13 +02:00
ret - > content = ( xmlChar * ) xmlMallocAtomic ( ret - > size ) ;
2012-07-11 16:48:47 +08:00
if ( ret - > content = = NULL ) {
xmlBufMemoryError ( ret , " creating buffer " ) ;
xmlFree ( ret ) ;
return ( NULL ) ;
}
ret - > content [ 0 ] = 0 ;
} else
ret - > content = NULL ;
ret - > contentIO = NULL ;
return ( ret ) ;
}
/**
* xmlBufDetach :
* @ buf : the buffer
*
2012-08-07 14:34:53 +08:00
* Remove the string contained in a buffer and give it back to the
2012-07-11 16:48:47 +08: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 - > alloc = = XML_BUFFER_ALLOC_IMMUTABLE )
return ( NULL ) ;
if ( buf - > buffer ! = NULL )
return ( NULL ) ;
if ( buf - > error )
return ( NULL ) ;
ret = buf - > content ;
buf - > content = NULL ;
buf - > size = 0 ;
buf - > use = 0 ;
2022-04-08 12:16:51 -07:00
UPDATE_COMPAT ( buf ) ;
2012-07-11 16:48:47 +08:00
return ret ;
}
/**
* xmlBufCreateStatic :
* @ mem : the memory area
* @ size : the size in byte
*
* routine to create an XML buffer from an immutable memory area .
* The area won ' t be modified nor copied , and is expected to be
* present until the end of the buffer lifetime .
*
* returns the new structure .
*/
xmlBufPtr
xmlBufCreateStatic ( void * mem , size_t size ) {
xmlBufPtr ret ;
2017-06-08 22:36:09 +02:00
if ( mem = = NULL )
2012-07-11 16:48:47 +08:00
return ( NULL ) ;
ret = ( xmlBufPtr ) xmlMalloc ( sizeof ( xmlBuf ) ) ;
if ( ret = = NULL ) {
xmlBufMemoryError ( NULL , " creating buffer " ) ;
return ( NULL ) ;
}
ret - > use = size ;
ret - > size = size ;
2022-04-08 12:16:51 -07:00
UPDATE_COMPAT ( ret ) ;
2012-07-11 16:48:47 +08:00
ret - > alloc = XML_BUFFER_ALLOC_IMMUTABLE ;
ret - > content = ( xmlChar * ) mem ;
ret - > error = 0 ;
ret - > buffer = NULL ;
return ( ret ) ;
}
/**
2012-08-10 10:00:18 +08:00
* xmlBufGetAllocationScheme :
* @ buf : the buffer
2012-07-11 16:48:47 +08:00
*
2012-08-10 10:00:18 +08:00
* Get the buffer allocation scheme
2012-07-11 16:48:47 +08:00
*
2012-08-10 10:00:18 +08:00
* Returns the scheme or - 1 in case of error
2012-07-11 16:48:47 +08:00
*/
int
xmlBufGetAllocationScheme ( xmlBufPtr buf ) {
if ( buf = = NULL ) {
# ifdef DEBUG_BUFFER
xmlGenericError ( xmlGenericErrorContext ,
" xmlBufGetAllocationScheme: buf == NULL \n " ) ;
# endif
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 19:57:42 +08:00
if ( ( buf = = NULL ) | | ( buf - > error ! = 0 ) ) {
2012-07-11 16:48:47 +08:00
# ifdef DEBUG_BUFFER
xmlGenericError ( xmlGenericErrorContext ,
2012-07-16 19:57:42 +08:00
" xmlBufSetAllocationScheme: buf == NULL or in error \n " ) ;
2012-07-11 16:48:47 +08:00
# endif
return ( - 1 ) ;
}
if ( ( buf - > alloc = = XML_BUFFER_ALLOC_IMMUTABLE ) | |
( buf - > alloc = = XML_BUFFER_ALLOC_IO ) )
return ( - 1 ) ;
if ( ( scheme = = XML_BUFFER_ALLOC_DOUBLEIT ) | |
( scheme = = XML_BUFFER_ALLOC_EXACT ) | |
( scheme = = XML_BUFFER_ALLOC_HYBRID ) | |
2015-04-14 17:41:48 +08:00
( scheme = = XML_BUFFER_ALLOC_IMMUTABLE ) | |
( scheme = = XML_BUFFER_ALLOC_BOUNDED ) ) {
2012-07-11 16:48:47 +08: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 ) {
# ifdef DEBUG_BUFFER
xmlGenericError ( xmlGenericErrorContext ,
" xmlBufFree: buf == NULL \n " ) ;
# endif
return ;
}
if ( ( buf - > alloc = = XML_BUFFER_ALLOC_IO ) & &
( buf - > contentIO ! = NULL ) ) {
xmlFree ( buf - > contentIO ) ;
} else if ( ( buf - > content ! = NULL ) & &
( buf - > alloc ! = XML_BUFFER_ALLOC_IMMUTABLE ) ) {
xmlFree ( buf - > content ) ;
}
xmlFree ( buf ) ;
}
/**
* xmlBufEmpty :
* @ buf : the buffer
*
* empty a buffer .
*/
void
xmlBufEmpty ( xmlBufPtr buf ) {
2012-07-16 19:57:42 +08:00
if ( ( buf = = NULL ) | | ( buf - > error ! = 0 ) ) return ;
2012-07-11 16:48:47 +08:00
if ( buf - > content = = NULL ) return ;
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2012-07-11 16:48:47 +08:00
buf - > use = 0 ;
if ( buf - > alloc = = XML_BUFFER_ALLOC_IMMUTABLE ) {
buf - > content = BAD_CAST " " ;
} else 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 ;
}
2012-08-06 10:16:41 +08:00
UPDATE_COMPAT ( buf )
2012-07-11 16:48:47 +08: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 19:57:42 +08:00
if ( ( buf = = NULL ) | | ( buf - > error ! = 0 ) ) return ( 0 ) ;
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2012-07-11 16:48:47 +08:00
if ( len = = 0 ) return ( 0 ) ;
if ( len > buf - > use ) return ( 0 ) ;
buf - > use - = len ;
if ( ( buf - > alloc = = XML_BUFFER_ALLOC_IMMUTABLE ) | |
( ( buf - > alloc = = XML_BUFFER_ALLOC_IO ) & & ( buf - > contentIO ! = NULL ) ) ) {
/*
* we just move the content pointer , but also make sure
2019-09-30 17:04:54 +02:00
* the perceived buffer size has shrunk accordingly
2012-07-11 16:48:47 +08: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 10:16:41 +08:00
UPDATE_COMPAT ( buf )
2012-07-11 16:48:47 +08: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 19:57:42 +08:00
if ( ( buf = = NULL ) | | ( buf - > error ! = 0 ) ) return ( 0 ) ;
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2012-07-11 16:48:47 +08:00
if ( buf - > alloc = = XML_BUFFER_ALLOC_IMMUTABLE ) return ( 0 ) ;
2022-03-08 20:10:02 +01:00
if ( len < buf - > size - buf - > use )
2022-05-13 14:43:33 -07:00
return ( buf - > size - buf - > use - 1 ) ;
if ( len > = SIZE_MAX - buf - > use ) {
xmlBufMemoryError ( buf , " growing buffer past SIZE_MAX " ) ;
2022-03-08 20:10:02 +01:00
return ( 0 ) ;
2022-05-13 14:43:33 -07:00
}
2012-07-11 16:48:47 +08:00
2022-03-08 20:10:02 +01: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 16:48:47 +08:00
2015-04-14 17:41:48 +08:00
if ( buf - > alloc = = XML_BUFFER_ALLOC_BOUNDED ) {
/*
* Used to provide parsing limits
*/
2022-05-13 14:43:33 -07:00
if ( ( buf - > use + len + 1 > = XML_MAX_TEXT_LENGTH ) | |
2015-04-14 17:41:48 +08:00
( buf - > size > = XML_MAX_TEXT_LENGTH ) ) {
xmlBufMemoryError ( buf , " buffer error: text too long \n " ) ;
return ( 0 ) ;
}
if ( size > = XML_MAX_TEXT_LENGTH )
size = XML_MAX_TEXT_LENGTH ;
}
2012-07-11 16:48:47 +08: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 ) {
xmlBufMemoryError ( buf , " growing buffer " ) ;
return ( 0 ) ;
}
buf - > contentIO = newbuf ;
buf - > content = newbuf + start_buf ;
} else {
newbuf = ( xmlChar * ) xmlRealloc ( buf - > content , size ) ;
if ( newbuf = = NULL ) {
xmlBufMemoryError ( buf , " growing buffer " ) ;
return ( 0 ) ;
}
buf - > content = newbuf ;
}
buf - > size = size ;
2012-08-06 10:16:41 +08:00
UPDATE_COMPAT ( buf )
2022-05-13 14:43:33 -07:00
return ( buf - > size - buf - > use - 1 ) ;
2012-07-11 16:48:47 +08: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 01:18:30 +02:00
return ( ret > INT_MAX ? INT_MAX : ret ) ;
2012-07-11 16:48:47 +08: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 19:57:42 +08:00
if ( ( buf = = NULL ) | | ( buf - > error ! = 0 ) ) {
2012-07-11 16:48:47 +08:00
# ifdef DEBUG_BUFFER
xmlGenericError ( xmlGenericErrorContext ,
2012-07-16 19:57:42 +08:00
" xmlBufDump: buf == NULL or in error \n " ) ;
2012-07-11 16:48:47 +08:00
# endif
return ( 0 ) ;
}
if ( buf - > content = = NULL ) {
# ifdef DEBUG_BUFFER
xmlGenericError ( xmlGenericErrorContext ,
" xmlBufDump: buf->content == NULL \n " ) ;
# endif
return ( 0 ) ;
}
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2012-07-11 16:48:47 +08:00
if ( file = = NULL )
file = stdout ;
2022-09-01 03:14:13 +02:00
ret = fwrite ( buf - > content , 1 , buf - > use , file ) ;
2012-07-11 16:48:47 +08:00
return ( ret ) ;
}
/**
* xmlBufContent :
* @ buf : the buffer
*
* Function to extract the content of a buffer
*
* Returns the internal content
*/
xmlChar *
2014-10-13 16:06:21 +08:00
xmlBufContent ( const xmlBuf * buf )
2012-07-11 16:48:47 +08:00
{
2012-07-16 19:57:42 +08:00
if ( ( ! buf ) | | ( buf - > error ) )
2012-07-11 16:48:47 +08: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 16:06:21 +08:00
xmlBufEnd ( xmlBufPtr buf )
2012-07-11 16:48:47 +08:00
{
2012-07-16 19:57:42 +08:00
if ( ( ! buf ) | | ( buf - > error ) )
2012-07-11 16:48:47 +08:00
return NULL ;
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2012-07-11 16:48:47 +08: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 14:34:53 +08:00
if ( ( buf = = NULL ) | | ( buf - > error ) )
return ( - 1 ) ;
CHECK_COMPAT ( buf )
2022-05-29 09:46:00 -07:00
if ( len > = ( buf - > size - buf - > use ) )
2012-07-11 16:48:47 +08:00
return ( - 1 ) ;
buf - > use + = len ;
2022-05-29 09:46:00 -07:00
buf - > content [ buf - > use ] = 0 ;
2012-08-06 10:16:41 +08:00
UPDATE_COMPAT ( buf )
2012-07-11 16:48:47 +08: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 19:57:42 +08:00
if ( ( ! buf ) | | ( buf - > error ) )
2012-07-11 16:48:47 +08:00
return 0 ;
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2012-07-11 16:48:47 +08: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 19:57:42 +08:00
if ( ( ! buf ) | | ( buf - > error ) )
2012-07-11 16:48:47 +08:00
return 0 ;
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2012-07-11 16:48:47 +08:00
return ( buf - > use ) ;
}
/**
* xmlBufAvail :
* @ buf : the buffer
*
* Function to find how much free space is allocated but not
2022-05-25 18:13:07 -07: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 16:48:47 +08:00
*
2022-05-25 18:13:07 -07:00
* Returns the amount , or 0 if none or if an error occurred .
2012-07-11 16:48:47 +08:00
*/
size_t
xmlBufAvail ( const xmlBufPtr buf )
{
2012-07-16 19:57:42 +08:00
if ( ( ! buf ) | | ( buf - > error ) )
2012-07-11 16:48:47 +08:00
return 0 ;
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2012-07-11 16:48:47 +08:00
2022-05-25 18:13:07 -07:00
return ( ( buf - > size > buf - > use ) ? ( buf - > size - buf - > use - 1 ) : 0 ) ;
2012-07-11 16:48:47 +08: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 19:57:42 +08:00
if ( ( ! buf ) | | ( buf - > error ) )
2012-07-11 16:48:47 +08:00
return ( - 1 ) ;
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2012-07-11 16:48:47 +08: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 20:10:02 +01:00
size_t newSize ;
2012-07-11 16:48:47 +08:00
xmlChar * rebuf = NULL ;
size_t start_buf ;
2012-07-16 19:57:42 +08:00
if ( ( buf = = NULL ) | | ( buf - > error ) )
2012-07-11 16:48:47 +08:00
return ( 0 ) ;
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2012-07-11 16:48:47 +08:00
if ( buf - > alloc = = XML_BUFFER_ALLOC_IMMUTABLE ) return ( 0 ) ;
2015-04-14 17:41:48 +08:00
if ( buf - > alloc = = XML_BUFFER_ALLOC_BOUNDED ) {
/*
* Used to provide parsing limits
*/
if ( size > = XML_MAX_TEXT_LENGTH ) {
xmlBufMemoryError ( buf , " buffer error: text too long \n " ) ;
return ( 0 ) ;
}
}
2012-07-11 16:48:47 +08: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 20:10:02 +01:00
if ( buf - > size = = 0 ) {
newSize = ( size > SIZE_MAX - 10 ? SIZE_MAX : size + 10 ) ;
} else {
newSize = buf - > size ;
}
2012-07-11 16:48:47 +08:00
while ( size > newSize ) {
2022-03-08 20:10:02 +01:00
if ( newSize > SIZE_MAX / 2 ) {
2012-07-11 16:48:47 +08:00
xmlBufMemoryError ( buf , " growing buffer " ) ;
return 0 ;
}
newSize * = 2 ;
}
break ;
case XML_BUFFER_ALLOC_EXACT :
2022-03-08 20:10:02 +01:00
newSize = ( size > SIZE_MAX - 10 ? SIZE_MAX : size + 10 ) ;
2012-07-11 16:48:47 +08:00
break ;
case XML_BUFFER_ALLOC_HYBRID :
if ( buf - > use < BASE_BUFFER_SIZE )
newSize = size ;
else {
2022-03-08 20:10:02 +01:00
newSize = buf - > size ;
2012-07-11 16:48:47 +08:00
while ( size > newSize ) {
2022-03-08 20:10:02 +01:00
if ( newSize > SIZE_MAX / 2 ) {
2012-07-11 16:48:47 +08:00
xmlBufMemoryError ( buf , " growing buffer " ) ;
return 0 ;
}
newSize * = 2 ;
}
}
break ;
default :
2022-03-08 20:10:02 +01:00
newSize = ( size > SIZE_MAX - 10 ? SIZE_MAX : size + 10 ) ;
2012-07-11 16:48:47 +08: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 ) {
xmlBufMemoryError ( buf , " growing buffer " ) ;
return 0 ;
}
buf - > contentIO = rebuf ;
buf - > content = rebuf + start_buf ;
}
} else {
if ( buf - > content = = NULL ) {
rebuf = ( xmlChar * ) xmlMallocAtomic ( newSize ) ;
2022-05-29 09:46:00 -07:00
buf - > use = 0 ;
rebuf [ buf - > use ] = 0 ;
2012-07-11 16:48:47 +08: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 ) {
xmlBufMemoryError ( buf , " growing buffer " ) ;
return 0 ;
}
buf - > content = rebuf ;
}
buf - > size = newSize ;
2012-08-06 10:16:41 +08:00
UPDATE_COMPAT ( buf )
2012-07-11 16:48:47 +08: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 .
*
* Returns 0 successful , a positive error code number otherwise
* and - 1 in case of internal or API error .
*/
int
xmlBufAdd ( xmlBufPtr buf , const xmlChar * str , int len ) {
2022-03-08 20:10:02 +01:00
size_t needSize ;
2012-07-11 16:48:47 +08:00
2012-08-07 14:34:53 +08:00
if ( ( str = = NULL ) | | ( buf = = NULL ) | | ( buf - > error ) )
2012-07-11 16:48:47 +08:00
return - 1 ;
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2012-07-11 16:48:47 +08:00
if ( buf - > alloc = = XML_BUFFER_ALLOC_IMMUTABLE ) return - 1 ;
if ( len < - 1 ) {
# ifdef DEBUG_BUFFER
xmlGenericError ( xmlGenericErrorContext ,
" xmlBufAdd: len < 0 \n " ) ;
# endif
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-13 14:43:33 -07:00
/* Note that both buf->size and buf->use can be zero here. */
2022-03-08 20:10:02 +01:00
if ( ( size_t ) len > = buf - > size - buf - > use ) {
2022-05-13 14:43:33 -07:00
if ( ( size_t ) len > = SIZE_MAX - buf - > use ) {
xmlBufMemoryError ( buf , " growing buffer past SIZE_MAX " ) ;
2022-03-08 20:10:02 +01:00
return ( - 1 ) ;
2022-05-13 14:43:33 -07:00
}
2022-03-08 20:10:02 +01:00
needSize = buf - > use + len + 1 ;
2015-04-14 17:41:48 +08:00
if ( buf - > alloc = = XML_BUFFER_ALLOC_BOUNDED ) {
/*
* Used to provide parsing limits
*/
if ( needSize > = XML_MAX_TEXT_LENGTH ) {
xmlBufMemoryError ( buf , " buffer error: text too long \n " ) ;
return ( - 1 ) ;
}
}
2012-07-11 16:48:47 +08:00
if ( ! xmlBufResize ( buf , needSize ) ) {
xmlBufMemoryError ( buf , " growing buffer " ) ;
return XML_ERR_NO_MEMORY ;
}
}
2022-09-01 03:14:13 +02:00
memmove ( & buf - > content [ buf - > use ] , str , len ) ;
2012-07-11 16:48:47 +08:00
buf - > use + = len ;
buf - > content [ buf - > use ] = 0 ;
2012-08-06 10:16:41 +08:00
UPDATE_COMPAT ( buf )
2012-07-11 16:48:47 +08: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 19:57:42 +08:00
if ( ( buf = = NULL ) | | ( buf - > error ) )
2012-07-11 16:48:47 +08:00
return ( - 1 ) ;
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2012-07-11 16:48:47 +08:00
if ( buf - > alloc = = XML_BUFFER_ALLOC_IMMUTABLE ) return - 1 ;
if ( str = = NULL ) return - 1 ;
return xmlBufAdd ( buf , str , - 1 ) ;
}
/**
* xmlBufCCat :
* @ 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
xmlBufCCat ( xmlBufPtr buf , const char * str ) {
2022-03-08 20:10:02 +01:00
return xmlBufCat ( buf , ( const xmlChar * ) str ) ;
2012-07-11 16:48:47 +08:00
}
/**
* xmlBufWriteQuotedString :
* @ 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
*
* Returns 0 if successful , a positive error code number otherwise
* and - 1 in case of internal or API error .
*/
int
xmlBufWriteQuotedString ( xmlBufPtr buf , const xmlChar * string ) {
const xmlChar * cur , * base ;
2012-07-16 19:57:42 +08:00
if ( ( buf = = NULL ) | | ( buf - > error ) )
2012-07-11 16:48:47 +08:00
return ( - 1 ) ;
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2012-07-11 16:48:47 +08:00
if ( buf - > alloc = = XML_BUFFER_ALLOC_IMMUTABLE )
return ( - 1 ) ;
if ( xmlStrchr ( string , ' \" ' ) ) {
if ( xmlStrchr ( string , ' \' ' ) ) {
# ifdef DEBUG_BUFFER
xmlGenericError ( xmlGenericErrorContext ,
" xmlBufWriteQuotedString: string contains quote and double-quotes ! \n " ) ;
# endif
xmlBufCCat ( buf , " \" " ) ;
base = cur = string ;
while ( * cur ! = 0 ) {
if ( * cur = = ' " ' ) {
if ( base ! = cur )
xmlBufAdd ( buf , base , cur - base ) ;
xmlBufAdd ( buf , BAD_CAST " " " , 6 ) ;
cur + + ;
base = cur ;
}
else {
cur + + ;
}
}
if ( base ! = cur )
xmlBufAdd ( buf , base , cur - base ) ;
xmlBufCCat ( buf , " \" " ) ;
}
else {
xmlBufCCat ( buf , " \' " ) ;
xmlBufCat ( buf , string ) ;
xmlBufCCat ( buf , " \' " ) ;
}
} else {
xmlBufCCat ( buf , " \" " ) ;
xmlBufCat ( buf , string ) ;
xmlBufCCat ( buf , " \" " ) ;
}
return ( 0 ) ;
}
/**
* 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 ) {
xmlBufMemoryError ( NULL , " creating buffer " ) ;
return ( NULL ) ;
}
ret - > use = buffer - > use ;
ret - > size = buffer - > size ;
2022-04-08 12:16:51 -07:00
UPDATE_COMPAT ( ret ) ;
2012-07-11 16:48:47 +08: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 15:51:16 +02:00
if ( buf = = NULL )
2012-07-11 16:48:47 +08:00
return ( NULL ) ;
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2019-09-13 15:51:16 +02:00
if ( ( buf - > error ) | | ( buf - > buffer = = NULL ) ) {
2012-07-11 16:48:47 +08:00
xmlBufFree ( buf ) ;
return ( NULL ) ;
}
ret = buf - > buffer ;
/*
* 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 , " Used size too big for xmlBuffer " ) ;
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 , " Allocated size too big for xmlBuffer " ) ;
2022-09-01 01:18:30 +02:00
ret - > use = buf - > use ;
2012-07-11 16:48:47 +08:00
ret - > size = INT_MAX ;
2019-11-07 12:54:01 +01:00
} else {
2022-09-01 01:18:30 +02:00
ret - > use = buf - > use ;
ret - > size = buf - > size ;
2012-07-11 16:48:47 +08:00
}
ret - > alloc = buf - > alloc ;
ret - > content = buf - > content ;
ret - > contentIO = buf - > contentIO ;
xmlFree ( buf ) ;
return ( ret ) ;
}
/**
* xmlBufMergeBuffer :
* @ buf : an xmlBufPtr
* @ buffer : the buffer to consume into @ buf
*
* The content of @ buffer is appended to @ buf and @ buffer is freed
*
* Returns - 1 in case of error , 0 otherwise , in any case @ buffer is freed
*/
int
xmlBufMergeBuffer ( xmlBufPtr buf , xmlBufferPtr buffer ) {
2012-07-25 16:30:56 +08:00
int ret = 0 ;
2012-07-11 16:48:47 +08:00
2012-08-07 14:34:53 +08:00
if ( ( buf = = NULL ) | | ( buf - > error ) ) {
xmlBufferFree ( buffer ) ;
return ( - 1 ) ;
}
CHECK_COMPAT ( buf )
if ( ( buffer ! = NULL ) & & ( buffer - > content ! = NULL ) & &
2012-07-25 16:30:56 +08:00
( buffer - > use > 0 ) ) {
2012-07-11 16:48:47 +08:00
ret = xmlBufAdd ( buf , buffer - > content , buffer - > use ) ;
}
xmlBufferFree ( buffer ) ;
return ( ret ) ;
}
2012-07-16 16:28:47 +08:00
/**
* xmlBufResetInput :
* @ buf : an xmlBufPtr
* @ input : an xmlParserInputPtr
*
* Update the input to use the current set of pointers from the buffer .
*
2012-07-16 18:03:01 +08:00
* Returns - 1 in case of error , 0 otherwise
2012-07-16 16:28:47 +08:00
*/
int
xmlBufResetInput ( xmlBufPtr buf , xmlParserInputPtr input ) {
2012-07-16 19:57:42 +08:00
if ( ( input = = NULL ) | | ( buf = = NULL ) | | ( buf - > error ) )
2012-07-16 16:28:47 +08:00
return ( - 1 ) ;
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2012-07-16 16:28:47 +08:00
input - > base = input - > cur = buf - > content ;
input - > end = & buf - > content [ buf - > use ] ;
return ( 0 ) ;
}
2012-07-16 18:03:01 +08:00
/**
* xmlBufGetInputBase :
* @ buf : an xmlBufPtr
* @ input : an xmlParserInputPtr
*
* Get the base of the @ input relative to the beginning of the buffer
*
* Returns the size_t corresponding to the displacement
*/
size_t
xmlBufGetInputBase ( xmlBufPtr buf , xmlParserInputPtr input ) {
size_t base ;
2012-07-16 19:57:42 +08:00
if ( ( input = = NULL ) | | ( buf = = NULL ) | | ( buf - > error ) )
return ( - 1 ) ;
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2012-07-16 18:03:01 +08:00
base = input - > base - buf - > content ;
/*
2019-09-30 17:04:54 +02:00
* We could do some pointer arithmetic checks but that ' s probably
2012-07-16 18:03:01 +08:00
* sufficient .
*/
if ( base > buf - > size ) {
xmlBufOverflowError ( buf , " Input reference outside of the buffer " ) ;
base = 0 ;
}
return ( base ) ;
}
/**
* xmlBufSetInputBaseCur :
* @ buf : an xmlBufPtr
* @ input : an xmlParserInputPtr
2012-08-10 10:00:18 +08:00
* @ base : the base value relative to the beginning of the buffer
* @ cur : the cur value relative to the beginning of the buffer
2012-07-16 18:03:01 +08: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
xmlBufSetInputBaseCur ( xmlBufPtr buf , xmlParserInputPtr input ,
size_t base , size_t cur ) {
2020-07-11 14:34:57 +02:00
if ( input = = NULL )
return ( - 1 ) ;
if ( ( buf = = NULL ) | | ( buf - > error ) ) {
input - > base = input - > cur = input - > end = BAD_CAST " " ;
2012-07-16 18:03:01 +08:00
return ( - 1 ) ;
2020-07-11 14:34:57 +02:00
}
2012-08-07 14:34:53 +08:00
CHECK_COMPAT ( buf )
2012-07-16 18:03:01 +08:00
input - > base = & buf - > content [ base ] ;
input - > cur = input - > base + cur ;
input - > end = & buf - > content [ buf - > use ] ;
return ( 0 ) ;
}
2012-09-12 01:32:11 +03:00