Home | History | Annotate | Download | only in libxml2
      1 /*
      2  * entities.c : implementation for the XML entities handling
      3  *
      4  * See Copyright for the status of this software.
      5  *
      6  * daniel (at) veillard.com
      7  */
      8 
      9 #define IN_LIBXML
     10 #include "libxml.h"
     11 
     12 #include <string.h>
     13 #ifdef HAVE_STDLIB_H
     14 #include <stdlib.h>
     15 #endif
     16 #include <libxml/xmlmemory.h>
     17 #include <libxml/hash.h>
     18 #include <libxml/entities.h>
     19 #include <libxml/parser.h>
     20 #include <libxml/parserInternals.h>
     21 #include <libxml/xmlerror.h>
     22 #include <libxml/globals.h>
     23 #include <libxml/dict.h>
     24 
     25 /*
     26  * The XML predefined entities.
     27  */
     28 
     29 static xmlEntity xmlEntityLt = {
     30     NULL, XML_ENTITY_DECL, BAD_CAST "lt",
     31     NULL, NULL, NULL, NULL, NULL, NULL,
     32     BAD_CAST "<", BAD_CAST "<", 1,
     33     XML_INTERNAL_PREDEFINED_ENTITY,
     34     NULL, NULL, NULL, NULL, 0, 1
     35 };
     36 static xmlEntity xmlEntityGt = {
     37     NULL, XML_ENTITY_DECL, BAD_CAST "gt",
     38     NULL, NULL, NULL, NULL, NULL, NULL,
     39     BAD_CAST ">", BAD_CAST ">", 1,
     40     XML_INTERNAL_PREDEFINED_ENTITY,
     41     NULL, NULL, NULL, NULL, 0, 1
     42 };
     43 static xmlEntity xmlEntityAmp = {
     44     NULL, XML_ENTITY_DECL, BAD_CAST "amp",
     45     NULL, NULL, NULL, NULL, NULL, NULL,
     46     BAD_CAST "&", BAD_CAST "&", 1,
     47     XML_INTERNAL_PREDEFINED_ENTITY,
     48     NULL, NULL, NULL, NULL, 0, 1
     49 };
     50 static xmlEntity xmlEntityQuot = {
     51     NULL, XML_ENTITY_DECL, BAD_CAST "quot",
     52     NULL, NULL, NULL, NULL, NULL, NULL,
     53     BAD_CAST "\"", BAD_CAST "\"", 1,
     54     XML_INTERNAL_PREDEFINED_ENTITY,
     55     NULL, NULL, NULL, NULL, 0, 1
     56 };
     57 static xmlEntity xmlEntityApos = {
     58     NULL, XML_ENTITY_DECL, BAD_CAST "apos",
     59     NULL, NULL, NULL, NULL, NULL, NULL,
     60     BAD_CAST "'", BAD_CAST "'", 1,
     61     XML_INTERNAL_PREDEFINED_ENTITY,
     62     NULL, NULL, NULL, NULL, 0, 1
     63 };
     64 
     65 /**
     66  * xmlEntitiesErrMemory:
     67  * @extra:  extra informations
     68  *
     69  * Handle an out of memory condition
     70  */
     71 static void
     72 xmlEntitiesErrMemory(const char *extra)
     73 {
     74     __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
     75 }
     76 
     77 /**
     78  * xmlEntitiesErr:
     79  * @code:  the error code
     80  * @msg:  the message
     81  *
     82  * Handle an out of memory condition
     83  */
     84 static void
     85 xmlEntitiesErr(xmlParserErrors code, const char *msg)
     86 {
     87     __xmlSimpleError(XML_FROM_TREE, code, NULL, msg, NULL);
     88 }
     89 
     90 /*
     91  * xmlFreeEntity : clean-up an entity record.
     92  */
     93 static void
     94 xmlFreeEntity(xmlEntityPtr entity)
     95 {
     96     xmlDictPtr dict = NULL;
     97 
     98     if (entity == NULL)
     99         return;
    100 
    101     if (entity->doc != NULL)
    102         dict = entity->doc->dict;
    103 
    104 
    105     if ((entity->children) && (entity->owner == 1) &&
    106         (entity == (xmlEntityPtr) entity->children->parent))
    107         xmlFreeNodeList(entity->children);
    108     if (dict != NULL) {
    109         if ((entity->name != NULL) && (!xmlDictOwns(dict, entity->name)))
    110             xmlFree((char *) entity->name);
    111         if ((entity->ExternalID != NULL) &&
    112 	    (!xmlDictOwns(dict, entity->ExternalID)))
    113             xmlFree((char *) entity->ExternalID);
    114         if ((entity->SystemID != NULL) &&
    115 	    (!xmlDictOwns(dict, entity->SystemID)))
    116             xmlFree((char *) entity->SystemID);
    117         if ((entity->URI != NULL) && (!xmlDictOwns(dict, entity->URI)))
    118             xmlFree((char *) entity->URI);
    119         if ((entity->content != NULL)
    120             && (!xmlDictOwns(dict, entity->content)))
    121             xmlFree((char *) entity->content);
    122         if ((entity->orig != NULL) && (!xmlDictOwns(dict, entity->orig)))
    123             xmlFree((char *) entity->orig);
    124     } else {
    125         if (entity->name != NULL)
    126             xmlFree((char *) entity->name);
    127         if (entity->ExternalID != NULL)
    128             xmlFree((char *) entity->ExternalID);
    129         if (entity->SystemID != NULL)
    130             xmlFree((char *) entity->SystemID);
    131         if (entity->URI != NULL)
    132             xmlFree((char *) entity->URI);
    133         if (entity->content != NULL)
    134             xmlFree((char *) entity->content);
    135         if (entity->orig != NULL)
    136             xmlFree((char *) entity->orig);
    137     }
    138     xmlFree(entity);
    139 }
    140 
    141 /*
    142  * xmlCreateEntity:
    143  *
    144  * internal routine doing the entity node strutures allocations
    145  */
    146 static xmlEntityPtr
    147 xmlCreateEntity(xmlDictPtr dict, const xmlChar *name, int type,
    148 	        const xmlChar *ExternalID, const xmlChar *SystemID,
    149 	        const xmlChar *content) {
    150     xmlEntityPtr ret;
    151 
    152     ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
    153     if (ret == NULL) {
    154         xmlEntitiesErrMemory("xmlCreateEntity: malloc failed");
    155 	return(NULL);
    156     }
    157     memset(ret, 0, sizeof(xmlEntity));
    158     ret->type = XML_ENTITY_DECL;
    159     ret->checked = 0;
    160 
    161     /*
    162      * fill the structure.
    163      */
    164     ret->etype = (xmlEntityType) type;
    165     if (dict == NULL) {
    166 	ret->name = xmlStrdup(name);
    167 	if (ExternalID != NULL)
    168 	    ret->ExternalID = xmlStrdup(ExternalID);
    169 	if (SystemID != NULL)
    170 	    ret->SystemID = xmlStrdup(SystemID);
    171     } else {
    172         ret->name = xmlDictLookup(dict, name, -1);
    173 	if (ExternalID != NULL)
    174 	    ret->ExternalID = xmlDictLookup(dict, ExternalID, -1);
    175 	if (SystemID != NULL)
    176 	    ret->SystemID = xmlDictLookup(dict, SystemID, -1);
    177     }
    178     if (content != NULL) {
    179         ret->length = xmlStrlen(content);
    180 	if ((dict != NULL) && (ret->length < 5))
    181 	    ret->content = (xmlChar *)
    182 	                   xmlDictLookup(dict, content, ret->length);
    183 	else
    184 	    ret->content = xmlStrndup(content, ret->length);
    185      } else {
    186         ret->length = 0;
    187         ret->content = NULL;
    188     }
    189     ret->URI = NULL; /* to be computed by the layer knowing
    190 			the defining entity */
    191     ret->orig = NULL;
    192     ret->owner = 0;
    193 
    194     return(ret);
    195 }
    196 
    197 /*
    198  * xmlAddEntity : register a new entity for an entities table.
    199  */
    200 static xmlEntityPtr
    201 xmlAddEntity(xmlDtdPtr dtd, const xmlChar *name, int type,
    202 	  const xmlChar *ExternalID, const xmlChar *SystemID,
    203 	  const xmlChar *content) {
    204     xmlDictPtr dict = NULL;
    205     xmlEntitiesTablePtr table = NULL;
    206     xmlEntityPtr ret;
    207 
    208     if (name == NULL)
    209 	return(NULL);
    210     if (dtd == NULL)
    211 	return(NULL);
    212     if (dtd->doc != NULL)
    213         dict = dtd->doc->dict;
    214 
    215     switch (type) {
    216         case XML_INTERNAL_GENERAL_ENTITY:
    217         case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
    218         case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
    219 	    if (dtd->entities == NULL)
    220 		dtd->entities = xmlHashCreateDict(0, dict);
    221 	    table = dtd->entities;
    222 	    break;
    223         case XML_INTERNAL_PARAMETER_ENTITY:
    224         case XML_EXTERNAL_PARAMETER_ENTITY:
    225 	    if (dtd->pentities == NULL)
    226 		dtd->pentities = xmlHashCreateDict(0, dict);
    227 	    table = dtd->pentities;
    228 	    break;
    229         case XML_INTERNAL_PREDEFINED_ENTITY:
    230 	    return(NULL);
    231     }
    232     if (table == NULL)
    233 	return(NULL);
    234     ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content);
    235     if (ret == NULL)
    236         return(NULL);
    237     ret->doc = dtd->doc;
    238 
    239     if (xmlHashAddEntry(table, name, ret)) {
    240 	/*
    241 	 * entity was already defined at another level.
    242 	 */
    243         xmlFreeEntity(ret);
    244 	return(NULL);
    245     }
    246     return(ret);
    247 }
    248 
    249 /**
    250  * xmlGetPredefinedEntity:
    251  * @name:  the entity name
    252  *
    253  * Check whether this name is an predefined entity.
    254  *
    255  * Returns NULL if not, otherwise the entity
    256  */
    257 xmlEntityPtr
    258 xmlGetPredefinedEntity(const xmlChar *name) {
    259     if (name == NULL) return(NULL);
    260     switch (name[0]) {
    261         case 'l':
    262 	    if (xmlStrEqual(name, BAD_CAST "lt"))
    263 	        return(&xmlEntityLt);
    264 	    break;
    265         case 'g':
    266 	    if (xmlStrEqual(name, BAD_CAST "gt"))
    267 	        return(&xmlEntityGt);
    268 	    break;
    269         case 'a':
    270 	    if (xmlStrEqual(name, BAD_CAST "amp"))
    271 	        return(&xmlEntityAmp);
    272 	    if (xmlStrEqual(name, BAD_CAST "apos"))
    273 	        return(&xmlEntityApos);
    274 	    break;
    275         case 'q':
    276 	    if (xmlStrEqual(name, BAD_CAST "quot"))
    277 	        return(&xmlEntityQuot);
    278 	    break;
    279 	default:
    280 	    break;
    281     }
    282     return(NULL);
    283 }
    284 
    285 /**
    286  * xmlAddDtdEntity:
    287  * @doc:  the document
    288  * @name:  the entity name
    289  * @type:  the entity type XML_xxx_yyy_ENTITY
    290  * @ExternalID:  the entity external ID if available
    291  * @SystemID:  the entity system ID if available
    292  * @content:  the entity content
    293  *
    294  * Register a new entity for this document DTD external subset.
    295  *
    296  * Returns a pointer to the entity or NULL in case of error
    297  */
    298 xmlEntityPtr
    299 xmlAddDtdEntity(xmlDocPtr doc, const xmlChar *name, int type,
    300 	        const xmlChar *ExternalID, const xmlChar *SystemID,
    301 		const xmlChar *content) {
    302     xmlEntityPtr ret;
    303     xmlDtdPtr dtd;
    304 
    305     if (doc == NULL) {
    306 	xmlEntitiesErr(XML_DTD_NO_DOC,
    307 	        "xmlAddDtdEntity: document is NULL");
    308 	return(NULL);
    309     }
    310     if (doc->extSubset == NULL) {
    311 	xmlEntitiesErr(XML_DTD_NO_DTD,
    312 	        "xmlAddDtdEntity: document without external subset");
    313 	return(NULL);
    314     }
    315     dtd = doc->extSubset;
    316     ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content);
    317     if (ret == NULL) return(NULL);
    318 
    319     /*
    320      * Link it to the DTD
    321      */
    322     ret->parent = dtd;
    323     ret->doc = dtd->doc;
    324     if (dtd->last == NULL) {
    325 	dtd->children = dtd->last = (xmlNodePtr) ret;
    326     } else {
    327         dtd->last->next = (xmlNodePtr) ret;
    328 	ret->prev = dtd->last;
    329 	dtd->last = (xmlNodePtr) ret;
    330     }
    331     return(ret);
    332 }
    333 
    334 /**
    335  * xmlAddDocEntity:
    336  * @doc:  the document
    337  * @name:  the entity name
    338  * @type:  the entity type XML_xxx_yyy_ENTITY
    339  * @ExternalID:  the entity external ID if available
    340  * @SystemID:  the entity system ID if available
    341  * @content:  the entity content
    342  *
    343  * Register a new entity for this document.
    344  *
    345  * Returns a pointer to the entity or NULL in case of error
    346  */
    347 xmlEntityPtr
    348 xmlAddDocEntity(xmlDocPtr doc, const xmlChar *name, int type,
    349 	        const xmlChar *ExternalID, const xmlChar *SystemID,
    350 	        const xmlChar *content) {
    351     xmlEntityPtr ret;
    352     xmlDtdPtr dtd;
    353 
    354     if (doc == NULL) {
    355 	xmlEntitiesErr(XML_DTD_NO_DOC,
    356 	        "xmlAddDocEntity: document is NULL");
    357 	return(NULL);
    358     }
    359     if (doc->intSubset == NULL) {
    360 	xmlEntitiesErr(XML_DTD_NO_DTD,
    361 	        "xmlAddDocEntity: document without internal subset");
    362 	return(NULL);
    363     }
    364     dtd = doc->intSubset;
    365     ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content);
    366     if (ret == NULL) return(NULL);
    367 
    368     /*
    369      * Link it to the DTD
    370      */
    371     ret->parent = dtd;
    372     ret->doc = dtd->doc;
    373     if (dtd->last == NULL) {
    374 	dtd->children = dtd->last = (xmlNodePtr) ret;
    375     } else {
    376 	dtd->last->next = (xmlNodePtr) ret;
    377 	ret->prev = dtd->last;
    378 	dtd->last = (xmlNodePtr) ret;
    379     }
    380     return(ret);
    381 }
    382 
    383 /**
    384  * xmlNewEntity:
    385  * @doc:  the document
    386  * @name:  the entity name
    387  * @type:  the entity type XML_xxx_yyy_ENTITY
    388  * @ExternalID:  the entity external ID if available
    389  * @SystemID:  the entity system ID if available
    390  * @content:  the entity content
    391  *
    392  * Create a new entity, this differs from xmlAddDocEntity() that if
    393  * the document is NULL or has no internal subset defined, then an
    394  * unlinked entity structure will be returned, it is then the responsability
    395  * of the caller to link it to the document later or free it when not needed
    396  * anymore.
    397  *
    398  * Returns a pointer to the entity or NULL in case of error
    399  */
    400 xmlEntityPtr
    401 xmlNewEntity(xmlDocPtr doc, const xmlChar *name, int type,
    402 	     const xmlChar *ExternalID, const xmlChar *SystemID,
    403 	     const xmlChar *content) {
    404     xmlEntityPtr ret;
    405     xmlDictPtr dict;
    406 
    407     if ((doc != NULL) && (doc->intSubset != NULL)) {
    408 	return(xmlAddDocEntity(doc, name, type, ExternalID, SystemID, content));
    409     }
    410     if (doc != NULL)
    411         dict = doc->dict;
    412     else
    413         dict = NULL;
    414     ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content);
    415     if (ret == NULL)
    416         return(NULL);
    417     ret->doc = doc;
    418     return(ret);
    419 }
    420 
    421 /**
    422  * xmlGetEntityFromTable:
    423  * @table:  an entity table
    424  * @name:  the entity name
    425  * @parameter:  look for parameter entities
    426  *
    427  * Do an entity lookup in the table.
    428  * returns the corresponding parameter entity, if found.
    429  *
    430  * Returns A pointer to the entity structure or NULL if not found.
    431  */
    432 static xmlEntityPtr
    433 xmlGetEntityFromTable(xmlEntitiesTablePtr table, const xmlChar *name) {
    434     return((xmlEntityPtr) xmlHashLookup(table, name));
    435 }
    436 
    437 /**
    438  * xmlGetParameterEntity:
    439  * @doc:  the document referencing the entity
    440  * @name:  the entity name
    441  *
    442  * Do an entity lookup in the internal and external subsets and
    443  * returns the corresponding parameter entity, if found.
    444  *
    445  * Returns A pointer to the entity structure or NULL if not found.
    446  */
    447 xmlEntityPtr
    448 xmlGetParameterEntity(xmlDocPtr doc, const xmlChar *name) {
    449     xmlEntitiesTablePtr table;
    450     xmlEntityPtr ret;
    451 
    452     if (doc == NULL)
    453 	return(NULL);
    454     if ((doc->intSubset != NULL) && (doc->intSubset->pentities != NULL)) {
    455 	table = (xmlEntitiesTablePtr) doc->intSubset->pentities;
    456 	ret = xmlGetEntityFromTable(table, name);
    457 	if (ret != NULL)
    458 	    return(ret);
    459     }
    460     if ((doc->extSubset != NULL) && (doc->extSubset->pentities != NULL)) {
    461 	table = (xmlEntitiesTablePtr) doc->extSubset->pentities;
    462 	return(xmlGetEntityFromTable(table, name));
    463     }
    464     return(NULL);
    465 }
    466 
    467 /**
    468  * xmlGetDtdEntity:
    469  * @doc:  the document referencing the entity
    470  * @name:  the entity name
    471  *
    472  * Do an entity lookup in the DTD entity hash table and
    473  * returns the corresponding entity, if found.
    474  * Note: the first argument is the document node, not the DTD node.
    475  *
    476  * Returns A pointer to the entity structure or NULL if not found.
    477  */
    478 xmlEntityPtr
    479 xmlGetDtdEntity(xmlDocPtr doc, const xmlChar *name) {
    480     xmlEntitiesTablePtr table;
    481 
    482     if (doc == NULL)
    483 	return(NULL);
    484     if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
    485 	table = (xmlEntitiesTablePtr) doc->extSubset->entities;
    486 	return(xmlGetEntityFromTable(table, name));
    487     }
    488     return(NULL);
    489 }
    490 
    491 /**
    492  * xmlGetDocEntity:
    493  * @doc:  the document referencing the entity
    494  * @name:  the entity name
    495  *
    496  * Do an entity lookup in the document entity hash table and
    497  * returns the corresponding entity, otherwise a lookup is done
    498  * in the predefined entities too.
    499  *
    500  * Returns A pointer to the entity structure or NULL if not found.
    501  */
    502 xmlEntityPtr
    503 xmlGetDocEntity(xmlDocPtr doc, const xmlChar *name) {
    504     xmlEntityPtr cur;
    505     xmlEntitiesTablePtr table;
    506 
    507     if (doc != NULL) {
    508 	if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
    509 	    table = (xmlEntitiesTablePtr) doc->intSubset->entities;
    510 	    cur = xmlGetEntityFromTable(table, name);
    511 	    if (cur != NULL)
    512 		return(cur);
    513 	}
    514 	if (doc->standalone != 1) {
    515 	    if ((doc->extSubset != NULL) &&
    516 		(doc->extSubset->entities != NULL)) {
    517 		table = (xmlEntitiesTablePtr) doc->extSubset->entities;
    518 		cur = xmlGetEntityFromTable(table, name);
    519 		if (cur != NULL)
    520 		    return(cur);
    521 	    }
    522 	}
    523     }
    524     return(xmlGetPredefinedEntity(name));
    525 }
    526 
    527 /*
    528  * Macro used to grow the current buffer.
    529  */
    530 #define growBufferReentrant() {						\
    531     buffer_size *= 2;							\
    532     buffer = (xmlChar *)						\
    533     		xmlRealloc(buffer, buffer_size * sizeof(xmlChar));	\
    534     if (buffer == NULL) {						\
    535         xmlEntitiesErrMemory("xmlEncodeEntitiesReentrant: realloc failed");\
    536 	return(NULL);							\
    537     }									\
    538 }
    539 
    540 
    541 /**
    542  * xmlEncodeEntitiesReentrant:
    543  * @doc:  the document containing the string
    544  * @input:  A string to convert to XML.
    545  *
    546  * Do a global encoding of a string, replacing the predefined entities
    547  * and non ASCII values with their entities and CharRef counterparts.
    548  * Contrary to xmlEncodeEntities, this routine is reentrant, and result
    549  * must be deallocated.
    550  *
    551  * Returns A newly allocated string with the substitution done.
    552  */
    553 xmlChar *
    554 xmlEncodeEntitiesReentrant(xmlDocPtr doc, const xmlChar *input) {
    555     const xmlChar *cur = input;
    556     xmlChar *buffer = NULL;
    557     xmlChar *out = NULL;
    558     int buffer_size = 0;
    559     int html = 0;
    560 
    561     if (input == NULL) return(NULL);
    562     if (doc != NULL)
    563         html = (doc->type == XML_HTML_DOCUMENT_NODE);
    564 
    565     /*
    566      * allocate an translation buffer.
    567      */
    568     buffer_size = 1000;
    569     buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
    570     if (buffer == NULL) {
    571         xmlEntitiesErrMemory("xmlEncodeEntitiesReentrant: malloc failed");
    572 	return(NULL);
    573     }
    574     out = buffer;
    575 
    576     while (*cur != '\0') {
    577         if (out - buffer > buffer_size - 100) {
    578 	    int indx = out - buffer;
    579 
    580 	    growBufferReentrant();
    581 	    out = &buffer[indx];
    582 	}
    583 
    584 	/*
    585 	 * By default one have to encode at least '<', '>', '"' and '&' !
    586 	 */
    587 	if (*cur == '<') {
    588 	    *out++ = '&';
    589 	    *out++ = 'l';
    590 	    *out++ = 't';
    591 	    *out++ = ';';
    592 	} else if (*cur == '>') {
    593 	    *out++ = '&';
    594 	    *out++ = 'g';
    595 	    *out++ = 't';
    596 	    *out++ = ';';
    597 	} else if (*cur == '&') {
    598 	    *out++ = '&';
    599 	    *out++ = 'a';
    600 	    *out++ = 'm';
    601 	    *out++ = 'p';
    602 	    *out++ = ';';
    603 	} else if (((*cur >= 0x20) && (*cur < 0x80)) ||
    604 	    (*cur == '\n') || (*cur == '\t') || ((html) && (*cur == '\r'))) {
    605 	    /*
    606 	     * default case, just copy !
    607 	     */
    608 	    *out++ = *cur;
    609 	} else if (*cur >= 0x80) {
    610 	    if (((doc != NULL) && (doc->encoding != NULL)) || (html)) {
    611 		/*
    612 		 * Bjrn Reese <br (at) sseusa.com> provided the patch
    613 	        xmlChar xc;
    614 	        xc = (*cur & 0x3F) << 6;
    615 	        if (cur[1] != 0) {
    616 		    xc += *(++cur) & 0x3F;
    617 		    *out++ = xc;
    618 	        } else
    619 		 */
    620 		*out++ = *cur;
    621 	    } else {
    622 		/*
    623 		 * We assume we have UTF-8 input.
    624 		 */
    625 		char buf[11], *ptr;
    626 		int val = 0, l = 1;
    627 
    628 		if (*cur < 0xC0) {
    629 		    xmlEntitiesErr(XML_CHECK_NOT_UTF8,
    630 			    "xmlEncodeEntitiesReentrant : input not UTF-8");
    631 		    if (doc != NULL)
    632 			doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
    633 		    snprintf(buf, sizeof(buf), "&#%d;", *cur);
    634 		    buf[sizeof(buf) - 1] = 0;
    635 		    ptr = buf;
    636 		    while (*ptr != 0) *out++ = *ptr++;
    637 		    cur++;
    638 		    continue;
    639 		} else if (*cur < 0xE0) {
    640                     val = (cur[0]) & 0x1F;
    641 		    val <<= 6;
    642 		    val |= (cur[1]) & 0x3F;
    643 		    l = 2;
    644 		} else if (*cur < 0xF0) {
    645                     val = (cur[0]) & 0x0F;
    646 		    val <<= 6;
    647 		    val |= (cur[1]) & 0x3F;
    648 		    val <<= 6;
    649 		    val |= (cur[2]) & 0x3F;
    650 		    l = 3;
    651 		} else if (*cur < 0xF8) {
    652                     val = (cur[0]) & 0x07;
    653 		    val <<= 6;
    654 		    val |= (cur[1]) & 0x3F;
    655 		    val <<= 6;
    656 		    val |= (cur[2]) & 0x3F;
    657 		    val <<= 6;
    658 		    val |= (cur[3]) & 0x3F;
    659 		    l = 4;
    660 		}
    661 		if ((l == 1) || (!IS_CHAR(val))) {
    662 		    xmlEntitiesErr(XML_ERR_INVALID_CHAR,
    663 			"xmlEncodeEntitiesReentrant : char out of range\n");
    664 		    if (doc != NULL)
    665 			doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
    666 		    snprintf(buf, sizeof(buf), "&#%d;", *cur);
    667 		    buf[sizeof(buf) - 1] = 0;
    668 		    ptr = buf;
    669 		    while (*ptr != 0) *out++ = *ptr++;
    670 		    cur++;
    671 		    continue;
    672 		}
    673 		/*
    674 		 * We could do multiple things here. Just save as a char ref
    675 		 */
    676 		snprintf(buf, sizeof(buf), "&#x%X;", val);
    677 		buf[sizeof(buf) - 1] = 0;
    678 		ptr = buf;
    679 		while (*ptr != 0) *out++ = *ptr++;
    680 		cur += l;
    681 		continue;
    682 	    }
    683 	} else if (IS_BYTE_CHAR(*cur)) {
    684 	    char buf[11], *ptr;
    685 
    686 	    snprintf(buf, sizeof(buf), "&#%d;", *cur);
    687 	    buf[sizeof(buf) - 1] = 0;
    688             ptr = buf;
    689 	    while (*ptr != 0) *out++ = *ptr++;
    690 	}
    691 	cur++;
    692     }
    693     *out++ = 0;
    694     return(buffer);
    695 }
    696 
    697 /**
    698  * xmlEncodeSpecialChars:
    699  * @doc:  the document containing the string
    700  * @input:  A string to convert to XML.
    701  *
    702  * Do a global encoding of a string, replacing the predefined entities
    703  * this routine is reentrant, and result must be deallocated.
    704  *
    705  * Returns A newly allocated string with the substitution done.
    706  */
    707 xmlChar *
    708 xmlEncodeSpecialChars(xmlDocPtr doc ATTRIBUTE_UNUSED, const xmlChar *input) {
    709     const xmlChar *cur = input;
    710     xmlChar *buffer = NULL;
    711     xmlChar *out = NULL;
    712     int buffer_size = 0;
    713     if (input == NULL) return(NULL);
    714 
    715     /*
    716      * allocate an translation buffer.
    717      */
    718     buffer_size = 1000;
    719     buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
    720     if (buffer == NULL) {
    721         xmlEntitiesErrMemory("xmlEncodeSpecialChars: malloc failed");
    722 	return(NULL);
    723     }
    724     out = buffer;
    725 
    726     while (*cur != '\0') {
    727         if (out - buffer > buffer_size - 10) {
    728 	    int indx = out - buffer;
    729 
    730 	    growBufferReentrant();
    731 	    out = &buffer[indx];
    732 	}
    733 
    734 	/*
    735 	 * By default one have to encode at least '<', '>', '"' and '&' !
    736 	 */
    737 	if (*cur == '<') {
    738 	    *out++ = '&';
    739 	    *out++ = 'l';
    740 	    *out++ = 't';
    741 	    *out++ = ';';
    742 	} else if (*cur == '>') {
    743 	    *out++ = '&';
    744 	    *out++ = 'g';
    745 	    *out++ = 't';
    746 	    *out++ = ';';
    747 	} else if (*cur == '&') {
    748 	    *out++ = '&';
    749 	    *out++ = 'a';
    750 	    *out++ = 'm';
    751 	    *out++ = 'p';
    752 	    *out++ = ';';
    753 	} else if (*cur == '"') {
    754 	    *out++ = '&';
    755 	    *out++ = 'q';
    756 	    *out++ = 'u';
    757 	    *out++ = 'o';
    758 	    *out++ = 't';
    759 	    *out++ = ';';
    760 	} else if (*cur == '\r') {
    761 	    *out++ = '&';
    762 	    *out++ = '#';
    763 	    *out++ = '1';
    764 	    *out++ = '3';
    765 	    *out++ = ';';
    766 	} else {
    767 	    /*
    768 	     * Works because on UTF-8, all extended sequences cannot
    769 	     * result in bytes in the ASCII range.
    770 	     */
    771 	    *out++ = *cur;
    772 	}
    773 	cur++;
    774     }
    775     *out++ = 0;
    776     return(buffer);
    777 }
    778 
    779 /**
    780  * xmlCreateEntitiesTable:
    781  *
    782  * create and initialize an empty entities hash table.
    783  * This really doesn't make sense and should be deprecated
    784  *
    785  * Returns the xmlEntitiesTablePtr just created or NULL in case of error.
    786  */
    787 xmlEntitiesTablePtr
    788 xmlCreateEntitiesTable(void) {
    789     return((xmlEntitiesTablePtr) xmlHashCreate(0));
    790 }
    791 
    792 /**
    793  * xmlFreeEntityWrapper:
    794  * @entity:  An entity
    795  * @name:  its name
    796  *
    797  * Deallocate the memory used by an entities in the hash table.
    798  */
    799 static void
    800 xmlFreeEntityWrapper(xmlEntityPtr entity,
    801 	               const xmlChar *name ATTRIBUTE_UNUSED) {
    802     if (entity != NULL)
    803 	xmlFreeEntity(entity);
    804 }
    805 
    806 /**
    807  * xmlFreeEntitiesTable:
    808  * @table:  An entity table
    809  *
    810  * Deallocate the memory used by an entities hash table.
    811  */
    812 void
    813 xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
    814     xmlHashFree(table, (xmlHashDeallocator) xmlFreeEntityWrapper);
    815 }
    816 
    817 #ifdef LIBXML_TREE_ENABLED
    818 /**
    819  * xmlCopyEntity:
    820  * @ent:  An entity
    821  *
    822  * Build a copy of an entity
    823  *
    824  * Returns the new xmlEntitiesPtr or NULL in case of error.
    825  */
    826 static xmlEntityPtr
    827 xmlCopyEntity(xmlEntityPtr ent) {
    828     xmlEntityPtr cur;
    829 
    830     cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
    831     if (cur == NULL) {
    832         xmlEntitiesErrMemory("xmlCopyEntity:: malloc failed");
    833 	return(NULL);
    834     }
    835     memset(cur, 0, sizeof(xmlEntity));
    836     cur->type = XML_ENTITY_DECL;
    837 
    838     cur->etype = ent->etype;
    839     if (ent->name != NULL)
    840 	cur->name = xmlStrdup(ent->name);
    841     if (ent->ExternalID != NULL)
    842 	cur->ExternalID = xmlStrdup(ent->ExternalID);
    843     if (ent->SystemID != NULL)
    844 	cur->SystemID = xmlStrdup(ent->SystemID);
    845     if (ent->content != NULL)
    846 	cur->content = xmlStrdup(ent->content);
    847     if (ent->orig != NULL)
    848 	cur->orig = xmlStrdup(ent->orig);
    849     if (ent->URI != NULL)
    850 	cur->URI = xmlStrdup(ent->URI);
    851     return(cur);
    852 }
    853 
    854 /**
    855  * xmlCopyEntitiesTable:
    856  * @table:  An entity table
    857  *
    858  * Build a copy of an entity table.
    859  *
    860  * Returns the new xmlEntitiesTablePtr or NULL in case of error.
    861  */
    862 xmlEntitiesTablePtr
    863 xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
    864     return(xmlHashCopy(table, (xmlHashCopier) xmlCopyEntity));
    865 }
    866 #endif /* LIBXML_TREE_ENABLED */
    867 
    868 #ifdef LIBXML_OUTPUT_ENABLED
    869 
    870 /**
    871  * xmlDumpEntityContent:
    872  * @buf:  An XML buffer.
    873  * @content:  The entity content.
    874  *
    875  * This will dump the quoted string value, taking care of the special
    876  * treatment required by %
    877  */
    878 static void
    879 xmlDumpEntityContent(xmlBufferPtr buf, const xmlChar *content) {
    880     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
    881     if (xmlStrchr(content, '%')) {
    882         const xmlChar * base, *cur;
    883 
    884 	xmlBufferCCat(buf, "\"");
    885 	base = cur = content;
    886 	while (*cur != 0) {
    887 	    if (*cur == '"') {
    888 		if (base != cur)
    889 		    xmlBufferAdd(buf, base, cur - base);
    890 		xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
    891 		cur++;
    892 		base = cur;
    893 	    } else if (*cur == '%') {
    894 		if (base != cur)
    895 		    xmlBufferAdd(buf, base, cur - base);
    896 		xmlBufferAdd(buf, BAD_CAST "&#x25;", 6);
    897 		cur++;
    898 		base = cur;
    899 	    } else {
    900 		cur++;
    901 	    }
    902 	}
    903 	if (base != cur)
    904 	    xmlBufferAdd(buf, base, cur - base);
    905 	xmlBufferCCat(buf, "\"");
    906     } else {
    907         xmlBufferWriteQuotedString(buf, content);
    908     }
    909 }
    910 
    911 /**
    912  * xmlDumpEntityDecl:
    913  * @buf:  An XML buffer.
    914  * @ent:  An entity table
    915  *
    916  * This will dump the content of the entity table as an XML DTD definition
    917  */
    918 void
    919 xmlDumpEntityDecl(xmlBufferPtr buf, xmlEntityPtr ent) {
    920     if ((buf == NULL) || (ent == NULL)) return;
    921     switch (ent->etype) {
    922 	case XML_INTERNAL_GENERAL_ENTITY:
    923 	    xmlBufferWriteChar(buf, "<!ENTITY ");
    924 	    xmlBufferWriteCHAR(buf, ent->name);
    925 	    xmlBufferWriteChar(buf, " ");
    926 	    if (ent->orig != NULL)
    927 		xmlBufferWriteQuotedString(buf, ent->orig);
    928 	    else
    929 		xmlDumpEntityContent(buf, ent->content);
    930 	    xmlBufferWriteChar(buf, ">\n");
    931 	    break;
    932 	case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
    933 	    xmlBufferWriteChar(buf, "<!ENTITY ");
    934 	    xmlBufferWriteCHAR(buf, ent->name);
    935 	    if (ent->ExternalID != NULL) {
    936 		 xmlBufferWriteChar(buf, " PUBLIC ");
    937 		 xmlBufferWriteQuotedString(buf, ent->ExternalID);
    938 		 xmlBufferWriteChar(buf, " ");
    939 		 xmlBufferWriteQuotedString(buf, ent->SystemID);
    940 	    } else {
    941 		 xmlBufferWriteChar(buf, " SYSTEM ");
    942 		 xmlBufferWriteQuotedString(buf, ent->SystemID);
    943 	    }
    944 	    xmlBufferWriteChar(buf, ">\n");
    945 	    break;
    946 	case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
    947 	    xmlBufferWriteChar(buf, "<!ENTITY ");
    948 	    xmlBufferWriteCHAR(buf, ent->name);
    949 	    if (ent->ExternalID != NULL) {
    950 		 xmlBufferWriteChar(buf, " PUBLIC ");
    951 		 xmlBufferWriteQuotedString(buf, ent->ExternalID);
    952 		 xmlBufferWriteChar(buf, " ");
    953 		 xmlBufferWriteQuotedString(buf, ent->SystemID);
    954 	    } else {
    955 		 xmlBufferWriteChar(buf, " SYSTEM ");
    956 		 xmlBufferWriteQuotedString(buf, ent->SystemID);
    957 	    }
    958 	    if (ent->content != NULL) { /* Should be true ! */
    959 		xmlBufferWriteChar(buf, " NDATA ");
    960 		if (ent->orig != NULL)
    961 		    xmlBufferWriteCHAR(buf, ent->orig);
    962 		else
    963 		    xmlBufferWriteCHAR(buf, ent->content);
    964 	    }
    965 	    xmlBufferWriteChar(buf, ">\n");
    966 	    break;
    967 	case XML_INTERNAL_PARAMETER_ENTITY:
    968 	    xmlBufferWriteChar(buf, "<!ENTITY % ");
    969 	    xmlBufferWriteCHAR(buf, ent->name);
    970 	    xmlBufferWriteChar(buf, " ");
    971 	    if (ent->orig == NULL)
    972 		xmlDumpEntityContent(buf, ent->content);
    973 	    else
    974 		xmlBufferWriteQuotedString(buf, ent->orig);
    975 	    xmlBufferWriteChar(buf, ">\n");
    976 	    break;
    977 	case XML_EXTERNAL_PARAMETER_ENTITY:
    978 	    xmlBufferWriteChar(buf, "<!ENTITY % ");
    979 	    xmlBufferWriteCHAR(buf, ent->name);
    980 	    if (ent->ExternalID != NULL) {
    981 		 xmlBufferWriteChar(buf, " PUBLIC ");
    982 		 xmlBufferWriteQuotedString(buf, ent->ExternalID);
    983 		 xmlBufferWriteChar(buf, " ");
    984 		 xmlBufferWriteQuotedString(buf, ent->SystemID);
    985 	    } else {
    986 		 xmlBufferWriteChar(buf, " SYSTEM ");
    987 		 xmlBufferWriteQuotedString(buf, ent->SystemID);
    988 	    }
    989 	    xmlBufferWriteChar(buf, ">\n");
    990 	    break;
    991 	default:
    992 	    xmlEntitiesErr(XML_DTD_UNKNOWN_ENTITY,
    993 		"xmlDumpEntitiesDecl: internal: unknown type entity type");
    994     }
    995 }
    996 
    997 /**
    998  * xmlDumpEntityDeclScan:
    999  * @ent:  An entity table
   1000  * @buf:  An XML buffer.
   1001  *
   1002  * When using the hash table scan function, arguments need to be reversed
   1003  */
   1004 static void
   1005 xmlDumpEntityDeclScan(xmlEntityPtr ent, xmlBufferPtr buf) {
   1006     xmlDumpEntityDecl(buf, ent);
   1007 }
   1008 
   1009 /**
   1010  * xmlDumpEntitiesTable:
   1011  * @buf:  An XML buffer.
   1012  * @table:  An entity table
   1013  *
   1014  * This will dump the content of the entity table as an XML DTD definition
   1015  */
   1016 void
   1017 xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
   1018     xmlHashScan(table, (xmlHashScanner)xmlDumpEntityDeclScan, buf);
   1019 }
   1020 #endif /* LIBXML_OUTPUT_ENABLED */
   1021 #define bottom_entities
   1022 #include "elfgcchack.h"
   1023