Annotation of XML/entities.c, revision 1.53

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

Webmaster