Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200/* * HTMLtree.c : implementation of access function for an HTML tree. * * See Copyright for the status of this software. * * daniel@veillard.com */
#define IN_LIBXML#include "libxml.h"#ifdef LIBXML_HTML_ENABLED
#include <string.h> /* for memset() only ! */#include <ctype.h>#include <stdlib.h>
#include <libxml/xmlmemory.h>#include <libxml/HTMLparser.h>#include <libxml/HTMLtree.h>#include <libxml/entities.h>#include <libxml/xmlerror.h>#include <libxml/parserInternals.h>#include <libxml/uri.h>
#include "private/buf.h"#include "private/error.h"#include "private/io.h"#include "private/save.h"
/************************************************************************ * * * Getting/Setting encoding meta tags * * * ************************************************************************/
/** * htmlGetMetaEncoding: * @doc: the document * * Encoding definition lookup in the Meta tags * * Returns the current encoding as flagged in the HTML source */const xmlChar *htmlGetMetaEncoding(htmlDocPtr doc) { htmlNodePtr cur; const xmlChar *content; const xmlChar *encoding;
if (doc == NULL) return(NULL); cur = doc->children;
/* * Search the html */ while (cur != NULL) { if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) { if (xmlStrEqual(cur->name, BAD_CAST"html")) break; if (xmlStrEqual(cur->name, BAD_CAST"head")) goto found_head; if (xmlStrEqual(cur->name, BAD_CAST"meta")) goto found_meta; } cur = cur->next; } if (cur == NULL) return(NULL); cur = cur->children;
/* * Search the head */ while (cur != NULL) { if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) { if (xmlStrEqual(cur->name, BAD_CAST"head")) break; if (xmlStrEqual(cur->name, BAD_CAST"meta")) goto found_meta; } cur = cur->next; } if (cur == NULL) return(NULL);found_head: cur = cur->children;
/* * Search the meta elements */found_meta: while (cur != NULL) { if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) { if (xmlStrEqual(cur->name, BAD_CAST"meta")) { xmlAttrPtr attr = cur->properties; int http; const xmlChar *value;
content = NULL; http = 0; while (attr != NULL) { if ((attr->children != NULL) && (attr->children->type == XML_TEXT_NODE) && (attr->children->next == NULL)) { value = attr->children->content; if ((!xmlStrcasecmp(attr->name, BAD_CAST"http-equiv")) && (!xmlStrcasecmp(value, BAD_CAST"Content-Type"))) http = 1; else if ((value != NULL) && (!xmlStrcasecmp(attr->name, BAD_CAST"content"))) content = value; if ((http != 0) && (content != NULL)) goto found_content; } attr = attr->next; } } } cur = cur->next; } return(NULL);
found_content: encoding = xmlStrstr(content, BAD_CAST"charset="); if (encoding == NULL) encoding = xmlStrstr(content, BAD_CAST"Charset="); if (encoding == NULL) encoding = xmlStrstr(content, BAD_CAST"CHARSET="); if (encoding != NULL) { encoding += 8; } else { encoding = xmlStrstr(content, BAD_CAST"charset ="); if (encoding == NULL) encoding = xmlStrstr(content, BAD_CAST"Charset ="); if (encoding == NULL) encoding = xmlStrstr(content, BAD_CAST"CHARSET ="); if (encoding != NULL) encoding += 9; } if (encoding != NULL) { while ((*encoding == ' ') || (*encoding == '\t')) encoding++; } return(encoding);}
/** * htmlSetMetaEncoding: * @doc: the document * @encoding: the encoding string * * Sets the current encoding in the Meta tags * NOTE: this will not change the document content encoding, just * the META flag associated. * * Returns 0 in case of success and -1 in case of error */inthtmlSetMetaEncoding(htmlDocPtr doc, const xmlChar *encoding) { htmlNodePtr cur, meta = NULL, head = NULL; const xmlChar *content = NULL; char newcontent[100];
newcontent[0] = 0;
if (doc == NULL) return(-1);
/* html isn't a real encoding it's just libxml2 way to get entities */ if (!xmlStrcasecmp(encoding, BAD_CAST "html")) return(-1);
if (encoding != NULL) { snprintf(newcontent, sizeof(newcontent), "text/html; charset=%s", (char *)encoding); newcontent[sizeof(newcontent) - 1] = 0; }
cur = doc->children;
/* * Search the html */ while (cur != NULL) { if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) { if (xmlStrcasecmp(cur->name, BAD_CAST"html") == 0) break; if (xmlStrcasecmp(cur->name, BAD_CAST"head") == 0) goto found_head; if (xmlStrcasecmp(cur->name, BAD_CAST"meta") == 0) goto found_meta; } cur = cur->next; } if (cur == NULL) return(-1); cur = cur->children;
/* * Search the head */ while (cur != NULL) { if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) { if (xmlStrcasecmp(cur->name, BAD_CAST"head") == 0) break; if (xmlStrcasecmp(cur->name, BAD_CAST"meta") == 0) { head = cur->parent; goto found_meta; } } cur = cur->next; } if (cur == NULL) return(-1);found_head: head = cur; if (cur->children == NULL) goto create; cur = cur->children;
found_meta: /* * Search and update all the remaining the meta elements carrying * encoding information */ while (cur != NULL) { if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) { if (xmlStrcasecmp(cur->name, BAD_CAST"meta") == 0) { xmlAttrPtr attr = cur->properties; int http; const xmlChar *value;
content = NULL; http = 0; while (attr != NULL) { if ((attr->children != NULL) && (attr->children->type == XML_TEXT_NODE) && (attr->children->next == NULL)) { value = attr->children->content; if ((!xmlStrcasecmp(attr->name, BAD_CAST"http-equiv")) && (!xmlStrcasecmp(value, BAD_CAST"Content-Type"))) http = 1; else { if ((value != NULL) && (!xmlStrcasecmp(attr->name, BAD_CAST"content"))) content = value; } if ((http != 0) && (content != NULL)) break; } attr = attr->next; } if ((http != 0) && (content != NULL)) { meta = cur; break; }
} } cur = cur->next; }create: if (meta == NULL) { if ((encoding != NULL) && (head != NULL)) { /* * Create a new Meta element with the right attributes */
meta = xmlNewDocNode(doc, NULL, BAD_CAST"meta", NULL); if (head->children == NULL) xmlAddChild(head, meta); else xmlAddPrevSibling(head->children, meta); xmlNewProp(meta, BAD_CAST"http-equiv", BAD_CAST"Content-Type"); xmlNewProp(meta, BAD_CAST"content", BAD_CAST newcontent); } } else { /* remove the meta tag if NULL is passed */ if (encoding == NULL) { xmlUnlinkNode(meta); xmlFreeNode(meta); } /* change the document only if there is a real encoding change */ else if (xmlStrcasestr(content, encoding) == NULL) { xmlSetProp(meta, BAD_CAST"content", BAD_CAST newcontent); } }
return(0);}
/** * booleanHTMLAttrs: * * These are the HTML attributes which will be output * in minimized form, i.e. <option selected="selected"> will be * output as <option selected>, as per XSLT 1.0 16.2 "HTML Output Method" * */static const char* const htmlBooleanAttrs[] = { "checked", "compact", "declare", "defer", "disabled", "ismap", "multiple", "nohref", "noresize", "noshade", "nowrap", "readonly", "selected", NULL};
/** * htmlIsBooleanAttr: * @name: the name of the attribute to check * * Determine if a given attribute is a boolean attribute. * * returns: false if the attribute is not boolean, true otherwise. */inthtmlIsBooleanAttr(const xmlChar *name){ int i = 0;
while (htmlBooleanAttrs[i] != NULL) { if (xmlStrcasecmp((const xmlChar *)htmlBooleanAttrs[i], name) == 0) return 1; i++; } return 0;}
#ifdef LIBXML_OUTPUT_ENABLED/************************************************************************ * * * Output error handlers * * * ************************************************************************//** * htmlSaveErrMemory: * @extra: extra information * * Handle an out of memory condition */static voidhtmlSaveErrMemory(const char *extra){ __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);}
/** * htmlSaveErr: * @code: the error number * @node: the location of the error. * @extra: extra information * * Handle an out of memory condition */static voidhtmlSaveErr(int code, xmlNodePtr node, const char *extra){ const char *msg = NULL;
switch(code) { case XML_SAVE_NOT_UTF8: msg = "string is not in UTF-8\n"; break; case XML_SAVE_CHAR_INVALID: msg = "invalid character value\n"; break; case XML_SAVE_UNKNOWN_ENCODING: msg = "unknown encoding %s\n"; break; case XML_SAVE_NO_DOCTYPE: msg = "HTML has no DOCTYPE\n"; break; default: msg = "unexpected error number\n"; } __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);}
/************************************************************************ * * * Dumping HTML tree content to a simple buffer * * * ************************************************************************/
/** * htmlBufNodeDumpFormat: * @buf: the xmlBufPtr output * @doc: the document * @cur: the current node * @format: should formatting spaces been added * * Dump an HTML node, recursive behaviour,children are printed too. * * Returns the number of byte written or -1 in case of error */static size_thtmlBufNodeDumpFormat(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, int format) { size_t use; int ret; xmlOutputBufferPtr outbuf;
if (cur == NULL) { return (-1); } if (buf == NULL) { return (-1); } outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); if (outbuf == NULL) { htmlSaveErrMemory("allocating HTML output buffer"); return (-1); } memset(outbuf, 0, sizeof(xmlOutputBuffer)); outbuf->buffer = buf; outbuf->encoder = NULL; outbuf->writecallback = NULL; outbuf->closecallback = NULL; outbuf->context = NULL; outbuf->written = 0;
use = xmlBufUse(buf); htmlNodeDumpFormatOutput(outbuf, doc, cur, NULL, format); xmlFree(outbuf); ret = xmlBufUse(buf) - use; return (ret);}
/** * htmlNodeDump: * @buf: the HTML buffer output * @doc: the document * @cur: the current node * * Dump an HTML node, recursive behaviour,children are printed too, * and formatting returns are added. * * Returns the number of byte written or -1 in case of error */inthtmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur) { xmlBufPtr buffer; size_t ret;
if ((buf == NULL) || (cur == NULL)) return(-1);
xmlInitParser(); buffer = xmlBufFromBuffer(buf); if (buffer == NULL) return(-1);
ret = htmlBufNodeDumpFormat(buffer, doc, cur, 1);
xmlBufBackToBuffer(buffer);
if (ret > INT_MAX) return(-1); return((int) ret);}
/** * htmlNodeDumpFileFormat: * @out: the FILE pointer * @doc: the document * @cur: the current node * @encoding: the document encoding * @format: should formatting spaces been added * * Dump an HTML node, recursive behaviour,children are printed too. * * TODO: if encoding == NULL try to save in the doc encoding * * returns: the number of byte written or -1 in case of failure. */inthtmlNodeDumpFileFormat(FILE *out, xmlDocPtr doc, xmlNodePtr cur, const char *encoding, int format) { xmlOutputBufferPtr buf; xmlCharEncodingHandlerPtr handler = NULL; int ret;
xmlInitParser();
if (encoding != NULL) { xmlCharEncoding enc;
enc = xmlParseCharEncoding(encoding); if (enc != XML_CHAR_ENCODING_UTF8) { handler = xmlFindCharEncodingHandler(encoding); if (handler == NULL) htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); } } else { /* * Fallback to HTML or ASCII when the encoding is unspecified */ if (handler == NULL) handler = xmlFindCharEncodingHandler("HTML"); if (handler == NULL) handler = xmlFindCharEncodingHandler("ascii"); }
/* * save the content to a temp buffer. */ buf = xmlOutputBufferCreateFile(out, handler); if (buf == NULL) return(0);
htmlNodeDumpFormatOutput(buf, doc, cur, NULL, format);
ret = xmlOutputBufferClose(buf); return(ret);}
/** * htmlNodeDumpFile: * @out: the FILE pointer * @doc: the document * @cur: the current node * * Dump an HTML node, recursive behaviour,children are printed too, * and formatting returns are added. */voidhtmlNodeDumpFile(FILE *out, xmlDocPtr doc, xmlNodePtr cur) { htmlNodeDumpFileFormat(out, doc, cur, NULL, 1);}
/** * htmlDocDumpMemoryFormat: * @cur: the document * @mem: OUT: the memory pointer * @size: OUT: the memory length * @format: should formatting spaces been added * * Dump an HTML document in memory and return the xmlChar * and it's size. * It's up to the caller to free the memory. */voidhtmlDocDumpMemoryFormat(xmlDocPtr cur, xmlChar**mem, int *size, int format) { xmlOutputBufferPtr buf; xmlCharEncodingHandlerPtr handler = NULL; const char *encoding;
xmlInitParser();
if ((mem == NULL) || (size == NULL)) return; if (cur == NULL) { *mem = NULL; *size = 0; return; }
encoding = (const char *) htmlGetMetaEncoding(cur);
if (encoding != NULL) { xmlCharEncoding enc;
enc = xmlParseCharEncoding(encoding); if (enc != XML_CHAR_ENCODING_UTF8) { handler = xmlFindCharEncodingHandler(encoding); if (handler == NULL) htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
} } else { /* * Fallback to HTML or ASCII when the encoding is unspecified */ if (handler == NULL) handler = xmlFindCharEncodingHandler("HTML"); if (handler == NULL) handler = xmlFindCharEncodingHandler("ascii"); }
buf = xmlAllocOutputBufferInternal(handler); if (buf == NULL) { *mem = NULL; *size = 0; return; }
htmlDocContentDumpFormatOutput(buf, cur, NULL, format);
xmlOutputBufferFlush(buf); if (buf->conv != NULL) { *size = xmlBufUse(buf->conv); *mem = xmlStrndup(xmlBufContent(buf->conv), *size); } else { *size = xmlBufUse(buf->buffer); *mem = xmlStrndup(xmlBufContent(buf->buffer), *size); } (void)xmlOutputBufferClose(buf);}
/** * htmlDocDumpMemory: * @cur: the document * @mem: OUT: the memory pointer * @size: OUT: the memory length * * Dump an HTML document in memory and return the xmlChar * and it's size. * It's up to the caller to free the memory. */voidhtmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) { htmlDocDumpMemoryFormat(cur, mem, size, 1);}
/************************************************************************ * * * Dumping HTML tree content to an I/O output buffer * * * ************************************************************************/
/** * htmlDtdDumpOutput: * @buf: the HTML buffer output * @doc: the document * @encoding: the encoding string * * TODO: check whether encoding is needed * * Dump the HTML document DTD, if any. */static voidhtmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, const char *encoding ATTRIBUTE_UNUSED) { xmlDtdPtr cur = doc->intSubset;
if (cur == NULL) { htmlSaveErr(XML_SAVE_NO_DOCTYPE, (xmlNodePtr) doc, NULL); return; } xmlOutputBufferWriteString(buf, "<!DOCTYPE "); xmlOutputBufferWriteString(buf, (const char *)cur->name); if (cur->ExternalID != NULL) { xmlOutputBufferWriteString(buf, " PUBLIC "); xmlBufWriteQuotedString(buf->buffer, cur->ExternalID); if (cur->SystemID != NULL) { xmlOutputBufferWriteString(buf, " "); xmlBufWriteQuotedString(buf->buffer, cur->SystemID); } } else if (cur->SystemID != NULL && xmlStrcmp(cur->SystemID, BAD_CAST "about:legacy-compat")) { xmlOutputBufferWriteString(buf, " SYSTEM "); xmlBufWriteQuotedString(buf->buffer, cur->SystemID); } xmlOutputBufferWriteString(buf, ">\n");}
/** * htmlAttrDumpOutput: * @buf: the HTML buffer output * @doc: the document * @cur: the attribute pointer * * Dump an HTML attribute */static voidhtmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) { xmlChar *value;
/* * The html output method should not escape a & character * occurring in an attribute value immediately followed by * a { character (see Section B.7.1 of the HTML 4.0 Recommendation). * This is implemented in xmlEncodeEntitiesReentrant */
if (cur == NULL) { return; } xmlOutputBufferWriteString(buf, " "); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); xmlOutputBufferWriteString(buf, ":"); } xmlOutputBufferWriteString(buf, (const char *)cur->name); if ((cur->children != NULL) && (!htmlIsBooleanAttr(cur->name))) { value = xmlNodeListGetString(doc, cur->children, 0); if (value) { xmlOutputBufferWriteString(buf, "="); if ((cur->ns == NULL) && (cur->parent != NULL) && (cur->parent->ns == NULL) && ((!xmlStrcasecmp(cur->name, BAD_CAST "href")) || (!xmlStrcasecmp(cur->name, BAD_CAST "action")) || (!xmlStrcasecmp(cur->name, BAD_CAST "src")) || ((!xmlStrcasecmp(cur->name, BAD_CAST "name")) && (!xmlStrcasecmp(cur->parent->name, BAD_CAST "a"))))) { xmlChar *escaped; xmlChar *tmp = value;
while (IS_BLANK_CH(*tmp)) tmp++;
/* * Angle brackets are technically illegal in URIs, but they're * used in server side includes, for example. Curly brackets * are illegal as well and often used in templates. * Don't escape non-whitespace, printable ASCII chars for * improved interoperability. Only escape space, control * and non-ASCII chars. */ escaped = xmlURIEscapeStr(tmp, BAD_CAST "\"#$%&+,/:;<=>?@[\\]^`{|}"); if (escaped != NULL) { xmlBufWriteQuotedString(buf->buffer, escaped); xmlFree(escaped); } else { xmlBufWriteQuotedString(buf->buffer, value); } } else { xmlBufWriteQuotedString(buf->buffer, value); } xmlFree(value); } else { xmlOutputBufferWriteString(buf, "=\"\""); } }}
/** * htmlNodeDumpFormatOutput: * @buf: the HTML buffer output * @doc: the document * @cur: the current node * @encoding: the encoding string (unused) * @format: should formatting spaces been added * * Dump an HTML node, recursive behaviour,children are printed too. */voidhtmlNodeDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, const char *encoding ATTRIBUTE_UNUSED, int format) { xmlNodePtr root, parent; xmlAttrPtr attr; const htmlElemDesc * info;
xmlInitParser();
if ((cur == NULL) || (buf == NULL)) { return; }
root = cur; parent = cur->parent; while (1) { switch (cur->type) { case XML_HTML_DOCUMENT_NODE: case XML_DOCUMENT_NODE: if (((xmlDocPtr) cur)->intSubset != NULL) { htmlDtdDumpOutput(buf, (xmlDocPtr) cur, NULL); } if (cur->children != NULL) { /* Always validate cur->parent when descending. */ if (cur->parent == parent) { parent = cur; cur = cur->children; continue; } } else { xmlOutputBufferWriteString(buf, "\n"); } break;
case XML_ELEMENT_NODE: /* * Some users like lxml are known to pass nodes with a corrupted * tree structure. Fall back to a recursive call to handle this * case. */ if ((cur->parent != parent) && (cur->children != NULL)) { htmlNodeDumpFormatOutput(buf, doc, cur, encoding, format); break; }
/* * Get specific HTML info for that node. */ if (cur->ns == NULL) info = htmlTagLookup(cur->name); else info = NULL;
xmlOutputBufferWriteString(buf, "<"); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); xmlOutputBufferWriteString(buf, ":"); } xmlOutputBufferWriteString(buf, (const char *)cur->name); if (cur->nsDef) xmlNsListDumpOutput(buf, cur->nsDef); attr = cur->properties; while (attr != NULL) { htmlAttrDumpOutput(buf, doc, attr); attr = attr->next; }
if ((info != NULL) && (info->empty)) { xmlOutputBufferWriteString(buf, ">"); } else if (cur->children == NULL) { if ((info != NULL) && (info->saveEndTag != 0) && (xmlStrcmp(BAD_CAST info->name, BAD_CAST "html")) && (xmlStrcmp(BAD_CAST info->name, BAD_CAST "body"))) { xmlOutputBufferWriteString(buf, ">"); } else { xmlOutputBufferWriteString(buf, "></"); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); xmlOutputBufferWriteString(buf, ":"); } xmlOutputBufferWriteString(buf, (const char *)cur->name); xmlOutputBufferWriteString(buf, ">"); } } else { xmlOutputBufferWriteString(buf, ">"); if ((format) && (info != NULL) && (!info->isinline) && (cur->children->type != HTML_TEXT_NODE) && (cur->children->type != HTML_ENTITY_REF_NODE) && (cur->children != cur->last) && (cur->name != NULL) && (cur->name[0] != 'p')) /* p, pre, param */ xmlOutputBufferWriteString(buf, "\n"); parent = cur; cur = cur->children; continue; }
if ((format) && (cur->next != NULL) && (info != NULL) && (!info->isinline)) { if ((cur->next->type != HTML_TEXT_NODE) && (cur->next->type != HTML_ENTITY_REF_NODE) && (parent != NULL) && (parent->name != NULL) && (parent->name[0] != 'p')) /* p, pre, param */ xmlOutputBufferWriteString(buf, "\n"); }
break;
case XML_ATTRIBUTE_NODE: htmlAttrDumpOutput(buf, doc, (xmlAttrPtr) cur); break;
case HTML_TEXT_NODE: if (cur->content == NULL) break; if (((cur->name == (const xmlChar *)xmlStringText) || (cur->name != (const xmlChar *)xmlStringTextNoenc)) && ((parent == NULL) || ((xmlStrcasecmp(parent->name, BAD_CAST "script")) && (xmlStrcasecmp(parent->name, BAD_CAST "style"))))) { xmlChar *buffer;
buffer = xmlEncodeEntitiesReentrant(doc, cur->content); if (buffer != NULL) { xmlOutputBufferWriteString(buf, (const char *)buffer); xmlFree(buffer); } } else { xmlOutputBufferWriteString(buf, (const char *)cur->content); } break;
case HTML_COMMENT_NODE: if (cur->content != NULL) { xmlOutputBufferWriteString(buf, "<!--"); xmlOutputBufferWriteString(buf, (const char *)cur->content); xmlOutputBufferWriteString(buf, "-->"); } break;
case HTML_PI_NODE: if (cur->name != NULL) { xmlOutputBufferWriteString(buf, "<?"); xmlOutputBufferWriteString(buf, (const char *)cur->name); if (cur->content != NULL) { xmlOutputBufferWriteString(buf, " "); xmlOutputBufferWriteString(buf, (const char *)cur->content); } xmlOutputBufferWriteString(buf, ">"); } break;
case HTML_ENTITY_REF_NODE: xmlOutputBufferWriteString(buf, "&"); xmlOutputBufferWriteString(buf, (const char *)cur->name); xmlOutputBufferWriteString(buf, ";"); break;
case HTML_PRESERVE_NODE: if (cur->content != NULL) { xmlOutputBufferWriteString(buf, (const char *)cur->content); } break;
default: break; }
while (1) { if (cur == root) return; if (cur->next != NULL) { cur = cur->next; break; }
cur = parent; /* cur->parent was validated when descending. */ parent = cur->parent;
if ((cur->type == XML_HTML_DOCUMENT_NODE) || (cur->type == XML_DOCUMENT_NODE)) { xmlOutputBufferWriteString(buf, "\n"); } else { if ((format) && (cur->ns == NULL)) info = htmlTagLookup(cur->name); else info = NULL;
if ((format) && (info != NULL) && (!info->isinline) && (cur->last->type != HTML_TEXT_NODE) && (cur->last->type != HTML_ENTITY_REF_NODE) && (cur->children != cur->last) && (cur->name != NULL) && (cur->name[0] != 'p')) /* p, pre, param */ xmlOutputBufferWriteString(buf, "\n");
xmlOutputBufferWriteString(buf, "</"); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); xmlOutputBufferWriteString(buf, ":"); } xmlOutputBufferWriteString(buf, (const char *)cur->name); xmlOutputBufferWriteString(buf, ">");
if ((format) && (info != NULL) && (!info->isinline) && (cur->next != NULL)) { if ((cur->next->type != HTML_TEXT_NODE) && (cur->next->type != HTML_ENTITY_REF_NODE) && (parent != NULL) && (parent->name != NULL) && (parent->name[0] != 'p')) /* p, pre, param */ xmlOutputBufferWriteString(buf, "\n"); } } } }}
/** * htmlNodeDumpOutput: * @buf: the HTML buffer output * @doc: the document * @cur: the current node * @encoding: the encoding string (unused) * * Dump an HTML node, recursive behaviour,children are printed too, * and formatting returns/spaces are added. */voidhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, const char *encoding ATTRIBUTE_UNUSED) { htmlNodeDumpFormatOutput(buf, doc, cur, NULL, 1);}
/** * htmlDocContentDumpFormatOutput: * @buf: the HTML buffer output * @cur: the document * @encoding: the encoding string (unused) * @format: should formatting spaces been added * * Dump an HTML document. */voidhtmlDocContentDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding ATTRIBUTE_UNUSED, int format) { int type = 0; if (cur) { type = cur->type; cur->type = XML_HTML_DOCUMENT_NODE; } htmlNodeDumpFormatOutput(buf, cur, (xmlNodePtr) cur, NULL, format); if (cur) cur->type = (xmlElementType) type;}
/** * htmlDocContentDumpOutput: * @buf: the HTML buffer output * @cur: the document * @encoding: the encoding string (unused) * * Dump an HTML document. Formatting return/spaces are added. */voidhtmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding ATTRIBUTE_UNUSED) { htmlNodeDumpFormatOutput(buf, cur, (xmlNodePtr) cur, NULL, 1);}
/************************************************************************ * * * Saving functions front-ends * * * ************************************************************************/
/** * htmlDocDump: * @f: the FILE* * @cur: the document * * Dump an HTML document to an open FILE. * * returns: the number of byte written or -1 in case of failure. */inthtmlDocDump(FILE *f, xmlDocPtr cur) { xmlOutputBufferPtr buf; xmlCharEncodingHandlerPtr handler = NULL; const char *encoding; int ret;
xmlInitParser();
if ((cur == NULL) || (f == NULL)) { return(-1); }
encoding = (const char *) htmlGetMetaEncoding(cur);
if (encoding != NULL) { xmlCharEncoding enc;
enc = xmlParseCharEncoding(encoding); if (enc != XML_CHAR_ENCODING_UTF8) { handler = xmlFindCharEncodingHandler(encoding); if (handler == NULL) htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); } } else { /* * Fallback to HTML or ASCII when the encoding is unspecified */ if (handler == NULL) handler = xmlFindCharEncodingHandler("HTML"); if (handler == NULL) handler = xmlFindCharEncodingHandler("ascii"); }
buf = xmlOutputBufferCreateFile(f, handler); if (buf == NULL) return(-1); htmlDocContentDumpOutput(buf, cur, NULL);
ret = xmlOutputBufferClose(buf); return(ret);}
/** * htmlSaveFile: * @filename: the filename (or URL) * @cur: the document * * Dump an HTML document to a file. If @filename is "-" the stdout file is * used. * returns: the number of byte written or -1 in case of failure. */inthtmlSaveFile(const char *filename, xmlDocPtr cur) { xmlOutputBufferPtr buf; xmlCharEncodingHandlerPtr handler = NULL; const char *encoding; int ret;
if ((cur == NULL) || (filename == NULL)) return(-1);
xmlInitParser();
encoding = (const char *) htmlGetMetaEncoding(cur);
if (encoding != NULL) { xmlCharEncoding enc;
enc = xmlParseCharEncoding(encoding); if (enc != XML_CHAR_ENCODING_UTF8) { handler = xmlFindCharEncodingHandler(encoding); if (handler == NULL) htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); } } else { /* * Fallback to HTML or ASCII when the encoding is unspecified */ if (handler == NULL) handler = xmlFindCharEncodingHandler("HTML"); if (handler == NULL) handler = xmlFindCharEncodingHandler("ascii"); }
/* * save the content to a temp buffer. */ buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression); if (buf == NULL) return(0);
htmlDocContentDumpOutput(buf, cur, NULL);
ret = xmlOutputBufferClose(buf); return(ret);}
/** * htmlSaveFileFormat: * @filename: the filename * @cur: the document * @format: should formatting spaces been added * @encoding: the document encoding * * Dump an HTML document to a file using a given encoding. * * returns: the number of byte written or -1 in case of failure. */inthtmlSaveFileFormat(const char *filename, xmlDocPtr cur, const char *encoding, int format) { xmlOutputBufferPtr buf; xmlCharEncodingHandlerPtr handler = NULL; int ret;
if ((cur == NULL) || (filename == NULL)) return(-1);
xmlInitParser();
if (encoding != NULL) { xmlCharEncoding enc;
enc = xmlParseCharEncoding(encoding); if (enc != XML_CHAR_ENCODING_UTF8) { handler = xmlFindCharEncodingHandler(encoding); if (handler == NULL) htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); } htmlSetMetaEncoding(cur, (const xmlChar *) encoding); } else { htmlSetMetaEncoding(cur, (const xmlChar *) "UTF-8");
/* * Fallback to HTML or ASCII when the encoding is unspecified */ if (handler == NULL) handler = xmlFindCharEncodingHandler("HTML"); if (handler == NULL) handler = xmlFindCharEncodingHandler("ascii"); }
/* * save the content to a temp buffer. */ buf = xmlOutputBufferCreateFilename(filename, handler, 0); if (buf == NULL) return(0);
htmlDocContentDumpFormatOutput(buf, cur, encoding, format);
ret = xmlOutputBufferClose(buf); return(ret);}
/** * htmlSaveFileEnc: * @filename: the filename * @cur: the document * @encoding: the document encoding * * Dump an HTML document to a file using a given encoding * and formatting returns/spaces are added. * * returns: the number of byte written or -1 in case of failure. */inthtmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) { return(htmlSaveFileFormat(filename, cur, encoding, 1));}
#endif /* LIBXML_OUTPUT_ENABLED */
#endif /* LIBXML_HTML_ENABLED */