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