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