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