Annotation of XML/entities.c, revision 1.20

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.20    ! daniel      6:  * $Id: entities.c,v 1.19 1998/11/11 20:07:54 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.2       httpng    252:  * xmlEncodeEntities : do a global encoding of a string, replacing the
1.19      daniel    253:  *                     predefined entities and non ASCII values with their
                    254:  *                     entities and CharRef counterparts.
                    255:  * TODO !!!! Once moved to UTF-8 internal encoding, the encoding of non-ascii
                    256:  *           get erroneous.
1.1       httpng    257:  */
1.2       httpng    258: CHAR *xmlEncodeEntities(xmlDocPtr doc, const CHAR *input) {
1.7       veillard  259:     const CHAR *cur = input;
1.3       httpng    260:     CHAR *out = buffer;
                    261: 
1.19      daniel    262:     if (input == NULL) return(NULL);
1.3       httpng    263:     if (buffer == NULL) {
                    264:         buffer_size = 1000;
                    265:         buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
                    266:        if (buffer == NULL) {
                    267:            perror("malloc failed");
                    268:             exit(1);
                    269:        }
                    270:        out = buffer;
                    271:     }
1.6       veillard  272:     while (*cur != '\0') {
                    273:         if (out - buffer > buffer_size - 100) {
                    274:            int index = out - buffer;
                    275: 
                    276:            growBuffer();
                    277:            out = &buffer[index];
                    278:        }
                    279: 
                    280:        /*
1.7       veillard  281:         * By default one have to encode at least '<', '>', '"' and '&' !
1.6       veillard  282:         */
                    283:        if (*cur == '<') {
                    284:            *out++ = '&';
                    285:            *out++ = 'l';
                    286:            *out++ = 't';
                    287:            *out++ = ';';
1.7       veillard  288:        } else if (*cur == '>') {
                    289:            *out++ = '&';
                    290:            *out++ = 'g';
                    291:            *out++ = 't';
                    292:            *out++ = ';';
1.6       veillard  293:        } else if (*cur == '&') {
                    294:            *out++ = '&';
                    295:            *out++ = 'a';
                    296:            *out++ = 'm';
                    297:            *out++ = 'p';
1.7       veillard  298:            *out++ = ';';
                    299:        } else if (*cur == '"') {
                    300:            *out++ = '&';
                    301:            *out++ = 'q';
                    302:            *out++ = 'u';
                    303:            *out++ = 'o';
                    304:            *out++ = 't';
                    305:            *out++ = ';';
                    306:        } else if (*cur == '\'') {
                    307:            *out++ = '&';
                    308:            *out++ = 'a';
                    309:            *out++ = 'p';
                    310:            *out++ = 'o';
                    311:            *out++ = 's';
1.6       veillard  312:            *out++ = ';';
1.19      daniel    313: #ifndef USE_UTF_8
                    314:        } else if ((sizeof(CHAR) == 1) && (*cur >= 0x80)) {
                    315:            char buf[10], *ptr;
                    316: #ifdef HAVE_SNPRINTF
                    317:            snprintf(buf, 9, "&#%d;", *cur);
                    318: #else
                    319:            sprintf(buf, "&#%d;", *cur);
                    320: #endif
                    321:             ptr = buf;
                    322:            while (*ptr != 0) *out++ = *ptr++;
                    323: #endif
1.20    ! daniel    324:        } else if ((*cur >= 1) && (*cur < 0x20) &&
        !           325:                   (*cur != '\n') && (*cur != '\r') && (*cur != '\t')) {
        !           326:            char buf[10], *ptr;
        !           327: 
        !           328: #ifdef HAVE_SNPRINTF
        !           329:            snprintf(buf, 9, "&#%d;", *cur);
        !           330: #else
        !           331:            sprintf(buf, "&#%d;", *cur);
        !           332: #endif
        !           333:             ptr = buf;
        !           334:            while (*ptr != 0) *out++ = *ptr++;
1.6       veillard  335:        } else {
                    336:            /*
                    337:             * default case, just copy !
                    338:             */
                    339:            *out++ = *cur;
                    340:        }
                    341:        cur++;
                    342:     }
                    343:     *out++ = 0;
                    344:     return(buffer);
1.2       httpng    345: }
                    346: 
                    347: /*
                    348:  * xmlCreateEntitiesTable : create and initialize an enmpty hash table
                    349:  */
                    350: xmlEntitiesTablePtr xmlCreateEntitiesTable(void) {
                    351:     xmlEntitiesTablePtr ret;
1.1       httpng    352: 
1.2       httpng    353:     ret = (xmlEntitiesTablePtr) 
                    354:          malloc(sizeof(xmlEntitiesTable));
1.1       httpng    355:     if (ret == NULL) {
1.2       httpng    356:         fprintf(stderr, "xmlCreateEntitiesTable : malloc(%d) failed\n",
                    357:                sizeof(xmlEntitiesTable));
                    358:         return(NULL);
                    359:     }
                    360:     ret->max_entities = XML_MIN_ENTITIES_TABLE;
                    361:     ret->nb_entities = 0;
                    362:     ret->table = (xmlEntityPtr ) 
                    363:          malloc(ret->max_entities * sizeof(xmlEntity));
                    364:     if (ret == NULL) {
                    365:         fprintf(stderr, "xmlCreateEntitiesTable : malloc(%d) failed\n",
                    366:                ret->max_entities * sizeof(xmlEntity));
                    367:        free(ret);
1.1       httpng    368:         return(NULL);
                    369:     }
                    370:     return(ret);
                    371: }
                    372: 
                    373: /*
1.2       httpng    374:  * xmlFreeEntitiesTable : clean up and free an entities hash table.
1.1       httpng    375:  */
1.2       httpng    376: void xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
1.1       httpng    377:     int i;
                    378: 
                    379:     if (table == NULL) return;
                    380: 
1.2       httpng    381:     for (i = 0;i < table->nb_entities;i++) {
                    382:         xmlFreeEntity(&table->table[i]);
1.1       httpng    383:     }
1.2       httpng    384:     free(table->table);
1.1       httpng    385:     free(table);
                    386: }
                    387: 
1.13      daniel    388: /*
                    389:  * Dump the content of an entity table to the document output.
                    390:  */
                    391: void xmlDumpEntitiesTable(xmlEntitiesTablePtr table) {
1.14      daniel    392:     int i;
                    393:     xmlEntityPtr cur;
                    394: 
                    395:     if (table == NULL) return;
                    396: 
                    397:     for (i = 0;i < table->nb_entities;i++) {
                    398:         cur = &table->table[i];
                    399:         switch (cur->type) {
                    400:            case XML_INTERNAL_GENERAL_ENTITY:
                    401:                xmlBufferWriteChar("<!ENTITY ");
                    402:                xmlBufferWriteCHAR(cur->name);
                    403:                xmlBufferWriteChar(" \"");
                    404:                xmlBufferWriteCHAR(cur->content);
                    405:                xmlBufferWriteChar("\">\n");
                    406:                break;
                    407:            case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
                    408:                xmlBufferWriteChar("<!ENTITY ");
                    409:                xmlBufferWriteCHAR(cur->name);
                    410:                if (cur->ExternalID != NULL) {
                    411:                     xmlBufferWriteChar(" PUBLIC \"");
                    412:                     xmlBufferWriteCHAR(cur->ExternalID);
                    413:                     xmlBufferWriteChar("\" \"");
                    414:                     xmlBufferWriteCHAR(cur->SystemID);
                    415:                     xmlBufferWriteChar("\"");
                    416:                } else {
                    417:                     xmlBufferWriteChar(" SYSTEM \"");
                    418:                     xmlBufferWriteCHAR(cur->SystemID);
                    419:                     xmlBufferWriteChar("\"");
                    420:                }
                    421:                xmlBufferWriteChar(">\n");
                    422:                break;
                    423:            case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
                    424:                xmlBufferWriteChar("<!ENTITY ");
                    425:                xmlBufferWriteCHAR(cur->name);
                    426:                if (cur->ExternalID != NULL) {
                    427:                     xmlBufferWriteChar(" PUBLIC \"");
                    428:                     xmlBufferWriteCHAR(cur->ExternalID);
                    429:                     xmlBufferWriteChar("\" \"");
                    430:                     xmlBufferWriteCHAR(cur->SystemID);
                    431:                     xmlBufferWriteChar("\"");
                    432:                } else {
                    433:                     xmlBufferWriteChar(" SYSTEM \"");
                    434:                     xmlBufferWriteCHAR(cur->SystemID);
                    435:                     xmlBufferWriteChar("\"");
                    436:                }
                    437:                if (cur->content != NULL) { /* Should be true ! */
                    438:                    xmlBufferWriteChar(" NDATA ");
                    439:                    xmlBufferWriteCHAR(cur->content);
                    440:                }
                    441:                xmlBufferWriteChar(">\n");
                    442:                break;
                    443:            case XML_INTERNAL_PARAMETER_ENTITY:
                    444:                xmlBufferWriteChar("<!ENTITY % ");
                    445:                xmlBufferWriteCHAR(cur->name);
                    446:                xmlBufferWriteChar(" \"");
                    447:                xmlBufferWriteCHAR(cur->content);
                    448:                xmlBufferWriteChar("\">\n");
                    449:                break;
                    450:            case XML_EXTERNAL_PARAMETER_ENTITY:
                    451:                xmlBufferWriteChar("<!ENTITY % ");
                    452:                xmlBufferWriteCHAR(cur->name);
                    453:                if (cur->ExternalID != NULL) {
                    454:                     xmlBufferWriteChar(" PUBLIC \"");
                    455:                     xmlBufferWriteCHAR(cur->ExternalID);
                    456:                     xmlBufferWriteChar("\" \"");
                    457:                     xmlBufferWriteCHAR(cur->SystemID);
                    458:                     xmlBufferWriteChar("\"");
                    459:                } else {
                    460:                     xmlBufferWriteChar(" SYSTEM \"");
                    461:                     xmlBufferWriteCHAR(cur->SystemID);
                    462:                     xmlBufferWriteChar("\"");
                    463:                }
                    464:                xmlBufferWriteChar(">\n");
                    465:                break;
                    466:            default:
                    467:                fprintf(stderr,
                    468:                    "xmlDumpEntitiesTable: internal: unknown type %d\n",
                    469:                        cur->type);
                    470:        }
                    471:     }
1.13      daniel    472: }

Webmaster