Annotation of XML/entities.c, revision 1.14
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.14 ! daniel 6: * $Id: entities.c,v 1.13 1998/08/06 16:45:43 daniel Exp $
1.1 httpng 7: */
8:
9: #include <stdio.h>
10: #include <malloc.h>
1.10 daniel 11: #include <string.h>
1.1 httpng 12: #include "entities.h"
13:
14: /*
1.3 httpng 15: * A buffer used for converting entities to their equivalent and back.
16: */
1.14 ! daniel 17: static int buffer_size = 0;
1.6 veillard 18: static CHAR *buffer = NULL;
1.3 httpng 19:
20: void growBuffer(void) {
21: buffer_size *= 2;
22: buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
23: if (buffer == NULL) {
24: perror("realloc failed");
25: exit(1);
26: }
27: }
28:
29: /*
1.2 httpng 30: * xmlFreeEntity : clean-up an entity record.
1.1 httpng 31: */
32:
1.2 httpng 33: void xmlFreeEntity(xmlEntityPtr entity) {
34: if (entity == NULL) return;
35:
1.11 daniel 36: if (entity->name != NULL)
37: free((char *) entity->name);
1.14 ! daniel 38: if (entity->ExternalID != NULL)
! 39: free((char *) entity->ExternalID);
! 40: if (entity->SystemID != NULL)
! 41: free((char *) entity->SystemID);
! 42: if (entity->content != NULL)
! 43: free((char *) entity->content);
! 44: memset(entity, -1, sizeof(xmlEntity));
1.2 httpng 45: }
1.1 httpng 46:
47: /*
1.2 httpng 48: * xmlAddDocEntity : register a new entity for an entities table.
1.13 daniel 49: *
50: * TODO !!! We should check here that the combination of type
51: * ExternalID and SystemID is valid.
1.1 httpng 52: */
1.13 daniel 53: static void xmlAddEntity(xmlEntitiesTablePtr table, const CHAR *name, int type,
54: const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
1.2 httpng 55: int i;
56: xmlEntityPtr cur;
1.14 ! daniel 57: int len;
1.1 httpng 58:
1.2 httpng 59: for (i = 0;i < table->nb_entities;i++) {
60: cur = &table->table[i];
1.11 daniel 61: if (!xmlStrcmp(cur->name, name)) {
1.13 daniel 62: /*
63: * The entity is already defined in this Dtd, the spec says to NOT
64: * override it ... Is it worth a Warning ??? !!!
65: */
66: return;
1.7 veillard 67: }
1.2 httpng 68: }
69: if (table->nb_entities >= table->max_entities) {
70: /*
71: * need more elements.
72: */
73: table->max_entities *= 2;
74: table->table = (xmlEntityPtr)
75: realloc(table->table, table->max_entities * sizeof(xmlEntity));
76: if (table->table) {
77: perror("realloc failed");
78: exit(1);
79: }
80: }
81: cur = &table->table[table->nb_entities];
1.11 daniel 82: cur->name = xmlStrdup(name);
1.14 ! daniel 83: for (len = 0;name[0] != 0;name++)len++;
! 84: cur->len = len;
1.13 daniel 85: cur->type = type;
86: if (ExternalID != NULL)
87: cur->ExternalID = xmlStrdup(ExternalID);
1.14 ! daniel 88: else
! 89: cur->ExternalID = NULL;
1.13 daniel 90: if (SystemID != NULL)
1.14 ! daniel 91: cur->SystemID = xmlStrdup(SystemID);
! 92: else
! 93: cur->SystemID = NULL;
1.13 daniel 94: if (content != NULL)
95: cur->content = xmlStrdup(content);
1.14 ! daniel 96: else
! 97: cur->content = NULL;
1.2 httpng 98: table->nb_entities++;
99: }
1.1 httpng 100:
101:
102: /*
1.12 daniel 103: * xmlAddDtdEntity : register a new entity for this DTD.
1.1 httpng 104: */
1.13 daniel 105: void xmlAddDtdEntity(xmlDtdPtr dtd, const CHAR *name, int type,
106: const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
1.2 httpng 107: xmlEntitiesTablePtr table;
1.1 httpng 108:
1.2 httpng 109: table = (xmlEntitiesTablePtr) dtd->entities;
110: if (table == NULL) {
111: table = xmlCreateEntitiesTable();
112: dtd->entities = table;
1.1 httpng 113: }
1.13 daniel 114: xmlAddEntity(table, name, type, ExternalID, SystemID, content);
1.1 httpng 115: }
116:
117: /*
1.2 httpng 118: * xmlAddDocEntity : register a new entity for this document.
1.1 httpng 119: */
1.13 daniel 120: void xmlAddDocEntity(xmlDocPtr doc, const CHAR *name, int type,
121: const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
1.12 daniel 122: if (doc->dtd == NULL) {
123: fprintf(stderr, "xmlAddDocEntity: document without DTD\n");
124: return;
1.2 httpng 125: }
1.13 daniel 126: xmlAddDtdEntity(doc->dtd, name, type, ExternalID, SystemID, content);
1.1 httpng 127: }
128:
129: /*
130: * xmlGetEntity : do an entity lookup in the hash table and
1.7 veillard 131: * returns the corrsponding CHAR *, if found, zero otherwise.
1.1 httpng 132: */
1.11 daniel 133: CHAR *xmlGetEntity(xmlDocPtr doc, const CHAR *name) {
1.2 httpng 134: int i;
135: xmlEntityPtr cur;
136: xmlEntitiesTablePtr table;
137:
1.12 daniel 138: if (doc->dtd == NULL) return(NULL);
139: if (doc->dtd->entities == NULL) return(NULL);
140: table = (xmlEntitiesTablePtr) doc->dtd->entities;
1.2 httpng 141: for (i = 0;i < table->nb_entities;i++) {
142: cur = &table->table[i];
1.11 daniel 143: if (!xmlStrcmp(cur->name, name)) return(cur->content);
1.2 httpng 144: }
1.12 daniel 145: /* TODO !!! recurse for embedded DTD if available */
1.7 veillard 146: return(NULL);
1.1 httpng 147: }
148:
149: /*
1.6 veillard 150: * xmlReadEntities : read an entity.
1.12 daniel 151: * TODO !!!! Complete nonsense, rewite !!!
1.1 httpng 152: */
1.7 veillard 153: const CHAR *xmlReadEntity(xmlDocPtr doc, const CHAR **input) {
154: static CHAR *entity = NULL;
155: static int entity_size = 100;
156: const CHAR *cur = *input;
157:
158: if (entity == NULL) {
159: entity = (CHAR *) malloc(entity_size * sizeof(CHAR));
160: if (entity == NULL) {
161: fprintf(stderr, "xmlReadEntity : cannot allocate %d bytes\n",
162: entity_size * sizeof(CHAR));
163: return(NULL);
164: }
165: }
166: if (*cur == '&') {
167: cur++;
168: if (*cur == '#') {
169: /* TODO !!!!
170: fprintf(stderr, "Character reference not yet implemented\n"); */
1.3 httpng 171: } else {
1.7 veillard 172: /* TODO !!!!
173: fprintf(stderr, "Entity search not yet implemented\n"); */
1.3 httpng 174: }
175: }
1.7 veillard 176:
177: /*
178: * The few predefined entities.
179: */
180: if ((cur[0] == 'a') && (cur[1] == 'm') && (cur[2] == 'p') &&
181: (cur[3] == ';')) {
1.13 daniel 182: entity[0] = '&';
1.7 veillard 183: entity[1] = 0;
1.8 veillard 184: cur += 3;
1.7 veillard 185: *input = cur;
186: return(entity);
187: } else if ((cur[0] == 'q') && (cur[1] == 'u') && (cur[2] == 'o') &&
188: (cur[3] == 't') && (cur[4] == ';')) {
189: entity[0] = '"';
190: entity[1] = 0;
191: cur += 4;
192: *input = cur;
193: return(entity);
194: } else if ((cur[0] == 'a') && (cur[1] == 'p') && (cur[2] == 'o') &&
195: (cur[3] == 's') && (cur[4] == ';')) {
196: entity[0] = '\'';
197: entity[1] = 0;
198: cur += 4;
199: *input = cur;
200: return(entity);
201: } else if ((cur[0] == 'l') && (cur[1] == 't') && (cur[2] == ';')) {
202: entity[0] = '<';
203: entity[1] = 0;
1.8 veillard 204: cur += 2;
1.7 veillard 205: *input = cur;
206: return(entity);
207: } else if ((cur[0] == 'g') && (cur[1] == 't') && (cur[2] == ';')) {
208: entity[0] = '>';
209: entity[1] = 0;
1.8 veillard 210: cur += 2;
1.7 veillard 211: *input = cur;
212: return(entity);
1.13 daniel 213: } else {
214: entity[0] = '&';
215: entity[1] = 0;
216: return(entity);
1.7 veillard 217: }
1.13 daniel 218:
1.7 veillard 219:
220: return(NULL);
1.3 httpng 221: }
222:
223: /*
1.14 ! daniel 224: * xmlEntityLookup : do a lookup for an entity.
! 225: */
! 226: const CHAR *xmlEntityLookup(xmlDocPtr doc, const CHAR **input) {
! 227: static CHAR *entity = NULL;
! 228: static int entity_size = 10;
! 229: const CHAR *cur = *input;
! 230: int isParameter;
! 231: int i;
! 232: xmlEntitiesTablePtr table;
! 233: xmlEntityPtr ent;
! 234:
! 235: if (*cur == '&') isParameter = 0;
! 236: else if (*cur == '%') isParameter = 1;
! 237: else return(NULL);
! 238:
! 239: if (entity == NULL) {
! 240: entity = (CHAR *) malloc(entity_size * sizeof(CHAR));
! 241: if (entity == NULL) {
! 242: fprintf(stderr, "xmlReadEntity : cannot allocate %d bytes\n",
! 243: entity_size * sizeof(CHAR));
! 244: return(NULL);
! 245: }
! 246: }
! 247: /* skip the first char */
! 248: cur++;
! 249:
! 250: /*
! 251: * The few predefined entities.
! 252: */
! 253: if ((cur[0] == 'a') && (cur[1] == 'm') && (cur[2] == 'p') &&
! 254: (cur[3] == ';')) {
! 255: entity[0] = '&';
! 256: entity[1] = 0;
! 257: cur += 3;
! 258: *input = cur;
! 259: return(xmlStrdup(entity));
! 260: } else if ((cur[0] == 'q') && (cur[1] == 'u') && (cur[2] == 'o') &&
! 261: (cur[3] == 't') && (cur[4] == ';')) {
! 262: entity[0] = '"';
! 263: entity[1] = 0;
! 264: cur += 4;
! 265: *input = cur;
! 266: return(xmlStrdup(entity));
! 267: } else if ((cur[0] == 'a') && (cur[1] == 'p') && (cur[2] == 'o') &&
! 268: (cur[3] == 's') && (cur[4] == ';')) {
! 269: entity[0] = '\'';
! 270: entity[1] = 0;
! 271: cur += 4;
! 272: *input = cur;
! 273: return(xmlStrdup(entity));
! 274: } else if ((cur[0] == 'l') && (cur[1] == 't') && (cur[2] == ';')) {
! 275: entity[0] = '<';
! 276: entity[1] = 0;
! 277: cur += 2;
! 278: *input = cur;
! 279: return(xmlStrdup(entity));
! 280: } else if ((cur[0] == 'g') && (cur[1] == 't') && (cur[2] == ';')) {
! 281: entity[0] = '>';
! 282: entity[1] = 0;
! 283: cur += 2;
! 284: *input = cur;
! 285: return(xmlStrdup(entity));
! 286: } else {
! 287: if ((doc->dtd != NULL) && (doc->dtd->entities != NULL)) {
! 288: table = (xmlEntitiesTablePtr) doc->dtd->entities;
! 289: /*
! 290: * Browse the set of entities declared and check for the
! 291: * first match...
! 292: */
! 293: for (i = 0;i < table->nb_entities;i++) {
! 294: ent = &table->table[i];
! 295: if (!xmlStrncmp(ent->name, cur, ent->len)) {
! 296: switch (ent->type) {
! 297: case XML_INTERNAL_GENERAL_ENTITY:
! 298: case XML_INTERNAL_PARAMETER_ENTITY:
! 299: cur += ent->len;
! 300: *input = cur;
! 301: /* Do the substitution on existing entities */
! 302: return(xmlDecodeEntities(doc, ent->content,
! 303: ent->len));
! 304: break;
! 305: case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
! 306: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
! 307: case XML_EXTERNAL_PARAMETER_ENTITY:
! 308: fprintf(stderr,
! 309: "External entities not supported\n");
! 310: break;
! 311: default:
! 312: fprintf(stderr,
! 313: "xmlDumpEntitiesTable: internal: unknown type %d\n",
! 314: ent->type);
! 315: }
! 316: }
! 317: }
! 318: }
! 319: if (isParameter)
! 320: entity[0] = '%';
! 321: else
! 322: entity[0] = '&';
! 323: entity[1] = 0;
! 324: return(xmlStrdup(entity));
! 325: }
! 326:
! 327:
! 328: return(NULL);
! 329: }
! 330: /*
1.7 veillard 331: * xmlDecodeEntities : do a global entities lookup on a input string
1.3 httpng 332: * and returns a duplicate after the entities substitution.
333: */
1.7 veillard 334: CHAR *xmlDecodeEntities(xmlDocPtr doc, const CHAR *input, int len) {
335: const CHAR *cur = input;
1.14 ! daniel 336: CHAR *out;
! 337: CHAR *buffer;
! 338: int buffer_size;
1.3 httpng 339: int i;
340:
1.14 ! daniel 341: buffer_size = 10000 + len * 2;
! 342: buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
1.3 httpng 343: if (buffer == NULL) {
1.14 ! daniel 344: perror("malloc failed");
! 345: exit(1);
1.3 httpng 346: }
1.14 ! daniel 347: out = buffer;
1.7 veillard 348: for (i = 0;(*cur != 0) && (cur - input < len);cur++) {
1.3 httpng 349: if (*cur == '&') {
1.14 ! daniel 350: const CHAR *base, *entity = xmlEntityLookup(doc, &cur);
! 351: if (entity != NULL) {
! 352: base = entity;
1.3 httpng 353: while (*entity != 0) {
354: *out++ = *entity++;
355: i++;
1.6 veillard 356: if (i + 10 > buffer_size) {
357: int index = out - buffer;
358:
359: growBuffer();
360: out = &buffer[index];
361: }
1.3 httpng 362: }
1.14 ! daniel 363: free(base);
! 364: }
1.3 httpng 365: } else if (*cur == '%') {
1.7 veillard 366: /* TODO !!!!!
367: fprintf(stderr, " \n"); */
1.3 httpng 368: } else {
1.7 veillard 369: *out++ = *cur;
1.3 httpng 370: i++;
371: }
372:
1.6 veillard 373: if (i + 10 > buffer_size) {
374: int index = out - buffer;
375:
376: growBuffer();
377: out = &buffer[index];
378: }
1.3 httpng 379: }
1.7 veillard 380: *out++ = 0;
1.3 httpng 381: return(buffer);
1.1 httpng 382: }
383:
384: /*
1.2 httpng 385: * xmlEncodeEntities : do a global encoding of a string, replacing the
1.11 daniel 386: * basic content with their entities form.
1.12 daniel 387: * TODO !!!! rewite !!!
1.1 httpng 388: */
1.2 httpng 389: CHAR *xmlEncodeEntities(xmlDocPtr doc, const CHAR *input) {
1.7 veillard 390: const CHAR *cur = input;
1.3 httpng 391: CHAR *out = buffer;
392:
393: if (buffer == NULL) {
394: buffer_size = 1000;
395: buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
396: if (buffer == NULL) {
397: perror("malloc failed");
398: exit(1);
399: }
400: out = buffer;
401: }
1.6 veillard 402: while (*cur != '\0') {
403: if (out - buffer > buffer_size - 100) {
404: int index = out - buffer;
405:
406: growBuffer();
407: out = &buffer[index];
408: }
409:
410: /*
1.7 veillard 411: * By default one have to encode at least '<', '>', '"' and '&' !
412: * One could try a better encoding using the entities defined and
413: * used as a compression code !!!.
1.6 veillard 414: */
415: if (*cur == '<') {
416: *out++ = '&';
417: *out++ = 'l';
418: *out++ = 't';
419: *out++ = ';';
1.7 veillard 420: } else if (*cur == '>') {
421: *out++ = '&';
422: *out++ = 'g';
423: *out++ = 't';
424: *out++ = ';';
1.6 veillard 425: } else if (*cur == '&') {
426: *out++ = '&';
427: *out++ = 'a';
428: *out++ = 'm';
429: *out++ = 'p';
1.7 veillard 430: *out++ = ';';
431: } else if (*cur == '"') {
432: *out++ = '&';
433: *out++ = 'q';
434: *out++ = 'u';
435: *out++ = 'o';
436: *out++ = 't';
437: *out++ = ';';
438: } else if (*cur == '\'') {
439: *out++ = '&';
440: *out++ = 'a';
441: *out++ = 'p';
442: *out++ = 'o';
443: *out++ = 's';
1.6 veillard 444: *out++ = ';';
445: } else {
446: /*
447: * default case, just copy !
448: */
449: *out++ = *cur;
450: }
451: cur++;
452: }
453: *out++ = 0;
454: return(buffer);
1.2 httpng 455: }
456:
457: /*
458: * xmlCreateEntitiesTable : create and initialize an enmpty hash table
459: */
460: xmlEntitiesTablePtr xmlCreateEntitiesTable(void) {
461: xmlEntitiesTablePtr ret;
1.1 httpng 462:
1.2 httpng 463: ret = (xmlEntitiesTablePtr)
464: malloc(sizeof(xmlEntitiesTable));
1.1 httpng 465: if (ret == NULL) {
1.2 httpng 466: fprintf(stderr, "xmlCreateEntitiesTable : malloc(%d) failed\n",
467: sizeof(xmlEntitiesTable));
468: return(NULL);
469: }
470: ret->max_entities = XML_MIN_ENTITIES_TABLE;
471: ret->nb_entities = 0;
472: ret->table = (xmlEntityPtr )
473: malloc(ret->max_entities * sizeof(xmlEntity));
474: if (ret == NULL) {
475: fprintf(stderr, "xmlCreateEntitiesTable : malloc(%d) failed\n",
476: ret->max_entities * sizeof(xmlEntity));
477: free(ret);
1.1 httpng 478: return(NULL);
479: }
480: return(ret);
481: }
482:
483: /*
1.2 httpng 484: * xmlFreeEntitiesTable : clean up and free an entities hash table.
1.1 httpng 485: */
1.2 httpng 486: void xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
1.1 httpng 487: int i;
488:
489: if (table == NULL) return;
490:
1.2 httpng 491: for (i = 0;i < table->nb_entities;i++) {
492: xmlFreeEntity(&table->table[i]);
1.1 httpng 493: }
1.2 httpng 494: free(table->table);
1.1 httpng 495: free(table);
496: }
497:
1.13 daniel 498: /*
499: * Dump the content of an entity table to the document output.
500: */
501: void xmlDumpEntitiesTable(xmlEntitiesTablePtr table) {
1.14 ! daniel 502: int i;
! 503: xmlEntityPtr cur;
! 504:
! 505: if (table == NULL) return;
! 506:
! 507: for (i = 0;i < table->nb_entities;i++) {
! 508: cur = &table->table[i];
! 509: switch (cur->type) {
! 510: case XML_INTERNAL_GENERAL_ENTITY:
! 511: xmlBufferWriteChar("<!ENTITY ");
! 512: xmlBufferWriteCHAR(cur->name);
! 513: xmlBufferWriteChar(" \"");
! 514: xmlBufferWriteCHAR(cur->content);
! 515: xmlBufferWriteChar("\">\n");
! 516: break;
! 517: case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
! 518: xmlBufferWriteChar("<!ENTITY ");
! 519: xmlBufferWriteCHAR(cur->name);
! 520: if (cur->ExternalID != NULL) {
! 521: xmlBufferWriteChar(" PUBLIC \"");
! 522: xmlBufferWriteCHAR(cur->ExternalID);
! 523: xmlBufferWriteChar("\" \"");
! 524: xmlBufferWriteCHAR(cur->SystemID);
! 525: xmlBufferWriteChar("\"");
! 526: } else {
! 527: xmlBufferWriteChar(" SYSTEM \"");
! 528: xmlBufferWriteCHAR(cur->SystemID);
! 529: xmlBufferWriteChar("\"");
! 530: }
! 531: xmlBufferWriteChar(">\n");
! 532: break;
! 533: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
! 534: xmlBufferWriteChar("<!ENTITY ");
! 535: xmlBufferWriteCHAR(cur->name);
! 536: if (cur->ExternalID != NULL) {
! 537: xmlBufferWriteChar(" PUBLIC \"");
! 538: xmlBufferWriteCHAR(cur->ExternalID);
! 539: xmlBufferWriteChar("\" \"");
! 540: xmlBufferWriteCHAR(cur->SystemID);
! 541: xmlBufferWriteChar("\"");
! 542: } else {
! 543: xmlBufferWriteChar(" SYSTEM \"");
! 544: xmlBufferWriteCHAR(cur->SystemID);
! 545: xmlBufferWriteChar("\"");
! 546: }
! 547: if (cur->content != NULL) { /* Should be true ! */
! 548: xmlBufferWriteChar(" NDATA ");
! 549: xmlBufferWriteCHAR(cur->content);
! 550: }
! 551: xmlBufferWriteChar(">\n");
! 552: break;
! 553: case XML_INTERNAL_PARAMETER_ENTITY:
! 554: xmlBufferWriteChar("<!ENTITY % ");
! 555: xmlBufferWriteCHAR(cur->name);
! 556: xmlBufferWriteChar(" \"");
! 557: xmlBufferWriteCHAR(cur->content);
! 558: xmlBufferWriteChar("\">\n");
! 559: break;
! 560: case XML_EXTERNAL_PARAMETER_ENTITY:
! 561: xmlBufferWriteChar("<!ENTITY % ");
! 562: xmlBufferWriteCHAR(cur->name);
! 563: if (cur->ExternalID != NULL) {
! 564: xmlBufferWriteChar(" PUBLIC \"");
! 565: xmlBufferWriteCHAR(cur->ExternalID);
! 566: xmlBufferWriteChar("\" \"");
! 567: xmlBufferWriteCHAR(cur->SystemID);
! 568: xmlBufferWriteChar("\"");
! 569: } else {
! 570: xmlBufferWriteChar(" SYSTEM \"");
! 571: xmlBufferWriteCHAR(cur->SystemID);
! 572: xmlBufferWriteChar("\"");
! 573: }
! 574: xmlBufferWriteChar(">\n");
! 575: break;
! 576: default:
! 577: fprintf(stderr,
! 578: "xmlDumpEntitiesTable: internal: unknown type %d\n",
! 579: cur->type);
! 580: }
! 581: }
1.13 daniel 582: }
Webmaster