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