Annotation of XML/entities.c, revision 1.49

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

Webmaster