Annotation of XML/entities.c, revision 1.24
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.23 daniel 6: * Daniel.Veillard@w3.org
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.
1.22 daniel 34: *
35: * TODO: remove this, this helps performances but forbid reentrancy in a
36: * stupid way.
1.3 httpng 37: */
1.14 daniel 38: static int buffer_size = 0;
1.6 veillard 39: static CHAR *buffer = NULL;
1.3 httpng 40:
41: void growBuffer(void) {
42: buffer_size *= 2;
43: buffer = (CHAR *) realloc(buffer, buffer_size * sizeof(CHAR));
44: if (buffer == NULL) {
45: perror("realloc failed");
46: exit(1);
47: }
48: }
49:
50: /*
1.2 httpng 51: * xmlFreeEntity : clean-up an entity record.
1.1 httpng 52: */
1.2 httpng 53: void xmlFreeEntity(xmlEntityPtr entity) {
54: if (entity == NULL) return;
55:
1.11 daniel 56: if (entity->name != NULL)
57: free((char *) entity->name);
1.14 daniel 58: if (entity->ExternalID != NULL)
59: free((char *) entity->ExternalID);
60: if (entity->SystemID != NULL)
61: free((char *) entity->SystemID);
62: if (entity->content != NULL)
63: free((char *) entity->content);
64: memset(entity, -1, sizeof(xmlEntity));
1.2 httpng 65: }
1.1 httpng 66:
67: /*
1.22 daniel 68: * xmlAddEntity : register a new entity for an entities table.
1.13 daniel 69: *
70: * TODO !!! We should check here that the combination of type
71: * ExternalID and SystemID is valid.
1.1 httpng 72: */
1.22 daniel 73: static void
74: xmlAddEntity(xmlEntitiesTablePtr table, const CHAR *name, int type,
1.13 daniel 75: const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
1.2 httpng 76: int i;
77: xmlEntityPtr cur;
1.14 daniel 78: int len;
1.1 httpng 79:
1.2 httpng 80: for (i = 0;i < table->nb_entities;i++) {
81: cur = &table->table[i];
1.11 daniel 82: if (!xmlStrcmp(cur->name, name)) {
1.13 daniel 83: /*
84: * The entity is already defined in this Dtd, the spec says to NOT
85: * override it ... Is it worth a Warning ??? !!!
86: */
87: return;
1.7 veillard 88: }
1.2 httpng 89: }
90: if (table->nb_entities >= table->max_entities) {
91: /*
92: * need more elements.
93: */
94: table->max_entities *= 2;
95: table->table = (xmlEntityPtr)
96: realloc(table->table, table->max_entities * sizeof(xmlEntity));
97: if (table->table) {
98: perror("realloc failed");
99: exit(1);
100: }
101: }
102: cur = &table->table[table->nb_entities];
1.11 daniel 103: cur->name = xmlStrdup(name);
1.14 daniel 104: for (len = 0;name[0] != 0;name++)len++;
105: cur->len = len;
1.13 daniel 106: cur->type = type;
107: if (ExternalID != NULL)
108: cur->ExternalID = xmlStrdup(ExternalID);
1.14 daniel 109: else
110: cur->ExternalID = NULL;
1.13 daniel 111: if (SystemID != NULL)
1.14 daniel 112: cur->SystemID = xmlStrdup(SystemID);
113: else
114: cur->SystemID = NULL;
1.13 daniel 115: if (content != NULL)
116: cur->content = xmlStrdup(content);
1.14 daniel 117: else
118: cur->content = NULL;
1.2 httpng 119: table->nb_entities++;
120: }
1.1 httpng 121:
1.22 daniel 122: /**
123: * xmlInitializePredefinedEntities:
124: *
125: * Set up the predefined entities.
1.15 daniel 126: */
127: void xmlInitializePredefinedEntities(void) {
128: int i;
129: CHAR name[50];
130: CHAR value[50];
131: const char *in;
132: CHAR *out;
133:
134: if (xmlPredefinedEntities != NULL) return;
135:
136: xmlPredefinedEntities = xmlCreateEntitiesTable();
137: for (i = 0;i < sizeof(xmlPredefinedEntityValues) /
138: sizeof(xmlPredefinedEntityValues[0]);i++) {
139: in = xmlPredefinedEntityValues[i].name;
140: out = &name[0];
141: for (;(*out++ = (CHAR) *in);)in++;
142: in = xmlPredefinedEntityValues[i].value;
143: out = &value[0];
144: for (;(*out++ = (CHAR) *in);)in++;
145: xmlAddEntity(xmlPredefinedEntities, (const CHAR *) &name[0],
1.18 daniel 146: XML_INTERNAL_PREDEFINED_ENTITY, NULL, NULL,
1.15 daniel 147: &value[0]);
148: }
149: }
1.17 daniel 150:
151: /**
152: * xmlGetPredefinedEntity:
153: * @name: the entity name
154: *
155: * Check whether this name is an predefined entity.
156: *
1.24 ! daniel 157: * Returns NULL if not, othervise the entity
1.17 daniel 158: */
159: xmlEntityPtr
160: xmlGetPredefinedEntity(const CHAR *name) {
161: int i;
162: xmlEntityPtr cur;
163:
164: if (xmlPredefinedEntities == NULL)
165: xmlInitializePredefinedEntities();
166: for (i = 0;i < xmlPredefinedEntities->nb_entities;i++) {
167: cur = &xmlPredefinedEntities->table[i];
168: if (!xmlStrcmp(cur->name, name)) return(cur);
169: }
170: return(NULL);
171: }
172:
1.22 daniel 173: /**
174: * xmlAddDtdEntity:
175: * @doc: the document
176: * @name: the entity name
177: * @type: the entity type XML_xxx_yyy_ENTITY
178: * @ExternalID: the entity external ID if available
179: * @SystemID: the entity system ID if available
180: * @content: the entity content
181: *
182: * Register a new entity for this document DTD.
1.1 httpng 183: */
1.22 daniel 184: void
185: xmlAddDtdEntity(xmlDocPtr doc, const CHAR *name, int type,
1.13 daniel 186: const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
1.2 httpng 187: xmlEntitiesTablePtr table;
1.1 httpng 188:
1.22 daniel 189: if (doc->extSubset == NULL) {
190: fprintf(stderr,
191: "xmlAddDtdEntity: document without external subset !\n");
1.16 daniel 192: return;
193: }
1.22 daniel 194: table = (xmlEntitiesTablePtr) doc->extSubset->entities;
1.2 httpng 195: if (table == NULL) {
196: table = xmlCreateEntitiesTable();
1.22 daniel 197: doc->extSubset->entities = table;
1.1 httpng 198: }
1.13 daniel 199: xmlAddEntity(table, name, type, ExternalID, SystemID, content);
1.1 httpng 200: }
201:
1.22 daniel 202: /**
203: * xmlAddDocEntity:
204: * @doc: the document
205: * @name: the entity name
206: * @type: the entity type XML_xxx_yyy_ENTITY
207: * @ExternalID: the entity external ID if available
208: * @SystemID: the entity system ID if available
209: * @content: the entity content
210: *
211: * Register a new entity for this document.
1.1 httpng 212: */
1.22 daniel 213: void
214: xmlAddDocEntity(xmlDocPtr doc, const CHAR *name, int type,
1.13 daniel 215: const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
1.16 daniel 216: xmlEntitiesTablePtr table;
217:
1.22 daniel 218: if (doc == NULL) {
219: fprintf(stderr,
220: "xmlAddDocEntity: document is NULL !\n");
221: return;
222: }
223: if (doc->intSubset == NULL) {
224: fprintf(stderr,
225: "xmlAddDtdEntity: document without internal subset !\n");
226: return;
227: }
228: table = (xmlEntitiesTablePtr) doc->intSubset->entities;
1.16 daniel 229: if (table == NULL) {
230: table = xmlCreateEntitiesTable();
1.22 daniel 231: doc->intSubset->entities = table;
1.2 httpng 232: }
1.22 daniel 233: xmlAddEntity(table, name, type, ExternalID, SystemID, content);
1.1 httpng 234: }
235:
1.22 daniel 236: /**
237: * xmlGetDtdEntity:
238: * @doc: the document referencing the entity
239: * @name: the entity name
240: *
241: * Do an entity lookup in the Dtd entity hash table and
242: * returns the corresponding entity, if found.
243: *
1.24 ! daniel 244: * Returns A pointer to the entity structure or NULL if not found.
1.1 httpng 245: */
1.22 daniel 246: xmlEntityPtr
247: xmlGetDtdEntity(xmlDocPtr doc, const CHAR *name) {
1.2 httpng 248: int i;
249: xmlEntityPtr cur;
250: xmlEntitiesTablePtr table;
251:
1.22 daniel 252: if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
253: table = (xmlEntitiesTablePtr) doc->extSubset->entities;
1.15 daniel 254: for (i = 0;i < table->nb_entities;i++) {
255: cur = &table->table[i];
256: if (!xmlStrcmp(cur->name, name)) return(cur);
257: }
258: }
1.7 veillard 259: return(NULL);
1.3 httpng 260: }
261:
1.22 daniel 262: /**
263: * xmlGetDocEntity:
264: * @doc: the document referencing the entity
265: * @name: the entity name
266: *
267: * Do an entity lookup in the document entity hash table and
268: * returns the corrsponding entity, otherwise a lookup is done
269: * in the predefined entities too.
270: *
1.24 ! daniel 271: * Returns A pointer to the entity structure or NULL if not found.
1.14 daniel 272: */
1.22 daniel 273: xmlEntityPtr
274: xmlGetDocEntity(xmlDocPtr doc, const CHAR *name) {
1.14 daniel 275: int i;
1.16 daniel 276: xmlEntityPtr cur;
1.14 daniel 277: xmlEntitiesTablePtr table;
278:
1.22 daniel 279: if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
280: table = (xmlEntitiesTablePtr) doc->intSubset->entities;
1.16 daniel 281: for (i = 0;i < table->nb_entities;i++) {
282: cur = &table->table[i];
283: if (!xmlStrcmp(cur->name, name)) return(cur);
284: }
285: }
1.15 daniel 286: if (xmlPredefinedEntities == NULL)
287: xmlInitializePredefinedEntities();
1.16 daniel 288: table = xmlPredefinedEntities;
289: for (i = 0;i < table->nb_entities;i++) {
290: cur = &table->table[i];
291: if (!xmlStrcmp(cur->name, name)) return(cur);
1.14 daniel 292: }
293:
294: return(NULL);
1.1 httpng 295: }
296:
297: /*
1.21 daniel 298: * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
299: * | [#x10000-#x10FFFF]
300: * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
301: */
302: #define IS_CHAR(c) \
303: (((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) || \
304: (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF)))
305:
1.22 daniel 306: /**
307: * xmlEncodeEntities:
308: * @doc: the document containing the string
309: * @input: A string to convert to XML.
310: *
311: * Do a global encoding of a string, replacing the predefined entities
312: * and non ASCII values with their entities and CharRef counterparts.
313: *
1.19 daniel 314: * TODO !!!! Once moved to UTF-8 internal encoding, the encoding of non-ascii
315: * get erroneous.
1.22 daniel 316: *
317: * TODO This routine is not reentrant and this will be changed, the interface
318: * should not be modified though.
319: *
1.24 ! daniel 320: * Returns A newly allocated string with the substitution done.
1.1 httpng 321: */
1.22 daniel 322: CHAR *
323: xmlEncodeEntities(xmlDocPtr doc, const CHAR *input) {
1.7 veillard 324: const CHAR *cur = input;
1.3 httpng 325: CHAR *out = buffer;
326:
1.19 daniel 327: if (input == NULL) return(NULL);
1.3 httpng 328: if (buffer == NULL) {
329: buffer_size = 1000;
330: buffer = (CHAR *) malloc(buffer_size * sizeof(CHAR));
331: if (buffer == NULL) {
332: perror("malloc failed");
333: exit(1);
334: }
335: out = buffer;
336: }
1.6 veillard 337: while (*cur != '\0') {
338: if (out - buffer > buffer_size - 100) {
339: int index = out - buffer;
340:
341: growBuffer();
342: out = &buffer[index];
343: }
344:
345: /*
1.7 veillard 346: * By default one have to encode at least '<', '>', '"' and '&' !
1.6 veillard 347: */
348: if (*cur == '<') {
349: *out++ = '&';
350: *out++ = 'l';
351: *out++ = 't';
352: *out++ = ';';
1.7 veillard 353: } else if (*cur == '>') {
354: *out++ = '&';
355: *out++ = 'g';
356: *out++ = 't';
357: *out++ = ';';
1.6 veillard 358: } else if (*cur == '&') {
359: *out++ = '&';
360: *out++ = 'a';
361: *out++ = 'm';
362: *out++ = 'p';
1.7 veillard 363: *out++ = ';';
364: } else if (*cur == '"') {
365: *out++ = '&';
366: *out++ = 'q';
367: *out++ = 'u';
368: *out++ = 'o';
369: *out++ = 't';
370: *out++ = ';';
371: } else if (*cur == '\'') {
372: *out++ = '&';
373: *out++ = 'a';
374: *out++ = 'p';
375: *out++ = 'o';
376: *out++ = 's';
1.6 veillard 377: *out++ = ';';
1.21 daniel 378: } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
379: (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
380: /*
381: * default case, just copy !
382: */
383: *out++ = *cur;
1.19 daniel 384: #ifndef USE_UTF_8
385: } else if ((sizeof(CHAR) == 1) && (*cur >= 0x80)) {
386: char buf[10], *ptr;
387: #ifdef HAVE_SNPRINTF
388: snprintf(buf, 9, "&#%d;", *cur);
389: #else
390: sprintf(buf, "&#%d;", *cur);
391: #endif
392: ptr = buf;
393: while (*ptr != 0) *out++ = *ptr++;
394: #endif
1.21 daniel 395: } else if (IS_CHAR(*cur)) {
1.20 daniel 396: char buf[10], *ptr;
397:
398: #ifdef HAVE_SNPRINTF
399: snprintf(buf, 9, "&#%d;", *cur);
400: #else
401: sprintf(buf, "&#%d;", *cur);
402: #endif
403: ptr = buf;
404: while (*ptr != 0) *out++ = *ptr++;
1.21 daniel 405: }
406: #if 0
407: else {
1.6 veillard 408: /*
1.21 daniel 409: * default case, this is not a valid char !
410: * Skip it...
1.6 veillard 411: */
1.21 daniel 412: fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
1.6 veillard 413: }
1.21 daniel 414: #endif
1.6 veillard 415: cur++;
416: }
417: *out++ = 0;
418: return(buffer);
1.2 httpng 419: }
420:
1.22 daniel 421: /**
422: * xmlCreateEntitiesTable:
423: *
424: * create and initialize an empty entities hash table.
425: *
1.24 ! daniel 426: * Returns the xmlEntitiesTablePtr just created or NULL in case of error.
1.2 httpng 427: */
1.22 daniel 428: xmlEntitiesTablePtr
429: xmlCreateEntitiesTable(void) {
1.2 httpng 430: xmlEntitiesTablePtr ret;
1.1 httpng 431:
1.2 httpng 432: ret = (xmlEntitiesTablePtr)
433: malloc(sizeof(xmlEntitiesTable));
1.1 httpng 434: if (ret == NULL) {
1.2 httpng 435: fprintf(stderr, "xmlCreateEntitiesTable : malloc(%d) failed\n",
436: sizeof(xmlEntitiesTable));
437: return(NULL);
438: }
439: ret->max_entities = XML_MIN_ENTITIES_TABLE;
440: ret->nb_entities = 0;
441: ret->table = (xmlEntityPtr )
442: malloc(ret->max_entities * sizeof(xmlEntity));
443: if (ret == NULL) {
444: fprintf(stderr, "xmlCreateEntitiesTable : malloc(%d) failed\n",
445: ret->max_entities * sizeof(xmlEntity));
446: free(ret);
1.1 httpng 447: return(NULL);
448: }
449: return(ret);
450: }
451:
1.22 daniel 452: /**
453: * xmlFreeEntitiesTable:
454: * @table: An entity table
455: *
456: * Deallocate the memory used by an entities hash table.
1.1 httpng 457: */
1.22 daniel 458: void
459: xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
1.1 httpng 460: int i;
461:
462: if (table == NULL) return;
463:
1.2 httpng 464: for (i = 0;i < table->nb_entities;i++) {
465: xmlFreeEntity(&table->table[i]);
1.1 httpng 466: }
1.2 httpng 467: free(table->table);
1.1 httpng 468: free(table);
469: }
470:
1.22 daniel 471: /**
472: * xmlCopyEntitiesTable:
473: * @table: An entity table
474: *
475: * Build a copy of an entity table.
476: *
1.24 ! daniel 477: * Returns the new xmlEntitiesTablePtr or NULL in case of error.
1.22 daniel 478: */
479: xmlEntitiesTablePtr
480: xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
481: xmlEntitiesTablePtr ret;
482: xmlEntityPtr cur, ent;
483: int i;
484:
485: ret = (xmlEntitiesTablePtr) malloc(sizeof(xmlEntitiesTable));
486: if (ret == NULL) {
487: fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
488: return(NULL);
489: }
490: ret->table = (xmlEntityPtr) malloc(table->max_entities *
491: sizeof(xmlEntity));
492: if (ret->table == NULL) {
493: fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
494: free(ret);
495: return(NULL);
496: }
497: ret->max_entities = table->max_entities;
498: ret->nb_entities = table->nb_entities;
499: for (i = 0;i < ret->nb_entities;i++) {
500: cur = &ret->table[i];
501: ent = &table->table[i];
502: cur->len = ent->len;
503: cur->type = ent->type;
504: if (ent->name != NULL)
505: cur->name = xmlStrdup(ent->name);
506: else
507: cur->name = NULL;
508: if (ent->ExternalID != NULL)
509: cur->ExternalID = xmlStrdup(ent->ExternalID);
510: else
511: cur->ExternalID = NULL;
512: if (ent->SystemID != NULL)
513: cur->SystemID = xmlStrdup(ent->SystemID);
514: else
515: cur->SystemID = NULL;
516: if (ent->content != NULL)
517: cur->content = xmlStrdup(ent->content);
518: else
519: cur->content = NULL;
520: }
521: return(ret);
522: }
523:
524: /**
525: * xmlDumpEntitiesTable:
526: * @table: An entity table
527: *
528: * This will dump the content of the entity table as an XML DTD definition
529: *
530: * NOTE: TODO an extra parameter allowing a reentant implementation will
531: * be added.
1.13 daniel 532: */
1.22 daniel 533: void
534: xmlDumpEntitiesTable(xmlEntitiesTablePtr table) {
1.14 daniel 535: int i;
536: xmlEntityPtr cur;
537:
538: if (table == NULL) return;
539:
540: for (i = 0;i < table->nb_entities;i++) {
541: cur = &table->table[i];
542: switch (cur->type) {
543: case XML_INTERNAL_GENERAL_ENTITY:
544: xmlBufferWriteChar("<!ENTITY ");
545: xmlBufferWriteCHAR(cur->name);
546: xmlBufferWriteChar(" \"");
547: xmlBufferWriteCHAR(cur->content);
548: xmlBufferWriteChar("\">\n");
549: break;
550: case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
551: xmlBufferWriteChar("<!ENTITY ");
552: xmlBufferWriteCHAR(cur->name);
553: if (cur->ExternalID != NULL) {
554: xmlBufferWriteChar(" PUBLIC \"");
555: xmlBufferWriteCHAR(cur->ExternalID);
556: xmlBufferWriteChar("\" \"");
557: xmlBufferWriteCHAR(cur->SystemID);
558: xmlBufferWriteChar("\"");
559: } else {
560: xmlBufferWriteChar(" SYSTEM \"");
561: xmlBufferWriteCHAR(cur->SystemID);
562: xmlBufferWriteChar("\"");
563: }
564: xmlBufferWriteChar(">\n");
565: break;
566: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
567: xmlBufferWriteChar("<!ENTITY ");
568: xmlBufferWriteCHAR(cur->name);
569: if (cur->ExternalID != NULL) {
570: xmlBufferWriteChar(" PUBLIC \"");
571: xmlBufferWriteCHAR(cur->ExternalID);
572: xmlBufferWriteChar("\" \"");
573: xmlBufferWriteCHAR(cur->SystemID);
574: xmlBufferWriteChar("\"");
575: } else {
576: xmlBufferWriteChar(" SYSTEM \"");
577: xmlBufferWriteCHAR(cur->SystemID);
578: xmlBufferWriteChar("\"");
579: }
580: if (cur->content != NULL) { /* Should be true ! */
581: xmlBufferWriteChar(" NDATA ");
582: xmlBufferWriteCHAR(cur->content);
583: }
584: xmlBufferWriteChar(">\n");
585: break;
586: case XML_INTERNAL_PARAMETER_ENTITY:
587: xmlBufferWriteChar("<!ENTITY % ");
588: xmlBufferWriteCHAR(cur->name);
589: xmlBufferWriteChar(" \"");
590: xmlBufferWriteCHAR(cur->content);
591: xmlBufferWriteChar("\">\n");
592: break;
593: case XML_EXTERNAL_PARAMETER_ENTITY:
594: xmlBufferWriteChar("<!ENTITY % ");
595: xmlBufferWriteCHAR(cur->name);
596: if (cur->ExternalID != NULL) {
597: xmlBufferWriteChar(" PUBLIC \"");
598: xmlBufferWriteCHAR(cur->ExternalID);
599: xmlBufferWriteChar("\" \"");
600: xmlBufferWriteCHAR(cur->SystemID);
601: xmlBufferWriteChar("\"");
602: } else {
603: xmlBufferWriteChar(" SYSTEM \"");
604: xmlBufferWriteCHAR(cur->SystemID);
605: xmlBufferWriteChar("\"");
606: }
607: xmlBufferWriteChar(">\n");
608: break;
609: default:
610: fprintf(stderr,
611: "xmlDumpEntitiesTable: internal: unknown type %d\n",
612: cur->type);
613: }
614: }
1.13 daniel 615: }
Webmaster