Annotation of embedaddon/libxml2/HTMLtree.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>