xmlsave.c revision 38ae7e4efe803ea78b6499cd05a394db32623e41
/*
* 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 <string.h>
#include <libxml/xmlmemory.h>
#include <libxml/parserInternals.h>
#define MAX_INDENT 60
#include <libxml/HTMLtree.h>
/************************************************************************
* *
* XHTML detection *
* *
************************************************************************/
#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
"-//W3C//DTD XHTML 1.0 Strict//EN"
#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
"-//W3C//DTD XHTML 1.0 Frameset//EN"
#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
"-//W3C//DTD XHTML 1.0 Transitional//EN"
#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
/**
* 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
return(-1);
}
}
return(0);
}
#ifdef LIBXML_OUTPUT_ENABLED
#define TODO \
"Unimplemented block at %s:%d\n", \
struct _xmlSaveCtxt {
void *_private;
int type;
int fd;
int options;
int level;
int format;
int indent_nr;
int indent_size;
};
/************************************************************************
* *
* Output error handlers *
* *
************************************************************************/
/**
* xmlSaveErrMemory:
* @extra: extra informations
*
* Handle an out of memory condition
*/
static void
xmlSaveErrMemory(const char *extra)
{
}
/**
* xmlSaveErr:
* @code: the error number
* @node: the location of the error.
* @extra: extra informations
*
* Handle an out of memory condition
*/
static void
{
switch(code) {
case XML_SAVE_NOT_UTF8:
msg = "string is not in UTF-8\n";
break;
case XML_SAVE_CHAR_INVALID:
msg = "invalid character value\n";
break;
msg = "unknown encoding %s\n";
break;
case XML_SAVE_NO_DOCTYPE:
msg = "document has no DOCTYPE\n";
break;
default:
msg = "unexpected error number\n";
}
}
/************************************************************************
* *
* Special escaping routines *
* *
************************************************************************/
static unsigned char *
unsigned char *ptr;
*out++ = '&';
*out++ = '#';
*out++ = 'x';
while (val > 0) {
switch (val & 0xF) {
case 0: *ptr-- = '0'; break;
default: *ptr-- = '0'; break;
}
val >>= 4;
}
*out++ = ';';
*out = 0;
return(out);
}
/**
* xmlEscapeEntities:
* @out: a pointer to an array of bytes to store the result
* @outlen: the length of @out
* @in: a pointer to an array of unescaped UTF-8 bytes
* @inlen: the length of @in
*
* Take a block of UTF-8 chars in and escape them. Used when there is no
* encoding specified.
*
* Returns 0 if success, or -1 otherwise
* The value of @inlen after return is the number of octets consumed
* if the return value is positive, else unpredictable.
* The value of @outlen after return is the number of octets consumed.
*/
static int
const unsigned char* inend;
int val;
if (*in == '<') {
*out++ = '&';
*out++ = 'l';
*out++ = 't';
*out++ = ';';
in++;
continue;
} else if (*in == '>') {
*out++ = '&';
*out++ = 'g';
*out++ = 't';
*out++ = ';';
in++;
continue;
} else if (*in == '&') {
*out++ = '&';
*out++ = 'a';
*out++ = 'm';
*out++ = 'p';
*out++ = ';';
in++;
continue;
/*
* default case, just copy !
*/
continue;
} else if (*in >= 0x80) {
/*
* We assume we have UTF-8 input.
*/
if (*in < 0xC0) {
in++;
goto error;
} else if (*in < 0xE0) {
val <<= 6;
in += 2;
} else if (*in < 0xF0) {
val <<= 6;
val <<= 6;
in += 3;
} else if (*in < 0xF8) {
val <<= 6;
val <<= 6;
val <<= 6;
in += 4;
} else {
in++;
goto error;
}
in++;
goto error;
}
/*
* We could do multiple things here. Just save as a char ref
*/
} else if (IS_BYTE_CHAR(*in)) {
} else {
"xmlEscapeEntities : char out of range\n");
in++;
goto error;
}
}
return(0);
return(-1);
}
/************************************************************************
* *
* Allocation and deallocation *
* *
************************************************************************/
/**
* xmlSaveCtxtInit:
* @ctxt: the saving context
*
* Initialize a saving context
*/
static void
{
int i;
int len;
} else {
ctxt->indent_size);
}
if (xmlSaveNoEmptyTags) {
}
}
/**
* xmlFreeSaveCtxt:
*
* Free a saving context, destroying the ouptut in any remaining buffer
*/
static void
{
}
/**
* xmlNewSaveCtxt:
*
* Create a new saving context
*
* Returns the new structure or NULL in case of error
*/
static xmlSaveCtxtPtr
{
xmlSaveErrMemory("creating saving context");
return ( NULL );
}
return(NULL);
}
}
/*
* Use the options
*/
/* Re-check this option as it may already have been set */
}
if (options & XML_SAVE_FORMAT)
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
{
case XML_TEXT_NODE:
break;
case XML_ENTITY_REF_NODE:
break;
default:
/* should not happen unless we have a badly built tree */
break;
}
}
}
/************************************************************************
* *
* Dumping XML tree content to an I/O output buffer *
* *
************************************************************************/
#ifdef LIBXML_HTML_ENABLED
static void
#endif
/**
* 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
return;
/* Within the context of an element attributes */
} else
}
}
/**
* 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
}
}
/**
* xmlDtdDumpOutput:
* @buf: the XML buffer output
* @dtd: the pointer to the DTD
*
* Dump the XML document DTD, if any.
*/
static void
return;
}
return;
}
/*
* Dump the notations first they are not in the DTD children list
* Do this only on a standalone DTD or on the internal subset though.
*/
}
}
/**
* xmlAttrDumpOutput:
* @buf: the XML buffer output
* @cur: the attribute pointer
*
* Dump an XML attribute
*/
static void
}
}
/**
* 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
}
}
/**
* xmlNodeListDumpOutput:
* @cur: the first node
*
* Dump an XML node list, recursive behaviour, children are printed too.
*/
static void
}
}
}
/**
* xmlNodeDumpOutputInternal:
* @cur: the current node
*
* Dump an XML node, recursive behaviour, children are printed too.
*/
static void
int format;
return;
return;
return;
}
return;
}
return;
}
return;
}
return;
}
return;
}
} else {
/*
* Disable escaping, needed for XSLT
*/
}
}
return;
}
}
} else {
}
return;
}
}
return;
}
return;
}
} else {
while (*end != '\0') {
}
end++;
}
}
}
return;
}
return;
}
return;
}
if (format == 1) {
break;
}
}
}
}
return;
}
}
}
}
}
/**
* xmlDocContentDumpOutput:
* @cur: the document
*
* Dump an XML document.
*/
static int
#ifdef LIBXML_HTML_ENABLED
int is_xhtml = 0;
#endif
}
if ((enc != XML_CHAR_ENCODING_UTF8) &&
(enc != XML_CHAR_ENCODING_NONE) &&
(enc != XML_CHAR_ENCODING_ASCII)) {
/*
* we need to switch to this encoding but just for this document
* since we output the XMLDecl the conversion must be done to not
* generate not well formed documents.
*/
(const char *)encoding);
return(-1);
}
xmlSaveErrMemory("creating encoding buffer");
return(-1);
}
/*
* initialize the state, e.g. if outputting a BOM
*/
}
}
/*
* Save the XML declaration
*/
else
}
switch (cur->standalone) {
case 0:
break;
case 1:
break;
}
}
#ifdef LIBXML_HTML_ENABLED
}
}
#endif
#ifdef LIBXML_HTML_ENABLED
if (is_xhtml)
else
#endif
}
}
/*
* Restore the state of the saving context at the end of the document
*/
if ((enc != XML_CHAR_ENCODING_UTF8) &&
(enc != XML_CHAR_ENCODING_NONE) &&
(enc != XML_CHAR_ENCODING_ASCII)) {
}
}
return(0);
}
#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
return(-1);
return(0);
return(0);
return(0);
case 'a':
return(1);
return(0);
case 'b':
return(1);
return(1);
return(1);
return(0);
case 'c':
return(1);
return(0);
case 'f':
return(1);
return(0);
case 'h':
return(1);
return(0);
case 'i':
return(1);
return(1);
return(1);
return(0);
case 'l':
return(1);
return(0);
case 'm':
return(1);
return(0);
case 'p':
return(1);
return(0);
}
return(0);
}
/**
* xhtmlAttrListDumpOutput:
* @cur: the first attribute pointer
*
* Dump a list of XML attributes
*/
static void
else
else
else
}
}
/*
* C.8
*/
}
}
/*
* C.7.
*/
} else
}
}
/**
* 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
}
}
}
/**
* 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.
*/
static void
return;
}
return;
return;
return;
}
return;
}
return;
}
return;
}
return;
}
} else {
/*
* Disable escaping, needed for XSLT
*/
}
}
return;
}
}
} else {
}
return;
}
}
return;
}
return;
}
while (*end != '\0') {
}
end++;
}
}
return;
}
return;
}
if (format == 1) {
format = 0;
break;
}
}
}
}
/*
* 3.1.1. Strictly Conforming Documents A.3.1.1 3/
*/
" xmlns=\"http://www.w3.org/1999/xhtml\"");
}
break;
}
}
}
}
addmeta = 1;
}
/*
* C.2. Empty Elements
*/
} else {
if (addmeta == 1) {
if (xmlIndentTreeOutput)
}
} else {
}
} else {
}
/*
* C.3. Element Minimization and Empty Element Content
*/
}
}
return;
}
if (addmeta == 1) {
if (xmlIndentTreeOutput)
}
} else {
}
}
}
#if 0
/*
* This was removed due to problems with HTML processors.
* See bug #345147.
*/
/*
* 4.8. Script and Style elements
*/
/* Nothing to escape, so just output as is... */
/* FIXME: Should we do something about "--" also? */
/* (We cannot use xhtmlNodeDumpOutput() here because
* we wish to leave '>' unescaped!) */
} else {
/* We must use a CDATA section. Unfortunately,
* this will break CSS and JavaScript when read by
* a browser in HTML4-compliant mode. :-( */
while (*end != '\0') {
if (*end == ']' &&
(const char *)start);
}
end++;
}
(const char *)start);
}
}
} else {
}
}
}
#endif
if ((xmlIndentTreeOutput) && (format))
}
}
}
#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.
*/
{
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.
*/
{
int compression = 0; /* TODO handle compression option */
return(NULL);
}
return(ret);
}
/**
* 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.
*/
{
return(NULL);
}
} else
return(NULL);
}
return(ret);
}
/**
* 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.
*/
{
return(NULL);
}
return(ret);
}
/**
* xmlSaveDoc:
* @ctxt: a document saving context
* @doc: a document
*
* Save a full document to a saving context
* TODO: The function is not fully implemented yet as it does not return the
* byte count but 0 instead
*
* Returns the number of byte written or -1 in case of error
*/
long
{
long ret = 0;
return(-1);
return(ret);
}
/**
* xmlSaveTree:
* @ctxt: a document saving context
* @node: the top node of the subtree to save
*
* Save a subtree starting at the node parameter to a saving context
* TODO: The function is not fully implemented yet as it does not return the
* byte count but 0 instead
*
* Returns the number of byte written or -1 in case of error
*/
long
{
long ret = 0;
return(ret);
}
/**
* 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
{
}
/**
* 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
{
int ret;
return(ret);
}
/**
* xmlSaveSetEscape:
* @ctxt: a document saving context
* @escape: the escaping function
*
* Set a custom escaping function to be used for text in element content
*
* Returns 0 if successful or -1 in case of error.
*/
int
{
return(0);
}
/**
* xmlSaveSetAttrEscape:
* @ctxt: a document saving context
* @escape: the escaping function
*
* Set a custom escaping function to be used for text in attribute content
*
* Returns 0 if successful or -1 in case of error.
*/
int
{
return(0);
}
/************************************************************************
* *
* 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
{
return;
while (*cur != 0) {
if (*cur == '\n') {
cur++;
} else if (*cur == '\r') {
cur++;
} else if (*cur == '\t') {
cur++;
} else if (*cur == '"') {
cur++;
} else if (*cur == '<') {
cur++;
} else if (*cur == '>') {
cur++;
} else if (*cur == '&') {
cur++;
/*
* We assume we have UTF-8 content.
*/
unsigned char tmp[10];
int val = 0, l = 1;
if (*cur < 0xC0) {
cur++;
continue;
} else if (*cur < 0xE0) {
val <<= 6;
l = 2;
} else if (*cur < 0xF0) {
val <<= 6;
val <<= 6;
l = 3;
} else if (*cur < 0xF8) {
val <<= 6;
val <<= 6;
val <<= 6;
l = 4;
}
cur++;
continue;
}
/*
* We could do multiple things here. Just save
* as a char ref
*/
cur += l;
} else {
cur++;
}
}
}
/**
* 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
int format)
{
unsigned int use;
int ret;
#ifdef DEBUG_TREE
"xmlNodeDump : node == NULL\n");
#endif
return (-1);
}
#ifdef DEBUG_TREE
"xmlNodeDump : buf == NULL\n");
#endif
return (-1);
}
xmlSaveErrMemory("creating buffer");
return (-1);
}
return (ret);
}
/**
* xmlElemDump:
* @f: the FILE * for the output
* @doc: the document
* @cur: the current node
*
*/
void
{
#ifdef DEBUG_TREE
"xmlElemDump : cur == NULL\n");
#endif
return;
}
#ifdef DEBUG_TREE
"xmlElemDump : doc == NULL\n");
}
#endif
return;
#ifdef LIBXML_HTML_ENABLED
#else
#endif /* LIBXML_HTML_ENABLED */
} else
}
/************************************************************************
* *
* 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
{
#ifdef LIBXML_HTML_ENABLED
int is_xhtml = 0;
#endif
encoding = "UTF-8";
#ifdef LIBXML_HTML_ENABLED
if (is_xhtml < 0)
is_xhtml = 0;
}
if (is_xhtml)
else
#endif
}
/**
* 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
int * doc_txt_len, const char * txt_encoding,
int format) {
int dummy = 0;
if (doc_txt_len == NULL) {
}
if (doc_txt_ptr == NULL) {
*doc_txt_len = 0;
return;
}
*doc_txt_ptr = NULL;
*doc_txt_len = 0;
/* No document, no output */
return;
}
/*
* Validate the encoding value, if provided.
* This logic is copied from xmlSaveFileEnc.
*/
if (txt_encoding == NULL)
if (txt_encoding != NULL) {
return;
}
}
xmlSaveErrMemory("creating buffer");
return;
}
} else {
}
(void)xmlOutputBufferClose(out_buff);
*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
}
/**
* 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
}
/**
* 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
int * doc_txt_len, const char * txt_encoding) {
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
const char * encoding;
int ret;
#ifdef DEBUG_TREE
"xmlDocDump : document == NULL\n");
#endif
return(-1);
}
}
}
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
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.
* Warning ! This call xmlOutputBufferClose() on buf which is not available
* after this call.
*
* returns: the number of bytes written or -1 in case of failure.
*/
int
int ret;
return(-1);
}
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.
* Warning ! This call xmlOutputBufferClose() on buf which is not available
* after this call.
*
* returns: the number of bytes written or -1 in case of failure.
*/
int
{
int ret;
return(-1);
}
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
int ret;
return(-1);
return(-1);
}
#ifdef HAVE_ZLIB_H
#endif
/*
* save the content to a temp buffer.
*/
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
}
/**
* 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
}
/**
* 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
}
#endif /* LIBXML_OUTPUT_ENABLED */
#define bottom_xmlsave
#include "elfgcchack.h"