diff --git a/ChangeLog b/ChangeLog index 7e4402b4..814dae9f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Thu Mar 4 14:39:38 CET 2004 Daniel Veillard + + * Makefile.am tree.c xmlsave.c include/libxml/xmlsave.h: commiting + the new xmlsave module before the actuall big code change. + Thu Mar 4 12:38:53 CET 2004 Daniel Veillard * xmlschemas.c: applied patch from Adam Dickmeiss for mixed content diff --git a/Makefile.am b/Makefile.am index f9feb84b..70d350ff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,7 +27,7 @@ libxml2_la_SOURCES = SAX.c entities.c encoding.c error.c parserInternals.c \ catalog.c globals.c threads.c c14n.c xmlstring.c \ xmlregexp.c xmlschemas.c xmlschemastypes.c xmlunicode.c \ triostr.c trio.c xmlreader.c relaxng.c dict.c SAX2.c \ - xmlwriter.c legacy.c chvalid.c pattern.c + xmlwriter.c legacy.c chvalid.c pattern.c xmlsave.c else libxml2_la_SOURCES = SAX.c entities.c encoding.c error.c parserInternals.c \ parser.c tree.c hash.c list.c xmlIO.c xmlmemory.c uri.c \ @@ -36,7 +36,7 @@ libxml2_la_SOURCES = SAX.c entities.c encoding.c error.c parserInternals.c \ catalog.c globals.c threads.c c14n.c xmlstring.c \ xmlregexp.c xmlschemas.c xmlschemastypes.c xmlunicode.c \ xmlreader.c relaxng.c dict.c SAX2.c \ - xmlwriter.c legacy.c chvalid.c pattern.c + xmlwriter.c legacy.c chvalid.c pattern.c xmlsave.c endif DEPS = $(top_builddir)/libxml2.la diff --git a/include/libxml/xmlsave.h b/include/libxml/xmlsave.h new file mode 100644 index 00000000..f783ffd6 --- /dev/null +++ b/include/libxml/xmlsave.h @@ -0,0 +1,59 @@ +/* + * Summary: the XML document serializer + * Description: API to save document or subtree of document + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XMLSAVE_H__ +#define __XML_XMLSAVE_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _xmlSaveCtxt xmlSaveCtxt; +typedef xmlSaveCtxt *xmlSaveCtxtPtr; + +XMLPUBFUN xmlSaveCtxtPtr XMLCALL + xmlSaveToFd (int fd, + const char *encoding, + int options); +XMLPUBFUN xmlSaveCtxtPtr XMLCALL + xmlSaveToFilename (const char *filename, + const char *encoding, + int options); +XMLPUBFUN xmlSaveCtxtPtr XMLCALL + xmlSaveToBuffer (xmlBufferPtr buffer, + const char *encoding, + int options); +XMLPUBFUN xmlSaveCtxtPtr XMLCALL + xmlSaveToIO (xmlOutputWriteCallback iowrite, + xmlOutputCloseCallback ioclose, + void *ioctx, + const char *encoding, + int options); + +XMLPUBFUN long XMLCALL + xmlSaveDoc (xmlSaveCtxtPtr ctxt, + xmlDocPtr doc); +XMLPUBFUN long XMLCALL + xmlSaveTree (xmlSaveCtxtPtr ctxt, + xmlNodePtr node); + +XMLPUBFUN int XMLCALL + xmlSaveFlush (xmlSaveCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlSaveClose (xmlSaveCtxtPtr ctxt); +#ifdef __cplusplus +} +#endif +#endif /* __XML_XMLSAVE_H__ */ + + diff --git a/tree.c b/tree.c index 84290819..330197dc 100644 --- a/tree.c +++ b/tree.c @@ -6948,1692 +6948,6 @@ xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) { } -#ifdef LIBXML_OUTPUT_ENABLED -/************************************************************************ - * * - * Output error handlers * - * * - ************************************************************************/ -/** - * xmlSaveErrMemory: - * @extra: extra informations - * - * Handle an out of memory condition - */ -static void -xmlSaveErrMemory(const char *extra) -{ - __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra); -} - -/** - * xmlSaveErr: - * @code: the error number - * @node: the location of the error. - * @extra: extra informations - * - * Handle an out of memory condition - */ -static void -xmlSaveErr(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"; - break; - case XML_SAVE_CHAR_INVALID: - msg = "invalid character value"; - break; - case XML_SAVE_UNKNOWN_ENCODING: - msg = "unknown encoding %s"; - break; - case XML_SAVE_NO_DOCTYPE: - msg = "document has no DOCTYPE"; - break; - default: - msg = "unexpected error number"; - } - __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra); -} -/************************************************************************ - * * - * Dumping XML tree content to a simple buffer * - * * - ************************************************************************/ -/** - * xmlAttrSerializeTxtContent: - * @buf: the XML buffer output - * @doc: the document - * @attr: the attribute node - * @string: the text content - * - * Serialize text attribute values to an xml simple buffer - */ -void -xmlAttrSerializeTxtContent(xmlBufferPtr buf, xmlDocPtr doc, - xmlAttrPtr attr, const xmlChar *string) { - xmlChar *base, *cur; - - if (string == NULL) return; - base = cur = (xmlChar *)string; - while (*cur != 0) { - if (*cur == '\n') { - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferAdd(buf, BAD_CAST " ", 5); - cur++; - base = cur; - } else if (*cur == '\r') { - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferAdd(buf, BAD_CAST " ", 5); - cur++; - base = cur; - } else if (*cur == '\t') { - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferAdd(buf, BAD_CAST " ", 4); - cur++; - base = cur; -#if 0 - base = cur = children->content; - } else if (*cur == '\'') { - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferAdd(buf, BAD_CAST "'", 6); - cur++; - base = cur; -#endif - } else if (*cur == '"') { - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferAdd(buf, BAD_CAST """, 6); - cur++; - base = cur; - } else if (*cur == '<') { - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferAdd(buf, BAD_CAST "<", 4); - cur++; - base = cur; - } else if (*cur == '>') { - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferAdd(buf, BAD_CAST ">", 4); - cur++; - base = cur; - } else if (*cur == '&') { - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferAdd(buf, BAD_CAST "&", 5); - cur++; - base = cur; - } else if ((*cur >= 0x80) && ((doc == NULL) || - (doc->encoding == NULL))) { - /* - * We assume we have UTF-8 content. - */ - char tmp[10]; - int val = 0, l = 1; - - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - if (*cur < 0xC0) { - xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr, NULL); - if (doc != NULL) - doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); - snprintf(tmp, sizeof(tmp), "&#%d;", *cur); - tmp[sizeof(tmp) - 1] = 0; - xmlBufferAdd(buf, (xmlChar *) tmp, -1); - cur++; - base = cur; - continue; - } else if (*cur < 0xE0) { - val = (cur[0]) & 0x1F; - val <<= 6; - val |= (cur[1]) & 0x3F; - l = 2; - } else if (*cur < 0xF0) { - val = (cur[0]) & 0x0F; - val <<= 6; - val |= (cur[1]) & 0x3F; - val <<= 6; - val |= (cur[2]) & 0x3F; - l = 3; - } else if (*cur < 0xF8) { - val = (cur[0]) & 0x07; - val <<= 6; - val |= (cur[1]) & 0x3F; - val <<= 6; - val |= (cur[2]) & 0x3F; - val <<= 6; - val |= (cur[3]) & 0x3F; - l = 4; - } - if ((l == 1) || (!IS_CHAR(val))) { - xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr, NULL); - if (doc != NULL) - doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); - snprintf(tmp, sizeof(tmp), "&#%d;", *cur); - tmp[sizeof(tmp) - 1] = 0; - xmlBufferAdd(buf, (xmlChar *) tmp, -1); - cur++; - base = cur; - continue; - } - /* - * We could do multiple things here. Just save - * as a char ref - */ - snprintf(tmp, sizeof(tmp), "&#x%X;", val); - tmp[sizeof(tmp) - 1] = 0; - xmlBufferAdd(buf, (xmlChar *) tmp, -1); - cur += l; - base = cur; - } else { - cur++; - } - } - if (base != cur) - xmlBufferAdd(buf, base, cur - base); -} - -/** - * xmlAttrSerializeContent: - * @buf: the XML buffer output - * @doc: the document - * @attr: the attribute pointer - * - * Serialize the attribute in the buffer - */ -static void -xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) -{ - xmlNodePtr children; - - children = attr->children; - while (children != NULL) { - switch (children->type) { - case XML_TEXT_NODE: - xmlAttrSerializeTxtContent(buf, doc, attr, children->content); - break; - case XML_ENTITY_REF_NODE: - xmlBufferAdd(buf, BAD_CAST "&", 1); - xmlBufferAdd(buf, children->name, - xmlStrlen(children->name)); - xmlBufferAdd(buf, BAD_CAST ";", 1); - break; - default: - /* should not happen unless we have a badly built tree */ - break; - } - children = children->next; - } -} - -/** - * xmlNodeDump: - * @buf: the XML buffer output - * @doc: the document - * @cur: the current node - * @level: the imbrication level for indenting - * @format: is formatting allowed - * - * Dump an XML node, recursive behaviour,children are printed too. - * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 - * or xmlKeepBlanksDefault(0) was called - * - * Returns the number of bytes written to the buffer or -1 in case of error - */ -int -xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, - int format) -{ - unsigned int use; - int ret; - xmlOutputBufferPtr outbuf; - - xmlInitParser(); - - if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNodeDump : node == NULL\n"); -#endif - return (-1); - } - if (buf == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNodeDump : buf == NULL\n"); -#endif - return (-1); - } - outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); - if (outbuf == NULL) { - xmlSaveErrMemory("creating buffer"); - return (-1); - } - memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer)); - outbuf->buffer = buf; - outbuf->encoder = NULL; - outbuf->writecallback = NULL; - outbuf->closecallback = NULL; - outbuf->context = NULL; - outbuf->written = 0; - - use = buf->use; - xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL); - xmlFree(outbuf); - ret = buf->use - use; - return (ret); -} - -/** - * xmlElemDump: - * @f: the FILE * for the output - * @doc: the document - * @cur: the current node - * - * Dump an XML/HTML node, recursive behaviour, children are printed too. - */ -void -xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur) -{ - xmlOutputBufferPtr outbuf; - - xmlInitParser(); - - if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlElemDump : cur == NULL\n"); -#endif - return; - } -#ifdef DEBUG_TREE - if (doc == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlElemDump : doc == NULL\n"); - } -#endif - - outbuf = xmlOutputBufferCreateFile(f, NULL); - if (outbuf == NULL) - return; - if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) { -#ifdef LIBXML_HTML_ENABLED - htmlNodeDumpOutput(outbuf, doc, cur, NULL); -#else - xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n"); -#endif /* LIBXML_HTML_ENABLED */ - } else - xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL); - xmlOutputBufferClose(outbuf); -} - -/************************************************************************ - * * - * Dumping XML tree content to an I/O output buffer * - * * - ************************************************************************/ - -#ifdef LIBXML_HTML_ENABLED -static void -xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, - int level, int format, const char *encoding); -#endif -static void -xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, - int level, int format, const char *encoding); -static void -xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc, - xmlNodePtr cur, int level, int format, const char *encoding); - -void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur); - -/** - * xmlNsDumpOutput: - * @buf: the XML buffer output - * @cur: a namespace - * - * Dump a local Namespace definition. - * Should be called in the context of attributes dumps. - */ -static void -xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) { - if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNsDumpOutput : Ns == NULL\n"); -#endif - return; - } - if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) { - if (xmlStrEqual(cur->prefix, BAD_CAST "xml")) - return; - - /* Within the context of an element attributes */ - if (cur->prefix != NULL) { - xmlOutputBufferWriteString(buf, " xmlns:"); - xmlOutputBufferWriteString(buf, (const char *)cur->prefix); - } else - xmlOutputBufferWriteString(buf, " xmlns"); - xmlOutputBufferWriteString(buf, "="); - xmlBufferWriteQuotedString(buf->buffer, cur->href); - } -} - -/** - * xmlNsListDumpOutput: - * @buf: the XML buffer output - * @cur: the first namespace - * - * Dump a list of local Namespace definitions. - * Should be called in the context of attributes dumps. - */ -void -xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) { - while (cur != NULL) { - xmlNsDumpOutput(buf, cur); - cur = cur->next; - } -} - -/** - * xmlDtdDumpOutput: - * @buf: the XML buffer output - * @doc: the document - * @encoding: an optional encoding string - * - * Dump the XML document DTD, if any. - */ -static void -xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) { - if (dtd == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlDtdDumpOutput : no internal subset\n"); -#endif - return; - } - xmlOutputBufferWriteString(buf, "name); - if (dtd->ExternalID != NULL) { - xmlOutputBufferWriteString(buf, " PUBLIC "); - xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID); - xmlOutputBufferWriteString(buf, " "); - xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID); - } else if (dtd->SystemID != NULL) { - xmlOutputBufferWriteString(buf, " SYSTEM "); - xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID); - } - if ((dtd->entities == NULL) && (dtd->elements == NULL) && - (dtd->attributes == NULL) && (dtd->notations == NULL) && - (dtd->pentities == NULL)) { - xmlOutputBufferWriteString(buf, ">"); - return; - } - xmlOutputBufferWriteString(buf, " [\n"); - xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding); - xmlOutputBufferWriteString(buf, "]>"); -} - -/** - * xmlAttrDumpOutput: - * @buf: the XML buffer output - * @doc: the document - * @cur: the attribute pointer - * @encoding: an optional encoding string - * - * Dump an XML attribute - */ -static void -xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur, - const char *encoding ATTRIBUTE_UNUSED) { - if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlAttrDumpOutput : property == NULL\n"); -#endif - 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); - xmlOutputBufferWriteString(buf, "=\""); - xmlAttrSerializeContent(buf->buffer, doc, cur); - xmlOutputBufferWriteString(buf, "\""); -} - -/** - * 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(xmlOutputBufferPtr buf, xmlDocPtr doc, - xmlAttrPtr cur, const char *encoding) { - if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlAttrListDumpOutput : property == NULL\n"); -#endif - return; - } - while (cur != NULL) { - xmlAttrDumpOutput(buf, doc, cur, encoding); - cur = cur->next; - } -} - - - -/** - * xmlNodeListDumpOutput: - * @buf: the XML buffer output - * @doc: the document - * @cur: the first node - * @level: the imbrication level for indenting - * @format: is formatting allowed - * @encoding: an optional encoding string - * - * Dump an XML node list, recursive behaviour, children are printed too. - * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 - * or xmlKeepBlanksDefault(0) was called - */ -static void -xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, - xmlNodePtr cur, int level, int format, const char *encoding) { - int i; - - if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNodeListDumpOutput : node == NULL\n"); -#endif - return; - } - while (cur != NULL) { - if ((format) && (xmlIndentTreeOutput) && - (cur->type == XML_ELEMENT_NODE)) - for (i = 0;i < level;i++) - xmlOutputBufferWriteString(buf, xmlTreeIndentString); - xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding); - if (format) { - xmlOutputBufferWriteString(buf, "\n"); - } - cur = cur->next; - } -} - -/** - * xmlNodeDumpOutputInternal: - * @buf: the XML buffer output - * @doc: the document - * @cur: the current node - * @level: the imbrication level for indenting - * @format: is formatting allowed - * @encoding: an optional encoding string - * - * Dump an XML node, recursive behaviour, children are printed too. - * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 - * or xmlKeepBlanksDefault(0) was called - */ -static void -xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc, - xmlNodePtr cur, int level, int format, const char *encoding) { - int i; - xmlNodePtr tmp; - xmlChar *start, *end; - - if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNodeDumpOutput : node == NULL\n"); -#endif - return; - } - if (cur->type == XML_XINCLUDE_START) - return; - if (cur->type == XML_XINCLUDE_END) - return; - if (cur->type == XML_DTD_NODE) { - xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding); - return; - } - if (cur->type == XML_DOCUMENT_FRAG_NODE) { - xmlNodeListDumpOutput(buf, doc, cur->children, level, format, encoding); - return; - } - if (cur->type == XML_ELEMENT_DECL) { - xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur); - return; - } - if (cur->type == XML_ATTRIBUTE_DECL) { - xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur); - return; - } - if (cur->type == XML_ENTITY_DECL) { - xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur); - return; - } - if (cur->type == XML_TEXT_NODE) { - if (cur->content != NULL) { - if ((cur->name == xmlStringText) || - (cur->name != xmlStringTextNoenc)) { - xmlChar *buffer; - - if (encoding == NULL) - buffer = xmlEncodeEntitiesReentrant(doc, cur->content); - else - buffer = xmlEncodeSpecialChars(doc, cur->content); - if (buffer != NULL) { - xmlOutputBufferWriteString(buf, (const char *)buffer); - xmlFree(buffer); - } - } else { - /* - * Disable escaping, needed for XSLT - */ - xmlOutputBufferWriteString(buf, (const char *) cur->content); - } - } - - return; - } - if (cur->type == XML_PI_NODE) { - if (cur->content != NULL) { - xmlOutputBufferWriteString(buf, "name); - if (cur->content != NULL) { - xmlOutputBufferWriteString(buf, " "); - xmlOutputBufferWriteString(buf, (const char *)cur->content); - } - xmlOutputBufferWriteString(buf, "?>"); - } else { - xmlOutputBufferWriteString(buf, "name); - xmlOutputBufferWriteString(buf, "?>"); - } - return; - } - if (cur->type == XML_COMMENT_NODE) { - if (cur->content != NULL) { - xmlOutputBufferWriteString(buf, ""); - } - return; - } - if (cur->type == XML_ENTITY_REF_NODE) { - xmlOutputBufferWriteString(buf, "&"); - xmlOutputBufferWriteString(buf, (const char *)cur->name); - xmlOutputBufferWriteString(buf, ";"); - return; - } - if (cur->type == XML_CDATA_SECTION_NODE) { - start = end = cur->content; - while (*end != '\0') { - if ((*end == ']') && (*(end + 1) == ']') && (*(end + 2) == '>')) { - end = end + 2; - xmlOutputBufferWriteString(buf, ""); - start = end; - } - end++; - } - if (start != end) { - xmlOutputBufferWriteString(buf, ""); - } - return; - } - if (cur->type == XML_ATTRIBUTE_NODE) { - xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding); - return; - } - if (cur->type == XML_NAMESPACE_DECL) { - xmlNsDumpOutput(buf, (xmlNsPtr) cur); - return; - } - - 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)) { - format = 0; - break; - } - tmp = tmp->next; - } - } - 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); - if (cur->properties != NULL) - xmlAttrListDumpOutput(buf, doc, cur->properties, encoding); - - if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) && - (cur->children == NULL) && (!xmlSaveNoEmptyTags)) { - xmlOutputBufferWriteString(buf, "/>"); - return; - } - xmlOutputBufferWriteString(buf, ">"); - if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) { - xmlChar *buffer; - - if (encoding == NULL) - buffer = xmlEncodeEntitiesReentrant(doc, cur->content); - else - buffer = xmlEncodeSpecialChars(doc, cur->content); - if (buffer != NULL) { - xmlOutputBufferWriteString(buf, (const char *)buffer); - xmlFree(buffer); - } - } - if (cur->children != NULL) { - if (format) xmlOutputBufferWriteString(buf, "\n"); - xmlNodeListDumpOutput(buf, doc, cur->children, - (level >= 0?level+1:-1), format, encoding); - if ((xmlIndentTreeOutput) && (format)) - for (i = 0;i < level;i++) - xmlOutputBufferWriteString(buf, xmlTreeIndentString); - } - xmlOutputBufferWriteString(buf, "ns != NULL) && (cur->ns->prefix != NULL)) { - xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); - xmlOutputBufferWriteString(buf, ":"); - } - - xmlOutputBufferWriteString(buf, (const char *)cur->name); - xmlOutputBufferWriteString(buf, ">"); -} - -/** - * xmlNodeDumpOutput: - * @buf: the XML buffer output - * @doc: the document - * @cur: the current node - * @level: the imbrication level for indenting - * @format: is formatting allowed - * @encoding: an optional encoding string - * - * Dump an XML node, recursive behaviour, children are printed too. - * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 - * or xmlKeepBlanksDefault(0) was called - */ -void -xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, - int level, int format, const char *encoding) -{ -#ifdef LIBXML_HTML_ENABLED - xmlDtdPtr dtd; - int is_xhtml = 0; -#endif - - xmlInitParser(); - -#ifdef LIBXML_HTML_ENABLED - dtd = xmlGetIntSubset(doc); - if (dtd != NULL) { - is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID); - if (is_xhtml < 0) - is_xhtml = 0; - if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) && - (cur->type == XML_ELEMENT_NODE) && - (xmlStrEqual(cur->name, BAD_CAST "html"))) { - if (encoding != NULL) - htmlSetMetaEncoding((htmlDocPtr) doc, - (const xmlChar *) encoding); - else - htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8"); - } - } - - if (is_xhtml) - xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding); - else -#endif - xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding); -} - -/** - * xmlDocContentDumpOutput: - * @buf: the XML buffer output - * @cur: the document - * @encoding: an optional encoding string - * @format: should formatting spaces been added - * - * Dump an XML document. - * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 - * or xmlKeepBlanksDefault(0) was called - */ -static void -xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur, - const char *encoding, int format) { -#ifdef LIBXML_HTML_ENABLED - xmlDtdPtr dtd; - int is_xhtml = 0; -#endif - const xmlChar *oldenc = cur->encoding; - - xmlInitParser(); - - if (encoding != NULL) - cur->encoding = BAD_CAST encoding; - - xmlOutputBufferWriteString(buf, "version != NULL) - xmlBufferWriteQuotedString(buf->buffer, cur->version); - else - xmlOutputBufferWriteString(buf, "\"1.0\""); - if (encoding == NULL) { - if (cur->encoding != NULL) - encoding = (const char *) cur->encoding; - else if (cur->charset != XML_CHAR_ENCODING_UTF8) - encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset); - } - if (encoding != NULL) { - xmlOutputBufferWriteString(buf, " encoding="); - xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding); - } - switch (cur->standalone) { - case 0: - xmlOutputBufferWriteString(buf, " standalone=\"no\""); - break; - case 1: - xmlOutputBufferWriteString(buf, " standalone=\"yes\""); - break; - } - xmlOutputBufferWriteString(buf, "?>\n"); - -#ifdef LIBXML_HTML_ENABLED - dtd = xmlGetIntSubset(cur); - if (dtd != NULL) { - is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID); - if (is_xhtml < 0) is_xhtml = 0; - } - if (is_xhtml) { - if (encoding != NULL) - htmlSetMetaEncoding(cur, (const xmlChar *) encoding); - else - htmlSetMetaEncoding(cur, BAD_CAST "UTF-8"); - } -#endif - if (cur->children != NULL) { - xmlNodePtr child = cur->children; - - while (child != NULL) { -#ifdef LIBXML_HTML_ENABLED - if (is_xhtml) - xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding); - else -#endif - xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding); - xmlOutputBufferWriteString(buf, "\n"); - child = child->next; - } - } - if (encoding != NULL) - cur->encoding = oldenc; -} -#endif /* LIBXML_OUTPUT_ENABLED */ - -#ifdef LIBXML_HTML_ENABLED -/************************************************************************ - * * - * Functions specific to XHTML serialization * - * * - ************************************************************************/ - -#define XHTML_STRICT_PUBLIC_ID BAD_CAST \ - "-//W3C//DTD XHTML 1.0 Strict//EN" -#define XHTML_STRICT_SYSTEM_ID BAD_CAST \ - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" -#define XHTML_FRAME_PUBLIC_ID BAD_CAST \ - "-//W3C//DTD XHTML 1.0 Frameset//EN" -#define XHTML_FRAME_SYSTEM_ID BAD_CAST \ - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd" -#define XHTML_TRANS_PUBLIC_ID BAD_CAST \ - "-//W3C//DTD XHTML 1.0 Transitional//EN" -#define XHTML_TRANS_SYSTEM_ID BAD_CAST \ - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" - -#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml" -/** - * xmlIsXHTML: - * @systemID: the system identifier - * @publicID: the public identifier - * - * Try to find if the document correspond to an XHTML DTD - * - * Returns 1 if true, 0 if not and -1 in case of error - */ -int -xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) { - if ((systemID == NULL) && (publicID == NULL)) - return(-1); - if (publicID != NULL) { - if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1); - if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1); - if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1); - } - if (systemID != NULL) { - if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1); - if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1); - if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1); - } - return(0); -} - -#ifdef LIBXML_OUTPUT_ENABLED -/** - * xhtmlIsEmpty: - * @node: the node - * - * Check if a node is an empty xhtml node - * - * Returns 1 if the node is an empty node, 0 if not and -1 in case of error - */ -static int -xhtmlIsEmpty(xmlNodePtr node) { - if (node == NULL) - return(-1); - if (node->type != XML_ELEMENT_NODE) - return(0); - if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME))) - return(0); - if (node->children != NULL) - return(0); - switch (node->name[0]) { - case 'a': - if (xmlStrEqual(node->name, BAD_CAST "area")) - return(1); - return(0); - case 'b': - if (xmlStrEqual(node->name, BAD_CAST "br")) - return(1); - if (xmlStrEqual(node->name, BAD_CAST "base")) - return(1); - if (xmlStrEqual(node->name, BAD_CAST "basefont")) - return(1); - return(0); - case 'c': - if (xmlStrEqual(node->name, BAD_CAST "col")) - return(1); - return(0); - case 'f': - if (xmlStrEqual(node->name, BAD_CAST "frame")) - return(1); - return(0); - case 'h': - if (xmlStrEqual(node->name, BAD_CAST "hr")) - return(1); - return(0); - case 'i': - if (xmlStrEqual(node->name, BAD_CAST "img")) - return(1); - if (xmlStrEqual(node->name, BAD_CAST "input")) - return(1); - if (xmlStrEqual(node->name, BAD_CAST "isindex")) - return(1); - return(0); - case 'l': - if (xmlStrEqual(node->name, BAD_CAST "link")) - return(1); - return(0); - case 'm': - if (xmlStrEqual(node->name, BAD_CAST "meta")) - return(1); - return(0); - case 'p': - if (xmlStrEqual(node->name, BAD_CAST "param")) - return(1); - return(0); - } - return(0); -} - -/** - * xhtmlAttrListDumpOutput: - * @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 -xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, - xmlAttrPtr cur, const char *encoding) { - xmlAttrPtr xml_lang = NULL; - xmlAttrPtr lang = NULL; - xmlAttrPtr name = NULL; - xmlAttrPtr id = NULL; - xmlNodePtr parent; - - if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlAttrListDumpOutput : property == NULL\n"); -#endif - return; - } - parent = cur->parent; - while (cur != NULL) { - if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id"))) - id = cur; - else - if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name"))) - name = cur; - else - if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang"))) - lang = cur; - else - if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) && - (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml"))) - xml_lang = cur; - else if ((cur->ns == NULL) && - ((cur->children == NULL) || - (cur->children->content == NULL) || - (cur->children->content[0] == 0)) && - (htmlIsBooleanAttr(cur->name))) { - if (cur->children != NULL) - xmlFreeNode(cur->children); - cur->children = xmlNewText(cur->name); - if (cur->children != NULL) - cur->children->parent = (xmlNodePtr) cur; - } - xmlAttrDumpOutput(buf, doc, cur, encoding); - cur = cur->next; - } - /* - * C.8 - */ - if ((name != NULL) && (id == NULL)) { - if ((parent != NULL) && (parent->name != NULL) && - ((xmlStrEqual(parent->name, BAD_CAST "a")) || - (xmlStrEqual(parent->name, BAD_CAST "p")) || - (xmlStrEqual(parent->name, BAD_CAST "div")) || - (xmlStrEqual(parent->name, BAD_CAST "img")) || - (xmlStrEqual(parent->name, BAD_CAST "map")) || - (xmlStrEqual(parent->name, BAD_CAST "applet")) || - (xmlStrEqual(parent->name, BAD_CAST "form")) || - (xmlStrEqual(parent->name, BAD_CAST "frame")) || - (xmlStrEqual(parent->name, BAD_CAST "iframe")))) { - xmlOutputBufferWriteString(buf, " id=\""); - xmlAttrSerializeContent(buf->buffer, doc, name); - xmlOutputBufferWriteString(buf, "\""); - } - } - /* - * C.7. - */ - if ((lang != NULL) && (xml_lang == NULL)) { - xmlOutputBufferWriteString(buf, " xml:lang=\""); - xmlAttrSerializeContent(buf->buffer, doc, lang); - xmlOutputBufferWriteString(buf, "\""); - } else - if ((xml_lang != NULL) && (lang == NULL)) { - xmlOutputBufferWriteString(buf, " lang=\""); - xmlAttrSerializeContent(buf->buffer, doc, xml_lang); - xmlOutputBufferWriteString(buf, "\""); - } -} - -/** - * xhtmlNodeListDumpOutput: - * @buf: the XML buffer output - * @doc: the XHTML document - * @cur: the first node - * @level: the imbrication level for indenting - * @format: is formatting allowed - * @encoding: an optional encoding string - * - * Dump an XML node list, recursive behaviour, children are printed too. - * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 - * or xmlKeepBlanksDefault(0) was called - */ -static void -xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, - xmlNodePtr cur, int level, int format, const char *encoding) { - int i; - - if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xhtmlNodeListDumpOutput : node == NULL\n"); -#endif - return; - } - while (cur != NULL) { - if ((format) && (xmlIndentTreeOutput) && - (cur->type == XML_ELEMENT_NODE)) - for (i = 0;i < level;i++) - xmlOutputBufferWriteString(buf, xmlTreeIndentString); - xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding); - if (format) { - xmlOutputBufferWriteString(buf, "\n"); - } - cur = cur->next; - } -} - -/** - * xhtmlNodeDumpOutput: - * @buf: the XML buffer output - * @doc: the XHTML document - * @cur: the current node - * @level: the imbrication level for indenting - * @format: is formatting allowed - * @encoding: an optional encoding string - * - * Dump an XHTML node, recursive behaviour, children are printed too. - * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 - * or xmlKeepBlanksDefault(0) was called - */ -static void -xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, - int level, int format, const char *encoding) { - int i; - xmlNodePtr tmp; - xmlChar *start, *end; - - if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlNodeDumpOutput : node == NULL\n"); -#endif - return; - } - if (cur->type == XML_XINCLUDE_START) - return; - if (cur->type == XML_XINCLUDE_END) - return; - if (cur->type == XML_DTD_NODE) { - xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding); - return; - } - if (cur->type == XML_ELEMENT_DECL) { - xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur); - return; - } - if (cur->type == XML_ATTRIBUTE_DECL) { - xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur); - return; - } - if (cur->type == XML_ENTITY_DECL) { - xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur); - return; - } - if (cur->type == XML_TEXT_NODE) { - if (cur->content != NULL) { - if ((cur->name == xmlStringText) || - (cur->name != xmlStringTextNoenc)) { - xmlChar *buffer; - - if (encoding == NULL) - buffer = xmlEncodeEntitiesReentrant(doc, cur->content); - else - buffer = xmlEncodeSpecialChars(doc, cur->content); - if (buffer != NULL) { - xmlOutputBufferWriteString(buf, (const char *)buffer); - xmlFree(buffer); - } - } else { - /* - * Disable escaping, needed for XSLT - */ - xmlOutputBufferWriteString(buf, (const char *) cur->content); - } - } - - return; - } - if (cur->type == XML_PI_NODE) { - if (cur->content != NULL) { - xmlOutputBufferWriteString(buf, "name); - if (cur->content != NULL) { - xmlOutputBufferWriteString(buf, " "); - xmlOutputBufferWriteString(buf, (const char *)cur->content); - } - xmlOutputBufferWriteString(buf, "?>"); - } else { - xmlOutputBufferWriteString(buf, "name); - xmlOutputBufferWriteString(buf, "?>"); - } - return; - } - if (cur->type == XML_COMMENT_NODE) { - if (cur->content != NULL) { - xmlOutputBufferWriteString(buf, ""); - } - return; - } - if (cur->type == XML_ENTITY_REF_NODE) { - xmlOutputBufferWriteString(buf, "&"); - xmlOutputBufferWriteString(buf, (const char *)cur->name); - xmlOutputBufferWriteString(buf, ";"); - return; - } - if (cur->type == XML_CDATA_SECTION_NODE) { - start = end = cur->content; - while (*end != '\0') { - if (*end == ']' && *(end + 1) == ']' && *(end + 2) == '>') { - end = end + 2; - xmlOutputBufferWriteString(buf, ""); - start = end; - } - end++; - } - if (start != end) { - xmlOutputBufferWriteString(buf, ""); - } - return; - } - - if (format == 1) { - tmp = cur->children; - while (tmp != NULL) { - if ((tmp->type == XML_TEXT_NODE) || - (tmp->type == XML_ENTITY_REF_NODE)) { - format = 0; - break; - } - tmp = tmp->next; - } - } - 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); - if ((xmlStrEqual(cur->name, BAD_CAST "html") && - (cur->ns == NULL) && (cur->nsDef == NULL))) { - /* - * 3.1.1. Strictly Conforming Documents A.3.1.1 3/ - */ - xmlOutputBufferWriteString(buf, - " xmlns=\"http://www.w3.org/1999/xhtml\""); - } - if (cur->properties != NULL) - xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding); - - if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) { - if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) && - (xhtmlIsEmpty(cur) == 1)) { - /* - * C.2. Empty Elements - */ - xmlOutputBufferWriteString(buf, " />"); - } else { - /* - * C.3. Element Minimization and Empty Element Content - */ - xmlOutputBufferWriteString(buf, ">ns != NULL) && (cur->ns->prefix != NULL)) { - xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); - xmlOutputBufferWriteString(buf, ":"); - } - xmlOutputBufferWriteString(buf, (const char *)cur->name); - xmlOutputBufferWriteString(buf, ">"); - } - return; - } - xmlOutputBufferWriteString(buf, ">"); - if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) { - xmlChar *buffer; - - if (encoding == NULL) - buffer = xmlEncodeEntitiesReentrant(doc, cur->content); - else - buffer = xmlEncodeSpecialChars(doc, cur->content); - if (buffer != NULL) { - xmlOutputBufferWriteString(buf, (const char *)buffer); - xmlFree(buffer); - } - } - - /* - * 4.8. Script and Style elements - */ - if ((cur->type == XML_ELEMENT_NODE) && - ((xmlStrEqual(cur->name, BAD_CAST "script")) || - (xmlStrEqual(cur->name, BAD_CAST "style"))) && - ((cur->ns == NULL) || - (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) { - xmlNodePtr child = cur->children; - - while (child != NULL) { - if ((child->type == XML_TEXT_NODE) || - (child->type == XML_CDATA_SECTION_NODE)) { - /* - * Apparently CDATA escaping for style just break on IE, - * mozilla and galeon, so ... - */ - if (xmlStrEqual(cur->name, BAD_CAST "style") && - (xmlStrchr(child->content, '<') == NULL) && - (xmlStrchr(child->content, '>') == NULL) && - (xmlStrchr(child->content, '&') == NULL)) { - xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding); - } else { - start = end = child->content; - while (*end != '\0') { - if (*end == ']' && - *(end + 1) == ']' && - *(end + 2) == '>') { - end = end + 2; - xmlOutputBufferWriteString(buf, ""); - start = end; - } - end++; - } - if (start != end) { - xmlOutputBufferWriteString(buf, ""); - } - } - } else { - xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding); - } - child = child->next; - } - } else if (cur->children != NULL) { - if (format) xmlOutputBufferWriteString(buf, "\n"); - xhtmlNodeListDumpOutput(buf, doc, cur->children, - (level >= 0?level+1:-1), format, encoding); - if ((xmlIndentTreeOutput) && (format)) - for (i = 0;i < level;i++) - xmlOutputBufferWriteString(buf, xmlTreeIndentString); - } - xmlOutputBufferWriteString(buf, "ns != NULL) && (cur->ns->prefix != NULL)) { - xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); - xmlOutputBufferWriteString(buf, ":"); - } - - xmlOutputBufferWriteString(buf, (const char *)cur->name); - xmlOutputBufferWriteString(buf, ">"); -} -#endif /* LIBXML_OUTPUT_ENABLED */ -#endif - -#ifdef LIBXML_OUTPUT_ENABLED -/************************************************************************ - * * - * Saving functions front-ends * - * * - ************************************************************************/ - -/** - * xmlDocDumpFormatMemoryEnc: - * @out_doc: Document to generate XML text from - * @doc_txt_ptr: Memory pointer for allocated XML text - * @doc_txt_len: Length of the generated XML text - * @txt_encoding: Character encoding to use when generating XML text - * @format: should formatting spaces been added - * - * Dump the current DOM tree into memory using the character encoding specified - * by the caller. Note it is up to the caller of this function to free the - * allocated memory with xmlFree(). - * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 - * or xmlKeepBlanksDefault(0) was called - */ - -void -xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr, - int * doc_txt_len, const char * txt_encoding, - int format) { - int dummy = 0; - xmlOutputBufferPtr out_buff = NULL; - xmlCharEncodingHandlerPtr conv_hdlr = NULL; - - if (doc_txt_len == NULL) { - doc_txt_len = &dummy; /* Continue, caller just won't get length */ - } - - if (doc_txt_ptr == NULL) { - *doc_txt_len = 0; - return; - } - - *doc_txt_ptr = NULL; - *doc_txt_len = 0; - - if (out_doc == NULL) { - /* No document, no output */ - return; - } - - /* - * Validate the encoding value, if provided. - * This logic is copied from xmlSaveFileEnc. - */ - - if (txt_encoding == NULL) - txt_encoding = (const char *) out_doc->encoding; - if (txt_encoding != NULL) { - conv_hdlr = xmlFindCharEncodingHandler(txt_encoding); - if ( conv_hdlr == NULL ) { - xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc, - txt_encoding); - return; - } - } - - if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) { - xmlSaveErrMemory("creating buffer"); - return; - } - - xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format); - xmlOutputBufferFlush(out_buff); - if (out_buff->conv != NULL) { - *doc_txt_len = out_buff->conv->use; - *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len); - } else { - *doc_txt_len = out_buff->buffer->use; - *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len); - } - (void)xmlOutputBufferClose(out_buff); - - if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) { - *doc_txt_len = 0; - xmlSaveErrMemory("creating output"); - } - - return; -} - -/** - * xmlDocDumpMemory: - * @cur: the document - * @mem: OUT: the memory pointer - * @size: OUT: the memory length - * - * Dump an XML document in memory and return the #xmlChar * and it's size - * in bytes. It's up to the caller to free the memory with xmlFree(). - * The resulting byte array is zero terminated, though the last 0 is not - * included in the returned size. - */ -void -xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) { - xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0); -} - -/** - * xmlDocDumpFormatMemory: - * @cur: the document - * @mem: OUT: the memory pointer - * @size: OUT: the memory length - * @format: should formatting spaces been added - * - * - * Dump an XML document in memory and return the #xmlChar * and it's size. - * It's up to the caller to free the memory with xmlFree(). - * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 - * or xmlKeepBlanksDefault(0) was called - */ -void -xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) { - xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format); -} - -/** - * xmlDocDumpMemoryEnc: - * @out_doc: Document to generate XML text from - * @doc_txt_ptr: Memory pointer for allocated XML text - * @doc_txt_len: Length of the generated XML text - * @txt_encoding: Character encoding to use when generating XML text - * - * Dump the current DOM tree into memory using the character encoding specified - * by the caller. Note it is up to the caller of this function to free the - * allocated memory with xmlFree(). - */ - -void -xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr, - int * doc_txt_len, const char * txt_encoding) { - xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len, - txt_encoding, 0); -} - -/** - * xmlDocFormatDump: - * @f: the FILE* - * @cur: the document - * @format: should formatting spaces been added - * - * Dump an XML document to an open FILE. - * - * returns: the number of bytes written or -1 in case of failure. - * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 - * or xmlKeepBlanksDefault(0) was called - */ -int -xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) { - xmlOutputBufferPtr buf; - const char * encoding; - xmlCharEncodingHandlerPtr handler = NULL; - int ret; - - if (cur == NULL) { -#ifdef DEBUG_TREE - xmlGenericError(xmlGenericErrorContext, - "xmlDocDump : document == NULL\n"); -#endif - return(-1); - } - encoding = (const char *) cur->encoding; - - if (encoding != NULL) { - handler = xmlFindCharEncodingHandler(encoding); - if (handler == NULL) { - xmlFree((char *) cur->encoding); - cur->encoding = NULL; - } - } - buf = xmlOutputBufferCreateFile(f, handler); - if (buf == NULL) return(-1); - xmlDocContentDumpOutput(buf, cur, NULL, format); - - ret = xmlOutputBufferClose(buf); - return(ret); -} - -/** - * xmlDocDump: - * @f: the FILE* - * @cur: the document - * - * Dump an XML document to an open FILE. - * - * returns: the number of bytes written or -1 in case of failure. - */ -int -xmlDocDump(FILE *f, xmlDocPtr cur) { - return(xmlDocFormatDump (f, cur, 0)); -} - -/** - * xmlSaveFileTo: - * @buf: an output I/O buffer - * @cur: the document - * @encoding: the encoding if any assuming the I/O layer handles the trancoding - * - * Dump an XML document to an I/O buffer. - * - * returns: the number of bytes written or -1 in case of failure. - */ -int -xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) { - int ret; - - if (buf == NULL) return(0); - xmlDocContentDumpOutput(buf, cur, encoding, 0); - ret = xmlOutputBufferClose(buf); - return(ret); -} - -/** - * xmlSaveFormatFileTo: - * @buf: an output I/O buffer - * @cur: the document - * @encoding: the encoding if any assuming the I/O layer handles the trancoding - * @format: should formatting spaces been added - * - * Dump an XML document to an I/O buffer. - * - * returns: the number of bytes written or -1 in case of failure. - * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 - * or xmlKeepBlanksDefault(0) was called - */ -int -xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) { - int ret; - - if (buf == NULL) return(0); - xmlDocContentDumpOutput(buf, cur, encoding, format); - ret = xmlOutputBufferClose(buf); - return(ret); -} - -/** - * xmlSaveFormatFileEnc: - * @filename: the filename or URL to output - * @cur: the document being saved - * @encoding: the name of the encoding to use or NULL. - * @format: should formatting spaces be added. - * - * Dump an XML document to a file or an URL. - * - * Returns the number of bytes written or -1 in case of error. - * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 - * or xmlKeepBlanksDefault(0) was called - */ -int -xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur, - const char * encoding, int format ) { - xmlOutputBufferPtr buf; - xmlCharEncodingHandlerPtr handler = NULL; - int ret; - - if (cur == NULL) - return(-1); - - if (encoding == NULL) - encoding = (const char *) cur->encoding; - - if (encoding != NULL) { - - handler = xmlFindCharEncodingHandler(encoding); - if (handler == NULL) - return(-1); - } - -#ifdef HAVE_ZLIB_H - if (cur->compression < 0) cur->compression = xmlCompressMode; -#endif - /* - * save the content to a temp buffer. - */ - buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression); - if (buf == NULL) return(-1); - - xmlDocContentDumpOutput(buf, cur, encoding, format); - - ret = xmlOutputBufferClose(buf); - return(ret); -} - - -/** - * xmlSaveFileEnc: - * @filename: the filename (or URL) - * @cur: the document - * @encoding: the name of an encoding (or NULL) - * - * Dump an XML document, converting it to the given encoding - * - * returns: the number of bytes written or -1 in case of failure. - */ -int -xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) { - return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) ); -} - -/** - * xmlSaveFormatFile: - * @filename: the filename (or URL) - * @cur: the document - * @format: should formatting spaces been added - * - * Dump an XML document to a file. Will use compression if - * compiled in and enabled. If @filename is "-" the stdout file is - * used. If @format is set then the document will be indented on output. - * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 - * or xmlKeepBlanksDefault(0) was called - * - * returns: the number of bytes written or -1 in case of failure. - */ -int -xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) { - return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) ); -} - -/** - * xmlSaveFile: - * @filename: the filename (or URL) - * @cur: the document - * - * Dump an XML document to a file. Will use compression if - * compiled in and enabled. If @filename is "-" the stdout file is - * used. - * returns: the number of bytes written or -1 in case of failure. - */ -int -xmlSaveFile(const char *filename, xmlDocPtr cur) { - return(xmlSaveFormatFileEnc(filename, cur, NULL, 0)); -} - -#endif /* LIBXML_OUTPUT_ENABLED */ - /** * xmlGetDocCompressMode: * @doc: the document diff --git a/xmlsave.c b/xmlsave.c new file mode 100644 index 00000000..15630dcb --- /dev/null +++ b/xmlsave.c @@ -0,0 +1,1950 @@ +/* + * xmlsave.c: Implemetation of the document serializer + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXML +#include "libxml.h" + +#include +#include +#include +#include +#include +#ifdef LIBXML_HTML_ENABLED +#include + +/************************************************************************ + * * + * XHTML detection * + * * + ************************************************************************/ +#define XHTML_STRICT_PUBLIC_ID BAD_CAST \ + "-//W3C//DTD XHTML 1.0 Strict//EN" +#define XHTML_STRICT_SYSTEM_ID BAD_CAST \ + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" +#define XHTML_FRAME_PUBLIC_ID BAD_CAST \ + "-//W3C//DTD XHTML 1.0 Frameset//EN" +#define XHTML_FRAME_SYSTEM_ID BAD_CAST \ + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd" +#define XHTML_TRANS_PUBLIC_ID BAD_CAST \ + "-//W3C//DTD XHTML 1.0 Transitional//EN" +#define XHTML_TRANS_SYSTEM_ID BAD_CAST \ + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" + +#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml" +/** + * xmlIsXHTML: + * @systemID: the system identifier + * @publicID: the public identifier + * + * Try to find if the document correspond to an XHTML DTD + * + * Returns 1 if true, 0 if not and -1 in case of error + */ +int +xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) { + if ((systemID == NULL) && (publicID == NULL)) + return(-1); + if (publicID != NULL) { + if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1); + if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1); + if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1); + } + if (systemID != NULL) { + if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1); + if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1); + if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1); + } + return(0); +} +#endif /* LIBXML_HTML_ENABLED */ + + +#ifdef LIBXML_OUTPUT_ENABLED + +#define TODO \ + xmlGenericError(xmlGenericErrorContext, \ + "Unimplemented block at %s:%d\n", \ + __FILE__, __LINE__); + +struct _xmlSaveCtxt { + void *_private; + int type; + int fd; + const xmlChar *filename; + const xmlChar *encoding; + xmlCharEncodingHandlerPtr handler; + xmlOutputBufferPtr out; + int options; + int level; +}; + +/************************************************************************ + * * + * Output error handlers * + * * + ************************************************************************/ +/** + * xmlSaveErrMemory: + * @extra: extra informations + * + * Handle an out of memory condition + */ +static void +xmlSaveErrMemory(const char *extra) +{ + __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra); +} + +/** + * xmlSaveErr: + * @code: the error number + * @node: the location of the error. + * @extra: extra informations + * + * Handle an out of memory condition + */ +static void +xmlSaveErr(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"; + break; + case XML_SAVE_CHAR_INVALID: + msg = "invalid character value"; + break; + case XML_SAVE_UNKNOWN_ENCODING: + msg = "unknown encoding %s"; + break; + case XML_SAVE_NO_DOCTYPE: + msg = "document has no DOCTYPE"; + break; + default: + msg = "unexpected error number"; + } + __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra); +} + +/************************************************************************ + * * + * Allocation and deallocation * + * * + ************************************************************************/ + +/** + * xmlFreeSaveCtxt: + * + * Free a saving context, destroying the ouptut in any remaining buffer + */ +static void +xmlFreeSaveCtxt(xmlSaveCtxtPtr ctxt) +{ + if (ctxt == NULL) return; + if (ctxt->encoding != NULL) + xmlFree((char *) ctxt->encoding); + xmlFree(ctxt); +} + +/** + * xmlNewSaveCtxt: + * + * Create a new saving context + * + * Returns the new structure or NULL in case of error + */ +static xmlSaveCtxtPtr +xmlNewSaveCtxt(const char *encoding, int options) +{ + xmlSaveCtxtPtr ret; + + ret = (xmlSaveCtxtPtr) xmlMalloc(sizeof(xmlSaveCtxt)); + if (ret == NULL) { + xmlSaveErrMemory("creating saving context"); + return ( NULL ); + } + memset(ret, 0, sizeof(xmlSaveCtxt)); + ret->options = options; + if (encoding != NULL) { + ret->handler = xmlFindCharEncodingHandler(encoding); + if (ret->handler == NULL) { + xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); + xmlFreeSaveCtxt(ret); + return(NULL); + } + ret->encoding = xmlStrdup((const xmlChar *)encoding); + } + return(ret); +} + +/************************************************************************ + * * + * Dumping XML tree content to a simple buffer * + * * + ************************************************************************/ +/** + * xmlAttrSerializeContent: + * @buf: the XML buffer output + * @doc: the document + * @attr: the attribute pointer + * + * Serialize the attribute in the buffer + */ +static void +xmlAttrSerializeContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr) +{ + xmlNodePtr children; + + children = attr->children; + while (children != NULL) { + switch (children->type) { + case XML_TEXT_NODE: + xmlAttrSerializeTxtContent(buf, doc, attr, children->content); + break; + case XML_ENTITY_REF_NODE: + xmlBufferAdd(buf, BAD_CAST "&", 1); + xmlBufferAdd(buf, children->name, + xmlStrlen(children->name)); + xmlBufferAdd(buf, BAD_CAST ";", 1); + break; + default: + /* should not happen unless we have a badly built tree */ + break; + } + children = children->next; + } +} + +/************************************************************************ + * * + * Dumping XML tree content to an I/O output buffer * + * * + ************************************************************************/ + +#ifdef LIBXML_HTML_ENABLED +static void +xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, + int level, int format, const char *encoding); +#endif +static void +xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, + int level, int format, const char *encoding); +static void +xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc, + xmlNodePtr cur, int level, int format, const char *encoding); + +void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur); + +/** + * xmlNsDumpOutput: + * @buf: the XML buffer output + * @cur: a namespace + * + * Dump a local Namespace definition. + * Should be called in the context of attributes dumps. + */ +static void +xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) { + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNsDumpOutput : Ns == NULL\n"); +#endif + return; + } + if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) { + if (xmlStrEqual(cur->prefix, BAD_CAST "xml")) + return; + + /* Within the context of an element attributes */ + if (cur->prefix != NULL) { + xmlOutputBufferWriteString(buf, " xmlns:"); + xmlOutputBufferWriteString(buf, (const char *)cur->prefix); + } else + xmlOutputBufferWriteString(buf, " xmlns"); + xmlOutputBufferWriteString(buf, "="); + xmlBufferWriteQuotedString(buf->buffer, cur->href); + } +} + +/** + * xmlNsListDumpOutput: + * @buf: the XML buffer output + * @cur: the first namespace + * + * Dump a list of local Namespace definitions. + * Should be called in the context of attributes dumps. + */ +void +xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) { + while (cur != NULL) { + xmlNsDumpOutput(buf, cur); + cur = cur->next; + } +} + +/** + * xmlDtdDumpOutput: + * @buf: the XML buffer output + * @doc: the document + * @encoding: an optional encoding string + * + * Dump the XML document DTD, if any. + */ +static void +xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) { + if (dtd == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlDtdDumpOutput : no internal subset\n"); +#endif + return; + } + xmlOutputBufferWriteString(buf, "name); + if (dtd->ExternalID != NULL) { + xmlOutputBufferWriteString(buf, " PUBLIC "); + xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID); + xmlOutputBufferWriteString(buf, " "); + xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID); + } else if (dtd->SystemID != NULL) { + xmlOutputBufferWriteString(buf, " SYSTEM "); + xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID); + } + if ((dtd->entities == NULL) && (dtd->elements == NULL) && + (dtd->attributes == NULL) && (dtd->notations == NULL) && + (dtd->pentities == NULL)) { + xmlOutputBufferWriteString(buf, ">"); + return; + } + xmlOutputBufferWriteString(buf, " [\n"); + xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding); + xmlOutputBufferWriteString(buf, "]>"); +} + +/** + * xmlAttrDumpOutput: + * @buf: the XML buffer output + * @doc: the document + * @cur: the attribute pointer + * @encoding: an optional encoding string + * + * Dump an XML attribute + */ +static void +xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur, + const char *encoding ATTRIBUTE_UNUSED) { + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAttrDumpOutput : property == NULL\n"); +#endif + 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); + xmlOutputBufferWriteString(buf, "=\""); + xmlAttrSerializeContent(buf->buffer, doc, cur); + xmlOutputBufferWriteString(buf, "\""); +} + +/** + * 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(xmlOutputBufferPtr buf, xmlDocPtr doc, + xmlAttrPtr cur, const char *encoding) { + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAttrListDumpOutput : property == NULL\n"); +#endif + return; + } + while (cur != NULL) { + xmlAttrDumpOutput(buf, doc, cur, encoding); + cur = cur->next; + } +} + + + +/** + * xmlNodeListDumpOutput: + * @buf: the XML buffer output + * @doc: the document + * @cur: the first node + * @level: the imbrication level for indenting + * @format: is formatting allowed + * @encoding: an optional encoding string + * + * Dump an XML node list, recursive behaviour, children are printed too. + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + */ +static void +xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, + xmlNodePtr cur, int level, int format, const char *encoding) { + int i; + + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNodeListDumpOutput : node == NULL\n"); +#endif + return; + } + while (cur != NULL) { + if ((format) && (xmlIndentTreeOutput) && + (cur->type == XML_ELEMENT_NODE)) + for (i = 0;i < level;i++) + xmlOutputBufferWriteString(buf, xmlTreeIndentString); + xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding); + if (format) { + xmlOutputBufferWriteString(buf, "\n"); + } + cur = cur->next; + } +} + +/** + * xmlNodeDumpOutputInternal: + * @buf: the XML buffer output + * @doc: the document + * @cur: the current node + * @level: the imbrication level for indenting + * @format: is formatting allowed + * @encoding: an optional encoding string + * + * Dump an XML node, recursive behaviour, children are printed too. + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + */ +static void +xmlNodeDumpOutputInternal(xmlOutputBufferPtr buf, xmlDocPtr doc, + xmlNodePtr cur, int level, int format, const char *encoding) { + int i; + xmlNodePtr tmp; + xmlChar *start, *end; + + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNodeDumpOutput : node == NULL\n"); +#endif + return; + } + if (cur->type == XML_XINCLUDE_START) + return; + if (cur->type == XML_XINCLUDE_END) + return; + if (cur->type == XML_DTD_NODE) { + xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding); + return; + } + if (cur->type == XML_DOCUMENT_FRAG_NODE) { + xmlNodeListDumpOutput(buf, doc, cur->children, level, format, encoding); + return; + } + if (cur->type == XML_ELEMENT_DECL) { + xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur); + return; + } + if (cur->type == XML_ATTRIBUTE_DECL) { + xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur); + return; + } + if (cur->type == XML_ENTITY_DECL) { + xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur); + return; + } + if (cur->type == XML_TEXT_NODE) { + if (cur->content != NULL) { + if ((cur->name == xmlStringText) || + (cur->name != xmlStringTextNoenc)) { + xmlChar *buffer; + + if (encoding == NULL) + buffer = xmlEncodeEntitiesReentrant(doc, cur->content); + else + buffer = xmlEncodeSpecialChars(doc, cur->content); + if (buffer != NULL) { + xmlOutputBufferWriteString(buf, (const char *)buffer); + xmlFree(buffer); + } + } else { + /* + * Disable escaping, needed for XSLT + */ + xmlOutputBufferWriteString(buf, (const char *) cur->content); + } + } + + return; + } + if (cur->type == XML_PI_NODE) { + if (cur->content != NULL) { + xmlOutputBufferWriteString(buf, "name); + if (cur->content != NULL) { + xmlOutputBufferWriteString(buf, " "); + xmlOutputBufferWriteString(buf, (const char *)cur->content); + } + xmlOutputBufferWriteString(buf, "?>"); + } else { + xmlOutputBufferWriteString(buf, "name); + xmlOutputBufferWriteString(buf, "?>"); + } + return; + } + if (cur->type == XML_COMMENT_NODE) { + if (cur->content != NULL) { + xmlOutputBufferWriteString(buf, ""); + } + return; + } + if (cur->type == XML_ENTITY_REF_NODE) { + xmlOutputBufferWriteString(buf, "&"); + xmlOutputBufferWriteString(buf, (const char *)cur->name); + xmlOutputBufferWriteString(buf, ";"); + return; + } + if (cur->type == XML_CDATA_SECTION_NODE) { + start = end = cur->content; + while (*end != '\0') { + if ((*end == ']') && (*(end + 1) == ']') && (*(end + 2) == '>')) { + end = end + 2; + xmlOutputBufferWriteString(buf, ""); + start = end; + } + end++; + } + if (start != end) { + xmlOutputBufferWriteString(buf, ""); + } + return; + } + if (cur->type == XML_ATTRIBUTE_NODE) { + xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding); + return; + } + if (cur->type == XML_NAMESPACE_DECL) { + xmlNsDumpOutput(buf, (xmlNsPtr) cur); + return; + } + + 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)) { + format = 0; + break; + } + tmp = tmp->next; + } + } + 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); + if (cur->properties != NULL) + xmlAttrListDumpOutput(buf, doc, cur->properties, encoding); + + if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) && + (cur->children == NULL) && (!xmlSaveNoEmptyTags)) { + xmlOutputBufferWriteString(buf, "/>"); + return; + } + xmlOutputBufferWriteString(buf, ">"); + if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) { + xmlChar *buffer; + + if (encoding == NULL) + buffer = xmlEncodeEntitiesReentrant(doc, cur->content); + else + buffer = xmlEncodeSpecialChars(doc, cur->content); + if (buffer != NULL) { + xmlOutputBufferWriteString(buf, (const char *)buffer); + xmlFree(buffer); + } + } + if (cur->children != NULL) { + if (format) xmlOutputBufferWriteString(buf, "\n"); + xmlNodeListDumpOutput(buf, doc, cur->children, + (level >= 0?level+1:-1), format, encoding); + if ((xmlIndentTreeOutput) && (format)) + for (i = 0;i < level;i++) + xmlOutputBufferWriteString(buf, xmlTreeIndentString); + } + xmlOutputBufferWriteString(buf, "ns != NULL) && (cur->ns->prefix != NULL)) { + xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); + xmlOutputBufferWriteString(buf, ":"); + } + + xmlOutputBufferWriteString(buf, (const char *)cur->name); + xmlOutputBufferWriteString(buf, ">"); +} + +/** + * xmlDocContentDumpOutput: + * @buf: the XML buffer output + * @cur: the document + * @encoding: an optional encoding string + * @format: should formatting spaces been added + * + * Dump an XML document. + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + */ +static void +xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur, + const char *encoding, int format) { +#ifdef LIBXML_HTML_ENABLED + xmlDtdPtr dtd; + int is_xhtml = 0; +#endif + const xmlChar *oldenc = cur->encoding; + + xmlInitParser(); + + if (encoding != NULL) + cur->encoding = BAD_CAST encoding; + + xmlOutputBufferWriteString(buf, "version != NULL) + xmlBufferWriteQuotedString(buf->buffer, cur->version); + else + xmlOutputBufferWriteString(buf, "\"1.0\""); + if (encoding == NULL) { + if (cur->encoding != NULL) + encoding = (const char *) cur->encoding; + else if (cur->charset != XML_CHAR_ENCODING_UTF8) + encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset); + } + if (encoding != NULL) { + xmlOutputBufferWriteString(buf, " encoding="); + xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding); + } + switch (cur->standalone) { + case 0: + xmlOutputBufferWriteString(buf, " standalone=\"no\""); + break; + case 1: + xmlOutputBufferWriteString(buf, " standalone=\"yes\""); + break; + } + xmlOutputBufferWriteString(buf, "?>\n"); + +#ifdef LIBXML_HTML_ENABLED + dtd = xmlGetIntSubset(cur); + if (dtd != NULL) { + is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID); + if (is_xhtml < 0) is_xhtml = 0; + } + if (is_xhtml) { + if (encoding != NULL) + htmlSetMetaEncoding(cur, (const xmlChar *) encoding); + else + htmlSetMetaEncoding(cur, BAD_CAST "UTF-8"); + } +#endif + if (cur->children != NULL) { + xmlNodePtr child = cur->children; + + while (child != NULL) { +#ifdef LIBXML_HTML_ENABLED + if (is_xhtml) + xhtmlNodeDumpOutput(buf, cur, child, 0, format, encoding); + else +#endif + xmlNodeDumpOutputInternal(buf, cur, child, 0, format, encoding); + xmlOutputBufferWriteString(buf, "\n"); + child = child->next; + } + } + if (encoding != NULL) + cur->encoding = oldenc; +} + +#ifdef LIBXML_HTML_ENABLED +/************************************************************************ + * * + * Functions specific to XHTML serialization * + * * + ************************************************************************/ + +/** + * xhtmlIsEmpty: + * @node: the node + * + * Check if a node is an empty xhtml node + * + * Returns 1 if the node is an empty node, 0 if not and -1 in case of error + */ +static int +xhtmlIsEmpty(xmlNodePtr node) { + if (node == NULL) + return(-1); + if (node->type != XML_ELEMENT_NODE) + return(0); + if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME))) + return(0); + if (node->children != NULL) + return(0); + switch (node->name[0]) { + case 'a': + if (xmlStrEqual(node->name, BAD_CAST "area")) + return(1); + return(0); + case 'b': + if (xmlStrEqual(node->name, BAD_CAST "br")) + return(1); + if (xmlStrEqual(node->name, BAD_CAST "base")) + return(1); + if (xmlStrEqual(node->name, BAD_CAST "basefont")) + return(1); + return(0); + case 'c': + if (xmlStrEqual(node->name, BAD_CAST "col")) + return(1); + return(0); + case 'f': + if (xmlStrEqual(node->name, BAD_CAST "frame")) + return(1); + return(0); + case 'h': + if (xmlStrEqual(node->name, BAD_CAST "hr")) + return(1); + return(0); + case 'i': + if (xmlStrEqual(node->name, BAD_CAST "img")) + return(1); + if (xmlStrEqual(node->name, BAD_CAST "input")) + return(1); + if (xmlStrEqual(node->name, BAD_CAST "isindex")) + return(1); + return(0); + case 'l': + if (xmlStrEqual(node->name, BAD_CAST "link")) + return(1); + return(0); + case 'm': + if (xmlStrEqual(node->name, BAD_CAST "meta")) + return(1); + return(0); + case 'p': + if (xmlStrEqual(node->name, BAD_CAST "param")) + return(1); + return(0); + } + return(0); +} + +/** + * xhtmlAttrListDumpOutput: + * @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 +xhtmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, + xmlAttrPtr cur, const char *encoding) { + xmlAttrPtr xml_lang = NULL; + xmlAttrPtr lang = NULL; + xmlAttrPtr name = NULL; + xmlAttrPtr id = NULL; + xmlNodePtr parent; + + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAttrListDumpOutput : property == NULL\n"); +#endif + return; + } + parent = cur->parent; + while (cur != NULL) { + if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id"))) + id = cur; + else + if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name"))) + name = cur; + else + if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang"))) + lang = cur; + else + if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) && + (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml"))) + xml_lang = cur; + else if ((cur->ns == NULL) && + ((cur->children == NULL) || + (cur->children->content == NULL) || + (cur->children->content[0] == 0)) && + (htmlIsBooleanAttr(cur->name))) { + if (cur->children != NULL) + xmlFreeNode(cur->children); + cur->children = xmlNewText(cur->name); + if (cur->children != NULL) + cur->children->parent = (xmlNodePtr) cur; + } + xmlAttrDumpOutput(buf, doc, cur, encoding); + cur = cur->next; + } + /* + * C.8 + */ + if ((name != NULL) && (id == NULL)) { + if ((parent != NULL) && (parent->name != NULL) && + ((xmlStrEqual(parent->name, BAD_CAST "a")) || + (xmlStrEqual(parent->name, BAD_CAST "p")) || + (xmlStrEqual(parent->name, BAD_CAST "div")) || + (xmlStrEqual(parent->name, BAD_CAST "img")) || + (xmlStrEqual(parent->name, BAD_CAST "map")) || + (xmlStrEqual(parent->name, BAD_CAST "applet")) || + (xmlStrEqual(parent->name, BAD_CAST "form")) || + (xmlStrEqual(parent->name, BAD_CAST "frame")) || + (xmlStrEqual(parent->name, BAD_CAST "iframe")))) { + xmlOutputBufferWriteString(buf, " id=\""); + xmlAttrSerializeContent(buf->buffer, doc, name); + xmlOutputBufferWriteString(buf, "\""); + } + } + /* + * C.7. + */ + if ((lang != NULL) && (xml_lang == NULL)) { + xmlOutputBufferWriteString(buf, " xml:lang=\""); + xmlAttrSerializeContent(buf->buffer, doc, lang); + xmlOutputBufferWriteString(buf, "\""); + } else + if ((xml_lang != NULL) && (lang == NULL)) { + xmlOutputBufferWriteString(buf, " lang=\""); + xmlAttrSerializeContent(buf->buffer, doc, xml_lang); + xmlOutputBufferWriteString(buf, "\""); + } +} + +/** + * xhtmlNodeListDumpOutput: + * @buf: the XML buffer output + * @doc: the XHTML document + * @cur: the first node + * @level: the imbrication level for indenting + * @format: is formatting allowed + * @encoding: an optional encoding string + * + * Dump an XML node list, recursive behaviour, children are printed too. + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + */ +static void +xhtmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, + xmlNodePtr cur, int level, int format, const char *encoding) { + int i; + + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xhtmlNodeListDumpOutput : node == NULL\n"); +#endif + return; + } + while (cur != NULL) { + if ((format) && (xmlIndentTreeOutput) && + (cur->type == XML_ELEMENT_NODE)) + for (i = 0;i < level;i++) + xmlOutputBufferWriteString(buf, xmlTreeIndentString); + xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding); + if (format) { + xmlOutputBufferWriteString(buf, "\n"); + } + cur = cur->next; + } +} + +/** + * xhtmlNodeDumpOutput: + * @buf: the XML buffer output + * @doc: the XHTML document + * @cur: the current node + * @level: the imbrication level for indenting + * @format: is formatting allowed + * @encoding: an optional encoding string + * + * Dump an XHTML node, recursive behaviour, children are printed too. + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + */ +static void +xhtmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, + int level, int format, const char *encoding) { + int i; + xmlNodePtr tmp; + xmlChar *start, *end; + + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNodeDumpOutput : node == NULL\n"); +#endif + return; + } + if (cur->type == XML_XINCLUDE_START) + return; + if (cur->type == XML_XINCLUDE_END) + return; + if (cur->type == XML_DTD_NODE) { + xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding); + return; + } + if (cur->type == XML_ELEMENT_DECL) { + xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur); + return; + } + if (cur->type == XML_ATTRIBUTE_DECL) { + xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur); + return; + } + if (cur->type == XML_ENTITY_DECL) { + xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur); + return; + } + if (cur->type == XML_TEXT_NODE) { + if (cur->content != NULL) { + if ((cur->name == xmlStringText) || + (cur->name != xmlStringTextNoenc)) { + xmlChar *buffer; + + if (encoding == NULL) + buffer = xmlEncodeEntitiesReentrant(doc, cur->content); + else + buffer = xmlEncodeSpecialChars(doc, cur->content); + if (buffer != NULL) { + xmlOutputBufferWriteString(buf, (const char *)buffer); + xmlFree(buffer); + } + } else { + /* + * Disable escaping, needed for XSLT + */ + xmlOutputBufferWriteString(buf, (const char *) cur->content); + } + } + + return; + } + if (cur->type == XML_PI_NODE) { + if (cur->content != NULL) { + xmlOutputBufferWriteString(buf, "name); + if (cur->content != NULL) { + xmlOutputBufferWriteString(buf, " "); + xmlOutputBufferWriteString(buf, (const char *)cur->content); + } + xmlOutputBufferWriteString(buf, "?>"); + } else { + xmlOutputBufferWriteString(buf, "name); + xmlOutputBufferWriteString(buf, "?>"); + } + return; + } + if (cur->type == XML_COMMENT_NODE) { + if (cur->content != NULL) { + xmlOutputBufferWriteString(buf, ""); + } + return; + } + if (cur->type == XML_ENTITY_REF_NODE) { + xmlOutputBufferWriteString(buf, "&"); + xmlOutputBufferWriteString(buf, (const char *)cur->name); + xmlOutputBufferWriteString(buf, ";"); + return; + } + if (cur->type == XML_CDATA_SECTION_NODE) { + start = end = cur->content; + while (*end != '\0') { + if (*end == ']' && *(end + 1) == ']' && *(end + 2) == '>') { + end = end + 2; + xmlOutputBufferWriteString(buf, ""); + start = end; + } + end++; + } + if (start != end) { + xmlOutputBufferWriteString(buf, ""); + } + return; + } + + if (format == 1) { + tmp = cur->children; + while (tmp != NULL) { + if ((tmp->type == XML_TEXT_NODE) || + (tmp->type == XML_ENTITY_REF_NODE)) { + format = 0; + break; + } + tmp = tmp->next; + } + } + 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); + if ((xmlStrEqual(cur->name, BAD_CAST "html") && + (cur->ns == NULL) && (cur->nsDef == NULL))) { + /* + * 3.1.1. Strictly Conforming Documents A.3.1.1 3/ + */ + xmlOutputBufferWriteString(buf, + " xmlns=\"http://www.w3.org/1999/xhtml\""); + } + if (cur->properties != NULL) + xhtmlAttrListDumpOutput(buf, doc, cur->properties, encoding); + + if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) { + if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) && + (xhtmlIsEmpty(cur) == 1)) { + /* + * C.2. Empty Elements + */ + xmlOutputBufferWriteString(buf, " />"); + } else { + /* + * C.3. Element Minimization and Empty Element Content + */ + xmlOutputBufferWriteString(buf, ">ns != NULL) && (cur->ns->prefix != NULL)) { + xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); + xmlOutputBufferWriteString(buf, ":"); + } + xmlOutputBufferWriteString(buf, (const char *)cur->name); + xmlOutputBufferWriteString(buf, ">"); + } + return; + } + xmlOutputBufferWriteString(buf, ">"); + if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) { + xmlChar *buffer; + + if (encoding == NULL) + buffer = xmlEncodeEntitiesReentrant(doc, cur->content); + else + buffer = xmlEncodeSpecialChars(doc, cur->content); + if (buffer != NULL) { + xmlOutputBufferWriteString(buf, (const char *)buffer); + xmlFree(buffer); + } + } + + /* + * 4.8. Script and Style elements + */ + if ((cur->type == XML_ELEMENT_NODE) && + ((xmlStrEqual(cur->name, BAD_CAST "script")) || + (xmlStrEqual(cur->name, BAD_CAST "style"))) && + ((cur->ns == NULL) || + (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) { + xmlNodePtr child = cur->children; + + while (child != NULL) { + if ((child->type == XML_TEXT_NODE) || + (child->type == XML_CDATA_SECTION_NODE)) { + /* + * Apparently CDATA escaping for style just break on IE, + * mozilla and galeon, so ... + */ + if (xmlStrEqual(cur->name, BAD_CAST "style") && + (xmlStrchr(child->content, '<') == NULL) && + (xmlStrchr(child->content, '>') == NULL) && + (xmlStrchr(child->content, '&') == NULL)) { + xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding); + } else { + start = end = child->content; + while (*end != '\0') { + if (*end == ']' && + *(end + 1) == ']' && + *(end + 2) == '>') { + end = end + 2; + xmlOutputBufferWriteString(buf, ""); + start = end; + } + end++; + } + if (start != end) { + xmlOutputBufferWriteString(buf, ""); + } + } + } else { + xhtmlNodeDumpOutput(buf, doc, child, 0, 0, encoding); + } + child = child->next; + } + } else if (cur->children != NULL) { + if (format) xmlOutputBufferWriteString(buf, "\n"); + xhtmlNodeListDumpOutput(buf, doc, cur->children, + (level >= 0?level+1:-1), format, encoding); + if ((xmlIndentTreeOutput) && (format)) + for (i = 0;i < level;i++) + xmlOutputBufferWriteString(buf, xmlTreeIndentString); + } + xmlOutputBufferWriteString(buf, "ns != NULL) && (cur->ns->prefix != NULL)) { + xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); + xmlOutputBufferWriteString(buf, ":"); + } + + xmlOutputBufferWriteString(buf, (const char *)cur->name); + xmlOutputBufferWriteString(buf, ">"); +} +#endif + +/************************************************************************ + * * + * Public entry points * + * * + ************************************************************************/ + +/** + * xmlSaveToFd: + * @fd: a file descriptor number + * @encoding: the encoding name to use or NULL + * @options: a set of xmlSaveOptions + * + * Create a document saving context serializing to a file descriptor + * with the encoding and the options given. + * + * Returns a new serialization context or NULL in case of error. + */ +xmlSaveCtxtPtr +xmlSaveToFd(int fd, const char *encoding, int options) +{ + xmlSaveCtxtPtr ret; + + ret = xmlNewSaveCtxt(encoding, options); + if (ret == NULL) return(NULL); + ret->out = xmlOutputBufferCreateFd(fd, ret->handler); + if (ret->out == NULL) { + xmlFreeSaveCtxt(ret); + return(NULL); + } + return(ret); +} + +/** + * xmlSaveToFilename: + * @filename: a file name or an URL + * @encoding: the encoding name to use or NULL + * @options: a set of xmlSaveOptions + * + * Create a document saving context serializing to a filename or possibly + * to an URL (but this is less reliable) with the encoding and the options + * given. + * + * Returns a new serialization context or NULL in case of error. + */ +xmlSaveCtxtPtr +xmlSaveToFilename(const char *filename, const char *encoding, int options) +{ + xmlSaveCtxtPtr ret; + int compression = 0; /* TODO handle compression option */ + + ret = xmlNewSaveCtxt(encoding, options); + if (ret == NULL) return(NULL); + ret->out = xmlOutputBufferCreateFilename(filename, ret->handler, + compression); + if (ret->out == NULL) { + xmlFreeSaveCtxt(ret); + return(NULL); + } + return(ret); +} + +#if 0 +/** + * xmlSaveToBuffer: + * @buffer: a buffer + * @encoding: the encoding name to use or NULL + * @options: a set of xmlSaveOptions + * + * Create a document saving context serializing to a buffer + * with the encoding and the options given + * + * Returns a new serialization context or NULL in case of error. + */ +xmlSaveCtxtPtr +xmlSaveToBuffer(xmlBufferPtr buffer, const char *encoding, int options) +{ + TODO + return(NULL); +} +#endif + +/** + * xmlSaveToIO: + * @iowrite: an I/O write function + * @ioclose: an I/O close function + * @ioctx: an I/O handler + * @encoding: the encoding name to use or NULL + * @options: a set of xmlSaveOptions + * + * Create a document saving context serializing to a file descriptor + * with the encoding and the options given + * + * Returns a new serialization context or NULL in case of error. + */ +xmlSaveCtxtPtr +xmlSaveToIO(xmlOutputWriteCallback iowrite, + xmlOutputCloseCallback ioclose, + void *ioctx, const char *encoding, int options) +{ + xmlSaveCtxtPtr ret; + + ret = xmlNewSaveCtxt(encoding, options); + if (ret == NULL) return(NULL); + ret->out = xmlOutputBufferCreateIO(iowrite, ioclose, ioctx, ret->handler); + if (ret->out == NULL) { + xmlFreeSaveCtxt(ret); + return(NULL); + } + return(ret); +} + +/** + * xmlSaveDoc: + * @ctxt: a document saving context + * @doc: a document + * + * Save a full document to a saving context + * + * Returns the number of byte written or -1 in case of error + */ +long +xmlSaveDoc(xmlSaveCtxtPtr ctxt, xmlDocPtr doc) +{ +} + +/** + * xmlSaveTree: + * @ctxt: a document saving context + * @node: a document + * + * Save a subtree starting at the node parameter to a saving context + * + * Returns the number of byte written or -1 in case of error + */ +long +xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr node) +{ +} + +/** + * xmlSaveFlush: + * @ctxt: a document saving context + * + * Flush a document saving context, i.e. make sure that all bytes have + * been output. + * + * Returns the number of byte written or -1 in case of error. + */ +int +xmlSaveFlush(xmlSaveCtxtPtr ctxt) +{ + if (ctxt == NULL) return(-1); + if (ctxt->out == NULL) return(-1); + return(xmlOutputBufferFlush(ctxt->out)); +} + +/** + * xmlSaveClose: + * @ctxt: a document saving context + * + * Close a document saving context, i.e. make sure that all bytes have + * been output and free the associated data. + * + * Returns the number of byte written or -1 in case of error. + */ +int +xmlSaveClose(xmlSaveCtxtPtr ctxt) +{ + int ret; + + if (ctxt == NULL) return(-1); + ret = xmlSaveFlush(ctxt); + xmlFreeSaveCtxt(ctxt); + return(ret); +} + +/************************************************************************ + * * + * Public entry points based on buffers * + * * + ************************************************************************/ +/** + * xmlAttrSerializeTxtContent: + * @buf: the XML buffer output + * @doc: the document + * @attr: the attribute node + * @string: the text content + * + * Serialize text attribute values to an xml simple buffer + */ +void +xmlAttrSerializeTxtContent(xmlBufferPtr buf, xmlDocPtr doc, + xmlAttrPtr attr, const xmlChar *string) { + xmlChar *base, *cur; + + if (string == NULL) return; + base = cur = (xmlChar *)string; + while (*cur != 0) { + if (*cur == '\n') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST " ", 5); + cur++; + base = cur; + } else if (*cur == '\r') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST " ", 5); + cur++; + base = cur; + } else if (*cur == '\t') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST " ", 4); + cur++; + base = cur; + } else if (*cur == '"') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST """, 6); + cur++; + base = cur; + } else if (*cur == '<') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST "<", 4); + cur++; + base = cur; + } else if (*cur == '>') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST ">", 4); + cur++; + base = cur; + } else if (*cur == '&') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST "&", 5); + cur++; + base = cur; + } else if ((*cur >= 0x80) && ((doc == NULL) || + (doc->encoding == NULL))) { + /* + * We assume we have UTF-8 content. + */ + char tmp[10]; + int val = 0, l = 1; + + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + if (*cur < 0xC0) { + xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr, NULL); + if (doc != NULL) + doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); + snprintf(tmp, sizeof(tmp), "&#%d;", *cur); + tmp[sizeof(tmp) - 1] = 0; + xmlBufferAdd(buf, (xmlChar *) tmp, -1); + cur++; + base = cur; + continue; + } else if (*cur < 0xE0) { + val = (cur[0]) & 0x1F; + val <<= 6; + val |= (cur[1]) & 0x3F; + l = 2; + } else if (*cur < 0xF0) { + val = (cur[0]) & 0x0F; + val <<= 6; + val |= (cur[1]) & 0x3F; + val <<= 6; + val |= (cur[2]) & 0x3F; + l = 3; + } else if (*cur < 0xF8) { + val = (cur[0]) & 0x07; + val <<= 6; + val |= (cur[1]) & 0x3F; + val <<= 6; + val |= (cur[2]) & 0x3F; + val <<= 6; + val |= (cur[3]) & 0x3F; + l = 4; + } + if ((l == 1) || (!IS_CHAR(val))) { + xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr, NULL); + if (doc != NULL) + doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); + snprintf(tmp, sizeof(tmp), "&#%d;", *cur); + tmp[sizeof(tmp) - 1] = 0; + xmlBufferAdd(buf, (xmlChar *) tmp, -1); + cur++; + base = cur; + continue; + } + /* + * We could do multiple things here. Just save + * as a char ref + */ + snprintf(tmp, sizeof(tmp), "&#x%X;", val); + tmp[sizeof(tmp) - 1] = 0; + xmlBufferAdd(buf, (xmlChar *) tmp, -1); + cur += l; + base = cur; + } else { + cur++; + } + } + if (base != cur) + xmlBufferAdd(buf, base, cur - base); +} + +/** + * xmlNodeDump: + * @buf: the XML buffer output + * @doc: the document + * @cur: the current node + * @level: the imbrication level for indenting + * @format: is formatting allowed + * + * Dump an XML node, recursive behaviour,children are printed too. + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + * + * Returns the number of bytes written to the buffer or -1 in case of error + */ +int +xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, + int format) +{ + unsigned int use; + int ret; + xmlOutputBufferPtr outbuf; + + xmlInitParser(); + + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNodeDump : node == NULL\n"); +#endif + return (-1); + } + if (buf == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNodeDump : buf == NULL\n"); +#endif + return (-1); + } + outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); + if (outbuf == NULL) { + xmlSaveErrMemory("creating buffer"); + return (-1); + } + memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer)); + outbuf->buffer = buf; + outbuf->encoder = NULL; + outbuf->writecallback = NULL; + outbuf->closecallback = NULL; + outbuf->context = NULL; + outbuf->written = 0; + + use = buf->use; + xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL); + xmlFree(outbuf); + ret = buf->use - use; + return (ret); +} + +/** + * xmlElemDump: + * @f: the FILE * for the output + * @doc: the document + * @cur: the current node + * + * Dump an XML/HTML node, recursive behaviour, children are printed too. + */ +void +xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur) +{ + xmlOutputBufferPtr outbuf; + + xmlInitParser(); + + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlElemDump : cur == NULL\n"); +#endif + return; + } +#ifdef DEBUG_TREE + if (doc == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlElemDump : doc == NULL\n"); + } +#endif + + outbuf = xmlOutputBufferCreateFile(f, NULL); + if (outbuf == NULL) + return; + if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) { +#ifdef LIBXML_HTML_ENABLED + htmlNodeDumpOutput(outbuf, doc, cur, NULL); +#else + xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n"); +#endif /* LIBXML_HTML_ENABLED */ + } else + xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL); + xmlOutputBufferClose(outbuf); +} + +/************************************************************************ + * * + * Saving functions front-ends * + * * + ************************************************************************/ + +/** + * xmlNodeDumpOutput: + * @buf: the XML buffer output + * @doc: the document + * @cur: the current node + * @level: the imbrication level for indenting + * @format: is formatting allowed + * @encoding: an optional encoding string + * + * Dump an XML node, recursive behaviour, children are printed too. + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + */ +void +xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, + int level, int format, const char *encoding) +{ +#ifdef LIBXML_HTML_ENABLED + xmlDtdPtr dtd; + int is_xhtml = 0; +#endif + + xmlInitParser(); + +#ifdef LIBXML_HTML_ENABLED + dtd = xmlGetIntSubset(doc); + if (dtd != NULL) { + is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID); + if (is_xhtml < 0) + is_xhtml = 0; + if ((is_xhtml) && (cur->parent == (xmlNodePtr) doc) && + (cur->type == XML_ELEMENT_NODE) && + (xmlStrEqual(cur->name, BAD_CAST "html"))) { + if (encoding != NULL) + htmlSetMetaEncoding((htmlDocPtr) doc, + (const xmlChar *) encoding); + else + htmlSetMetaEncoding((htmlDocPtr) doc, BAD_CAST "UTF-8"); + } + } + + if (is_xhtml) + xhtmlNodeDumpOutput(buf, doc, cur, level, format, encoding); + else +#endif + xmlNodeDumpOutputInternal(buf, doc, cur, level, format, encoding); +} + +/** + * xmlDocDumpFormatMemoryEnc: + * @out_doc: Document to generate XML text from + * @doc_txt_ptr: Memory pointer for allocated XML text + * @doc_txt_len: Length of the generated XML text + * @txt_encoding: Character encoding to use when generating XML text + * @format: should formatting spaces been added + * + * Dump the current DOM tree into memory using the character encoding specified + * by the caller. Note it is up to the caller of this function to free the + * allocated memory with xmlFree(). + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + */ + +void +xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr, + int * doc_txt_len, const char * txt_encoding, + int format) { + int dummy = 0; + xmlOutputBufferPtr out_buff = NULL; + xmlCharEncodingHandlerPtr conv_hdlr = NULL; + + if (doc_txt_len == NULL) { + doc_txt_len = &dummy; /* Continue, caller just won't get length */ + } + + if (doc_txt_ptr == NULL) { + *doc_txt_len = 0; + return; + } + + *doc_txt_ptr = NULL; + *doc_txt_len = 0; + + if (out_doc == NULL) { + /* No document, no output */ + return; + } + + /* + * Validate the encoding value, if provided. + * This logic is copied from xmlSaveFileEnc. + */ + + if (txt_encoding == NULL) + txt_encoding = (const char *) out_doc->encoding; + if (txt_encoding != NULL) { + conv_hdlr = xmlFindCharEncodingHandler(txt_encoding); + if ( conv_hdlr == NULL ) { + xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc, + txt_encoding); + return; + } + } + + if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) { + xmlSaveErrMemory("creating buffer"); + return; + } + + xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, format); + xmlOutputBufferFlush(out_buff); + if (out_buff->conv != NULL) { + *doc_txt_len = out_buff->conv->use; + *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len); + } else { + *doc_txt_len = out_buff->buffer->use; + *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len); + } + (void)xmlOutputBufferClose(out_buff); + + if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) { + *doc_txt_len = 0; + xmlSaveErrMemory("creating output"); + } + + return; +} + +/** + * xmlDocDumpMemory: + * @cur: the document + * @mem: OUT: the memory pointer + * @size: OUT: the memory length + * + * Dump an XML document in memory and return the #xmlChar * and it's size + * in bytes. It's up to the caller to free the memory with xmlFree(). + * The resulting byte array is zero terminated, though the last 0 is not + * included in the returned size. + */ +void +xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) { + xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0); +} + +/** + * xmlDocDumpFormatMemory: + * @cur: the document + * @mem: OUT: the memory pointer + * @size: OUT: the memory length + * @format: should formatting spaces been added + * + * + * Dump an XML document in memory and return the #xmlChar * and it's size. + * It's up to the caller to free the memory with xmlFree(). + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + */ +void +xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) { + xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format); +} + +/** + * xmlDocDumpMemoryEnc: + * @out_doc: Document to generate XML text from + * @doc_txt_ptr: Memory pointer for allocated XML text + * @doc_txt_len: Length of the generated XML text + * @txt_encoding: Character encoding to use when generating XML text + * + * Dump the current DOM tree into memory using the character encoding specified + * by the caller. Note it is up to the caller of this function to free the + * allocated memory with xmlFree(). + */ + +void +xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr, + int * doc_txt_len, const char * txt_encoding) { + xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len, + txt_encoding, 0); +} + +/** + * xmlDocFormatDump: + * @f: the FILE* + * @cur: the document + * @format: should formatting spaces been added + * + * Dump an XML document to an open FILE. + * + * returns: the number of bytes written or -1 in case of failure. + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + */ +int +xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) { + xmlOutputBufferPtr buf; + const char * encoding; + xmlCharEncodingHandlerPtr handler = NULL; + int ret; + + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlDocDump : document == NULL\n"); +#endif + return(-1); + } + encoding = (const char *) cur->encoding; + + if (encoding != NULL) { + handler = xmlFindCharEncodingHandler(encoding); + if (handler == NULL) { + xmlFree((char *) cur->encoding); + cur->encoding = NULL; + } + } + buf = xmlOutputBufferCreateFile(f, handler); + if (buf == NULL) return(-1); + xmlDocContentDumpOutput(buf, cur, NULL, format); + + ret = xmlOutputBufferClose(buf); + return(ret); +} + +/** + * xmlDocDump: + * @f: the FILE* + * @cur: the document + * + * Dump an XML document to an open FILE. + * + * returns: the number of bytes written or -1 in case of failure. + */ +int +xmlDocDump(FILE *f, xmlDocPtr cur) { + return(xmlDocFormatDump (f, cur, 0)); +} + +/** + * xmlSaveFileTo: + * @buf: an output I/O buffer + * @cur: the document + * @encoding: the encoding if any assuming the I/O layer handles the trancoding + * + * Dump an XML document to an I/O buffer. + * + * returns: the number of bytes written or -1 in case of failure. + */ +int +xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) { + int ret; + + if (buf == NULL) return(0); + xmlDocContentDumpOutput(buf, cur, encoding, 0); + ret = xmlOutputBufferClose(buf); + return(ret); +} + +/** + * xmlSaveFormatFileTo: + * @buf: an output I/O buffer + * @cur: the document + * @encoding: the encoding if any assuming the I/O layer handles the trancoding + * @format: should formatting spaces been added + * + * Dump an XML document to an I/O buffer. + * + * returns: the number of bytes written or -1 in case of failure. + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + */ +int +xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format) { + int ret; + + if (buf == NULL) return(0); + xmlDocContentDumpOutput(buf, cur, encoding, format); + ret = xmlOutputBufferClose(buf); + return(ret); +} + +/** + * xmlSaveFormatFileEnc: + * @filename: the filename or URL to output + * @cur: the document being saved + * @encoding: the name of the encoding to use or NULL. + * @format: should formatting spaces be added. + * + * Dump an XML document to a file or an URL. + * + * Returns the number of bytes written or -1 in case of error. + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + */ +int +xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur, + const char * encoding, int format ) { + xmlOutputBufferPtr buf; + xmlCharEncodingHandlerPtr handler = NULL; + int ret; + + if (cur == NULL) + return(-1); + + if (encoding == NULL) + encoding = (const char *) cur->encoding; + + if (encoding != NULL) { + + handler = xmlFindCharEncodingHandler(encoding); + if (handler == NULL) + return(-1); + } + +#ifdef HAVE_ZLIB_H + if (cur->compression < 0) cur->compression = xmlGetCompressMode(); +#endif + /* + * save the content to a temp buffer. + */ + buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression); + if (buf == NULL) return(-1); + + xmlDocContentDumpOutput(buf, cur, encoding, format); + + ret = xmlOutputBufferClose(buf); + return(ret); +} + + +/** + * xmlSaveFileEnc: + * @filename: the filename (or URL) + * @cur: the document + * @encoding: the name of an encoding (or NULL) + * + * Dump an XML document, converting it to the given encoding + * + * returns: the number of bytes written or -1 in case of failure. + */ +int +xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) { + return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) ); +} + +/** + * xmlSaveFormatFile: + * @filename: the filename (or URL) + * @cur: the document + * @format: should formatting spaces been added + * + * Dump an XML document to a file. Will use compression if + * compiled in and enabled. If @filename is "-" the stdout file is + * used. If @format is set then the document will be indented on output. + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + * + * returns: the number of bytes written or -1 in case of failure. + */ +int +xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) { + return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) ); +} + +/** + * xmlSaveFile: + * @filename: the filename (or URL) + * @cur: the document + * + * Dump an XML document to a file. Will use compression if + * compiled in and enabled. If @filename is "-" the stdout file is + * used. + * returns: the number of bytes written or -1 in case of failure. + */ +int +xmlSaveFile(const char *filename, xmlDocPtr cur) { + return(xmlSaveFormatFileEnc(filename, cur, NULL, 0)); +} + +#endif /* LIBXML_OUTPUT_ENABLED */ +