551 lines
18 KiB
Diff
551 lines
18 KiB
Diff
From dc6f009280e6108fe25f4c4ce32e18fb69cf496e Mon Sep 17 00:00:00 2001
|
|
From: Nick Wellnhofer <wellnhofer@aevum.de>
|
|
Date: Tue, 28 Jul 2020 19:07:19 +0200
|
|
Subject: [PATCH] Make xmlNodeDumpOutputInternal non-recursive
|
|
|
|
Fixes stack overflow with deeply nested documents.
|
|
---
|
|
xmlsave.c | 470 ++++++++++++++++++++++++++++++++------------------------------
|
|
1 file changed, 240 insertions(+), 230 deletions(-)
|
|
|
|
diff --git a/xmlsave.c b/xmlsave.c
|
|
index cf32d69..2235c8f 100644
|
|
--- a/xmlsave.c
|
|
+++ b/xmlsave.c
|
|
@@ -590,7 +590,6 @@ static int xmlSaveClearEncoding(xmlSaveCtxtPtr ctxt) {
|
|
static void
|
|
xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
|
|
#endif
|
|
-static void xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
|
|
static void xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
|
|
void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
|
|
static int xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur);
|
|
@@ -705,6 +704,7 @@ xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
|
|
static void
|
|
xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) {
|
|
xmlOutputBufferPtr buf;
|
|
+ xmlNodePtr cur;
|
|
int format, level;
|
|
|
|
if (dtd == NULL) return;
|
|
@@ -742,7 +742,9 @@ xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) {
|
|
level = ctxt->level;
|
|
ctxt->format = 0;
|
|
ctxt->level = -1;
|
|
- xmlNodeListDumpOutput(ctxt, dtd->children);
|
|
+ for (cur = dtd->children; cur != NULL; cur = cur->next) {
|
|
+ xmlNodeDumpOutputInternal(ctxt, cur);
|
|
+ }
|
|
ctxt->format = format;
|
|
ctxt->level = level;
|
|
xmlOutputBufferWrite(buf, 2, "]>");
|
|
@@ -776,58 +778,9 @@ xmlAttrDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
|
|
xmlOutputBufferWrite(buf, 1, "\"");
|
|
}
|
|
|
|
-/**
|
|
- * xmlAttrListDumpOutput:
|
|
- * @buf: the XML buffer output
|
|
- * @doc: the document
|
|
- * @cur: the first attribute pointer
|
|
- * @encoding: an optional encoding string
|
|
- *
|
|
- * Dump a list of XML attributes
|
|
- */
|
|
-static void
|
|
-xmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
|
|
- if (cur == NULL) return;
|
|
- while (cur != NULL) {
|
|
- xmlAttrDumpOutput(ctxt, cur);
|
|
- cur = cur->next;
|
|
- }
|
|
-}
|
|
-
|
|
-
|
|
-
|
|
-/**
|
|
- * xmlNodeListDumpOutput:
|
|
- * @cur: the first node
|
|
- *
|
|
- * Dump an XML node list, recursive behaviour, children are printed too.
|
|
- */
|
|
-static void
|
|
-xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
|
|
- xmlOutputBufferPtr buf;
|
|
-
|
|
- if (cur == NULL) return;
|
|
- buf = ctxt->buf;
|
|
- while (cur != NULL) {
|
|
- if ((ctxt->format == 1) && (xmlIndentTreeOutput) &&
|
|
- ((cur->type == XML_ELEMENT_NODE) ||
|
|
- (cur->type == XML_COMMENT_NODE) ||
|
|
- (cur->type == XML_PI_NODE)))
|
|
- xmlOutputBufferWrite(buf, ctxt->indent_size *
|
|
- (ctxt->level > ctxt->indent_nr ?
|
|
- ctxt->indent_nr : ctxt->level),
|
|
- ctxt->indent);
|
|
- xmlNodeDumpOutputInternal(ctxt, cur);
|
|
- if (ctxt->format == 1) {
|
|
- xmlOutputBufferWrite(buf, 1, "\n");
|
|
- }
|
|
- cur = cur->next;
|
|
- }
|
|
-}
|
|
-
|
|
#ifdef LIBXML_HTML_ENABLED
|
|
/**
|
|
- * xmlNodeDumpOutputInternal:
|
|
+ * htmlNodeDumpOutputInternal:
|
|
* @cur: the current node
|
|
*
|
|
* Dump an HTML node, recursive behaviour, children are printed too.
|
|
@@ -893,57 +846,111 @@ htmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
|
|
*/
|
|
static void
|
|
xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
|
|
- int format;
|
|
- xmlNodePtr tmp;
|
|
+ int format = ctxt->format;
|
|
+ xmlNodePtr tmp, root, unformattedNode = NULL;
|
|
+ xmlAttrPtr attr;
|
|
xmlChar *start, *end;
|
|
xmlOutputBufferPtr buf;
|
|
|
|
if (cur == NULL) return;
|
|
buf = ctxt->buf;
|
|
- if (cur->type == XML_XINCLUDE_START)
|
|
- return;
|
|
- if (cur->type == XML_XINCLUDE_END)
|
|
- return;
|
|
- if ((cur->type == XML_DOCUMENT_NODE) ||
|
|
- (cur->type == XML_HTML_DOCUMENT_NODE)) {
|
|
- xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
|
|
- return;
|
|
- }
|
|
-#ifdef LIBXML_HTML_ENABLED
|
|
- if (ctxt->options & XML_SAVE_XHTML) {
|
|
- xhtmlNodeDumpOutput(ctxt, cur);
|
|
- return;
|
|
- }
|
|
- if (((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL) &&
|
|
- (cur->doc->type == XML_HTML_DOCUMENT_NODE) &&
|
|
- ((ctxt->options & XML_SAVE_AS_XML) == 0)) ||
|
|
- (ctxt->options & XML_SAVE_AS_HTML)) {
|
|
- htmlNodeDumpOutputInternal(ctxt, cur);
|
|
- return;
|
|
- }
|
|
-#endif
|
|
- if (cur->type == XML_DTD_NODE) {
|
|
- xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
|
|
- return;
|
|
- }
|
|
- if (cur->type == XML_DOCUMENT_FRAG_NODE) {
|
|
- xmlNodeListDumpOutput(ctxt, cur->children);
|
|
- return;
|
|
- }
|
|
- if (cur->type == XML_ELEMENT_DECL) {
|
|
- xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
|
|
- return;
|
|
- }
|
|
- if (cur->type == XML_ATTRIBUTE_DECL) {
|
|
- xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
|
|
- return;
|
|
- }
|
|
- if (cur->type == XML_ENTITY_DECL) {
|
|
- xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
|
|
- return;
|
|
- }
|
|
- if (cur->type == XML_TEXT_NODE) {
|
|
- if (cur->content != NULL) {
|
|
+
|
|
+ root = cur;
|
|
+ while (1) {
|
|
+ switch (cur->type) {
|
|
+ case XML_DOCUMENT_NODE:
|
|
+ case XML_HTML_DOCUMENT_NODE:
|
|
+ xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
|
|
+ break;
|
|
+
|
|
+ case XML_DTD_NODE:
|
|
+ xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
|
|
+ break;
|
|
+
|
|
+ case XML_DOCUMENT_FRAG_NODE:
|
|
+ if (cur->children != NULL) {
|
|
+ cur = cur->children;
|
|
+ continue;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case XML_ELEMENT_DECL:
|
|
+ xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
|
|
+ break;
|
|
+
|
|
+ case XML_ATTRIBUTE_DECL:
|
|
+ xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
|
|
+ break;
|
|
+
|
|
+ case XML_ENTITY_DECL:
|
|
+ xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
|
|
+ break;
|
|
+
|
|
+ case XML_ELEMENT_NODE:
|
|
+ if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
|
|
+ xmlOutputBufferWrite(buf, ctxt->indent_size *
|
|
+ (ctxt->level > ctxt->indent_nr ?
|
|
+ ctxt->indent_nr : ctxt->level),
|
|
+ ctxt->indent);
|
|
+
|
|
+ xmlOutputBufferWrite(buf, 1, "<");
|
|
+ if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
|
|
+ xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
|
|
+ xmlOutputBufferWrite(buf, 1, ":");
|
|
+ }
|
|
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
|
+ if (cur->nsDef)
|
|
+ xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
|
|
+ for (attr = cur->properties; attr != NULL; attr = attr->next)
|
|
+ xmlAttrDumpOutput(ctxt, attr);
|
|
+
|
|
+ if (cur->children == NULL) {
|
|
+ if ((ctxt->options & XML_SAVE_NO_EMPTY) == 0) {
|
|
+ if (ctxt->format == 2)
|
|
+ xmlOutputBufferWriteWSNonSig(ctxt, 0);
|
|
+ xmlOutputBufferWrite(buf, 2, "/>");
|
|
+ } else {
|
|
+ if (ctxt->format == 2)
|
|
+ xmlOutputBufferWriteWSNonSig(ctxt, 1);
|
|
+ xmlOutputBufferWrite(buf, 3, "></");
|
|
+ if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
|
|
+ xmlOutputBufferWriteString(buf,
|
|
+ (const char *)cur->ns->prefix);
|
|
+ xmlOutputBufferWrite(buf, 1, ":");
|
|
+ }
|
|
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
|
+ if (ctxt->format == 2)
|
|
+ xmlOutputBufferWriteWSNonSig(ctxt, 0);
|
|
+ xmlOutputBufferWrite(buf, 1, ">");
|
|
+ }
|
|
+ } else {
|
|
+ if (ctxt->format == 1) {
|
|
+ tmp = cur->children;
|
|
+ while (tmp != NULL) {
|
|
+ if ((tmp->type == XML_TEXT_NODE) ||
|
|
+ (tmp->type == XML_CDATA_SECTION_NODE) ||
|
|
+ (tmp->type == XML_ENTITY_REF_NODE)) {
|
|
+ ctxt->format = 0;
|
|
+ unformattedNode = cur;
|
|
+ break;
|
|
+ }
|
|
+ tmp = tmp->next;
|
|
+ }
|
|
+ }
|
|
+ if (ctxt->format == 2)
|
|
+ xmlOutputBufferWriteWSNonSig(ctxt, 1);
|
|
+ xmlOutputBufferWrite(buf, 1, ">");
|
|
+ if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n");
|
|
+ if (ctxt->level >= 0) ctxt->level++;
|
|
+ cur = cur->children;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ break;
|
|
+
|
|
+ case XML_TEXT_NODE:
|
|
+ if (cur->content == NULL)
|
|
+ break;
|
|
if (cur->name != xmlStringTextNoenc) {
|
|
xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
|
|
} else {
|
|
@@ -952,139 +959,129 @@ xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
|
|
*/
|
|
xmlOutputBufferWriteString(buf, (const char *) cur->content);
|
|
}
|
|
- }
|
|
+ break;
|
|
|
|
- return;
|
|
- }
|
|
- if (cur->type == XML_PI_NODE) {
|
|
- if (cur->content != NULL) {
|
|
- xmlOutputBufferWrite(buf, 2, "<?");
|
|
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
|
- if (cur->content != NULL) {
|
|
- if (ctxt->format == 2)
|
|
- xmlOutputBufferWriteWSNonSig(ctxt, 0);
|
|
- else
|
|
- xmlOutputBufferWrite(buf, 1, " ");
|
|
- xmlOutputBufferWriteString(buf, (const char *)cur->content);
|
|
- }
|
|
- xmlOutputBufferWrite(buf, 2, "?>");
|
|
- } else {
|
|
- xmlOutputBufferWrite(buf, 2, "<?");
|
|
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
|
- if (ctxt->format == 2)
|
|
- xmlOutputBufferWriteWSNonSig(ctxt, 0);
|
|
- xmlOutputBufferWrite(buf, 2, "?>");
|
|
- }
|
|
- return;
|
|
- }
|
|
- if (cur->type == XML_COMMENT_NODE) {
|
|
- if (cur->content != NULL) {
|
|
- xmlOutputBufferWrite(buf, 4, "<!--");
|
|
- xmlOutputBufferWriteString(buf, (const char *)cur->content);
|
|
- xmlOutputBufferWrite(buf, 3, "-->");
|
|
- }
|
|
- return;
|
|
- }
|
|
- if (cur->type == XML_ENTITY_REF_NODE) {
|
|
- xmlOutputBufferWrite(buf, 1, "&");
|
|
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
|
- xmlOutputBufferWrite(buf, 1, ";");
|
|
- return;
|
|
- }
|
|
- if (cur->type == XML_CDATA_SECTION_NODE) {
|
|
- if (cur->content == NULL || *cur->content == '\0') {
|
|
- xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
|
|
- } else {
|
|
- start = end = cur->content;
|
|
- while (*end != '\0') {
|
|
- if ((*end == ']') && (*(end + 1) == ']') &&
|
|
- (*(end + 2) == '>')) {
|
|
- end = end + 2;
|
|
- xmlOutputBufferWrite(buf, 9, "<![CDATA[");
|
|
- xmlOutputBufferWrite(buf, end - start, (const char *)start);
|
|
- xmlOutputBufferWrite(buf, 3, "]]>");
|
|
- start = end;
|
|
- }
|
|
- end++;
|
|
- }
|
|
- if (start != end) {
|
|
- xmlOutputBufferWrite(buf, 9, "<![CDATA[");
|
|
- xmlOutputBufferWriteString(buf, (const char *)start);
|
|
- xmlOutputBufferWrite(buf, 3, "]]>");
|
|
- }
|
|
- }
|
|
- return;
|
|
- }
|
|
- if (cur->type == XML_ATTRIBUTE_NODE) {
|
|
- xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
|
|
- return;
|
|
- }
|
|
- if (cur->type == XML_NAMESPACE_DECL) {
|
|
- xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
|
|
- return;
|
|
- }
|
|
+ case XML_PI_NODE:
|
|
+ if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
|
|
+ xmlOutputBufferWrite(buf, ctxt->indent_size *
|
|
+ (ctxt->level > ctxt->indent_nr ?
|
|
+ ctxt->indent_nr : ctxt->level),
|
|
+ ctxt->indent);
|
|
|
|
- format = ctxt->format;
|
|
- if (format == 1) {
|
|
- tmp = cur->children;
|
|
- while (tmp != NULL) {
|
|
- if ((tmp->type == XML_TEXT_NODE) ||
|
|
- (tmp->type == XML_CDATA_SECTION_NODE) ||
|
|
- (tmp->type == XML_ENTITY_REF_NODE)) {
|
|
- ctxt->format = 0;
|
|
- break;
|
|
- }
|
|
- tmp = tmp->next;
|
|
- }
|
|
- }
|
|
- xmlOutputBufferWrite(buf, 1, "<");
|
|
- if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
|
|
- xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
|
|
- xmlOutputBufferWrite(buf, 1, ":");
|
|
- }
|
|
+ if (cur->content != NULL) {
|
|
+ xmlOutputBufferWrite(buf, 2, "<?");
|
|
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
|
+ if (cur->content != NULL) {
|
|
+ if (ctxt->format == 2)
|
|
+ xmlOutputBufferWriteWSNonSig(ctxt, 0);
|
|
+ else
|
|
+ xmlOutputBufferWrite(buf, 1, " ");
|
|
+ xmlOutputBufferWriteString(buf,
|
|
+ (const char *)cur->content);
|
|
+ }
|
|
+ xmlOutputBufferWrite(buf, 2, "?>");
|
|
+ } else {
|
|
+ xmlOutputBufferWrite(buf, 2, "<?");
|
|
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
|
+ if (ctxt->format == 2)
|
|
+ xmlOutputBufferWriteWSNonSig(ctxt, 0);
|
|
+ xmlOutputBufferWrite(buf, 2, "?>");
|
|
+ }
|
|
+ break;
|
|
|
|
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
|
- if (cur->nsDef)
|
|
- xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
|
|
- if (cur->properties != NULL)
|
|
- xmlAttrListDumpOutput(ctxt, cur->properties);
|
|
-
|
|
- if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
|
|
- (cur->children == NULL) && ((ctxt->options & XML_SAVE_NO_EMPTY) == 0)) {
|
|
- if (ctxt->format == 2)
|
|
- xmlOutputBufferWriteWSNonSig(ctxt, 0);
|
|
- xmlOutputBufferWrite(buf, 2, "/>");
|
|
- ctxt->format = format;
|
|
- return;
|
|
- }
|
|
- if (ctxt->format == 2)
|
|
- xmlOutputBufferWriteWSNonSig(ctxt, 1);
|
|
- xmlOutputBufferWrite(buf, 1, ">");
|
|
- if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
|
|
- xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
|
|
- }
|
|
- if (cur->children != NULL) {
|
|
- if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n");
|
|
- if (ctxt->level >= 0) ctxt->level++;
|
|
- xmlNodeListDumpOutput(ctxt, cur->children);
|
|
- if (ctxt->level > 0) ctxt->level--;
|
|
- if ((xmlIndentTreeOutput) && (ctxt->format == 1))
|
|
- xmlOutputBufferWrite(buf, ctxt->indent_size *
|
|
- (ctxt->level > ctxt->indent_nr ?
|
|
- ctxt->indent_nr : ctxt->level),
|
|
- ctxt->indent);
|
|
- }
|
|
- xmlOutputBufferWrite(buf, 2, "</");
|
|
- if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
|
|
- xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
|
|
- xmlOutputBufferWrite(buf, 1, ":");
|
|
- }
|
|
+ case XML_COMMENT_NODE:
|
|
+ if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
|
|
+ xmlOutputBufferWrite(buf, ctxt->indent_size *
|
|
+ (ctxt->level > ctxt->indent_nr ?
|
|
+ ctxt->indent_nr : ctxt->level),
|
|
+ ctxt->indent);
|
|
|
|
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
|
- if (ctxt->format == 2)
|
|
- xmlOutputBufferWriteWSNonSig(ctxt, 0);
|
|
- xmlOutputBufferWrite(buf, 1, ">");
|
|
- ctxt->format = format;
|
|
+ if (cur->content != NULL) {
|
|
+ xmlOutputBufferWrite(buf, 4, "<!--");
|
|
+ xmlOutputBufferWriteString(buf, (const char *)cur->content);
|
|
+ xmlOutputBufferWrite(buf, 3, "-->");
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case XML_ENTITY_REF_NODE:
|
|
+ xmlOutputBufferWrite(buf, 1, "&");
|
|
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
|
+ xmlOutputBufferWrite(buf, 1, ";");
|
|
+ break;
|
|
+
|
|
+ case XML_CDATA_SECTION_NODE:
|
|
+ if (cur->content == NULL || *cur->content == '\0') {
|
|
+ xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
|
|
+ } else {
|
|
+ start = end = cur->content;
|
|
+ while (*end != '\0') {
|
|
+ if ((*end == ']') && (*(end + 1) == ']') &&
|
|
+ (*(end + 2) == '>')) {
|
|
+ end = end + 2;
|
|
+ xmlOutputBufferWrite(buf, 9, "<![CDATA[");
|
|
+ xmlOutputBufferWrite(buf, end - start,
|
|
+ (const char *)start);
|
|
+ xmlOutputBufferWrite(buf, 3, "]]>");
|
|
+ start = end;
|
|
+ }
|
|
+ end++;
|
|
+ }
|
|
+ if (start != end) {
|
|
+ xmlOutputBufferWrite(buf, 9, "<![CDATA[");
|
|
+ xmlOutputBufferWriteString(buf, (const char *)start);
|
|
+ xmlOutputBufferWrite(buf, 3, "]]>");
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case XML_ATTRIBUTE_NODE:
|
|
+ xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
|
|
+ break;
|
|
+
|
|
+ case XML_NAMESPACE_DECL:
|
|
+ xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ while (1) {
|
|
+ if (cur == root)
|
|
+ return;
|
|
+ if (ctxt->format == 1) {
|
|
+ xmlOutputBufferWrite(buf, 1, "\n");
|
|
+ }
|
|
+ if (cur->next != NULL) {
|
|
+ cur = cur->next;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ cur = cur->parent;
|
|
+
|
|
+ if (ctxt->level > 0) ctxt->level--;
|
|
+ if ((xmlIndentTreeOutput) && (ctxt->format == 1))
|
|
+ xmlOutputBufferWrite(buf, ctxt->indent_size *
|
|
+ (ctxt->level > ctxt->indent_nr ?
|
|
+ ctxt->indent_nr : ctxt->level),
|
|
+ ctxt->indent);
|
|
+ if (cur == unformattedNode) {
|
|
+ ctxt->format = format;
|
|
+ unformattedNode = NULL;
|
|
+ }
|
|
+
|
|
+ xmlOutputBufferWrite(buf, 2, "</");
|
|
+ if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
|
|
+ xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
|
|
+ xmlOutputBufferWrite(buf, 1, ":");
|
|
+ }
|
|
+
|
|
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
|
+ if (ctxt->format == 2)
|
|
+ xmlOutputBufferWriteWSNonSig(ctxt, 0);
|
|
+ xmlOutputBufferWrite(buf, 1, ">");
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
/**
|
|
@@ -1865,12 +1862,25 @@ xmlSaveDoc(xmlSaveCtxtPtr ctxt, xmlDocPtr doc)
|
|
* Returns the number of byte written or -1 in case of error
|
|
*/
|
|
long
|
|
-xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr node)
|
|
+xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr cur)
|
|
{
|
|
long ret = 0;
|
|
|
|
- if ((ctxt == NULL) || (node == NULL)) return(-1);
|
|
- xmlNodeDumpOutputInternal(ctxt, node);
|
|
+ if ((ctxt == NULL) || (cur == NULL)) return(-1);
|
|
+#ifdef LIBXML_HTML_ENABLED
|
|
+ if (ctxt->options & XML_SAVE_XHTML) {
|
|
+ xhtmlNodeDumpOutput(ctxt, cur);
|
|
+ return(ret);
|
|
+ }
|
|
+ if (((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL) &&
|
|
+ (cur->doc->type == XML_HTML_DOCUMENT_NODE) &&
|
|
+ ((ctxt->options & XML_SAVE_AS_XML) == 0)) ||
|
|
+ (ctxt->options & XML_SAVE_AS_HTML)) {
|
|
+ htmlNodeDumpOutputInternal(ctxt, cur);
|
|
+ return(ret);
|
|
+ }
|
|
+#endif
|
|
+ xmlNodeDumpOutputInternal(ctxt, cur);
|
|
return(ret);
|
|
}
|
|
|
|
--
|
|
1.8.3.1
|
|
|