2024-02-27 20:04:27 +00:00
//
// File loading code for Mini-XML, a small XML file parsing library.
//
// https://www.msweet.org/mxml
//
// Copyright © 2003-2024 by Michael R Sweet.
//
// Licensed under Apache License v2.0. See the file "LICENSE" for more
// information.
//
2003-06-03 19:46:29 +00:00
2019-02-10 15:40:53 +00:00
# ifndef _WIN32
2004-07-11 13:14:07 +00:00
# include <unistd.h>
2024-02-27 20:04:27 +00:00
# endif // !_WIN32
2009-02-05 06:06:11 +00:00
# include "mxml-private.h"
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
//
2024-03-06 19:45:10 +00:00
// Local types...
2024-02-27 20:04:27 +00:00
//
2004-05-16 21:54:47 +00:00
2024-03-06 19:45:10 +00:00
typedef enum _mxml_encoding_e // Character encoding
{
_MXML_ENCODING_UTF8 , // UTF-8
_MXML_ENCODING_UTF16BE , // UTF-16 Big-Endian
_MXML_ENCODING_UTF16LE // UTF-16 Little-Endian
} _mxml_encoding_t ;
typedef struct _mxml_stringbuf_s // String buffer
{
char * buffer , // Buffer
* bufptr ; // Pointer into buffer
size_t bufsize ; // Size of buffer
bool bufalloc ; // Allocate buffer?
} _mxml_stringbuf_t ;
2004-05-16 21:54:47 +00:00
2024-02-27 20:04:27 +00:00
//
// Macro to test for a bad XML character...
//
2005-01-29 17:03:33 +00:00
# define mxml_bad_char(ch) ((ch) < ' ' && (ch) != '\n' && (ch) != '\r' && (ch) != '\t')
2024-02-27 20:04:27 +00:00
//
2024-03-06 19:45:10 +00:00
// Local functions...
2024-02-27 20:04:27 +00:00
//
2004-07-11 13:14:07 +00:00
2024-03-06 19:45:10 +00:00
static bool mxml_add_char ( int ch , char * * ptr , char * * buffer , size_t * bufsize ) ;
static int mxml_get_entity ( mxml_read_cb_t read_cb , void * read_cbdata , _mxml_encoding_t * encoding , mxml_node_t * parent , int * line ) ;
static int mxml_getc ( mxml_read_cb_t read_cb , void * read_cbdata , _mxml_encoding_t * encoding ) ;
static inline int mxml_isspace ( int ch )
{
return ( ch = = ' ' | | ch = = ' \t ' | | ch = = ' \r ' | | ch = = ' \n ' ) ;
}
static mxml_node_t * mxml_load_data ( mxml_read_cb_t read_cb , void * read_cbdata , mxml_node_t * top , mxml_load_cb_t load_cb , void * load_cbdata , mxml_sax_cb_t sax_cb , void * sax_data ) ;
static int mxml_parse_element ( mxml_read_cb_t read_cb , void * read_cbdata , mxml_node_t * node , _mxml_encoding_t * encoding , int * line ) ;
static ssize_t mxml_read_cb_fd ( int * fd , void * buffer , size_t bytes ) ;
static ssize_t mxml_read_cb_file ( FILE * fp , void * buffer , size_t bytes ) ;
static ssize_t mxml_read_cb_string ( _mxml_stringbuf_t * sb , void * buffer , size_t bytes ) ;
static ssize_t mxml_write_cb_fd ( int * fd , const void * buffer , size_t bytes ) ;
static ssize_t mxml_write_cb_file ( FILE * fp , const void * buffer , size_t bytes ) ;
static ssize_t mxml_write_cb_string ( _mxml_stringbuf_t * sb , const void * buffer , size_t bytes ) ;
static int mxml_write_node ( mxml_write_cb_t write_cb , void * write_cbdata , mxml_node_t * node , mxml_save_cb_t save_cb , void * save_cbdata , int col , _mxml_global_t * global ) ;
static int mxml_write_string ( mxml_write_cb_t write_cb , void * write_cbdata , const char * s , bool use_entities , int col ) ;
static int mxml_write_ws ( mxml_write_cb_t write_cb , void * write_cbdata , mxml_node_t * node , mxml_save_cb_t save_cb , void * save_cbdata , mxml_ws_t ws , int col ) ;
//
// 'mxmlLoadFd()' - Load a file descriptor into an XML node tree.
//
// The nodes in the specified file are added to the specified top node.
// If no top node is provided, the XML file MUST be well-formed with a
// single parent node like <?xml> for the entire file. The callback
// function returns the value type that should be used for child nodes.
// The constants `MXML_INTEGER_CALLBACK`, `MXML_OPAQUE_CALLBACK`,
// `MXML_REAL_CALLBACK`, and `MXML_TEXT_CALLBACK` are defined for
// loading child (data) nodes of the specified type.
//
// Note: The most common programming error when using the Mini-XML library is
// to load an XML file using the `MXML_TEXT_CALLBACK`, which returns inline
// text as a series of whitespace-delimited words, instead of using the
// `MXML_OPAQUE_CALLBACK` which returns the inline text as a single string
// (including whitespace).
//
2007-04-23 21:48:03 +00:00
2024-03-06 19:45:10 +00:00
mxml_node_t * // O - First node or `NULL` if the file could not be read.
mxmlLoadFd (
mxml_node_t * top , // I - Top node
int fd , // I - File descriptor to read from
mxml_load_cb_t load_cb , // I - Load callback function or `NULL`
void * load_cbdata , // I - Load callback data
mxml_sax_cb_t sax_cb , // I - SAX callback function or `NULL``
void * sax_cbdata ) // I - SAX callback data
2004-07-11 13:14:07 +00:00
{
2024-03-06 19:45:10 +00:00
// Range check input...
if ( fd < 0 )
return ( NULL ) ;
// Read the XML data...
return ( mxml_load_data ( ( mxml_read_cb_t ) mxml_read_cb_fd , & fd , top , load_cb , load_cbdata , sax_cb , sax_cbdata ) ) ;
}
2004-07-11 13:14:07 +00:00
2024-02-27 20:04:27 +00:00
//
2024-03-06 19:45:10 +00:00
// 'mxmlLoadFile()' - Load a file into an XML node tree.
//
// The nodes in the specified file are added to the specified top node.
// If no top node is provided, the XML file MUST be well-formed with a
// single parent node like <?xml> for the entire file. The callback
// function returns the value type that should be used for child nodes.
// The constants `MXML_INTEGER_CALLBACK`, `MXML_OPAQUE_CALLBACK`,
// `MXML_REAL_CALLBACK`, and `MXML_TEXT_CALLBACK` are defined for
// loading child (data) nodes of the specified type.
//
// Note: The most common programming error when using the Mini-XML library is
// to load an XML file using the `MXML_TEXT_CALLBACK`, which returns inline
// text as a series of whitespace-delimited words, instead of using the
// `MXML_OPAQUE_CALLBACK` which returns the inline text as a single string
// (including whitespace).
2024-02-27 20:04:27 +00:00
//
2003-06-03 19:46:29 +00:00
2024-03-06 19:45:10 +00:00
mxml_node_t * // O - First node or `NULL` if the file could not be read.
mxmlLoadFile (
mxml_node_t * top , // I - Top node
FILE * fp , // I - File to read from
mxml_load_cb_t load_cb , // I - Load callback function or `NULL`
void * load_cbdata , // I - Load callback data
mxml_sax_cb_t sax_cb , // I - SAX callback function or `NULL``
void * sax_cbdata ) // I - SAX callback data
{
// Range check input...
if ( ! fp )
return ( NULL ) ;
// Read the XML data...
return ( mxml_load_data ( ( mxml_read_cb_t ) mxml_read_cb_file , fp , top , load_cb , load_cbdata , sax_cb , sax_cbdata ) ) ;
}
2003-06-19 03:20:41 +00:00
2024-02-27 20:04:27 +00:00
//
2024-03-06 19:45:10 +00:00
// 'mxmlLoadFilename()' - Load a file into an XML node tree.
2024-02-27 20:04:27 +00:00
//
// The nodes in the specified file are added to the specified top node.
// If no top node is provided, the XML file MUST be well-formed with a
// single parent node like <?xml> for the entire file. The callback
// function returns the value type that should be used for child nodes.
2024-03-06 19:45:10 +00:00
// The constants `MXML_INTEGER_CALLBACK`, `MXML_OPAQUE_CALLBACK`,
// `MXML_REAL_CALLBACK`, and `MXML_TEXT_CALLBACK` are defined for
2024-02-27 20:04:27 +00:00
// loading child (data) nodes of the specified type.
//
// Note: The most common programming error when using the Mini-XML library is
// to load an XML file using the `MXML_TEXT_CALLBACK`, which returns inline
// text as a series of whitespace-delimited words, instead of using the
// `MXML_OPAQUE_CALLBACK` which returns the inline text as a single string
// (including whitespace).
//
mxml_node_t * // O - First node or `NULL` if the file could not be read.
2024-03-06 19:45:10 +00:00
mxmlLoadFilename (
mxml_node_t * top , // I - Top node
const char * filename , // I - File to read from
mxml_load_cb_t load_cb , // I - Load callback function or `NULL`
void * load_cbdata , // I - Load callback data
mxml_sax_cb_t sax_cb , // I - SAX callback function or `NULL``
void * sax_cbdata ) // I - SAX callback data
2004-07-11 13:14:07 +00:00
{
2024-03-06 19:45:10 +00:00
FILE * fp ; // File pointer
mxml_node_t * ret ; // Node
2004-07-11 13:14:07 +00:00
2024-03-06 19:45:10 +00:00
// Range check input...
if ( ! filename )
return ( NULL ) ;
// Open the file...
if ( ( fp = fopen ( filename , " r " ) ) = = NULL )
return ( NULL ) ;
2004-07-11 13:14:07 +00:00
2024-02-27 20:04:27 +00:00
// Read the XML data...
2024-03-06 19:45:10 +00:00
ret = mxml_load_data ( ( mxml_read_cb_t ) mxml_read_cb_file , fp , top , load_cb , load_cbdata , sax_cb , sax_cbdata ) ;
// Close the file and return...
fclose ( fp ) ;
return ( ret ) ;
2004-07-11 13:14:07 +00:00
}
2024-02-27 20:04:27 +00:00
//
2024-03-06 19:45:10 +00:00
// 'mxmlLoadIO()' - Load an XML node tree using a read callback.
2024-02-27 20:04:27 +00:00
//
// The nodes in the specified file are added to the specified top node.
// If no top node is provided, the XML file MUST be well-formed with a
// single parent node like <?xml> for the entire file. The callback
// function returns the value type that should be used for child nodes.
2024-03-06 19:45:10 +00:00
// The constants `MXML_INTEGER_CALLBACK`, `MXML_OPAQUE_CALLBACK`,
// `MXML_REAL_CALLBACK`, and `MXML_TEXT_CALLBACK` are defined for
2024-02-27 20:04:27 +00:00
// loading child (data) nodes of the specified type.
//
// Note: The most common programming error when using the Mini-XML library is
// to load an XML file using the `MXML_TEXT_CALLBACK`, which returns inline
// text as a series of whitespace-delimited words, instead of using the
// `MXML_OPAQUE_CALLBACK` which returns the inline text as a single string
// (including whitespace).
//
mxml_node_t * // O - First node or `NULL` if the file could not be read.
2024-03-06 19:45:10 +00:00
mxmlLoadIO (
mxml_node_t * top , // I - Top node
mxml_read_cb_t read_cb , // I - Read callback function
void * read_cbdata , // I - Read callback data
mxml_load_cb_t load_cb , // I - Load callback function or `NULL`
void * load_cbdata , // I - Load callback data
mxml_sax_cb_t sax_cb , // I - SAX callback function or `NULL``
void * sax_cbdata ) // I - SAX callback data
2003-06-19 03:20:41 +00:00
{
2024-03-06 19:45:10 +00:00
// Range check input...
if ( ! read_cb )
return ( NULL ) ;
2024-02-27 20:04:27 +00:00
// Read the XML data...
2024-03-06 19:45:10 +00:00
return ( mxml_load_data ( read_cb , read_cbdata , top , load_cb , load_cbdata , sax_cb , sax_cbdata ) ) ;
2003-06-19 03:20:41 +00:00
}
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
//
// 'mxmlLoadString()' - Load a string into an XML node tree.
//
// The nodes in the specified string are added to the specified top node.
// If no top node is provided, the XML string MUST be well-formed with a
// single parent node like <?xml> for the entire string. The callback
// function returns the value type that should be used for child nodes.
2024-03-06 19:45:10 +00:00
// The constants `MXML_INTEGER_CALLBACK`, `MXML_OPAQUE_CALLBACK`,
// `MXML_REAL_CALLBACK`, and `MXML_TEXT_CALLBACK` are defined for
2024-02-27 20:04:27 +00:00
// loading child (data) nodes of the specified type.
//
// Note: The most common programming error when using the Mini-XML library is
// to load an XML file using the `MXML_TEXT_CALLBACK`, which returns inline
// text as a series of whitespace-delimited words, instead of using the
// `MXML_OPAQUE_CALLBACK` which returns the inline text as a single string
// (including whitespace).
//
mxml_node_t * // O - First node or `NULL` if the string has errors.
2024-03-06 19:45:10 +00:00
mxmlLoadString (
mxml_node_t * top , // I - Top node
const char * s , // I - String to load
mxml_load_cb_t load_cb , // I - Load callback function or `NULL`
void * load_cbdata , // I - Load callback data
mxml_sax_cb_t sax_cb , // I - SAX callback function or `NULL``
void * sax_cbdata ) // I - SAX callback data
2003-06-19 03:20:41 +00:00
{
2024-03-06 19:45:10 +00:00
_mxml_stringbuf_t sb ; // String buffer
// Range check input...
if ( ! s )
return ( NULL ) ;
// Setup string buffer...
sb . buffer = ( char * ) s ;
sb . bufptr = ( char * ) s ;
sb . bufsize = strlen ( s ) ;
sb . bufalloc = false ;
2024-02-27 20:04:27 +00:00
// Read the XML data...
2024-03-06 19:45:10 +00:00
return ( mxml_load_data ( ( mxml_read_cb_t ) mxml_read_cb_string , & sb , top , load_cb , load_cbdata , sax_cb , sax_cbdata ) ) ;
2003-06-19 03:20:41 +00:00
}
2024-02-27 20:04:27 +00:00
//
// 'mxmlSaveAllocString()' - Save an XML tree to an allocated string.
//
// This function returns a pointer to a string containing the textual
// representation of the XML node tree. The string should be freed
// using `free()` when you are done with it. `NULL` is returned if the node
// would produce an empty string or if the string cannot be allocated.
//
// The callback argument specifies a function that returns a whitespace
// string or `NULL` before and after each element. If `MXML_NO_CALLBACK`
// is specified, whitespace will only be added before `MXML_TYPE_TEXT` nodes
// with leading whitespace and before attribute names inside opening
// element tags.
//
char * // O - Allocated string or `NULL`
2007-04-23 21:48:03 +00:00
mxmlSaveAllocString (
2024-02-27 20:04:27 +00:00
mxml_node_t * node , // I - Node to write
2024-03-06 19:45:10 +00:00
mxml_save_cb_t save_cb , // I - Whitespace callback function
void * save_cbdata ) // I - Whitespace callback data
2003-07-22 10:29:19 +00:00
{
2024-03-06 19:45:10 +00:00
_mxml_stringbuf_t sb ; // String buffer
_mxml_global_t * global = _mxml_global ( ) ;
// Global data
2003-07-22 10:29:19 +00:00
2024-03-06 19:45:10 +00:00
// Setup a string buffer
if ( ( sb . buffer = malloc ( 1024 ) ) = = NULL )
2003-07-22 10:29:19 +00:00
return ( NULL ) ;
2024-03-06 19:45:10 +00:00
sb . bufptr = sb . buffer ;
sb . bufsize = 1024 ;
sb . bufalloc = true ;
2003-07-22 10:29:19 +00:00
2024-03-06 19:45:10 +00:00
// Write the top node...
if ( mxml_write_node ( ( mxml_write_cb_t ) mxml_write_cb_string , & sb , node , save_cb , save_cbdata , 0 , global ) < 0 )
{
free ( sb . buffer ) ;
2003-07-22 10:29:19 +00:00
return ( NULL ) ;
2024-03-06 19:45:10 +00:00
}
2003-07-22 10:29:19 +00:00
2024-03-06 19:45:10 +00:00
// Nul-terminate the string...
* ( sb . bufptr ) = ' \0 ' ;
2003-07-22 10:29:19 +00:00
2024-02-27 20:04:27 +00:00
// Return the allocated string...
2024-03-06 19:45:10 +00:00
return ( sb . buffer ) ;
2003-07-22 10:29:19 +00:00
}
2024-02-27 20:04:27 +00:00
//
// 'mxmlSaveFd()' - Save an XML tree to a file descriptor.
//
// The callback argument specifies a function that returns a whitespace
// string or NULL before and after each element. If `MXML_NO_CALLBACK`
// is specified, whitespace will only be added before `MXML_TYPE_TEXT` nodes
// with leading whitespace and before attribute names inside opening
// element tags.
//
2024-03-03 01:02:08 +00:00
bool // O - `true` on success, `false` on error.
2024-02-27 20:04:27 +00:00
mxmlSaveFd ( mxml_node_t * node , // I - Node to write
int fd , // I - File descriptor to write to
2024-03-06 19:45:10 +00:00
mxml_save_cb_t save_cb , // I - Whitespace callback function
void * save_cbdata ) // I - Whitespace callback data
2004-07-11 13:14:07 +00:00
{
2024-02-27 20:04:27 +00:00
int col ; // Final column
2007-09-21 04:46:02 +00:00
_mxml_global_t * global = _mxml_global ( ) ;
2024-02-27 20:04:27 +00:00
// Global data
2004-07-11 13:14:07 +00:00
2024-02-27 20:04:27 +00:00
// Write the node...
2024-03-06 19:45:10 +00:00
if ( ( col = mxml_write_node ( ( mxml_write_cb_t ) mxml_write_cb_fd , & fd , node , save_cb , save_cbdata , 0 , global ) ) < 0 )
return ( false ) ;
2004-07-11 13:14:07 +00:00
2024-03-06 19:45:10 +00:00
// Make sure the file ends with a newline...
2004-07-11 13:14:07 +00:00
if ( col > 0 )
2024-02-27 20:04:27 +00:00
{
2024-03-06 19:45:10 +00:00
if ( write ( fd , " \n " , 1 ) < 0 )
return ( false ) ;
2024-02-27 20:04:27 +00:00
}
2004-07-11 13:14:07 +00:00
2024-03-06 19:45:10 +00:00
return ( true ) ;
2004-07-11 13:14:07 +00:00
}
2024-02-27 20:04:27 +00:00
//
// 'mxmlSaveFile()' - Save an XML tree to a file.
//
// The callback argument specifies a function that returns a whitespace
// string or NULL before and after each element. If `MXML_NO_CALLBACK`
// is specified, whitespace will only be added before `MXML_TYPE_TEXT` nodes
// with leading whitespace and before attribute names inside opening
// element tags.
//
2024-03-03 01:02:08 +00:00
bool // O - `true` on success, `false` on error.
2024-03-06 19:45:10 +00:00
mxmlSaveFile (
mxml_node_t * node , // I - Node to write
FILE * fp , // I - File to write to
mxml_save_cb_t save_cb , // I - Whitespace callback function
void * save_cbdata ) // I - Whitespace callback data
2003-06-19 03:20:41 +00:00
{
2024-03-06 19:45:10 +00:00
int col ; // Final column
2007-09-21 04:46:02 +00:00
_mxml_global_t * global = _mxml_global ( ) ;
2024-02-27 20:04:27 +00:00
// Global data
2003-06-19 03:20:41 +00:00
2024-02-27 20:04:27 +00:00
// Write the node...
2024-03-06 19:45:10 +00:00
if ( ( col = mxml_write_node ( ( mxml_write_cb_t ) mxml_write_cb_file , fp , node , save_cb , save_cbdata , 0 , global ) ) < 0 )
return ( false ) ;
2003-06-19 03:20:41 +00:00
2024-03-06 19:45:10 +00:00
// Make sure the file ends with a newline...
2003-06-19 03:20:41 +00:00
if ( col > 0 )
2024-02-27 20:04:27 +00:00
{
2003-06-19 03:20:41 +00:00
if ( putc ( ' \n ' , fp ) < 0 )
2024-03-06 19:45:10 +00:00
return ( false ) ;
2024-02-27 20:04:27 +00:00
}
2003-06-19 03:20:41 +00:00
2024-03-06 19:45:10 +00:00
return ( true ) ;
2003-06-19 03:20:41 +00:00
}
2024-02-27 20:04:27 +00:00
//
2024-03-06 19:45:10 +00:00
// 'mxmlSaveFilename()' - Save an XML tree to a file.
2024-02-27 20:04:27 +00:00
//
// The callback argument specifies a function that returns a whitespace
// string or NULL before and after each element. If `MXML_NO_CALLBACK`
// is specified, whitespace will only be added before `MXML_TYPE_TEXT` nodes
// with leading whitespace and before attribute names inside opening
// element tags.
//
2024-03-06 19:45:10 +00:00
bool // O - `true` on success, `false` on error.
mxmlSaveFilename (
mxml_node_t * node , // I - Node to write
const char * filename , // I - File to write to
mxml_save_cb_t save_cb , // I - Whitespace callback function
void * save_cbdata ) // I - Whitespace callback data
2003-06-19 03:20:41 +00:00
{
2024-03-06 19:45:10 +00:00
bool ret = true ; // Return value
FILE * fp ; // File pointer
int col ; // Final column
2007-09-21 04:46:02 +00:00
_mxml_global_t * global = _mxml_global ( ) ;
2024-02-27 20:04:27 +00:00
// Global data
2003-06-19 04:25:12 +00:00
2024-03-06 19:45:10 +00:00
// Open the file...
if ( ( fp = fopen ( filename , " w " ) ) = = NULL )
return ( false ) ;
2003-06-19 04:25:12 +00:00
2024-03-06 19:45:10 +00:00
// Write the node...
if ( ( col = mxml_write_node ( ( mxml_write_cb_t ) mxml_write_cb_file , fp , node , save_cb , save_cbdata , 0 , global ) ) < 0 )
2021-10-26 18:44:15 +00:00
{
2024-03-06 19:45:10 +00:00
ret = false ;
2021-10-26 18:44:15 +00:00
}
2024-03-06 19:45:10 +00:00
else if ( col > 0 )
2024-02-27 20:04:27 +00:00
{
2024-03-06 19:45:10 +00:00
// Make sure the file ends with a newline...
if ( putc ( ' \n ' , fp ) < 0 )
ret = false ;
2024-02-27 20:04:27 +00:00
}
2003-06-19 04:25:12 +00:00
2024-03-06 19:45:10 +00:00
fclose ( fp ) ;
return ( ret ) ;
2003-06-19 03:20:41 +00:00
}
2024-02-27 20:04:27 +00:00
//
2024-03-06 19:45:10 +00:00
// 'mxmlSaveIO()' - Save an XML tree using a callback.
2024-02-27 20:04:27 +00:00
//
2024-03-06 19:45:10 +00:00
// The callback argument specifies a function that returns a whitespace
// string or NULL before and after each element. If `MXML_NO_CALLBACK`
// is specified, whitespace will only be added before `MXML_TYPE_TEXT` nodes
// with leading whitespace and before attribute names inside opening
// element tags.
2024-02-27 20:04:27 +00:00
//
2024-03-06 19:45:10 +00:00
bool // O - `true` on success, `false` on error.
mxmlSaveIO (
mxml_node_t * node , // I - Node to write
mxml_write_cb_t write_cb , // I - Write callback function
void * write_cbdata , // I - Write callback data
mxml_save_cb_t save_cb , // I - Whitespace callback function
void * save_cbdata ) // I - Whitespace callback data
2007-04-23 21:48:03 +00:00
{
2024-03-06 19:45:10 +00:00
int col ; // Final column
_mxml_global_t * global = _mxml_global ( ) ;
// Global data
2007-04-23 21:48:03 +00:00
2024-03-06 19:45:10 +00:00
// Range check input...
if ( ! node | | ! write_cb )
return ( false ) ;
2007-04-23 21:48:03 +00:00
2024-03-06 19:45:10 +00:00
// Write the node...
if ( ( col = mxml_write_node ( write_cb , write_cbdata , node , save_cb , save_cbdata , 0 , global ) ) < 0 )
return ( false ) ;
if ( col > 0 )
{
// Make sure the file ends with a newline...
if ( ( write_cb ) ( write_cbdata , " \n " , 1 ) < 0 )
return ( false ) ;
}
return ( true ) ;
2007-04-23 21:48:03 +00:00
}
2024-02-27 20:04:27 +00:00
//
2024-03-06 19:45:10 +00:00
// 'mxmlSaveString()' - Save an XML node tree to a string.
2024-02-27 20:04:27 +00:00
//
2024-03-06 19:45:10 +00:00
// This function returns the total number of bytes that would be
// required for the string but only copies (bufsize - 1) characters
// into the specified buffer.
2024-02-27 20:04:27 +00:00
//
2024-03-06 19:45:10 +00:00
// The callback argument specifies a function that returns a whitespace
// string or NULL before and after each element. If `MXML_NO_CALLBACK`
// is specified, whitespace will only be added before `MXML_TYPE_TEXT` nodes
// with leading whitespace and before attribute names inside opening
// element tags.
2024-02-27 20:04:27 +00:00
//
2024-03-06 19:45:10 +00:00
size_t // O - Size of string
mxmlSaveString (
mxml_node_t * node , // I - Node to write
char * buffer , // I - String buffer
size_t bufsize , // I - Size of string buffer
mxml_save_cb_t save_cb , // I - Whitespace callback function
void * save_cbdata ) // I - Whitespace callback function
2007-04-23 21:48:03 +00:00
{
2024-03-06 19:45:10 +00:00
_mxml_stringbuf_t sb ; // String buffer
_mxml_global_t * global = _mxml_global ( ) ;
// Global data
2007-04-23 21:48:03 +00:00
2024-03-06 19:45:10 +00:00
// Setup the string buffer...
sb . buffer = buffer ;
sb . bufptr = buffer ;
sb . bufsize = bufsize ;
sb . bufalloc = false ;
2024-02-27 20:04:27 +00:00
2024-03-06 19:45:10 +00:00
// Write the node...
if ( mxml_write_node ( ( mxml_write_cb_t ) mxml_write_cb_string , & sb , node , save_cb , save_cbdata , 0 , global ) < 0 )
return ( false ) ;
// Nul-terminate the string...
if ( sb . bufptr < ( sb . buffer + sb . bufsize ) )
* ( sb . bufptr ) = ' \0 ' ;
// Return the number of characters...
return ( ( size_t ) ( sb . bufptr - sb . buffer ) ) ;
2007-04-23 21:48:03 +00:00
}
2024-02-27 20:04:27 +00:00
//
// 'mxmlSetCustomHandlers()' - Set the handling functions for custom data.
//
// The load function accepts a node pointer and a data string and must
// return 0 on success and non-zero on error.
//
// The save function accepts a node pointer and must return a malloc'd
// string on success and `NULL` on error.
//
2004-10-28 02:58:01 +00:00
void
2007-04-23 21:48:03 +00:00
mxmlSetCustomHandlers (
2024-02-27 20:04:27 +00:00
mxml_custom_load_cb_t load , // I - Load function
mxml_custom_save_cb_t save ) // I - Save function
2004-10-28 02:58:01 +00:00
{
2007-09-21 04:46:02 +00:00
_mxml_global_t * global = _mxml_global ( ) ;
2024-02-27 20:04:27 +00:00
// Global data
2007-09-21 04:46:02 +00:00
global - > custom_load_cb = load ;
global - > custom_save_cb = save ;
2004-10-28 02:58:01 +00:00
}
2024-02-27 20:04:27 +00:00
//
// 'mxmlSetErrorCallback()' - Set the error message callback.
//
2003-12-03 03:59:04 +00:00
void
2024-02-27 20:04:27 +00:00
mxmlSetErrorCallback ( mxml_error_cb_t cb ) // I - Error callback function
2003-12-03 03:59:04 +00:00
{
2007-09-21 04:46:02 +00:00
_mxml_global_t * global = _mxml_global ( ) ;
2024-02-27 20:04:27 +00:00
// Global data
2007-09-21 04:46:02 +00:00
global - > error_cb = cb ;
2003-12-03 03:59:04 +00:00
}
2024-02-27 20:04:27 +00:00
//
// 'mxmlSetWrapMargin()' - Set the wrap margin when saving XML data.
//
// Wrapping is disabled when "column" is 0.
//
2007-04-18 01:08:58 +00:00
void
2024-02-27 20:04:27 +00:00
mxmlSetWrapMargin ( int column ) // I - Column for wrapping, 0 to disable wrapping
2007-04-18 01:08:58 +00:00
{
2007-09-21 04:46:02 +00:00
_mxml_global_t * global = _mxml_global ( ) ;
2024-02-27 20:04:27 +00:00
// Global data
2007-09-21 04:46:02 +00:00
2008-03-21 04:59:01 +00:00
global - > wrap = column ;
2007-04-18 01:08:58 +00:00
}
2024-02-27 20:04:27 +00:00
//
// 'mxml_add_char()' - Add a character to a buffer, expanding as needed.
//
2003-06-19 03:20:41 +00:00
2024-03-06 19:45:10 +00:00
static bool // O - `true` on success, `false` on error
mxml_add_char ( int ch , // I - Character to add
char * * bufptr , // IO - Current position in buffer
char * * buffer , // IO - Current buffer
size_t * bufsize ) // IO - Current buffer size
2003-06-19 03:20:41 +00:00
{
2024-02-27 20:04:27 +00:00
char * newbuffer ; // New buffer value
2003-06-19 03:20:41 +00:00
2003-12-21 15:01:15 +00:00
if ( * bufptr > = ( * buffer + * bufsize - 4 ) )
2003-06-19 03:20:41 +00:00
{
2024-02-27 20:04:27 +00:00
// Increase the size of the buffer...
2003-06-19 03:20:41 +00:00
if ( * bufsize < 1024 )
( * bufsize ) * = 2 ;
else
( * bufsize ) + = 1024 ;
if ( ( newbuffer = realloc ( * buffer , * bufsize ) ) = = NULL )
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Unable to expand string buffer to %lu bytes. " , ( unsigned long ) * bufsize ) ;
2003-06-19 03:20:41 +00:00
2024-03-06 19:45:10 +00:00
return ( false ) ;
2003-06-19 03:20:41 +00:00
}
* bufptr = newbuffer + ( * bufptr - * buffer ) ;
2003-07-23 14:47:17 +00:00
* buffer = newbuffer ;
2003-06-19 03:20:41 +00:00
}
2004-10-28 01:07:00 +00:00
if ( ch < 0x80 )
2003-12-21 15:01:15 +00:00
{
2024-02-27 20:04:27 +00:00
// Single byte ASCII...
2003-12-21 15:01:15 +00:00
* ( * bufptr ) + + = ch ;
}
2004-10-28 01:07:00 +00:00
else if ( ch < 0x800 )
2003-12-21 15:01:15 +00:00
{
2024-02-27 20:04:27 +00:00
// Two-byte UTF-8...
2003-12-21 15:01:15 +00:00
* ( * bufptr ) + + = 0xc0 | ( ch > > 6 ) ;
* ( * bufptr ) + + = 0x80 | ( ch & 0x3f ) ;
}
2004-10-28 01:07:00 +00:00
else if ( ch < 0x10000 )
2003-12-21 15:01:15 +00:00
{
2024-02-27 20:04:27 +00:00
// Three-byte UTF-8...
2003-12-21 15:01:15 +00:00
* ( * bufptr ) + + = 0xe0 | ( ch > > 12 ) ;
* ( * bufptr ) + + = 0x80 | ( ( ch > > 6 ) & 0x3f ) ;
* ( * bufptr ) + + = 0x80 | ( ch & 0x3f ) ;
}
else
{
2024-02-27 20:04:27 +00:00
// Four-byte UTF-8...
2003-12-21 15:01:15 +00:00
* ( * bufptr ) + + = 0xf0 | ( ch > > 18 ) ;
* ( * bufptr ) + + = 0x80 | ( ( ch > > 12 ) & 0x3f ) ;
* ( * bufptr ) + + = 0x80 | ( ( ch > > 6 ) & 0x3f ) ;
* ( * bufptr ) + + = 0x80 | ( ch & 0x3f ) ;
}
2003-06-19 03:20:41 +00:00
2024-03-06 19:45:10 +00:00
return ( true ) ;
2003-06-19 03:20:41 +00:00
}
2024-02-27 20:04:27 +00:00
//
2024-03-06 19:45:10 +00:00
// 'mxml_get_entity()' - Get the character corresponding to an entity...
2024-02-27 20:04:27 +00:00
//
2003-12-21 15:01:15 +00:00
2024-03-06 19:45:10 +00:00
static int // O - Character value or `EOF` on error
mxml_get_entity (
mxml_read_cb_t read_cb , // I - Read callback function
void * read_cbdata , // I - Read callback data
_mxml_encoding_t * encoding , // IO - Character encoding
mxml_node_t * parent , // I - Parent node
int * line ) // IO - Current line number
2003-12-21 15:01:15 +00:00
{
2024-03-06 19:45:10 +00:00
int ch ; // Current character
char entity [ 64 ] , // Entity string
* entptr ; // Pointer into entity
// Read a HTML character entity of the form "&NAME;", "&#NUMBER;", or "&#xHEX"...
entptr = entity ;
while ( ( ch = mxml_getc ( read_cb , read_cbdata , encoding ) ) ! = EOF )
{
if ( ch > 126 | | ( ! isalnum ( ch ) & & ch ! = ' # ' ) )
{
break ;
}
else if ( entptr < ( entity + sizeof ( entity ) - 1 ) )
{
* entptr + + = ch ;
}
else
{
_mxml_error ( " Entity name too long under parent <%s> on line %d. " , mxmlGetElement ( parent ) , * line ) ;
break ;
}
}
* entptr = ' \0 ' ;
if ( ch ! = ' ; ' )
{
_mxml_error ( " Character entity '%s' not terminated under parent <%s> on line %d. " , entity , mxmlGetElement ( parent ) , * line ) ;
2003-12-21 15:01:15 +00:00
2024-03-06 19:45:10 +00:00
if ( ch = = ' \n ' )
( * line ) + + ;
return ( EOF ) ;
}
2003-12-21 15:01:15 +00:00
2024-03-06 19:45:10 +00:00
if ( entity [ 0 ] = = ' # ' )
{
if ( entity [ 1 ] = = ' x ' )
ch = ( int ) strtol ( entity + 2 , NULL , 16 ) ;
else
ch = ( int ) strtol ( entity + 1 , NULL , 10 ) ;
}
else if ( ( ch = mxmlEntityGetValue ( entity ) ) < 0 )
{
_mxml_error ( " Entity name '%s;' not supported under parent <%s> on line %d. " , entity , mxmlGetElement ( parent ) , * line ) ;
}
2003-12-21 15:01:15 +00:00
2024-03-06 19:45:10 +00:00
if ( mxml_bad_char ( ch ) )
2024-02-27 20:04:27 +00:00
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Bad control character 0x%02x under parent <%s> on line %d not allowed by XML standard. " , ch , mxmlGetElement ( parent ) , * line ) ;
return ( EOF ) ;
2024-02-27 20:04:27 +00:00
}
2003-12-21 15:01:15 +00:00
2024-03-06 19:45:10 +00:00
return ( ch ) ;
}
//
// 'mxml_getc()' - Read a character from a file descriptor.
//
static int // O - Character or `EOF`
mxml_getc ( mxml_read_cb_t read_cb , // I - Read callback function
void * read_cbdata , // I - Read callback data
_mxml_encoding_t * encoding ) // IO - Encoding
{
int ch ; // Current character
unsigned char buffer [ 4 ] ; // Read buffer
// Grab the next character...
read_first_byte :
if ( ( read_cb ) ( read_cbdata , buffer , 1 ) ! = 1 )
return ( EOF ) ;
ch = buffer [ 0 ] ;
2004-07-11 13:14:07 +00:00
switch ( * encoding )
2003-12-21 15:01:15 +00:00
{
2024-03-06 19:45:10 +00:00
case _MXML_ENCODING_UTF8 :
2024-02-27 20:04:27 +00:00
// Got a UTF-8 character; convert UTF-8 to Unicode and return...
2004-07-11 13:14:07 +00:00
if ( ! ( ch & 0x80 ) )
2005-01-29 17:03:33 +00:00
{
2024-03-06 19:45:10 +00:00
// ASCII
break ;
2005-01-29 17:03:33 +00:00
}
else if ( ch = = 0xfe )
2004-07-11 13:14:07 +00:00
{
2024-02-27 20:04:27 +00:00
// UTF-16 big-endian BOM?
2024-03-06 19:45:10 +00:00
if ( ( read_cb ) ( read_cbdata , buffer + 1 , 1 ) ! = 1 )
return ( EOF ) ;
2013-11-12 05:03:47 +00:00
2024-03-06 19:45:10 +00:00
if ( buffer [ 1 ] ! = 0xff )
2004-07-11 13:14:07 +00:00
return ( EOF ) ;
2024-03-06 19:45:10 +00:00
// Yes, switch to UTF-16 BE and try reading again...
* encoding = _MXML_ENCODING_UTF16BE ;
2004-07-11 13:14:07 +00:00
2024-03-06 19:45:10 +00:00
goto read_first_byte ;
2004-07-11 13:14:07 +00:00
}
else if ( ch = = 0xff )
{
2024-02-27 20:04:27 +00:00
// UTF-16 little-endian BOM?
2024-03-06 19:45:10 +00:00
if ( ( read_cb ) ( read_cbdata , buffer + 1 , 1 ) ! = 1 )
return ( EOF ) ;
2013-11-12 05:03:47 +00:00
2024-03-06 19:45:10 +00:00
if ( buffer [ 1 ] ! = 0xfe )
2004-07-11 13:14:07 +00:00
return ( EOF ) ;
2024-03-06 19:45:10 +00:00
// Yes, switch to UTF-16 LE and try reading again...
* encoding = _MXML_ENCODING_UTF16LE ;
2004-07-11 13:14:07 +00:00
2024-03-06 19:45:10 +00:00
goto read_first_byte ;
2004-07-11 13:14:07 +00:00
}
else if ( ( ch & 0xe0 ) = = 0xc0 )
{
2024-02-27 20:04:27 +00:00
// Two-byte value...
2024-03-06 19:45:10 +00:00
if ( ( read_cb ) ( read_cbdata , buffer + 1 , 1 ) ! = 1 )
return ( EOF ) ;
2004-07-11 13:14:07 +00:00
2024-03-06 19:45:10 +00:00
if ( ( buffer [ 1 ] & 0xc0 ) ! = 0x80 )
2004-07-11 13:14:07 +00:00
return ( EOF ) ;
2024-03-06 19:45:10 +00:00
ch = ( ( ch & 0x1f ) < < 6 ) | ( buffer [ 1 ] & 0x3f ) ;
2004-10-28 01:07:00 +00:00
if ( ch < 0x80 )
2009-03-19 05:27:26 +00:00
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Invalid UTF-8 sequence for character 0x%04x. " , ch ) ;
2004-10-28 01:07:00 +00:00
return ( EOF ) ;
2009-03-19 05:27:26 +00:00
}
2004-07-11 13:14:07 +00:00
}
else if ( ( ch & 0xf0 ) = = 0xe0 )
{
2024-02-27 20:04:27 +00:00
// Three-byte value...
2024-03-06 19:45:10 +00:00
if ( ( read_cb ) ( read_cbdata , buffer + 1 , 2 ) ! = 2 )
return ( EOF ) ;
2004-07-11 13:14:07 +00:00
2024-03-06 19:45:10 +00:00
if ( ( buffer [ 1 ] & 0xc0 ) ! = 0x80 | | ( buffer [ 2 ] & 0xc0 ) ! = 0x80 )
2004-07-11 13:14:07 +00:00
return ( EOF ) ;
2024-03-06 19:45:10 +00:00
ch = ( ( ch & 0x0f ) < < 12 ) | ( ( buffer [ 1 ] & 0x3f ) < < 6 ) | ( buffer [ 2 ] & 0x3f ) ;
2004-10-28 01:07:00 +00:00
if ( ch < 0x800 )
2009-03-19 05:27:26 +00:00
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Invalid UTF-8 sequence for character 0x%04x. " , ch ) ;
2009-03-19 05:27:26 +00:00
return ( EOF ) ;
}
2024-02-27 20:04:27 +00:00
// Ignore (strip) Byte Order Mark (BOM)...
2009-05-17 05:20:52 +00:00
if ( ch = = 0xfeff )
2024-03-06 19:45:10 +00:00
goto read_first_byte ;
2004-07-11 13:14:07 +00:00
}
else if ( ( ch & 0xf8 ) = = 0xf0 )
{
2024-02-27 20:04:27 +00:00
// Four-byte value...
2024-03-06 19:45:10 +00:00
if ( ( read_cb ) ( read_cbdata , buffer + 1 , 3 ) ! = 3 )
2004-07-11 13:14:07 +00:00
return ( EOF ) ;
2024-03-06 19:45:10 +00:00
if ( ( buffer [ 1 ] & 0xc0 ) ! = 0x80 | | ( buffer [ 2 ] & 0xc0 ) ! = 0x80 | | ( buffer [ 3 ] & 0xc0 ) ! = 0x80 )
2004-07-11 13:14:07 +00:00
return ( EOF ) ;
2024-03-06 19:45:10 +00:00
ch = ( ( ch & 0x07 ) < < 18 ) | ( ( buffer [ 1 ] & 0x3f ) < < 12 ) | ( ( buffer [ 2 ] & 0x3f ) < < 6 ) | ( buffer [ 3 ] & 0x3f ) ;
2004-10-28 01:07:00 +00:00
if ( ch < 0x10000 )
2009-03-19 05:27:26 +00:00
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Invalid UTF-8 sequence for character 0x%04x. " , ch ) ;
2004-10-28 01:07:00 +00:00
return ( EOF ) ;
2009-03-19 05:27:26 +00:00
}
2004-07-11 13:14:07 +00:00
}
else
2024-02-27 20:04:27 +00:00
{
2004-07-11 13:14:07 +00:00
return ( EOF ) ;
2024-02-27 20:04:27 +00:00
}
2004-07-11 13:14:07 +00:00
break ;
2024-03-06 19:45:10 +00:00
case _MXML_ENCODING_UTF16BE :
2024-02-27 20:04:27 +00:00
// Read UTF-16 big-endian char...
2024-03-06 19:45:10 +00:00
if ( ( read_cb ) ( read_cbdata , buffer + 1 , 1 ) ! = 1 )
2005-01-29 17:03:33 +00:00
return ( EOF ) ;
2004-07-11 13:14:07 +00:00
2024-03-06 19:45:10 +00:00
ch = ( ch < < 8 ) | buffer [ 1 ] ;
2004-07-11 13:14:07 +00:00
2024-03-06 19:45:10 +00:00
if ( ch > = 0xd800 & & ch < = 0xdbff )
2004-07-11 13:14:07 +00:00
{
2024-02-27 20:04:27 +00:00
// Multi-word UTF-16 char...
2024-03-06 19:45:10 +00:00
int lch ; // Lower bits
2004-07-11 13:14:07 +00:00
2024-03-06 19:45:10 +00:00
if ( ( read_cb ) ( read_cbdata , buffer + 2 , 2 ) ! = 2 )
return ( EOF ) ;
2004-07-11 13:14:07 +00:00
2024-03-06 19:45:10 +00:00
lch = ( buffer [ 2 ] < < 8 ) | buffer [ 3 ] ;
2004-07-11 13:14:07 +00:00
if ( lch < 0xdc00 | | lch > = 0xdfff )
return ( EOF ) ;
ch = ( ( ( ch & 0x3ff ) < < 10 ) | ( lch & 0x3ff ) ) + 0x10000 ;
}
break ;
2003-12-21 15:01:15 +00:00
2024-03-06 19:45:10 +00:00
case _MXML_ENCODING_UTF16LE :
// Read UTF-16 little-endian char...
if ( ( read_cb ) ( read_cbdata , buffer + 1 , 1 ) ! = 1 )
2004-05-16 21:54:47 +00:00
return ( EOF ) ;
2024-03-06 19:45:10 +00:00
ch | = buffer [ 1 ] < < 8 ;
2003-12-21 15:01:15 +00:00
2024-03-06 19:45:10 +00:00
if ( ch > = 0xd800 & & ch < = 0xdbff )
2004-05-16 21:54:47 +00:00
{
2024-02-27 20:04:27 +00:00
// Multi-word UTF-16 char...
2024-03-06 19:45:10 +00:00
int lch ; // Lower bits
2003-12-21 15:01:15 +00:00
2024-03-06 19:45:10 +00:00
if ( ( read_cb ) ( read_cbdata , buffer + 2 , 2 ) ! = 2 )
2004-05-16 21:54:47 +00:00
return ( EOF ) ;
2003-12-21 15:01:15 +00:00
2024-03-06 19:45:10 +00:00
lch = ( buffer [ 3 ] < < 8 ) | buffer [ 2 ] ;
2004-05-16 21:54:47 +00:00
2004-07-11 13:14:07 +00:00
if ( lch < 0xdc00 | | lch > = 0xdfff )
2004-05-16 21:54:47 +00:00
return ( EOF ) ;
ch = ( ( ( ch & 0x3ff ) < < 10 ) | ( lch & 0x3ff ) ) + 0x10000 ;
}
break ;
2003-12-21 15:01:15 +00:00
}
2024-03-06 19:45:10 +00:00
// MXML_DEBUG("mxml_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
2004-07-11 13:14:07 +00:00
2005-01-29 17:03:33 +00:00
if ( mxml_bad_char ( ch ) )
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Bad control character 0x%02x not allowed by XML standard. " , ch ) ;
2005-01-29 17:03:33 +00:00
return ( EOF ) ;
}
2004-07-11 13:14:07 +00:00
return ( ch ) ;
}
2024-02-27 20:04:27 +00:00
//
// 'mxml_load_data()' - Load data into an XML node tree.
//
2003-06-19 03:20:41 +00:00
2024-03-06 19:45:10 +00:00
static mxml_node_t * // O - First node or `NULL` if the XML could not be read.
2007-04-23 21:48:03 +00:00
mxml_load_data (
2024-03-06 19:45:10 +00:00
mxml_read_cb_t read_cb , // I - Read callback function
void * read_cbdata , // I - Read callback data
2024-02-27 20:04:27 +00:00
mxml_node_t * top , // I - Top node
2024-03-06 19:45:10 +00:00
mxml_load_cb_t load_cb , // I - Load callback function
void * load_cbdata , // I - Load callback data
mxml_sax_cb_t sax_cb , // I - SAX callback function
void * sax_cbdata ) // I - SAX callback data
2003-06-03 19:46:29 +00:00
{
2024-02-27 20:04:27 +00:00
mxml_node_t * node = NULL , // Current node
* first = NULL , // First node added
* parent = NULL ; // Current parent node
int line = 1 , // Current line number
2024-03-02 23:47:57 +00:00
ch ; // Character from file
2024-03-06 19:45:10 +00:00
bool whitespace = false ; // Whitespace seen?
2024-02-27 20:04:27 +00:00
char * buffer , // String buffer
* bufptr ; // Pointer into buffer
2024-03-06 19:45:10 +00:00
size_t bufsize ; // Size of buffer
2024-02-27 20:04:27 +00:00
mxml_type_t type ; // Current node type
2024-03-06 19:45:10 +00:00
_mxml_encoding_t encoding = _MXML_ENCODING_UTF8 ;
// Character encoding
2007-09-21 04:46:02 +00:00
_mxml_global_t * global = _mxml_global ( ) ;
2024-02-27 20:04:27 +00:00
// Global data
static const char * const types [ ] = // Type strings...
2005-05-18 01:45:20 +00:00
{
2024-03-02 23:47:57 +00:00
" MXML_TYPE_CDATA " , // CDATA
" MXML_TYPE_COMMENT " , // Comment
" MXML_TYPE_DECLARATION " , // Declaration
" MXML_TYPE_DIRECTIVE " , // Processing instruction/directive
2024-02-27 20:04:27 +00:00
" MXML_TYPE_ELEMENT " , // XML element with attributes
" MXML_TYPE_INTEGER " , // Integer value
" MXML_TYPE_OPAQUE " , // Opaque string
" MXML_TYPE_REAL " , // Real value
" MXML_TYPE_TEXT " , // Text fragment
" MXML_TYPE_CUSTOM " // Custom data
2005-05-18 01:45:20 +00:00
} ;
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
// Read elements and other nodes from the file...
2003-06-15 21:31:45 +00:00
if ( ( buffer = malloc ( 64 ) ) = = NULL )
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Unable to allocate string buffer. " ) ;
2003-06-15 21:31:45 +00:00
return ( NULL ) ;
}
bufsize = 64 ;
2003-06-03 19:46:29 +00:00
bufptr = buffer ;
parent = top ;
2005-05-18 01:45:20 +00:00
first = NULL ;
2003-06-03 19:46:29 +00:00
2024-03-06 19:45:10 +00:00
if ( load_cb & & parent )
type = ( * load_cb ) ( load_cbdata , parent ) ;
else if ( ! load_cb & & load_cbdata )
type = * ( ( mxml_type_t * ) load_cbdata ) ;
2014-01-05 03:21:00 +00:00
else if ( parent )
2024-02-27 20:04:27 +00:00
type = MXML_TYPE_TEXT ;
2014-01-05 03:21:00 +00:00
else
2024-02-27 20:04:27 +00:00
type = MXML_TYPE_IGNORE ;
2003-06-03 19:46:29 +00:00
2024-03-06 19:45:10 +00:00
if ( ( ch = mxml_getc ( read_cb , read_cbdata , & encoding ) ) = = EOF )
2019-07-04 02:27:11 +00:00
{
2019-07-08 18:15:19 +00:00
free ( buffer ) ;
2019-07-04 02:27:11 +00:00
return ( NULL ) ;
}
else if ( ch ! = ' < ' & & ! top )
{
2019-07-08 18:15:19 +00:00
free ( buffer ) ;
2024-03-06 19:45:10 +00:00
_mxml_error ( " XML does not start with '<' (saw '%c'). " , ch ) ;
2019-07-04 02:27:11 +00:00
return ( NULL ) ;
}
do
2003-06-03 19:46:29 +00:00
{
2024-03-02 23:47:57 +00:00
if ( ( ch = = ' < ' | | ( mxml_isspace ( ch ) & & type ! = MXML_TYPE_OPAQUE & & type ! = MXML_TYPE_CUSTOM ) ) & & bufptr > buffer )
2003-06-03 19:46:29 +00:00
{
2024-02-27 20:04:27 +00:00
// Add a new value node...
2003-06-03 19:46:29 +00:00
* bufptr = ' \0 ' ;
switch ( type )
{
2024-02-27 20:04:27 +00:00
case MXML_TYPE_INTEGER :
2024-03-02 23:47:57 +00:00
node = mxmlNewInteger ( parent , strtol ( buffer , & bufptr , 0 ) ) ;
2003-06-03 19:46:29 +00:00
break ;
2024-02-27 20:04:27 +00:00
case MXML_TYPE_OPAQUE :
2003-06-03 19:46:29 +00:00
node = mxmlNewOpaque ( parent , buffer ) ;
break ;
2024-02-27 20:04:27 +00:00
case MXML_TYPE_REAL :
2003-06-04 02:34:30 +00:00
node = mxmlNewReal ( parent , strtod ( buffer , & bufptr ) ) ;
2003-06-03 19:46:29 +00:00
break ;
2024-02-27 20:04:27 +00:00
case MXML_TYPE_TEXT :
2003-06-03 19:46:29 +00:00
node = mxmlNewText ( parent , whitespace , buffer ) ;
break ;
2024-02-27 20:04:27 +00:00
case MXML_TYPE_CUSTOM :
2007-09-21 04:46:02 +00:00
if ( global - > custom_load_cb )
2004-10-28 02:58:01 +00:00
{
2024-02-27 20:04:27 +00:00
// Use the callback to fill in the custom data...
2004-10-28 02:58:01 +00:00
node = mxmlNewCustom ( parent , NULL , NULL ) ;
2024-03-03 01:02:08 +00:00
if ( ! ( * global - > custom_load_cb ) ( node , buffer ) )
2004-10-28 02:58:01 +00:00
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Bad custom value '%s' in parent <%s> on line %d. " , buffer , parent ? parent - > value . element . name : " null " , line ) ;
2004-10-28 02:58:01 +00:00
mxmlDelete ( node ) ;
node = NULL ;
}
break ;
}
2024-02-27 20:04:27 +00:00
default : // Ignore...
2003-06-03 19:46:29 +00:00
node = NULL ;
break ;
2013-11-12 05:03:47 +00:00
}
2003-06-03 19:46:29 +00:00
2003-06-04 02:34:30 +00:00
if ( * bufptr )
{
2024-02-27 20:04:27 +00:00
// Bad integer/real number value...
2024-03-06 19:45:10 +00:00
_mxml_error ( " Bad %s value '%s' in parent <%s> on line %d. " , type = = MXML_TYPE_INTEGER ? " integer " : " real " , buffer , parent ? parent - > value . element . name : " null " , line ) ;
2003-06-04 02:34:30 +00:00
break ;
}
2024-03-06 19:45:10 +00:00
MXML_DEBUG ( " mxml_load_data: node=%p(%s), parent=%p \n " , node , buffer , parent ) ;
2003-06-04 02:34:30 +00:00
bufptr = buffer ;
2024-02-27 20:04:27 +00:00
whitespace = mxml_isspace ( ch ) & & type = = MXML_TYPE_TEXT ;
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
if ( ! node & & type ! = MXML_TYPE_IGNORE )
2003-06-03 19:46:29 +00:00
{
2024-02-27 20:04:27 +00:00
// Print error and return...
2024-03-06 19:45:10 +00:00
_mxml_error ( " Unable to add value node of type %s to parent <%s> on line %d. " , types [ type ] , parent ? parent - > value . element . name : " null " , line ) ;
2005-05-18 01:45:20 +00:00
goto error ;
2003-06-03 19:46:29 +00:00
}
2005-05-18 01:45:20 +00:00
2007-04-23 21:48:03 +00:00
if ( sax_cb )
{
2024-03-06 19:45:10 +00:00
if ( ! ( sax_cb ) ( sax_cbdata , node , MXML_SAX_EVENT_DATA ) )
2024-03-04 12:37:33 +00:00
goto error ;
2007-04-23 21:48:03 +00:00
if ( ! mxmlRelease ( node ) )
node = NULL ;
}
2005-06-07 23:43:45 +00:00
if ( ! first & & node )
2005-05-18 01:45:20 +00:00
first = node ;
2003-06-03 19:46:29 +00:00
}
2024-02-27 20:04:27 +00:00
else if ( mxml_isspace ( ch ) & & type = = MXML_TYPE_TEXT )
{
2024-03-02 23:47:57 +00:00
whitespace = true ;
2024-02-27 20:04:27 +00:00
}
2003-06-04 16:30:40 +00:00
2019-01-05 17:23:17 +00:00
if ( ch = = ' \n ' )
line + + ;
2024-02-27 20:04:27 +00:00
// Add lone whitespace node if we have an element and existing whitespace...
if ( ch = = ' < ' & & whitespace & & type = = MXML_TYPE_TEXT )
2003-06-04 16:30:40 +00:00
{
2011-03-24 05:47:51 +00:00
if ( parent )
2007-04-23 21:48:03 +00:00
{
2011-03-24 05:47:51 +00:00
node = mxmlNewText ( parent , whitespace , " " ) ;
2007-04-23 21:48:03 +00:00
2011-03-24 05:47:51 +00:00
if ( sax_cb )
{
2024-03-06 19:45:10 +00:00
if ( ! ( sax_cb ) ( sax_cbdata , node , MXML_SAX_EVENT_DATA ) )
2024-03-04 12:37:33 +00:00
goto error ;
2007-04-23 21:48:03 +00:00
2011-03-24 05:47:51 +00:00
if ( ! mxmlRelease ( node ) )
node = NULL ;
}
if ( ! first & & node )
first = node ;
}
2005-08-16 14:46:18 +00:00
2024-03-02 23:47:57 +00:00
whitespace = false ;
2003-06-04 16:30:40 +00:00
}
2003-06-03 19:46:29 +00:00
if ( ch = = ' < ' )
{
2024-02-27 20:04:27 +00:00
// Start of open/close tag...
2003-06-03 19:46:29 +00:00
bufptr = buffer ;
2024-03-06 19:45:10 +00:00
while ( ( ch = mxml_getc ( read_cb , read_cbdata , & encoding ) ) ! = EOF )
2019-01-05 17:23:17 +00:00
{
2007-09-09 07:27:08 +00:00
if ( mxml_isspace ( ch ) | | ch = = ' > ' | | ( ch = = ' / ' & & bufptr > buffer ) )
2024-02-27 20:04:27 +00:00
{
2003-06-03 19:46:29 +00:00
break ;
2024-02-27 20:04:27 +00:00
}
2007-04-18 02:45:47 +00:00
else if ( ch = = ' < ' )
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Bare < in element. " ) ;
2007-04-18 02:45:47 +00:00
goto error ;
}
2003-12-21 15:01:15 +00:00
else if ( ch = = ' & ' )
2003-06-04 16:30:40 +00:00
{
2024-03-06 19:45:10 +00:00
if ( ( ch = mxml_get_entity ( read_cb , read_cbdata , & encoding , parent , & line ) ) = = EOF )
2003-12-21 15:01:15 +00:00
goto error ;
2024-03-06 19:45:10 +00:00
if ( ! mxml_add_char ( ch , & bufptr , & buffer , & bufsize ) )
2003-12-21 15:01:15 +00:00
goto error ;
2003-06-15 21:31:45 +00:00
}
2016-06-13 00:51:16 +00:00
else if ( ch < ' 0 ' & & ch ! = ' ! ' & & ch ! = ' - ' & & ch ! = ' . ' & & ch ! = ' / ' )
2024-02-27 20:04:27 +00:00
{
2016-06-13 00:51:16 +00:00
goto error ;
2024-02-27 20:04:27 +00:00
}
2024-03-06 19:45:10 +00:00
else if ( ! mxml_add_char ( ch , & bufptr , & buffer , & bufsize ) )
2024-02-27 20:04:27 +00:00
{
2003-12-21 15:01:15 +00:00
goto error ;
2024-02-27 20:04:27 +00:00
}
else if ( ( ( bufptr - buffer ) = = 1 & & buffer [ 0 ] = = ' ? ' ) | | ( ( bufptr - buffer ) = = 3 & & ! strncmp ( buffer , " !-- " , 3 ) ) | | ( ( bufptr - buffer ) = = 8 & & ! strncmp ( buffer , " ![CDATA[ " , 8 ) ) )
{
2003-06-15 21:31:45 +00:00
break ;
2024-02-27 20:04:27 +00:00
}
2003-06-04 16:30:40 +00:00
2019-01-05 17:23:17 +00:00
if ( ch = = ' \n ' )
line + + ;
}
2003-06-03 19:46:29 +00:00
* bufptr = ' \0 ' ;
2019-07-08 18:15:19 +00:00
if ( ! strcmp ( buffer , " !-- " ) )
2003-06-04 01:23:21 +00:00
{
2024-02-27 20:04:27 +00:00
// Gather rest of comment...
2024-03-06 19:45:10 +00:00
while ( ( ch = mxml_getc ( read_cb , read_cbdata , & encoding ) ) ! = EOF )
2003-06-04 01:23:21 +00:00
{
2024-02-27 20:04:27 +00:00
if ( ch = = ' > ' & & bufptr > ( buffer + 4 ) & & bufptr [ - 3 ] ! = ' - ' & & bufptr [ - 2 ] = = ' - ' & & bufptr [ - 1 ] = = ' - ' )
2003-06-04 16:30:40 +00:00
break ;
2024-03-06 19:45:10 +00:00
else if ( ! mxml_add_char ( ch , & bufptr , & buffer , & bufsize ) )
2005-01-29 07:19:38 +00:00
goto error ;
2019-01-05 17:23:17 +00:00
if ( ch = = ' \n ' )
line + + ;
2005-01-29 07:19:38 +00:00
}
2003-12-21 15:01:15 +00:00
2024-02-27 20:04:27 +00:00
// Error out if we didn't get the whole comment...
2005-01-29 07:19:38 +00:00
if ( ch ! = ' > ' )
2005-05-18 01:45:20 +00:00
{
2024-02-27 20:04:27 +00:00
// Print error and return...
2024-03-06 19:45:10 +00:00
_mxml_error ( " Early EOF in comment node on line %d. " , line ) ;
2005-05-18 01:45:20 +00:00
goto error ;
}
2024-02-27 20:04:27 +00:00
// Otherwise add this as an element under the current parent...
2024-03-02 23:47:57 +00:00
bufptr [ - 2 ] = ' \0 ' ;
2005-01-29 07:19:38 +00:00
2010-09-19 06:14:36 +00:00
if ( ! parent & & first )
{
2024-02-27 20:04:27 +00:00
// There can only be one root element!
2024-03-06 19:45:10 +00:00
_mxml_error ( " <%s--> cannot be a second root node after <%s> on line %d. " , buffer , first - > value . element . name , line ) ;
2013-11-12 05:03:47 +00:00
goto error ;
2010-09-19 06:14:36 +00:00
}
2024-03-02 23:47:57 +00:00
if ( ( node = mxmlNewComment ( parent , buffer + 3 ) ) = = NULL )
2005-01-29 07:19:38 +00:00
{
2024-02-27 20:04:27 +00:00
// Just print error for now...
2024-03-06 19:45:10 +00:00
_mxml_error ( " Unable to add comment node to parent <%s> on line %d. " , parent ? parent - > value . element . name : " null " , line ) ;
2005-01-29 07:19:38 +00:00
break ;
}
2005-08-16 14:46:18 +00:00
2024-03-06 19:45:10 +00:00
MXML_DEBUG ( " mxml_load_data: node=%p(<%s-->), parent=%p \n " , node , buffer , parent ) ;
2007-04-23 21:48:03 +00:00
if ( sax_cb )
{
2024-03-06 19:45:10 +00:00
if ( ! ( sax_cb ) ( sax_cbdata , node , MXML_SAX_EVENT_COMMENT ) )
2024-03-04 12:37:33 +00:00
goto error ;
2007-04-23 21:48:03 +00:00
if ( ! mxmlRelease ( node ) )
node = NULL ;
}
2007-09-15 20:03:15 +00:00
if ( node & & ! first )
2005-08-16 14:46:18 +00:00
first = node ;
2005-01-29 07:19:38 +00:00
}
else if ( ! strcmp ( buffer , " ![CDATA[ " ) )
{
2024-02-27 20:04:27 +00:00
// Gather CDATA section...
2024-03-06 19:45:10 +00:00
while ( ( ch = mxml_getc ( read_cb , read_cbdata , & encoding ) ) ! = EOF )
2005-01-29 07:19:38 +00:00
{
if ( ch = = ' > ' & & ! strncmp ( bufptr - 2 , " ]] " , 2 ) )
2017-03-30 01:42:30 +00:00
{
2024-02-27 20:04:27 +00:00
// Drop terminator from CDATA string...
2017-03-30 01:42:30 +00:00
bufptr [ - 2 ] = ' \0 ' ;
2005-01-29 07:19:38 +00:00
break ;
2017-03-30 01:42:30 +00:00
}
2024-03-06 19:45:10 +00:00
else if ( ! mxml_add_char ( ch , & bufptr , & buffer , & bufsize ) )
2024-02-27 20:04:27 +00:00
{
2005-01-29 07:19:38 +00:00
goto error ;
2024-02-27 20:04:27 +00:00
}
2019-01-05 17:23:17 +00:00
if ( ch = = ' \n ' )
line + + ;
2003-06-04 16:30:40 +00:00
}
2003-06-04 01:23:21 +00:00
2024-02-27 20:04:27 +00:00
// Error out if we didn't get the whole comment...
2003-06-04 16:30:40 +00:00
if ( ch ! = ' > ' )
2005-05-18 01:45:20 +00:00
{
2024-02-27 20:04:27 +00:00
// Print error and return...
2024-03-06 19:45:10 +00:00
_mxml_error ( " Early EOF in CDATA node on line %d. " , line ) ;
2005-05-18 01:45:20 +00:00
goto error ;
}
2024-02-27 20:04:27 +00:00
// Otherwise add this as an element under the current parent...
2024-03-02 23:47:57 +00:00
bufptr [ - 2 ] = ' \0 ' ;
2003-06-04 16:30:40 +00:00
2010-09-19 06:14:36 +00:00
if ( ! parent & & first )
{
2024-02-27 20:04:27 +00:00
// There can only be one root element!
2024-03-06 19:45:10 +00:00
_mxml_error ( " <%s]]> cannot be a second root node after <%s> on line %d. " , buffer , first - > value . element . name , line ) ;
2013-11-12 05:03:47 +00:00
goto error ;
2010-09-19 06:14:36 +00:00
}
2024-03-02 23:47:57 +00:00
if ( ( node = mxmlNewCDATA ( parent , buffer + 8 ) ) = = NULL )
2003-06-04 16:30:40 +00:00
{
2024-02-27 20:04:27 +00:00
// Print error and return...
2024-03-06 19:45:10 +00:00
_mxml_error ( " Unable to add CDATA node to parent <%s> on line %d. " , parent ? parent - > value . element . name : " null " , line ) ;
2005-05-18 01:45:20 +00:00
goto error ;
2003-06-04 16:30:40 +00:00
}
2005-08-16 14:46:18 +00:00
2024-03-06 19:45:10 +00:00
MXML_DEBUG ( " mxml_load_data: node=%p(<%s]]>), parent=%p \n " , node , buffer , parent ) ;
2007-04-23 21:48:03 +00:00
if ( sax_cb )
{
2024-03-06 19:45:10 +00:00
if ( ! ( sax_cb ) ( sax_cbdata , node , MXML_SAX_EVENT_CDATA ) )
2024-03-04 12:37:33 +00:00
goto error ;
2007-04-23 21:48:03 +00:00
if ( ! mxmlRelease ( node ) )
node = NULL ;
}
2007-09-15 20:03:15 +00:00
if ( node & & ! first )
2005-08-16 14:46:18 +00:00
first = node ;
2003-06-04 16:30:40 +00:00
}
2005-01-29 07:19:38 +00:00
else if ( buffer [ 0 ] = = ' ? ' )
{
2024-02-27 20:04:27 +00:00
// Gather rest of processing instruction...
2024-03-06 19:45:10 +00:00
while ( ( ch = mxml_getc ( read_cb , read_cbdata , & encoding ) ) ! = EOF )
2005-01-29 07:19:38 +00:00
{
if ( ch = = ' > ' & & bufptr > buffer & & bufptr [ - 1 ] = = ' ? ' )
break ;
2024-03-06 19:45:10 +00:00
else if ( ! mxml_add_char ( ch , & bufptr , & buffer , & bufsize ) )
2005-01-29 07:19:38 +00:00
goto error ;
2019-01-05 17:23:17 +00:00
if ( ch = = ' \n ' )
line + + ;
2005-01-29 07:19:38 +00:00
}
2024-02-27 20:04:27 +00:00
// Error out if we didn't get the whole processing instruction...
2005-01-29 07:19:38 +00:00
if ( ch ! = ' > ' )
2005-05-18 01:45:20 +00:00
{
2024-02-27 20:04:27 +00:00
// Print error and return...
2024-03-06 19:45:10 +00:00
_mxml_error ( " Early EOF in processing instruction node on line %d. " , line ) ;
2005-05-18 01:45:20 +00:00
goto error ;
}
2024-02-27 20:04:27 +00:00
// Otherwise add this as an element under the current parent...
2024-03-02 23:47:57 +00:00
bufptr [ - 1 ] = ' \0 ' ;
2005-01-29 07:19:38 +00:00
2019-07-08 18:15:19 +00:00
if ( ! parent & & first )
2010-09-19 06:14:36 +00:00
{
2024-02-27 20:04:27 +00:00
// There can only be one root element!
2024-03-06 19:45:10 +00:00
_mxml_error ( " <%s?> cannot be a second root node after <%s> on line %d. " , buffer , first - > value . element . name , line ) ;
2013-11-12 05:03:47 +00:00
goto error ;
2010-09-19 06:14:36 +00:00
}
2024-03-02 23:47:57 +00:00
if ( ( node = mxmlNewDirective ( parent , buffer + 1 ) ) = = NULL )
2005-01-29 07:19:38 +00:00
{
2024-02-27 20:04:27 +00:00
// Print error and return...
2024-03-06 19:45:10 +00:00
_mxml_error ( " Unable to add processing instruction node to parent <%s> on line %d. " , parent ? parent - > value . element . name : " null " , line ) ;
2005-05-18 01:45:20 +00:00
goto error ;
2005-01-29 07:19:38 +00:00
}
2024-03-06 19:45:10 +00:00
MXML_DEBUG ( " mxml_load_data: node=%p(<%s?>), parent=%p \n " , node , buffer , parent ) ;
2007-04-23 21:48:03 +00:00
if ( sax_cb )
{
2024-03-06 19:45:10 +00:00
if ( ! ( sax_cb ) ( sax_cbdata , node , MXML_SAX_EVENT_DIRECTIVE ) )
2024-03-04 12:37:33 +00:00
goto error ;
2005-08-16 14:46:18 +00:00
2024-03-02 23:47:57 +00:00
if ( strncmp ( node - > value . directive , " xml " , 4 ) & & ! mxmlRelease ( node ) )
2007-04-23 21:48:03 +00:00
node = NULL ;
}
if ( node )
2007-09-15 20:03:15 +00:00
{
if ( ! first )
2008-01-13 00:42:35 +00:00
first = node ;
2007-04-23 21:48:03 +00:00
2008-01-13 00:42:35 +00:00
if ( ! parent )
{
parent = node ;
2007-04-23 21:48:03 +00:00
2024-03-06 19:45:10 +00:00
if ( load_cb )
type = ( load_cb ) ( load_cbdata , parent ) ;
else if ( load_cbdata )
type = * ( ( mxml_type_t * ) load_cbdata ) ;
2014-10-19 17:21:48 +00:00
else
2024-02-27 20:04:27 +00:00
type = MXML_TYPE_TEXT ;
2008-01-13 00:42:35 +00:00
}
}
2005-01-29 07:19:38 +00:00
}
2003-06-04 16:30:40 +00:00
else if ( buffer [ 0 ] = = ' ! ' )
{
2024-02-27 20:04:27 +00:00
// Gather rest of declaration...
2003-06-04 16:30:40 +00:00
do
{
if ( ch = = ' > ' )
2024-02-27 20:04:27 +00:00
{
2003-06-04 16:30:40 +00:00
break ;
2024-02-27 20:04:27 +00:00
}
2003-12-21 15:01:15 +00:00
else
2003-06-04 16:30:40 +00:00
{
2003-12-21 15:01:15 +00:00
if ( ch = = ' & ' )
2019-01-05 17:23:17 +00:00
{
2024-03-06 19:45:10 +00:00
if ( ( ch = mxml_get_entity ( read_cb , read_cbdata , & encoding , parent , & line ) ) = = EOF )
2003-12-21 15:01:15 +00:00
goto error ;
2019-01-05 17:23:17 +00:00
}
2003-12-21 15:01:15 +00:00
2024-03-06 19:45:10 +00:00
if ( ! mxml_add_char ( ch , & bufptr , & buffer , & bufsize ) )
2003-12-21 15:01:15 +00:00
goto error ;
2003-06-04 01:23:21 +00:00
}
2019-01-05 17:23:17 +00:00
if ( ch = = ' \n ' )
line + + ;
2003-06-04 01:23:21 +00:00
}
2024-03-06 19:45:10 +00:00
while ( ( ch = mxml_getc ( read_cb , read_cbdata , & encoding ) ) ! = EOF ) ;
2003-06-04 01:23:21 +00:00
2024-02-27 20:04:27 +00:00
// Error out if we didn't get the whole declaration...
2003-06-04 16:30:40 +00:00
if ( ch ! = ' > ' )
2005-05-18 01:45:20 +00:00
{
2024-02-27 20:04:27 +00:00
// Print error and return...
2024-03-06 19:45:10 +00:00
_mxml_error ( " Early EOF in declaration node on line %d. " , line ) ;
2005-05-18 01:45:20 +00:00
goto error ;
}
2003-06-04 16:30:40 +00:00
2024-02-27 20:04:27 +00:00
// Otherwise add this as an element under the current parent...
2003-06-04 16:30:40 +00:00
* bufptr = ' \0 ' ;
2010-09-19 06:14:36 +00:00
if ( ! parent & & first )
{
2024-02-27 20:04:27 +00:00
// There can only be one root element!
2024-03-06 19:45:10 +00:00
_mxml_error ( " <%s> cannot be a second root node after <%s> on line %d. " , buffer , first - > value . element . name , line ) ;
2013-11-12 05:03:47 +00:00
goto error ;
2010-09-19 06:14:36 +00:00
}
2024-03-02 23:47:57 +00:00
if ( ( node = mxmlNewDeclaration ( parent , buffer + 1 ) ) = = NULL )
2003-06-04 16:30:40 +00:00
{
2024-02-27 20:04:27 +00:00
// Print error and return...
2024-03-06 19:45:10 +00:00
_mxml_error ( " Unable to add declaration node to parent <%s> on line %d. " , parent ? parent - > value . element . name : " null " , line ) ;
2005-05-18 01:45:20 +00:00
goto error ;
2003-06-04 16:30:40 +00:00
}
2024-03-06 19:45:10 +00:00
MXML_DEBUG ( " mxml_load_data: node=%p(<%s>), parent=%p \n " , node , buffer , parent ) ;
2007-04-23 21:48:03 +00:00
if ( sax_cb )
{
2024-03-06 19:45:10 +00:00
if ( ! ( sax_cb ) ( sax_cbdata , node , MXML_SAX_EVENT_DECLARATION ) )
2024-03-04 12:37:33 +00:00
goto error ;
2005-08-16 14:46:18 +00:00
2007-04-23 21:48:03 +00:00
if ( ! mxmlRelease ( node ) )
node = NULL ;
}
2003-06-04 16:30:40 +00:00
2008-01-13 00:42:35 +00:00
if ( node )
{
if ( ! first )
first = node ;
if ( ! parent )
{
parent = node ;
2024-03-06 19:45:10 +00:00
if ( load_cb )
type = ( load_cb ) ( load_cbdata , parent ) ;
else if ( load_cbdata )
type = * ( ( mxml_type_t * ) load_cbdata ) ;
2014-10-19 17:21:48 +00:00
else
2024-02-27 20:04:27 +00:00
type = MXML_TYPE_TEXT ;
2008-01-13 00:42:35 +00:00
}
}
2003-06-04 01:23:21 +00:00
}
else if ( buffer [ 0 ] = = ' / ' )
2003-06-03 19:46:29 +00:00
{
2024-02-27 20:04:27 +00:00
// Handle close tag...
2024-03-06 19:45:10 +00:00
MXML_DEBUG ( " mxml_load_data: <%s>, parent=%p \n " , buffer , parent ) ;
2003-06-03 19:46:29 +00:00
if ( ! parent | | strcmp ( buffer + 1 , parent - > value . element . name ) )
{
2024-02-27 20:04:27 +00:00
// Close tag doesn't match tree; print an error for now...
2024-03-06 19:45:10 +00:00
_mxml_error ( " Mismatched close tag <%s> under parent <%s> on line %d. " , buffer , parent ? parent - > value . element . name : " (null) " , line ) ;
2005-05-18 01:45:20 +00:00
goto error ;
2003-06-03 19:46:29 +00:00
}
2024-02-27 20:04:27 +00:00
// Keep reading until we see >...
2003-06-03 19:46:29 +00:00
while ( ch ! = ' > ' & & ch ! = EOF )
2024-03-06 19:45:10 +00:00
ch = mxml_getc ( read_cb , read_cbdata , & encoding ) ;
2003-06-03 19:46:29 +00:00
2007-04-23 21:48:03 +00:00
node = parent ;
parent = parent - > parent ;
if ( sax_cb )
{
2024-03-06 19:45:10 +00:00
if ( ! ( sax_cb ) ( sax_cbdata , node , MXML_SAX_EVENT_ELEMENT_CLOSE ) )
2024-03-04 12:37:33 +00:00
goto error ;
2007-04-23 21:48:03 +00:00
2021-10-26 18:34:33 +00:00
if ( ! mxmlRelease ( node ) )
{
if ( first = = node )
first = NULL ;
node = NULL ;
}
2007-04-23 21:48:03 +00:00
}
2024-02-27 20:04:27 +00:00
// Ascend into the parent and set the value type as needed...
2024-03-06 19:45:10 +00:00
if ( load_cb & & parent )
type = ( load_cb ) ( load_cbdata , parent ) ;
else if ( ! load_cb & & load_cbdata )
type = * ( ( mxml_type_t * ) load_cbdata ) ;
2003-06-03 19:46:29 +00:00
}
else
{
2024-02-27 20:04:27 +00:00
// Handle open tag...
2010-09-19 06:14:36 +00:00
if ( ! parent & & first )
{
2024-02-27 20:04:27 +00:00
// There can only be one root element!
2024-03-06 19:45:10 +00:00
_mxml_error ( " <%s> cannot be a second root node after <%s> on line %d. " , buffer , first - > value . element . name , line ) ;
2013-11-12 05:03:47 +00:00
goto error ;
2010-09-19 06:14:36 +00:00
}
2005-08-16 14:46:18 +00:00
if ( ( node = mxmlNewElement ( parent , buffer ) ) = = NULL )
2003-06-03 19:46:29 +00:00
{
2024-02-27 20:04:27 +00:00
// Just print error for now...
2024-03-06 19:45:10 +00:00
_mxml_error ( " Unable to add element node to parent <%s> on line %d. " , parent ? parent - > value . element . name : " null " , line ) ;
2005-05-18 01:45:20 +00:00
goto error ;
2003-06-03 19:46:29 +00:00
}
2007-09-09 07:27:08 +00:00
if ( mxml_isspace ( ch ) )
2007-09-09 08:11:25 +00:00
{
2024-03-06 19:45:10 +00:00
MXML_DEBUG ( " mxml_load_data: node=%p(<%s...>), parent=%p \n " , node , buffer , parent ) ;
if ( ( ch = mxml_parse_element ( read_cb , read_cbdata , node , & encoding , & line ) ) = = EOF )
2007-09-09 08:11:25 +00:00
goto error ;
}
2003-06-03 19:46:29 +00:00
else if ( ch = = ' / ' )
{
2024-03-06 19:45:10 +00:00
MXML_DEBUG ( " mxml_load_data: node=%p(<%s/>), parent=%p \n " , node , buffer , parent ) ;
if ( ( ch = mxml_getc ( read_cb , read_cbdata , & encoding ) ) ! = ' > ' )
2003-06-03 19:46:29 +00:00
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Expected > but got '%c' instead for element <%s/> on line %d. " , ch , buffer , line ) ;
2005-08-16 14:46:18 +00:00
mxmlDelete ( node ) ;
2021-10-26 18:34:33 +00:00
node = NULL ;
2005-05-18 01:45:20 +00:00
goto error ;
2003-06-03 19:46:29 +00:00
}
ch = ' / ' ;
}
2007-04-23 21:48:03 +00:00
if ( sax_cb )
2024-03-04 12:37:33 +00:00
{
2024-03-06 19:45:10 +00:00
if ( ! ( sax_cb ) ( sax_cbdata , node , MXML_SAX_EVENT_ELEMENT_OPEN ) )
2024-03-04 12:37:33 +00:00
goto error ;
}
2007-04-23 21:48:03 +00:00
if ( ! first )
first = node ;
2003-06-03 19:46:29 +00:00
if ( ch = = EOF )
break ;
if ( ch ! = ' / ' )
{
2024-02-27 20:04:27 +00:00
// Descend into this node, setting the value type as needed...
2003-06-03 19:46:29 +00:00
parent = node ;
2024-03-06 19:45:10 +00:00
if ( load_cb & & parent )
type = ( load_cb ) ( load_cbdata , parent ) ;
else if ( ! load_cb & & load_cbdata )
type = * ( ( mxml_type_t * ) load_cbdata ) ;
2016-06-13 00:27:11 +00:00
else
2024-02-27 20:04:27 +00:00
type = MXML_TYPE_TEXT ;
2003-06-03 19:46:29 +00:00
}
2007-04-23 21:48:03 +00:00
else if ( sax_cb )
{
2024-03-06 19:45:10 +00:00
if ( ! ( sax_cb ) ( sax_cbdata , node , MXML_SAX_EVENT_ELEMENT_CLOSE ) )
2024-03-04 12:37:33 +00:00
goto error ;
2007-04-23 21:48:03 +00:00
2021-10-26 18:34:33 +00:00
if ( ! mxmlRelease ( node ) )
{
if ( first = = node )
first = NULL ;
node = NULL ;
}
2007-04-23 21:48:03 +00:00
}
2003-06-03 19:46:29 +00:00
}
2003-06-04 16:30:40 +00:00
bufptr = buffer ;
2003-06-03 19:46:29 +00:00
}
else if ( ch = = ' & ' )
{
2024-02-27 20:04:27 +00:00
// Add character entity to current buffer...
2024-03-06 19:45:10 +00:00
if ( ( ch = mxml_get_entity ( read_cb , read_cbdata , & encoding , parent , & line ) ) = = EOF )
2003-12-21 15:01:15 +00:00
goto error ;
2003-06-03 19:46:29 +00:00
2024-03-06 19:45:10 +00:00
if ( ! mxml_add_char ( ch , & bufptr , & buffer , & bufsize ) )
2003-12-21 15:01:15 +00:00
goto error ;
2003-06-03 19:46:29 +00:00
}
2024-02-27 20:04:27 +00:00
else if ( type = = MXML_TYPE_OPAQUE | | type = = MXML_TYPE_CUSTOM | | ! mxml_isspace ( ch ) )
2003-06-03 19:46:29 +00:00
{
2024-02-27 20:04:27 +00:00
// Add character to current buffer...
2024-03-06 19:45:10 +00:00
if ( ! mxml_add_char ( ch , & bufptr , & buffer , & bufsize ) )
2003-12-21 15:01:15 +00:00
goto error ;
2003-06-03 19:46:29 +00:00
}
}
2024-03-06 19:45:10 +00:00
while ( ( ch = mxml_getc ( read_cb , read_cbdata , & encoding ) ) ! = EOF ) ;
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
// Free the string buffer - we don't need it anymore...
2003-06-15 21:31:45 +00:00
free ( buffer ) ;
2024-02-27 20:04:27 +00:00
// Find the top element and return it...
2003-06-03 19:46:29 +00:00
if ( parent )
{
2007-04-18 02:37:01 +00:00
node = parent ;
2014-01-05 03:28:03 +00:00
while ( parent ! = top & & parent - > parent )
2003-06-03 19:46:29 +00:00
parent = parent - > parent ;
2007-04-18 02:37:01 +00:00
if ( node ! = parent )
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Missing close tag </%s> under parent <%s> on line %d. " , mxmlGetElement ( node ) , node - > parent ? node - > parent - > value . element . name : " (null) " , line ) ;
2007-04-18 02:37:01 +00:00
mxmlDelete ( first ) ;
return ( NULL ) ;
}
2003-06-03 19:46:29 +00:00
}
2007-09-15 20:03:15 +00:00
if ( parent )
return ( parent ) ;
else
return ( first ) ;
2003-12-21 15:01:15 +00:00
2024-02-27 20:04:27 +00:00
// Common error return...
2019-01-05 17:23:17 +00:00
error :
2003-12-21 15:01:15 +00:00
2005-05-18 01:45:20 +00:00
mxmlDelete ( first ) ;
2003-12-21 15:01:15 +00:00
free ( buffer ) ;
return ( NULL ) ;
2003-06-03 19:46:29 +00:00
}
2024-02-27 20:04:27 +00:00
//
// 'mxml_parse_element()' - Parse an element for any attributes...
//
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
static int // O - Terminating character
2007-04-23 21:48:03 +00:00
mxml_parse_element (
2024-03-06 19:45:10 +00:00
mxml_read_cb_t read_cb , // I - Read callback function
void * read_cbdata , // I - Read callback data
mxml_node_t * node , // I - Element node
_mxml_encoding_t * encoding , // IO - Encoding
int * line ) // IO - Current line number
2003-06-03 19:46:29 +00:00
{
2024-03-06 19:45:10 +00:00
int ch , // Current character in file
quote ; // Quoting character
char * name , // Attribute name
* value , // Attribute value
* ptr ; // Pointer into name/value
size_t namesize , // Size of name string
valsize ; // Size of value string
2003-12-19 02:56:11 +00:00
2024-02-27 20:04:27 +00:00
// Initialize the name and value buffers...
2003-06-15 21:31:45 +00:00
if ( ( name = malloc ( 64 ) ) = = NULL )
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Unable to allocate memory for name. " ) ;
2003-06-15 21:31:45 +00:00
return ( EOF ) ;
}
namesize = 64 ;
if ( ( value = malloc ( 64 ) ) = = NULL )
{
free ( name ) ;
2024-03-06 19:45:10 +00:00
_mxml_error ( " Unable to allocate memory for value. " ) ;
2003-06-15 21:31:45 +00:00
return ( EOF ) ;
}
valsize = 64 ;
2024-02-27 20:04:27 +00:00
// Loop until we hit a >, /, ?, or EOF...
2024-03-06 19:45:10 +00:00
while ( ( ch = mxml_getc ( read_cb , read_cbdata , encoding ) ) ! = EOF )
2003-06-03 19:46:29 +00:00
{
2024-03-06 19:45:10 +00:00
MXML_DEBUG ( " mxml_parse_element: ch='%c' \n " , ch ) ;
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
// Skip leading whitespace...
2007-09-09 07:27:08 +00:00
if ( mxml_isspace ( ch ) )
2019-01-05 17:23:17 +00:00
{
if ( ch = = ' \n ' )
( * line ) + + ;
2003-06-03 19:46:29 +00:00
continue ;
2019-01-05 17:23:17 +00:00
}
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
// Stop at /, ?, or >...
2003-06-03 19:46:29 +00:00
if ( ch = = ' / ' | | ch = = ' ? ' )
{
2024-02-27 20:04:27 +00:00
// Grab the > character and print an error if it isn't there...
2024-03-06 19:45:10 +00:00
quote = mxml_getc ( read_cb , read_cbdata , encoding ) ;
2003-06-03 19:46:29 +00:00
if ( quote ! = ' > ' )
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Expected '>' after '%c' for element %s, but got '%c' on line %d. " , ch , mxmlGetElement ( node ) , quote , * line ) ;
2007-04-18 02:45:47 +00:00
goto error ;
2003-06-03 19:46:29 +00:00
}
break ;
}
2007-04-18 02:45:47 +00:00
else if ( ch = = ' < ' )
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Bare < in element %s on line %d. " , mxmlGetElement ( node ) , * line ) ;
2007-04-18 02:45:47 +00:00
goto error ;
}
2003-06-03 19:46:29 +00:00
else if ( ch = = ' > ' )
2024-02-27 20:04:27 +00:00
{
2003-06-03 19:46:29 +00:00
break ;
2024-02-27 20:04:27 +00:00
}
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
// Read the attribute name...
2020-10-02 20:36:19 +00:00
ptr = name ;
2024-03-06 19:45:10 +00:00
if ( ! mxml_add_char ( ch , & ptr , & name , & namesize ) )
2020-10-02 20:36:19 +00:00
goto error ;
2003-06-03 19:46:29 +00:00
2003-12-01 15:27:47 +00:00
if ( ch = = ' \" ' | | ch = = ' \' ' )
{
2024-02-27 20:04:27 +00:00
// Name is in quotes, so get a quoted string...
2003-12-01 15:27:47 +00:00
quote = ch ;
2024-03-06 19:45:10 +00:00
while ( ( ch = mxml_getc ( read_cb , read_cbdata , encoding ) ) ! = EOF )
2003-06-03 19:46:29 +00:00
{
2003-12-21 15:01:15 +00:00
if ( ch = = ' & ' )
2019-01-05 17:23:17 +00:00
{
2024-03-06 19:45:10 +00:00
if ( ( ch = mxml_get_entity ( read_cb , read_cbdata , encoding , node , line ) ) = = EOF )
2003-12-21 15:01:15 +00:00
goto error ;
2019-01-05 17:23:17 +00:00
}
else if ( ch = = ' \n ' )
2024-02-27 20:04:27 +00:00
{
2019-01-05 17:23:17 +00:00
( * line ) + + ;
2024-02-27 20:04:27 +00:00
}
2003-12-21 15:01:15 +00:00
2024-03-06 19:45:10 +00:00
if ( ! mxml_add_char ( ch , & ptr , & name , & namesize ) )
2003-12-21 15:01:15 +00:00
goto error ;
2003-12-01 15:27:47 +00:00
if ( ch = = quote )
break ;
2003-06-03 19:46:29 +00:00
}
2003-12-01 15:27:47 +00:00
}
else
{
2024-02-27 20:04:27 +00:00
// Grab an normal, non-quoted name...
2024-03-06 19:45:10 +00:00
while ( ( ch = mxml_getc ( read_cb , read_cbdata , encoding ) ) ! = EOF )
2019-01-05 17:23:17 +00:00
{
2024-02-27 20:04:27 +00:00
if ( mxml_isspace ( ch ) | | ch = = ' = ' | | ch = = ' / ' | | ch = = ' > ' | | ch = = ' ? ' )
2019-01-05 17:23:17 +00:00
{
if ( ch = = ' \n ' )
( * line ) + + ;
2003-12-01 15:27:47 +00:00
break ;
2019-01-05 17:23:17 +00:00
}
2003-12-21 15:01:15 +00:00
else
2003-12-01 15:27:47 +00:00
{
2003-12-21 15:01:15 +00:00
if ( ch = = ' & ' )
2019-01-05 17:23:17 +00:00
{
2024-03-06 19:45:10 +00:00
if ( ( ch = mxml_get_entity ( read_cb , read_cbdata , encoding , node , line ) ) = = EOF )
2003-12-21 15:01:15 +00:00
goto error ;
2019-01-05 17:23:17 +00:00
}
2003-12-21 15:01:15 +00:00
2024-03-06 19:45:10 +00:00
if ( ! mxml_add_char ( ch , & ptr , & name , & namesize ) )
2003-12-21 15:01:15 +00:00
goto error ;
2003-12-01 15:27:47 +00:00
}
2019-01-05 17:23:17 +00:00
}
2003-12-01 15:27:47 +00:00
}
2003-06-03 19:46:29 +00:00
* ptr = ' \0 ' ;
2005-01-29 17:03:33 +00:00
if ( mxmlElementGetAttr ( node , name ) )
2019-01-05 17:23:17 +00:00
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Duplicate attribute '%s' in element %s on line %d. " , name , mxmlGetElement ( node ) , * line ) ;
2005-01-29 17:03:33 +00:00
goto error ;
2019-01-05 17:23:17 +00:00
}
2005-01-29 17:03:33 +00:00
2008-01-13 00:42:35 +00:00
while ( ch ! = EOF & & mxml_isspace ( ch ) )
2019-01-05 17:23:17 +00:00
{
2024-03-06 19:45:10 +00:00
ch = mxml_getc ( read_cb , read_cbdata , encoding ) ;
2008-01-13 00:42:35 +00:00
2019-01-05 17:23:17 +00:00
if ( ch = = ' \n ' )
( * line ) + + ;
}
2003-06-03 19:46:29 +00:00
if ( ch = = ' = ' )
{
2024-02-27 20:04:27 +00:00
// Read the attribute value...
2024-03-06 19:45:10 +00:00
while ( ( ch = mxml_getc ( read_cb , read_cbdata , encoding ) ) ! = EOF & & mxml_isspace ( ch ) )
2019-01-05 17:23:17 +00:00
{
if ( ch = = ' \n ' )
( * line ) + + ;
}
2008-01-13 00:42:35 +00:00
if ( ch = = EOF )
2003-06-03 19:46:29 +00:00
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Missing value for attribute '%s' in element %s on line %d. " , name , mxmlGetElement ( node ) , * line ) ;
2007-09-09 08:22:12 +00:00
goto error ;
2003-06-03 19:46:29 +00:00
}
if ( ch = = ' \' ' | | ch = = ' \" ' )
{
2024-02-27 20:04:27 +00:00
// Read quoted value...
2003-06-03 19:46:29 +00:00
quote = ch ;
ptr = value ;
2024-03-06 19:45:10 +00:00
while ( ( ch = mxml_getc ( read_cb , read_cbdata , encoding ) ) ! = EOF )
2019-01-05 17:23:17 +00:00
{
2003-06-03 19:46:29 +00:00
if ( ch = = quote )
2019-01-05 17:23:17 +00:00
{
2003-06-03 19:46:29 +00:00
break ;
2019-01-05 17:23:17 +00:00
}
2003-12-21 15:01:15 +00:00
else
2003-06-03 19:46:29 +00:00
{
2003-12-21 15:01:15 +00:00
if ( ch = = ' & ' )
2019-01-05 17:23:17 +00:00
{
2024-03-06 19:45:10 +00:00
if ( ( ch = mxml_get_entity ( read_cb , read_cbdata , encoding , node , line ) ) = = EOF )
2003-12-21 15:01:15 +00:00
goto error ;
2019-01-05 17:23:17 +00:00
}
else if ( ch = = ' \n ' )
2024-02-27 20:04:27 +00:00
{
2019-01-05 17:23:17 +00:00
( * line ) + + ;
2024-02-27 20:04:27 +00:00
}
2013-11-12 05:03:47 +00:00
2024-03-06 19:45:10 +00:00
if ( ! mxml_add_char ( ch , & ptr , & value , & valsize ) )
2003-12-21 15:01:15 +00:00
goto error ;
2003-06-03 19:46:29 +00:00
}
2019-01-05 17:23:17 +00:00
}
2003-06-03 19:46:29 +00:00
* ptr = ' \0 ' ;
}
else
{
2024-02-27 20:04:27 +00:00
// Read unquoted value...
2020-01-10 19:55:59 +00:00
ptr = value ;
2024-03-06 19:45:10 +00:00
if ( ! mxml_add_char ( ch , & ptr , & value , & valsize ) )
2020-01-10 19:55:59 +00:00
goto error ;
2003-06-03 19:46:29 +00:00
2024-03-06 19:45:10 +00:00
while ( ( ch = mxml_getc ( read_cb , read_cbdata , encoding ) ) ! = EOF )
2019-01-05 17:23:17 +00:00
{
2007-09-09 07:27:08 +00:00
if ( mxml_isspace ( ch ) | | ch = = ' = ' | | ch = = ' / ' | | ch = = ' > ' )
2019-01-05 17:23:17 +00:00
{
if ( ch = = ' \n ' )
( * line ) + + ;
2003-06-03 19:46:29 +00:00
break ;
2019-01-05 17:23:17 +00:00
}
2003-12-21 15:01:15 +00:00
else
2003-06-03 19:46:29 +00:00
{
2003-12-21 15:01:15 +00:00
if ( ch = = ' & ' )
2019-01-05 17:23:17 +00:00
{
2024-03-06 19:45:10 +00:00
if ( ( ch = mxml_get_entity ( read_cb , read_cbdata , encoding , node , line ) ) = = EOF )
2003-12-21 15:01:15 +00:00
goto error ;
2019-01-05 17:23:17 +00:00
}
2013-11-12 05:03:47 +00:00
2024-03-06 19:45:10 +00:00
if ( ! mxml_add_char ( ch , & ptr , & value , & valsize ) )
2003-12-21 15:01:15 +00:00
goto error ;
2003-06-03 19:46:29 +00:00
}
2019-01-05 17:23:17 +00:00
}
2003-06-03 19:46:29 +00:00
* ptr = ' \0 ' ;
}
2003-12-01 15:27:47 +00:00
2024-02-27 20:04:27 +00:00
// Set the attribute with the given string value...
2003-12-01 15:27:47 +00:00
mxmlElementSetAttr ( node , name , value ) ;
2024-03-06 19:45:10 +00:00
MXML_DEBUG ( " mxml_parse_element: %s= \" %s \" \n " , name , value ) ;
2003-06-03 19:46:29 +00:00
}
else
2003-12-01 15:27:47 +00:00
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Missing value for attribute '%s' in element %s on line %d. " , name , mxmlGetElement ( node ) , * line ) ;
2007-09-09 08:22:12 +00:00
goto error ;
2003-12-01 15:27:47 +00:00
}
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
// Check the end character...
2003-06-19 03:20:41 +00:00
if ( ch = = ' / ' | | ch = = ' ? ' )
{
2024-02-27 20:04:27 +00:00
// Grab the > character and print an error if it isn't there...
2024-03-06 19:45:10 +00:00
quote = mxml_getc ( read_cb , read_cbdata , encoding ) ;
2003-06-19 03:20:41 +00:00
if ( quote ! = ' > ' )
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Expected '>' after '%c' for element %s, but got '%c' on line %d. " , ch , mxmlGetElement ( node ) , quote , * line ) ;
2003-06-19 03:20:41 +00:00
ch = EOF ;
}
break ;
}
else if ( ch = = ' > ' )
break ;
2003-06-03 19:46:29 +00:00
}
2024-02-27 20:04:27 +00:00
// Free the name and value buffers and return...
2003-06-15 21:31:45 +00:00
free ( name ) ;
2024-03-06 19:45:10 +00:00
free ( value ) ;
2004-05-16 21:54:47 +00:00
2024-03-06 19:45:10 +00:00
return ( ch ) ;
2009-03-19 05:27:26 +00:00
2024-03-06 19:45:10 +00:00
// Common error return point...
error :
2004-10-28 01:07:00 +00:00
2024-03-06 19:45:10 +00:00
free ( name ) ;
free ( value ) ;
2004-05-16 21:54:47 +00:00
2024-03-06 19:45:10 +00:00
return ( EOF ) ;
}
2004-05-16 21:54:47 +00:00
2004-10-28 01:07:00 +00:00
2024-03-06 19:45:10 +00:00
//
// 'mxml_read_cb_fd()' - Read bytes from a file descriptor.
//
2004-05-16 21:54:47 +00:00
2024-03-06 19:45:10 +00:00
static ssize_t // O - Bytes read
mxml_read_cb_fd ( int * fd , // I - File descriptor
void * buffer , // I - Buffer
size_t bytes ) // I - Bytes to read
{
// TODO: Handle EAGAIN/EINTR?
return ( read ( * fd , buffer , bytes ) ) ;
}
2004-05-16 21:54:47 +00:00
2024-03-06 19:45:10 +00:00
//
// 'mxml_read_cb_file()' - Read bytes from a file pointer.
//
2004-05-16 21:54:47 +00:00
2024-03-06 19:45:10 +00:00
static ssize_t // O - Bytes read
mxml_read_cb_file ( FILE * fp , // I - File pointer
void * buffer , // I - Buffer
size_t bytes ) // I - Bytes to read
{
if ( feof ( fp ) )
return ( - 1 ) ;
else
return ( ( ssize_t ) fread ( buffer , 1 , bytes , fp ) ) ;
}
2004-05-16 21:54:47 +00:00
2003-12-21 15:01:15 +00:00
2024-03-06 19:45:10 +00:00
//
// 'mxml_read_cb_string()' - Read bytes from a string.
//
2003-12-21 15:01:15 +00:00
2024-03-06 19:45:10 +00:00
static ssize_t // O - Bytes read
mxml_read_cb_string (
_mxml_stringbuf_t * sb , // I - String buffer
void * buffer , // I - Buffer
size_t bytes ) // I - Bytes to read
{
size_t remaining ; // Remaining bytes in buffer
2004-05-16 21:54:47 +00:00
2024-03-06 19:45:10 +00:00
if ( ( remaining = sb - > bufsize - ( size_t ) ( sb - > bufptr - sb - > buffer ) ) < bytes )
bytes = remaining ;
2004-05-16 21:54:47 +00:00
2024-03-06 19:45:10 +00:00
if ( bytes > 0 )
{
// Copy bytes from string...
memcpy ( buffer , sb - > bufptr , bytes ) ;
sb - > bufptr + = bytes ;
2003-06-19 03:20:41 +00:00
}
2004-05-16 21:54:47 +00:00
2024-03-06 19:45:10 +00:00
return ( ( ssize_t ) bytes ) ;
2003-06-19 03:20:41 +00:00
}
2024-02-27 20:04:27 +00:00
//
2024-03-06 19:45:10 +00:00
// 'mxml_write_cb_fd()' - Write bytes to a file descriptor.
2024-02-27 20:04:27 +00:00
//
2003-06-19 04:25:12 +00:00
2024-03-06 19:45:10 +00:00
static ssize_t // O - Bytes written
mxml_write_cb_fd ( int * fd , // I - File descriptor
const void * buffer , // I - Buffer
size_t bytes ) // I - Bytes to write
2003-06-19 04:25:12 +00:00
{
2024-03-06 19:45:10 +00:00
// TODO: Handle EAGAIN/EINTR?
return ( write ( * fd , buffer , bytes ) ) ;
}
2003-06-19 04:25:12 +00:00
2003-12-21 15:01:15 +00:00
2024-03-06 19:45:10 +00:00
//
// 'mxml_write_cb_file()' - Write bytes to a file pointer.
//
2003-06-19 04:25:12 +00:00
2024-03-06 19:45:10 +00:00
static ssize_t // O - Bytes written
mxml_write_cb_file ( FILE * fp , // I - File pointer
const void * buffer , // I - Buffer
size_t bytes ) // I - Bytes to write
{
return ( ( ssize_t ) fwrite ( buffer , 1 , bytes , fp ) ) ;
2003-06-19 04:25:12 +00:00
}
2024-02-27 20:04:27 +00:00
//
2024-03-06 19:45:10 +00:00
// 'mxml_write_cb_string()' - Write bytes to a string buffer.
2024-02-27 20:04:27 +00:00
//
2003-12-01 15:27:47 +00:00
2024-03-06 19:45:10 +00:00
static ssize_t // O - Bytes written
mxml_write_cb_string (
_mxml_stringbuf_t * sb , // I - String buffer
const void * buffer , // I - Buffer
size_t bytes ) // I - Bytes to write
2003-12-01 15:27:47 +00:00
{
2024-03-06 19:45:10 +00:00
size_t remaining ; // Remaining bytes
2003-12-01 15:27:47 +00:00
2024-03-06 19:45:10 +00:00
// Expand buffer as needed...
if ( ( sb - > bufptr + bytes ) > = ( sb - > buffer + sb - > bufsize - 1 ) & & sb - > bufalloc )
2003-12-01 15:27:47 +00:00
{
2024-03-06 19:45:10 +00:00
// Reallocate buffer
char * temp ; // New buffer pointer
size_t newsize ; // New bufsize
2003-12-01 15:27:47 +00:00
2024-03-06 19:45:10 +00:00
newsize = ( size_t ) ( sb - > bufptr - sb - > buffer ) + bytes + 257 ;
if ( ( temp = realloc ( sb - > buffer , newsize ) ) = = NULL )
2003-12-01 15:27:47 +00:00
{
2024-03-06 19:45:10 +00:00
_mxml_error ( " Unable to expand string buffer - %s " , strerror ( errno ) ) ;
return ( - 1 ) ;
2003-12-01 15:27:47 +00:00
}
2024-03-06 19:45:10 +00:00
sb - > bufptr = temp + ( sb - > bufptr - sb - > buffer ) ;
sb - > buffer = temp ;
sb - > bufsize = newsize ;
2003-12-01 15:27:47 +00:00
}
2024-03-06 19:45:10 +00:00
// Copy what we can...
if ( sb - > bufptr > = ( sb - > buffer + sb - > bufsize - 1 ) )
return ( - 1 ) ; // No more room
else if ( ( remaining = ( sb - > bufsize - ( size_t ) ( sb - > bufptr - sb - > buffer ) - 1 ) ) < bytes )
bytes = remaining ;
2003-12-01 15:27:47 +00:00
2024-03-06 19:45:10 +00:00
memcpy ( sb - > bufptr , buffer , bytes ) ;
sb - > bufptr + = bytes ;
return ( bytes ) ;
2003-12-01 15:27:47 +00:00
}
2024-02-27 20:04:27 +00:00
//
// 'mxml_write_node()' - Save an XML node to a file.
//
2003-06-04 02:34:30 +00:00
2024-02-27 20:04:27 +00:00
static int // O - Column or -1 on error
2024-03-06 19:45:10 +00:00
mxml_write_node (
mxml_write_cb_t write_cb , // I - Write callback function
void * write_cbdata , // I - Write callback data
mxml_node_t * node , // I - Node to write
mxml_save_cb_t save_cb , // I - Whitespace callback function
void * save_cbdata , // I - Whitespace callback data
int col , // I - Current column
_mxml_global_t * global ) // I - Global data
2003-06-04 02:34:30 +00:00
{
2024-02-27 20:04:27 +00:00
mxml_node_t * current , // Current node
* next ; // Next node
2024-03-06 19:45:10 +00:00
size_t i , // Looping var
2024-02-27 20:04:27 +00:00
width ; // Width of attr + value
_mxml_attr_t * attr ; // Current attribute
2024-03-06 19:45:10 +00:00
char s [ 255 ] , // Temporary string
* data ; // Custom data string
const char * text ; // Text string
bool whitespace ; // Whitespace before text string?
2003-06-04 02:34:30 +00:00
2010-09-19 07:27:48 +00:00
2024-02-27 20:04:27 +00:00
// Loop through this node and all of its children...
2024-03-06 19:45:10 +00:00
for ( current = node ; current & & col > = 0 ; current = next )
2003-06-04 02:34:30 +00:00
{
2024-02-27 20:04:27 +00:00
// Print the node value...
2024-03-06 19:45:10 +00:00
MXML_DEBUG ( " mxml_write_node: current=%p(%d) \n " , current , current - > type ) ;
switch ( mxmlGetType ( current ) )
2016-06-12 21:12:11 +00:00
{
2024-03-02 23:47:57 +00:00
case MXML_TYPE_CDATA :
2024-03-06 19:45:10 +00:00
col = mxml_write_ws ( write_cb , write_cbdata , current , save_cb , save_cbdata , MXML_WS_BEFORE_OPEN , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , " <![CDATA[ " , /*use_entities*/ false , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , mxmlGetCDATA ( current ) , /*use_entities*/ false , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , " ]]> " , /*use_entities*/ false , col ) ;
col = mxml_write_ws ( write_cb , write_cbdata , current , save_cb , save_cbdata , MXML_WS_AFTER_OPEN , col ) ;
2024-03-02 23:47:57 +00:00
break ;
case MXML_TYPE_COMMENT :
2024-03-06 19:45:10 +00:00
col = mxml_write_ws ( write_cb , write_cbdata , current , save_cb , save_cbdata , MXML_WS_BEFORE_OPEN , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , " <!-- " , /*use_entities*/ false , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , mxmlGetComment ( current ) , /*use_entities*/ false , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , " --> " , /*use_entities*/ false , col ) ;
col = mxml_write_ws ( write_cb , write_cbdata , current , save_cb , save_cbdata , MXML_WS_AFTER_OPEN , col ) ;
2024-03-02 23:47:57 +00:00
break ;
case MXML_TYPE_DECLARATION :
2024-03-06 19:45:10 +00:00
col = mxml_write_ws ( write_cb , write_cbdata , current , save_cb , save_cbdata , MXML_WS_BEFORE_OPEN , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , " <! " , /*use_entities*/ false , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , mxmlGetDeclaration ( current ) , /*use_entities*/ false , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , " > " , /*use_entities*/ false , col ) ;
col = mxml_write_ws ( write_cb , write_cbdata , current , save_cb , save_cbdata , MXML_WS_AFTER_OPEN , col ) ;
2024-03-02 23:47:57 +00:00
break ;
2017-03-30 01:42:30 +00:00
2024-03-02 23:47:57 +00:00
case MXML_TYPE_DIRECTIVE :
2024-03-06 19:45:10 +00:00
col = mxml_write_ws ( write_cb , write_cbdata , current , save_cb , save_cbdata , MXML_WS_BEFORE_OPEN , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , " <? " , /*use_entities*/ false , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , mxmlGetDirective ( current ) , /*use_entities*/ false , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , " ?> " , /*use_entities*/ false , col ) ;
col = mxml_write_ws ( write_cb , write_cbdata , current , save_cb , save_cbdata , MXML_WS_AFTER_OPEN , col ) ;
2024-03-02 23:47:57 +00:00
break ;
case MXML_TYPE_ELEMENT :
2024-03-06 19:45:10 +00:00
col = mxml_write_ws ( write_cb , write_cbdata , current , save_cb , save_cbdata , MXML_WS_BEFORE_OPEN , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , " < " , /*use_entities*/ false , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , mxmlGetElement ( current ) , /*use_entities*/ true , col ) ;
2005-01-29 07:19:38 +00:00
2024-03-06 19:45:10 +00:00
for ( i = current - > value . element . num_attrs , attr = current - > value . element . attrs ; i > 0 & & col > = 0 ; i - - , attr + + )
2016-06-12 21:12:11 +00:00
{
2024-03-06 19:45:10 +00:00
width = strlen ( attr - > name ) ;
2003-06-04 02:34:30 +00:00
2016-06-12 21:12:11 +00:00
if ( attr - > value )
width + = strlen ( attr - > value ) + 3 ;
2003-06-04 02:34:30 +00:00
2016-06-12 21:12:11 +00:00
if ( global - > wrap > 0 & & ( col + width ) > global - > wrap )
2024-03-06 19:45:10 +00:00
col = mxml_write_string ( write_cb , write_cbdata , " \n " , /*use_entities*/ false , col ) ;
2016-06-12 21:12:11 +00:00
else
2024-03-06 19:45:10 +00:00
col = mxml_write_string ( write_cb , write_cbdata , " " , /*use_entities*/ false , col ) ;
2016-06-12 21:12:11 +00:00
2024-03-06 19:45:10 +00:00
col = mxml_write_string ( write_cb , write_cbdata , attr - > name , /*use_entities*/ true , col ) ;
2003-06-04 02:34:30 +00:00
2016-06-12 21:12:11 +00:00
if ( attr - > value )
{
2024-03-06 19:45:10 +00:00
col = mxml_write_string ( write_cb , write_cbdata , " = \" " , /*use_entities*/ false , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , attr - > value , /*use_entities*/ true , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , " \" " , /*use_entities*/ false , col ) ;
2016-06-12 21:12:11 +00:00
}
2003-06-04 02:34:30 +00:00
}
2024-03-06 19:45:10 +00:00
col = mxml_write_string ( write_cb , write_cbdata , current - > child ? " > " : " /> " , /*use_entities*/ false , col ) ;
col = mxml_write_ws ( write_cb , write_cbdata , current , save_cb , save_cbdata , MXML_WS_AFTER_OPEN , col ) ;
2016-06-12 21:12:11 +00:00
break ;
2003-06-04 02:34:30 +00:00
2024-02-27 20:04:27 +00:00
case MXML_TYPE_INTEGER :
2016-06-12 21:12:11 +00:00
if ( current - > prev )
{
2024-03-06 19:45:10 +00:00
// Add whitespace separator...
2016-06-12 21:12:11 +00:00
if ( global - > wrap > 0 & & col > global - > wrap )
2024-03-06 19:45:10 +00:00
col = mxml_write_string ( write_cb , write_cbdata , " \n " , /*use_entities*/ false , col ) ;
2016-06-12 21:12:11 +00:00
else
2024-03-06 19:45:10 +00:00
col = mxml_write_string ( write_cb , write_cbdata , " " , /*use_entities*/ false , col ) ;
2016-06-12 21:12:11 +00:00
}
2003-06-04 21:19:00 +00:00
2024-03-06 19:45:10 +00:00
// Write integer...
2024-03-02 23:47:57 +00:00
snprintf ( s , sizeof ( s ) , " %ld " , current - > value . integer ) ;
2024-03-06 19:45:10 +00:00
col = mxml_write_string ( write_cb , write_cbdata , s , /*use_entities*/ true , col ) ;
2016-06-12 21:12:11 +00:00
break ;
2003-06-04 21:19:00 +00:00
2024-02-27 20:04:27 +00:00
case MXML_TYPE_OPAQUE :
2024-03-06 19:45:10 +00:00
col = mxml_write_string ( write_cb , write_cbdata , mxmlGetOpaque ( current ) , /*use_entities*/ true , col ) ;
2016-06-12 21:12:11 +00:00
break ;
2010-09-19 07:27:48 +00:00
2024-02-27 20:04:27 +00:00
case MXML_TYPE_REAL :
2016-06-12 21:12:11 +00:00
if ( current - > prev )
2003-06-04 21:19:00 +00:00
{
2024-03-06 19:45:10 +00:00
// Add whitespace separator...
2016-06-12 21:12:11 +00:00
if ( global - > wrap > 0 & & col > global - > wrap )
2024-03-06 19:45:10 +00:00
col = mxml_write_string ( write_cb , write_cbdata , " \n " , /*use_entities*/ false , col ) ;
2016-06-12 21:12:11 +00:00
else
2024-03-06 19:45:10 +00:00
col = mxml_write_string ( write_cb , write_cbdata , " " , /*use_entities*/ false , col ) ;
2003-06-04 17:37:23 +00:00
}
2003-06-04 02:34:30 +00:00
2024-03-06 19:45:10 +00:00
// Write real number...
2024-02-27 20:04:27 +00:00
// TODO: Provide locale-neutral formatting/scanning code for REAL
2018-12-03 16:21:39 +00:00
snprintf ( s , sizeof ( s ) , " %f " , current - > value . real ) ;
2024-03-06 19:45:10 +00:00
col = mxml_write_string ( write_cb , write_cbdata , s , /*use_entities*/ true , col ) ;
2016-06-12 21:12:11 +00:00
break ;
2010-09-19 07:27:48 +00:00
2024-02-27 20:04:27 +00:00
case MXML_TYPE_TEXT :
2024-03-06 19:45:10 +00:00
text = mxmlGetText ( current , & whitespace ) ;
if ( whitespace & & col > 0 )
2010-09-19 07:27:48 +00:00
{
2024-03-06 19:45:10 +00:00
// Add whitespace separator...
2016-06-12 21:12:11 +00:00
if ( global - > wrap > 0 & & col > global - > wrap )
2024-03-06 19:45:10 +00:00
col = mxml_write_string ( write_cb , write_cbdata , " \n " , /*use_entities*/ false , col ) ;
2016-06-12 21:12:11 +00:00
else
2024-03-06 19:45:10 +00:00
col = mxml_write_string ( write_cb , write_cbdata , " " , /*use_entities*/ false , col ) ;
2010-09-19 07:27:48 +00:00
}
2016-06-12 21:12:11 +00:00
2024-03-06 19:45:10 +00:00
col = mxml_write_string ( write_cb , write_cbdata , text , /*use_entities*/ true , col ) ;
2016-06-12 21:12:11 +00:00
break ;
2003-06-04 02:34:30 +00:00
2024-02-27 20:04:27 +00:00
case MXML_TYPE_CUSTOM :
2024-03-06 19:45:10 +00:00
if ( ! global - > custom_save_cb )
return ( - 1 ) ;
2003-06-04 02:34:30 +00:00
2024-03-06 19:45:10 +00:00
if ( ( data = ( * global - > custom_save_cb ) ( current ) ) = = NULL )
return ( - 1 ) ;
2003-06-04 02:34:30 +00:00
2024-03-06 19:45:10 +00:00
col = mxml_write_string ( write_cb , write_cbdata , data , /*use_entities*/ true , col ) ;
2016-06-12 21:12:11 +00:00
2024-03-06 19:45:10 +00:00
free ( data ) ;
break ;
2003-06-04 02:34:30 +00:00
2024-02-27 20:04:27 +00:00
default : // Should never happen
2010-09-19 07:27:48 +00:00
return ( - 1 ) ;
2016-06-12 21:12:11 +00:00
}
2003-06-04 02:34:30 +00:00
2024-02-27 20:04:27 +00:00
// Figure out the next node...
2024-03-06 19:45:10 +00:00
if ( ( next = mxmlGetFirstChild ( current ) ) = = NULL )
2016-06-12 21:12:11 +00:00
{
2018-10-01 17:15:22 +00:00
if ( current = = node )
2016-06-12 21:12:11 +00:00
{
2024-02-27 20:04:27 +00:00
// Don't traverse to sibling node if we are at the "root" node...
2018-10-01 17:15:22 +00:00
next = NULL ;
}
else
{
2024-02-27 20:04:27 +00:00
// Try the next sibling, and continue traversing upwards as needed...
2024-03-06 19:45:10 +00:00
while ( ( next = mxmlGetNextSibling ( current ) ) = = NULL )
2010-09-19 07:27:48 +00:00
{
2024-03-06 19:45:10 +00:00
if ( current = = node | | ! mxmlGetParent ( current ) )
2018-10-01 17:15:22 +00:00
break ;
2004-10-28 02:58:01 +00:00
2024-03-02 23:47:57 +00:00
// Declarations and directives have no end tags...
2024-03-06 19:45:10 +00:00
current = mxmlGetParent ( current ) ;
2018-10-01 17:15:22 +00:00
2024-03-06 19:45:10 +00:00
if ( mxmlGetType ( current ) = = MXML_TYPE_ELEMENT )
2018-10-01 17:15:22 +00:00
{
2024-03-06 19:45:10 +00:00
col = mxml_write_ws ( write_cb , write_cbdata , current , save_cb , save_cbdata , MXML_WS_BEFORE_CLOSE , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , " </ " , /*use_entities*/ false , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , mxmlGetElement ( current ) , /*use_entities*/ true , col ) ;
col = mxml_write_string ( write_cb , write_cbdata , " > " , /*use_entities*/ false , col ) ;
col = mxml_write_ws ( write_cb , write_cbdata , current , save_cb , save_cbdata , MXML_WS_AFTER_CLOSE , col ) ;
2018-10-01 17:15:22 +00:00
}
if ( current = = node )
break ;
2010-09-19 07:27:48 +00:00
}
2016-06-12 21:12:11 +00:00
}
}
2003-06-04 02:34:30 +00:00
}
return ( col ) ;
}
2024-02-27 20:04:27 +00:00
//
// 'mxml_write_string()' - Write a string, escaping & and < as needed.
//
2003-06-03 19:46:29 +00:00
2024-03-06 19:45:10 +00:00
static int // O - New column or `-1` on error
2007-04-23 21:48:03 +00:00
mxml_write_string (
2024-03-06 19:45:10 +00:00
mxml_write_cb_t write_cb , // I - Write callback function
void * write_cbdata , // I - Write callback data
2024-02-27 20:04:27 +00:00
const char * s , // I - String to write
2024-03-06 19:45:10 +00:00
bool use_entities , // I - Escape special characters?
int col ) // I - Current column
2003-06-03 19:46:29 +00:00
{
2024-03-06 19:45:10 +00:00
const char * frag , // Start of current string fragment
* ptr , // Pointer into string
* ent ; // Entity, if any
size_t fraglen ; // Length of fragment
2003-06-19 04:25:12 +00:00
2024-03-06 19:45:10 +00:00
MXML_DEBUG ( " mxml_write_string(write_cb=%p, write_cbdata=%p, s= \" %s \" , use_entities=%s, col=%d) \n " , write_cb , write_cbdata , s , use_entities ? " true " : " false " , col ) ;
2003-06-19 04:25:12 +00:00
2024-03-06 19:45:10 +00:00
if ( col < 0 )
return ( - 1 ) ;
for ( frag = ptr = s ; * ptr ; ptr + + )
2003-06-03 19:46:29 +00:00
{
2024-03-06 19:45:10 +00:00
if ( use_entities & & ( ent = _mxml_entity_string ( * ptr ) ) ! = NULL )
2003-06-03 19:46:29 +00:00
{
2024-03-06 19:45:10 +00:00
size_t entlen = strlen ( ent ) ; // Length of entity
2003-06-04 16:30:40 +00:00
2024-03-06 19:45:10 +00:00
if ( ptr > frag )
2003-06-04 16:30:40 +00:00
{
2024-03-06 19:45:10 +00:00
// Write current fragment
fraglen = ( size_t ) ( ptr - frag ) ;
if ( ( write_cb ) ( write_cbdata , frag , fraglen ) ! = ( ssize_t ) fraglen )
return ( - 1 ) ;
2003-06-19 04:25:12 +00:00
}
2024-03-06 19:45:10 +00:00
frag = ptr + 1 ;
// Write entity
if ( ( write_cb ) ( write_cbdata , ent , entlen ) ! = ( ssize_t ) entlen )
2003-12-18 04:16:37 +00:00
return ( - 1 ) ;
2024-03-06 19:45:10 +00:00
col + + ;
2003-06-04 16:30:40 +00:00
}
2024-03-06 19:45:10 +00:00
else if ( * ptr = = ' \r ' | | * ptr = = ' \n ' )
2024-02-27 20:04:27 +00:00
{
2024-03-06 19:45:10 +00:00
// CR or LF resets column
col = 0 ;
2024-02-27 20:04:27 +00:00
}
2024-03-06 19:45:10 +00:00
else if ( * ptr = = ' \t ' )
{
// Tab indents column
col = col - ( col % MXML_TAB ) + MXML_TAB ;
}
else
{
// All other characters are 1 column wide
col + + ;
}
}
if ( ptr > frag )
{
// Write final fragment
fraglen = ( size_t ) ( ptr - frag ) ;
2003-06-03 19:46:29 +00:00
2024-03-06 19:45:10 +00:00
if ( ( write_cb ) ( write_cbdata , frag , fraglen ) ! = ( ssize_t ) fraglen )
return ( - 1 ) ;
2003-06-03 19:46:29 +00:00
}
2024-03-06 19:45:10 +00:00
return ( col ) ;
2003-06-03 19:46:29 +00:00
}
2024-02-27 20:04:27 +00:00
//
// 'mxml_write_ws()' - Do whitespace callback...
//
2003-06-04 21:19:00 +00:00
2024-03-06 19:45:10 +00:00
static int // O - New column or `-1` on error
mxml_write_ws (
mxml_write_cb_t write_cb , // I - Write callback function
void * write_cbdata , // I - Write callback data
mxml_node_t * node , // I - Current node
mxml_save_cb_t save_cb , // I - Whitespace callback function
void * save_cbdata , // I - Whitespace callback data
mxml_ws_t ws , // I - Whitespace value
int col ) // I - Current column
2003-06-04 21:19:00 +00:00
{
2024-02-27 20:04:27 +00:00
const char * s ; // Whitespace string
2003-06-04 21:19:00 +00:00
2024-03-06 19:45:10 +00:00
if ( save_cb & & ( s = ( * save_cb ) ( save_cbdata , node , ws ) ) ! = NULL )
col = mxml_write_string ( write_cb , write_cbdata , s , /*use_entities*/ false , col ) ;
2003-06-04 21:19:00 +00:00
return ( col ) ;
}