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