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