xml/libxml2libs/src/libxml2/libxml2_htmltree.c
changeset 0 e35f40988205
equal deleted inserted replaced
-1:000000000000 0:e35f40988205
       
     1 /*
       
     2  * libxml2_htmltree.c : implementation of access function for an HTML tree.
       
     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 #include "xmlenglibxml.h"
       
    12 
       
    13 #include <string.h> /* for memset() only ! */
       
    14 
       
    15 #ifdef HAVE_CTYPE_H
       
    16 #include <ctype.h>
       
    17 #endif
       
    18 #ifdef HAVE_STDLIB_H
       
    19 #include <stdlib.h>
       
    20 #endif
       
    21 
       
    22 #include <stdapis/libxml2/libxml2_xmlmemory.h>
       
    23 #include "libxml2_htmlparser.h"
       
    24 #include "libxml2_htmltree.h"
       
    25 #include <stdapis/libxml2/libxml2_entities.h>
       
    26 #include <stdapis/libxml2/libxml2_valid.h>
       
    27 #include <stdapis/libxml2/libxml2_xmlerror.h>
       
    28 #include "libxml2_xmlerror2.h"
       
    29 #include <stdapis/libxml2/libxml2_xmlsave.h>
       
    30 #include <stdapis/libxml2/libxml2_parserinternals.h>
       
    31 #include <stdapis/libxml2/libxml2_globals.h>
       
    32 #include <stdapis/libxml2/libxml2_uri.h>
       
    33 
       
    34 #ifdef LIBXML_HTML_ENABLED
       
    35 
       
    36 /************************************************************************
       
    37  *                                                                      *
       
    38  *          Getting/Setting encoding meta tags                          *
       
    39  *                                                                      *
       
    40  ************************************************************************/
       
    41 
       
    42 /**
       
    43  * htmlGetMetaEncoding:
       
    44  * @param doc the document
       
    45  *
       
    46  * Encoding definition lookup in the Meta tags
       
    47  *
       
    48  * Returns the current encoding as flagged in the HTML source
       
    49  */
       
    50 const xmlChar *
       
    51 htmlGetMetaEncoding(htmlDocPtr doc) {
       
    52     htmlNodePtr cur;
       
    53     const xmlChar *content;
       
    54     const xmlChar *encoding;
       
    55 
       
    56     if (doc == NULL)
       
    57         return(NULL);
       
    58     cur = doc->children;
       
    59 
       
    60     /*
       
    61      * Search the html
       
    62      */
       
    63     while (cur != NULL) {
       
    64         if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
       
    65             if (xmlStrEqual(cur->name, BAD_CAST"html"))
       
    66                 break;
       
    67             if (xmlStrEqual(cur->name, BAD_CAST"head"))
       
    68                 goto found_head;
       
    69             if (xmlStrEqual(cur->name, BAD_CAST"meta"))
       
    70                 goto found_meta;
       
    71         }
       
    72         cur = cur->next;
       
    73     }
       
    74     if (cur == NULL)
       
    75         return(NULL);
       
    76     cur = cur->children;
       
    77 
       
    78     /*
       
    79      * Search the head
       
    80      */
       
    81     while (cur != NULL) {
       
    82         if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
       
    83             if (xmlStrEqual(cur->name, BAD_CAST"head"))
       
    84                 break;
       
    85             if (xmlStrEqual(cur->name, BAD_CAST"meta"))
       
    86                 goto found_meta;
       
    87         }
       
    88         cur = cur->next;
       
    89     }
       
    90     if (cur == NULL)
       
    91         return(NULL);
       
    92 found_head:
       
    93     cur = cur->children;
       
    94 
       
    95     /*
       
    96      * Search the meta elements
       
    97      */
       
    98 found_meta:
       
    99     while (cur != NULL) {
       
   100         if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
       
   101             if (xmlStrEqual(cur->name, BAD_CAST"meta")) {
       
   102                 xmlAttrPtr attr = cur->properties;
       
   103                 int http;
       
   104                 const xmlChar *value;
       
   105 
       
   106                 content = NULL;
       
   107                 http = 0;
       
   108                 while (attr != NULL) {
       
   109                     if ((attr->children != NULL) &&
       
   110                         (attr->children->type == XML_TEXT_NODE) &&
       
   111                         (attr->children->next == NULL)) {
       
   112                         value = attr->children->content;
       
   113                         if ((!xmlStrcasecmp(attr->name, BAD_CAST"http-equiv"))
       
   114                          && (!xmlStrcasecmp(value, BAD_CAST"Content-Type")))
       
   115                             http = 1;
       
   116                         else if ((value != NULL)
       
   117                          && (!xmlStrcasecmp(attr->name, BAD_CAST"content")))
       
   118                             content = value;
       
   119                         if ((http != 0) && (content != NULL))
       
   120                             goto found_content;
       
   121                     }
       
   122                     attr = attr->next;
       
   123                 }
       
   124             }
       
   125         }
       
   126         cur = cur->next;
       
   127     }
       
   128     return(NULL);
       
   129 
       
   130 found_content:
       
   131     encoding = xmlStrstr(content, BAD_CAST"charset=");
       
   132     if (encoding == NULL)
       
   133         encoding = xmlStrstr(content, BAD_CAST"Charset=");
       
   134     if (encoding == NULL)
       
   135         encoding = xmlStrstr(content, BAD_CAST"CHARSET=");
       
   136     if (encoding != NULL) {
       
   137         encoding += 8;
       
   138     } else {
       
   139         encoding = xmlStrstr(content, BAD_CAST"charset =");
       
   140         if (encoding == NULL)
       
   141             encoding = xmlStrstr(content, BAD_CAST"Charset =");
       
   142         if (encoding == NULL)
       
   143             encoding = xmlStrstr(content, BAD_CAST"CHARSET =");
       
   144         if (encoding != NULL)
       
   145             encoding += 9;
       
   146     }
       
   147     if (encoding != NULL) {
       
   148         while ((*encoding == ' ') || (*encoding == '\t')) encoding++;
       
   149     }
       
   150     return(encoding);
       
   151 }
       
   152 
       
   153 
       
   154 #endif /* LIBXML_HTML_ENABLED */
       
   155 
       
   156 #if defined(LIBXML_HTML_ENABLED) || defined(XMLENGINE_XSLT)
       
   157 /**
       
   158  * htmlSetMetaEncoding:
       
   159  * @param doc the document
       
   160  * @param encoding the encoding string
       
   161  *
       
   162  * Sets the current encoding in the Meta tags
       
   163  * NOTE: this will not change the document content encoding, just
       
   164  * the META flag associated.
       
   165  *
       
   166  * Returns 0 in case of success and -1 in case of error
       
   167  */
       
   168 XMLPUBFUNEXPORT int
       
   169 htmlSetMetaEncoding(htmlDocPtr doc, const xmlChar *encoding) {
       
   170     htmlNodePtr cur, meta;
       
   171     const xmlChar *content;
       
   172     char newcontent[100];
       
   173 	LOAD_GS_SAFE_DOC(doc)
       
   174 
       
   175     if (doc == NULL)
       
   176         return(-1);
       
   177 
       
   178     if (encoding != NULL) {
       
   179         snprintf(newcontent, sizeof(newcontent), "text/html; charset=%s",
       
   180                 encoding);
       
   181         newcontent[sizeof(newcontent) - 1] = 0;
       
   182     }
       
   183 
       
   184     cur = doc->children;
       
   185 
       
   186     /*
       
   187      * Search the html
       
   188      */
       
   189     while (cur != NULL) {
       
   190         if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
       
   191             if (xmlStrcasecmp(cur->name, BAD_CAST"html") == 0)
       
   192                 break;
       
   193             if (xmlStrcasecmp(cur->name, BAD_CAST"head") == 0)
       
   194                 goto found_head;
       
   195             if (xmlStrcasecmp(cur->name, BAD_CAST"meta") == 0)
       
   196                 goto found_meta;
       
   197         }
       
   198         cur = cur->next;
       
   199     }
       
   200     if (cur == NULL)
       
   201         return(-1);
       
   202     cur = cur->children;
       
   203 
       
   204     /*
       
   205      * Search the head
       
   206      */
       
   207     while (cur != NULL) {
       
   208         if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
       
   209             if (xmlStrcasecmp(cur->name, BAD_CAST"head") == 0)
       
   210                 break;
       
   211             if (xmlStrcasecmp(cur->name, BAD_CAST"meta") == 0)
       
   212                 goto found_meta;
       
   213         }
       
   214         cur = cur->next;
       
   215     }
       
   216     if (cur == NULL)
       
   217         return(-1);
       
   218 found_head:
       
   219     if (cur->children == NULL) {
       
   220         if (encoding == NULL)
       
   221             return(0);
       
   222         meta = xmlNewDocNode(doc, NULL, BAD_CAST"meta", NULL);
       
   223         xmlAddChild(cur, meta);
       
   224         xmlNewProp(meta, BAD_CAST"http-equiv", BAD_CAST"Content-Type");
       
   225         xmlNewProp(meta, BAD_CAST"content", BAD_CAST newcontent);
       
   226         if ( OOM_FLAG )     //oom set in xmlNewProp
       
   227             return(-1);
       
   228         return(0);
       
   229     }
       
   230     cur = cur->children;
       
   231 
       
   232 found_meta:
       
   233     if (encoding != NULL) {
       
   234         /*
       
   235          * Create a new Meta element with the right attributes
       
   236          */
       
   237 
       
   238         meta = xmlNewDocNode(doc, NULL, BAD_CAST"meta", NULL);
       
   239         xmlAddPrevSibling(cur, meta);
       
   240         xmlNewProp(meta, BAD_CAST"http-equiv", BAD_CAST"Content-Type");
       
   241         xmlNewProp(meta, BAD_CAST"content", BAD_CAST newcontent);
       
   242     }
       
   243 
       
   244     /*
       
   245      * Search and destroy all the remaining the meta elements carrying
       
   246      * encoding informations
       
   247      */
       
   248     while (cur != NULL) {
       
   249         if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
       
   250             if (xmlStrcasecmp(cur->name, BAD_CAST"meta") == 0) {
       
   251                 xmlAttrPtr attr = cur->properties;
       
   252                 int http;
       
   253                 const xmlChar *value;
       
   254 
       
   255                 content = NULL;
       
   256                 http = 0;
       
   257                 while (attr != NULL) {
       
   258                     if ((attr->children != NULL) &&
       
   259                         (attr->children->type == XML_TEXT_NODE) &&
       
   260                         (attr->children->next == NULL)) {
       
   261                         value = attr->children->content;
       
   262                         if ((!xmlStrcasecmp(attr->name, BAD_CAST"http-equiv"))
       
   263                          && (!xmlStrcasecmp(value, BAD_CAST"Content-Type")))
       
   264                             http = 1;
       
   265                         else
       
   266                         {
       
   267                            if ((value != NULL) &&
       
   268                                 (!xmlStrcasecmp(attr->name, BAD_CAST"content")))
       
   269                               content = value;
       
   270                         }
       
   271                         if ((http != 0) && (content != NULL))
       
   272                             break;
       
   273                     }
       
   274                     attr = attr->next;
       
   275                 }
       
   276                 if ((http != 0) && (content != NULL)) {
       
   277                     meta = cur;
       
   278                     cur = cur->next;
       
   279                     xmlUnlinkNode(meta);
       
   280                     xmlFreeNode(meta);
       
   281                     continue;
       
   282                 }
       
   283 
       
   284             }
       
   285         }
       
   286         cur = cur->next;
       
   287     }
       
   288     return(0);
       
   289 }
       
   290 
       
   291 /**
       
   292  * booleanHTMLAttrs:
       
   293  *
       
   294  * These are the HTML attributes which will be output
       
   295  * in minimized form, i.e. <option selected="selected"> will be
       
   296  * output as <option selected>, as per XSLT 1.0 16.2 "HTML Output Method"
       
   297  *
       
   298  */
       
   299 static const char* const htmlBooleanAttrs[] = {
       
   300   "checked", "compact", "declare", "defer", "disabled", "ismap",
       
   301   "multiple", "nohref", "noresize", "noshade", "nowrap", "readonly",
       
   302   "selected", NULL
       
   303 };
       
   304 
       
   305 
       
   306 /**
       
   307  * htmlIsBooleanAttr:
       
   308  * @param name the name of the attribute to check
       
   309  *
       
   310  * Determine if a given attribute is a boolean attribute.
       
   311  *
       
   312  * returns: false if the attribute is not boolean, true otherwise.
       
   313  */
       
   314 XMLPUBFUNEXPORT int
       
   315 htmlIsBooleanAttr(const xmlChar *name)
       
   316 {
       
   317     int i = 0;
       
   318 
       
   319     while (htmlBooleanAttrs[i] != NULL) {
       
   320         if (xmlStrcasecmp((const xmlChar *)htmlBooleanAttrs[i], name) == 0)
       
   321             return 1;
       
   322         i++;
       
   323     }
       
   324     return 0;
       
   325 }
       
   326 #endif // HTML or XSLT
       
   327 
       
   328 #ifdef LIBXML_HTML_ENABLED
       
   329 
       
   330 #ifdef LIBXML_OUTPUT_ENABLED
       
   331 /************************************************************************
       
   332  *                                                                      *
       
   333  *          Output error handlers                                       *
       
   334  *                                                                      *
       
   335  ************************************************************************/
       
   336 /**
       
   337  * htmlSaveErrMemory:
       
   338  * @param extra extra informations
       
   339  *
       
   340  * Handle an out of memory condition
       
   341  */
       
   342 static void
       
   343 htmlSaveErrMemory(const char *extra)
       
   344 {
       
   345     __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);
       
   346 }
       
   347 
       
   348 /**
       
   349  * htmlSaveErr:
       
   350  * @param code the error number
       
   351  * @param node the location of the error.
       
   352  * @param extra extra informations
       
   353  *
       
   354  * Handle an out of memory condition
       
   355  */
       
   356 static void
       
   357 htmlSaveErr(int code, xmlNodePtr node, const char *extra); // Moved to XSLT-enabled part of the file
       
   358 
       
   359 /************************************************************************
       
   360  *                                                                      *
       
   361  *          Dumping HTML tree content to a simple buffer                *
       
   362  *                                                                      *
       
   363  ************************************************************************/
       
   364 
       
   365 static int
       
   366 htmlNodeDumpFormat(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
       
   367                    int format);
       
   368 
       
   369 /**
       
   370  * htmlNodeDumpFormat:
       
   371  * @param buf the HTML buffer output
       
   372  * @param doc the document
       
   373  * @param cur the current node
       
   374  * @param format should formatting spaces been added
       
   375  *
       
   376  * Dump an HTML node, recursive behaviour,children are printed too.
       
   377  *
       
   378  * Returns the number of byte written or -1 in case of error
       
   379  */
       
   380 static int
       
   381 htmlNodeDumpFormat(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
       
   382                    int format) {
       
   383     unsigned int use;
       
   384     int ret;
       
   385     xmlOutputBufferPtr outbuf;
       
   386 
       
   387     if (cur == NULL) {
       
   388         return (-1);
       
   389     }
       
   390     if (buf == NULL) {
       
   391         return (-1);
       
   392     }
       
   393     outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
       
   394     if (outbuf == NULL) {
       
   395         htmlSaveErrMemory("allocating HTML output buffer");
       
   396         return (-1);
       
   397     }
       
   398     memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
       
   399     outbuf->buffer = buf;
       
   400     outbuf->encoder = NULL;
       
   401     outbuf->writecallback = NULL;
       
   402     outbuf->closecallback = NULL;
       
   403     outbuf->context = NULL;
       
   404     outbuf->written = 0;
       
   405 
       
   406     use = buf->use;
       
   407     htmlNodeDumpFormatOutput(outbuf, doc, cur, NULL, format);
       
   408     xmlFree(outbuf);
       
   409     ret = buf->use - use;
       
   410     return (ret);
       
   411 }
       
   412 
       
   413 /**
       
   414  * htmlNodeDump:
       
   415  * @param buf the HTML buffer output
       
   416  * @param doc the document
       
   417  * @param cur the current node
       
   418  *
       
   419  * Dump an HTML node, recursive behaviour,children are printed too,
       
   420  * and formatting returns are added.
       
   421  *
       
   422  * Returns the number of byte written or -1 in case of error
       
   423  */
       
   424 int
       
   425 htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur) {
       
   426     xmlInitParser();
       
   427 
       
   428     return(htmlNodeDumpFormat(buf, doc, cur, 1));
       
   429 }
       
   430 
       
   431 /**
       
   432  * htmlNodeDumpFileFormat:
       
   433  * @param out the FILE pointer
       
   434  * @param doc the document
       
   435  * @param cur the current node
       
   436  * @param encoding the document encoding
       
   437  * @param format should formatting spaces been added
       
   438  *
       
   439  * Dump an HTML node, recursive behaviour,children are printed too.
       
   440  *
       
   441  
       
   442  *
       
   443  * returns: the number of byte written or -1 in case of failure.
       
   444  */
       
   445 int
       
   446 htmlNodeDumpFileFormat(FILE *out, xmlDocPtr doc,
       
   447                        xmlNodePtr cur, const char *encoding, int format) {
       
   448     xmlOutputBufferPtr buf;
       
   449     xmlCharEncodingHandlerPtr handler = NULL;
       
   450     int ret;
       
   451 
       
   452     xmlInitParser();
       
   453 
       
   454     if (encoding != NULL) {
       
   455         xmlCharEncoding enc;
       
   456 
       
   457         enc = xmlParseCharEncoding(encoding);
       
   458         if (enc != XML_CHAR_ENCODING_UTF8) {
       
   459             handler = xmlFindCharEncodingHandler(encoding);
       
   460             if (handler == NULL)
       
   461                 return(-1);
       
   462         }
       
   463     }
       
   464 
       
   465     /*
       
   466      * Fallback to HTML or ASCII when the encoding is unspecified
       
   467      */
       
   468     if (handler == NULL)
       
   469         handler = xmlFindCharEncodingHandler("HTML");
       
   470     if (handler == NULL)
       
   471         handler = xmlFindCharEncodingHandler("ascii");
       
   472 
       
   473     /*
       
   474      * save the content to a temp buffer.
       
   475      */
       
   476     buf = xmlOutputBufferCreateFile(out, handler);
       
   477     if (buf == NULL) return(0);
       
   478 
       
   479     htmlNodeDumpFormatOutput(buf, doc, cur, encoding, format);
       
   480 
       
   481     ret = xmlOutputBufferClose(buf);
       
   482     return(ret);
       
   483 }
       
   484 
       
   485 /**
       
   486  * htmlNodeDumpFile:
       
   487  * @param out the FILE pointer
       
   488  * @param doc the document
       
   489  * @param cur the current node
       
   490  *
       
   491  * Dump an HTML node, recursive behaviour,children are printed too,
       
   492  * and formatting returns are added.
       
   493  */
       
   494 void
       
   495 htmlNodeDumpFile(FILE *out, xmlDocPtr doc, xmlNodePtr cur) {
       
   496     htmlNodeDumpFileFormat(out, doc, cur, NULL, 1);
       
   497 }
       
   498 
       
   499 /**
       
   500  * htmlDocDumpMemory:
       
   501  * @param cur the document
       
   502  * @param mem OUT: the memory pointer
       
   503  * @param size OUT: the memory length
       
   504  *
       
   505  * Dump an HTML document in memory and return the xmlChar * and it's size.
       
   506  * It's up to the caller to free the memory.
       
   507  */
       
   508 void
       
   509 htmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
       
   510     xmlOutputBufferPtr buf;
       
   511     xmlCharEncodingHandlerPtr handler = NULL;
       
   512     const char *encoding;
       
   513 
       
   514     xmlInitParser();
       
   515 
       
   516     if (cur == NULL) {
       
   517         *mem = NULL;
       
   518         *size = 0;
       
   519         return;
       
   520     }
       
   521 
       
   522     encoding = (const char *) htmlGetMetaEncoding(cur);
       
   523 
       
   524     if (encoding != NULL) {
       
   525         xmlCharEncoding enc;
       
   526 
       
   527         enc = xmlParseCharEncoding(encoding);
       
   528         if (enc != cur->charset) {
       
   529             if (cur->charset != XML_CHAR_ENCODING_UTF8) {
       
   530                 /*
       
   531                  * Not supported yet
       
   532                  */
       
   533                 *mem = NULL;
       
   534                 *size = 0;
       
   535                 return;
       
   536             }
       
   537 
       
   538             handler = xmlFindCharEncodingHandler(encoding);
       
   539             if (handler == NULL) {
       
   540                 *mem = NULL;
       
   541                 *size = 0;
       
   542                 return;
       
   543             }
       
   544         }
       
   545     }
       
   546 
       
   547     /*
       
   548      * Fallback to HTML or ASCII when the encoding is unspecified
       
   549      */
       
   550     if (handler == NULL)
       
   551         handler = xmlFindCharEncodingHandler("HTML");
       
   552     if (handler == NULL)
       
   553         handler = xmlFindCharEncodingHandler("ascii");
       
   554 
       
   555     buf = xmlAllocOutputBuffer(handler);
       
   556     if (buf == NULL) {
       
   557         *mem = NULL;
       
   558         *size = 0;
       
   559         return;
       
   560     }
       
   561 
       
   562     htmlDocContentDumpOutput(buf, cur, NULL);
       
   563     xmlOutputBufferFlush(buf);
       
   564     if (buf->conv != NULL) {
       
   565         *size = buf->conv->use;
       
   566         *mem = xmlStrndup(buf->conv->content, *size);
       
   567     } else {
       
   568         *size = buf->buffer->use;
       
   569         *mem = xmlStrndup(buf->buffer->content, *size);
       
   570     }
       
   571     (void)xmlOutputBufferClose(buf);
       
   572 }
       
   573 
       
   574 
       
   575 /************************************************************************
       
   576  *                                                                      *
       
   577  *          Dumping HTML tree content to an I/O output buffer           *
       
   578  *                                                                      *
       
   579  ************************************************************************/
       
   580 
       
   581 /**
       
   582  * htmlNodeDumpOutput:
       
   583  * @param buf the HTML buffer output
       
   584  * @param doc the document
       
   585  * @param cur the current node
       
   586  * @param encoding the encoding string
       
   587  *
       
   588  * Dump an HTML node, recursive behaviour,children are printed too,
       
   589  * and formatting returns/spaces are added.
       
   590  */
       
   591 void
       
   592 htmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
       
   593                xmlNodePtr cur, const char *encoding) {
       
   594     htmlNodeDumpFormatOutput(buf, doc, cur, encoding, 1);
       
   595 }
       
   596 #endif  /* LIBXML_OUTPUT_ENABLED */
       
   597 #endif  /* defined(LIBXML_HTML_ENABLED) */
       
   598 
       
   599 #if defined(LIBXML_HTML_ENABLED) || defined(XMLENGINE_XSLT)
       
   600 #ifdef LIBXML_OUTPUT_ENABLED
       
   601 /**
       
   602  * htmlSaveErr:
       
   603  * @param code the error number
       
   604  * @param node the location of the error.
       
   605  * @param extra extra informations
       
   606  *
       
   607  * Handle an out of memory condition
       
   608  */
       
   609 static void
       
   610 htmlSaveErr(int code, xmlNodePtr node, const char *extra)
       
   611 {
       
   612     const char *msg = NULL;
       
   613 
       
   614     switch(code) {
       
   615         case XML_SAVE_NOT_UTF8:
       
   616         msg = "string is not in UTF-8";
       
   617         break;
       
   618     case XML_SAVE_CHAR_INVALID:
       
   619         msg = "invalid character value";
       
   620         break;
       
   621     case XML_SAVE_UNKNOWN_ENCODING:
       
   622         msg = "unknown encoding %s";
       
   623         break;
       
   624     case XML_SAVE_NO_DOCTYPE:
       
   625         msg = "HTML has no DOCTYPE";
       
   626         break;
       
   627     default:
       
   628         msg = "unexpected error number";
       
   629     }
       
   630     __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);
       
   631 }
       
   632 
       
   633 /**
       
   634  * htmlDtdDumpOutput:
       
   635  * @param buf the HTML buffer output
       
   636  * @param doc the document
       
   637  * @param encoding the encoding string
       
   638  *
       
   639  
       
   640  *
       
   641  * Dump the HTML document DTD, if any.
       
   642  */
       
   643 static void
       
   644 htmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
       
   645                   const char *encoding ATTRIBUTE_UNUSED) {
       
   646     xmlDtdPtr cur = doc->intSubset;
       
   647 
       
   648     if (cur == NULL) {
       
   649         htmlSaveErr(XML_SAVE_NO_DOCTYPE, (xmlNodePtr) doc, NULL);
       
   650         return;
       
   651     }
       
   652     xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
       
   653     xmlOutputBufferWriteString(buf, (const char *)cur->name);
       
   654     if (cur->ExternalID != NULL) {
       
   655         xmlOutputBufferWriteString(buf, " PUBLIC ");
       
   656         xmlBufferWriteQuotedString(buf->buffer, cur->ExternalID);
       
   657         if (cur->SystemID != NULL) {
       
   658             xmlOutputBufferWriteString(buf, " ");
       
   659             xmlBufferWriteQuotedString(buf->buffer, cur->SystemID);
       
   660         }
       
   661     }  else if (cur->SystemID != NULL) {
       
   662         xmlOutputBufferWriteString(buf, " SYSTEM ");
       
   663         xmlBufferWriteQuotedString(buf->buffer, cur->SystemID);
       
   664     }
       
   665     xmlOutputBufferWriteString(buf, ">\n");
       
   666 }
       
   667 
       
   668 /**
       
   669  * htmlAttrDumpOutput:
       
   670  * @param buf the HTML buffer output
       
   671  * @param doc the document
       
   672  * @param cur the attribute pointer
       
   673  * @param encoding the encoding string
       
   674  *
       
   675  * Dump an HTML attribute
       
   676  */
       
   677 static void
       
   678 htmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
       
   679                    const char *encoding ATTRIBUTE_UNUSED) {
       
   680     xmlChar *value;
       
   681 
       
   682     /*
       
   683      
       
   684      
       
   685      
       
   686      */
       
   687 
       
   688     if (cur == NULL) {
       
   689         return;
       
   690     }
       
   691     xmlOutputBufferWriteString(buf, " ");
       
   692     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
       
   693         xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
       
   694         xmlOutputBufferWriteString(buf, ":");
       
   695     }
       
   696     xmlOutputBufferWriteString(buf, (const char *)cur->name);
       
   697     if ((cur->children != NULL) && (!htmlIsBooleanAttr(cur->name))) {
       
   698         value = xmlNodeListGetString(doc, cur->children, 0);
       
   699         if (value) {
       
   700             xmlOutputBufferWriteString(buf, "=");
       
   701             if ((cur->ns == NULL) && (cur->parent != NULL) &&
       
   702                 (cur->parent->ns == NULL) &&
       
   703                 ((!xmlStrcasecmp(cur->name, BAD_CAST "href")) ||
       
   704                  (!xmlStrcasecmp(cur->name, BAD_CAST "action")) ||
       
   705                  (!xmlStrcasecmp(cur->name, BAD_CAST "src")))) {
       
   706                 xmlChar *escaped;
       
   707                 xmlChar *tmp = value;
       
   708 
       
   709                 while (IS_BLANK_CH(*tmp)) tmp++;
       
   710 
       
   711                 escaped = xmlURIEscapeStr(tmp, BAD_CAST"@/:=?;#%&,+");
       
   712                 if (escaped != NULL) {
       
   713                     xmlBufferWriteQuotedString(buf->buffer, escaped);
       
   714                     xmlFree(escaped);
       
   715                 } else {
       
   716                     xmlBufferWriteQuotedString(buf->buffer, value);
       
   717                 }
       
   718             } else {
       
   719                 xmlBufferWriteQuotedString(buf->buffer, value);
       
   720             }
       
   721             xmlFree(value);
       
   722         } else  {
       
   723             xmlOutputBufferWriteString(buf, "=\"\"");
       
   724         }
       
   725     }
       
   726 }
       
   727 
       
   728 /**
       
   729  * htmlAttrListDumpOutput:
       
   730  * @param buf the HTML buffer output
       
   731  * @param doc the document
       
   732  * @param cur the first attribute pointer
       
   733  * @param encoding the encoding string
       
   734  *
       
   735  * Dump a list of HTML attributes
       
   736  */
       
   737 static void
       
   738 htmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur, const char *encoding) {
       
   739     if (cur == NULL) {
       
   740         return;
       
   741     }
       
   742     while (cur != NULL) {
       
   743         htmlAttrDumpOutput(buf, doc, cur, encoding);
       
   744         cur = cur->next;
       
   745     }
       
   746 }
       
   747 
       
   748 /**
       
   749  * htmlNodeListDumpOutput:
       
   750  * @param buf the HTML buffer output
       
   751  * @param doc the document
       
   752  * @param cur the first node
       
   753  * @param encoding the encoding string
       
   754  * @param format should formatting spaces been added
       
   755  *
       
   756  * Dump an HTML node list, recursive behaviour,children are printed too.
       
   757  */
       
   758 static void
       
   759 htmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
       
   760                        xmlNodePtr cur, const char *encoding, int format) {
       
   761     if (cur == NULL) {
       
   762         return;
       
   763     }
       
   764     while (cur != NULL) {
       
   765         htmlNodeDumpFormatOutput(buf, doc, cur, encoding, format);
       
   766         cur = cur->next;
       
   767     }
       
   768 }
       
   769 
       
   770 /**
       
   771  * htmlNodeDumpFormatOutput:
       
   772  * @param buf the HTML buffer output
       
   773  * @param doc the document
       
   774  * @param cur the current node
       
   775  * @param encoding the encoding string
       
   776  * @param format should formatting spaces been added
       
   777  *
       
   778  * Dump an HTML node, recursive behaviour,children are printed too.
       
   779  */
       
   780 XMLPUBFUNEXPORT void
       
   781 htmlNodeDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
       
   782                          xmlNodePtr cur, const char *encoding, int format) {
       
   783     const htmlElemDesc * info;
       
   784 
       
   785     xmlInitParser();
       
   786 
       
   787     if (cur == NULL) {
       
   788         return;
       
   789     }
       
   790     /*
       
   791      * Special cases.
       
   792      */
       
   793     if (cur->type == XML_DTD_NODE)
       
   794         return;
       
   795     if (cur->type == XML_HTML_DOCUMENT_NODE) {
       
   796         htmlDocContentDumpOutput(buf, (xmlDocPtr) cur, encoding);
       
   797         return;
       
   798     }
       
   799     if (cur->type == HTML_TEXT_NODE) {
       
   800         if (cur->content) {
       
   801             if (
       
   802                   ( 
       
   803                     (cur->name == (const xmlChar*) xmlStringText     ) ||
       
   804                     (cur->name != (const xmlChar*) xmlStringTextNoenc)
       
   805                   )
       
   806                 &&
       
   807                   (!cur->parent ||
       
   808                     (
       
   809                      xmlStrcasecmp(cur->parent->name, BAD_CAST "script")
       
   810                       &&
       
   811                      xmlStrcasecmp(cur->parent->name, BAD_CAST "style")
       
   812                     )
       
   813                   )
       
   814                )
       
   815             {
       
   816                 xmlChar* buffer;
       
   817 
       
   818                 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
       
   819                 if (buffer) {
       
   820                     xmlOutputBufferWriteString(buf, (const char *)buffer);
       
   821                     xmlFree(buffer);
       
   822                 }
       
   823             } else {
       
   824                 xmlOutputBufferWriteString(buf, (const char *)cur->content);
       
   825             }
       
   826         }
       
   827         return;
       
   828     }
       
   829     if (cur->type == HTML_COMMENT_NODE) {
       
   830         if (cur->content != NULL) {
       
   831             xmlOutputBufferWriteString(buf, "<!--");
       
   832             xmlOutputBufferWriteString(buf, (const char *)cur->content);
       
   833             xmlOutputBufferWriteString(buf, "-->");
       
   834         }
       
   835         return;
       
   836     }
       
   837 
       
   838     if (cur->type == HTML_PI_NODE) {
       
   839         if (cur->name == NULL)
       
   840             return;
       
   841         xmlOutputBufferWriteString(buf, "<?");
       
   842         xmlOutputBufferWriteString(buf, (const char *)cur->name);
       
   843         if (cur->content != NULL) {
       
   844             xmlOutputBufferWriteString(buf, " ");
       
   845             xmlOutputBufferWriteString(buf, (const char *)cur->content);
       
   846         }
       
   847         xmlOutputBufferWriteString(buf, ">");
       
   848         return;
       
   849     }
       
   850 
       
   851     if (cur->type == HTML_ENTITY_REF_NODE) {
       
   852         xmlOutputBufferWriteString(buf, "&");
       
   853         xmlOutputBufferWriteString(buf, (const char *)cur->name);
       
   854         xmlOutputBufferWriteString(buf, ";");
       
   855         return;
       
   856     }
       
   857 
       
   858     if (cur->type == HTML_PRESERVE_NODE) {
       
   859         if (cur->content != NULL) {
       
   860             xmlOutputBufferWriteString(buf, (const char *)cur->content);
       
   861         }
       
   862         return;
       
   863     }
       
   864 
       
   865     /*
       
   866      * Get specific HTML info for that node.
       
   867      */
       
   868     info = cur->ns ? NULL : htmlTagLookup(cur->name);
       
   869 
       
   870     xmlOutputBufferWriteString(buf, "<");
       
   871     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
       
   872         xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
       
   873         xmlOutputBufferWriteString(buf, ":");
       
   874     }
       
   875     xmlOutputBufferWriteString(buf, (const char *)cur->name);
       
   876     if (cur->nsDef)
       
   877         xmlNsListDumpOutput(buf, cur->nsDef);
       
   878     if (cur->properties != NULL)
       
   879         htmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
       
   880 
       
   881     if ((info != NULL) && (info->empty)) {
       
   882         xmlOutputBufferWriteString(buf, ">");
       
   883         if ((format) && (!info->isinline) && (cur->next != NULL)) {
       
   884             if ((cur->next->type != HTML_TEXT_NODE) &&
       
   885                 (cur->next->type != HTML_ENTITY_REF_NODE) &&
       
   886                 (cur->parent != NULL) &&
       
   887                 (cur->parent->name != NULL) &&
       
   888                 (cur->parent->name[0] != 'p')) /* p, pre, param */
       
   889                 xmlOutputBufferWriteString(buf, "\n");
       
   890         }
       
   891         return;
       
   892     }
       
   893 
       
   894     if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
       
   895         (cur->children == NULL))
       
   896     {
       
   897         if ((info != NULL) && (info->saveEndTag != 0) &&
       
   898             (xmlStrcmp(BAD_CAST info->name, BAD_CAST "html")) &&
       
   899             (xmlStrcmp(BAD_CAST info->name, BAD_CAST "body")))
       
   900         {
       
   901             xmlOutputBufferWriteString(buf, ">");
       
   902         } else {
       
   903             xmlOutputBufferWriteString(buf, "></");
       
   904             if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
       
   905                 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
       
   906                 xmlOutputBufferWriteString(buf, ":");
       
   907             }
       
   908             xmlOutputBufferWriteString(buf, (const char *)cur->name);
       
   909             xmlOutputBufferWriteString(buf, ">");
       
   910         }
       
   911         if ((format) && (cur->next != NULL) &&
       
   912                 (info != NULL) && (!info->isinline))
       
   913         {
       
   914             if ((cur->next->type != HTML_TEXT_NODE) &&
       
   915                 (cur->next->type != HTML_ENTITY_REF_NODE) &&
       
   916                 (cur->parent != NULL) &&
       
   917                 (cur->parent->name != NULL) &&
       
   918                 (cur->parent->name[0] != 'p')) /* p, pre, param */
       
   919                 xmlOutputBufferWriteString(buf, "\n");
       
   920         }
       
   921         return;
       
   922     }
       
   923     xmlOutputBufferWriteString(buf, ">");
       
   924     if ((cur->type != XML_ELEMENT_NODE) &&
       
   925         (cur->content != NULL)) {
       
   926             /*
       
   927              * Uses the OutputBuffer property to automatically convert
       
   928              * invalids to charrefs
       
   929              */
       
   930 
       
   931             xmlOutputBufferWriteString(buf, (const char *) cur->content);
       
   932     }
       
   933     if (cur->children != NULL) {
       
   934         if ((format) && (info != NULL) && (!info->isinline) &&
       
   935             (cur->children->type != HTML_TEXT_NODE) &&
       
   936             (cur->children->type != HTML_ENTITY_REF_NODE) &&
       
   937             (cur->children != cur->last) &&
       
   938             (cur->name != NULL) &&
       
   939             (cur->name[0] != 'p')) /* p, pre, param */
       
   940             xmlOutputBufferWriteString(buf, "\n");
       
   941         htmlNodeListDumpOutput(buf, doc, cur->children, encoding, format);
       
   942         if ((format) && (info != NULL) && (!info->isinline) &&
       
   943             (cur->last->type != HTML_TEXT_NODE) &&
       
   944             (cur->last->type != HTML_ENTITY_REF_NODE) &&
       
   945             (cur->children != cur->last) &&
       
   946             (cur->name != NULL) &&
       
   947             (cur->name[0] != 'p')) /* p, pre, param */
       
   948             xmlOutputBufferWriteString(buf, "\n");
       
   949     }
       
   950     xmlOutputBufferWriteString(buf, "</");
       
   951     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
       
   952         xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
       
   953         xmlOutputBufferWriteString(buf, ":");
       
   954     }
       
   955     xmlOutputBufferWriteString(buf, (const char *)cur->name);
       
   956     xmlOutputBufferWriteString(buf, ">");
       
   957     if ((format) && (info != NULL) && (!info->isinline) &&
       
   958         (cur->next != NULL)) {
       
   959         if ((cur->next->type != HTML_TEXT_NODE) &&
       
   960             (cur->next->type != HTML_ENTITY_REF_NODE) &&
       
   961             (cur->parent != NULL) &&
       
   962             (cur->parent->name != NULL) &&
       
   963             (cur->parent->name[0] != 'p')) /* p, pre, param */
       
   964             xmlOutputBufferWriteString(buf, "\n");
       
   965     }
       
   966 }
       
   967 
       
   968 
       
   969 /**
       
   970  * htmlDocContentDumpFormatOutput:
       
   971  * @param buf the HTML buffer output
       
   972  * @param cur the document
       
   973  * @param encoding the encoding string
       
   974  * @param format should formatting spaces been added
       
   975  *
       
   976  * Dump an HTML document.
       
   977  */
       
   978 XMLPUBFUNEXPORT void
       
   979 htmlDocContentDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
       
   980                                const char *encoding, int format) {
       
   981     int type;
       
   982 
       
   983     xmlInitParser();
       
   984 
       
   985     /*
       
   986      * force to output the stuff as HTML, especially for entities
       
   987      */
       
   988     type = cur->type;
       
   989     cur->type = XML_HTML_DOCUMENT_NODE;
       
   990     if (cur->intSubset != NULL) {
       
   991         htmlDtdDumpOutput(buf, cur, NULL);
       
   992     }
       
   993     if (cur->children != NULL) {
       
   994         htmlNodeListDumpOutput(buf, cur, cur->children, encoding, format);
       
   995     }
       
   996     xmlOutputBufferWriteString(buf, "\n");
       
   997     cur->type = (xmlElementType) type;
       
   998 }
       
   999 
       
  1000 /**
       
  1001  * htmlDocContentDumpOutput:
       
  1002  * @param buf the HTML buffer output
       
  1003  * @param cur the document
       
  1004  * @param encoding the encoding string
       
  1005  *
       
  1006  * Dump an HTML document. Formating return/spaces are added.
       
  1007  */
       
  1008 XMLPUBFUNEXPORT void
       
  1009 htmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
       
  1010                          const char *encoding) {
       
  1011     htmlDocContentDumpFormatOutput(buf, cur, encoding, 1);
       
  1012 }
       
  1013 
       
  1014 #endif /* LIBXML_OUTPUT_ENABLED */
       
  1015 #endif /* defined(IBXML_HTML_ENABLED) || defined(XMLENGINE_XSLT) */
       
  1016 
       
  1017 #ifdef LIBXML_HTML_ENABLED
       
  1018 #ifdef LIBXML_OUTPUT_ENABLED
       
  1019 
       
  1020 /************************************************************************
       
  1021  *                                                                      *
       
  1022  *      Saving functions front-ends                                     *
       
  1023  *                                                                      *
       
  1024  ************************************************************************/
       
  1025 
       
  1026 /**
       
  1027  * htmlDocDump:
       
  1028  * @param f the FILE*
       
  1029  * @param cur the document
       
  1030  *
       
  1031  * Dump an HTML document to an open FILE.
       
  1032  *
       
  1033  * returns: the number of byte written or -1 in case of failure.
       
  1034  */
       
  1035 int
       
  1036 htmlDocDump(FILE *f, xmlDocPtr cur) {
       
  1037     xmlOutputBufferPtr buf;
       
  1038     xmlCharEncodingHandlerPtr handler = NULL;
       
  1039     const char *encoding;
       
  1040     int ret;
       
  1041 
       
  1042     xmlInitParser();
       
  1043 
       
  1044     if (cur == NULL) {
       
  1045         return(-1);
       
  1046     }
       
  1047 
       
  1048     encoding = (const char *) htmlGetMetaEncoding(cur);
       
  1049 
       
  1050     if (encoding != NULL) {
       
  1051         xmlCharEncoding enc;
       
  1052 
       
  1053         enc = xmlParseCharEncoding(encoding);
       
  1054         if (enc != cur->charset) {
       
  1055             if (cur->charset != XML_CHAR_ENCODING_UTF8) {
       
  1056                 /*
       
  1057                  * Not supported yet
       
  1058                  */
       
  1059                 return(-1);
       
  1060             }
       
  1061 
       
  1062             handler = xmlFindCharEncodingHandler(encoding);
       
  1063             if (handler == NULL)
       
  1064                 return(-1);
       
  1065         }
       
  1066     }
       
  1067 
       
  1068     /*
       
  1069      * Fallback to HTML or ASCII when the encoding is unspecified
       
  1070      */
       
  1071     if (handler == NULL)
       
  1072         handler = xmlFindCharEncodingHandler("HTML");
       
  1073     if (handler == NULL)
       
  1074         handler = xmlFindCharEncodingHandler("ascii");
       
  1075 
       
  1076     buf = xmlOutputBufferCreateFile(f, handler);
       
  1077     if (buf == NULL) return(-1);
       
  1078     htmlDocContentDumpOutput(buf, cur, NULL);
       
  1079 
       
  1080     ret = xmlOutputBufferClose(buf);
       
  1081     return(ret);
       
  1082 }
       
  1083 
       
  1084 /**
       
  1085  * htmlSaveFile:
       
  1086  * @param filename the filename (or URL)
       
  1087  * @param cur the document
       
  1088  *
       
  1089  * Dump an HTML document to a file. If filename is "-" the stdout file is
       
  1090  * used.
       
  1091  * returns: the number of byte written or -1 in case of failure.
       
  1092  */
       
  1093 int
       
  1094 htmlSaveFile(const char *filename, xmlDocPtr cur) {
       
  1095     xmlOutputBufferPtr buf;
       
  1096     xmlCharEncodingHandlerPtr handler = NULL;
       
  1097     const char *encoding;
       
  1098     int ret;
       
  1099 
       
  1100     xmlInitParser();
       
  1101 
       
  1102     encoding = (const char *) htmlGetMetaEncoding(cur);
       
  1103 
       
  1104     if (encoding != NULL) {
       
  1105         xmlCharEncoding enc;
       
  1106 
       
  1107         enc = xmlParseCharEncoding(encoding);
       
  1108         if (enc != cur->charset) {
       
  1109             if (cur->charset != XML_CHAR_ENCODING_UTF8) {
       
  1110                 /*
       
  1111                  * Not supported yet
       
  1112                  */
       
  1113                 return(-1);
       
  1114             }
       
  1115 
       
  1116             handler = xmlFindCharEncodingHandler(encoding);
       
  1117             if (handler == NULL)
       
  1118                 return(-1);
       
  1119         }
       
  1120     }
       
  1121 
       
  1122     /*
       
  1123      * Fallback to HTML or ASCII when the encoding is unspecified
       
  1124      */
       
  1125     if (handler == NULL)
       
  1126         handler = xmlFindCharEncodingHandler("HTML");
       
  1127     if (handler == NULL)
       
  1128         handler = xmlFindCharEncodingHandler("ascii");
       
  1129 
       
  1130     /*
       
  1131      * save the content to a temp buffer.
       
  1132      */
       
  1133     buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
       
  1134     if (buf == NULL) return(0);
       
  1135 
       
  1136     htmlDocContentDumpOutput(buf, cur, NULL);
       
  1137 
       
  1138     ret = xmlOutputBufferClose(buf);
       
  1139     return(ret);
       
  1140 }
       
  1141 
       
  1142 /**
       
  1143  * htmlSaveFileFormat:
       
  1144  * @param filename the filename
       
  1145  * @param cur the document
       
  1146  * @param format should formatting spaces been added
       
  1147  * @param encoding the document encoding
       
  1148  *
       
  1149  * Dump an HTML document to a file using a given encoding.
       
  1150  *
       
  1151  * returns: the number of byte written or -1 in case of failure.
       
  1152  */
       
  1153 int
       
  1154 htmlSaveFileFormat(const char *filename, xmlDocPtr cur,
       
  1155                    const char *encoding, int format) {
       
  1156     xmlOutputBufferPtr buf;
       
  1157     xmlCharEncodingHandlerPtr handler = NULL;
       
  1158     int ret;
       
  1159 
       
  1160     xmlInitParser();
       
  1161 
       
  1162     if (encoding != NULL) {
       
  1163         xmlCharEncoding enc;
       
  1164 
       
  1165         enc = xmlParseCharEncoding(encoding);
       
  1166         if (enc != cur->charset) {
       
  1167             if (cur->charset != XML_CHAR_ENCODING_UTF8) {
       
  1168                 /*
       
  1169                  * Not supported yet
       
  1170                  */
       
  1171                 return(-1);
       
  1172             }
       
  1173 
       
  1174             handler = xmlFindCharEncodingHandler(encoding);
       
  1175             if (handler == NULL)
       
  1176                 return(-1);
       
  1177             htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
       
  1178         }
       
  1179     } else {
       
  1180         htmlSetMetaEncoding(cur, (const xmlChar *) "UTF-8");
       
  1181     }
       
  1182 
       
  1183     /*
       
  1184      * Fallback to HTML or ASCII when the encoding is unspecified
       
  1185      */
       
  1186     if (handler == NULL){
       
  1187         handler = xmlFindCharEncodingHandler("HTML");
       
  1188         if (handler == NULL)
       
  1189             handler = xmlFindCharEncodingHandler("ascii");
       
  1190     }
       
  1191     /*
       
  1192      * save the content to a temp buffer.
       
  1193      */
       
  1194     buf = xmlOutputBufferCreateFilename(filename, handler, 0);
       
  1195     if (buf == NULL) return(0);
       
  1196 
       
  1197     htmlDocContentDumpFormatOutput(buf, cur, encoding, format);
       
  1198 
       
  1199     ret = xmlOutputBufferClose(buf);
       
  1200     return(ret);
       
  1201 }
       
  1202 
       
  1203 /**
       
  1204  * htmlSaveFileEnc:
       
  1205  * @param filename the filename
       
  1206  * @param cur the document
       
  1207  * @param encoding the document encoding
       
  1208  *
       
  1209  * Dump an HTML document to a file using a given encoding
       
  1210  * and formatting returns/spaces are added.
       
  1211  *
       
  1212  * returns: the number of byte written or -1 in case of failure.
       
  1213  */
       
  1214 int
       
  1215 htmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
       
  1216     return(htmlSaveFileFormat(filename, cur, encoding, 1));
       
  1217 }
       
  1218 
       
  1219 #endif /* LIBXML_OUTPUT_ENABLED */
       
  1220 
       
  1221 #endif /* LIBXML_HTML_ENABLED */
       
  1222