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