2004-03-04 16:40:59 +03:00
/*
2019-09-30 18:04:54 +03:00
* xmlsave . c : Implementation of the document serializer
2004-03-04 16:40:59 +03:00
*
* See Copyright for the status of this software .
*
* daniel @ veillard . com
*/
# define IN_LIBXML
# include "libxml.h"
2024-03-03 18:51:07 +03:00
# include <limits.h>
2024-01-04 23:20:51 +03:00
# include <stdlib.h>
2004-03-04 16:40:59 +03:00
# include <string.h>
# include <libxml/xmlmemory.h>
# include <libxml/parserInternals.h>
# include <libxml/tree.h>
# include <libxml/xmlsave.h>
2004-03-28 20:12:44 +04:00
# define MAX_INDENT 60
2004-05-01 03:11:45 +04:00
# include <libxml/HTMLtree.h>
2022-08-26 02:22:33 +03:00
# include "private/buf.h"
# include "private/enc.h"
2024-07-12 03:01:06 +03:00
# include "private/entities.h"
2022-08-26 02:22:33 +03:00
# include "private/error.h"
2024-02-16 17:42:38 +03:00
# include "private/io.h"
2022-08-26 02:22:33 +03:00
# include "private/save.h"
2012-07-16 10:52:00 +04:00
2022-09-01 21:45:35 +03:00
# ifdef LIBXML_OUTPUT_ENABLED
2004-03-04 16:40:59 +03:00
# define XHTML_NS_NAME BAD_CAST "http: //www.w3.org/1999/xhtml"
struct _xmlSaveCtxt {
void * _private ;
int type ;
int fd ;
const xmlChar * filename ;
const xmlChar * encoding ;
xmlCharEncodingHandlerPtr handler ;
2004-03-15 16:46:37 +03:00
xmlOutputBufferPtr buf ;
2004-03-04 16:40:59 +03:00
int options ;
int level ;
2004-03-15 16:46:37 +03:00
int format ;
2004-05-15 22:57:31 +04:00
char indent [ MAX_INDENT + 1 ] ; /* array for indenting output */
2004-03-28 20:12:44 +04:00
int indent_nr ;
int indent_size ;
2004-05-15 22:57:31 +04:00
xmlCharEncodingOutputFunc escape ; /* used for element content */
2004-03-04 16:40:59 +03:00
} ;
/************************************************************************
* *
2012-09-11 09:26:36 +04:00
* Output error handlers *
2004-03-04 16:40:59 +03:00
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* xmlSaveErrMemory :
2020-03-08 19:19:42 +03:00
* @ extra : extra information
2004-03-04 16:40:59 +03:00
*
* Handle an out of memory condition
*/
static void
2024-01-02 23:49:43 +03:00
xmlSaveErrMemory ( xmlOutputBufferPtr out )
2004-03-04 16:40:59 +03:00
{
2024-01-02 23:49:43 +03:00
if ( out ! = NULL )
out - > error = XML_ERR_NO_MEMORY ;
2023-12-18 23:30:22 +03:00
xmlRaiseMemoryError ( NULL , NULL , NULL , XML_FROM_OUTPUT , NULL ) ;
2004-03-04 16:40:59 +03:00
}
/**
* xmlSaveErr :
* @ code : the error number
* @ node : the location of the error .
2020-03-08 19:19:42 +03:00
* @ extra : extra information
2004-03-04 16:40:59 +03:00
*
* Handle an out of memory condition
*/
static void
2024-01-02 23:49:43 +03:00
xmlSaveErr ( xmlOutputBufferPtr out , int code , xmlNodePtr node ,
const char * extra )
2004-03-04 16:40:59 +03:00
{
const char * msg = NULL ;
2023-12-18 23:30:22 +03:00
int res ;
2004-03-04 16:40:59 +03:00
2024-01-02 23:49:43 +03:00
/* Don't overwrite memory errors */
if ( ( out ! = NULL ) & & ( out - > error = = XML_ERR_NO_MEMORY ) )
return ;
if ( code = = XML_ERR_NO_MEMORY ) {
xmlSaveErrMemory ( out ) ;
return ;
}
if ( out ! = NULL )
out - > error = code ;
2024-07-25 01:26:48 +03:00
if ( code = = XML_ERR_UNSUPPORTED_ENCODING ) {
msg = " Unsupported encoding: %s " ;
} else {
msg = xmlErrString ( code ) ;
extra = NULL ;
2004-03-04 16:40:59 +03:00
}
2023-12-18 23:30:22 +03:00
2024-06-26 02:18:55 +03:00
res = xmlRaiseError ( NULL , NULL , NULL , NULL , node ,
XML_FROM_OUTPUT , code , XML_ERR_ERROR , NULL , 0 ,
extra , NULL , NULL , 0 , 0 ,
msg , extra ) ;
2023-12-18 23:30:22 +03:00
if ( res < 0 )
2024-01-02 23:49:43 +03:00
xmlSaveErrMemory ( out ) ;
2004-03-04 16:40:59 +03:00
}
2004-05-15 01:50:42 +04:00
/************************************************************************
* *
* Special escaping routines *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-05-15 20:37:50 +04:00
2024-07-12 17:25:05 +03:00
/*
* Tables generated with tools / genEscape . py
*/
static const char xmlEscapeContent [ ] = {
8 , ' & ' , ' # ' , ' x ' , ' F ' , ' F ' , ' F ' , ' D ' , ' ; ' , 4 , ' & ' , ' # ' ,
' 9 ' , ' ; ' , 5 , ' & ' , ' # ' , ' 1 ' , ' 0 ' , ' ; ' , 5 , ' & ' , ' # ' , ' 1 ' ,
' 3 ' , ' ; ' , 6 , ' & ' , ' q ' , ' u ' , ' o ' , ' t ' , ' ; ' , 5 , ' & ' , ' a ' ,
' m ' , ' p ' , ' ; ' , 4 , ' & ' , ' l ' , ' t ' , ' ; ' , 4 , ' & ' , ' g ' , ' t ' ,
' ; ' ,
} ;
2024-09-10 18:12:25 +03:00
static const signed char xmlEscapeTab [ 128 ] = {
2024-07-12 17:25:05 +03:00
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 1 , - 1 , 0 , 0 , 20 , 0 , 0 ,
0 , 0 , 0 , 0 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , 33 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , 39 , - 1 , 44 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
} ;
2024-09-10 18:12:25 +03:00
static const signed char xmlEscapeTabAttr [ 128 ] = {
2024-07-12 17:25:05 +03:00
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 9 , 14 , 0 , 0 , 20 , 0 , 0 ,
0 , 0 , 0 , 0 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , 26 , - 1 , - 1 , - 1 , 33 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , 39 , - 1 , 44 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
} ;
2024-07-11 23:06:31 +03:00
static void
xmlSerializeText ( xmlOutputBufferPtr buf , const xmlChar * string ,
unsigned flags ) {
2024-07-12 17:25:05 +03:00
const char * cur ;
2024-09-10 18:12:25 +03:00
const signed char * tab ;
2024-07-11 23:06:31 +03:00
2024-07-18 02:59:25 +03:00
if ( string = = NULL )
return ;
2024-07-12 17:25:05 +03:00
if ( flags & XML_ESCAPE_ATTR )
tab = xmlEscapeTabAttr ;
else
tab = xmlEscapeTab ;
2024-01-02 16:04:44 +03:00
2024-07-12 17:25:05 +03:00
cur = ( const char * ) string ;
2024-07-11 23:06:31 +03:00
while ( * cur ! = 0 ) {
2024-07-12 17:25:05 +03:00
const char * base ;
int c ;
int offset ;
2024-07-11 23:06:31 +03:00
2024-07-12 17:25:05 +03:00
base = cur ;
offset = - 1 ;
2024-07-11 23:06:31 +03:00
2024-07-12 17:25:05 +03:00
while ( 1 ) {
c = ( unsigned char ) * cur ;
2024-07-11 23:06:31 +03:00
2024-07-12 17:25:05 +03:00
if ( c < 0x80 ) {
offset = tab [ c ] ;
if ( offset > = 0 )
break ;
} else if ( flags & XML_ESCAPE_NON_ASCII ) {
2024-07-11 23:06:31 +03:00
break ;
2024-07-12 17:25:05 +03:00
}
2024-07-11 23:06:31 +03:00
2024-07-12 17:25:05 +03:00
cur + = 1 ;
}
2024-07-11 23:06:31 +03:00
2024-07-12 17:25:05 +03:00
if ( cur > base )
xmlOutputBufferWrite ( buf , cur - base , base ) ;
2024-07-11 23:06:31 +03:00
2024-07-12 17:25:05 +03:00
if ( offset > = 0 ) {
if ( c = = 0 )
2024-07-11 23:06:31 +03:00
break ;
2024-07-12 17:25:05 +03:00
xmlOutputBufferWrite ( buf , xmlEscapeContent [ offset ] ,
& xmlEscapeContent [ offset + 1 ] ) ;
cur + = 1 ;
2024-07-11 23:06:31 +03:00
} else {
2024-07-12 17:25:05 +03:00
char tempBuf [ 12 ] ;
int tempSize ;
int val = 0 , len = 4 ;
val = xmlGetUTF8Char ( ( const xmlChar * ) cur , & len ) ;
if ( val < 0 ) {
val = 0xFFFD ;
cur + = 1 ;
} else {
if ( ! IS_CHAR ( val ) )
val = 0xFFFD ;
cur + = len ;
}
tempSize = xmlSerializeHexCharRef ( tempBuf , val ) ;
xmlOutputBufferWrite ( buf , tempSize , tempBuf ) ;
2024-07-11 23:06:31 +03:00
}
2004-05-15 01:50:42 +04:00
}
}
2004-03-04 16:40:59 +03:00
/************************************************************************
* *
* Allocation and deallocation *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2024-07-02 20:43:24 +03:00
/**
* xmlSaveSetIndentString :
* @ ctxt : save context
* @ indent : indent string
*
* Sets the indent string .
*
* Available since 2.14 .0 .
*
* Returns 0 on success , - 1 if the string is NULL , empty or too long .
*/
int
xmlSaveSetIndentString ( xmlSaveCtxtPtr ctxt , const char * indent ) {
size_t len ;
int i ;
2024-07-11 02:23:57 +03:00
if ( ( ctxt = = NULL ) | | ( indent = = NULL ) )
2024-07-02 20:43:24 +03:00
return ( - 1 ) ;
len = strlen ( indent ) ;
if ( ( len < = 0 ) | | ( len > MAX_INDENT ) )
return ( - 1 ) ;
ctxt - > indent_size = len ;
ctxt - > indent_nr = MAX_INDENT / ctxt - > indent_size ;
for ( i = 0 ; i < ctxt - > indent_nr ; i + + )
memcpy ( & ctxt - > indent [ i * ctxt - > indent_size ] , indent , len ) ;
return ( 0 ) ;
}
2004-03-28 20:12:44 +04:00
/**
* xmlSaveCtxtInit :
* @ ctxt : the saving context
*
* Initialize a saving context
*/
static void
2024-07-02 19:51:59 +03:00
xmlSaveCtxtInit ( xmlSaveCtxtPtr ctxt , int options )
2004-03-28 20:12:44 +04:00
{
if ( ctxt = = NULL ) return ;
2024-07-02 19:51:59 +03:00
2024-07-02 20:43:24 +03:00
xmlSaveSetIndentString ( ctxt , xmlTreeIndentString ) ;
2005-09-12 16:16:35 +04:00
2024-07-02 19:51:59 +03:00
if ( options & XML_SAVE_FORMAT )
ctxt - > format = 1 ;
else if ( options & XML_SAVE_WSNONSIG )
ctxt - > format = 2 ;
2024-07-02 20:22:32 +03:00
if ( ( ( options & XML_SAVE_EMPTY ) = = 0 ) & &
( xmlSaveNoEmptyTags ) )
options | = XML_SAVE_NO_EMPTY ;
ctxt - > options = options ;
2004-03-28 20:12:44 +04:00
}
2004-03-04 16:40:59 +03:00
/**
* xmlFreeSaveCtxt :
*
2019-09-30 18:04:54 +03:00
* Free a saving context , destroying the output in any remaining buffer
2004-03-04 16:40:59 +03:00
*/
static void
xmlFreeSaveCtxt ( xmlSaveCtxtPtr ctxt )
{
if ( ctxt = = NULL ) return ;
if ( ctxt - > encoding ! = NULL )
xmlFree ( ( char * ) ctxt - > encoding ) ;
2004-04-29 21:14:25 +04:00
if ( ctxt - > buf ! = NULL )
xmlOutputBufferClose ( ctxt - > buf ) ;
2004-03-04 16:40:59 +03:00
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 ) {
2024-01-02 23:49:43 +03:00
xmlSaveErrMemory ( NULL ) ;
2004-03-04 16:40:59 +03:00
return ( NULL ) ;
}
memset ( ret , 0 , sizeof ( xmlSaveCtxt ) ) ;
2005-01-16 03:05:58 +03:00
2004-03-04 16:40:59 +03:00
if ( encoding ! = NULL ) {
2024-01-02 20:33:57 +03:00
int res ;
res = xmlOpenCharEncodingHandler ( encoding , /* output */ 1 ,
& ret - > handler ) ;
2024-06-22 20:15:17 +03:00
if ( res ! = XML_ERR_OK ) {
2024-01-02 23:49:43 +03:00
xmlSaveErr ( NULL , res , NULL , encoding ) ;
2004-03-04 16:40:59 +03:00
xmlFreeSaveCtxt ( ret ) ;
return ( NULL ) ;
}
ret - > encoding = xmlStrdup ( ( const xmlChar * ) encoding ) ;
}
2005-09-12 16:16:35 +04:00
2024-07-02 19:51:59 +03:00
xmlSaveCtxtInit ( ret , options ) ;
2005-09-12 16:16:35 +04:00
2004-03-04 16:40:59 +03:00
return ( ret ) ;
}
/************************************************************************
* *
2012-09-11 09:26:36 +04:00
* Dumping XML tree content to a simple buffer *
2004-03-04 16:40:59 +03:00
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2024-07-11 23:06:31 +03:00
static void
xmlSaveWriteText ( xmlSaveCtxt * ctxt , const xmlChar * text , unsigned flags ) {
if ( ctxt - > encoding = = NULL )
flags | = XML_ESCAPE_NON_ASCII ;
xmlSerializeText ( ctxt - > buf , text , flags ) ;
}
2004-03-04 16:40:59 +03:00
/**
2024-07-11 23:06:31 +03:00
* xmlSaveWriteAttrContent :
* @ ctxt : save context
2004-03-04 16:40:59 +03:00
* @ attr : the attribute pointer
*
* Serialize the attribute in the buffer
*/
static void
2024-07-11 23:06:31 +03:00
xmlSaveWriteAttrContent ( xmlSaveCtxt * ctxt , xmlAttrPtr attr )
2004-03-04 16:40:59 +03:00
{
xmlNodePtr children ;
2024-07-11 23:06:31 +03:00
xmlOutputBufferPtr buf = ctxt - > buf ;
2004-03-04 16:40:59 +03:00
children = attr - > children ;
while ( children ! = NULL ) {
switch ( children - > type ) {
case XML_TEXT_NODE :
2024-07-11 23:06:31 +03:00
xmlSaveWriteText ( ctxt , children - > content , XML_ESCAPE_ATTR ) ;
2004-03-04 16:40:59 +03:00
break ;
case XML_ENTITY_REF_NODE :
2024-02-16 17:42:38 +03:00
xmlOutputBufferWrite ( buf , 1 , " & " ) ;
xmlOutputBufferWriteString ( buf , ( const char * ) children - > name ) ;
xmlOutputBufferWrite ( buf , 1 , " ; " ) ;
2004-03-04 16:40:59 +03:00
break ;
default :
/* should not happen unless we have a badly built tree */
break ;
}
children = children - > next ;
}
}
2024-02-01 21:01:57 +03:00
/**
* xmlBufDumpNotationDecl :
* @ buf : the XML buffer output
* @ nota : A notation declaration
*
* This will dump the content the notation declaration as an XML DTD definition
*/
static void
xmlBufDumpNotationDecl ( xmlOutputBufferPtr buf , xmlNotationPtr nota ) {
xmlOutputBufferWrite ( buf , 11 , " <!NOTATION " ) ;
xmlOutputBufferWriteString ( buf , ( const char * ) nota - > name ) ;
if ( nota - > PublicID ! = NULL ) {
xmlOutputBufferWrite ( buf , 8 , " PUBLIC " ) ;
2024-02-16 17:42:38 +03:00
xmlOutputBufferWriteQuotedString ( buf , nota - > PublicID ) ;
2024-02-01 21:01:57 +03:00
if ( nota - > SystemID ! = NULL ) {
xmlOutputBufferWrite ( buf , 1 , " " ) ;
2024-02-16 17:42:38 +03:00
xmlOutputBufferWriteQuotedString ( buf , nota - > SystemID ) ;
2024-02-01 21:01:57 +03:00
}
} else {
xmlOutputBufferWrite ( buf , 8 , " SYSTEM " ) ;
2024-02-16 17:42:38 +03:00
xmlOutputBufferWriteQuotedString ( buf , nota - > SystemID ) ;
2024-02-01 21:01:57 +03:00
}
xmlOutputBufferWrite ( buf , 3 , " > \n " ) ;
}
/**
* xmlBufDumpNotationDeclScan :
* @ nota : A notation declaration
* @ buf : the XML buffer output
*
* This is called with the hash scan function , and just reverses args
*/
static void
xmlBufDumpNotationDeclScan ( void * nota , void * buf ,
const xmlChar * name ATTRIBUTE_UNUSED ) {
xmlBufDumpNotationDecl ( ( xmlOutputBufferPtr ) buf , ( xmlNotationPtr ) nota ) ;
}
2012-07-16 10:52:00 +04:00
/**
* xmlBufDumpNotationTable :
* @ buf : an xmlBufPtr output
* @ table : A notation table
*
* This will dump the content of the notation table as an XML DTD definition
*/
2022-08-26 02:22:33 +03:00
static void
2024-02-01 21:01:57 +03:00
xmlBufDumpNotationTable ( xmlOutputBufferPtr buf , xmlNotationTablePtr table ) {
xmlHashScan ( table , xmlBufDumpNotationDeclScan , buf ) ;
}
2012-07-16 10:52:00 +04:00
2024-02-01 21:01:57 +03:00
/**
* xmlBufDumpElementOccur :
* @ buf : output buffer
* @ cur : element table
*
* Dump the occurrence operator of an element .
*/
static void
xmlBufDumpElementOccur ( xmlOutputBufferPtr buf , xmlElementContentPtr cur ) {
switch ( cur - > ocur ) {
case XML_ELEMENT_CONTENT_ONCE :
break ;
case XML_ELEMENT_CONTENT_OPT :
xmlOutputBufferWrite ( buf , 1 , " ? " ) ;
break ;
case XML_ELEMENT_CONTENT_MULT :
xmlOutputBufferWrite ( buf , 1 , " * " ) ;
break ;
case XML_ELEMENT_CONTENT_PLUS :
xmlOutputBufferWrite ( buf , 1 , " + " ) ;
break ;
2012-07-16 10:52:00 +04:00
}
2024-02-01 21:01:57 +03:00
}
/**
* xmlBufDumpElementContent :
* @ buf : output buffer
* @ content : element table
*
* This will dump the content of the element table as an XML DTD definition
*/
static void
xmlBufDumpElementContent ( xmlOutputBufferPtr buf ,
xmlElementContentPtr content ) {
xmlElementContentPtr cur ;
if ( content = = NULL ) return ;
xmlOutputBufferWrite ( buf , 1 , " ( " ) ;
cur = content ;
do {
if ( cur = = NULL ) return ;
switch ( cur - > type ) {
case XML_ELEMENT_CONTENT_PCDATA :
xmlOutputBufferWrite ( buf , 7 , " #PCDATA " ) ;
break ;
case XML_ELEMENT_CONTENT_ELEMENT :
if ( cur - > prefix ! = NULL ) {
xmlOutputBufferWriteString ( buf ,
( const char * ) cur - > prefix ) ;
xmlOutputBufferWrite ( buf , 1 , " : " ) ;
}
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > name ) ;
break ;
case XML_ELEMENT_CONTENT_SEQ :
case XML_ELEMENT_CONTENT_OR :
if ( ( cur ! = content ) & &
( cur - > parent ! = NULL ) & &
( ( cur - > type ! = cur - > parent - > type ) | |
( cur - > ocur ! = XML_ELEMENT_CONTENT_ONCE ) ) )
xmlOutputBufferWrite ( buf , 1 , " ( " ) ;
cur = cur - > c1 ;
continue ;
}
while ( cur ! = content ) {
xmlElementContentPtr parent = cur - > parent ;
if ( parent = = NULL ) return ;
if ( ( ( cur - > type = = XML_ELEMENT_CONTENT_OR ) | |
( cur - > type = = XML_ELEMENT_CONTENT_SEQ ) ) & &
( ( cur - > type ! = parent - > type ) | |
( cur - > ocur ! = XML_ELEMENT_CONTENT_ONCE ) ) )
xmlOutputBufferWrite ( buf , 1 , " ) " ) ;
xmlBufDumpElementOccur ( buf , cur ) ;
if ( cur = = parent - > c1 ) {
if ( parent - > type = = XML_ELEMENT_CONTENT_SEQ )
xmlOutputBufferWrite ( buf , 3 , " , " ) ;
else if ( parent - > type = = XML_ELEMENT_CONTENT_OR )
xmlOutputBufferWrite ( buf , 3 , " | " ) ;
cur = parent - > c2 ;
break ;
}
cur = parent ;
}
} while ( cur ! = content ) ;
xmlOutputBufferWrite ( buf , 1 , " ) " ) ;
xmlBufDumpElementOccur ( buf , content ) ;
2012-07-16 10:52:00 +04:00
}
/**
* xmlBufDumpElementDecl :
* @ buf : an xmlBufPtr output
* @ elem : An element table
*
* This will dump the content of the element declaration as an XML
* DTD definition
*/
2022-08-26 02:22:33 +03:00
static void
2024-02-01 21:01:57 +03:00
xmlBufDumpElementDecl ( xmlOutputBufferPtr buf , xmlElementPtr elem ) {
xmlOutputBufferWrite ( buf , 10 , " <!ELEMENT " ) ;
if ( elem - > prefix ! = NULL ) {
xmlOutputBufferWriteString ( buf , ( const char * ) elem - > prefix ) ;
xmlOutputBufferWrite ( buf , 1 , " : " ) ;
}
xmlOutputBufferWriteString ( buf , ( const char * ) elem - > name ) ;
xmlOutputBufferWrite ( buf , 1 , " " ) ;
2012-07-16 10:52:00 +04:00
2024-02-01 21:01:57 +03:00
switch ( elem - > etype ) {
case XML_ELEMENT_TYPE_EMPTY :
xmlOutputBufferWrite ( buf , 5 , " EMPTY " ) ;
break ;
case XML_ELEMENT_TYPE_ANY :
xmlOutputBufferWrite ( buf , 3 , " ANY " ) ;
break ;
case XML_ELEMENT_TYPE_MIXED :
case XML_ELEMENT_TYPE_ELEMENT :
xmlBufDumpElementContent ( buf , elem - > content ) ;
break ;
default :
/* assert(0); */
break ;
2012-07-16 10:52:00 +04:00
}
2024-02-01 21:01:57 +03:00
xmlOutputBufferWrite ( buf , 2 , " > \n " ) ;
2012-07-16 10:52:00 +04:00
}
2024-02-01 21:01:57 +03:00
/**
* xmlBufDumpEnumeration :
* @ buf : output buffer
* @ enum : An enumeration
*
* This will dump the content of the enumeration
*/
static void
xmlBufDumpEnumeration ( xmlOutputBufferPtr buf , xmlEnumerationPtr cur ) {
while ( cur ! = NULL ) {
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > name ) ;
if ( cur - > next ! = NULL )
xmlOutputBufferWrite ( buf , 3 , " | " ) ;
cur = cur - > next ;
}
xmlOutputBufferWrite ( buf , 1 , " ) " ) ;
}
2012-07-16 10:52:00 +04:00
/**
* xmlBufDumpAttributeDecl :
2024-02-01 21:01:57 +03:00
* @ buf : output buffer
2012-07-16 10:52:00 +04:00
* @ attr : An attribute declaration
*
* This will dump the content of the attribute declaration as an XML
* DTD definition
*/
2022-08-26 02:22:33 +03:00
static void
2024-02-01 21:01:57 +03:00
xmlBufDumpAttributeDecl ( xmlOutputBufferPtr buf , xmlAttributePtr attr ) {
xmlOutputBufferWrite ( buf , 10 , " <!ATTLIST " ) ;
xmlOutputBufferWriteString ( buf , ( const char * ) attr - > elem ) ;
xmlOutputBufferWrite ( buf , 1 , " " ) ;
if ( attr - > prefix ! = NULL ) {
xmlOutputBufferWriteString ( buf , ( const char * ) attr - > prefix ) ;
xmlOutputBufferWrite ( buf , 1 , " : " ) ;
}
xmlOutputBufferWriteString ( buf , ( const char * ) attr - > name ) ;
2012-07-16 10:52:00 +04:00
2024-02-01 21:01:57 +03:00
switch ( attr - > atype ) {
case XML_ATTRIBUTE_CDATA :
xmlOutputBufferWrite ( buf , 6 , " CDATA " ) ;
break ;
case XML_ATTRIBUTE_ID :
xmlOutputBufferWrite ( buf , 3 , " ID " ) ;
break ;
case XML_ATTRIBUTE_IDREF :
xmlOutputBufferWrite ( buf , 6 , " IDREF " ) ;
break ;
case XML_ATTRIBUTE_IDREFS :
xmlOutputBufferWrite ( buf , 7 , " IDREFS " ) ;
break ;
case XML_ATTRIBUTE_ENTITY :
xmlOutputBufferWrite ( buf , 7 , " ENTITY " ) ;
break ;
case XML_ATTRIBUTE_ENTITIES :
xmlOutputBufferWrite ( buf , 9 , " ENTITIES " ) ;
break ;
case XML_ATTRIBUTE_NMTOKEN :
xmlOutputBufferWrite ( buf , 8 , " NMTOKEN " ) ;
break ;
case XML_ATTRIBUTE_NMTOKENS :
xmlOutputBufferWrite ( buf , 9 , " NMTOKENS " ) ;
break ;
case XML_ATTRIBUTE_ENUMERATION :
xmlOutputBufferWrite ( buf , 2 , " ( " ) ;
xmlBufDumpEnumeration ( buf , attr - > tree ) ;
break ;
case XML_ATTRIBUTE_NOTATION :
xmlOutputBufferWrite ( buf , 11 , " NOTATION ( " ) ;
xmlBufDumpEnumeration ( buf , attr - > tree ) ;
break ;
default :
/* assert(0); */
break ;
}
switch ( attr - > def ) {
case XML_ATTRIBUTE_NONE :
break ;
case XML_ATTRIBUTE_REQUIRED :
xmlOutputBufferWrite ( buf , 10 , " #REQUIRED " ) ;
break ;
case XML_ATTRIBUTE_IMPLIED :
xmlOutputBufferWrite ( buf , 9 , " #IMPLIED " ) ;
break ;
case XML_ATTRIBUTE_FIXED :
xmlOutputBufferWrite ( buf , 7 , " #FIXED " ) ;
break ;
default :
/* assert(0); */
break ;
}
if ( attr - > defaultValue ! = NULL ) {
xmlOutputBufferWrite ( buf , 1 , " " ) ;
2024-02-16 17:42:38 +03:00
xmlOutputBufferWriteQuotedString ( buf , attr - > defaultValue ) ;
2024-02-01 21:01:57 +03:00
}
xmlOutputBufferWrite ( buf , 2 , " > \n " ) ;
}
/**
* xmlBufDumpEntityContent :
* @ buf : output buffer
* @ content : entity content .
*
* This will dump the quoted string value , taking care of the special
* treatment required by %
*/
static void
xmlBufDumpEntityContent ( xmlOutputBufferPtr buf , const xmlChar * content ) {
if ( xmlStrchr ( content , ' % ' ) ) {
const char * base , * cur ;
xmlOutputBufferWrite ( buf , 1 , " \" " ) ;
base = cur = ( const char * ) content ;
while ( * cur ! = 0 ) {
if ( * cur = = ' " ' ) {
if ( base ! = cur )
xmlOutputBufferWrite ( buf , cur - base , base ) ;
xmlOutputBufferWrite ( buf , 6 , " " " ) ;
cur + + ;
base = cur ;
} else if ( * cur = = ' % ' ) {
if ( base ! = cur )
xmlOutputBufferWrite ( buf , cur - base , base ) ;
xmlOutputBufferWrite ( buf , 6 , " % " ) ;
cur + + ;
base = cur ;
} else {
cur + + ;
}
}
if ( base ! = cur )
xmlOutputBufferWrite ( buf , cur - base , base ) ;
xmlOutputBufferWrite ( buf , 1 , " \" " ) ;
} else {
2024-02-16 17:42:38 +03:00
xmlOutputBufferWriteQuotedString ( buf , content ) ;
2012-07-16 10:52:00 +04:00
}
}
/**
* xmlBufDumpEntityDecl :
* @ buf : an xmlBufPtr output
* @ ent : An entity table
*
* This will dump the content of the entity table as an XML DTD definition
*/
2022-08-26 02:22:33 +03:00
static void
2024-02-01 21:01:57 +03:00
xmlBufDumpEntityDecl ( xmlOutputBufferPtr buf , xmlEntityPtr ent ) {
if ( ( ent - > etype = = XML_INTERNAL_PARAMETER_ENTITY ) | |
( ent - > etype = = XML_EXTERNAL_PARAMETER_ENTITY ) )
xmlOutputBufferWrite ( buf , 11 , " <!ENTITY % " ) ;
else
xmlOutputBufferWrite ( buf , 9 , " <!ENTITY " ) ;
xmlOutputBufferWriteString ( buf , ( const char * ) ent - > name ) ;
xmlOutputBufferWrite ( buf , 1 , " " ) ;
if ( ( ent - > etype = = XML_EXTERNAL_GENERAL_PARSED_ENTITY ) | |
( ent - > etype = = XML_EXTERNAL_GENERAL_UNPARSED_ENTITY ) | |
( ent - > etype = = XML_EXTERNAL_PARAMETER_ENTITY ) ) {
if ( ent - > ExternalID ! = NULL ) {
xmlOutputBufferWrite ( buf , 7 , " PUBLIC " ) ;
2024-02-16 17:42:38 +03:00
xmlOutputBufferWriteQuotedString ( buf , ent - > ExternalID ) ;
2024-02-01 21:01:57 +03:00
xmlOutputBufferWrite ( buf , 1 , " " ) ;
} else {
xmlOutputBufferWrite ( buf , 7 , " SYSTEM " ) ;
}
2024-02-16 17:42:38 +03:00
xmlOutputBufferWriteQuotedString ( buf , ent - > SystemID ) ;
2024-02-01 21:01:57 +03:00
}
2012-07-16 10:52:00 +04:00
2024-02-01 21:01:57 +03:00
if ( ent - > etype = = XML_EXTERNAL_GENERAL_UNPARSED_ENTITY ) {
if ( ent - > content ! = NULL ) { /* Should be true ! */
xmlOutputBufferWrite ( buf , 7 , " NDATA " ) ;
if ( ent - > orig ! = NULL )
xmlOutputBufferWriteString ( buf , ( const char * ) ent - > orig ) ;
else
xmlOutputBufferWriteString ( buf , ( const char * ) ent - > content ) ;
}
}
if ( ( ent - > etype = = XML_INTERNAL_GENERAL_ENTITY ) | |
( ent - > etype = = XML_INTERNAL_PARAMETER_ENTITY ) ) {
if ( ent - > orig ! = NULL )
2024-02-16 17:42:38 +03:00
xmlOutputBufferWriteQuotedString ( buf , ent - > orig ) ;
2024-02-01 21:01:57 +03:00
else
xmlBufDumpEntityContent ( buf , ent - > content ) ;
2012-07-16 10:52:00 +04:00
}
2024-02-01 21:01:57 +03:00
xmlOutputBufferWrite ( buf , 2 , " > \n " ) ;
2012-07-16 10:52:00 +04:00
}
2004-03-04 16:40:59 +03:00
/************************************************************************
* *
2012-09-11 09:26:36 +04:00
* Dumping XML tree content to an I / O output buffer *
2004-03-04 16:40:59 +03:00
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-09-01 17:08:57 +04:00
static int xmlSaveSwitchEncoding ( xmlSaveCtxtPtr ctxt , const char * encoding ) {
xmlOutputBufferPtr buf = ctxt - > buf ;
if ( ( encoding ! = NULL ) & & ( buf - > encoder = = NULL ) & & ( buf - > conv = = NULL ) ) {
2023-12-10 19:14:57 +03:00
xmlCharEncodingHandler * handler ;
int res ;
2024-01-02 20:33:57 +03:00
res = xmlOpenCharEncodingHandler ( encoding , /* output */ 1 , & handler ) ;
2024-06-22 20:15:17 +03:00
if ( res ! = XML_ERR_OK ) {
2024-01-02 23:49:43 +03:00
xmlSaveErr ( buf , res , NULL , encoding ) ;
2023-12-10 19:14:57 +03:00
return ( - 1 ) ;
}
2024-07-07 04:01:51 +03:00
buf - > conv = xmlBufCreate ( 4000 /* MINLEN */ ) ;
2008-09-01 17:08:57 +04:00
if ( buf - > conv = = NULL ) {
2023-12-10 19:14:57 +03:00
xmlCharEncCloseFunc ( handler ) ;
2024-01-02 23:49:43 +03:00
xmlSaveErrMemory ( buf ) ;
2008-09-01 17:08:57 +04:00
return ( - 1 ) ;
}
2023-12-10 19:14:57 +03:00
buf - > encoder = handler ;
2008-09-01 17:08:57 +04:00
/*
* initialize the state , e . g . if outputting a BOM
*/
2012-07-16 10:52:00 +04:00
xmlCharEncOutput ( buf , 1 ) ;
2008-09-01 17:08:57 +04:00
}
return ( 0 ) ;
}
static int xmlSaveClearEncoding ( xmlSaveCtxtPtr ctxt ) {
xmlOutputBufferPtr buf = ctxt - > buf ;
xmlOutputBufferFlush ( buf ) ;
xmlCharEncCloseFunc ( buf - > encoder ) ;
2012-07-16 10:52:00 +04:00
xmlBufFree ( buf - > conv ) ;
2008-09-01 17:08:57 +04:00
buf - > encoder = NULL ;
buf - > conv = NULL ;
return ( 0 ) ;
}
2004-03-04 16:40:59 +03:00
# ifdef LIBXML_HTML_ENABLED
static void
2004-03-15 16:46:37 +03:00
xhtmlNodeDumpOutput ( xmlSaveCtxtPtr ctxt , xmlNodePtr cur ) ;
2004-03-04 16:40:59 +03:00
# endif
2004-03-15 16:46:37 +03:00
static void xmlNodeDumpOutputInternal ( xmlSaveCtxtPtr ctxt , xmlNodePtr cur ) ;
2006-10-17 03:22:10 +04:00
static int xmlDocContentDumpOutput ( xmlSaveCtxtPtr ctxt , xmlDocPtr cur ) ;
2004-03-04 16:40:59 +03:00
2024-07-02 20:14:40 +03:00
static void
2024-07-02 23:43:49 +03:00
xmlSaveWriteIndent ( xmlSaveCtxtPtr ctxt , int extra )
2024-07-02 20:14:40 +03:00
{
2024-07-02 23:43:49 +03:00
int level ;
2024-07-02 20:22:32 +03:00
if ( ( ctxt - > options & XML_SAVE_NO_INDENT ) | |
( ( ( ctxt - > options & XML_SAVE_INDENT ) = = 0 ) & &
( xmlIndentTreeOutput = = 0 ) ) )
2024-07-02 20:14:40 +03:00
return ;
2024-07-02 23:43:49 +03:00
level = ctxt - > level + extra ;
if ( level > ctxt - > indent_nr )
level = ctxt - > indent_nr ;
xmlOutputBufferWrite ( ctxt - > buf , ctxt - > indent_size * level , ctxt - > indent ) ;
2024-07-02 20:14:40 +03:00
}
2010-11-03 17:33:40 +03:00
/**
* xmlOutputBufferWriteWSNonSig :
* @ ctxt : The save context
* @ extra : Number of extra indents to apply to ctxt - > level
*
* Write out formatting for non - significant whitespace output .
*/
static void
xmlOutputBufferWriteWSNonSig ( xmlSaveCtxtPtr ctxt , int extra )
{
int i ;
if ( ( ctxt = = NULL ) | | ( ctxt - > buf = = NULL ) )
return ;
xmlOutputBufferWrite ( ctxt - > buf , 1 , " \n " ) ;
for ( i = 0 ; i < ( ctxt - > level + extra ) ; i + = ctxt - > indent_nr ) {
xmlOutputBufferWrite ( ctxt - > buf , ctxt - > indent_size *
( ( ctxt - > level + extra - i ) > ctxt - > indent_nr ?
ctxt - > indent_nr : ( ctxt - > level + extra - i ) ) ,
ctxt - > indent ) ;
}
}
2004-03-04 16:40:59 +03:00
/**
* xmlNsDumpOutput :
* @ buf : the XML buffer output
* @ cur : a namespace
2010-11-03 17:33:40 +03:00
* @ ctxt : the output save context . Optional .
2004-03-04 16:40:59 +03:00
*
* Dump a local Namespace definition .
* Should be called in the context of attributes dumps .
2010-11-03 17:33:40 +03:00
* If @ ctxt is supplied , @ buf should be its buffer .
2004-03-04 16:40:59 +03:00
*/
static void
2024-07-11 23:06:31 +03:00
xmlNsDumpOutput ( xmlOutputBufferPtr buf , xmlNsPtr cur , xmlSaveCtxtPtr ctxt ) {
unsigned escapeFlags = XML_ESCAPE_ATTR ;
2004-11-05 13:03:46 +03:00
if ( ( cur = = NULL ) | | ( buf = = NULL ) ) return ;
2024-07-11 23:06:31 +03:00
if ( ( ctxt = = NULL ) | | ( ctxt - > encoding = = NULL ) )
escapeFlags | = XML_ESCAPE_NON_ASCII ;
2004-03-04 16:40:59 +03:00
if ( ( cur - > type = = XML_LOCAL_NAMESPACE ) & & ( cur - > href ! = NULL ) ) {
if ( xmlStrEqual ( cur - > prefix , BAD_CAST " xml " ) )
return ;
2010-11-03 17:33:40 +03:00
if ( ctxt ! = NULL & & ctxt - > format = = 2 )
xmlOutputBufferWriteWSNonSig ( ctxt , 2 ) ;
else
xmlOutputBufferWrite ( buf , 1 , " " ) ;
2004-03-04 16:40:59 +03:00
/* Within the context of an element attributes */
if ( cur - > prefix ! = NULL ) {
2010-11-03 17:33:40 +03:00
xmlOutputBufferWrite ( buf , 6 , " xmlns: " ) ;
2004-03-04 16:40:59 +03:00
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > prefix ) ;
} else
2010-11-03 17:33:40 +03:00
xmlOutputBufferWrite ( buf , 5 , " xmlns " ) ;
2024-04-15 12:27:44 +03:00
xmlOutputBufferWrite ( buf , 2 , " = \" " ) ;
2024-07-11 23:06:31 +03:00
xmlSerializeText ( buf , cur - > href , escapeFlags ) ;
2024-04-15 12:27:44 +03:00
xmlOutputBufferWrite ( buf , 1 , " \" " ) ;
2004-03-04 16:40:59 +03:00
}
}
2010-11-03 17:33:40 +03:00
/**
* xmlNsListDumpOutputCtxt
* @ ctxt : the save context
* @ cur : the first namespace
*
* Dump a list of local namespace definitions to a save context .
* Should be called in the context of attribute dumps .
*/
static void
2024-07-11 23:06:31 +03:00
xmlNsListDumpOutputCtxt ( xmlSaveCtxtPtr ctxt , xmlNsPtr cur ) {
2010-11-03 17:33:40 +03:00
while ( cur ! = NULL ) {
2024-07-11 23:06:31 +03:00
xmlNsDumpOutput ( ctxt - > buf , cur , ctxt ) ;
2010-11-03 17:33:40 +03:00
cur = cur - > next ;
}
}
2004-03-04 16:40:59 +03:00
/**
* 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 ) {
2024-07-11 23:06:31 +03:00
xmlNsDumpOutput ( buf , cur , NULL ) ;
2004-03-04 16:40:59 +03:00
cur = cur - > next ;
}
}
/**
* xmlDtdDumpOutput :
* @ buf : the XML buffer output
2004-03-15 16:46:37 +03:00
* @ dtd : the pointer to the DTD
2012-09-11 09:26:36 +04:00
*
2004-03-04 16:40:59 +03:00
* Dump the XML document DTD , if any .
*/
static void
2004-03-15 16:46:37 +03:00
xmlDtdDumpOutput ( xmlSaveCtxtPtr ctxt , xmlDtdPtr dtd ) {
xmlOutputBufferPtr buf ;
2020-07-28 20:07:19 +03:00
xmlNodePtr cur ;
2004-03-15 16:46:37 +03:00
int format , level ;
if ( dtd = = NULL ) return ;
if ( ( ctxt = = NULL ) | | ( ctxt - > buf = = NULL ) )
return ;
buf = ctxt - > buf ;
2004-05-15 20:37:50 +04:00
xmlOutputBufferWrite ( buf , 10 , " <!DOCTYPE " ) ;
2004-03-04 16:40:59 +03:00
xmlOutputBufferWriteString ( buf , ( const char * ) dtd - > name ) ;
if ( dtd - > ExternalID ! = NULL ) {
2004-05-15 20:37:50 +04:00
xmlOutputBufferWrite ( buf , 8 , " PUBLIC " ) ;
2024-02-16 17:42:38 +03:00
xmlOutputBufferWriteQuotedString ( buf , dtd - > ExternalID ) ;
2004-05-15 20:37:50 +04:00
xmlOutputBufferWrite ( buf , 1 , " " ) ;
2024-02-16 17:42:38 +03:00
xmlOutputBufferWriteQuotedString ( buf , dtd - > SystemID ) ;
2004-03-04 16:40:59 +03:00
} else if ( dtd - > SystemID ! = NULL ) {
2004-05-15 20:37:50 +04:00
xmlOutputBufferWrite ( buf , 8 , " SYSTEM " ) ;
2024-02-16 17:42:38 +03:00
xmlOutputBufferWriteQuotedString ( buf , dtd - > SystemID ) ;
2004-03-04 16:40:59 +03:00
}
if ( ( dtd - > entities = = NULL ) & & ( dtd - > elements = = NULL ) & &
2004-09-09 00:55:38 +04:00
( dtd - > attributes = = NULL ) & & ( dtd - > notations = = NULL ) & &
( dtd - > pentities = = NULL ) ) {
2004-05-15 20:37:50 +04:00
xmlOutputBufferWrite ( buf , 1 , " > " ) ;
2004-03-04 16:40:59 +03:00
return ;
}
2004-05-15 20:37:50 +04:00
xmlOutputBufferWrite ( buf , 3 , " [ \n " ) ;
2004-09-09 00:55:38 +04:00
/*
* 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 .
*/
if ( ( dtd - > notations ! = NULL ) & & ( ( dtd - > doc = = NULL ) | |
( dtd - > doc - > intSubset = = dtd ) ) ) {
2023-12-10 19:14:57 +03:00
xmlBufDumpNotationTable ( buf , ( xmlNotationTablePtr ) dtd - > notations ) ;
2004-08-14 15:15:13 +04:00
}
2004-03-15 16:46:37 +03:00
format = ctxt - > format ;
level = ctxt - > level ;
ctxt - > format = 0 ;
ctxt - > level = - 1 ;
2020-07-28 20:07:19 +03:00
for ( cur = dtd - > children ; cur ! = NULL ; cur = cur - > next ) {
xmlNodeDumpOutputInternal ( ctxt , cur ) ;
}
2004-03-15 16:46:37 +03:00
ctxt - > format = format ;
ctxt - > level = level ;
2004-05-15 20:37:50 +04:00
xmlOutputBufferWrite ( buf , 2 , " ]> " ) ;
2004-03-04 16:40:59 +03:00
}
/**
* xmlAttrDumpOutput :
* @ buf : the XML buffer output
* @ cur : the attribute pointer
*
* Dump an XML attribute
*/
static void
2004-03-15 16:46:37 +03:00
xmlAttrDumpOutput ( xmlSaveCtxtPtr ctxt , xmlAttrPtr cur ) {
xmlOutputBufferPtr buf ;
2004-05-15 20:37:50 +04:00
2004-03-15 16:46:37 +03:00
if ( cur = = NULL ) return ;
buf = ctxt - > buf ;
2004-11-05 13:03:46 +03:00
if ( buf = = NULL ) return ;
2010-11-03 17:33:40 +03:00
if ( ctxt - > format = = 2 )
xmlOutputBufferWriteWSNonSig ( ctxt , 2 ) ;
else
xmlOutputBufferWrite ( buf , 1 , " " ) ;
2004-03-04 16:40:59 +03:00
if ( ( cur - > ns ! = NULL ) & & ( cur - > ns - > prefix ! = NULL ) ) {
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > ns - > prefix ) ;
2004-05-15 20:37:50 +04:00
xmlOutputBufferWrite ( buf , 1 , " : " ) ;
2004-03-04 16:40:59 +03:00
}
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > name ) ;
2004-05-15 20:37:50 +04:00
xmlOutputBufferWrite ( buf , 2 , " = \" " ) ;
2023-12-14 15:37:43 +03:00
# ifdef LIBXML_HTML_ENABLED
2023-12-10 19:14:57 +03:00
if ( ( ctxt - > options & XML_SAVE_XHTML ) & &
( cur - > ns = = NULL ) & &
( ( cur - > children = = NULL ) | |
( cur - > children - > content = = NULL ) | |
( cur - > children - > content [ 0 ] = = 0 ) ) & &
( htmlIsBooleanAttr ( cur - > name ) ) ) {
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > name ) ;
2023-12-14 15:37:43 +03:00
} else
# endif
{
2024-07-11 23:06:31 +03:00
xmlSaveWriteAttrContent ( ctxt , cur ) ;
2023-12-10 19:14:57 +03:00
}
2004-05-15 20:37:50 +04:00
xmlOutputBufferWrite ( buf , 1 , " \" " ) ;
2004-03-04 16:40:59 +03:00
}
2008-09-01 17:08:57 +04:00
# ifdef LIBXML_HTML_ENABLED
/**
2020-07-28 20:07:19 +03:00
* htmlNodeDumpOutputInternal :
2008-09-01 17:08:57 +04:00
* @ cur : the current node
*
* Dump an HTML node , recursive behaviour , children are printed too .
*/
static int
htmlNodeDumpOutputInternal ( xmlSaveCtxtPtr ctxt , xmlNodePtr cur ) {
const xmlChar * oldctxtenc = ctxt - > encoding ;
const xmlChar * encoding = ctxt - > encoding ;
xmlOutputBufferPtr buf = ctxt - > buf ;
int switched_encoding = 0 ;
xmlDocPtr doc ;
xmlInitParser ( ) ;
2009-09-02 16:58:13 +04:00
doc = cur - > doc ;
2024-07-11 23:06:31 +03:00
if ( ( encoding = = NULL ) & & ( doc ! = NULL ) )
encoding = doc - > encoding ;
2008-09-01 17:08:57 +04:00
if ( ( encoding ! = NULL ) & & ( doc ! = NULL ) )
htmlSetMetaEncoding ( doc , ( const xmlChar * ) encoding ) ;
if ( ( encoding = = NULL ) & & ( doc ! = NULL ) )
encoding = htmlGetMetaEncoding ( doc ) ;
if ( encoding = = NULL )
encoding = BAD_CAST " HTML " ;
if ( ( encoding ! = NULL ) & & ( oldctxtenc = = NULL ) & &
( buf - > encoder = = NULL ) & & ( buf - > conv = = NULL ) ) {
2024-07-11 23:06:31 +03:00
if ( xmlSaveSwitchEncoding ( ctxt , ( const char * ) encoding ) < 0 )
2008-09-01 17:08:57 +04:00
return ( - 1 ) ;
switched_encoding = 1 ;
}
if ( ctxt - > options & XML_SAVE_FORMAT )
htmlNodeDumpFormatOutput ( buf , doc , cur ,
( const char * ) encoding , 1 ) ;
else
htmlNodeDumpFormatOutput ( buf , doc , cur ,
( const char * ) encoding , 0 ) ;
/*
* Restore the state of the saving context at the end of the document
*/
if ( ( switched_encoding ) & & ( oldctxtenc = = NULL ) ) {
xmlSaveClearEncoding ( ctxt ) ;
}
return ( 0 ) ;
}
# endif
2004-03-04 16:40:59 +03:00
/**
* xmlNodeDumpOutputInternal :
* @ cur : the current node
*
* Dump an XML node , recursive behaviour , children are printed too .
*/
static void
2004-03-15 16:46:37 +03:00
xmlNodeDumpOutputInternal ( xmlSaveCtxtPtr ctxt , xmlNodePtr cur ) {
2020-07-28 20:07:19 +03:00
int format = ctxt - > format ;
2021-05-18 21:08:28 +03:00
xmlNodePtr tmp , root , unformattedNode = NULL , parent ;
2020-07-28 20:07:19 +03:00
xmlAttrPtr attr ;
2004-03-04 16:40:59 +03:00
xmlChar * start , * end ;
2004-03-15 16:46:37 +03:00
xmlOutputBufferPtr buf ;
2004-03-04 16:40:59 +03:00
2004-03-15 16:46:37 +03:00
if ( cur = = NULL ) return ;
buf = ctxt - > buf ;
2020-07-28 20:07:19 +03:00
root = cur ;
2021-05-18 21:08:28 +03:00
parent = cur - > parent ;
2020-07-28 20:07:19 +03:00
while ( 1 ) {
switch ( cur - > type ) {
case XML_DOCUMENT_NODE :
case XML_HTML_DOCUMENT_NODE :
xmlDocContentDumpOutput ( ctxt , ( xmlDocPtr ) cur ) ;
break ;
case XML_DTD_NODE :
xmlDtdDumpOutput ( ctxt , ( xmlDtdPtr ) cur ) ;
break ;
case XML_DOCUMENT_FRAG_NODE :
2021-05-18 21:08:28 +03:00
/* Always validate cur->parent when descending. */
if ( ( cur - > parent = = parent ) & & ( cur - > children ! = NULL ) ) {
parent = cur ;
2020-07-28 20:07:19 +03:00
cur = cur - > children ;
continue ;
}
break ;
case XML_ELEMENT_DECL :
2023-12-10 19:14:57 +03:00
xmlBufDumpElementDecl ( buf , ( xmlElementPtr ) cur ) ;
2020-07-28 20:07:19 +03:00
break ;
case XML_ATTRIBUTE_DECL :
2023-12-10 19:14:57 +03:00
xmlBufDumpAttributeDecl ( buf , ( xmlAttributePtr ) cur ) ;
2020-07-28 20:07:19 +03:00
break ;
case XML_ENTITY_DECL :
2023-12-10 19:14:57 +03:00
xmlBufDumpEntityDecl ( buf , ( xmlEntityPtr ) cur ) ;
2020-07-28 20:07:19 +03:00
break ;
case XML_ELEMENT_NODE :
2024-07-02 20:14:40 +03:00
if ( ( cur ! = root ) & & ( ctxt - > format = = 1 ) )
2024-07-02 23:43:49 +03:00
xmlSaveWriteIndent ( ctxt , 0 ) ;
2021-05-25 11:55:25 +03:00
2021-05-18 21:08:28 +03:00
/*
* Some users like lxml are known to pass nodes with a corrupted
* tree structure . Fall back to a recursive call to handle this
* case .
*/
if ( ( cur - > parent ! = parent ) & & ( cur - > children ! = NULL ) ) {
xmlNodeDumpOutputInternal ( ctxt , cur ) ;
break ;
}
2020-07-28 20:07:19 +03:00
xmlOutputBufferWrite ( buf , 1 , " < " ) ;
if ( ( cur - > ns ! = NULL ) & & ( cur - > ns - > prefix ! = NULL ) ) {
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > ns - > prefix ) ;
xmlOutputBufferWrite ( buf , 1 , " : " ) ;
}
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > name ) ;
if ( cur - > nsDef )
2024-07-11 23:06:31 +03:00
xmlNsListDumpOutputCtxt ( ctxt , cur - > nsDef ) ;
2020-07-28 20:07:19 +03:00
for ( attr = cur - > properties ; attr ! = NULL ; attr = attr - > next )
xmlAttrDumpOutput ( ctxt , attr ) ;
if ( cur - > children = = NULL ) {
if ( ( ctxt - > options & XML_SAVE_NO_EMPTY ) = = 0 ) {
if ( ctxt - > format = = 2 )
xmlOutputBufferWriteWSNonSig ( ctxt , 0 ) ;
xmlOutputBufferWrite ( buf , 2 , " /> " ) ;
} else {
if ( ctxt - > format = = 2 )
xmlOutputBufferWriteWSNonSig ( ctxt , 1 ) ;
xmlOutputBufferWrite ( buf , 3 , " ></ " ) ;
if ( ( cur - > ns ! = NULL ) & & ( cur - > ns - > prefix ! = NULL ) ) {
xmlOutputBufferWriteString ( buf ,
( const char * ) cur - > ns - > prefix ) ;
xmlOutputBufferWrite ( buf , 1 , " : " ) ;
}
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > name ) ;
if ( ctxt - > format = = 2 )
xmlOutputBufferWriteWSNonSig ( ctxt , 0 ) ;
xmlOutputBufferWrite ( buf , 1 , " > " ) ;
}
} else {
if ( ctxt - > format = = 1 ) {
tmp = cur - > children ;
while ( tmp ! = NULL ) {
if ( ( tmp - > type = = XML_TEXT_NODE ) | |
( tmp - > type = = XML_CDATA_SECTION_NODE ) | |
( tmp - > type = = XML_ENTITY_REF_NODE ) ) {
ctxt - > format = 0 ;
unformattedNode = cur ;
break ;
}
tmp = tmp - > next ;
}
}
if ( ctxt - > format = = 2 )
xmlOutputBufferWriteWSNonSig ( ctxt , 1 ) ;
xmlOutputBufferWrite ( buf , 1 , " > " ) ;
if ( ctxt - > format = = 1 ) xmlOutputBufferWrite ( buf , 1 , " \n " ) ;
if ( ctxt - > level > = 0 ) ctxt - > level + + ;
2021-05-18 21:08:28 +03:00
parent = cur ;
2020-07-28 20:07:19 +03:00
cur = cur - > children ;
continue ;
}
break ;
case XML_TEXT_NODE :
if ( cur - > content = = NULL )
break ;
2005-02-11 13:58:55 +03:00
if ( cur - > name ! = xmlStringTextNoenc ) {
2024-07-11 23:06:31 +03:00
if ( ctxt - > escape )
xmlOutputBufferWriteEscape ( buf , cur - > content ,
ctxt - > escape ) ;
# ifdef TEST_OUTPUT_BUFFER_WRITE_ESCAPE
else if ( ctxt - > encoding )
xmlOutputBufferWriteEscape ( buf , cur - > content , NULL ) ;
# endif
else
xmlSaveWriteText ( ctxt , cur - > content , /* flags */ 0 ) ;
2004-03-04 16:40:59 +03:00
} else {
/*
* Disable escaping , needed for XSLT
*/
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > content ) ;
}
2020-07-28 20:07:19 +03:00
break ;
2004-03-04 16:40:59 +03:00
2020-07-28 20:07:19 +03:00
case XML_PI_NODE :
2024-07-02 20:14:40 +03:00
if ( ( cur ! = root ) & & ( ctxt - > format = = 1 ) )
2024-07-02 23:43:49 +03:00
xmlSaveWriteIndent ( ctxt , 0 ) ;
2004-03-04 16:40:59 +03:00
2020-07-28 20:07:19 +03:00
if ( cur - > content ! = NULL ) {
xmlOutputBufferWrite ( buf , 2 , " <? " ) ;
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > name ) ;
if ( cur - > content ! = NULL ) {
if ( ctxt - > format = = 2 )
xmlOutputBufferWriteWSNonSig ( ctxt , 0 ) ;
else
xmlOutputBufferWrite ( buf , 1 , " " ) ;
xmlOutputBufferWriteString ( buf ,
( const char * ) cur - > content ) ;
}
xmlOutputBufferWrite ( buf , 2 , " ?> " ) ;
} else {
xmlOutputBufferWrite ( buf , 2 , " <? " ) ;
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > name ) ;
if ( ctxt - > format = = 2 )
xmlOutputBufferWriteWSNonSig ( ctxt , 0 ) ;
xmlOutputBufferWrite ( buf , 2 , " ?> " ) ;
}
break ;
2004-03-04 16:40:59 +03:00
2020-07-28 20:07:19 +03:00
case XML_COMMENT_NODE :
2024-07-02 20:14:40 +03:00
if ( ( cur ! = root ) & & ( ctxt - > format = = 1 ) )
2024-07-02 23:43:49 +03:00
xmlSaveWriteIndent ( ctxt , 0 ) ;
2004-03-04 16:40:59 +03:00
2020-07-28 20:07:19 +03:00
if ( cur - > content ! = NULL ) {
xmlOutputBufferWrite ( buf , 4 , " <!-- " ) ;
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > content ) ;
xmlOutputBufferWrite ( buf , 3 , " --> " ) ;
}
break ;
case XML_ENTITY_REF_NODE :
xmlOutputBufferWrite ( buf , 1 , " & " ) ;
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > name ) ;
xmlOutputBufferWrite ( buf , 1 , " ; " ) ;
break ;
case XML_CDATA_SECTION_NODE :
if ( cur - > content = = NULL | | * cur - > content = = ' \0 ' ) {
xmlOutputBufferWrite ( buf , 12 , " <![CDATA[]]> " ) ;
} else {
start = end = cur - > content ;
while ( * end ! = ' \0 ' ) {
if ( ( * end = = ' ] ' ) & & ( * ( end + 1 ) = = ' ] ' ) & &
( * ( end + 2 ) = = ' > ' ) ) {
end = end + 2 ;
xmlOutputBufferWrite ( buf , 9 , " <![CDATA[ " ) ;
xmlOutputBufferWrite ( buf , end - start ,
( const char * ) start ) ;
xmlOutputBufferWrite ( buf , 3 , " ]]> " ) ;
start = end ;
}
end + + ;
}
if ( start ! = end ) {
xmlOutputBufferWrite ( buf , 9 , " <![CDATA[ " ) ;
xmlOutputBufferWriteString ( buf , ( const char * ) start ) ;
xmlOutputBufferWrite ( buf , 3 , " ]]> " ) ;
}
}
break ;
case XML_ATTRIBUTE_NODE :
xmlAttrDumpOutput ( ctxt , ( xmlAttrPtr ) cur ) ;
break ;
case XML_NAMESPACE_DECL :
2024-07-11 23:06:31 +03:00
xmlNsDumpOutput ( buf , ( xmlNsPtr ) cur , ctxt ) ;
2020-07-28 20:07:19 +03:00
break ;
default :
break ;
}
while ( 1 ) {
if ( cur = = root )
return ;
2020-08-17 00:38:00 +03:00
if ( ( ctxt - > format = = 1 ) & &
( cur - > type ! = XML_XINCLUDE_START ) & &
( cur - > type ! = XML_XINCLUDE_END ) )
2020-07-28 20:07:19 +03:00
xmlOutputBufferWrite ( buf , 1 , " \n " ) ;
if ( cur - > next ! = NULL ) {
cur = cur - > next ;
break ;
}
2021-05-18 21:08:28 +03:00
cur = parent ;
/* cur->parent was validated when descending. */
parent = cur - > parent ;
2020-07-28 20:07:19 +03:00
2020-07-28 22:52:55 +03:00
if ( cur - > type = = XML_ELEMENT_NODE ) {
2020-07-29 01:39:15 +03:00
if ( ctxt - > level > 0 ) ctxt - > level - - ;
2024-07-02 20:14:40 +03:00
if ( ctxt - > format = = 1 )
2024-07-02 23:43:49 +03:00
xmlSaveWriteIndent ( ctxt , 0 ) ;
2020-07-29 01:39:15 +03:00
2020-07-28 22:52:55 +03:00
xmlOutputBufferWrite ( buf , 2 , " </ " ) ;
if ( ( cur - > ns ! = NULL ) & & ( cur - > ns - > prefix ! = NULL ) ) {
xmlOutputBufferWriteString ( buf ,
( const char * ) cur - > ns - > prefix ) ;
xmlOutputBufferWrite ( buf , 1 , " : " ) ;
}
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > name ) ;
if ( ctxt - > format = = 2 )
xmlOutputBufferWriteWSNonSig ( ctxt , 0 ) ;
xmlOutputBufferWrite ( buf , 1 , " > " ) ;
2020-07-29 01:39:15 +03:00
if ( cur = = unformattedNode ) {
ctxt - > format = format ;
unformattedNode = NULL ;
}
2020-07-28 20:07:19 +03:00
}
}
}
2004-03-04 16:40:59 +03:00
}
/**
* xmlDocContentDumpOutput :
* @ cur : the document
*
* Dump an XML document .
*/
2006-10-17 03:22:10 +04:00
static int
2004-03-15 16:46:37 +03:00
xmlDocContentDumpOutput ( xmlSaveCtxtPtr ctxt , xmlDocPtr cur ) {
2004-03-04 16:40:59 +03:00
# ifdef LIBXML_HTML_ENABLED
xmlDtdPtr dtd ;
int is_xhtml = 0 ;
# endif
2006-10-17 03:22:10 +04:00
const xmlChar * oldctxtenc = ctxt - > encoding ;
2004-03-15 16:46:37 +03:00
const xmlChar * encoding = ctxt - > encoding ;
2006-10-17 03:22:10 +04:00
xmlOutputBufferPtr buf = ctxt - > buf ;
xmlCharEncoding enc ;
2008-09-01 17:08:57 +04:00
int switched_encoding = 0 ;
2004-03-04 16:40:59 +03:00
xmlInitParser ( ) ;
2008-09-01 17:08:57 +04:00
if ( ( cur - > type ! = XML_HTML_DOCUMENT_NODE ) & &
( cur - > type ! = XML_DOCUMENT_NODE ) )
return ( - 1 ) ;
2024-07-11 23:06:31 +03:00
if ( ctxt - > encoding = = NULL )
2006-10-17 03:22:10 +04:00
encoding = cur - > encoding ;
2004-03-04 16:40:59 +03:00
2008-09-25 18:31:40 +04:00
if ( ( ( cur - > type = = XML_HTML_DOCUMENT_NODE ) & &
( ( ctxt - > options & XML_SAVE_AS_XML ) = = 0 ) & &
( ( ctxt - > options & XML_SAVE_XHTML ) = = 0 ) ) | |
( ctxt - > options & XML_SAVE_AS_HTML ) ) {
2008-09-01 17:08:57 +04:00
# ifdef LIBXML_HTML_ENABLED
if ( encoding ! = NULL )
htmlSetMetaEncoding ( cur , ( const xmlChar * ) encoding ) ;
if ( encoding = = NULL )
encoding = htmlGetMetaEncoding ( cur ) ;
if ( encoding = = NULL )
encoding = BAD_CAST " HTML " ;
if ( ( encoding ! = NULL ) & & ( oldctxtenc = = NULL ) & &
( buf - > encoder = = NULL ) & & ( buf - > conv = = NULL ) ) {
if ( xmlSaveSwitchEncoding ( ctxt , ( const char * ) encoding ) < 0 ) {
2006-10-17 03:22:10 +04:00
return ( - 1 ) ;
}
2008-09-01 17:08:57 +04:00
}
if ( ctxt - > options & XML_SAVE_FORMAT )
htmlDocContentDumpFormatOutput ( buf , cur ,
( const char * ) encoding , 1 ) ;
else
htmlDocContentDumpFormatOutput ( buf , cur ,
( const char * ) encoding , 0 ) ;
return ( 0 ) ;
# else
return ( - 1 ) ;
# endif
2008-09-25 18:31:40 +04:00
} else if ( ( cur - > type = = XML_DOCUMENT_NODE ) | |
( ctxt - > options & XML_SAVE_AS_XML ) | |
( ctxt - > options & XML_SAVE_XHTML ) ) {
2008-09-01 17:08:57 +04:00
enc = xmlParseCharEncoding ( ( const char * ) encoding ) ;
if ( ( encoding ! = NULL ) & & ( oldctxtenc = = NULL ) & &
( buf - > encoder = = NULL ) & & ( buf - > conv = = NULL ) & &
( ( ctxt - > options & XML_SAVE_NO_DECL ) = = 0 ) ) {
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 .
*/
2024-07-11 23:06:31 +03:00
if ( xmlSaveSwitchEncoding ( ctxt , ( const char * ) encoding ) < 0 )
2008-09-01 17:08:57 +04:00
return ( - 1 ) ;
switched_encoding = 1 ;
2006-10-17 03:22:10 +04:00
}
}
2008-09-01 17:08:57 +04:00
/*
* Save the XML declaration
*/
if ( ( ctxt - > options & XML_SAVE_NO_DECL ) = = 0 ) {
xmlOutputBufferWrite ( buf , 14 , " <?xml version= " ) ;
2012-09-11 09:26:36 +04:00
if ( cur - > version ! = NULL )
2024-02-16 17:42:38 +03:00
xmlOutputBufferWriteQuotedString ( buf , cur - > version ) ;
2008-09-01 17:08:57 +04:00
else
xmlOutputBufferWrite ( buf , 5 , " \" 1.0 \" " ) ;
if ( encoding ! = NULL ) {
xmlOutputBufferWrite ( buf , 10 , " encoding= " ) ;
2024-02-16 17:42:38 +03:00
xmlOutputBufferWriteQuotedString ( buf , ( xmlChar * ) encoding ) ;
2008-09-01 17:08:57 +04:00
}
switch ( cur - > standalone ) {
case 0 :
xmlOutputBufferWrite ( buf , 16 , " standalone= \" no \" " ) ;
break ;
case 1 :
xmlOutputBufferWrite ( buf , 17 , " standalone= \" yes \" " ) ;
break ;
}
xmlOutputBufferWrite ( buf , 3 , " ?> \n " ) ;
2005-08-08 18:44:11 +04:00
}
2004-03-04 16:40:59 +03:00
# ifdef LIBXML_HTML_ENABLED
2008-09-25 18:31:40 +04:00
if ( ctxt - > options & XML_SAVE_XHTML )
is_xhtml = 1 ;
2008-09-01 17:08:57 +04:00
if ( ( ctxt - > options & XML_SAVE_NO_XHTML ) = = 0 ) {
dtd = xmlGetIntSubset ( cur ) ;
if ( dtd ! = NULL ) {
is_xhtml = xmlIsXHTML ( dtd - > SystemID , dtd - > ExternalID ) ;
if ( is_xhtml < 0 ) is_xhtml = 0 ;
}
2005-09-13 01:43:20 +04:00
}
2004-03-04 16:40:59 +03:00
# endif
2008-09-01 17:08:57 +04:00
if ( cur - > children ! = NULL ) {
xmlNodePtr child = cur - > children ;
2004-03-04 16:40:59 +03:00
2008-09-01 17:08:57 +04:00
while ( child ! = NULL ) {
ctxt - > level = 0 ;
2004-03-04 16:40:59 +03:00
# ifdef LIBXML_HTML_ENABLED
2008-09-01 17:08:57 +04:00
if ( is_xhtml )
xhtmlNodeDumpOutput ( ctxt , child ) ;
else
2004-03-04 16:40:59 +03:00
# endif
2008-09-01 17:08:57 +04:00
xmlNodeDumpOutputInternal ( ctxt , child ) ;
2020-08-17 00:38:00 +03:00
if ( ( child - > type ! = XML_XINCLUDE_START ) & &
( child - > type ! = XML_XINCLUDE_END ) )
xmlOutputBufferWrite ( buf , 1 , " \n " ) ;
2008-09-01 17:08:57 +04:00
child = child - > next ;
}
2004-03-04 16:40:59 +03:00
}
}
2008-09-01 17:08:57 +04:00
2006-10-17 03:22:10 +04:00
/*
* Restore the state of the saving context at the end of the document
*/
2008-09-01 17:08:57 +04:00
if ( ( switched_encoding ) & & ( oldctxtenc = = NULL ) ) {
xmlSaveClearEncoding ( ctxt ) ;
2006-10-17 03:22:10 +04:00
}
return ( 0 ) ;
2004-03-04 16:40:59 +03:00
}
# 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 ) ;
2024-03-17 21:24:06 +03:00
switch ( node - > name ? node - > name [ 0 ] : 0 ) {
2004-03-04 16:40:59 +03:00
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 :
* @ cur : the first attribute pointer
*
* Dump a list of XML attributes
*/
static void
2004-03-15 16:46:37 +03:00
xhtmlAttrListDumpOutput ( xmlSaveCtxtPtr ctxt , xmlAttrPtr cur ) {
2004-03-04 16:40:59 +03:00
xmlAttrPtr xml_lang = NULL ;
xmlAttrPtr lang = NULL ;
xmlAttrPtr name = NULL ;
xmlAttrPtr id = NULL ;
xmlNodePtr parent ;
2004-03-15 16:46:37 +03:00
xmlOutputBufferPtr buf ;
2004-03-04 16:40:59 +03:00
2004-03-15 16:46:37 +03:00
if ( cur = = NULL ) return ;
buf = ctxt - > buf ;
2004-03-04 16:40:59 +03:00
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 ;
2004-03-15 16:46:37 +03:00
xmlAttrDumpOutput ( ctxt , cur ) ;
2004-03-04 16:40:59 +03:00
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 " ) ) ) ) {
2004-05-15 20:37:50 +04:00
xmlOutputBufferWrite ( buf , 5 , " id= \" " ) ;
2024-07-11 23:06:31 +03:00
xmlSaveWriteAttrContent ( ctxt , name ) ;
2004-05-15 20:37:50 +04:00
xmlOutputBufferWrite ( buf , 1 , " \" " ) ;
2004-03-04 16:40:59 +03:00
}
}
/*
* C .7 .
*/
if ( ( lang ! = NULL ) & & ( xml_lang = = NULL ) ) {
2004-05-15 20:37:50 +04:00
xmlOutputBufferWrite ( buf , 11 , " xml:lang= \" " ) ;
2024-07-11 23:06:31 +03:00
xmlSaveWriteAttrContent ( ctxt , lang ) ;
2004-05-15 20:37:50 +04:00
xmlOutputBufferWrite ( buf , 1 , " \" " ) ;
2012-09-11 09:26:36 +04:00
} else
2004-03-04 16:40:59 +03:00
if ( ( xml_lang ! = NULL ) & & ( lang = = NULL ) ) {
2004-05-15 20:37:50 +04:00
xmlOutputBufferWrite ( buf , 7 , " lang= \" " ) ;
2024-07-11 23:06:31 +03:00
xmlSaveWriteAttrContent ( ctxt , xml_lang ) ;
2004-05-15 20:37:50 +04:00
xmlOutputBufferWrite ( buf , 1 , " \" " ) ;
2004-03-04 16:40:59 +03:00
}
}
/**
* 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
2004-03-15 16:46:37 +03:00
xhtmlNodeDumpOutput ( xmlSaveCtxtPtr ctxt , xmlNodePtr cur ) {
2023-12-10 19:14:57 +03:00
int format = ctxt - > format , addmeta , oldoptions ;
2024-04-02 15:41:15 +03:00
xmlNodePtr tmp , root , unformattedNode = NULL , parent ;
2004-03-04 16:40:59 +03:00
xmlChar * start , * end ;
2020-07-28 19:33:50 +03:00
xmlOutputBufferPtr buf = ctxt - > buf ;
2004-03-04 16:40:59 +03:00
2004-03-15 16:46:37 +03:00
if ( cur = = NULL ) return ;
2020-07-28 19:33:50 +03:00
2023-12-10 19:14:57 +03:00
oldoptions = ctxt - > options ;
ctxt - > options | = XML_SAVE_XHTML ;
2020-07-28 19:33:50 +03:00
root = cur ;
2024-04-02 15:41:15 +03:00
parent = cur - > parent ;
2020-07-28 19:33:50 +03:00
while ( 1 ) {
switch ( cur - > type ) {
case XML_DOCUMENT_NODE :
case XML_HTML_DOCUMENT_NODE :
xmlDocContentDumpOutput ( ctxt , ( xmlDocPtr ) cur ) ;
break ;
case XML_NAMESPACE_DECL :
2024-07-11 23:06:31 +03:00
xmlNsDumpOutput ( buf , ( xmlNsPtr ) cur , ctxt ) ;
2020-07-28 19:33:50 +03:00
break ;
case XML_DTD_NODE :
xmlDtdDumpOutput ( ctxt , ( xmlDtdPtr ) cur ) ;
break ;
case XML_DOCUMENT_FRAG_NODE :
2024-04-02 15:41:15 +03:00
/* Always validate cur->parent when descending. */
if ( ( cur - > parent = = parent ) & & ( cur - > children ! = NULL ) ) {
parent = cur ;
2020-07-28 19:33:50 +03:00
cur = cur - > children ;
continue ;
}
break ;
case XML_ELEMENT_DECL :
2023-12-10 19:14:57 +03:00
xmlBufDumpElementDecl ( buf , ( xmlElementPtr ) cur ) ;
2020-07-28 19:33:50 +03:00
break ;
case XML_ATTRIBUTE_DECL :
2023-12-10 19:14:57 +03:00
xmlBufDumpAttributeDecl ( buf , ( xmlAttributePtr ) cur ) ;
2020-07-28 19:33:50 +03:00
break ;
case XML_ENTITY_DECL :
2023-12-10 19:14:57 +03:00
xmlBufDumpEntityDecl ( buf , ( xmlEntityPtr ) cur ) ;
2020-07-28 19:33:50 +03:00
break ;
case XML_ELEMENT_NODE :
addmeta = 0 ;
2024-07-02 20:14:40 +03:00
if ( ( cur ! = root ) & & ( ctxt - > format = = 1 ) )
2024-07-02 23:43:49 +03:00
xmlSaveWriteIndent ( ctxt , 0 ) ;
2020-07-28 19:33:50 +03:00
2024-04-02 15:41:15 +03:00
/*
* Some users like lxml are known to pass nodes with a corrupted
* tree structure . Fall back to a recursive call to handle this
* case .
*/
if ( ( cur - > parent ! = parent ) & & ( cur - > children ! = NULL ) ) {
xhtmlNodeDumpOutput ( ctxt , cur ) ;
break ;
}
2020-07-28 19:33:50 +03:00
xmlOutputBufferWrite ( buf , 1 , " < " ) ;
if ( ( cur - > ns ! = NULL ) & & ( cur - > ns - > prefix ! = NULL ) ) {
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > ns - > prefix ) ;
xmlOutputBufferWrite ( buf , 1 , " : " ) ;
}
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > name ) ;
if ( cur - > nsDef )
2024-07-11 23:06:31 +03:00
xmlNsListDumpOutputCtxt ( ctxt , cur - > nsDef ) ;
2020-07-28 19:33:50 +03:00
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 ( ctxt , cur - > properties ) ;
2024-04-02 15:41:15 +03:00
if ( ( parent ! = NULL ) & &
( parent - > parent = = ( xmlNodePtr ) cur - > doc ) & &
2020-07-28 19:33:50 +03:00
xmlStrEqual ( cur - > name , BAD_CAST " head " ) & &
2024-04-02 15:41:15 +03:00
xmlStrEqual ( parent - > name , BAD_CAST " html " ) ) {
2020-07-28 19:33:50 +03:00
tmp = cur - > children ;
while ( tmp ! = NULL ) {
if ( xmlStrEqual ( tmp - > name , BAD_CAST " meta " ) ) {
xmlChar * httpequiv ;
httpequiv = xmlGetProp ( tmp , BAD_CAST " http-equiv " ) ;
if ( httpequiv ! = NULL ) {
if ( xmlStrcasecmp ( httpequiv ,
BAD_CAST " Content-Type " ) = = 0 ) {
xmlFree ( httpequiv ) ;
break ;
}
xmlFree ( httpequiv ) ;
}
}
tmp = tmp - > next ;
}
if ( tmp = = NULL )
addmeta = 1 ;
}
if ( cur - > children = = NULL ) {
if ( ( ( cur - > ns = = NULL ) | | ( cur - > ns - > prefix = = NULL ) ) & &
( ( xhtmlIsEmpty ( cur ) = = 1 ) & & ( addmeta = = 0 ) ) ) {
/*
* C .2 . Empty Elements
*/
xmlOutputBufferWrite ( buf , 3 , " /> " ) ;
} else {
if ( addmeta = = 1 ) {
xmlOutputBufferWrite ( buf , 1 , " > " ) ;
if ( ctxt - > format = = 1 ) {
xmlOutputBufferWrite ( buf , 1 , " \n " ) ;
2024-07-02 23:43:49 +03:00
xmlSaveWriteIndent ( ctxt , 1 ) ;
2020-07-28 19:33:50 +03:00
}
xmlOutputBufferWriteString ( buf ,
" <meta http-equiv= \" Content-Type \" "
" content= \" text/html; charset= " ) ;
if ( ctxt - > encoding ) {
xmlOutputBufferWriteString ( buf ,
( const char * ) ctxt - > encoding ) ;
} else {
xmlOutputBufferWrite ( buf , 5 , " UTF-8 " ) ;
}
xmlOutputBufferWrite ( buf , 4 , " \" /> " ) ;
if ( ctxt - > format = = 1 )
xmlOutputBufferWrite ( buf , 1 , " \n " ) ;
} else {
xmlOutputBufferWrite ( buf , 1 , " > " ) ;
}
/*
* C .3 . Element Minimization and Empty Element Content
*/
xmlOutputBufferWrite ( buf , 2 , " </ " ) ;
if ( ( cur - > ns ! = NULL ) & & ( cur - > ns - > prefix ! = NULL ) ) {
xmlOutputBufferWriteString ( buf ,
( const char * ) cur - > ns - > prefix ) ;
xmlOutputBufferWrite ( buf , 1 , " : " ) ;
}
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > name ) ;
xmlOutputBufferWrite ( buf , 1 , " > " ) ;
}
} else {
xmlOutputBufferWrite ( buf , 1 , " > " ) ;
if ( addmeta = = 1 ) {
if ( ctxt - > format = = 1 ) {
xmlOutputBufferWrite ( buf , 1 , " \n " ) ;
2024-07-02 23:43:49 +03:00
xmlSaveWriteIndent ( ctxt , 1 ) ;
2020-07-28 19:33:50 +03:00
}
xmlOutputBufferWriteString ( buf ,
" <meta http-equiv= \" Content-Type \" "
" content= \" text/html; charset= " ) ;
if ( ctxt - > encoding ) {
xmlOutputBufferWriteString ( buf ,
( const char * ) ctxt - > encoding ) ;
} else {
xmlOutputBufferWrite ( buf , 5 , " UTF-8 " ) ;
}
xmlOutputBufferWrite ( buf , 4 , " \" /> " ) ;
}
if ( ctxt - > format = = 1 ) {
tmp = cur - > children ;
while ( tmp ! = NULL ) {
if ( ( tmp - > type = = XML_TEXT_NODE ) | |
( tmp - > type = = XML_ENTITY_REF_NODE ) ) {
unformattedNode = cur ;
ctxt - > format = 0 ;
break ;
}
tmp = tmp - > next ;
}
}
if ( ctxt - > format = = 1 ) xmlOutputBufferWrite ( buf , 1 , " \n " ) ;
if ( ctxt - > level > = 0 ) ctxt - > level + + ;
2024-04-02 15:41:15 +03:00
parent = cur ;
2020-07-28 19:33:50 +03:00
cur = cur - > children ;
continue ;
}
break ;
case XML_TEXT_NODE :
if ( cur - > content = = NULL )
break ;
2004-03-04 16:40:59 +03:00
if ( ( cur - > name = = xmlStringText ) | |
( cur - > name ! = xmlStringTextNoenc ) ) {
2024-07-11 23:06:31 +03:00
if ( ctxt - > escape )
xmlOutputBufferWriteEscape ( buf , cur - > content ,
ctxt - > escape ) ;
else
xmlSaveWriteText ( ctxt , cur - > content , /* flags */ 0 ) ;
2004-03-04 16:40:59 +03:00
} else {
/*
* Disable escaping , needed for XSLT
*/
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > content ) ;
}
2020-07-28 19:33:50 +03:00
break ;
2004-03-04 16:40:59 +03:00
2020-07-28 19:33:50 +03:00
case XML_PI_NODE :
if ( cur - > content ! = NULL ) {
xmlOutputBufferWrite ( buf , 2 , " <? " ) ;
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > name ) ;
if ( cur - > content ! = NULL ) {
xmlOutputBufferWrite ( buf , 1 , " " ) ;
xmlOutputBufferWriteString ( buf ,
( const char * ) cur - > content ) ;
}
xmlOutputBufferWrite ( buf , 2 , " ?> " ) ;
} else {
xmlOutputBufferWrite ( buf , 2 , " <? " ) ;
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > name ) ;
xmlOutputBufferWrite ( buf , 2 , " ?> " ) ;
}
break ;
2004-03-04 16:40:59 +03:00
2020-07-28 19:33:50 +03:00
case XML_COMMENT_NODE :
if ( cur - > content ! = NULL ) {
xmlOutputBufferWrite ( buf , 4 , " <!-- " ) ;
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > content ) ;
xmlOutputBufferWrite ( buf , 3 , " --> " ) ;
}
break ;
case XML_ENTITY_REF_NODE :
xmlOutputBufferWrite ( buf , 1 , " & " ) ;
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > name ) ;
xmlOutputBufferWrite ( buf , 1 , " ; " ) ;
break ;
case XML_CDATA_SECTION_NODE :
if ( cur - > content = = NULL | | * cur - > content = = ' \0 ' ) {
xmlOutputBufferWrite ( buf , 12 , " <![CDATA[]]> " ) ;
} else {
start = end = cur - > content ;
while ( * end ! = ' \0 ' ) {
if ( * end = = ' ] ' & & * ( end + 1 ) = = ' ] ' & &
* ( end + 2 ) = = ' > ' ) {
end = end + 2 ;
xmlOutputBufferWrite ( buf , 9 , " <![CDATA[ " ) ;
xmlOutputBufferWrite ( buf , end - start ,
( const char * ) start ) ;
xmlOutputBufferWrite ( buf , 3 , " ]]> " ) ;
start = end ;
2017-11-13 23:13:46 +03:00
}
2020-07-28 19:33:50 +03:00
end + + ;
}
if ( start ! = end ) {
xmlOutputBufferWrite ( buf , 9 , " <![CDATA[ " ) ;
xmlOutputBufferWriteString ( buf , ( const char * ) start ) ;
xmlOutputBufferWrite ( buf , 3 , " ]]> " ) ;
2017-11-13 23:13:46 +03:00
}
}
2020-07-28 19:33:50 +03:00
break ;
2005-08-26 19:33:26 +04:00
2020-07-28 19:33:50 +03:00
case XML_ATTRIBUTE_NODE :
xmlAttrDumpOutput ( ctxt , ( xmlAttrPtr ) cur ) ;
break ;
2004-03-04 16:40:59 +03:00
2020-07-28 19:33:50 +03:00
default :
break ;
}
2004-03-15 16:46:37 +03:00
2020-07-28 19:33:50 +03:00
while ( 1 ) {
if ( cur = = root )
return ;
2020-07-28 22:52:55 +03:00
if ( ctxt - > format = = 1 )
2020-07-28 19:33:50 +03:00
xmlOutputBufferWrite ( buf , 1 , " \n " ) ;
if ( cur - > next ! = NULL ) {
cur = cur - > next ;
break ;
}
2006-07-13 17:07:11 +04:00
2024-04-02 15:41:15 +03:00
cur = parent ;
/* cur->parent was validated when descending. */
parent = cur - > parent ;
2020-07-28 19:33:50 +03:00
2020-07-28 22:52:55 +03:00
if ( cur - > type = = XML_ELEMENT_NODE ) {
2020-07-29 01:39:15 +03:00
if ( ctxt - > level > 0 ) ctxt - > level - - ;
2024-07-02 20:14:40 +03:00
if ( ctxt - > format = = 1 )
2024-07-02 23:43:49 +03:00
xmlSaveWriteIndent ( ctxt , 0 ) ;
2020-07-29 01:39:15 +03:00
2020-07-28 22:52:55 +03:00
xmlOutputBufferWrite ( buf , 2 , " </ " ) ;
if ( ( cur - > ns ! = NULL ) & & ( cur - > ns - > prefix ! = NULL ) ) {
xmlOutputBufferWriteString ( buf ,
( const char * ) cur - > ns - > prefix ) ;
xmlOutputBufferWrite ( buf , 1 , " : " ) ;
}
xmlOutputBufferWriteString ( buf , ( const char * ) cur - > name ) ;
xmlOutputBufferWrite ( buf , 1 , " > " ) ;
2020-07-29 01:39:15 +03:00
if ( cur = = unformattedNode ) {
ctxt - > format = format ;
unformattedNode = NULL ;
}
2020-07-28 19:33:50 +03:00
}
}
}
2023-12-10 19:14:57 +03:00
ctxt - > options = oldoptions ;
2004-03-04 16:40:59 +03:00
}
# 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 ) ;
2004-03-15 16:46:37 +03:00
ret - > buf = xmlOutputBufferCreateFd ( fd , ret - > handler ) ;
if ( ret - > buf = = NULL ) {
2004-03-04 16:40:59 +03:00
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 ) ;
2004-03-15 16:46:37 +03:00
ret - > buf = xmlOutputBufferCreateFilename ( filename , ret - > handler ,
2004-03-04 16:40:59 +03:00
compression ) ;
2004-03-15 16:46:37 +03:00
if ( ret - > buf = = NULL ) {
2004-03-04 16:40:59 +03:00
xmlFreeSaveCtxt ( ret ) ;
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 .
2005-11-09 11:56:26 +03:00
*/
2004-03-04 16:40:59 +03:00
xmlSaveCtxtPtr
xmlSaveToBuffer ( xmlBufferPtr buffer , const char * encoding , int options )
{
2005-11-09 11:56:26 +03:00
xmlSaveCtxtPtr ret ;
ret = xmlNewSaveCtxt ( encoding , options ) ;
if ( ret = = NULL ) return ( NULL ) ;
2019-11-11 15:49:11 +03:00
ret - > buf = xmlOutputBufferCreateBuffer ( buffer , ret - > handler ) ;
if ( ret - > buf = = NULL ) {
xmlFreeSaveCtxt ( ret ) ;
return ( NULL ) ;
2005-11-09 11:56:26 +03:00
}
return ( ret ) ;
2004-03-04 16:40:59 +03:00
}
/**
* 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 ) ;
2004-03-15 16:46:37 +03:00
ret - > buf = xmlOutputBufferCreateIO ( iowrite , ioclose , ioctx , ret - > handler ) ;
if ( ret - > buf = = NULL ) {
2004-03-04 16:40:59 +03:00
xmlFreeSaveCtxt ( ret ) ;
return ( NULL ) ;
}
return ( ret ) ;
}
/**
* xmlSaveDoc :
* @ ctxt : a document saving context
* @ doc : a document
*
* Save a full document to a saving context
2004-04-16 20:30:05 +04:00
* TODO : The function is not fully implemented yet as it does not return the
* byte count but 0 instead
2004-03-04 16:40:59 +03:00
*
* Returns the number of byte written or - 1 in case of error
*/
long
xmlSaveDoc ( xmlSaveCtxtPtr ctxt , xmlDocPtr doc )
{
2004-03-15 16:46:37 +03:00
long ret = 0 ;
2004-11-05 20:22:25 +03:00
if ( ( ctxt = = NULL ) | | ( doc = = NULL ) ) return ( - 1 ) ;
2006-10-17 03:22:10 +04:00
if ( xmlDocContentDumpOutput ( ctxt , doc ) < 0 )
return ( - 1 ) ;
2004-03-15 16:46:37 +03:00
return ( ret ) ;
2004-03-04 16:40:59 +03:00
}
/**
* xmlSaveTree :
* @ ctxt : a document saving context
2023-09-21 23:57:33 +03:00
* @ cur : the top node of the subtree to save
2004-03-04 16:40:59 +03:00
*
* Save a subtree starting at the node parameter to a saving context
2004-04-16 20:30:05 +04:00
* TODO : The function is not fully implemented yet as it does not return the
* byte count but 0 instead
2004-03-04 16:40:59 +03:00
*
* Returns the number of byte written or - 1 in case of error
*/
long
2020-07-28 20:07:19 +03:00
xmlSaveTree ( xmlSaveCtxtPtr ctxt , xmlNodePtr cur )
2004-03-04 16:40:59 +03:00
{
2004-03-15 16:46:37 +03:00
long ret = 0 ;
2020-07-28 20:07:19 +03:00
if ( ( ctxt = = NULL ) | | ( cur = = NULL ) ) return ( - 1 ) ;
# ifdef LIBXML_HTML_ENABLED
if ( ctxt - > options & XML_SAVE_XHTML ) {
xhtmlNodeDumpOutput ( ctxt , cur ) ;
return ( ret ) ;
}
if ( ( ( cur - > type ! = XML_NAMESPACE_DECL ) & & ( cur - > doc ! = NULL ) & &
( cur - > doc - > type = = XML_HTML_DOCUMENT_NODE ) & &
( ( ctxt - > options & XML_SAVE_AS_XML ) = = 0 ) ) | |
( ctxt - > options & XML_SAVE_AS_HTML ) ) {
htmlNodeDumpOutputInternal ( ctxt , cur ) ;
return ( ret ) ;
}
# endif
xmlNodeDumpOutputInternal ( ctxt , cur ) ;
2004-03-15 16:46:37 +03:00
return ( ret ) ;
2004-03-04 16:40:59 +03:00
}
2024-05-20 14:58:22 +03:00
/**
* xmlSaveNotationDecl :
* @ ctxt : save context
* @ cur : notation
*
* Serialize a notation declaration .
*
* Return 0 on succes , - 1 on error .
*/
2024-02-01 21:01:57 +03:00
int
xmlSaveNotationDecl ( xmlSaveCtxtPtr ctxt , xmlNotationPtr cur ) {
2024-03-04 03:31:12 +03:00
if ( ctxt = = NULL )
return ( - 1 ) ;
2024-02-01 21:01:57 +03:00
xmlBufDumpNotationDecl ( ctxt - > buf , cur ) ;
return ( 0 ) ;
}
2024-05-20 14:58:22 +03:00
/**
* xmlSaveNotationTable :
* @ ctxt : save context
* @ cur : notation table
*
* Serialize notation declarations of a document .
*
* Return 0 on succes , - 1 on error .
*/
2024-02-01 21:01:57 +03:00
int
xmlSaveNotationTable ( xmlSaveCtxtPtr ctxt , xmlNotationTablePtr cur ) {
2024-03-04 03:31:12 +03:00
if ( ctxt = = NULL )
return ( - 1 ) ;
2024-02-01 21:01:57 +03:00
xmlBufDumpNotationTable ( ctxt - > buf , cur ) ;
return ( 0 ) ;
}
2004-03-04 16:40:59 +03:00
/**
* 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 ) ;
2004-03-15 16:46:37 +03:00
if ( ctxt - > buf = = NULL ) return ( - 1 ) ;
return ( xmlOutputBufferFlush ( ctxt - > buf ) ) ;
2004-03-04 16:40:59 +03:00
}
/**
* 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 ) ;
}
2023-12-10 19:14:57 +03:00
/**
* xmlSaveFinish :
* @ 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 .
*
2024-05-20 14:58:22 +03:00
* Available since 2.13 .0 .
*
2023-12-10 19:14:57 +03:00
* Returns an xmlParserErrors code .
*/
int
xmlSaveFinish ( xmlSaveCtxtPtr ctxt )
{
int ret ;
if ( ctxt = = NULL )
return ( XML_ERR_INTERNAL_ERROR ) ;
xmlSaveFlush ( ctxt ) ;
ret = ctxt - > buf - > error ;
xmlFreeSaveCtxt ( ctxt ) ;
return ( ret ) ;
}
2004-05-15 22:57:31 +04:00
/**
* xmlSaveSetEscape :
* @ ctxt : a document saving context
* @ escape : the escaping function
*
2024-07-11 21:23:49 +03:00
* DEPRECATED : Don ' t use .
*
2004-05-15 22:57:31 +04:00
* Set a custom escaping function to be used for text in element content
*
* Returns 0 if successful or - 1 in case of error .
*/
int
xmlSaveSetEscape ( xmlSaveCtxtPtr ctxt , xmlCharEncodingOutputFunc escape )
{
if ( ctxt = = NULL ) return ( - 1 ) ;
ctxt - > escape = escape ;
return ( 0 ) ;
}
/**
* xmlSaveSetAttrEscape :
* @ ctxt : a document saving context
* @ escape : the escaping function
*
2024-07-11 21:23:49 +03:00
* DEPRECATED : Don ' t use .
*
* Has no effect .
2004-05-15 22:57:31 +04:00
*
* Returns 0 if successful or - 1 in case of error .
*/
int
2024-07-11 21:23:49 +03:00
xmlSaveSetAttrEscape ( xmlSaveCtxtPtr ctxt ,
xmlCharEncodingOutputFunc escape ATTRIBUTE_UNUSED )
2004-05-15 22:57:31 +04:00
{
if ( ctxt = = NULL ) return ( - 1 ) ;
return ( 0 ) ;
}
2004-03-04 16:40:59 +03:00
/************************************************************************
* *
* Public entry points based on buffers *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-07-16 10:52:00 +04:00
2004-03-04 16:40:59 +03:00
/**
2012-07-16 10:52:00 +04:00
* xmlBufAttrSerializeTxtContent :
2024-02-16 17:42:38 +03:00
* @ buf : output buffer
2004-03-04 16:40:59 +03:00
* @ doc : the document
* @ string : the text content
*
2012-07-16 10:52:00 +04:00
* Serialize text attribute values to an xmlBufPtr
2004-03-04 16:40:59 +03:00
*/
void
2024-02-16 17:42:38 +03:00
xmlBufAttrSerializeTxtContent ( xmlOutputBufferPtr buf , xmlDocPtr doc ,
const xmlChar * string )
2004-05-15 20:37:50 +04:00
{
2024-07-11 23:06:31 +03:00
int flags = XML_ESCAPE_ATTR ;
2024-01-02 16:04:44 +03:00
2024-07-11 23:06:31 +03:00
if ( ( doc = = NULL ) | | ( doc - > encoding = = NULL ) )
flags | = XML_ESCAPE_NON_ASCII ;
xmlSerializeText ( buf , string , flags ) ;
2012-07-16 10:52:00 +04:00
}
/**
* 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 ,
2024-02-16 17:42:38 +03:00
xmlAttrPtr attr ATTRIBUTE_UNUSED ,
const xmlChar * string )
2012-07-16 10:52:00 +04:00
{
2024-02-16 17:42:38 +03:00
xmlOutputBufferPtr out ;
2012-07-16 10:52:00 +04:00
if ( ( buf = = NULL ) | | ( string = = NULL ) )
return ;
2024-02-16 17:42:38 +03:00
out = xmlOutputBufferCreateBuffer ( buf , NULL ) ;
xmlBufAttrSerializeTxtContent ( out , doc , string ) ;
2024-04-09 16:39:06 +03:00
xmlOutputBufferFlush ( out ) ;
2024-03-05 22:00:44 +03:00
if ( ( out = = NULL ) | | ( out - > error ) )
xmlFree ( xmlBufferDetach ( buf ) ) ;
2024-02-16 17:42:38 +03:00
xmlOutputBufferClose ( out ) ;
2004-03-04 16:40:59 +03:00
}
/**
* 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
Doc: do not mislead towards "infeasible" scenario wrt. xmlBufNodeDump
At least when merely public API is to be leveraged, one cannot use
xmlBufCreate function that would otherwise be a clear fit, and relying
on some invariants wrt. how some other struct fields will get
initialized along the construction/filling such parent struct and
(ab)using that instead does not appear clever, either.
Hence, instruct people what's the Right Thing for the moment, that is,
make them use xmlNodeDumpOutput instead (together with likewise public
xmlAllocOutputBuffer).
Going forward, it's questionable what do with xmlBuf* family of
functions that are once public, since they, for any practical purpose,
cannot be used by the library clients (that's how I've run into this).
Signed-off-by: Jan Pokorný <jpokorny@redhat.com>
2019-07-11 20:24:11 +03:00
* or xmlKeepBlanksDefault ( 0 ) was called .
2012-07-16 10:52:00 +04:00
* Since this is using xmlBuffer structures it is limited to 2 GB and somehow
Doc: do not mislead towards "infeasible" scenario wrt. xmlBufNodeDump
At least when merely public API is to be leveraged, one cannot use
xmlBufCreate function that would otherwise be a clear fit, and relying
on some invariants wrt. how some other struct fields will get
initialized along the construction/filling such parent struct and
(ab)using that instead does not appear clever, either.
Hence, instruct people what's the Right Thing for the moment, that is,
make them use xmlNodeDumpOutput instead (together with likewise public
xmlAllocOutputBuffer).
Going forward, it's questionable what do with xmlBuf* family of
functions that are once public, since they, for any practical purpose,
cannot be used by the library clients (that's how I've run into this).
Signed-off-by: Jan Pokorný <jpokorny@redhat.com>
2019-07-11 20:24:11 +03:00
* deprecated , use xmlNodeDumpOutput ( ) instead .
2004-03-04 16:40:59 +03:00
*
* 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 )
{
2012-07-16 10:52:00 +04:00
xmlBufPtr buffer ;
2024-07-07 04:01:51 +03:00
size_t ret1 ;
int ret2 ;
2012-07-16 10:52:00 +04:00
if ( ( buf = = NULL ) | | ( cur = = NULL ) )
return ( - 1 ) ;
2024-03-03 18:51:07 +03:00
if ( level < 0 )
level = 0 ;
else if ( level > 100 )
level = 100 ;
2012-07-16 10:52:00 +04:00
buffer = xmlBufFromBuffer ( buf ) ;
if ( buffer = = NULL )
return ( - 1 ) ;
2024-07-07 04:01:51 +03:00
ret1 = xmlBufNodeDump ( buffer , doc , cur , level , format ) ;
ret2 = xmlBufBackToBuffer ( buffer , buf ) ;
if ( ( ret1 = = ( size_t ) - 1 ) | | ( ret2 < 0 ) )
2012-07-16 10:52:00 +04:00
return ( - 1 ) ;
2024-07-07 04:01:51 +03:00
return ( ret1 > INT_MAX ? INT_MAX : ret1 ) ;
2012-07-16 10:52:00 +04:00
}
/**
* xmlBufNodeDump :
* @ 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 , in case of error 0
* is returned or @ buf stores the error
*/
size_t
xmlBufNodeDump ( xmlBufPtr buf , xmlDocPtr doc , xmlNodePtr cur , int level ,
int format )
{
size_t use ;
2024-03-05 20:06:02 +03:00
size_t ret ;
2004-03-04 16:40:59 +03:00
xmlOutputBufferPtr outbuf ;
xmlInitParser ( ) ;
if ( cur = = NULL ) {
2024-03-04 03:39:00 +03:00
return ( ( size_t ) - 1 ) ;
2004-03-04 16:40:59 +03:00
}
if ( buf = = NULL ) {
2024-03-04 03:39:00 +03:00
return ( ( size_t ) - 1 ) ;
2004-03-04 16:40:59 +03:00
}
outbuf = ( xmlOutputBufferPtr ) xmlMalloc ( sizeof ( xmlOutputBuffer ) ) ;
if ( outbuf = = NULL ) {
2024-01-02 23:49:43 +03:00
xmlSaveErrMemory ( NULL ) ;
2024-03-04 03:39:00 +03:00
return ( ( size_t ) - 1 ) ;
2004-03-04 16:40:59 +03:00
}
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 ;
2012-07-16 10:52:00 +04:00
use = xmlBufUse ( buf ) ;
2004-03-04 16:40:59 +03:00
xmlNodeDumpOutput ( outbuf , doc , cur , level , format , NULL ) ;
2024-03-05 20:06:02 +03:00
if ( outbuf - > error )
ret = ( size_t ) - 1 ;
else
ret = xmlBufUse ( buf ) - use ;
2004-03-04 16:40:59 +03:00
xmlFree ( outbuf ) ;
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 ) {
return ;
}
outbuf = xmlOutputBufferCreateFile ( f , NULL ) ;
if ( outbuf = = NULL )
return ;
# ifdef LIBXML_HTML_ENABLED
2024-01-02 23:49:43 +03:00
if ( ( doc ! = NULL ) & & ( doc - > type = = XML_HTML_DOCUMENT_NODE ) )
2004-03-04 16:40:59 +03:00
htmlNodeDumpOutput ( outbuf , doc , cur , NULL ) ;
2024-01-02 23:49:43 +03:00
else
2004-03-04 16:40:59 +03:00
# endif /* LIBXML_HTML_ENABLED */
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 )
{
2004-03-15 16:46:37 +03:00
xmlSaveCtxt ctxt ;
2024-07-02 19:51:59 +03:00
int options ;
2004-03-04 16:40:59 +03:00
# ifdef LIBXML_HTML_ENABLED
xmlDtdPtr dtd ;
int is_xhtml = 0 ;
# endif
2023-09-21 02:29:40 +03:00
( void ) doc ;
2004-03-04 16:40:59 +03:00
xmlInitParser ( ) ;
2004-11-05 13:03:46 +03:00
if ( ( buf = = NULL ) | | ( cur = = NULL ) ) return ;
2024-03-03 18:51:07 +03:00
if ( level < 0 )
level = 0 ;
else if ( level > 100 )
level = 100 ;
2005-03-31 19:22:56 +04:00
if ( encoding = = NULL )
encoding = " UTF-8 " ;
2004-03-15 16:46:37 +03:00
memset ( & ctxt , 0 , sizeof ( ctxt ) ) ;
ctxt . buf = buf ;
ctxt . level = level ;
ctxt . encoding = ( const xmlChar * ) encoding ;
2024-07-02 19:51:59 +03:00
options = XML_SAVE_AS_XML ;
if ( format )
options | = XML_SAVE_FORMAT ;
xmlSaveCtxtInit ( & ctxt , options ) ;
2004-03-15 16:46:37 +03:00
2004-03-04 16:40:59 +03:00
# ifdef LIBXML_HTML_ENABLED
dtd = xmlGetIntSubset ( doc ) ;
if ( dtd ! = NULL ) {
2005-09-13 01:43:20 +04:00
is_xhtml = xmlIsXHTML ( dtd - > SystemID , dtd - > ExternalID ) ;
if ( is_xhtml < 0 )
is_xhtml = 0 ;
2004-03-04 16:40:59 +03:00
}
if ( is_xhtml )
2004-03-15 16:46:37 +03:00
xhtmlNodeDumpOutput ( & ctxt , cur ) ;
2004-03-04 16:40:59 +03:00
else
# endif
2004-03-15 16:46:37 +03:00
xmlNodeDumpOutputInternal ( & ctxt , cur ) ;
2004-03-04 16:40:59 +03:00
}
/**
* 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 ) {
2004-03-15 16:46:37 +03:00
xmlSaveCtxt ctxt ;
2024-07-02 19:51:59 +03:00
int options ;
2004-03-04 16:40:59 +03:00
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 ) {
2024-01-02 20:33:57 +03:00
int res ;
res = xmlOpenCharEncodingHandler ( txt_encoding , /* output */ 1 ,
& conv_hdlr ) ;
2024-06-22 20:15:17 +03:00
if ( res ! = XML_ERR_OK ) {
2024-01-02 23:49:43 +03:00
xmlSaveErr ( NULL , res , NULL , txt_encoding ) ;
2004-03-04 16:40:59 +03:00
return ;
}
}
2024-06-18 23:55:34 +03:00
out_buff = xmlAllocOutputBuffer ( conv_hdlr ) ;
if ( out_buff = = NULL ) {
2024-01-02 23:49:43 +03:00
xmlSaveErrMemory ( NULL ) ;
2004-03-04 16:40:59 +03:00
return ;
}
2004-03-15 16:46:37 +03:00
memset ( & ctxt , 0 , sizeof ( ctxt ) ) ;
ctxt . buf = out_buff ;
ctxt . level = 0 ;
ctxt . encoding = ( const xmlChar * ) txt_encoding ;
2024-07-02 19:51:59 +03:00
options = XML_SAVE_AS_XML ;
if ( format )
options | = XML_SAVE_FORMAT ;
xmlSaveCtxtInit ( & ctxt , options ) ;
2004-03-15 16:46:37 +03:00
xmlDocContentDumpOutput ( & ctxt , out_doc ) ;
2004-03-04 16:40:59 +03:00
xmlOutputBufferFlush ( out_buff ) ;
2024-03-05 20:06:02 +03:00
if ( ! out_buff - > error ) {
if ( out_buff - > conv ! = NULL ) {
* doc_txt_len = xmlBufUse ( out_buff - > conv ) ;
* doc_txt_ptr = xmlBufDetach ( out_buff - > conv ) ;
} else {
* doc_txt_len = xmlBufUse ( out_buff - > buffer ) ;
* doc_txt_ptr = xmlBufDetach ( out_buff - > buffer ) ;
}
}
2004-03-04 16:40:59 +03:00
2023-12-10 19:14:57 +03:00
xmlOutputBufferClose ( out_buff ) ;
2004-03-04 16:40:59 +03:00
}
/**
* 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 ) {
2004-03-15 16:46:37 +03:00
xmlSaveCtxt ctxt ;
2004-03-04 16:40:59 +03:00
xmlOutputBufferPtr buf ;
const char * encoding ;
xmlCharEncodingHandlerPtr handler = NULL ;
int ret ;
2024-07-02 19:51:59 +03:00
int options ;
2004-03-04 16:40:59 +03:00
if ( cur = = NULL ) {
return ( - 1 ) ;
}
encoding = ( const char * ) cur - > encoding ;
if ( encoding ! = NULL ) {
2024-06-22 20:15:17 +03:00
int res ;
res = xmlOpenCharEncodingHandler ( encoding , /* output */ 1 , & handler ) ;
if ( res ! = XML_ERR_OK ) {
2007-07-26 15:41:46 +04:00
xmlFree ( ( char * ) cur - > encoding ) ;
encoding = NULL ;
2004-03-04 16:40:59 +03:00
}
2007-07-26 15:41:46 +04:00
}
2004-03-04 16:40:59 +03:00
buf = xmlOutputBufferCreateFile ( f , handler ) ;
if ( buf = = NULL ) return ( - 1 ) ;
2004-03-15 16:46:37 +03:00
memset ( & ctxt , 0 , sizeof ( ctxt ) ) ;
ctxt . buf = buf ;
ctxt . level = 0 ;
ctxt . encoding = ( const xmlChar * ) encoding ;
2024-07-02 19:51:59 +03:00
options = XML_SAVE_AS_XML ;
if ( format )
options | = XML_SAVE_FORMAT ;
xmlSaveCtxtInit ( & ctxt , options ) ;
2004-03-15 16:46:37 +03:00
xmlDocContentDumpOutput ( & ctxt , cur ) ;
2004-03-04 16:40:59 +03:00
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
2019-09-30 18:04:54 +03:00
* @ encoding : the encoding if any assuming the I / O layer handles the transcoding
2004-03-04 16:40:59 +03:00
*
* Dump an XML document to an I / O buffer .
2004-11-04 13:49:00 +03:00
* Warning ! This call xmlOutputBufferClose ( ) on buf which is not available
* after this call .
2004-03-04 16:40:59 +03:00
*
* returns : the number of bytes written or - 1 in case of failure .
*/
int
xmlSaveFileTo ( xmlOutputBufferPtr buf , xmlDocPtr cur , const char * encoding ) {
2004-03-15 16:46:37 +03:00
xmlSaveCtxt ctxt ;
2004-03-04 16:40:59 +03:00
int ret ;
2004-11-04 13:49:00 +03:00
if ( buf = = NULL ) return ( - 1 ) ;
if ( cur = = NULL ) {
xmlOutputBufferClose ( buf ) ;
return ( - 1 ) ;
}
2004-03-15 16:46:37 +03:00
memset ( & ctxt , 0 , sizeof ( ctxt ) ) ;
ctxt . buf = buf ;
ctxt . level = 0 ;
ctxt . encoding = ( const xmlChar * ) encoding ;
2024-07-02 19:51:59 +03:00
xmlSaveCtxtInit ( & ctxt , XML_SAVE_AS_XML ) ;
2004-03-15 16:46:37 +03:00
xmlDocContentDumpOutput ( & ctxt , cur ) ;
2004-03-04 16:40:59 +03:00
ret = xmlOutputBufferClose ( buf ) ;
return ( ret ) ;
}
/**
* xmlSaveFormatFileTo :
* @ buf : an output I / O buffer
* @ cur : the document
2019-09-30 18:04:54 +03:00
* @ encoding : the encoding if any assuming the I / O layer handles the transcoding
2004-03-04 16:40:59 +03:00
* @ format : should formatting spaces been added
*
* Dump an XML document to an I / O buffer .
2004-11-04 13:49:00 +03:00
* Warning ! This call xmlOutputBufferClose ( ) on buf which is not available
* after this call .
2004-03-04 16:40:59 +03:00
*
* returns : the number of bytes written or - 1 in case of failure .
*/
int
2004-03-15 16:46:37 +03:00
xmlSaveFormatFileTo ( xmlOutputBufferPtr buf , xmlDocPtr cur ,
const char * encoding , int format )
{
xmlSaveCtxt ctxt ;
int ret ;
2024-07-02 19:51:59 +03:00
int options ;
2004-03-04 16:40:59 +03:00
2004-11-04 13:49:00 +03:00
if ( buf = = NULL ) return ( - 1 ) ;
2004-11-05 13:03:46 +03:00
if ( ( cur = = NULL ) | |
( ( cur - > type ! = XML_DOCUMENT_NODE ) & &
( cur - > type ! = XML_HTML_DOCUMENT_NODE ) ) ) {
2004-11-04 13:49:00 +03:00
xmlOutputBufferClose ( buf ) ;
return ( - 1 ) ;
}
2004-03-15 16:46:37 +03:00
memset ( & ctxt , 0 , sizeof ( ctxt ) ) ;
ctxt . buf = buf ;
ctxt . level = 0 ;
ctxt . encoding = ( const xmlChar * ) encoding ;
2024-07-02 19:51:59 +03:00
options = XML_SAVE_AS_XML ;
if ( format )
options | = XML_SAVE_FORMAT ;
xmlSaveCtxtInit ( & ctxt , options ) ;
2004-03-15 16:46:37 +03:00
xmlDocContentDumpOutput ( & ctxt , cur ) ;
ret = xmlOutputBufferClose ( buf ) ;
return ( ret ) ;
2004-03-04 16:40:59 +03:00
}
/**
* 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 ) {
2004-03-15 16:46:37 +03:00
xmlSaveCtxt ctxt ;
2004-03-04 16:40:59 +03:00
xmlOutputBufferPtr buf ;
xmlCharEncodingHandlerPtr handler = NULL ;
int ret ;
2024-07-02 19:51:59 +03:00
int options ;
2004-03-04 16:40:59 +03:00
if ( cur = = NULL )
return ( - 1 ) ;
if ( encoding = = NULL )
encoding = ( const char * ) cur - > encoding ;
if ( encoding ! = NULL ) {
2024-06-22 20:15:17 +03:00
int res ;
res = xmlOpenCharEncodingHandler ( encoding , /* output */ 1 , & handler ) ;
if ( res ! = XML_ERR_OK )
2024-01-02 20:33:57 +03:00
return ( - 1 ) ;
2004-03-04 16:40:59 +03:00
}
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2004-03-04 16:40:59 +03:00
if ( cur - > compression < 0 ) cur - > compression = xmlGetCompressMode ( ) ;
# endif
2012-09-11 09:26:36 +04:00
/*
2004-03-04 16:40:59 +03:00
* save the content to a temp buffer .
*/
buf = xmlOutputBufferCreateFilename ( filename , handler , cur - > compression ) ;
if ( buf = = NULL ) return ( - 1 ) ;
2004-03-15 16:46:37 +03:00
memset ( & ctxt , 0 , sizeof ( ctxt ) ) ;
ctxt . buf = buf ;
ctxt . level = 0 ;
ctxt . encoding = ( const xmlChar * ) encoding ;
2024-07-02 19:51:59 +03:00
options = XML_SAVE_AS_XML ;
if ( format )
options | = XML_SAVE_FORMAT ;
xmlSaveCtxtInit ( & ctxt , options ) ;
2004-03-15 16:46:37 +03:00
xmlDocContentDumpOutput ( & ctxt , cur ) ;
2004-03-04 16:40:59 +03:00
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 */