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