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