Annotation of embedaddon/libxml2/entities.c, revision 1.1.1.2

1.1       misho       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: 
1.1.1.2 ! misho      25: #include "save.h"
        !            26: 
1.1       misho      27: /*
                     28:  * The XML predefined entities.
                     29:  */
                     30: 
                     31: static xmlEntity xmlEntityLt = {
                     32:     NULL, XML_ENTITY_DECL, BAD_CAST "lt",
1.1.1.2 ! misho      33:     NULL, NULL, NULL, NULL, NULL, NULL,
1.1       misho      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",
1.1.1.2 ! misho      40:     NULL, NULL, NULL, NULL, NULL, NULL,
1.1       misho      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",
1.1.1.2 ! misho      47:     NULL, NULL, NULL, NULL, NULL, NULL,
1.1       misho      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",
1.1.1.2 ! misho      54:     NULL, NULL, NULL, NULL, NULL, NULL,
1.1       misho      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",
1.1.1.2 ! misho      61:     NULL, NULL, NULL, NULL, NULL, NULL,
1.1       misho      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.
1.1.1.2 ! misho     431:  *
1.1       misho     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.
1.1.1.2 ! misho     446:  *
1.1       misho     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.
1.1.1.2 ! misho     477:  *
1.1       misho     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.
1.1.1.2 ! misho     501:  *
1.1       misho     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() {                                                \
1.1.1.2 ! misho     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;                                            \
1.1       misho     540: }
                    541: 
                    542: /**
1.1.1.2 ! misho     543:  * xmlEncodeEntitiesInternal:
1.1       misho     544:  * @doc:  the document containing the string
                    545:  * @input:  A string to convert to XML.
1.1.1.2 ! misho     546:  * @attr: are we handling an atrbute value
1.1       misho     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:  */
1.1.1.2 ! misho     555: static xmlChar *
        !           556: xmlEncodeEntitiesInternal(xmlDocPtr doc, const xmlChar *input, int attr) {
1.1       misho     557:     const xmlChar *cur = input;
                    558:     xmlChar *buffer = NULL;
                    559:     xmlChar *out = NULL;
1.1.1.2 ! misho     560:     size_t buffer_size = 0;
1.1       misho     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) {
1.1.1.2 ! misho     573:         xmlEntitiesErrMemory("xmlEncodeEntities: malloc failed");
1.1       misho     574:        return(NULL);
                    575:     }
                    576:     out = buffer;
                    577: 
                    578:     while (*cur != '\0') {
1.1.1.2 ! misho     579:         size_t indx = out - buffer;
        !           580:         if (indx + 100 > buffer_size) {
1.1       misho     581: 
                    582:            growBufferReentrant();
                    583:            out = &buffer[indx];
                    584:        }
                    585: 
                    586:        /*
                    587:         * By default one have to encode at least '<', '>', '"' and '&' !
                    588:         */
                    589:        if (*cur == '<') {
1.1.1.2 ! misho     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:            }
1.1       misho     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 == '&') {
1.1.1.2 ! misho     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:            }
1.1       misho     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:                /*
1.1.1.2 ! misho     652:                 * Bjørn Reese <br@sseusa.com> provided the patch
1.1       misho     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,
1.1.1.2 ! misho     670:                            "xmlEncodeEntities: input not UTF-8");
1.1       misho     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,
1.1.1.2 ! misho     703:                        "xmlEncodeEntities: char out of range\n");
1.1       misho     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);
1.1.1.2 ! misho     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);
1.1       misho     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;
1.1.1.2 ! misho     790:     size_t buffer_size = 0;
1.1       misho     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') {
1.1.1.2 ! misho     805:         size_t indx = out - buffer;
        !           806:         if (indx + 10 > buffer_size) {
1.1       misho     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);
1.1.1.2 ! misho     855: 
        !           856: mem_error:
        !           857:     xmlEntitiesErrMemory("xmlEncodeSpecialChars: realloc failed");
        !           858:     xmlFree(buffer);
        !           859:     return(NULL);
1.1       misho     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
1.1.1.2 ! misho     906:  *
1.1       misho     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.
1.1.1.2 ! misho     942:  *
1.1       misho     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: }
1.1.1.2 ! misho    1091: 
1.1       misho    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>