2001-02-23 20:55:21 +03:00
/*
2001-12-31 19:16:02 +03:00
* entities . c : implementation for the XML entities handling
2001-02-23 20:55:21 +03:00
*
* See Copyright for the status of this software .
*
2001-06-24 16:13:24 +04:00
* daniel @ veillard . com
2001-02-23 20:55:21 +03:00
*/
2017-08-28 15:30:43 +03:00
/* To avoid EBCDIC trouble when parsing on zOS */
# if defined(__MVS__)
# pragma convert("ISO8859-1")
# endif
2002-03-18 22:37:11 +03:00
# define IN_LIBXML
2001-04-21 20:57:29 +04:00
# include "libxml.h"
2001-02-23 20:55:21 +03:00
# include <string.h>
# include <stdlib.h>
2022-03-02 02:29:17 +03:00
2001-02-23 20:55:21 +03:00
# include <libxml/xmlmemory.h>
# include <libxml/hash.h>
# include <libxml/entities.h>
# include <libxml/parser.h>
2003-10-18 20:20:14 +04:00
# include <libxml/parserInternals.h>
2001-02-23 20:55:21 +03:00
# include <libxml/xmlerror.h>
2005-01-23 23:15:53 +03:00
# include <libxml/dict.h>
2024-02-01 21:01:57 +03:00
# include <libxml/xmlsave.h>
2001-02-23 20:55:21 +03:00
2022-08-26 02:22:33 +03:00
# include "private/entities.h"
# include "private/error.h"
2012-09-11 10:02:08 +04:00
2001-02-23 20:55:21 +03:00
/*
* The XML predefined entities .
*/
2024-06-01 16:41:43 +03:00
static xmlEntity xmlEntityLt = {
2003-09-30 17:38:04 +04:00
NULL , XML_ENTITY_DECL , BAD_CAST " lt " ,
2012-09-11 09:26:36 +04:00
NULL , NULL , NULL , NULL , NULL , NULL ,
2003-09-30 17:38:04 +04:00
BAD_CAST " < " , BAD_CAST " < " , 1 ,
XML_INTERNAL_PREDEFINED_ENTITY ,
2022-12-19 22:56:23 +03:00
NULL , NULL , NULL , NULL , 0 , 0 , 0
2001-02-23 20:55:21 +03:00
} ;
2024-06-01 16:41:43 +03:00
static xmlEntity xmlEntityGt = {
2003-09-30 17:38:04 +04:00
NULL , XML_ENTITY_DECL , BAD_CAST " gt " ,
2012-09-11 09:26:36 +04:00
NULL , NULL , NULL , NULL , NULL , NULL ,
2003-09-30 17:38:04 +04:00
BAD_CAST " > " , BAD_CAST " > " , 1 ,
XML_INTERNAL_PREDEFINED_ENTITY ,
2022-12-19 22:56:23 +03:00
NULL , NULL , NULL , NULL , 0 , 0 , 0
2003-09-30 17:38:04 +04:00
} ;
2024-06-01 16:41:43 +03:00
static xmlEntity xmlEntityAmp = {
2003-09-30 17:38:04 +04:00
NULL , XML_ENTITY_DECL , BAD_CAST " amp " ,
2012-09-11 09:26:36 +04:00
NULL , NULL , NULL , NULL , NULL , NULL ,
2003-09-30 17:38:04 +04:00
BAD_CAST " & " , BAD_CAST " & " , 1 ,
XML_INTERNAL_PREDEFINED_ENTITY ,
2022-12-19 22:56:23 +03:00
NULL , NULL , NULL , NULL , 0 , 0 , 0
2003-09-30 17:38:04 +04:00
} ;
2024-06-01 16:41:43 +03:00
static xmlEntity xmlEntityQuot = {
2003-09-30 17:38:04 +04:00
NULL , XML_ENTITY_DECL , BAD_CAST " quot " ,
2012-09-11 09:26:36 +04:00
NULL , NULL , NULL , NULL , NULL , NULL ,
2003-09-30 17:38:04 +04:00
BAD_CAST " \" " , BAD_CAST " \" " , 1 ,
XML_INTERNAL_PREDEFINED_ENTITY ,
2022-12-19 22:56:23 +03:00
NULL , NULL , NULL , NULL , 0 , 0 , 0
2003-09-30 17:38:04 +04:00
} ;
2024-06-01 16:41:43 +03:00
static xmlEntity xmlEntityApos = {
2003-09-30 17:38:04 +04:00
NULL , XML_ENTITY_DECL , BAD_CAST " apos " ,
2012-09-11 09:26:36 +04:00
NULL , NULL , NULL , NULL , NULL , NULL ,
2003-09-30 17:38:04 +04:00
BAD_CAST " ' " , BAD_CAST " ' " , 1 ,
XML_INTERNAL_PREDEFINED_ENTITY ,
2022-12-19 22:56:23 +03:00
NULL , NULL , NULL , NULL , 0 , 0 , 0
2001-02-23 20:55:21 +03:00
} ;
/*
2024-05-20 14:58:22 +03:00
* xmlFreeEntity :
* @ entity : an entity
*
* Frees the entity .
2001-02-23 20:55:21 +03:00
*/
2023-10-06 11:43:38 +03:00
void
2005-01-23 23:15:53 +03:00
xmlFreeEntity ( xmlEntityPtr entity )
{
xmlDictPtr dict = NULL ;
if ( entity = = NULL )
return ;
if ( entity - > doc ! = NULL )
dict = entity - > doc - > dict ;
2001-02-23 20:55:21 +03:00
2023-12-27 05:53:24 +03:00
if ( ( entity - > children ) & &
2005-01-23 23:15:53 +03:00
( entity = = ( xmlEntityPtr ) entity - > children - > parent ) )
xmlFreeNodeList ( entity - > children ) ;
2022-08-31 23:11:25 +03:00
if ( ( entity - > name ! = NULL ) & &
( ( dict = = NULL ) | | ( ! xmlDictOwns ( dict , entity - > name ) ) ) )
xmlFree ( ( char * ) entity - > name ) ;
if ( entity - > ExternalID ! = NULL )
xmlFree ( ( char * ) entity - > ExternalID ) ;
if ( entity - > SystemID ! = NULL )
xmlFree ( ( char * ) entity - > SystemID ) ;
if ( entity - > URI ! = NULL )
xmlFree ( ( char * ) entity - > URI ) ;
if ( entity - > content ! = NULL )
xmlFree ( ( char * ) entity - > content ) ;
if ( entity - > orig ! = NULL )
xmlFree ( ( char * ) entity - > orig ) ;
2001-02-23 20:55:21 +03:00
xmlFree ( entity ) ;
}
/*
2008-08-25 18:53:31 +04:00
* xmlCreateEntity :
*
2019-09-30 18:04:54 +03:00
* internal routine doing the entity node structures allocations
2001-02-23 20:55:21 +03:00
*/
static xmlEntityPtr
2023-12-10 17:25:42 +03:00
xmlCreateEntity ( xmlDocPtr doc , const xmlChar * name , int type ,
2008-08-25 18:53:31 +04:00
const xmlChar * ExternalID , const xmlChar * SystemID ,
const xmlChar * content ) {
2001-02-23 20:55:21 +03:00
xmlEntityPtr ret ;
ret = ( xmlEntityPtr ) xmlMalloc ( sizeof ( xmlEntity ) ) ;
2023-12-10 17:25:42 +03:00
if ( ret = = NULL )
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
memset ( ret , 0 , sizeof ( xmlEntity ) ) ;
2023-12-10 17:25:42 +03:00
ret - > doc = doc ;
2001-02-23 20:55:21 +03:00
ret - > type = XML_ENTITY_DECL ;
/*
* fill the structure .
*/
ret - > etype = ( xmlEntityType ) type ;
2023-12-10 17:25:42 +03:00
if ( ( doc = = NULL ) | | ( doc - > dict = = NULL ) )
2005-01-23 23:15:53 +03:00
ret - > name = xmlStrdup ( name ) ;
2023-12-10 17:25:42 +03:00
else
ret - > name = xmlDictLookup ( doc - > dict , name , - 1 ) ;
if ( ret - > name = = NULL )
goto error ;
if ( ExternalID ! = NULL ) {
ret - > ExternalID = xmlStrdup ( ExternalID ) ;
if ( ret - > ExternalID = = NULL )
goto error ;
}
if ( SystemID ! = NULL ) {
ret - > SystemID = xmlStrdup ( SystemID ) ;
if ( ret - > SystemID = = NULL )
goto error ;
2005-01-23 23:15:53 +03:00
}
2001-02-23 20:55:21 +03:00
if ( content ! = NULL ) {
ret - > length = xmlStrlen ( content ) ;
2022-08-31 23:11:25 +03:00
ret - > content = xmlStrndup ( content , ret - > length ) ;
2023-12-10 17:25:42 +03:00
if ( ret - > content = = NULL )
goto error ;
2001-02-23 20:55:21 +03:00
} else {
ret - > length = 0 ;
ret - > content = NULL ;
}
ret - > URI = NULL ; /* to be computed by the layer knowing
the defining entity */
ret - > orig = NULL ;
2008-08-25 18:53:31 +04:00
return ( ret ) ;
2023-12-10 17:25:42 +03:00
error :
xmlFreeEntity ( ret ) ;
return ( NULL ) ;
2008-08-25 18:53:31 +04:00
}
2023-12-10 17:25:42 +03:00
/**
* xmlAddEntity :
* @ doc : the document
* @ extSubset : add to the external or internal subset
* @ name : the entity name
* @ type : the entity type XML_xxx_yyy_ENTITY
* @ ExternalID : the entity external ID if available
* @ SystemID : the entity system ID if available
* @ content : the entity content
* @ out : pointer to resulting entity ( optional )
*
* Register a new entity for this document .
*
2024-05-20 14:58:22 +03:00
* Available since 2.13 .0 .
*
2023-12-10 17:25:42 +03:00
* Returns an xmlParserErrors error code .
2008-08-25 18:53:31 +04:00
*/
2023-12-10 17:25:42 +03:00
int
xmlAddEntity ( xmlDocPtr doc , int extSubset , const xmlChar * name , int type ,
2008-08-25 18:53:31 +04:00
const xmlChar * ExternalID , const xmlChar * SystemID ,
2023-12-10 17:25:42 +03:00
const xmlChar * content , xmlEntityPtr * out ) {
xmlDtdPtr dtd ;
2008-08-25 18:53:31 +04:00
xmlDictPtr dict = NULL ;
xmlEntitiesTablePtr table = NULL ;
2021-02-08 22:58:32 +03:00
xmlEntityPtr ret , predef ;
2023-12-10 17:25:42 +03:00
int res ;
2008-08-25 18:53:31 +04:00
2023-12-10 17:25:42 +03:00
if ( out ! = NULL )
* out = NULL ;
if ( ( doc = = NULL ) | | ( name = = NULL ) )
return ( XML_ERR_ARGUMENT ) ;
dict = doc - > dict ;
if ( extSubset )
dtd = doc - > extSubset ;
else
dtd = doc - > intSubset ;
2008-08-25 18:53:31 +04:00
if ( dtd = = NULL )
2023-12-10 17:25:42 +03:00
return ( XML_DTD_NO_DTD ) ;
2008-08-25 18:53:31 +04:00
switch ( type ) {
case XML_INTERNAL_GENERAL_ENTITY :
case XML_EXTERNAL_GENERAL_PARSED_ENTITY :
case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY :
2021-02-08 22:58:32 +03:00
predef = xmlGetPredefinedEntity ( name ) ;
if ( predef ! = NULL ) {
int valid = 0 ;
/* 4.6 Predefined Entities */
2021-02-09 19:07:21 +03:00
if ( ( type = = XML_INTERNAL_GENERAL_ENTITY ) & &
( content ! = NULL ) ) {
2021-02-08 22:58:32 +03:00
int c = predef - > content [ 0 ] ;
if ( ( ( content [ 0 ] = = c ) & & ( content [ 1 ] = = 0 ) ) & &
( ( c = = ' > ' ) | | ( c = = ' \' ' ) | | ( c = = ' " ' ) ) ) {
valid = 1 ;
} else if ( ( content [ 0 ] = = ' & ' ) & & ( content [ 1 ] = = ' # ' ) ) {
if ( content [ 2 ] = = ' x ' ) {
xmlChar * hex = BAD_CAST " 0123456789ABCDEF " ;
xmlChar ref [ ] = " 00; " ;
ref [ 0 ] = hex [ c / 16 % 16 ] ;
ref [ 1 ] = hex [ c % 16 ] ;
if ( xmlStrcasecmp ( & content [ 3 ] , ref ) = = 0 )
valid = 1 ;
} else {
xmlChar ref [ ] = " 00; " ;
ref [ 0 ] = ' 0 ' + c / 10 % 10 ;
ref [ 1 ] = ' 0 ' + c % 10 ;
if ( xmlStrEqual ( & content [ 2 ] , ref ) )
valid = 1 ;
}
}
}
2023-12-10 17:25:42 +03:00
if ( ! valid )
return ( XML_ERR_REDECL_PREDEF_ENTITY ) ;
2021-02-08 22:58:32 +03:00
}
2023-12-10 17:25:42 +03:00
if ( dtd - > entities = = NULL ) {
2008-08-25 18:53:31 +04:00
dtd - > entities = xmlHashCreateDict ( 0 , dict ) ;
2023-12-10 17:25:42 +03:00
if ( dtd - > entities = = NULL )
return ( XML_ERR_NO_MEMORY ) ;
}
2008-08-25 18:53:31 +04:00
table = dtd - > entities ;
break ;
case XML_INTERNAL_PARAMETER_ENTITY :
case XML_EXTERNAL_PARAMETER_ENTITY :
2023-12-10 17:25:42 +03:00
if ( dtd - > pentities = = NULL ) {
2008-08-25 18:53:31 +04:00
dtd - > pentities = xmlHashCreateDict ( 0 , dict ) ;
2023-12-10 17:25:42 +03:00
if ( dtd - > pentities = = NULL )
return ( XML_ERR_NO_MEMORY ) ;
}
2008-08-25 18:53:31 +04:00
table = dtd - > pentities ;
break ;
2024-03-05 20:06:38 +03:00
default :
2023-12-10 17:25:42 +03:00
return ( XML_ERR_ARGUMENT ) ;
2008-08-25 18:53:31 +04:00
}
2023-12-10 17:25:42 +03:00
ret = xmlCreateEntity ( dtd - > doc , name , type , ExternalID , SystemID , content ) ;
2008-08-25 18:53:31 +04:00
if ( ret = = NULL )
2023-12-10 17:25:42 +03:00
return ( XML_ERR_NO_MEMORY ) ;
2001-02-23 20:55:21 +03:00
2023-12-10 17:25:42 +03:00
res = xmlHashAdd ( table , name , ret ) ;
if ( res < 0 ) {
xmlFreeEntity ( ret ) ;
return ( XML_ERR_NO_MEMORY ) ;
} else if ( res = = 0 ) {
2001-02-23 20:55:21 +03:00
/*
* entity was already defined at another level .
*/
xmlFreeEntity ( ret ) ;
2023-12-10 17:25:42 +03:00
return ( XML_WAR_ENTITY_REDEFINED ) ;
2001-02-23 20:55:21 +03:00
}
2023-12-10 17:25:42 +03:00
/*
* Link it to the DTD
*/
ret - > parent = dtd ;
ret - > doc = dtd - > doc ;
if ( dtd - > last = = NULL ) {
dtd - > children = dtd - > last = ( xmlNodePtr ) ret ;
} else {
dtd - > last - > next = ( xmlNodePtr ) ret ;
ret - > prev = dtd - > last ;
dtd - > last = ( xmlNodePtr ) ret ;
}
2024-06-09 15:22:53 +03:00
if ( out ! = NULL )
* out = ret ;
2023-12-10 17:25:42 +03:00
return ( 0 ) ;
2001-02-23 20:55:21 +03:00
}
/**
* xmlGetPredefinedEntity :
* @ name : the entity name
*
* Check whether this name is an predefined entity .
*
2001-12-31 19:16:02 +03:00
* Returns NULL if not , otherwise the entity
2001-02-23 20:55:21 +03:00
*/
xmlEntityPtr
xmlGetPredefinedEntity ( const xmlChar * name ) {
2003-09-30 17:38:04 +04:00
if ( name = = NULL ) return ( NULL ) ;
switch ( name [ 0 ] ) {
case ' l ' :
if ( xmlStrEqual ( name , BAD_CAST " lt " ) )
2024-06-01 16:41:43 +03:00
return ( & xmlEntityLt ) ;
2003-09-30 17:38:04 +04:00
break ;
case ' g ' :
if ( xmlStrEqual ( name , BAD_CAST " gt " ) )
2024-06-01 16:41:43 +03:00
return ( & xmlEntityGt ) ;
2003-09-30 17:38:04 +04:00
break ;
case ' a ' :
if ( xmlStrEqual ( name , BAD_CAST " amp " ) )
2024-06-01 16:41:43 +03:00
return ( & xmlEntityAmp ) ;
2003-09-30 17:38:04 +04:00
if ( xmlStrEqual ( name , BAD_CAST " apos " ) )
2024-06-01 16:41:43 +03:00
return ( & xmlEntityApos ) ;
2003-09-30 17:38:04 +04:00
break ;
case ' q ' :
if ( xmlStrEqual ( name , BAD_CAST " quot " ) )
2024-06-01 16:41:43 +03:00
return ( & xmlEntityQuot ) ;
2003-09-30 17:38:04 +04:00
break ;
default :
break ;
}
return ( NULL ) ;
2001-02-23 20:55:21 +03:00
}
/**
* xmlAddDtdEntity :
* @ doc : the document
* @ name : the entity name
* @ type : the entity type XML_xxx_yyy_ENTITY
* @ ExternalID : the entity external ID if available
* @ SystemID : the entity system ID if available
* @ content : the entity content
*
* Register a new entity for this document DTD external subset .
*
* Returns a pointer to the entity or NULL in case of error
*/
xmlEntityPtr
xmlAddDtdEntity ( xmlDocPtr doc , const xmlChar * name , int type ,
const xmlChar * ExternalID , const xmlChar * SystemID ,
const xmlChar * content ) {
xmlEntityPtr ret ;
2023-12-10 17:25:42 +03:00
xmlAddEntity ( doc , 1 , name , type , ExternalID , SystemID , content , & ret ) ;
2001-02-23 20:55:21 +03:00
return ( ret ) ;
}
/**
* xmlAddDocEntity :
* @ doc : the document
* @ name : the entity name
* @ type : the entity type XML_xxx_yyy_ENTITY
* @ ExternalID : the entity external ID if available
* @ SystemID : the entity system ID if available
* @ content : the entity content
*
* Register a new entity for this document .
*
* Returns a pointer to the entity or NULL in case of error
*/
xmlEntityPtr
xmlAddDocEntity ( xmlDocPtr doc , const xmlChar * name , int type ,
const xmlChar * ExternalID , const xmlChar * SystemID ,
const xmlChar * content ) {
xmlEntityPtr ret ;
2023-12-10 17:25:42 +03:00
xmlAddEntity ( doc , 0 , name , type , ExternalID , SystemID , content , & ret ) ;
2001-02-23 20:55:21 +03:00
return ( ret ) ;
}
2008-08-25 18:53:31 +04:00
/**
* xmlNewEntity :
* @ doc : the document
* @ name : the entity name
* @ type : the entity type XML_xxx_yyy_ENTITY
* @ ExternalID : the entity external ID if available
* @ SystemID : the entity system ID if available
* @ content : the entity content
*
* Create a new entity , this differs from xmlAddDocEntity ( ) that if
* the document is NULL or has no internal subset defined , then an
2019-09-30 18:04:54 +03:00
* unlinked entity structure will be returned , it is then the responsibility
2008-08-25 18:53:31 +04:00
* of the caller to link it to the document later or free it when not needed
* anymore .
*
* Returns a pointer to the entity or NULL in case of error
*/
xmlEntityPtr
xmlNewEntity ( xmlDocPtr doc , const xmlChar * name , int type ,
const xmlChar * ExternalID , const xmlChar * SystemID ,
const xmlChar * content ) {
if ( ( doc ! = NULL ) & & ( doc - > intSubset ! = NULL ) ) {
return ( xmlAddDocEntity ( doc , name , type , ExternalID , SystemID , content ) ) ;
}
2024-03-05 20:07:13 +03:00
if ( name = = NULL )
return ( NULL ) ;
2023-12-10 17:25:42 +03:00
return ( xmlCreateEntity ( doc , name , type , ExternalID , SystemID , content ) ) ;
2008-08-25 18:53:31 +04:00
}
2001-02-23 20:55:21 +03:00
/**
* xmlGetEntityFromTable :
* @ table : an entity table
* @ name : the entity name
* @ parameter : look for parameter entities
*
* Do an entity lookup in the table .
* returns the corresponding parameter entity , if found .
2012-09-11 09:26:36 +04:00
*
2001-02-23 20:55:21 +03:00
* Returns A pointer to the entity structure or NULL if not found .
*/
2001-03-24 20:00:36 +03:00
static xmlEntityPtr
2001-02-23 20:55:21 +03:00
xmlGetEntityFromTable ( xmlEntitiesTablePtr table , const xmlChar * name ) {
return ( ( xmlEntityPtr ) xmlHashLookup ( table , name ) ) ;
}
/**
* xmlGetParameterEntity :
* @ doc : the document referencing the entity
* @ name : the entity name
*
* Do an entity lookup in the internal and external subsets and
* returns the corresponding parameter entity , if found .
2012-09-11 09:26:36 +04:00
*
2001-02-23 20:55:21 +03:00
* Returns A pointer to the entity structure or NULL if not found .
*/
xmlEntityPtr
xmlGetParameterEntity ( xmlDocPtr doc , const xmlChar * name ) {
xmlEntitiesTablePtr table ;
xmlEntityPtr ret ;
2002-01-24 18:02:46 +03:00
if ( doc = = NULL )
return ( NULL ) ;
2001-02-23 20:55:21 +03:00
if ( ( doc - > intSubset ! = NULL ) & & ( doc - > intSubset - > pentities ! = NULL ) ) {
table = ( xmlEntitiesTablePtr ) doc - > intSubset - > pentities ;
ret = xmlGetEntityFromTable ( table , name ) ;
if ( ret ! = NULL )
return ( ret ) ;
}
if ( ( doc - > extSubset ! = NULL ) & & ( doc - > extSubset - > pentities ! = NULL ) ) {
table = ( xmlEntitiesTablePtr ) doc - > extSubset - > pentities ;
return ( xmlGetEntityFromTable ( table , name ) ) ;
}
return ( NULL ) ;
}
/**
* xmlGetDtdEntity :
* @ doc : the document referencing the entity
* @ name : the entity name
*
2001-12-31 19:16:02 +03:00
* Do an entity lookup in the DTD entity hash table and
2001-02-23 20:55:21 +03:00
* returns the corresponding entity , if found .
2002-01-24 18:02:46 +03:00
* Note : the first argument is the document node , not the DTD node .
2012-09-11 09:26:36 +04:00
*
2001-02-23 20:55:21 +03:00
* Returns A pointer to the entity structure or NULL if not found .
*/
xmlEntityPtr
xmlGetDtdEntity ( xmlDocPtr doc , const xmlChar * name ) {
xmlEntitiesTablePtr table ;
2002-01-24 18:02:46 +03:00
if ( doc = = NULL )
return ( NULL ) ;
2001-02-23 20:55:21 +03:00
if ( ( doc - > extSubset ! = NULL ) & & ( doc - > extSubset - > entities ! = NULL ) ) {
table = ( xmlEntitiesTablePtr ) doc - > extSubset - > entities ;
return ( xmlGetEntityFromTable ( table , name ) ) ;
}
return ( NULL ) ;
}
/**
* xmlGetDocEntity :
* @ doc : the document referencing the entity
* @ name : the entity name
*
* Do an entity lookup in the document entity hash table and
2001-12-31 19:16:02 +03:00
* returns the corresponding entity , otherwise a lookup is done
2001-02-23 20:55:21 +03:00
* in the predefined entities too .
2012-09-11 09:26:36 +04:00
*
2001-02-23 20:55:21 +03:00
* Returns A pointer to the entity structure or NULL if not found .
*/
xmlEntityPtr
2014-10-13 12:06:21 +04:00
xmlGetDocEntity ( const xmlDoc * doc , const xmlChar * name ) {
2001-02-23 20:55:21 +03:00
xmlEntityPtr cur ;
xmlEntitiesTablePtr table ;
if ( doc ! = NULL ) {
if ( ( doc - > intSubset ! = NULL ) & & ( doc - > intSubset - > entities ! = NULL ) ) {
table = ( xmlEntitiesTablePtr ) doc - > intSubset - > entities ;
cur = xmlGetEntityFromTable ( table , name ) ;
if ( cur ! = NULL )
return ( cur ) ;
}
2002-02-18 14:19:30 +03:00
if ( doc - > standalone ! = 1 ) {
if ( ( doc - > extSubset ! = NULL ) & &
( doc - > extSubset - > entities ! = NULL ) ) {
table = ( xmlEntitiesTablePtr ) doc - > extSubset - > entities ;
cur = xmlGetEntityFromTable ( table , name ) ;
if ( cur ! = NULL )
return ( cur ) ;
}
2001-02-23 20:55:21 +03:00
}
}
2003-09-30 17:38:04 +04:00
return ( xmlGetPredefinedEntity ( name ) ) ;
2001-02-23 20:55:21 +03:00
}
/*
* Macro used to grow the current buffer .
*/
# define growBufferReentrant() { \
2012-07-18 07:38:17 +04:00
xmlChar * tmp ; \
2012-07-20 11:41:34 +04:00
size_t new_size = buffer_size * 2 ; \
2012-07-18 07:38:17 +04:00
if ( new_size < buffer_size ) goto mem_error ; \
tmp = ( xmlChar * ) xmlRealloc ( buffer , new_size ) ; \
if ( tmp = = NULL ) goto mem_error ; \
buffer = tmp ; \
buffer_size = new_size ; \
2001-02-23 20:55:21 +03:00
}
/**
2012-09-05 07:45:32 +04:00
* xmlEncodeEntitiesInternal :
2001-02-23 20:55:21 +03:00
* @ doc : the document containing the string
* @ input : A string to convert to XML .
2019-09-30 18:04:54 +03:00
* @ attr : are we handling an attribute value
2001-02-23 20:55:21 +03:00
*
* Do a global encoding of a string , replacing the predefined entities
* and non ASCII values with their entities and CharRef counterparts .
* Contrary to xmlEncodeEntities , this routine is reentrant , and result
* must be deallocated .
*
* Returns A newly allocated string with the substitution done .
*/
2012-09-05 07:45:32 +04:00
static xmlChar *
xmlEncodeEntitiesInternal ( xmlDocPtr doc , const xmlChar * input , int attr ) {
2001-02-23 20:55:21 +03:00
const xmlChar * cur = input ;
xmlChar * buffer = NULL ;
xmlChar * out = NULL ;
2012-07-18 07:38:17 +04:00
size_t buffer_size = 0 ;
2001-02-23 20:55:21 +03:00
int html = 0 ;
if ( input = = NULL ) return ( NULL ) ;
if ( doc ! = NULL )
html = ( doc - > type = = XML_HTML_DOCUMENT_NODE ) ;
/*
* allocate an translation buffer .
*/
buffer_size = 1000 ;
2022-09-01 04:14:13 +03:00
buffer = ( xmlChar * ) xmlMalloc ( buffer_size ) ;
2023-12-10 17:25:42 +03:00
if ( buffer = = NULL )
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
out = buffer ;
while ( * cur ! = ' \0 ' ) {
2012-07-18 07:38:17 +04:00
size_t indx = out - buffer ;
if ( indx + 100 > buffer_size ) {
2001-02-23 20:55:21 +03:00
growBufferReentrant ( ) ;
2001-03-24 20:00:36 +03:00
out = & buffer [ indx ] ;
2001-02-23 20:55:21 +03:00
}
/*
* By default one have to encode at least ' < ' , ' > ' , ' " ' and ' & ' !
*/
if ( * cur = = ' < ' ) {
2012-09-05 07:45:32 +04:00
const xmlChar * end ;
/*
* Special handling of server side include in HTML attributes
*/
if ( html & & attr & &
( cur [ 1 ] = = ' ! ' ) & & ( cur [ 2 ] = = ' - ' ) & & ( cur [ 3 ] = = ' - ' ) & &
( ( end = xmlStrstr ( cur , BAD_CAST " --> " ) ) ! = NULL ) ) {
while ( cur ! = end ) {
* out + + = * cur + + ;
indx = out - buffer ;
if ( indx + 100 > buffer_size ) {
growBufferReentrant ( ) ;
out = & buffer [ indx ] ;
}
}
* out + + = * cur + + ;
* out + + = * cur + + ;
* out + + = * cur + + ;
continue ;
}
2001-02-23 20:55:21 +03:00
* out + + = ' & ' ;
* out + + = ' l ' ;
* out + + = ' t ' ;
* out + + = ' ; ' ;
} else if ( * cur = = ' > ' ) {
* out + + = ' & ' ;
* out + + = ' g ' ;
* out + + = ' t ' ;
* out + + = ' ; ' ;
} else if ( * cur = = ' & ' ) {
2012-09-05 07:45:32 +04:00
/*
* Special handling of & { . . . } construct from HTML 4 , see
* http : //www.w3.org/TR/html401/appendix/notes.html#h-B.7.1
*/
2012-09-11 10:02:08 +04:00
if ( html & & attr & & ( cur [ 1 ] = = ' { ' ) & &
( strchr ( ( const char * ) cur , ' } ' ) ) ) {
2012-09-05 07:45:32 +04:00
while ( * cur ! = ' } ' ) {
* out + + = * cur + + ;
indx = out - buffer ;
if ( indx + 100 > buffer_size ) {
growBufferReentrant ( ) ;
out = & buffer [ indx ] ;
}
}
* out + + = * cur + + ;
continue ;
}
2001-02-23 20:55:21 +03:00
* out + + = ' & ' ;
* out + + = ' a ' ;
* out + + = ' m ' ;
* out + + = ' p ' ;
* out + + = ' ; ' ;
} else if ( ( ( * cur > = 0x20 ) & & ( * cur < 0x80 ) ) | |
2003-02-23 16:52:30 +03:00
( * cur = = ' \n ' ) | | ( * cur = = ' \t ' ) | | ( ( html ) & & ( * cur = = ' \r ' ) ) ) {
2001-02-23 20:55:21 +03:00
/*
* default case , just copy !
*/
* out + + = * cur ;
} else if ( * cur > = 0x80 ) {
2001-04-24 16:12:30 +04:00
if ( ( ( doc ! = NULL ) & & ( doc - > encoding ! = NULL ) ) | | ( html ) ) {
2001-02-23 20:55:21 +03:00
/*
2013-03-28 04:47:42 +04:00
* Bjørn Reese < br @ sseusa . com > provided the patch
2001-02-23 20:55:21 +03:00
xmlChar xc ;
xc = ( * cur & 0x3F ) < < 6 ;
if ( cur [ 1 ] ! = 0 ) {
xc + = * ( + + cur ) & 0x3F ;
* out + + = xc ;
} else
*/
2006-03-09 19:49:24 +03:00
* out + + = * cur ;
2001-02-23 20:55:21 +03:00
} else {
/*
* We assume we have UTF - 8 input .
2020-08-17 03:19:35 +03:00
* It must match either :
* 110 xxxxx 10 xxxxxx
* 1110 xxxx 10 xxxxxx 10 xxxxxx
* 11110 xxx 10 xxxxxx 10 xxxxxx 10 xxxxxx
* That is :
* cur [ 0 ] is 11 xxxxxx
* cur [ 1 ] is 10 xxxxxx
* cur [ 2 ] is 10 xxxxxx if cur [ 0 ] is 111 xxxxx
* cur [ 3 ] is 10 xxxxxx if cur [ 0 ] is 1111 xxxx
* cur [ 0 ] is not 11111 xxx
2001-02-23 20:55:21 +03:00
*/
2023-12-10 17:25:42 +03:00
char buf [ 13 ] , * ptr ;
int val , l ;
l = 4 ;
val = xmlGetUTF8Char ( cur , & l ) ;
2024-01-04 23:20:51 +03:00
if ( val < 0 ) {
val = 0xFFFD ;
cur + + ;
} else {
if ( ! IS_CHAR ( val ) )
val = 0xFFFD ;
cur + = l ;
2001-02-23 20:55:21 +03:00
}
/*
* We could do multiple things here . Just save as a char ref
*/
2006-03-09 19:49:24 +03:00
snprintf ( buf , sizeof ( buf ) , " &#x%X; " , val ) ;
2001-02-23 20:55:21 +03:00
buf [ sizeof ( buf ) - 1 ] = 0 ;
ptr = buf ;
while ( * ptr ! = 0 ) * out + + = * ptr + + ;
continue ;
}
2003-10-18 20:20:14 +04:00
} else if ( IS_BYTE_CHAR ( * cur ) ) {
2003-10-01 23:13:56 +04:00
char buf [ 11 ] , * ptr ;
2001-02-23 20:55:21 +03:00
snprintf ( buf , sizeof ( buf ) , " &#%d; " , * cur ) ;
buf [ sizeof ( buf ) - 1 ] = 0 ;
ptr = buf ;
while ( * ptr ! = 0 ) * out + + = * ptr + + ;
}
cur + + ;
}
2009-09-05 16:52:55 +04:00
* out = 0 ;
2001-02-23 20:55:21 +03:00
return ( buffer ) ;
2012-07-18 07:38:17 +04:00
mem_error :
xmlFree ( buffer ) ;
return ( NULL ) ;
2001-02-23 20:55:21 +03:00
}
2012-09-05 07:45:32 +04:00
/**
* xmlEncodeAttributeEntities :
* @ doc : the document containing the string
* @ input : A string to convert to XML .
*
* Do a global encoding of a string , replacing the predefined entities
* and non ASCII values with their entities and CharRef counterparts for
* attribute values .
*
* Returns A newly allocated string with the substitution done .
*/
xmlChar *
xmlEncodeAttributeEntities ( xmlDocPtr doc , const xmlChar * input ) {
return xmlEncodeEntitiesInternal ( doc , input , 1 ) ;
}
/**
* xmlEncodeEntitiesReentrant :
* @ doc : the document containing the string
* @ input : A string to convert to XML .
*
* Do a global encoding of a string , replacing the predefined entities
* and non ASCII values with their entities and CharRef counterparts .
* Contrary to xmlEncodeEntities , this routine is reentrant , and result
* must be deallocated .
*
* Returns A newly allocated string with the substitution done .
*/
xmlChar *
xmlEncodeEntitiesReentrant ( xmlDocPtr doc , const xmlChar * input ) {
return xmlEncodeEntitiesInternal ( doc , input , 0 ) ;
}
2001-02-23 20:55:21 +03:00
/**
* xmlEncodeSpecialChars :
* @ doc : the document containing the string
* @ input : A string to convert to XML .
*
* Do a global encoding of a string , replacing the predefined entities
* this routine is reentrant , and result must be deallocated .
*
* Returns A newly allocated string with the substitution done .
*/
xmlChar *
2014-10-13 12:06:21 +04:00
xmlEncodeSpecialChars ( const xmlDoc * doc ATTRIBUTE_UNUSED , const xmlChar * input ) {
2001-02-23 20:55:21 +03:00
const xmlChar * cur = input ;
xmlChar * buffer = NULL ;
xmlChar * out = NULL ;
2012-07-18 07:38:17 +04:00
size_t buffer_size = 0 ;
2003-09-26 22:03:42 +04:00
if ( input = = NULL ) return ( NULL ) ;
2001-02-23 20:55:21 +03:00
/*
* allocate an translation buffer .
*/
buffer_size = 1000 ;
2022-09-01 04:14:13 +03:00
buffer = ( xmlChar * ) xmlMalloc ( buffer_size ) ;
2023-12-10 17:25:42 +03:00
if ( buffer = = NULL )
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
out = buffer ;
while ( * cur ! = ' \0 ' ) {
2012-07-18 07:38:17 +04:00
size_t indx = out - buffer ;
if ( indx + 10 > buffer_size ) {
2001-02-23 20:55:21 +03:00
growBufferReentrant ( ) ;
2001-03-24 20:00:36 +03:00
out = & buffer [ indx ] ;
2001-02-23 20:55:21 +03:00
}
/*
* By default one have to encode at least ' < ' , ' > ' , ' " ' and ' & ' !
*/
if ( * cur = = ' < ' ) {
* out + + = ' & ' ;
* out + + = ' l ' ;
* out + + = ' t ' ;
* out + + = ' ; ' ;
} else if ( * cur = = ' > ' ) {
* out + + = ' & ' ;
* out + + = ' g ' ;
* out + + = ' t ' ;
* out + + = ' ; ' ;
} else if ( * cur = = ' & ' ) {
* out + + = ' & ' ;
* out + + = ' a ' ;
* out + + = ' m ' ;
* out + + = ' p ' ;
* out + + = ' ; ' ;
} else if ( * cur = = ' " ' ) {
* out + + = ' & ' ;
* out + + = ' q ' ;
* out + + = ' u ' ;
* out + + = ' o ' ;
* out + + = ' t ' ;
* out + + = ' ; ' ;
2003-02-26 18:49:03 +03:00
} else if ( * cur = = ' \r ' ) {
* out + + = ' & ' ;
* out + + = ' # ' ;
* out + + = ' 1 ' ;
* out + + = ' 3 ' ;
* out + + = ' ; ' ;
2001-02-23 20:55:21 +03:00
} else {
/*
* Works because on UTF - 8 , all extended sequences cannot
* result in bytes in the ASCII range .
*/
* out + + = * cur ;
}
cur + + ;
}
2009-09-05 16:52:55 +04:00
* out = 0 ;
2001-02-23 20:55:21 +03:00
return ( buffer ) ;
2012-07-18 07:38:17 +04:00
mem_error :
xmlFree ( buffer ) ;
return ( NULL ) ;
2001-02-23 20:55:21 +03:00
}
/**
* xmlCreateEntitiesTable :
*
* create and initialize an empty entities hash table .
2005-01-24 01:56:39 +03:00
* This really doesn ' t make sense and should be deprecated
2001-02-23 20:55:21 +03:00
*
* Returns the xmlEntitiesTablePtr just created or NULL in case of error .
*/
xmlEntitiesTablePtr
xmlCreateEntitiesTable ( void ) {
return ( ( xmlEntitiesTablePtr ) xmlHashCreate ( 0 ) ) ;
}
2002-12-30 03:01:08 +03:00
/**
* xmlFreeEntityWrapper :
* @ entity : An entity
* @ name : its name
*
* Deallocate the memory used by an entities in the hash table .
*/
static void
2017-11-09 18:42:47 +03:00
xmlFreeEntityWrapper ( void * entity , const xmlChar * name ATTRIBUTE_UNUSED ) {
2002-12-30 03:01:08 +03:00
if ( entity ! = NULL )
2017-11-09 18:42:47 +03:00
xmlFreeEntity ( ( xmlEntityPtr ) entity ) ;
2002-12-30 03:01:08 +03:00
}
2001-02-23 20:55:21 +03:00
/**
* xmlFreeEntitiesTable :
* @ table : An entity table
*
* Deallocate the memory used by an entities hash table .
*/
void
xmlFreeEntitiesTable ( xmlEntitiesTablePtr table ) {
2017-11-09 18:42:47 +03:00
xmlHashFree ( table , xmlFreeEntityWrapper ) ;
2001-02-23 20:55:21 +03:00
}
/**
* xmlCopyEntity :
* @ ent : An entity
*
* Build a copy of an entity
2012-09-11 09:26:36 +04:00
*
2001-02-23 20:55:21 +03:00
* Returns the new xmlEntitiesPtr or NULL in case of error .
*/
2017-11-09 18:42:47 +03:00
static void *
xmlCopyEntity ( void * payload , const xmlChar * name ATTRIBUTE_UNUSED ) {
xmlEntityPtr ent = ( xmlEntityPtr ) payload ;
2001-02-23 20:55:21 +03:00
xmlEntityPtr cur ;
cur = ( xmlEntityPtr ) xmlMalloc ( sizeof ( xmlEntity ) ) ;
2023-12-10 17:25:42 +03:00
if ( cur = = NULL )
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
memset ( cur , 0 , sizeof ( xmlEntity ) ) ;
2002-01-09 14:51:37 +03:00
cur - > type = XML_ENTITY_DECL ;
2001-02-23 20:55:21 +03:00
cur - > etype = ent - > etype ;
2023-12-10 17:25:42 +03:00
if ( ent - > name ! = NULL ) {
2001-02-23 20:55:21 +03:00
cur - > name = xmlStrdup ( ent - > name ) ;
2023-12-10 17:25:42 +03:00
if ( cur - > name = = NULL )
goto error ;
}
if ( ent - > ExternalID ! = NULL ) {
2001-02-23 20:55:21 +03:00
cur - > ExternalID = xmlStrdup ( ent - > ExternalID ) ;
2023-12-10 17:25:42 +03:00
if ( cur - > ExternalID = = NULL )
goto error ;
}
if ( ent - > SystemID ! = NULL ) {
2001-02-23 20:55:21 +03:00
cur - > SystemID = xmlStrdup ( ent - > SystemID ) ;
2023-12-10 17:25:42 +03:00
if ( cur - > SystemID = = NULL )
goto error ;
}
if ( ent - > content ! = NULL ) {
2001-02-23 20:55:21 +03:00
cur - > content = xmlStrdup ( ent - > content ) ;
2023-12-10 17:25:42 +03:00
if ( cur - > content = = NULL )
goto error ;
}
if ( ent - > orig ! = NULL ) {
2001-02-23 20:55:21 +03:00
cur - > orig = xmlStrdup ( ent - > orig ) ;
2023-12-10 17:25:42 +03:00
if ( cur - > orig = = NULL )
goto error ;
}
if ( ent - > URI ! = NULL ) {
2002-01-27 00:42:58 +03:00
cur - > URI = xmlStrdup ( ent - > URI ) ;
2023-12-10 17:25:42 +03:00
if ( cur - > URI = = NULL )
goto error ;
}
2001-02-23 20:55:21 +03:00
return ( cur ) ;
2023-12-10 17:25:42 +03:00
error :
xmlFreeEntity ( cur ) ;
return ( NULL ) ;
2001-02-23 20:55:21 +03:00
}
/**
* xmlCopyEntitiesTable :
* @ table : An entity table
*
* Build a copy of an entity table .
2012-09-11 09:26:36 +04:00
*
2001-02-23 20:55:21 +03:00
* Returns the new xmlEntitiesTablePtr or NULL in case of error .
*/
xmlEntitiesTablePtr
xmlCopyEntitiesTable ( xmlEntitiesTablePtr table ) {
2023-12-10 17:25:42 +03:00
return ( xmlHashCopySafe ( table , xmlCopyEntity , xmlFreeEntityWrapper ) ) ;
2001-02-23 20:55:21 +03:00
}
2003-09-29 17:20:24 +04:00
# ifdef LIBXML_OUTPUT_ENABLED
2003-12-10 01:51:37 +03:00
2001-02-23 20:55:21 +03:00
/**
* xmlDumpEntityDecl :
* @ buf : An XML buffer .
* @ ent : An entity table
*
* This will dump the content of the entity table as an XML DTD definition
*/
void
xmlDumpEntityDecl ( xmlBufferPtr buf , xmlEntityPtr ent ) {
2024-02-01 21:01:57 +03:00
xmlSaveCtxtPtr save ;
if ( ( buf = = NULL ) | | ( ent = = NULL ) )
return ;
save = xmlSaveToBuffer ( buf , NULL , 0 ) ;
xmlSaveTree ( save , ( xmlNodePtr ) ent ) ;
2024-03-05 21:58:17 +03:00
if ( xmlSaveFinish ( save ) ! = XML_ERR_OK )
xmlFree ( xmlBufferDetach ( buf ) ) ;
2001-02-23 20:55:21 +03:00
}
2003-10-20 18:56:06 +04:00
/**
* xmlDumpEntityDeclScan :
* @ ent : An entity table
* @ buf : An XML buffer .
*
* When using the hash table scan function , arguments need to be reversed
*/
static void
2024-03-05 21:58:17 +03:00
xmlDumpEntityDeclScan ( void * ent , void * save ,
2017-11-09 18:42:47 +03:00
const xmlChar * name ATTRIBUTE_UNUSED ) {
2024-03-05 21:58:17 +03:00
xmlSaveTree ( save , ent ) ;
2003-10-20 18:56:06 +04:00
}
2012-09-11 09:26:36 +04:00
2001-02-23 20:55:21 +03:00
/**
* xmlDumpEntitiesTable :
* @ buf : An XML buffer .
* @ table : An entity table
*
* This will dump the content of the entity table as an XML DTD definition
*/
void
xmlDumpEntitiesTable ( xmlBufferPtr buf , xmlEntitiesTablePtr table ) {
2024-03-05 21:58:17 +03:00
xmlSaveCtxtPtr save ;
if ( ( buf = = NULL ) | | ( table = = NULL ) )
return ;
save = xmlSaveToBuffer ( buf , NULL , 0 ) ;
xmlHashScan ( table , xmlDumpEntityDeclScan , save ) ;
if ( xmlSaveFinish ( save ) ! = XML_ERR_OK )
xmlFree ( xmlBufferDetach ( buf ) ) ;
2001-02-23 20:55:21 +03:00
}
2003-09-29 17:20:24 +04:00
# endif /* LIBXML_OUTPUT_ENABLED */