Annotation of XML/entities.c, revision 1.53
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:
1.42 daniel 9: #ifdef WIN32
10: #include "win32config.h"
11: #else
1.37 daniel 12: #include "config.h"
13: #endif
14:
1.1 httpng 15: #include <stdio.h>
1.37 daniel 16: #include <string.h>
17: #ifdef HAVE_STDLIB_H
1.17 daniel 18: #include <stdlib.h>
1.37 daniel 19: #endif
1.36 daniel 20: #include "xmlmemory.h"
1.1 httpng 21: #include "entities.h"
1.41 daniel 22: #include "parser.h"
1.1 httpng 23:
24: /*
1.15 daniel 25: * The XML predefined entities.
26: */
27:
28: struct xmlPredefinedEntityValue {
29: const char *name;
30: const char *value;
31: };
32: struct xmlPredefinedEntityValue xmlPredefinedEntityValues[] = {
33: { "lt", "<" },
34: { "gt", ">" },
35: { "apos", "'" },
36: { "quot", "\"" },
37: { "amp", "&" }
38: };
39:
40: xmlEntitiesTablePtr xmlPredefinedEntities = NULL;
41:
42: /*
1.2 httpng 43: * xmlFreeEntity : clean-up an entity record.
1.1 httpng 44: */
1.2 httpng 45: void xmlFreeEntity(xmlEntityPtr entity) {
46: if (entity == NULL) return;
47:
1.52 daniel 48: if (entity->children)
49: xmlFreeNodeList(entity->children);
1.11 daniel 50: if (entity->name != NULL)
1.36 daniel 51: xmlFree((char *) entity->name);
1.14 daniel 52: if (entity->ExternalID != NULL)
1.36 daniel 53: xmlFree((char *) entity->ExternalID);
1.14 daniel 54: if (entity->SystemID != NULL)
1.36 daniel 55: xmlFree((char *) entity->SystemID);
1.14 daniel 56: if (entity->content != NULL)
1.36 daniel 57: xmlFree((char *) entity->content);
1.27 daniel 58: if (entity->orig != NULL)
1.36 daniel 59: xmlFree((char *) entity->orig);
1.14 daniel 60: memset(entity, -1, sizeof(xmlEntity));
1.51 daniel 61: xmlFree(entity);
1.2 httpng 62: }
1.1 httpng 63:
64: /*
1.22 daniel 65: * xmlAddEntity : register a new entity for an entities table.
1.1 httpng 66: */
1.51 daniel 67: static xmlEntityPtr
1.38 daniel 68: xmlAddEntity(xmlEntitiesTablePtr table, const xmlChar *name, int type,
69: const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) {
1.2 httpng 70: int i;
1.51 daniel 71: xmlEntityPtr ret;
1.1 httpng 72:
1.2 httpng 73: for (i = 0;i < table->nb_entities;i++) {
1.51 daniel 74: ret = table->table[i];
75: if (!xmlStrcmp(ret->name, name)) {
1.13 daniel 76: /*
77: * The entity is already defined in this Dtd, the spec says to NOT
78: * override it ... Is it worth a Warning ??? !!!
1.33 daniel 79: * Not having a cprinting context this seems hard ...
1.13 daniel 80: */
1.30 daniel 81: if (((type == XML_INTERNAL_PARAMETER_ENTITY) ||
82: (type == XML_EXTERNAL_PARAMETER_ENTITY)) &&
1.51 daniel 83: ((ret->etype == XML_INTERNAL_PARAMETER_ENTITY) ||
84: (ret->etype == XML_EXTERNAL_PARAMETER_ENTITY)))
85: return(NULL);
1.30 daniel 86: else
87: if (((type != XML_INTERNAL_PARAMETER_ENTITY) &&
88: (type != XML_EXTERNAL_PARAMETER_ENTITY)) &&
1.51 daniel 89: ((ret->etype != XML_INTERNAL_PARAMETER_ENTITY) &&
90: (ret->etype != XML_EXTERNAL_PARAMETER_ENTITY)))
91: return(NULL);
1.7 veillard 92: }
1.2 httpng 93: }
94: if (table->nb_entities >= table->max_entities) {
95: /*
96: * need more elements.
97: */
98: table->max_entities *= 2;
1.51 daniel 99: table->table = (xmlEntityPtr *)
100: xmlRealloc(table->table,
101: table->max_entities * sizeof(xmlEntityPtr));
1.29 daniel 102: if (table->table == NULL) {
1.2 httpng 103: perror("realloc failed");
1.51 daniel 104: return(NULL);
1.2 httpng 105: }
106: }
1.51 daniel 107: ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
108: if (ret == NULL) {
109: fprintf(stderr, "xmlAddEntity: out of memory\n");
110: return(NULL);
111: }
112: memset(ret, 0, sizeof(xmlEntity));
113: ret->type = XML_ENTITY_DECL;
114: table->table[table->nb_entities] = ret;
115:
116: /*
117: * fill the structure.
118: */
119: ret->name = xmlStrdup(name);
120: ret->etype = type;
1.13 daniel 121: if (ExternalID != NULL)
1.51 daniel 122: ret->ExternalID = xmlStrdup(ExternalID);
1.13 daniel 123: if (SystemID != NULL)
1.51 daniel 124: ret->SystemID = xmlStrdup(SystemID);
1.43 daniel 125: if (content != NULL) {
1.51 daniel 126: ret->length = xmlStrlen(content);
127: ret->content = xmlStrndup(content, ret->length);
1.43 daniel 128: } else {
1.51 daniel 129: ret->length = 0;
130: ret->content = NULL;
1.43 daniel 131: }
1.51 daniel 132: ret->orig = NULL;
1.2 httpng 133: table->nb_entities++;
1.51 daniel 134:
135: return(ret);
1.2 httpng 136: }
1.1 httpng 137:
1.22 daniel 138: /**
139: * xmlInitializePredefinedEntities:
140: *
141: * Set up the predefined entities.
1.15 daniel 142: */
143: void xmlInitializePredefinedEntities(void) {
144: int i;
1.38 daniel 145: xmlChar name[50];
146: xmlChar value[50];
1.15 daniel 147: const char *in;
1.38 daniel 148: xmlChar *out;
1.15 daniel 149:
150: if (xmlPredefinedEntities != NULL) return;
151:
152: xmlPredefinedEntities = xmlCreateEntitiesTable();
153: for (i = 0;i < sizeof(xmlPredefinedEntityValues) /
154: sizeof(xmlPredefinedEntityValues[0]);i++) {
155: in = xmlPredefinedEntityValues[i].name;
156: out = &name[0];
1.38 daniel 157: for (;(*out++ = (xmlChar) *in);)in++;
1.15 daniel 158: in = xmlPredefinedEntityValues[i].value;
159: out = &value[0];
1.38 daniel 160: for (;(*out++ = (xmlChar) *in);)in++;
161: xmlAddEntity(xmlPredefinedEntities, (const xmlChar *) &name[0],
1.18 daniel 162: XML_INTERNAL_PREDEFINED_ENTITY, NULL, NULL,
1.15 daniel 163: &value[0]);
164: }
165: }
1.17 daniel 166:
167: /**
1.40 daniel 168: * xmlCleanupPredefinedEntities:
169: *
170: * Cleanup up the predefined entities table.
171: */
172: void xmlCleanupPredefinedEntities(void) {
173: if (xmlPredefinedEntities == NULL) return;
174:
175: xmlFreeEntitiesTable(xmlPredefinedEntities);
176: xmlPredefinedEntities = NULL;
177: }
178:
179: /**
1.17 daniel 180: * xmlGetPredefinedEntity:
181: * @name: the entity name
182: *
183: * Check whether this name is an predefined entity.
184: *
1.24 daniel 185: * Returns NULL if not, othervise the entity
1.17 daniel 186: */
187: xmlEntityPtr
1.38 daniel 188: xmlGetPredefinedEntity(const xmlChar *name) {
1.17 daniel 189: int i;
190: xmlEntityPtr cur;
191:
192: if (xmlPredefinedEntities == NULL)
193: xmlInitializePredefinedEntities();
194: for (i = 0;i < xmlPredefinedEntities->nb_entities;i++) {
1.51 daniel 195: cur = xmlPredefinedEntities->table[i];
1.17 daniel 196: if (!xmlStrcmp(cur->name, name)) return(cur);
197: }
198: return(NULL);
199: }
200:
1.22 daniel 201: /**
202: * xmlAddDtdEntity:
203: * @doc: the document
204: * @name: the entity name
205: * @type: the entity type XML_xxx_yyy_ENTITY
206: * @ExternalID: the entity external ID if available
207: * @SystemID: the entity system ID if available
208: * @content: the entity content
209: *
1.51 daniel 210: * Register a new entity for this document DTD external subset.
211: *
212: * Returns a pointer to the entity or NULL in case of error
1.1 httpng 213: */
1.51 daniel 214: xmlEntityPtr
1.38 daniel 215: xmlAddDtdEntity(xmlDocPtr doc, const xmlChar *name, int type,
1.51 daniel 216: const xmlChar *ExternalID, const xmlChar *SystemID,
217: const xmlChar *content) {
1.2 httpng 218: xmlEntitiesTablePtr table;
1.51 daniel 219: xmlEntityPtr ret;
220: xmlDtdPtr dtd;
1.1 httpng 221:
1.51 daniel 222: if (doc == NULL) {
223: fprintf(stderr,
224: "xmlAddDtdEntity: doc == NULL !\n");
225: return(NULL);
226: }
1.22 daniel 227: if (doc->extSubset == NULL) {
228: fprintf(stderr,
229: "xmlAddDtdEntity: document without external subset !\n");
1.51 daniel 230: return(NULL);
1.16 daniel 231: }
1.51 daniel 232: dtd = doc->extSubset;
233: table = (xmlEntitiesTablePtr) dtd->entities;
1.2 httpng 234: if (table == NULL) {
235: table = xmlCreateEntitiesTable();
1.51 daniel 236: dtd->entities = table;
1.1 httpng 237: }
1.51 daniel 238: ret = xmlAddEntity(table, name, type, ExternalID, SystemID, content);
239: if (ret == NULL) return(NULL);
240:
241: /*
242: * Link it to the Dtd
243: */
244: ret->parent = dtd;
245: ret->doc = dtd->doc;
246: if (dtd->last == NULL) {
247: dtd->children = dtd->last = (xmlNodePtr) ret;
248: } else {
249: dtd->last->next = (xmlNodePtr) ret;
250: ret->prev = dtd->last;
251: dtd->last = (xmlNodePtr) ret;
252: }
253: return(ret);
1.1 httpng 254: }
255:
1.22 daniel 256: /**
257: * xmlAddDocEntity:
258: * @doc: the document
259: * @name: the entity name
260: * @type: the entity type XML_xxx_yyy_ENTITY
261: * @ExternalID: the entity external ID if available
262: * @SystemID: the entity system ID if available
263: * @content: the entity content
264: *
265: * Register a new entity for this document.
1.51 daniel 266: *
267: * Returns a pointer to the entity or NULL in case of error
1.1 httpng 268: */
1.51 daniel 269: xmlEntityPtr
1.38 daniel 270: xmlAddDocEntity(xmlDocPtr doc, const xmlChar *name, int type,
1.51 daniel 271: const xmlChar *ExternalID, const xmlChar *SystemID,
272: const xmlChar *content) {
1.16 daniel 273: xmlEntitiesTablePtr table;
1.51 daniel 274: xmlEntityPtr ret;
275: xmlDtdPtr dtd;
1.16 daniel 276:
1.22 daniel 277: if (doc == NULL) {
278: fprintf(stderr,
279: "xmlAddDocEntity: document is NULL !\n");
1.51 daniel 280: return(NULL);
1.22 daniel 281: }
282: if (doc->intSubset == NULL) {
283: fprintf(stderr,
284: "xmlAddDtdEntity: document without internal subset !\n");
1.51 daniel 285: return(NULL);
1.22 daniel 286: }
1.51 daniel 287: dtd = doc->intSubset;
1.22 daniel 288: table = (xmlEntitiesTablePtr) doc->intSubset->entities;
1.16 daniel 289: if (table == NULL) {
290: table = xmlCreateEntitiesTable();
1.22 daniel 291: doc->intSubset->entities = table;
1.2 httpng 292: }
1.51 daniel 293: ret = xmlAddEntity(table, name, type, ExternalID, SystemID, content);
294: if (ret == NULL) return(NULL);
295:
296: /*
297: * Link it to the Dtd
298: */
299: ret->parent = dtd;
300: ret->doc = dtd->doc;
301: if (dtd->last == NULL) {
302: dtd->children = dtd->last = (xmlNodePtr) ret;
303: } else {
304: dtd->last->next = (xmlNodePtr) ret;
305: ret->prev = dtd->last;
306: dtd->last = (xmlNodePtr) ret;
307: }
308: return(ret);
1.1 httpng 309: }
310:
1.22 daniel 311: /**
1.30 daniel 312: * xmlGetParameterEntity:
313: * @doc: the document referencing the entity
314: * @name: the entity name
315: *
316: * Do an entity lookup in the internal and external subsets and
317: * returns the corresponding parameter entity, if found.
318: *
319: * Returns A pointer to the entity structure or NULL if not found.
320: */
321: xmlEntityPtr
1.38 daniel 322: xmlGetParameterEntity(xmlDocPtr doc, const xmlChar *name) {
1.30 daniel 323: int i;
324: xmlEntityPtr cur;
325: xmlEntitiesTablePtr table;
326:
327: if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
328: table = (xmlEntitiesTablePtr) doc->intSubset->entities;
329: for (i = 0;i < table->nb_entities;i++) {
1.51 daniel 330: cur = table->table[i];
1.49 daniel 331: if (((cur->etype == XML_INTERNAL_PARAMETER_ENTITY) ||
332: (cur->etype == XML_EXTERNAL_PARAMETER_ENTITY)) &&
1.30 daniel 333: (!xmlStrcmp(cur->name, name))) return(cur);
334: }
335: }
336: if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
337: table = (xmlEntitiesTablePtr) doc->extSubset->entities;
338: for (i = 0;i < table->nb_entities;i++) {
1.51 daniel 339: cur = table->table[i];
1.49 daniel 340: if (((cur->etype == XML_INTERNAL_PARAMETER_ENTITY) ||
341: (cur->etype == XML_EXTERNAL_PARAMETER_ENTITY)) &&
1.30 daniel 342: (!xmlStrcmp(cur->name, name))) return(cur);
343: }
344: }
1.35 daniel 345: if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
346: table = (xmlEntitiesTablePtr) doc->extSubset->entities;
347: for (i = 0;i < table->nb_entities;i++) {
1.51 daniel 348: cur = table->table[i];
1.49 daniel 349: if (((cur->etype == XML_INTERNAL_PARAMETER_ENTITY) ||
350: (cur->etype == XML_EXTERNAL_PARAMETER_ENTITY)) &&
1.35 daniel 351: (!xmlStrcmp(cur->name, name))) return(cur);
352: }
353: }
1.30 daniel 354: return(NULL);
355: }
356:
357: /**
1.22 daniel 358: * xmlGetDtdEntity:
359: * @doc: the document referencing the entity
360: * @name: the entity name
361: *
362: * Do an entity lookup in the Dtd entity hash table and
363: * returns the corresponding entity, if found.
364: *
1.24 daniel 365: * Returns A pointer to the entity structure or NULL if not found.
1.1 httpng 366: */
1.22 daniel 367: xmlEntityPtr
1.38 daniel 368: xmlGetDtdEntity(xmlDocPtr doc, const xmlChar *name) {
1.2 httpng 369: int i;
370: xmlEntityPtr cur;
371: xmlEntitiesTablePtr table;
372:
1.22 daniel 373: if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
374: table = (xmlEntitiesTablePtr) doc->extSubset->entities;
1.15 daniel 375: for (i = 0;i < table->nb_entities;i++) {
1.51 daniel 376: cur = table->table[i];
1.49 daniel 377: if ((cur->etype != XML_INTERNAL_PARAMETER_ENTITY) &&
378: (cur->etype != XML_EXTERNAL_PARAMETER_ENTITY) &&
1.30 daniel 379: (!xmlStrcmp(cur->name, name))) return(cur);
1.15 daniel 380: }
381: }
1.7 veillard 382: return(NULL);
1.3 httpng 383: }
384:
1.22 daniel 385: /**
386: * xmlGetDocEntity:
387: * @doc: the document referencing the entity
388: * @name: the entity name
389: *
390: * Do an entity lookup in the document entity hash table and
391: * returns the corrsponding entity, otherwise a lookup is done
392: * in the predefined entities too.
393: *
1.24 daniel 394: * Returns A pointer to the entity structure or NULL if not found.
1.14 daniel 395: */
1.22 daniel 396: xmlEntityPtr
1.38 daniel 397: xmlGetDocEntity(xmlDocPtr doc, const xmlChar *name) {
1.14 daniel 398: int i;
1.16 daniel 399: xmlEntityPtr cur;
1.14 daniel 400: xmlEntitiesTablePtr table;
401:
1.22 daniel 402: if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
403: table = (xmlEntitiesTablePtr) doc->intSubset->entities;
1.16 daniel 404: for (i = 0;i < table->nb_entities;i++) {
1.51 daniel 405: cur = table->table[i];
1.49 daniel 406: if ((cur->etype != XML_INTERNAL_PARAMETER_ENTITY) &&
407: (cur->etype != XML_EXTERNAL_PARAMETER_ENTITY) &&
1.30 daniel 408: (!xmlStrcmp(cur->name, name))) return(cur);
1.16 daniel 409: }
410: }
1.34 daniel 411: if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
412: table = (xmlEntitiesTablePtr) doc->extSubset->entities;
413: for (i = 0;i < table->nb_entities;i++) {
1.51 daniel 414: cur = table->table[i];
1.49 daniel 415: if ((cur->etype != XML_INTERNAL_PARAMETER_ENTITY) &&
416: (cur->etype != XML_EXTERNAL_PARAMETER_ENTITY) &&
1.34 daniel 417: (!xmlStrcmp(cur->name, name))) return(cur);
418: }
419: }
1.15 daniel 420: if (xmlPredefinedEntities == NULL)
421: xmlInitializePredefinedEntities();
1.16 daniel 422: table = xmlPredefinedEntities;
423: for (i = 0;i < table->nb_entities;i++) {
1.51 daniel 424: cur = table->table[i];
1.49 daniel 425: if ((cur->etype != XML_INTERNAL_PARAMETER_ENTITY) &&
426: (cur->etype != XML_EXTERNAL_PARAMETER_ENTITY) &&
1.30 daniel 427: (!xmlStrcmp(cur->name, name))) return(cur);
1.14 daniel 428: }
429:
430: return(NULL);
1.1 httpng 431: }
432:
433: /*
1.21 daniel 434: * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
435: * | [#x10000-#x10FFFF]
436: * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
437: */
438: #define IS_CHAR(c) \
439: (((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) || \
440: (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF)))
441:
1.28 daniel 442: /*
443: * A buffer used for converting entities to their equivalent and back.
444: */
445: static int buffer_size = 0;
1.38 daniel 446: static xmlChar *buffer = NULL;
1.28 daniel 447:
1.44 daniel 448: int growBuffer(void) {
1.28 daniel 449: buffer_size *= 2;
1.38 daniel 450: buffer = (xmlChar *) xmlRealloc(buffer, buffer_size * sizeof(xmlChar));
1.28 daniel 451: if (buffer == NULL) {
452: perror("realloc failed");
1.44 daniel 453: return(-1);
1.28 daniel 454: }
1.44 daniel 455: return(0);
1.28 daniel 456: }
457:
458:
1.22 daniel 459: /**
460: * xmlEncodeEntities:
461: * @doc: the document containing the string
462: * @input: A string to convert to XML.
463: *
464: * Do a global encoding of a string, replacing the predefined entities
465: * and non ASCII values with their entities and CharRef counterparts.
466: *
1.33 daniel 467: * TODO: remove xmlEncodeEntities, once we are not afraid of breaking binary
468: * compatibility
1.28 daniel 469: *
470: * People must migrate their code to xmlEncodeEntitiesReentrant !
1.31 daniel 471: * This routine will issue a warning when encountered.
1.28 daniel 472: *
473: * Returns A newly allocated string with the substitution done.
474: */
1.38 daniel 475: const xmlChar *
476: xmlEncodeEntities(xmlDocPtr doc, const xmlChar *input) {
477: const xmlChar *cur = input;
478: xmlChar *out = buffer;
1.31 daniel 479: static int warning = 1;
1.39 daniel 480: int html = 0;
481:
1.31 daniel 482:
483: if (warning) {
484: fprintf(stderr, "Deprecated API xmlEncodeEntities() used\n");
485: fprintf(stderr, " change code to use xmlEncodeEntitiesReentrant()\n");
486: warning = 0;
487: }
1.28 daniel 488:
489: if (input == NULL) return(NULL);
1.39 daniel 490: if (doc != NULL)
491: html = (doc->type == XML_HTML_DOCUMENT_NODE);
492:
1.28 daniel 493: if (buffer == NULL) {
494: buffer_size = 1000;
1.38 daniel 495: buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
1.28 daniel 496: if (buffer == NULL) {
497: perror("malloc failed");
1.44 daniel 498: return(NULL);
1.28 daniel 499: }
500: out = buffer;
501: }
502: while (*cur != '\0') {
503: if (out - buffer > buffer_size - 100) {
504: int index = out - buffer;
505:
506: growBuffer();
507: out = &buffer[index];
508: }
509:
510: /*
511: * By default one have to encode at least '<', '>', '"' and '&' !
512: */
513: if (*cur == '<') {
514: *out++ = '&';
515: *out++ = 'l';
516: *out++ = 't';
517: *out++ = ';';
518: } else if (*cur == '>') {
519: *out++ = '&';
520: *out++ = 'g';
521: *out++ = 't';
522: *out++ = ';';
523: } else if (*cur == '&') {
524: *out++ = '&';
525: *out++ = 'a';
526: *out++ = 'm';
527: *out++ = 'p';
528: *out++ = ';';
529: } else if (*cur == '"') {
530: *out++ = '&';
531: *out++ = 'q';
532: *out++ = 'u';
533: *out++ = 'o';
534: *out++ = 't';
535: *out++ = ';';
1.39 daniel 536: } else if ((*cur == '\'') && (!html)) {
1.28 daniel 537: *out++ = '&';
538: *out++ = 'a';
539: *out++ = 'p';
540: *out++ = 'o';
541: *out++ = 's';
542: *out++ = ';';
543: } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
544: (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
545: /*
546: * default case, just copy !
547: */
548: *out++ = *cur;
549: #ifndef USE_UTF_8
1.38 daniel 550: } else if ((sizeof(xmlChar) == 1) && (*cur >= 0x80)) {
1.28 daniel 551: char buf[10], *ptr;
552: #ifdef HAVE_SNPRINTF
553: snprintf(buf, 9, "&#%d;", *cur);
554: #else
555: sprintf(buf, "&#%d;", *cur);
556: #endif
557: ptr = buf;
558: while (*ptr != 0) *out++ = *ptr++;
559: #endif
560: } else if (IS_CHAR(*cur)) {
561: char buf[10], *ptr;
562:
563: #ifdef HAVE_SNPRINTF
564: snprintf(buf, 9, "&#%d;", *cur);
565: #else
566: sprintf(buf, "&#%d;", *cur);
567: #endif
568: ptr = buf;
569: while (*ptr != 0) *out++ = *ptr++;
570: }
571: #if 0
572: else {
573: /*
574: * default case, this is not a valid char !
575: * Skip it...
576: */
577: fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
578: }
579: #endif
580: cur++;
581: }
582: *out++ = 0;
583: return(buffer);
584: }
585:
586: /*
587: * Macro used to grow the current buffer.
588: */
589: #define growBufferReentrant() { \
590: buffer_size *= 2; \
1.44 daniel 591: buffer = (xmlChar *) \
592: xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \
1.28 daniel 593: if (buffer == NULL) { \
594: perror("realloc failed"); \
1.44 daniel 595: return(NULL); \
1.28 daniel 596: } \
597: }
598:
599:
600: /**
601: * xmlEncodeEntitiesReentrant:
602: * @doc: the document containing the string
603: * @input: A string to convert to XML.
604: *
605: * Do a global encoding of a string, replacing the predefined entities
606: * and non ASCII values with their entities and CharRef counterparts.
607: * Contrary to xmlEncodeEntities, this routine is reentrant, and result
608: * must be deallocated.
609: *
610: * TODO !!!! Once moved to UTF-8 internal encoding, the encoding of non-ascii
611: * get erroneous.
612: *
1.24 daniel 613: * Returns A newly allocated string with the substitution done.
1.1 httpng 614: */
1.38 daniel 615: xmlChar *
616: xmlEncodeEntitiesReentrant(xmlDocPtr doc, const xmlChar *input) {
617: const xmlChar *cur = input;
618: xmlChar *buffer = NULL;
619: xmlChar *out = NULL;
1.26 daniel 620: int buffer_size = 0;
1.39 daniel 621: int html = 0;
1.3 httpng 622:
1.19 daniel 623: if (input == NULL) return(NULL);
1.39 daniel 624: if (doc != NULL)
625: html = (doc->type == XML_HTML_DOCUMENT_NODE);
1.26 daniel 626:
627: /*
628: * allocate an translation buffer.
629: */
630: buffer_size = 1000;
1.38 daniel 631: buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
1.3 httpng 632: if (buffer == NULL) {
1.26 daniel 633: perror("malloc failed");
1.44 daniel 634: return(NULL);
1.3 httpng 635: }
1.26 daniel 636: out = buffer;
637:
1.6 veillard 638: while (*cur != '\0') {
639: if (out - buffer > buffer_size - 100) {
640: int index = out - buffer;
641:
1.28 daniel 642: growBufferReentrant();
1.6 veillard 643: out = &buffer[index];
644: }
645:
646: /*
1.7 veillard 647: * By default one have to encode at least '<', '>', '"' and '&' !
1.6 veillard 648: */
649: if (*cur == '<') {
650: *out++ = '&';
651: *out++ = 'l';
652: *out++ = 't';
653: *out++ = ';';
1.7 veillard 654: } else if (*cur == '>') {
655: *out++ = '&';
656: *out++ = 'g';
657: *out++ = 't';
658: *out++ = ';';
1.6 veillard 659: } else if (*cur == '&') {
660: *out++ = '&';
661: *out++ = 'a';
662: *out++ = 'm';
663: *out++ = 'p';
1.7 veillard 664: *out++ = ';';
665: } else if (*cur == '"') {
666: *out++ = '&';
667: *out++ = 'q';
668: *out++ = 'u';
669: *out++ = 'o';
670: *out++ = 't';
671: *out++ = ';';
1.53 ! daniel 672: #if 0
1.39 daniel 673: } else if ((*cur == '\'') && (!html)) {
1.7 veillard 674: *out++ = '&';
675: *out++ = 'a';
676: *out++ = 'p';
677: *out++ = 'o';
678: *out++ = 's';
1.6 veillard 679: *out++ = ';';
1.53 ! daniel 680: #endif
1.21 daniel 681: } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
682: (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
683: /*
684: * default case, just copy !
685: */
686: *out++ = *cur;
1.46 daniel 687: } else if (*cur >= 0x80) {
688: if (html) {
1.50 daniel 689: char buf[15], *ptr;
1.46 daniel 690:
691: /*
692: * TODO: improve by searching in html40EntitiesTable
693: */
1.19 daniel 694: #ifdef HAVE_SNPRINTF
1.45 daniel 695: snprintf(buf, 9, "&#%d;", *cur);
1.19 daniel 696: #else
1.45 daniel 697: sprintf(buf, "&#%d;", *cur);
1.19 daniel 698: #endif
1.45 daniel 699: ptr = buf;
700: while (*ptr != 0) *out++ = *ptr++;
1.46 daniel 701: } else if (doc->encoding != NULL) {
702: /*
703: * TODO !!!
704: */
705: *out++ = *cur;
706: } else {
707: /*
708: * We assume we have UTF-8 input.
709: */
710: char buf[10], *ptr;
1.48 daniel 711: int val = 0, l = 1;
1.46 daniel 712:
713: if (*cur < 0xC0) {
714: fprintf(stderr,
715: "xmlEncodeEntitiesReentrant : input not UTF-8\n");
716: doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
717: #ifdef HAVE_SNPRINTF
718: snprintf(buf, 9, "&#%d;", *cur);
719: #else
720: sprintf(buf, "&#%d;", *cur);
721: #endif
722: ptr = buf;
723: while (*ptr != 0) *out++ = *ptr++;
724: continue;
725: } else if (*cur < 0xE0) {
726: val = (cur[0]) & 0x1F;
727: val <<= 6;
728: val |= (cur[1]) & 0x3F;
729: l = 2;
730: } else if (*cur < 0xF0) {
731: val = (cur[0]) & 0x0F;
732: val <<= 6;
733: val |= (cur[1]) & 0x3F;
734: val <<= 6;
735: val |= (cur[2]) & 0x3F;
736: l = 3;
737: } else if (*cur < 0xF8) {
738: val = (cur[0]) & 0x07;
739: val <<= 6;
740: val |= (cur[1]) & 0x3F;
741: val <<= 6;
742: val |= (cur[2]) & 0x3F;
743: val <<= 6;
744: val |= (cur[3]) & 0x3F;
745: l = 4;
746: }
747: if ((l == 1) || (!IS_CHAR(val))) {
748: fprintf(stderr,
749: "xmlEncodeEntitiesReentrant : char out of range\n");
750: doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
751: #ifdef HAVE_SNPRINTF
752: snprintf(buf, 9, "&#%d;", *cur);
753: #else
754: sprintf(buf, "&#%d;", *cur);
755: #endif
756: ptr = buf;
757: while (*ptr != 0) *out++ = *ptr++;
758: cur++;
759: continue;
760: }
761: /*
762: * We could do multiple things here. Just save as a char ref
763: */
764: #ifdef HAVE_SNPRINTF
1.50 daniel 765: snprintf(buf, 14, "&#x%X;", val);
1.46 daniel 766: #else
1.50 daniel 767: sprintf(buf, "&#x%X;", val);
1.46 daniel 768: #endif
1.50 daniel 769: buf[14] = 0;
1.47 daniel 770: ptr = buf;
771: while (*ptr != 0) *out++ = *ptr++;
772: cur += l;
773: continue;
1.45 daniel 774: }
1.21 daniel 775: } else if (IS_CHAR(*cur)) {
1.20 daniel 776: char buf[10], *ptr;
777:
778: #ifdef HAVE_SNPRINTF
779: snprintf(buf, 9, "&#%d;", *cur);
780: #else
781: sprintf(buf, "&#%d;", *cur);
782: #endif
783: ptr = buf;
784: while (*ptr != 0) *out++ = *ptr++;
1.21 daniel 785: }
786: #if 0
787: else {
1.6 veillard 788: /*
1.21 daniel 789: * default case, this is not a valid char !
790: * Skip it...
1.6 veillard 791: */
1.21 daniel 792: fprintf(stderr, "xmlEncodeEntities: invalid char %d\n", (int) *cur);
1.6 veillard 793: }
1.21 daniel 794: #endif
1.6 veillard 795: cur++;
796: }
797: *out++ = 0;
798: return(buffer);
1.2 httpng 799: }
800:
1.22 daniel 801: /**
802: * xmlCreateEntitiesTable:
803: *
804: * create and initialize an empty entities hash table.
805: *
1.24 daniel 806: * Returns the xmlEntitiesTablePtr just created or NULL in case of error.
1.2 httpng 807: */
1.22 daniel 808: xmlEntitiesTablePtr
809: xmlCreateEntitiesTable(void) {
1.2 httpng 810: xmlEntitiesTablePtr ret;
1.1 httpng 811:
1.2 httpng 812: ret = (xmlEntitiesTablePtr)
1.36 daniel 813: xmlMalloc(sizeof(xmlEntitiesTable));
1.1 httpng 814: if (ret == NULL) {
1.36 daniel 815: fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
1.28 daniel 816: (long)sizeof(xmlEntitiesTable));
1.2 httpng 817: return(NULL);
818: }
819: ret->max_entities = XML_MIN_ENTITIES_TABLE;
820: ret->nb_entities = 0;
1.51 daniel 821: ret->table = (xmlEntityPtr *)
822: xmlMalloc(ret->max_entities * sizeof(xmlEntityPtr));
1.2 httpng 823: if (ret == NULL) {
1.36 daniel 824: fprintf(stderr, "xmlCreateEntitiesTable : xmlMalloc(%ld) failed\n",
1.51 daniel 825: ret->max_entities * (long)sizeof(xmlEntityPtr));
1.36 daniel 826: xmlFree(ret);
1.1 httpng 827: return(NULL);
828: }
829: return(ret);
830: }
831:
1.22 daniel 832: /**
833: * xmlFreeEntitiesTable:
834: * @table: An entity table
835: *
836: * Deallocate the memory used by an entities hash table.
1.1 httpng 837: */
1.22 daniel 838: void
839: xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
1.1 httpng 840: int i;
841:
842: if (table == NULL) return;
843:
1.2 httpng 844: for (i = 0;i < table->nb_entities;i++) {
1.51 daniel 845: xmlFreeEntity(table->table[i]);
1.1 httpng 846: }
1.36 daniel 847: xmlFree(table->table);
848: xmlFree(table);
1.1 httpng 849: }
850:
1.22 daniel 851: /**
852: * xmlCopyEntitiesTable:
853: * @table: An entity table
854: *
855: * Build a copy of an entity table.
856: *
1.24 daniel 857: * Returns the new xmlEntitiesTablePtr or NULL in case of error.
1.22 daniel 858: */
859: xmlEntitiesTablePtr
860: xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
861: xmlEntitiesTablePtr ret;
862: xmlEntityPtr cur, ent;
863: int i;
864:
1.36 daniel 865: ret = (xmlEntitiesTablePtr) xmlMalloc(sizeof(xmlEntitiesTable));
1.22 daniel 866: if (ret == NULL) {
867: fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
868: return(NULL);
869: }
1.51 daniel 870: ret->table = (xmlEntityPtr *) xmlMalloc(table->max_entities *
871: sizeof(xmlEntityPtr));
1.22 daniel 872: if (ret->table == NULL) {
873: fprintf(stderr, "xmlCopyEntitiesTable: out of memory !\n");
1.36 daniel 874: xmlFree(ret);
1.22 daniel 875: return(NULL);
876: }
877: ret->max_entities = table->max_entities;
878: ret->nb_entities = table->nb_entities;
879: for (i = 0;i < ret->nb_entities;i++) {
1.51 daniel 880: cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
881: if (cur == NULL) {
882: fprintf(stderr, "xmlCopyEntityTable: out of memory !\n");
883: xmlFree(ret);
884: xmlFree(ret->table);
885: return(NULL);
886: }
887: memset(cur, 0, sizeof(xmlEntity));
888: cur->type = XML_ELEMENT_DECL;
889: ret->table[i] = cur;
890: ent = table->table[i];
891:
1.49 daniel 892: cur->etype = ent->etype;
1.22 daniel 893: if (ent->name != NULL)
894: cur->name = xmlStrdup(ent->name);
895: if (ent->ExternalID != NULL)
896: cur->ExternalID = xmlStrdup(ent->ExternalID);
897: if (ent->SystemID != NULL)
898: cur->SystemID = xmlStrdup(ent->SystemID);
899: if (ent->content != NULL)
900: cur->content = xmlStrdup(ent->content);
1.27 daniel 901: if (ent->orig != NULL)
902: cur->orig = xmlStrdup(ent->orig);
1.22 daniel 903: }
904: return(ret);
905: }
906:
907: /**
1.53 ! daniel 908: * xmlDumpEntityDecl:
! 909: * @buf: An XML buffer.
! 910: * @ent: An entity table
! 911: *
! 912: * This will dump the content of the entity table as an XML DTD definition
! 913: */
! 914: void
! 915: xmlDumpEntityDecl(xmlBufferPtr buf, xmlEntityPtr ent) {
! 916: switch (ent->etype) {
! 917: case XML_INTERNAL_GENERAL_ENTITY:
! 918: xmlBufferWriteChar(buf, "<!ENTITY ");
! 919: xmlBufferWriteCHAR(buf, ent->name);
! 920: xmlBufferWriteChar(buf, " ");
! 921: if (ent->orig != NULL)
! 922: xmlBufferWriteQuotedString(buf, ent->orig);
! 923: else
! 924: xmlBufferWriteQuotedString(buf, ent->content);
! 925: xmlBufferWriteChar(buf, ">\n");
! 926: break;
! 927: case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
! 928: xmlBufferWriteChar(buf, "<!ENTITY ");
! 929: xmlBufferWriteCHAR(buf, ent->name);
! 930: if (ent->ExternalID != NULL) {
! 931: xmlBufferWriteChar(buf, " PUBLIC ");
! 932: xmlBufferWriteQuotedString(buf, ent->ExternalID);
! 933: xmlBufferWriteChar(buf, " ");
! 934: xmlBufferWriteQuotedString(buf, ent->SystemID);
! 935: } else {
! 936: xmlBufferWriteChar(buf, " SYSTEM ");
! 937: xmlBufferWriteQuotedString(buf, ent->SystemID);
! 938: }
! 939: xmlBufferWriteChar(buf, ">\n");
! 940: break;
! 941: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
! 942: xmlBufferWriteChar(buf, "<!ENTITY ");
! 943: xmlBufferWriteCHAR(buf, ent->name);
! 944: if (ent->ExternalID != NULL) {
! 945: xmlBufferWriteChar(buf, " PUBLIC ");
! 946: xmlBufferWriteQuotedString(buf, ent->ExternalID);
! 947: xmlBufferWriteChar(buf, " ");
! 948: xmlBufferWriteQuotedString(buf, ent->SystemID);
! 949: } else {
! 950: xmlBufferWriteChar(buf, " SYSTEM ");
! 951: xmlBufferWriteQuotedString(buf, ent->SystemID);
! 952: }
! 953: if (ent->content != NULL) { /* Should be true ! */
! 954: xmlBufferWriteChar(buf, " NDATA ");
! 955: if (ent->orig != NULL)
! 956: xmlBufferWriteCHAR(buf, ent->orig);
! 957: else
! 958: xmlBufferWriteCHAR(buf, ent->content);
! 959: }
! 960: xmlBufferWriteChar(buf, ">\n");
! 961: break;
! 962: case XML_INTERNAL_PARAMETER_ENTITY:
! 963: xmlBufferWriteChar(buf, "<!ENTITY % ");
! 964: xmlBufferWriteCHAR(buf, ent->name);
! 965: xmlBufferWriteChar(buf, " ");
! 966: if (ent->orig == NULL)
! 967: xmlBufferWriteQuotedString(buf, ent->content);
! 968: else
! 969: xmlBufferWriteQuotedString(buf, ent->orig);
! 970: xmlBufferWriteChar(buf, ">\n");
! 971: break;
! 972: case XML_EXTERNAL_PARAMETER_ENTITY:
! 973: xmlBufferWriteChar(buf, "<!ENTITY % ");
! 974: xmlBufferWriteCHAR(buf, ent->name);
! 975: if (ent->ExternalID != NULL) {
! 976: xmlBufferWriteChar(buf, " PUBLIC ");
! 977: xmlBufferWriteQuotedString(buf, ent->ExternalID);
! 978: xmlBufferWriteChar(buf, " ");
! 979: xmlBufferWriteQuotedString(buf, ent->SystemID);
! 980: } else {
! 981: xmlBufferWriteChar(buf, " SYSTEM ");
! 982: xmlBufferWriteQuotedString(buf, ent->SystemID);
! 983: }
! 984: xmlBufferWriteChar(buf, ">\n");
! 985: break;
! 986: default:
! 987: fprintf(stderr,
! 988: "xmlDumpEntitiesTable: internal: unknown type %d\n",
! 989: ent->etype);
! 990: }
! 991: }
! 992:
! 993: /**
1.22 daniel 994: * xmlDumpEntitiesTable:
1.25 daniel 995: * @buf: An XML buffer.
1.22 daniel 996: * @table: An entity table
997: *
998: * This will dump the content of the entity table as an XML DTD definition
1.13 daniel 999: */
1.22 daniel 1000: void
1.25 daniel 1001: xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
1.14 daniel 1002: int i;
1003: xmlEntityPtr cur;
1004:
1005: if (table == NULL) return;
1006:
1007: for (i = 0;i < table->nb_entities;i++) {
1.51 daniel 1008: cur = table->table[i];
1.53 ! daniel 1009: xmlDumpEntityDecl(buf, cur);
1.14 daniel 1010: }
1.13 daniel 1011: }
Webmaster