Annotation of XML/entities.c, revision 1.48

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

Webmaster