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
}
2024-07-12 04:07:57 +03:00
int
xmlSerializeHexCharRef ( char * buf , int val ) {
char * out = buf ;
int shift = 0 , bits ;
* out + + = ' & ' ;
* out + + = ' # ' ;
* out + + = ' x ' ;
bits = val ;
if ( bits & 0xFF0000 ) {
shift = 16 ;
bits & = 0xFF0000 ;
} else if ( bits & 0x00FF00 ) {
shift = 8 ;
bits & = 0x00FF00 ;
}
if ( bits & 0xF0F0F0 ) {
shift + = 4 ;
}
do {
int d = ( val > > shift ) & 0x0F ;
if ( d < 10 )
* out + + = ' 0 ' + d ;
else
* out + + = ' A ' + ( d - 10 ) ;
shift - = 4 ;
} while ( shift > = 0 ) ;
* out + + = ' ; ' ;
return ( out - buf ) ;
}
int
xmlSerializeDecCharRef ( char * buf , int val ) {
char * out = buf ;
int len , i ;
* out + + = ' & ' ;
* out + + = ' # ' ;
if ( val < 100 ) {
len = ( val < 10 ) ? 1 : 2 ;
} else if ( val < 10000 ) {
len = ( val < 1000 ) ? 3 : 4 ;
} else if ( val < 1000000 ) {
len = ( val < 100000 ) ? 5 : 6 ;
} else {
len = 7 ;
}
for ( i = len - 1 ; i > = 0 ; i - - ) {
out [ i ] = ' 0 ' + val % 10 ;
val / = 10 ;
}
out [ len ] = ' ; ' ;
return ( len + 3 ) ;
}
2024-07-12 03:01:06 +03:00
static const char xmlEscapeSafe [ 128 ] = {
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 ,
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1
} ;
2001-02-23 20:55:21 +03:00
2024-07-12 03:01:06 +03:00
xmlChar *
xmlEscapeText ( const xmlChar * text , int flags ) {
const xmlChar * cur ;
xmlChar * buffer ;
xmlChar * out ;
const xmlChar * unescaped ;
size_t size = 50 ;
buffer = xmlMalloc ( size + 1 ) ;
2023-12-10 17:25:42 +03:00
if ( buffer = = NULL )
2024-07-12 03:01:06 +03:00
return ( NULL ) ;
2001-02-23 20:55:21 +03:00
out = buffer ;
2024-07-12 03:01:06 +03:00
cur = text ;
unescaped = cur ;
2012-09-05 07:45:32 +04:00
2024-07-12 03:01:06 +03:00
while ( * cur ! = ' \0 ' ) {
2024-07-12 04:07:57 +03:00
char buf [ 12 ] ;
2024-07-12 03:01:06 +03:00
const xmlChar * end ;
const xmlChar * repl ;
size_t used ;
size_t replSize ;
size_t unescapedSize ;
size_t totalSize ;
int chunkSize = 1 ;
int c ;
/* accelerator */
while ( 1 ) {
c = * cur ;
if ( c < 0x80 ) {
if ( ! xmlEscapeSafe [ * cur ] )
break ;
} else {
if ( flags & XML_ESCAPE_NON_ASCII )
break ;
}
cur + = 1 ;
}
if ( c = = 0 ) {
chunkSize = 0 ;
repl = BAD_CAST " " ;
replSize = 0 ;
} else if ( c = = ' < ' ) {
2012-09-05 07:45:32 +04:00
/*
* Special handling of server side include in HTML attributes
*/
2024-07-12 03:01:06 +03:00
if ( ( flags & XML_ESCAPE_HTML ) & & ( flags & XML_ESCAPE_ATTR ) & &
2012-09-05 07:45:32 +04:00
( cur [ 1 ] = = ' ! ' ) & & ( cur [ 2 ] = = ' - ' ) & & ( cur [ 3 ] = = ' - ' ) & &
( ( end = xmlStrstr ( cur , BAD_CAST " --> " ) ) ! = NULL ) ) {
2024-07-12 03:01:06 +03:00
chunkSize = ( end - cur ) + 3 ;
repl = cur ;
replSize = chunkSize ;
} else {
repl = BAD_CAST " < " ;
replSize = 4 ;
}
} else if ( c = = ' > ' ) {
repl = BAD_CAST " > " ;
replSize = 4 ;
} else if ( c = = ' & ' ) {
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
*/
2024-07-12 03:01:06 +03:00
if ( ( flags & XML_ESCAPE_HTML ) & & ( flags & XML_ESCAPE_ATTR ) & &
( cur [ 1 ] = = ' { ' ) & & ( end = xmlStrchr ( cur , ' } ' ) ) ) {
chunkSize = ( end - cur ) + 1 ;
repl = cur ;
replSize = chunkSize ;
2001-02-23 20:55:21 +03:00
} else {
2024-07-12 03:01:06 +03:00
repl = BAD_CAST " & " ;
replSize = 5 ;
}
} else if ( ( flags & XML_ESCAPE_QUOT ) & & ( c = = ' " ' ) ) {
repl = BAD_CAST " " " ;
replSize = 6 ;
} else if ( ( ( flags & XML_ESCAPE_HTML ) = = 0 ) & & ( c = = ' \r ' ) ) {
repl = BAD_CAST " " ;
replSize = 5 ;
} else if ( ( flags & XML_ESCAPE_NON_ASCII ) & & ( c > = 0x80 ) ) {
int val ;
chunkSize = 4 ;
val = xmlGetUTF8Char ( cur , & chunkSize ) ;
if ( val < 0 ) {
val = 0xFFFD ;
chunkSize = 1 ;
} else if ( ( ( flags & XML_ESCAPE_ALLOW_INVALID ) = = 0 ) & &
( ! IS_CHAR ( val ) ) ) {
val = 0xFFFD ;
}
2001-02-23 20:55:21 +03:00
2024-07-12 04:07:57 +03:00
replSize = xmlSerializeHexCharRef ( buf , val ) ;
2024-07-12 03:01:06 +03:00
repl = BAD_CAST buf ;
} else if ( ( flags & XML_ESCAPE_ALLOW_INVALID ) | |
( c > = 0x20 ) | |
( c = = ' \n ' ) | | ( c = = ' \t ' ) | | ( c = = ' \r ' ) ) {
/* default case, just copy */
cur + = 1 ;
if ( * cur ! = 0 )
continue ;
chunkSize = 0 ;
repl = BAD_CAST " " ;
replSize = 0 ;
} else {
/* ignore */
repl = BAD_CAST " " ;
replSize = 0 ;
}
used = out - buffer ;
unescapedSize = cur - unescaped ;
totalSize = unescapedSize + replSize ;
cur + = chunkSize ;
if ( totalSize > size - used ) {
xmlChar * tmp ;
size + = totalSize ;
if ( * cur ! = 0 )
size * = 2 ;
tmp = xmlRealloc ( buffer , size + 1 ) ;
if ( tmp = = NULL ) {
xmlFree ( buffer ) ;
return ( NULL ) ;
}
buffer = tmp ;
out = buffer + used ;
}
memcpy ( out , unescaped , unescapedSize ) ;
out + = unescapedSize ;
memcpy ( out , repl , replSize ) ;
out + = replSize ;
unescaped = cur ;
2001-02-23 20:55:21 +03:00
}
2024-07-12 03:01:06 +03:00
2009-09-05 16:52:55 +04:00
* out = 0 ;
2001-02-23 20:55:21 +03:00
return ( buffer ) ;
}
2012-09-05 07:45:32 +04:00
/**
2024-07-12 03:01:06 +03:00
* xmlEncodeEntitiesInternal :
2012-09-05 07:45:32 +04:00
* @ doc : the document containing the string
* @ input : A string to convert to XML .
2024-07-12 03:01:06 +03:00
* @ attr : are we handling an attribute value
2012-09-05 07:45:32 +04:00
*
* Do a global encoding of a string , replacing the predefined entities
2024-07-12 03:01:06 +03:00
* and non ASCII values with their entities and CharRef counterparts .
* Contrary to xmlEncodeEntities , this routine is reentrant , and result
* must be deallocated .
2012-09-05 07:45:32 +04:00
*
* Returns A newly allocated string with the substitution done .
*/
xmlChar *
2024-07-12 03:01:06 +03:00
xmlEncodeEntitiesInternal ( xmlDocPtr doc , const xmlChar * input ,
unsigned flags ) {
if ( input = = NULL )
return ( NULL ) ;
if ( ( doc ! = NULL ) & & ( doc - > type = = XML_HTML_DOCUMENT_NODE ) )
flags | = XML_ESCAPE_HTML ;
else if ( ( doc = = NULL ) | | ( doc - > encoding = = NULL ) )
flags | = XML_ESCAPE_NON_ASCII ;
return ( xmlEscapeText ( input , flags ) ) ;
2012-09-05 07:45:32 +04:00
}
/**
* 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 .
*
2024-07-12 03:01:06 +03:00
* This escapes ' < ' , ' > ' , ' & ' and ' \r ' . If the document has no encoding ,
* non - ASCII codepoints are escaped . There is some special handling for
* HTML documents .
*
2012-09-05 07:45:32 +04:00
* 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 :
2024-07-12 03:01:06 +03:00
* @ doc : unused
2001-02-23 20:55:21 +03:00
* @ 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 .
*
2024-07-12 03:01:06 +03:00
* This escapes ' < ' , ' > ' , ' & ' , ' " ' and ' \r ' chars .
*
2001-02-23 20:55:21 +03:00
* Returns A newly allocated string with the substitution done .
*/
xmlChar *
2024-07-12 03:01:06 +03:00
xmlEncodeSpecialChars ( const xmlDoc * doc ATTRIBUTE_UNUSED ,
const xmlChar * input ) {
if ( input = = NULL )
return ( NULL ) ;
2012-07-18 07:38:17 +04:00
2024-07-12 03:01:06 +03:00
return ( xmlEscapeText ( input , XML_ESCAPE_QUOT | XML_ESCAPE_ALLOW_INVALID ) ) ;
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 */