File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / entities.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 19:53:28 2014 UTC (9 years, 11 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, HEAD
libxml2 2.9.1

    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
   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(xmlDocPtr 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(xmlDocPtr 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"

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>