Annotation of XML/entities.c, revision 1.7

1.1       httpng      1: /*
                      2:  * entities.c : implementation for the XML entities handking
                      3:  */
                      4: 
                      5: #include <stdio.h>
                      6: #include <malloc.h>
1.2       httpng      7: #include <strings.h>
1.1       httpng      8: #include "entities.h"
                      9: 
                     10: /*
1.3       httpng     11:  * A buffer used for converting entities to their equivalent and back.
                     12:  */
1.6       veillard   13: static CHAR *buffer = NULL;
1.3       httpng     14: static int buffer_size = 0;
                     15: 
                     16: void growBuffer(void) {
                     17:     buffer_size *= 2;
                     18:     buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
                     19:     if (buffer == NULL) {
                     20:        perror("realloc failed");
                     21:        exit(1);
                     22:     }
                     23: }
                     24: 
                     25: /*
1.2       httpng     26:  * xmlFreeEntity : clean-up an entity record.
1.1       httpng     27:  */
                     28: 
1.2       httpng     29: void xmlFreeEntity(xmlEntityPtr entity) {
                     30:     if (entity == NULL) return;
                     31: 
1.7     ! veillard   32:     if (entity->value != NULL) free(entity->value);
        !            33:     entity->value = NULL;
1.2       httpng     34:     if (entity->id != NULL)
                     35:        free((char *) entity->id);
                     36: }
1.1       httpng     37: 
                     38: /*
1.2       httpng     39:  * xmlAddDocEntity : register a new entity for an entities table.
1.1       httpng     40:  */
1.7     ! veillard   41: static void xmlAddEntity(xmlEntitiesTablePtr table, CHAR *value,
        !            42:                          const CHAR *id) {
1.2       httpng     43:     int i;
                     44:     xmlEntityPtr cur;
1.1       httpng     45: 
1.2       httpng     46:     for (i = 0;i < table->nb_entities;i++) {
                     47:         cur = &table->table[i];
1.7     ! veillard   48:        if (!xmlStrcmp(cur->id, id)) {
        !            49:            free(cur->value);
        !            50:            cur->value = xmlStrdup(value);
        !            51:        }
1.2       httpng     52:     }
                     53:     if (table->nb_entities >= table->max_entities) {
                     54:         /*
                     55:         * need more elements.
                     56:         */
                     57:        table->max_entities *= 2;
                     58:        table->table = (xmlEntityPtr) 
                     59:            realloc(table->table, table->max_entities * sizeof(xmlEntity));
                     60:        if (table->table) {
                     61:            perror("realloc failed");
                     62:            exit(1);
                     63:        }
                     64:     }
                     65:     cur = &table->table[table->nb_entities];
1.7     ! veillard   66:     cur->value = xmlStrdup(value);
        !            67:     cur->id = xmlStrdup(id);
1.2       httpng     68:     table->nb_entities++;
                     69: }
1.1       httpng     70: 
                     71: 
                     72: /*
1.2       httpng     73:  * xmlAddDtdEntity : register a new entity for this document.
1.1       httpng     74:  */
1.7     ! veillard   75: void xmlAddDtdEntity(xmlDtdPtr dtd, CHAR *value, const CHAR *id) {
1.2       httpng     76:     xmlEntitiesTablePtr table;
1.1       httpng     77: 
1.2       httpng     78:     table = (xmlEntitiesTablePtr) dtd->entities;
                     79:     if (table == NULL) {
                     80:         table = xmlCreateEntitiesTable();
                     81:        dtd->entities = table;
1.1       httpng     82:     }
1.2       httpng     83:     xmlAddEntity(table, value, id);
1.1       httpng     84: }
                     85: 
                     86: /*
1.2       httpng     87:  * xmlAddDocEntity : register a new entity for this document.
1.1       httpng     88:  */
1.7     ! veillard   89: void xmlAddDocEntity(xmlDocPtr doc, CHAR *value, const CHAR *id) {
1.2       httpng     90:     xmlEntitiesTablePtr table;
1.1       httpng     91: 
1.2       httpng     92:     table = (xmlEntitiesTablePtr) doc->entities;
                     93:     if (table == NULL) {
                     94:         table = xmlCreateEntitiesTable();
                     95:        doc->entities = table;
                     96:     }
                     97:     xmlAddEntity(table, value, id);
1.1       httpng     98: }
                     99: 
                    100: /*
                    101:  * xmlGetEntity : do an entity lookup in the hash table and
1.7     ! veillard  102:  *       returns the corrsponding CHAR *, if found, zero otherwise.
1.1       httpng    103:  */
1.7     ! veillard  104: CHAR *xmlGetEntity(xmlDocPtr doc, const CHAR *id) {
1.2       httpng    105:     int i;
                    106:     xmlEntityPtr cur;
                    107:     xmlEntitiesTablePtr table;
                    108: 
                    109:     if (doc->entities == NULL) return(0);
1.5       veillard  110:     table = (xmlEntitiesTablePtr) doc->entities;
1.2       httpng    111:     for (i = 0;i < table->nb_entities;i++) {
                    112:         cur = &table->table[i];
1.7     ! veillard  113:        if (!xmlStrcmp(cur->id, id)) return(cur->value);
1.2       httpng    114:     }
1.7     ! veillard  115:     return(NULL);
1.1       httpng    116: }
                    117: 
                    118: /*
1.6       veillard  119:  * xmlReadEntities : read an entity.
1.1       httpng    120:  */
1.7     ! veillard  121: const CHAR *xmlReadEntity(xmlDocPtr doc, const CHAR **input) {
        !           122:     static CHAR *entity = NULL;
        !           123:     static int entity_size = 100;
        !           124:     const CHAR *cur = *input;
        !           125: 
        !           126:     if (entity == NULL) {
        !           127:         entity = (CHAR *) malloc(entity_size * sizeof(CHAR));
        !           128:        if (entity == NULL) {
        !           129:            fprintf(stderr, "xmlReadEntity : cannot allocate %d bytes\n",
        !           130:                    entity_size * sizeof(CHAR));
        !           131:             return(NULL);
        !           132:        }
        !           133:     }
        !           134:     if (*cur == '&') {
        !           135:         cur++;
        !           136:        if (*cur == '#') {
        !           137:            /* TODO !!!! 
        !           138:            fprintf(stderr, "Character reference not yet implemented\n"); */
1.3       httpng    139:        } else {
1.7     ! veillard  140:            /* TODO !!!! 
        !           141:            fprintf(stderr, "Entity search not yet implemented\n"); */
1.3       httpng    142:        }
                    143:     }
1.7     ! veillard  144: 
        !           145:     /*
        !           146:      * The few predefined entities.
        !           147:      */
        !           148:     if ((cur[0] == 'a') && (cur[1] == 'm') && (cur[2] == 'p') &&
        !           149:         (cur[3] == ';')) {
        !           150:         entity[0] = '%';
        !           151:         entity[1] = 0;
        !           152:        cur += 4;
        !           153:        *input = cur;
        !           154:         return(entity);
        !           155:     } else if ((cur[0] == 'q') && (cur[1] == 'u') && (cur[2] == 'o') &&
        !           156:         (cur[3] == 't') && (cur[4] == ';')) {
        !           157:         entity[0] = '"';
        !           158:         entity[1] = 0;
        !           159:        cur += 4;
        !           160:        *input = cur;
        !           161:         return(entity);
        !           162:     } else if ((cur[0] == 'a') && (cur[1] == 'p') && (cur[2] == 'o') &&
        !           163:         (cur[3] == 's') && (cur[4] == ';')) {
        !           164:         entity[0] = '\'';
        !           165:         entity[1] = 0;
        !           166:        cur += 4;
        !           167:        *input = cur;
        !           168:         return(entity);
        !           169:     } else if ((cur[0] == 'l') && (cur[1] == 't') && (cur[2] == ';')) {
        !           170:         entity[0] = '<';
        !           171:         entity[1] = 0;
        !           172:        cur += 3;
        !           173:        *input = cur;
        !           174:         return(entity);
        !           175:     } else if ((cur[0] == 'g') && (cur[1] == 't') && (cur[2] == ';')) {
        !           176:         entity[0] = '>';
        !           177:         entity[1] = 0;
        !           178:        cur += 3;
        !           179:        *input = cur;
        !           180:         return(entity);
        !           181:     }
        !           182: 
        !           183:     return(NULL);
1.3       httpng    184: }
                    185: 
                    186: /*
1.7     ! veillard  187:  * xmlDecodeEntities : do a global entities lookup on a input string
1.3       httpng    188:  *        and returns a duplicate after the entities substitution.
                    189:  */
1.7     ! veillard  190: CHAR *xmlDecodeEntities(xmlDocPtr doc, const CHAR *input, int len) {
        !           191:     const CHAR *cur = input;
1.3       httpng    192:     CHAR *out = buffer;
                    193:     int i;
                    194: 
                    195:     if (buffer == NULL) {
                    196:         buffer_size = 1000;
                    197:         buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
                    198:        if (buffer == NULL) {
                    199:            perror("malloc failed");
                    200:             exit(1);
                    201:        }
                    202:        out = buffer;
                    203:     }
1.7     ! veillard  204:     for (i = 0;(*cur != 0) && (cur - input < len);cur++) {
1.3       httpng    205:         if (*cur == '&') {
1.7     ! veillard  206:             const CHAR *entity = xmlReadEntity(doc, &cur);
1.3       httpng    207:            if (entity != NULL)
                    208:                while (*entity != 0) { 
                    209:                    *out++ = *entity++;
                    210:                    i++;
1.6       veillard  211:                    if (i + 10 > buffer_size) {
                    212:                        int index = out - buffer;
                    213: 
                    214:                        growBuffer();
                    215:                        out = &buffer[index];
                    216:                    }
1.3       httpng    217:                }
                    218:        } else if (*cur == '%') {
1.7     ! veillard  219:            /* TODO !!!!!
        !           220:            fprintf(stderr, " \n"); */
1.3       httpng    221:        } else {
1.7     ! veillard  222:            *out++ = *cur;
1.3       httpng    223:            i++;
                    224:        }
                    225: 
1.6       veillard  226:        if (i + 10 > buffer_size) {
                    227:            int index = out - buffer;
                    228: 
                    229:            growBuffer();
                    230:            out = &buffer[index];
                    231:        }
1.3       httpng    232:     }
1.7     ! veillard  233:     *out++ = 0;
1.3       httpng    234:     return(buffer);
1.1       httpng    235: }
                    236: 
                    237: /*
1.2       httpng    238:  * xmlEncodeEntities : do a global encoding of a string, replacing the
1.7     ! veillard  239:  *                     basic values with their entities form.
1.1       httpng    240:  */
1.2       httpng    241: CHAR *xmlEncodeEntities(xmlDocPtr doc, const CHAR *input) {
1.7     ! veillard  242:     const CHAR *cur = input;
1.3       httpng    243:     CHAR *out = buffer;
                    244: 
                    245:     if (buffer == NULL) {
                    246:         buffer_size = 1000;
                    247:         buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
                    248:        if (buffer == NULL) {
                    249:            perror("malloc failed");
                    250:             exit(1);
                    251:        }
                    252:        out = buffer;
                    253:     }
1.6       veillard  254:     while (*cur != '\0') {
                    255:         if (out - buffer > buffer_size - 100) {
                    256:            int index = out - buffer;
                    257: 
                    258:            growBuffer();
                    259:            out = &buffer[index];
                    260:        }
                    261: 
                    262:        /*
1.7     ! veillard  263:         * By default one have to encode at least '<', '>', '"' and '&' !
        !           264:         * One could try a better encoding using the entities defined and
        !           265:         * used as a compression code !!!.
1.6       veillard  266:         */
                    267:        if (*cur == '<') {
                    268:            *out++ = '&';
                    269:            *out++ = 'l';
                    270:            *out++ = 't';
                    271:            *out++ = ';';
1.7     ! veillard  272:        } else if (*cur == '>') {
        !           273:            *out++ = '&';
        !           274:            *out++ = 'g';
        !           275:            *out++ = 't';
        !           276:            *out++ = ';';
1.6       veillard  277:        } else if (*cur == '&') {
                    278:            *out++ = '&';
                    279:            *out++ = 'a';
                    280:            *out++ = 'm';
                    281:            *out++ = 'p';
1.7     ! veillard  282:            *out++ = ';';
        !           283:        } else if (*cur == '"') {
        !           284:            *out++ = '&';
        !           285:            *out++ = 'q';
        !           286:            *out++ = 'u';
        !           287:            *out++ = 'o';
        !           288:            *out++ = 't';
        !           289:            *out++ = ';';
        !           290:        } else if (*cur == '\'') {
        !           291:            *out++ = '&';
        !           292:            *out++ = 'a';
        !           293:            *out++ = 'p';
        !           294:            *out++ = 'o';
        !           295:            *out++ = 's';
1.6       veillard  296:            *out++ = ';';
                    297:        } else {
                    298:            /*
                    299:             * default case, just copy !
                    300:             */
                    301:            *out++ = *cur;
                    302:        }
                    303:        cur++;
                    304:     }
                    305:     *out++ = 0;
                    306:     return(buffer);
1.2       httpng    307: }
                    308: 
                    309: /*
                    310:  * xmlCreateEntitiesTable : create and initialize an enmpty hash table
                    311:  */
                    312: xmlEntitiesTablePtr xmlCreateEntitiesTable(void) {
                    313:     xmlEntitiesTablePtr ret;
1.1       httpng    314: 
1.2       httpng    315:     ret = (xmlEntitiesTablePtr) 
                    316:          malloc(sizeof(xmlEntitiesTable));
1.1       httpng    317:     if (ret == NULL) {
1.2       httpng    318:         fprintf(stderr, "xmlCreateEntitiesTable : malloc(%d) failed\n",
                    319:                sizeof(xmlEntitiesTable));
                    320:         return(NULL);
                    321:     }
                    322:     ret->max_entities = XML_MIN_ENTITIES_TABLE;
                    323:     ret->nb_entities = 0;
                    324:     ret->table = (xmlEntityPtr ) 
                    325:          malloc(ret->max_entities * sizeof(xmlEntity));
                    326:     if (ret == NULL) {
                    327:         fprintf(stderr, "xmlCreateEntitiesTable : malloc(%d) failed\n",
                    328:                ret->max_entities * sizeof(xmlEntity));
                    329:        free(ret);
1.1       httpng    330:         return(NULL);
                    331:     }
                    332:     return(ret);
                    333: }
                    334: 
                    335: /*
1.2       httpng    336:  * xmlFreeEntitiesTable : clean up and free an entities hash table.
1.1       httpng    337:  */
1.2       httpng    338: void xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
1.1       httpng    339:     int i;
                    340: 
                    341:     if (table == NULL) return;
                    342: 
1.2       httpng    343:     for (i = 0;i < table->nb_entities;i++) {
                    344:         xmlFreeEntity(&table->table[i]);
1.1       httpng    345:     }
1.2       httpng    346:     free(table->table);
1.1       httpng    347:     free(table);
                    348: }
                    349: 

Webmaster