Annotation of XML/entities.c, revision 1.51

1.1       httpng      1: /*
                      2:  * entities.c : implementation for the XML entities handking
1.9       veillard    3:  *
                      4:  * See Copyright for the status of this software.
                      5:  *
1.23      daniel      6:  * Daniel.Veillard@w3.org
1.1       httpng      7:  */
                      8: 
1.42      daniel      9: #ifdef WIN32
                     10: #include "win32config.h"
                     11: #else
1.37      daniel     12: #include "config.h"
                     13: #endif
                     14: 
1.1       httpng     15: #include <stdio.h>
1.37      daniel     16: #include <string.h>
                     17: #ifdef HAVE_STDLIB_H
1.17      daniel     18: #include <stdlib.h>
1.37      daniel     19: #endif
1.36      daniel     20: #include "xmlmemory.h"
1.1       httpng     21: #include "entities.h"
1.41      daniel     22: #include "parser.h"
1.1       httpng     23: 
                     24: /*
1.15      daniel     25:  * The XML predefined entities.
                     26:  */
                     27: 
                     28: struct xmlPredefinedEntityValue {
                     29:     const char *name;
                     30:     const char *value;
                     31: };
                     32: struct xmlPredefinedEntityValue xmlPredefinedEntityValues[] = {
                     33:     { "lt", "<" },
                     34:     { "gt", ">" },
                     35:     { "apos", "'" },
                     36:     { "quot", "\"" },
                     37:     { "amp", "&" }
                     38: };
                     39: 
                     40: xmlEntitiesTablePtr xmlPredefinedEntities = NULL;
                     41: 
                     42: /*
1.2       httpng     43:  * xmlFreeEntity : clean-up an entity record.
1.1       httpng     44:  */
1.2       httpng     45: void xmlFreeEntity(xmlEntityPtr entity) {
                     46:     if (entity == NULL) return;
                     47: 
1.11      daniel     48:     if (entity->name != NULL)
1.36      daniel     49:        xmlFree((char *) entity->name);
1.14      daniel     50:     if (entity->ExternalID != NULL)
1.36      daniel     51:         xmlFree((char *) entity->ExternalID);
1.14      daniel     52:     if (entity->SystemID != NULL)
1.36      daniel     53:         xmlFree((char *) entity->SystemID);
1.14      daniel     54:     if (entity->content != NULL)
1.36      daniel     55:         xmlFree((char *) entity->content);
1.27      daniel     56:     if (entity->orig != NULL)
1.36      daniel     57:         xmlFree((char *) entity->orig);
1.14      daniel     58:     memset(entity, -1, sizeof(xmlEntity));
1.51    ! daniel     59:     xmlFree(entity);
1.2       httpng     60: }
1.1       httpng     61: 
                     62: /*
1.22      daniel     63:  * xmlAddEntity : register a new entity for an entities table.
1.1       httpng     64:  */
1.51    ! daniel     65: static xmlEntityPtr
1.38      daniel     66: xmlAddEntity(xmlEntitiesTablePtr table, const xmlChar *name, int type,
                     67:          const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) {
1.2       httpng     68:     int i;
1.51    ! daniel     69:     xmlEntityPtr ret;
1.1       httpng     70: 
1.2       httpng     71:     for (i = 0;i < table->nb_entities;i++) {
1.51    ! daniel     72:         ret = table->table[i];
        !            73:        if (!xmlStrcmp(ret->name, name)) {
1.13      daniel     74:            /*
                     75:             * The entity is already defined in this Dtd, the spec says to NOT
                     76:             * override it ... Is it worth a Warning ??? !!!
1.33      daniel     77:             * Not having a cprinting context this seems hard ...
1.13      daniel     78:             */
1.30      daniel     79:            if (((type == XML_INTERNAL_PARAMETER_ENTITY) ||
                     80:                 (type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
1.51    ! daniel     81:                ((ret->etype == XML_INTERNAL_PARAMETER_ENTITY) ||
        !            82:                 (ret->etype == XML_EXTERNAL_PARAMETER_ENTITY)))
        !            83:                return(NULL);
1.30      daniel     84:            else
                     85:            if (((type != XML_INTERNAL_PARAMETER_ENTITY) &&
                     86:                 (type != XML_EXTERNAL_PARAMETER_ENTITY)) &&
1.51    ! daniel     87:                ((ret->etype != XML_INTERNAL_PARAMETER_ENTITY) &&
        !            88:                 (ret->etype != XML_EXTERNAL_PARAMETER_ENTITY)))
        !            89:                return(NULL);
1.7       veillard   90:        }
1.2       httpng     91:     }
                     92:     if (table->nb_entities >= table->max_entities) {
                     93:         /*
                     94:         * need more elements.
                     95:         */
                     96:        table->max_entities *= 2;
1.51    ! daniel     97:        table->table = (xmlEntityPtr *) 
        !            98:            xmlRealloc(table->table,
        !            99:                       table->max_entities * sizeof(xmlEntityPtr));
1.29      daniel    100:        if (table->table == NULL) {
1.2       httpng    101:            perror("realloc failed");
1.51    ! daniel    102:            return(NULL);
1.2       httpng    103:        }
                    104:     }
1.51    ! daniel    105:     ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
        !           106:     if (ret == NULL) {
        !           107:        fprintf(stderr, "xmlAddEntity: out of memory\n");
        !           108:        return(NULL);
        !           109:     }
        !           110:     memset(ret, 0, sizeof(xmlEntity));
        !           111:     ret->type = XML_ENTITY_DECL;
        !           112:     table->table[table->nb_entities] = ret;
        !           113: 
        !           114:     /*
        !           115:      * fill the structure.
        !           116:      */
        !           117:     ret->name = xmlStrdup(name);
        !           118:     ret->etype = type;
1.13      daniel    119:     if (ExternalID != NULL)
1.51    ! daniel    120:        ret->ExternalID = xmlStrdup(ExternalID);
1.13      daniel    121:     if (SystemID != NULL)
1.51    ! daniel    122:        ret->SystemID = xmlStrdup(SystemID);
1.43      daniel    123:     if (content != NULL) {
1.51    ! daniel    124:         ret->length = xmlStrlen(content);
        !           125:        ret->content = xmlStrndup(content, ret->length);
1.43      daniel    126:      } else {
1.51    ! daniel    127:         ret->length = 0;
        !           128:         ret->content = NULL;
1.43      daniel    129:     }
1.51    ! daniel    130:     ret->orig = NULL;
1.2       httpng    131:     table->nb_entities++;
1.51    ! daniel    132: 
        !           133:     return(ret);
1.2       httpng    134: }
1.1       httpng    135: 
1.22      daniel    136: /**
                    137:  * xmlInitializePredefinedEntities:
                    138:  *
                    139:  * Set up the predefined entities.
1.15      daniel    140:  */
                    141: void xmlInitializePredefinedEntities(void) {
                    142:     int i;
1.38      daniel    143:     xmlChar name[50];
                    144:     xmlChar value[50];
1.15      daniel    145:     const char *in;
1.38      daniel    146:     xmlChar *out;
1.15      daniel    147: 
                    148:     if (xmlPredefinedEntities != NULL) return;
                    149: 
                    150:     xmlPredefinedEntities = xmlCreateEntitiesTable();
                    151:     for (i = 0;i < sizeof(xmlPredefinedEntityValues) / 
                    152:                    sizeof(xmlPredefinedEntityValues[0]);i++) {
                    153:         in = xmlPredefinedEntityValues[i].name;
                    154:        out = &name[0];
1.38      daniel    155:        for (;(*out++ = (xmlChar) *in);)in++;
1.15      daniel    156:         in = xmlPredefinedEntityValues[i].value;
                    157:        out = &value[0];
1.38      daniel    158:        for (;(*out++ = (xmlChar) *in);)in++;
                    159:         xmlAddEntity(xmlPredefinedEntities, (const xmlChar *) &name[0],
1.18      daniel    160:                     XML_INTERNAL_PREDEFINED_ENTITY, NULL, NULL,
1.15      daniel    161:                     &value[0]);
                    162:     }
                    163: }
1.17      daniel    164: 
                    165: /**
1.40      daniel    166:  * xmlCleanupPredefinedEntities:
                    167:  *
                    168:  * Cleanup up the predefined entities table.
                    169:  */
                    170: void xmlCleanupPredefinedEntities(void) {
                    171:     if (xmlPredefinedEntities == NULL) return;
                    172: 
                    173:     xmlFreeEntitiesTable(xmlPredefinedEntities);
                    174:     xmlPredefinedEntities = NULL;
                    175: }
                    176: 
                    177: /**
1.17      daniel    178:  * xmlGetPredefinedEntity:
                    179:  * @name:  the entity name
                    180:  *
                    181:  * Check whether this name is an predefined entity.
                    182:  *
1.24      daniel    183:  * Returns NULL if not, othervise the entity
1.17      daniel    184:  */
                    185: xmlEntityPtr
1.38      daniel    186: xmlGetPredefinedEntity(const xmlChar *name) {
1.17      daniel    187:     int i;
                    188:     xmlEntityPtr cur;
                    189: 
                    190:     if (xmlPredefinedEntities == NULL)
                    191:         xmlInitializePredefinedEntities();
                    192:     for (i = 0;i < xmlPredefinedEntities->nb_entities;i++) {
1.51    ! daniel    193:        cur = xmlPredefinedEntities->table[i];
1.17      daniel    194:        if (!xmlStrcmp(cur->name, name)) return(cur);
                    195:     }
                    196:     return(NULL);
                    197: }
                    198: 
1.22      daniel    199: /**
                    200:  * xmlAddDtdEntity:
                    201:  * @doc:  the document
                    202:  * @name:  the entity name
                    203:  * @type:  the entity type XML_xxx_yyy_ENTITY
                    204:  * @ExternalID:  the entity external ID if available
                    205:  * @SystemID:  the entity system ID if available
                    206:  * @content:  the entity content
                    207:  *
1.51    ! daniel    208:  * Register a new entity for this document DTD external subset.
        !           209:  *
        !           210:  * Returns a pointer to the entity or NULL in case of error
1.1       httpng    211:  */
1.51    ! daniel    212: xmlEntityPtr
1.38      daniel    213: xmlAddDtdEntity(xmlDocPtr doc, const xmlChar *name, int type,
1.51    ! daniel    214:                const xmlChar *ExternalID, const xmlChar *SystemID,
        !           215:                const xmlChar *content) {
1.2       httpng    216:     xmlEntitiesTablePtr table;
1.51    ! daniel    217:     xmlEntityPtr ret;
        !           218:     xmlDtdPtr dtd;
1.1       httpng    219: 
1.51    ! daniel    220:     if (doc == NULL) {
        !           221:         fprintf(stderr,
        !           222:                "xmlAddDtdEntity: doc == NULL !\n");
        !           223:        return(NULL);
        !           224:     }
1.22      daniel    225:     if (doc->extSubset == NULL) {
                    226:         fprintf(stderr,
                    227:                "xmlAddDtdEntity: document without external subset !\n");
1.51    ! daniel    228:        return(NULL);
1.16      daniel    229:     }
1.51    ! daniel    230:     dtd = doc->extSubset;
        !           231:     table = (xmlEntitiesTablePtr) dtd->entities;
1.2       httpng    232:     if (table == NULL) {
                    233:         table = xmlCreateEntitiesTable();
1.51    ! daniel    234:        dtd->entities = table;
1.1       httpng    235:     }
1.51    ! daniel    236:     ret = xmlAddEntity(table, name, type, ExternalID, SystemID, content);
        !           237:     if (ret == NULL) return(NULL);
        !           238: 
        !           239:     /*
        !           240:      * Link it to the Dtd
        !           241:      */
        !           242:     ret->parent = dtd;
        !           243:     ret->doc = dtd->doc;
        !           244:     if (dtd->last == NULL) {
        !           245:        dtd->children = dtd->last = (xmlNodePtr) ret;
        !           246:     } else {
        !           247:         dtd->last->next = (xmlNodePtr) ret;
        !           248:        ret->prev = dtd->last;
        !           249:        dtd->last = (xmlNodePtr) ret;
        !           250:     }
        !           251:     return(ret);
1.1       httpng    252: }
                    253: 
1.22      daniel    254: /**
                    255:  * xmlAddDocEntity:
                    256:  * @doc:  the document
                    257:  * @name:  the entity name
                    258:  * @type:  the entity type XML_xxx_yyy_ENTITY
                    259:  * @ExternalID:  the entity external ID if available
                    260:  * @SystemID:  the entity system ID if available
                    261:  * @content:  the entity content
                    262:  *
                    263:  * Register a new entity for this document.
1.51    ! daniel    264:  *
        !           265:  * Returns a pointer to the entity or NULL in case of error
1.1       httpng    266:  */
1.51    ! daniel    267: xmlEntityPtr
1.38      daniel    268: xmlAddDocEntity(xmlDocPtr doc, const xmlChar *name, int type,
1.51    ! daniel    269:                const xmlChar *ExternalID, const xmlChar *SystemID,
        !           270:                const xmlChar *content) {
1.16      daniel    271:     xmlEntitiesTablePtr table;
1.51    ! daniel    272:     xmlEntityPtr ret;
        !           273:     xmlDtdPtr dtd;
1.16      daniel    274: 
1.22      daniel    275:     if (doc == NULL) {
                    276:         fprintf(stderr,
                    277:                "xmlAddDocEntity: document is NULL !\n");
1.51    ! daniel    278:        return(NULL);
1.22      daniel    279:     }
                    280:     if (doc->intSubset == NULL) {
                    281:         fprintf(stderr,
                    282:                "xmlAddDtdEntity: document without internal subset !\n");
1.51    ! daniel    283:        return(NULL);
1.22      daniel    284:     }
1.51    ! daniel    285:     dtd = doc->intSubset;
1.22      daniel    286:     table = (xmlEntitiesTablePtr) doc->intSubset->entities;
1.16      daniel    287:     if (table == NULL) {
                    288:         table = xmlCreateEntitiesTable();
1.22      daniel    289:        doc->intSubset->entities = table;
1.2       httpng    290:     }
1.51    ! daniel    291:     ret = xmlAddEntity(table, name, type, ExternalID, SystemID, content);
        !           292:     if (ret == NULL) return(NULL);
        !           293: 
        !           294:     /*
        !           295:      * Link it to the Dtd
        !           296:      */
        !           297:     ret->parent = dtd;
        !           298:     ret->doc = dtd->doc;
        !           299:     if (dtd->last == NULL) {
        !           300:        dtd->children = dtd->last = (xmlNodePtr) ret;
        !           301:     } else {
        !           302:        dtd->last->next = (xmlNodePtr) ret;
        !           303:        ret->prev = dtd->last;
        !           304:        dtd->last = (xmlNodePtr) ret;
        !           305:     }
        !           306:     return(ret);
1.1       httpng    307: }
                    308: 
1.22      daniel    309: /**
1.30      daniel    310:  * xmlGetParameterEntity:
                    311:  * @doc:  the document referencing the entity
                    312:  * @name:  the entity name
                    313:  *
                    314:  * Do an entity lookup in the internal and external subsets and
                    315:  * returns the corresponding parameter entity, if found.
                    316:  * 
                    317:  * Returns A pointer to the entity structure or NULL if not found.
                    318:  */
                    319: xmlEntityPtr
1.38      daniel    320: xmlGetParameterEntity(xmlDocPtr doc, const xmlChar *name) {
1.30      daniel    321:     int i;
                    322:     xmlEntityPtr cur;
                    323:     xmlEntitiesTablePtr table;
                    324: 
                    325:     if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
                    326:        table = (xmlEntitiesTablePtr) doc->intSubset->entities;
                    327:        for (i = 0;i < table->nb_entities;i++) {
1.51    ! daniel    328:            cur = table->table[i];
1.49      daniel    329:            if (((cur->etype ==  XML_INTERNAL_PARAMETER_ENTITY) ||
                    330:                 (cur->etype ==  XML_EXTERNAL_PARAMETER_ENTITY)) &&
1.30      daniel    331:                (!xmlStrcmp(cur->name, name))) return(cur);
                    332:        }
                    333:     }
                    334:     if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
                    335:        table = (xmlEntitiesTablePtr) doc->extSubset->entities;
                    336:        for (i = 0;i < table->nb_entities;i++) {
1.51    ! daniel    337:            cur = table->table[i];
1.49      daniel    338:            if (((cur->etype ==  XML_INTERNAL_PARAMETER_ENTITY) ||
                    339:                 (cur->etype ==  XML_EXTERNAL_PARAMETER_ENTITY)) &&
1.30      daniel    340:                (!xmlStrcmp(cur->name, name))) return(cur);
                    341:        }
                    342:     }
1.35      daniel    343:     if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
                    344:        table = (xmlEntitiesTablePtr) doc->extSubset->entities;
                    345:        for (i = 0;i < table->nb_entities;i++) {
1.51    ! daniel    346:            cur = table->table[i];
1.49      daniel    347:            if (((cur->etype ==  XML_INTERNAL_PARAMETER_ENTITY) ||
                    348:                 (cur->etype ==  XML_EXTERNAL_PARAMETER_ENTITY)) &&
1.35      daniel    349:                (!xmlStrcmp(cur->name, name))) return(cur);
                    350:        }
                    351:     }
1.30      daniel    352:     return(NULL);
                    353: }
                    354: 
                    355: /**
1.22      daniel    356:  * xmlGetDtdEntity:
                    357:  * @doc:  the document referencing the entity
                    358:  * @name:  the entity name
                    359:  *
                    360:  * Do an entity lookup in the Dtd entity hash table and
                    361:  * returns the corresponding entity, if found.
                    362:  * 
1.24      daniel    363:  * Returns A pointer to the entity structure or NULL if not found.
1.1       httpng    364:  */
1.22      daniel    365: xmlEntityPtr
1.38      daniel    366: xmlGetDtdEntity(xmlDocPtr doc, const xmlChar *name) {
1.2       httpng    367:     int i;
                    368:     xmlEntityPtr cur;
                    369:     xmlEntitiesTablePtr table;
                    370: 
1.22      daniel    371:     if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
                    372:        table = (xmlEntitiesTablePtr) doc->extSubset->entities;
1.15      daniel    373:        for (i = 0;i < table->nb_entities;i++) {
1.51    ! daniel    374:            cur = table->table[i];
1.49      daniel    375:            if ((cur->etype !=  XML_INTERNAL_PARAMETER_ENTITY) &&
                    376:                (cur->etype !=  XML_EXTERNAL_PARAMETER_ENTITY) &&
1.30      daniel    377:                (!xmlStrcmp(cur->name, name))) return(cur);
1.15      daniel    378:        }
                    379:     }
1.7       veillard  380:     return(NULL);
1.3       httpng    381: }
                    382: 
1.22      daniel    383: /**
                    384:  * xmlGetDocEntity:
                    385:  * @doc:  the document referencing the entity
                    386:  * @name:  the entity name
                    387:  *
                    388:  * Do an entity lookup in the document entity hash table and
                    389:  * returns the corrsponding entity, otherwise a lookup is done
                    390:  * in the predefined entities too.
                    391:  * 
1.24      daniel    392:  * Returns A pointer to the entity structure or NULL if not found.
1.14      daniel    393:  */
1.22      daniel    394: xmlEntityPtr
1.38      daniel    395: xmlGetDocEntity(xmlDocPtr doc, const xmlChar *name) {
1.14      daniel    396:     int i;
1.16      daniel    397:     xmlEntityPtr cur;
1.14      daniel    398:     xmlEntitiesTablePtr table;
                    399: 
1.22      daniel    400:     if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
                    401:        table = (xmlEntitiesTablePtr) doc->intSubset->entities;
1.16      daniel    402:        for (i = 0;i < table->nb_entities;i++) {
1.51    ! daniel    403:            cur = table->table[i];
1.49      daniel    404:            if ((cur->etype !=  XML_INTERNAL_PARAMETER_ENTITY) &&
                    405:                (cur->etype !=  XML_EXTERNAL_PARAMETER_ENTITY) &&
1.30      daniel    406:                (!xmlStrcmp(cur->name, name))) return(cur);
1.16      daniel    407:        }
                    408:     }
1.34      daniel    409:     if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
                    410:        table = (xmlEntitiesTablePtr) doc->extSubset->entities;
                    411:        for (i = 0;i < table->nb_entities;i++) {
1.51    ! daniel    412:            cur = table->table[i];
1.49      daniel    413:            if ((cur->etype !=  XML_INTERNAL_PARAMETER_ENTITY) &&
                    414:                (cur->etype !=  XML_EXTERNAL_PARAMETER_ENTITY) &&
1.34      daniel    415:                (!xmlStrcmp(cur->name, name))) return(cur);
                    416:        }
                    417:     }
1.15      daniel    418:     if (xmlPredefinedEntities == NULL)
                    419:         xmlInitializePredefinedEntities();
1.16      daniel    420:     table = xmlPredefinedEntities;
                    421:     for (i = 0;i < table->nb_entities;i++) {
1.51    ! daniel    422:        cur = table->table[i];
1.49      daniel    423:        if ((cur->etype !=  XML_INTERNAL_PARAMETER_ENTITY) &&
                    424:            (cur->etype !=  XML_EXTERNAL_PARAMETER_ENTITY) &&
1.30      daniel    425:            (!xmlStrcmp(cur->name, name))) return(cur);
1.14      daniel    426:     }
                    427: 
                    428:     return(NULL);
1.1       httpng    429: }
                    430: 
                    431: /*
1.21      daniel    432:  * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
                    433:  *                  | [#x10000-#x10FFFF]
                    434:  * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
                    435:  */
                    436: #define IS_CHAR(c)                                                     \
                    437:     (((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) ||                        \
                    438:      (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF)))
                    439: 
1.28      daniel    440: /*
                    441:  * A buffer used for converting entities to their equivalent and back.
                    442:  */
                    443: static int buffer_size = 0;
1.38      daniel    444: static xmlChar *buffer = NULL;
1.28      daniel    445: 
1.44      daniel    446: int growBuffer(void) {
1.28      daniel    447:     buffer_size *= 2;
1.38      daniel    448:     buffer = (xmlChar *) xmlRealloc(buffer, buffer_size * sizeof(xmlChar));
1.28      daniel    449:     if (buffer == NULL) {
                    450:         perror("realloc failed");
1.44      daniel    451:        return(-1);
1.28      daniel    452:     }
1.44      daniel    453:     return(0);
1.28      daniel    454: }
                    455: 
                    456: 
1.22      daniel    457: /**
                    458:  * xmlEncodeEntities:
                    459:  * @doc:  the document containing the string
                    460:  * @input:  A string to convert to XML.
                    461:  *
                    462:  * Do a global encoding of a string, replacing the predefined entities
                    463:  * and non ASCII values with their entities and CharRef counterparts.
                    464:  *
1.33      daniel    465:  * TODO: remove xmlEncodeEntities, once we are not afraid of breaking binary
                    466:  *       compatibility
1.28      daniel    467:  *
                    468:  * People must migrate their code to xmlEncodeEntitiesReentrant !
1.31      daniel    469:  * This routine will issue a warning when encountered.
1.28      daniel    470:  * 
                    471:  * Returns A newly allocated string with the substitution done.
                    472:  */
1.38      daniel    473: const xmlChar *
                    474: xmlEncodeEntities(xmlDocPtr doc, const xmlChar *input) {
                    475:     const xmlChar *cur = input;
                    476:     xmlChar *out = buffer;
1.31      daniel    477:     static int warning = 1;
1.39      daniel    478:     int html = 0;
                    479: 
1.31      daniel    480: 
                    481:     if (warning) {
                    482:     fprintf(stderr, "Deprecated API xmlEncodeEntities() used\n");
                    483:     fprintf(stderr, "   change code to use xmlEncodeEntitiesReentrant()\n");
                    484:     warning = 0;
                    485:     }
1.28      daniel    486: 
                    487:     if (input == NULL) return(NULL);
1.39      daniel    488:     if (doc != NULL)
                    489:         html = (doc->type == XML_HTML_DOCUMENT_NODE);
                    490: 
1.28      daniel    491:     if (buffer == NULL) {
                    492:         buffer_size = 1000;
1.38      daniel    493:         buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
1.28      daniel    494:        if (buffer == NULL) {
                    495:            perror("malloc failed");
1.44      daniel    496:             return(NULL);
1.28      daniel    497:        }
                    498:        out = buffer;
                    499:     }
                    500:     while (*cur != '\0') {
                    501:         if (out - buffer > buffer_size - 100) {
                    502:            int index = out - buffer;
                    503: 
                    504:            growBuffer();
                    505:            out = &buffer[index];
                    506:        }
                    507: 
                    508:        /*
                    509:         * By default one have to encode at least '<', '>', '"' and '&' !
                    510:         */
                    511:        if (*cur == '<') {
                    512:            *out++ = '&';
                    513:            *out++ = 'l';
                    514:            *out++ = 't';
                    515:            *out++ = ';';
                    516:        } else if (*cur == '>') {
                    517:            *out++ = '&';
                    518:            *out++ = 'g';
                    519:            *out++ = 't';
                    520:            *out++ = ';';
                    521:        } else if (*cur == '&') {
                    522:            *out++ = '&';
                    523:            *out++ = 'a';
                    524:            *out++ = 'm';
                    525:            *out++ = 'p';
                    526:            *out++ = ';';
                    527:        } else if (*cur == '"') {
                    528:            *out++ = '&';
                    529:            *out++ = 'q';
                    530:            *out++ = 'u';
                    531:            *out++ = 'o';
                    532:            *out++ = 't';
                    533:            *out++ = ';';
1.39      daniel    534:        } else if ((*cur == '\'') && (!html)) {
1.28      daniel    535:            *out++ = '&';
                    536:            *out++ = 'a';
                    537:            *out++ = 'p';
                    538:            *out++ = 'o';
                    539:            *out++ = 's';
                    540:            *out++ = ';';
                    541:        } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
                    542:            (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
                    543:            /*
                    544:             * default case, just copy !
                    545:             */
                    546:            *out++ = *cur;
                    547: #ifndef USE_UTF_8
1.38      daniel    548:        } else if ((sizeof(xmlChar) == 1) && (*cur >= 0x80)) {
1.28      daniel    549:            char buf[10], *ptr;
                    550: #ifdef HAVE_SNPRINTF
                    551:            snprintf(buf, 9, "&#%d;", *cur);
                    552: #else
                    553:            sprintf(buf, "&#%d;", *cur);
                    554: #endif
                    555:             ptr = buf;
                    556:            while (*ptr != 0) *out++ = *ptr++;
                    557: #endif
                    558:        } else if (IS_CHAR(*cur)) {
                    559:            char buf[10], *ptr;
                    560: 
                    561: #ifdef HAVE_SNPRINTF
                    562:            snprintf(buf, 9, "&#%d;", *cur);
                    563: #else
                    564:            sprintf(buf, "&#%d;", *cur);
                    565: #endif
                    566:             ptr = buf;
                    567:            while (*ptr != 0) *out++ = *ptr++;
                    568:        }
                    569: #if 0
                    570:        else {
                    571:            /*
                    572:             * default case, this is not a valid char !
                    573:             * Skip it...
                    574:             */
                    575:            fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
                    576:        }
                    577: #endif
                    578:        cur++;
                    579:     }
                    580:     *out++ = 0;
                    581:     return(buffer);
                    582: }
                    583: 
                    584: /*
                    585:  * Macro used to grow the current buffer.
                    586:  */
                    587: #define growBufferReentrant() {                                                \
                    588:     buffer_size *= 2;                                                  \
1.44      daniel    589:     buffer = (xmlChar *)                                               \
                    590:                xmlRealloc(buffer, buffer_size * sizeof(xmlChar));      \
1.28      daniel    591:     if (buffer == NULL) {                                              \
                    592:        perror("realloc failed");                                       \
1.44      daniel    593:        return(NULL);                                                   \
1.28      daniel    594:     }                                                                  \
                    595: }
                    596: 
                    597: 
                    598: /**
                    599:  * xmlEncodeEntitiesReentrant:
                    600:  * @doc:  the document containing the string
                    601:  * @input:  A string to convert to XML.
                    602:  *
                    603:  * Do a global encoding of a string, replacing the predefined entities
                    604:  * and non ASCII values with their entities and CharRef counterparts.
                    605:  * Contrary to xmlEncodeEntities, this routine is reentrant, and result
                    606:  * must be deallocated.
                    607:  *
                    608:  * TODO !!!! Once moved to UTF-8 internal encoding, the encoding of non-ascii
                    609:  *           get erroneous.
                    610:  *
1.24      daniel    611:  * Returns A newly allocated string with the substitution done.
1.1       httpng    612:  */
1.38      daniel    613: xmlChar *
                    614: xmlEncodeEntitiesReentrant(xmlDocPtr doc, const xmlChar *input) {
                    615:     const xmlChar *cur = input;
                    616:     xmlChar *buffer = NULL;
                    617:     xmlChar *out = NULL;
1.26      daniel    618:     int buffer_size = 0;
1.39      daniel    619:     int html = 0;
1.3       httpng    620: 
1.19      daniel    621:     if (input == NULL) return(NULL);
1.39      daniel    622:     if (doc != NULL)
                    623:         html = (doc->type == XML_HTML_DOCUMENT_NODE);
1.26      daniel    624: 
                    625:     /*
                    626:      * allocate an translation buffer.
                    627:      */
                    628:     buffer_size = 1000;
1.38      daniel    629:     buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
1.3       httpng    630:     if (buffer == NULL) {
1.26      daniel    631:        perror("malloc failed");
1.44      daniel    632:        return(NULL);
1.3       httpng    633:     }
1.26      daniel    634:     out = buffer;
                    635: 
1.6       veillard  636:     while (*cur != '\0') {
                    637:         if (out - buffer > buffer_size - 100) {
                    638:            int index = out - buffer;
                    639: 
1.28      daniel    640:            growBufferReentrant();
1.6       veillard  641:            out = &buffer[index];
                    642:        }
                    643: 
                    644:        /*
1.7       veillard  645:         * By default one have to encode at least '<', '>', '"' and '&' !
1.6       veillard  646:         */
                    647:        if (*cur == '<') {
                    648:            *out++ = '&';
                    649:            *out++ = 'l';
                    650:            *out++ = 't';
                    651:            *out++ = ';';
1.7       veillard  652:        } else if (*cur == '>') {
                    653:            *out++ = '&';
                    654:            *out++ = 'g';
                    655:            *out++ = 't';
                    656:            *out++ = ';';
1.6       veillard  657:        } else if (*cur == '&') {
                    658:            *out++ = '&';
                    659:            *out++ = 'a';
                    660:            *out++ = 'm';
                    661:            *out++ = 'p';
1.7       veillard  662:            *out++ = ';';
                    663:        } else if (*cur == '"') {
                    664:            *out++ = '&';
                    665:            *out++ = 'q';
                    666:            *out++ = 'u';
                    667:            *out++ = 'o';
                    668:            *out++ = 't';
                    669:            *out++ = ';';
1.39      daniel    670:        } else if ((*cur == '\'') && (!html)) {
1.7       veillard  671:            *out++ = '&';
                    672:            *out++ = 'a';
                    673:            *out++ = 'p';
                    674:            *out++ = 'o';
                    675:            *out++ = 's';
1.6       veillard  676:            *out++ = ';';
1.21      daniel    677:        } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
                    678:            (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
                    679:            /*
                    680:             * default case, just copy !
                    681:             */
                    682:            *out++ = *cur;
1.46      daniel    683:        } else if (*cur >= 0x80) {
                    684:            if (html) {
1.50      daniel    685:                char buf[15], *ptr;
1.46      daniel    686: 
                    687:                /*
                    688:                 * TODO: improve by searching in html40EntitiesTable
                    689:                 */
1.19      daniel    690: #ifdef HAVE_SNPRINTF
1.45      daniel    691:                snprintf(buf, 9, "&#%d;", *cur);
1.19      daniel    692: #else
1.45      daniel    693:                sprintf(buf, "&#%d;", *cur);
1.19      daniel    694: #endif
1.45      daniel    695:                ptr = buf;
                    696:                while (*ptr != 0) *out++ = *ptr++;
1.46      daniel    697:            } else if (doc->encoding != NULL) {
                    698:                /*
                    699:                 * TODO !!!
                    700:                 */
                    701:                *out++ = *cur;
                    702:            } else {
                    703:                /*
                    704:                 * We assume we have UTF-8 input.
                    705:                 */
                    706:                char buf[10], *ptr;
1.48      daniel    707:                int val = 0, l = 1;
1.46      daniel    708: 
                    709:                if (*cur < 0xC0) {
                    710:                    fprintf(stderr,
                    711:                            "xmlEncodeEntitiesReentrant : input not UTF-8\n");
                    712:                    doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
                    713: #ifdef HAVE_SNPRINTF
                    714:                    snprintf(buf, 9, "&#%d;", *cur);
                    715: #else
                    716:                    sprintf(buf, "&#%d;", *cur);
                    717: #endif
                    718:                    ptr = buf;
                    719:                    while (*ptr != 0) *out++ = *ptr++;
                    720:                    continue;
                    721:                } else if (*cur < 0xE0) {
                    722:                     val = (cur[0]) & 0x1F;
                    723:                    val <<= 6;
                    724:                    val |= (cur[1]) & 0x3F;
                    725:                    l = 2;
                    726:                } else if (*cur < 0xF0) {
                    727:                     val = (cur[0]) & 0x0F;
                    728:                    val <<= 6;
                    729:                    val |= (cur[1]) & 0x3F;
                    730:                    val <<= 6;
                    731:                    val |= (cur[2]) & 0x3F;
                    732:                    l = 3;
                    733:                } else if (*cur < 0xF8) {
                    734:                     val = (cur[0]) & 0x07;
                    735:                    val <<= 6;
                    736:                    val |= (cur[1]) & 0x3F;
                    737:                    val <<= 6;
                    738:                    val |= (cur[2]) & 0x3F;
                    739:                    val <<= 6;
                    740:                    val |= (cur[3]) & 0x3F;
                    741:                    l = 4;
                    742:                }
                    743:                if ((l == 1) || (!IS_CHAR(val))) {
                    744:                    fprintf(stderr,
                    745:                        "xmlEncodeEntitiesReentrant : char out of range\n");
                    746:                    doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
                    747: #ifdef HAVE_SNPRINTF
                    748:                    snprintf(buf, 9, "&#%d;", *cur);
                    749: #else
                    750:                    sprintf(buf, "&#%d;", *cur);
                    751: #endif
                    752:                    ptr = buf;
                    753:                    while (*ptr != 0) *out++ = *ptr++;
                    754:                    cur++;
                    755:                    continue;
                    756:                }
                    757:                /*
                    758:                 * We could do multiple things here. Just save as a char ref
                    759:                 */
                    760: #ifdef HAVE_SNPRINTF
1.50      daniel    761:                snprintf(buf, 14, "&#x%X;", val);
1.46      daniel    762: #else
1.50      daniel    763:                sprintf(buf, "&#x%X;", val);
1.46      daniel    764: #endif
1.50      daniel    765:                buf[14] = 0;
1.47      daniel    766:                ptr = buf;
                    767:                while (*ptr != 0) *out++ = *ptr++;
                    768:                cur += l;
                    769:                continue;
1.45      daniel    770:            }
1.21      daniel    771:        } else if (IS_CHAR(*cur)) {
1.20      daniel    772:            char buf[10], *ptr;
                    773: 
                    774: #ifdef HAVE_SNPRINTF
                    775:            snprintf(buf, 9, "&#%d;", *cur);
                    776: #else
                    777:            sprintf(buf, "&#%d;", *cur);
                    778: #endif
                    779:             ptr = buf;
                    780:            while (*ptr != 0) *out++ = *ptr++;
1.21      daniel    781:        }
                    782: #if 0
                    783:        else {
1.6       veillard  784:            /*
1.21      daniel    785:             * default case, this is not a valid char !
                    786:             * Skip it...
1.6       veillard  787:             */
1.21      daniel    788:            fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
1.6       veillard  789:        }
1.21      daniel    790: #endif
1.6       veillard  791:        cur++;
                    792:     }
                    793:     *out++ = 0;
                    794:     return(buffer);
1.2       httpng    795: }
                    796: 
1.22      daniel    797: /**
                    798:  * xmlCreateEntitiesTable:
                    799:  *
                    800:  * create and initialize an empty entities hash table.
                    801:  *
1.24      daniel    802:  * Returns the xmlEntitiesTablePtr just created or NULL in case of error.
1.2       httpng    803:  */
1.22      daniel    804: xmlEntitiesTablePtr
                    805: xmlCreateEntitiesTable(void) {
1.2       httpng    806:     xmlEntitiesTablePtr ret;
1.1       httpng    807: 
1.2       httpng    808:     ret = (xmlEntitiesTablePtr) 
1.36      daniel    809:          xmlMalloc(sizeof(xmlEntitiesTable));
1.1       httpng    810:     if (ret == NULL) {
1.36      daniel    811:         fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
1.28      daniel    812:                (long)sizeof(xmlEntitiesTable));
1.2       httpng    813:         return(NULL);
                    814:     }
                    815:     ret->max_entities = XML_MIN_ENTITIES_TABLE;
                    816:     ret->nb_entities = 0;
1.51    ! daniel    817:     ret->table = (xmlEntityPtr *) 
        !           818:          xmlMalloc(ret->max_entities * sizeof(xmlEntityPtr));
1.2       httpng    819:     if (ret == NULL) {
1.36      daniel    820:         fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
1.51    ! daniel    821:                ret->max_entities * (long)sizeof(xmlEntityPtr));
1.36      daniel    822:        xmlFree(ret);
1.1       httpng    823:         return(NULL);
                    824:     }
                    825:     return(ret);
                    826: }
                    827: 
1.22      daniel    828: /**
                    829:  * xmlFreeEntitiesTable:
                    830:  * @table:  An entity table
                    831:  *
                    832:  * Deallocate the memory used by an entities hash table.
1.1       httpng    833:  */
1.22      daniel    834: void
                    835: xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
1.1       httpng    836:     int i;
                    837: 
                    838:     if (table == NULL) return;
                    839: 
1.2       httpng    840:     for (i = 0;i < table->nb_entities;i++) {
1.51    ! daniel    841:         xmlFreeEntity(table->table[i]);
1.1       httpng    842:     }
1.36      daniel    843:     xmlFree(table->table);
                    844:     xmlFree(table);
1.1       httpng    845: }
                    846: 
1.22      daniel    847: /**
                    848:  * xmlCopyEntitiesTable:
                    849:  * @table:  An entity table
                    850:  *
                    851:  * Build a copy of an entity table.
                    852:  * 
1.24      daniel    853:  * Returns the new xmlEntitiesTablePtr or NULL in case of error.
1.22      daniel    854:  */
                    855: xmlEntitiesTablePtr
                    856: xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
                    857:     xmlEntitiesTablePtr ret;
                    858:     xmlEntityPtr cur, ent;
                    859:     int i;
                    860: 
1.36      daniel    861:     ret = (xmlEntitiesTablePtr) xmlMalloc(sizeof(xmlEntitiesTable));
1.22      daniel    862:     if (ret == NULL) {
                    863:         fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
                    864:        return(NULL);
                    865:     }
1.51    ! daniel    866:     ret->table = (xmlEntityPtr *) xmlMalloc(table->max_entities *
        !           867:                                             sizeof(xmlEntityPtr));
1.22      daniel    868:     if (ret->table == NULL) {
                    869:         fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
1.36      daniel    870:        xmlFree(ret);
1.22      daniel    871:        return(NULL);
                    872:     }
                    873:     ret->max_entities = table->max_entities;
                    874:     ret->nb_entities = table->nb_entities;
                    875:     for (i = 0;i < ret->nb_entities;i++) {
1.51    ! daniel    876:        cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
        !           877:        if (cur == NULL) {
        !           878:            fprintf(stderr, "xmlCopyEntityTable: out of memory !\n");
        !           879:            xmlFree(ret);
        !           880:            xmlFree(ret->table);
        !           881:            return(NULL);
        !           882:        }
        !           883:        memset(cur, 0, sizeof(xmlEntity));
        !           884:        cur->type = XML_ELEMENT_DECL;
        !           885:        ret->table[i] = cur;
        !           886:        ent = table->table[i];
        !           887: 
1.49      daniel    888:        cur->etype = ent->etype;
1.22      daniel    889:        if (ent->name != NULL)
                    890:            cur->name = xmlStrdup(ent->name);
                    891:        if (ent->ExternalID != NULL)
                    892:            cur->ExternalID = xmlStrdup(ent->ExternalID);
                    893:        if (ent->SystemID != NULL)
                    894:            cur->SystemID = xmlStrdup(ent->SystemID);
                    895:        if (ent->content != NULL)
                    896:            cur->content = xmlStrdup(ent->content);
1.27      daniel    897:        if (ent->orig != NULL)
                    898:            cur->orig = xmlStrdup(ent->orig);
1.22      daniel    899:     }
                    900:     return(ret);
                    901: }
                    902: 
                    903: /**
                    904:  * xmlDumpEntitiesTable:
1.25      daniel    905:  * @buf:  An XML buffer.
1.22      daniel    906:  * @table:  An entity table
                    907:  *
                    908:  * This will dump the content of the entity table as an XML DTD definition
1.13      daniel    909:  */
1.22      daniel    910: void
1.25      daniel    911: xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
1.14      daniel    912:     int i;
                    913:     xmlEntityPtr cur;
                    914: 
                    915:     if (table == NULL) return;
                    916: 
                    917:     for (i = 0;i < table->nb_entities;i++) {
1.51    ! daniel    918:         cur = table->table[i];
1.49      daniel    919:         switch (cur->etype) {
1.14      daniel    920:            case XML_INTERNAL_GENERAL_ENTITY:
1.25      daniel    921:                xmlBufferWriteChar(buf, "<!ENTITY ");
                    922:                xmlBufferWriteCHAR(buf, cur->name);
1.27      daniel    923:                xmlBufferWriteChar(buf, " ");
                    924:                if (cur->orig != NULL)
                    925:                    xmlBufferWriteQuotedString(buf, cur->orig);
                    926:                else
                    927:                    xmlBufferWriteQuotedString(buf, cur->content);
                    928:                xmlBufferWriteChar(buf, ">\n");
1.14      daniel    929:                break;
                    930:            case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1.25      daniel    931:                xmlBufferWriteChar(buf, "<!ENTITY ");
                    932:                xmlBufferWriteCHAR(buf, cur->name);
1.14      daniel    933:                if (cur->ExternalID != NULL) {
1.27      daniel    934:                     xmlBufferWriteChar(buf, " PUBLIC ");
                    935:                     xmlBufferWriteQuotedString(buf, cur->ExternalID);
                    936:                     xmlBufferWriteChar(buf, " ");
                    937:                     xmlBufferWriteQuotedString(buf, cur->SystemID);
1.14      daniel    938:                } else {
1.27      daniel    939:                     xmlBufferWriteChar(buf, " SYSTEM ");
                    940:                     xmlBufferWriteQuotedString(buf, cur->SystemID);
1.14      daniel    941:                }
1.25      daniel    942:                xmlBufferWriteChar(buf, ">\n");
1.14      daniel    943:                break;
                    944:            case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1.25      daniel    945:                xmlBufferWriteChar(buf, "<!ENTITY ");
                    946:                xmlBufferWriteCHAR(buf, cur->name);
1.14      daniel    947:                if (cur->ExternalID != NULL) {
1.27      daniel    948:                     xmlBufferWriteChar(buf, " PUBLIC ");
                    949:                     xmlBufferWriteQuotedString(buf, cur->ExternalID);
                    950:                     xmlBufferWriteChar(buf, " ");
                    951:                     xmlBufferWriteQuotedString(buf, cur->SystemID);
1.14      daniel    952:                } else {
1.27      daniel    953:                     xmlBufferWriteChar(buf, " SYSTEM ");
                    954:                     xmlBufferWriteQuotedString(buf, cur->SystemID);
1.14      daniel    955:                }
                    956:                if (cur->content != NULL) { /* Should be true ! */
1.25      daniel    957:                    xmlBufferWriteChar(buf, " NDATA ");
1.27      daniel    958:                    if (cur->orig != NULL)
                    959:                        xmlBufferWriteCHAR(buf, cur->orig);
                    960:                    else
                    961:                        xmlBufferWriteCHAR(buf, cur->content);
1.14      daniel    962:                }
1.25      daniel    963:                xmlBufferWriteChar(buf, ">\n");
1.14      daniel    964:                break;
                    965:            case XML_INTERNAL_PARAMETER_ENTITY:
1.25      daniel    966:                xmlBufferWriteChar(buf, "<!ENTITY % ");
                    967:                xmlBufferWriteCHAR(buf, cur->name);
1.27      daniel    968:                xmlBufferWriteChar(buf, " ");
                    969:                if (cur->orig == NULL)
                    970:                    xmlBufferWriteQuotedString(buf, cur->content);
                    971:                else
                    972:                    xmlBufferWriteQuotedString(buf, cur->orig);
                    973:                xmlBufferWriteChar(buf, ">\n");
1.14      daniel    974:                break;
                    975:            case XML_EXTERNAL_PARAMETER_ENTITY:
1.25      daniel    976:                xmlBufferWriteChar(buf, "<!ENTITY % ");
                    977:                xmlBufferWriteCHAR(buf, cur->name);
1.14      daniel    978:                if (cur->ExternalID != NULL) {
1.27      daniel    979:                     xmlBufferWriteChar(buf, " PUBLIC ");
                    980:                     xmlBufferWriteQuotedString(buf, cur->ExternalID);
                    981:                     xmlBufferWriteChar(buf, " ");
                    982:                     xmlBufferWriteQuotedString(buf, cur->SystemID);
1.14      daniel    983:                } else {
1.27      daniel    984:                     xmlBufferWriteChar(buf, " SYSTEM ");
                    985:                     xmlBufferWriteQuotedString(buf, cur->SystemID);
1.14      daniel    986:                }
1.25      daniel    987:                xmlBufferWriteChar(buf, ">\n");
1.14      daniel    988:                break;
                    989:            default:
                    990:                fprintf(stderr,
                    991:                    "xmlDumpEntitiesTable: internal: unknown type %d\n",
1.49      daniel    992:                        cur->etype);
1.14      daniel    993:        }
                    994:     }
1.13      daniel    995: }

Webmaster