Annotation of XML/entities.c, revision 1.21

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.21    ! daniel      6:  * $Id: entities.c,v 1.20 1998/11/15 05:36:36 daniel Exp $
1.1       httpng      7:  */
                      8: 
                      9: #include <stdio.h>
1.17      daniel     10: #include <stdlib.h>
1.10      daniel     11: #include <string.h>
1.1       httpng     12: #include "entities.h"
                     13: 
                     14: /*
1.15      daniel     15:  * The XML predefined entities.
                     16:  */
                     17: 
                     18: struct xmlPredefinedEntityValue {
                     19:     const char *name;
                     20:     const char *value;
                     21: };
                     22: struct xmlPredefinedEntityValue xmlPredefinedEntityValues[] = {
                     23:     { "lt", "<" },
                     24:     { "gt", ">" },
                     25:     { "apos", "'" },
                     26:     { "quot", "\"" },
                     27:     { "amp", "&" }
                     28: };
                     29: 
                     30: xmlEntitiesTablePtr xmlPredefinedEntities = NULL;
                     31: 
                     32: /*
1.3       httpng     33:  * A buffer used for converting entities to their equivalent and back.
                     34:  */
1.14      daniel     35: static int buffer_size = 0;
1.6       veillard   36: static CHAR *buffer = NULL;
1.3       httpng     37: 
                     38: void growBuffer(void) {
                     39:     buffer_size *= 2;
                     40:     buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
                     41:     if (buffer == NULL) {
                     42:        perror("realloc failed");
                     43:        exit(1);
                     44:     }
                     45: }
                     46: 
                     47: /*
1.2       httpng     48:  * xmlFreeEntity : clean-up an entity record.
1.1       httpng     49:  */
                     50: 
1.2       httpng     51: void xmlFreeEntity(xmlEntityPtr entity) {
                     52:     if (entity == NULL) return;
                     53: 
1.11      daniel     54:     if (entity->name != NULL)
                     55:        free((char *) entity->name);
1.14      daniel     56:     if (entity->ExternalID != NULL)
                     57:         free((char *) entity->ExternalID);
                     58:     if (entity->SystemID != NULL)
                     59:         free((char *) entity->SystemID);
                     60:     if (entity->content != NULL)
                     61:         free((char *) entity->content);
                     62:     memset(entity, -1, sizeof(xmlEntity));
1.2       httpng     63: }
1.1       httpng     64: 
                     65: /*
1.2       httpng     66:  * xmlAddDocEntity : register a new entity for an entities table.
1.13      daniel     67:  *
                     68:  * TODO !!! We should check here that the combination of type
                     69:  *          ExternalID and SystemID is valid.
1.1       httpng     70:  */
1.13      daniel     71: static void xmlAddEntity(xmlEntitiesTablePtr table, const CHAR *name, int type,
                     72:               const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
1.2       httpng     73:     int i;
                     74:     xmlEntityPtr cur;
1.14      daniel     75:     int len;
1.1       httpng     76: 
1.2       httpng     77:     for (i = 0;i < table->nb_entities;i++) {
                     78:         cur = &table->table[i];
1.11      daniel     79:        if (!xmlStrcmp(cur->name, name)) {
1.13      daniel     80:            /*
                     81:             * The entity is already defined in this Dtd, the spec says to NOT
                     82:             * override it ... Is it worth a Warning ??? !!!
                     83:             */
                     84:            return;
1.7       veillard   85:        }
1.2       httpng     86:     }
                     87:     if (table->nb_entities >= table->max_entities) {
                     88:         /*
                     89:         * need more elements.
                     90:         */
                     91:        table->max_entities *= 2;
                     92:        table->table = (xmlEntityPtr) 
                     93:            realloc(table->table, table->max_entities * sizeof(xmlEntity));
                     94:        if (table->table) {
                     95:            perror("realloc failed");
                     96:            exit(1);
                     97:        }
                     98:     }
                     99:     cur = &table->table[table->nb_entities];
1.11      daniel    100:     cur->name = xmlStrdup(name);
1.14      daniel    101:     for (len = 0;name[0] != 0;name++)len++;
                    102:     cur->len = len;
1.13      daniel    103:     cur->type = type;
                    104:     if (ExternalID != NULL)
                    105:        cur->ExternalID = xmlStrdup(ExternalID);
1.14      daniel    106:     else
                    107:         cur->ExternalID = NULL;
1.13      daniel    108:     if (SystemID != NULL)
1.14      daniel    109:        cur->SystemID = xmlStrdup(SystemID);
                    110:     else
                    111:         cur->SystemID = NULL;
1.13      daniel    112:     if (content != NULL)
                    113:        cur->content = xmlStrdup(content);
1.14      daniel    114:     else
                    115:         cur->content = NULL;
1.2       httpng    116:     table->nb_entities++;
                    117: }
1.1       httpng    118: 
1.15      daniel    119: /*
                    120:  * Set up xmlPredefinedEntities from xmlPredefinedEntityValues.
                    121:  */
                    122: void xmlInitializePredefinedEntities(void) {
                    123:     int i;
                    124:     CHAR name[50];
                    125:     CHAR value[50];
                    126:     const char *in;
                    127:     CHAR *out;
                    128: 
                    129:     if (xmlPredefinedEntities != NULL) return;
                    130: 
                    131:     xmlPredefinedEntities = xmlCreateEntitiesTable();
                    132:     for (i = 0;i < sizeof(xmlPredefinedEntityValues) / 
                    133:                    sizeof(xmlPredefinedEntityValues[0]);i++) {
                    134:         in = xmlPredefinedEntityValues[i].name;
                    135:        out = &name[0];
                    136:        for (;(*out++ = (CHAR) *in);)in++;
                    137:         in = xmlPredefinedEntityValues[i].value;
                    138:        out = &value[0];
                    139:        for (;(*out++ = (CHAR) *in);)in++;
                    140:         xmlAddEntity(xmlPredefinedEntities, (const CHAR *) &name[0],
1.18      daniel    141:                     XML_INTERNAL_PREDEFINED_ENTITY, NULL, NULL,
1.15      daniel    142:                     &value[0]);
                    143:     }
                    144: }
1.17      daniel    145: 
                    146: /**
                    147:  * xmlGetPredefinedEntity:
                    148:  * @name:  the entity name
                    149:  *
                    150:  * Check whether this name is an predefined entity.
                    151:  *
                    152:  * return values: NULL if not, othervise the entity
                    153:  */
                    154: xmlEntityPtr
                    155: xmlGetPredefinedEntity(const CHAR *name) {
                    156:     int i;
                    157:     xmlEntityPtr cur;
                    158: 
                    159:     if (xmlPredefinedEntities == NULL)
                    160:         xmlInitializePredefinedEntities();
                    161:     for (i = 0;i < xmlPredefinedEntities->nb_entities;i++) {
                    162:        cur = &xmlPredefinedEntities->table[i];
                    163:        if (!xmlStrcmp(cur->name, name)) return(cur);
                    164:     }
                    165:     return(NULL);
                    166: }
                    167: 
1.15      daniel    168: 
1.1       httpng    169: 
                    170: /*
1.12      daniel    171:  * xmlAddDtdEntity : register a new entity for this DTD.
1.1       httpng    172:  */
1.16      daniel    173: void xmlAddDtdEntity(xmlDocPtr doc, const CHAR *name, int type,
1.13      daniel    174:               const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
1.2       httpng    175:     xmlEntitiesTablePtr table;
1.1       httpng    176: 
1.16      daniel    177:     if (doc->dtd == NULL) {
                    178:         fprintf(stderr, "xmlAddDtdEntity: document without Dtd !\n");
                    179:        return;
                    180:     }
                    181:     table = (xmlEntitiesTablePtr) doc->dtd->entities;
1.2       httpng    182:     if (table == NULL) {
                    183:         table = xmlCreateEntitiesTable();
1.16      daniel    184:        doc->dtd->entities = table;
1.1       httpng    185:     }
1.13      daniel    186:     xmlAddEntity(table, name, type, ExternalID, SystemID, content);
1.1       httpng    187: }
                    188: 
                    189: /*
1.2       httpng    190:  * xmlAddDocEntity : register a new entity for this document.
1.1       httpng    191:  */
1.13      daniel    192: void xmlAddDocEntity(xmlDocPtr doc, const CHAR *name, int type,
                    193:               const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
1.16      daniel    194:     xmlEntitiesTablePtr table;
                    195: 
                    196:     table = (xmlEntitiesTablePtr) doc->entities;
                    197:     if (table == NULL) {
                    198:         table = xmlCreateEntitiesTable();
                    199:        doc->entities = table;
1.2       httpng    200:     }
1.16      daniel    201:     xmlAddEntity(doc->entities, name, type, ExternalID, SystemID, content);
1.1       httpng    202: }
                    203: 
                    204: /*
1.16      daniel    205:  * xmlGetDtdEntity : do an entity lookup in the Dtd entity hash table and
1.15      daniel    206:  *       returns the corrsponding entity, if found, NULL otherwise.
1.1       httpng    207:  */
1.16      daniel    208: xmlEntityPtr xmlGetDtdEntity(xmlDocPtr doc, const CHAR *name) {
1.2       httpng    209:     int i;
                    210:     xmlEntityPtr cur;
                    211:     xmlEntitiesTablePtr table;
                    212: 
1.15      daniel    213:     if ((doc->dtd != NULL) && (doc->dtd->entities != NULL)) {
                    214:        table = (xmlEntitiesTablePtr) doc->dtd->entities;
                    215:        for (i = 0;i < table->nb_entities;i++) {
                    216:            cur = &table->table[i];
                    217:            if (!xmlStrcmp(cur->name, name)) return(cur);
                    218:        }
                    219:     }
1.7       veillard  220:     return(NULL);
1.3       httpng    221: }
                    222: 
                    223: /*
1.16      daniel    224:  * xmlGetDocEntity : do an entity lookup in the document entity hash table and
                    225:  *       returns the corrsponding entity, otherwise a lookup is done
                    226:  *       in the predefined entities too.
1.14      daniel    227:  */
1.16      daniel    228: xmlEntityPtr xmlGetDocEntity(xmlDocPtr doc, const CHAR *name) {
1.14      daniel    229:     int i;
1.16      daniel    230:     xmlEntityPtr cur;
1.14      daniel    231:     xmlEntitiesTablePtr table;
                    232: 
1.16      daniel    233:     if (doc->entities != NULL) {
                    234:        table = (xmlEntitiesTablePtr) doc->entities;
                    235:        for (i = 0;i < table->nb_entities;i++) {
                    236:            cur = &table->table[i];
                    237:            if (!xmlStrcmp(cur->name, name)) return(cur);
                    238:        }
                    239:     }
1.15      daniel    240:     if (xmlPredefinedEntities == NULL)
                    241:         xmlInitializePredefinedEntities();
1.16      daniel    242:     table = xmlPredefinedEntities;
                    243:     for (i = 0;i < table->nb_entities;i++) {
                    244:        cur = &table->table[i];
                    245:        if (!xmlStrcmp(cur->name, name)) return(cur);
1.14      daniel    246:     }
                    247: 
                    248:     return(NULL);
1.1       httpng    249: }
                    250: 
                    251: /*
1.21    ! daniel    252:  * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
        !           253:  *                  | [#x10000-#x10FFFF]
        !           254:  * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
        !           255:  */
        !           256: #define IS_CHAR(c)                                                     \
        !           257:     (((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) ||                        \
        !           258:      (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF)))
        !           259: 
        !           260: /*
1.2       httpng    261:  * xmlEncodeEntities : do a global encoding of a string, replacing the
1.19      daniel    262:  *                     predefined entities and non ASCII values with their
                    263:  *                     entities and CharRef counterparts.
                    264:  * TODO !!!! Once moved to UTF-8 internal encoding, the encoding of non-ascii
                    265:  *           get erroneous.
1.1       httpng    266:  */
1.21    ! daniel    267: 
1.2       httpng    268: CHAR *xmlEncodeEntities(xmlDocPtr doc, const CHAR *input) {
1.7       veillard  269:     const CHAR *cur = input;
1.3       httpng    270:     CHAR *out = buffer;
                    271: 
1.19      daniel    272:     if (input == NULL) return(NULL);
1.3       httpng    273:     if (buffer == NULL) {
                    274:         buffer_size = 1000;
                    275:         buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
                    276:        if (buffer == NULL) {
                    277:            perror("malloc failed");
                    278:             exit(1);
                    279:        }
                    280:        out = buffer;
                    281:     }
1.6       veillard  282:     while (*cur != '\0') {
                    283:         if (out - buffer > buffer_size - 100) {
                    284:            int index = out - buffer;
                    285: 
                    286:            growBuffer();
                    287:            out = &buffer[index];
                    288:        }
                    289: 
                    290:        /*
1.7       veillard  291:         * By default one have to encode at least '<', '>', '"' and '&' !
1.6       veillard  292:         */
                    293:        if (*cur == '<') {
                    294:            *out++ = '&';
                    295:            *out++ = 'l';
                    296:            *out++ = 't';
                    297:            *out++ = ';';
1.7       veillard  298:        } else if (*cur == '>') {
                    299:            *out++ = '&';
                    300:            *out++ = 'g';
                    301:            *out++ = 't';
                    302:            *out++ = ';';
1.6       veillard  303:        } else if (*cur == '&') {
                    304:            *out++ = '&';
                    305:            *out++ = 'a';
                    306:            *out++ = 'm';
                    307:            *out++ = 'p';
1.7       veillard  308:            *out++ = ';';
                    309:        } else if (*cur == '"') {
                    310:            *out++ = '&';
                    311:            *out++ = 'q';
                    312:            *out++ = 'u';
                    313:            *out++ = 'o';
                    314:            *out++ = 't';
                    315:            *out++ = ';';
                    316:        } else if (*cur == '\'') {
                    317:            *out++ = '&';
                    318:            *out++ = 'a';
                    319:            *out++ = 'p';
                    320:            *out++ = 'o';
                    321:            *out++ = 's';
1.6       veillard  322:            *out++ = ';';
1.21    ! daniel    323:        } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
        !           324:            (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
        !           325:            /*
        !           326:             * default case, just copy !
        !           327:             */
        !           328:            *out++ = *cur;
1.19      daniel    329: #ifndef USE_UTF_8
                    330:        } else if ((sizeof(CHAR) == 1) && (*cur >= 0x80)) {
                    331:            char buf[10], *ptr;
                    332: #ifdef HAVE_SNPRINTF
                    333:            snprintf(buf, 9, "&#%d;", *cur);
                    334: #else
                    335:            sprintf(buf, "&#%d;", *cur);
                    336: #endif
                    337:             ptr = buf;
                    338:            while (*ptr != 0) *out++ = *ptr++;
                    339: #endif
1.21    ! daniel    340:        } else if (IS_CHAR(*cur)) {
1.20      daniel    341:            char buf[10], *ptr;
                    342: 
                    343: #ifdef HAVE_SNPRINTF
                    344:            snprintf(buf, 9, "&#%d;", *cur);
                    345: #else
                    346:            sprintf(buf, "&#%d;", *cur);
                    347: #endif
                    348:             ptr = buf;
                    349:            while (*ptr != 0) *out++ = *ptr++;
1.21    ! daniel    350:        }
        !           351: #if 0
        !           352:        else {
1.6       veillard  353:            /*
1.21    ! daniel    354:             * default case, this is not a valid char !
        !           355:             * Skip it...
1.6       veillard  356:             */
1.21    ! daniel    357:            fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
1.6       veillard  358:        }
1.21    ! daniel    359: #endif
1.6       veillard  360:        cur++;
                    361:     }
                    362:     *out++ = 0;
                    363:     return(buffer);
1.2       httpng    364: }
                    365: 
                    366: /*
                    367:  * xmlCreateEntitiesTable : create and initialize an enmpty hash table
                    368:  */
                    369: xmlEntitiesTablePtr xmlCreateEntitiesTable(void) {
                    370:     xmlEntitiesTablePtr ret;
1.1       httpng    371: 
1.2       httpng    372:     ret = (xmlEntitiesTablePtr) 
                    373:          malloc(sizeof(xmlEntitiesTable));
1.1       httpng    374:     if (ret == NULL) {
1.2       httpng    375:         fprintf(stderr, "xmlCreateEntitiesTable : malloc(%d) failed\n",
                    376:                sizeof(xmlEntitiesTable));
                    377:         return(NULL);
                    378:     }
                    379:     ret->max_entities = XML_MIN_ENTITIES_TABLE;
                    380:     ret->nb_entities = 0;
                    381:     ret->table = (xmlEntityPtr ) 
                    382:          malloc(ret->max_entities * sizeof(xmlEntity));
                    383:     if (ret == NULL) {
                    384:         fprintf(stderr, "xmlCreateEntitiesTable : malloc(%d) failed\n",
                    385:                ret->max_entities * sizeof(xmlEntity));
                    386:        free(ret);
1.1       httpng    387:         return(NULL);
                    388:     }
                    389:     return(ret);
                    390: }
                    391: 
                    392: /*
1.2       httpng    393:  * xmlFreeEntitiesTable : clean up and free an entities hash table.
1.1       httpng    394:  */
1.2       httpng    395: void xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
1.1       httpng    396:     int i;
                    397: 
                    398:     if (table == NULL) return;
                    399: 
1.2       httpng    400:     for (i = 0;i < table->nb_entities;i++) {
                    401:         xmlFreeEntity(&table->table[i]);
1.1       httpng    402:     }
1.2       httpng    403:     free(table->table);
1.1       httpng    404:     free(table);
                    405: }
                    406: 
1.13      daniel    407: /*
                    408:  * Dump the content of an entity table to the document output.
                    409:  */
                    410: void xmlDumpEntitiesTable(xmlEntitiesTablePtr table) {
1.14      daniel    411:     int i;
                    412:     xmlEntityPtr cur;
                    413: 
                    414:     if (table == NULL) return;
                    415: 
                    416:     for (i = 0;i < table->nb_entities;i++) {
                    417:         cur = &table->table[i];
                    418:         switch (cur->type) {
                    419:            case XML_INTERNAL_GENERAL_ENTITY:
                    420:                xmlBufferWriteChar("<!ENTITY ");
                    421:                xmlBufferWriteCHAR(cur->name);
                    422:                xmlBufferWriteChar(" \"");
                    423:                xmlBufferWriteCHAR(cur->content);
                    424:                xmlBufferWriteChar("\">\n");
                    425:                break;
                    426:            case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
                    427:                xmlBufferWriteChar("<!ENTITY ");
                    428:                xmlBufferWriteCHAR(cur->name);
                    429:                if (cur->ExternalID != NULL) {
                    430:                     xmlBufferWriteChar(" PUBLIC \"");
                    431:                     xmlBufferWriteCHAR(cur->ExternalID);
                    432:                     xmlBufferWriteChar("\" \"");
                    433:                     xmlBufferWriteCHAR(cur->SystemID);
                    434:                     xmlBufferWriteChar("\"");
                    435:                } else {
                    436:                     xmlBufferWriteChar(" SYSTEM \"");
                    437:                     xmlBufferWriteCHAR(cur->SystemID);
                    438:                     xmlBufferWriteChar("\"");
                    439:                }
                    440:                xmlBufferWriteChar(">\n");
                    441:                break;
                    442:            case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
                    443:                xmlBufferWriteChar("<!ENTITY ");
                    444:                xmlBufferWriteCHAR(cur->name);
                    445:                if (cur->ExternalID != NULL) {
                    446:                     xmlBufferWriteChar(" PUBLIC \"");
                    447:                     xmlBufferWriteCHAR(cur->ExternalID);
                    448:                     xmlBufferWriteChar("\" \"");
                    449:                     xmlBufferWriteCHAR(cur->SystemID);
                    450:                     xmlBufferWriteChar("\"");
                    451:                } else {
                    452:                     xmlBufferWriteChar(" SYSTEM \"");
                    453:                     xmlBufferWriteCHAR(cur->SystemID);
                    454:                     xmlBufferWriteChar("\"");
                    455:                }
                    456:                if (cur->content != NULL) { /* Should be true ! */
                    457:                    xmlBufferWriteChar(" NDATA ");
                    458:                    xmlBufferWriteCHAR(cur->content);
                    459:                }
                    460:                xmlBufferWriteChar(">\n");
                    461:                break;
                    462:            case XML_INTERNAL_PARAMETER_ENTITY:
                    463:                xmlBufferWriteChar("<!ENTITY % ");
                    464:                xmlBufferWriteCHAR(cur->name);
                    465:                xmlBufferWriteChar(" \"");
                    466:                xmlBufferWriteCHAR(cur->content);
                    467:                xmlBufferWriteChar("\">\n");
                    468:                break;
                    469:            case XML_EXTERNAL_PARAMETER_ENTITY:
                    470:                xmlBufferWriteChar("<!ENTITY % ");
                    471:                xmlBufferWriteCHAR(cur->name);
                    472:                if (cur->ExternalID != NULL) {
                    473:                     xmlBufferWriteChar(" PUBLIC \"");
                    474:                     xmlBufferWriteCHAR(cur->ExternalID);
                    475:                     xmlBufferWriteChar("\" \"");
                    476:                     xmlBufferWriteCHAR(cur->SystemID);
                    477:                     xmlBufferWriteChar("\"");
                    478:                } else {
                    479:                     xmlBufferWriteChar(" SYSTEM \"");
                    480:                     xmlBufferWriteCHAR(cur->SystemID);
                    481:                     xmlBufferWriteChar("\"");
                    482:                }
                    483:                xmlBufferWriteChar(">\n");
                    484:                break;
                    485:            default:
                    486:                fprintf(stderr,
                    487:                    "xmlDumpEntitiesTable: internal: unknown type %d\n",
                    488:                        cur->type);
                    489:        }
                    490:     }
1.13      daniel    491: }

Webmaster