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