upload tizen1.0 source
[external/libxml2.git] / entities.c
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 "&quot;", 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 "&#x25;", 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"