2003-06-03 19:46:29 +00:00
/*
2017-03-22 18:51:16 +00:00
* File loading code for Mini - XML , a small XML file parsing library .
2003-06-03 19:46:29 +00:00
*
2019-01-05 01:44:51 +00:00
* https : //www.msweet.org/mxml
2003-06-03 19:46:29 +00:00
*
2021-10-26 17:44:00 +00:00
* Copyright © 2003 - 2021 by Michael R Sweet .
2003-06-03 19:46:29 +00:00
*
2019-01-05 01:44:51 +00:00
* Licensed under Apache License v2 .0 . See the file " LICENSE " for more
* information .
2003-06-03 19:46:29 +00:00
*/
/*
* Include necessary headers . . .
*/
2019-02-10 15:40:53 +00:00
# ifndef _WIN32
2004-07-11 13:14:07 +00:00
# include <unistd.h>
2019-02-10 15:40:53 +00:00
# endif /* !_WIN32 */
2009-02-05 06:06:11 +00:00
# include "mxml-private.h"
2003-06-03 19:46:29 +00:00
2004-05-16 21:54:47 +00:00
/*
* Character encoding . . .
*/
# define ENCODE_UTF8 0 /* UTF-8 */
# define ENCODE_UTF16BE 1 /* UTF-16 Big-Endian */
# define ENCODE_UTF16LE 2 /* UTF-16 Little-Endian */
2005-01-29 17:03:33 +00:00
/*
* Macro to test for a bad XML character . . .
*/
# define mxml_bad_char(ch) ((ch) < ' ' && (ch) != '\n' && (ch) != '\r' && (ch) != '\t')
2004-07-11 13:14:07 +00:00
/*
2007-04-23 21:48:03 +00:00
* Types and structures . . .
2004-07-11 13:14:07 +00:00
*/
2007-04-23 21:48:03 +00:00
typedef int ( * _mxml_getc_cb_t ) ( void * , int * ) ;
typedef int ( * _mxml_putc_cb_t ) ( int , void * ) ;
typedef struct _mxml_fdbuf_s /**** File descriptor buffer ****/
2004-07-11 13:14:07 +00:00
{
int fd ; /* File descriptor */
unsigned char * current , /* Current position in buffer */
* end , /* End of buffer */
buffer [ 8192 ] ; /* Character buffer */
2007-04-23 21:48:03 +00:00
} _mxml_fdbuf_t ;
2004-07-11 13:14:07 +00:00
2003-06-03 19:46:29 +00:00
/*
* Local functions . . .
*/
2019-01-05 17:23:17 +00:00
static int mxml_add_char ( int ch , char * * ptr , char * * buffer , int * bufsize ) ;
2004-07-11 13:14:07 +00:00
static int mxml_fd_getc ( void * p , int * encoding ) ;
static int mxml_fd_putc ( int ch , void * p ) ;
2007-04-23 21:48:03 +00:00
static int mxml_fd_read ( _mxml_fdbuf_t * buf ) ;
static int mxml_fd_write ( _mxml_fdbuf_t * buf ) ;
2004-07-11 13:14:07 +00:00
static int mxml_file_getc ( void * p , int * encoding ) ;
static int mxml_file_putc ( int ch , void * p ) ;
2019-01-05 17:23:17 +00:00
static int mxml_get_entity ( mxml_node_t * parent , void * p , int * encoding , _mxml_getc_cb_t getc_cb , int * line ) ;
2007-09-09 07:27:08 +00:00
static inline int mxml_isspace ( int ch )
{
2019-01-05 17:23:17 +00:00
return ( ch = = ' ' | | ch = = ' \t ' | | ch = = ' \r ' | | ch = = ' \n ' ) ;
2007-09-09 07:27:08 +00:00
}
2019-01-05 17:23:17 +00:00
static mxml_node_t * mxml_load_data ( mxml_node_t * top , void * p , mxml_load_cb_t cb , _mxml_getc_cb_t getc_cb , mxml_sax_cb_t sax_cb , void * sax_data ) ;
static int mxml_parse_element ( mxml_node_t * node , void * p , int * encoding , _mxml_getc_cb_t getc_cb , int * line ) ;
2004-05-16 21:54:47 +00:00
static int mxml_string_getc ( void * p , int * encoding ) ;
2003-06-19 04:25:12 +00:00
static int mxml_string_putc ( int ch , void * p ) ;
2019-01-05 17:23:17 +00:00
static int mxml_write_name ( const char * s , void * p , _mxml_putc_cb_t putc_cb ) ;
static int mxml_write_node ( mxml_node_t * node , void * p , mxml_save_cb_t cb , int col , _mxml_putc_cb_t putc_cb , _mxml_global_t * global ) ;
static int mxml_write_string ( const char * s , void * p , _mxml_putc_cb_t putc_cb ) ;
static int mxml_write_ws ( mxml_node_t * node , void * p , mxml_save_cb_t cb , int ws , int col , _mxml_putc_cb_t putc_cb ) ;
2003-06-19 03:20:41 +00:00
2004-07-11 13:14:07 +00:00
/*
* ' 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 .
2017-04-24 14:42:03 +00:00
* The constants @ code MXML_INTEGER_CALLBACK @ , @ code MXML_OPAQUE_CALLBACK @ ,
* @ code MXML_REAL_CALLBACK @ , and @ code MXML_TEXT_CALLBACK @ are defined for
* loading child ( data ) nodes of the specified type .
2018-07-02 22:56:43 +00:00
*
* Note : The most common programming error when using the Mini - XML library is
* to load an XML file using the @ code MXML_TEXT_CALLBACK @ , which returns inline
* text as a series of whitespace - delimited words , instead of using the
* @ code MXML_OPAQUE_CALLBACK @ which returns the inline text as a single string
* ( including whitespace ) .
2004-07-11 13:14:07 +00:00
*/
2017-04-24 14:42:03 +00:00
mxml_node_t * /* O - First node or @code NULL@ if the file could not be read. */
2007-04-23 21:48:03 +00:00
mxmlLoadFd ( mxml_node_t * top , /* I - Top node */
int fd , /* I - File descriptor to read from */
2017-04-24 14:42:03 +00:00
mxml_load_cb_t cb ) /* I - Callback function or constant */
2004-07-11 13:14:07 +00:00
{
2007-04-23 21:48:03 +00:00
_mxml_fdbuf_t buf ; /* File descriptor buffer */
2004-07-11 13:14:07 +00:00
/*
* Initialize the file descriptor buffer . . .
*/
buf . fd = fd ;
buf . current = buf . buffer ;
buf . end = buf . buffer ;
/*
* Read the XML data . . .
*/
2007-04-23 21:48:03 +00:00
return ( mxml_load_data ( top , & buf , cb , mxml_fd_getc , MXML_NO_CALLBACK , NULL ) ) ;
2004-07-11 13:14:07 +00:00
}
2003-06-19 03:20:41 +00:00
/*
2003-06-19 04:25:12 +00:00
* ' mxmlLoadFile ( ) ' - Load a file into an XML node tree .
2003-06-19 03:20:41 +00:00
*
2003-06-19 04:25:12 +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
2003-06-19 03:20:41 +00:00
* function returns the value type that should be used for child nodes .
2017-04-24 14:42:03 +00:00
* The constants @ code MXML_INTEGER_CALLBACK @ , @ code MXML_OPAQUE_CALLBACK @ ,
* @ code MXML_REAL_CALLBACK @ , and @ code MXML_TEXT_CALLBACK @ are defined for
* loading child ( data ) nodes of the specified type .
2018-07-02 22:56:43 +00:00
*
* Note : The most common programming error when using the Mini - XML library is
* to load an XML file using the @ code MXML_TEXT_CALLBACK @ , which returns inline
* text as a series of whitespace - delimited words , instead of using the
* @ code MXML_OPAQUE_CALLBACK @ which returns the inline text as a single string
* ( including whitespace ) .
2003-06-19 03:20:41 +00:00
*/
2017-04-24 14:42:03 +00:00
mxml_node_t * /* O - First node or @code NULL@ if the file could not be read. */
2007-04-23 21:48:03 +00:00
mxmlLoadFile ( mxml_node_t * top , /* I - Top node */
FILE * fp , /* I - File to read from */
2017-04-24 14:42:03 +00:00
mxml_load_cb_t cb ) /* I - Callback function or constant */
2003-06-19 03:20:41 +00:00
{
2004-07-11 13:14:07 +00:00
/*
* Read the XML data . . .
*/
2007-04-23 21:48:03 +00:00
return ( mxml_load_data ( top , fp , cb , mxml_file_getc , MXML_NO_CALLBACK , NULL ) ) ;
2003-06-19 03:20:41 +00:00
}
2003-06-03 19:46:29 +00:00
/*
2003-06-19 04:25:12 +00:00
* ' mxmlLoadString ( ) ' - Load a string into an XML node tree .
2003-06-14 23:56:47 +00:00
*
2003-06-19 04:25:12 +00:00
* 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
2003-06-14 23:56:47 +00:00
* function returns the value type that should be used for child nodes .
2017-04-24 14:42:03 +00:00
* The constants @ code MXML_INTEGER_CALLBACK @ , @ code MXML_OPAQUE_CALLBACK @ ,
* @ code MXML_REAL_CALLBACK @ , and @ code MXML_TEXT_CALLBACK @ are defined for
* loading child ( data ) nodes of the specified type .
2018-07-02 22:56:43 +00:00
*
* Note : The most common programming error when using the Mini - XML library is
* to load an XML file using the @ code MXML_TEXT_CALLBACK @ , which returns inline
* text as a series of whitespace - delimited words , instead of using the
* @ code MXML_OPAQUE_CALLBACK @ which returns the inline text as a single string
* ( including whitespace ) .
2003-06-03 19:46:29 +00:00
*/
2017-04-24 14:42:03 +00:00
mxml_node_t * /* O - First node or @code NULL@ if the string has errors. */
2007-04-23 21:48:03 +00:00
mxmlLoadString ( mxml_node_t * top , /* I - Top node */
const char * s , /* I - String to load */
2017-04-24 14:42:03 +00:00
mxml_load_cb_t cb ) /* I - Callback function or constant */
2003-06-19 03:20:41 +00:00
{
2004-07-11 13:14:07 +00:00
/*
* Read the XML data . . .
*/
2007-10-03 06:25:07 +00:00
return ( mxml_load_data ( top , ( void * ) & s , cb , mxml_string_getc , MXML_NO_CALLBACK ,
2007-04-23 21:48:03 +00:00
NULL ) ) ;
2003-06-19 03:20:41 +00:00
}
2003-07-22 10:29:19 +00:00
/*
2010-09-19 07:29:46 +00:00
* ' mxmlSaveAllocString ( ) ' - Save an XML tree to an allocated string .
2003-07-22 10:29:19 +00:00
*
* This function returns a pointer to a string containing the textual
* representation of the XML node tree . The string should be freed
2017-04-24 14:42:03 +00:00
* using the free ( ) function when you are done with it . @ code NULL @ is returned
2003-07-22 10:29:19 +00:00
* if the node would produce an empty string or if the string cannot be
* allocated .
2004-07-11 13:14:07 +00:00
*
* The callback argument specifies a function that returns a whitespace
2017-04-24 14:42:03 +00:00
* string or NULL before and after each element . If @ code MXML_NO_CALLBACK @
* is specified , whitespace will only be added before @ code MXML_TEXT @ nodes
2004-07-11 13:14:07 +00:00
* with leading whitespace and before attribute names inside opening
* element tags .
2003-07-22 10:29:19 +00:00
*/
2017-04-24 14:42:03 +00:00
char * /* O - Allocated string or @code NULL@ */
2007-04-23 21:48:03 +00:00
mxmlSaveAllocString (
mxml_node_t * node , /* I - Node to write */
2017-04-24 14:42:03 +00:00
mxml_save_cb_t cb ) /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */
2003-07-22 10:29:19 +00:00
{
int bytes ; /* Required bytes */
char buffer [ 8192 ] ; /* Temporary buffer */
char * s ; /* Allocated string */
/*
* Write the node to the temporary buffer . . .
*/
bytes = mxmlSaveString ( node , buffer , sizeof ( buffer ) , cb ) ;
if ( bytes < = 0 )
return ( NULL ) ;
if ( bytes < ( int ) ( sizeof ( buffer ) - 1 ) )
{
/*
* Node fit inside the buffer , so just duplicate that string and
* return . . .
*/
return ( strdup ( buffer ) ) ;
}
/*
* Allocate a buffer of the required size and save the node to the
* new buffer . . .
*/
if ( ( s = malloc ( bytes + 1 ) ) = = NULL )
return ( NULL ) ;
mxmlSaveString ( node , s , bytes + 1 , cb ) ;
/*
* Return the allocated string . . .
*/
return ( s ) ;
}
2004-07-11 13:14:07 +00:00
/*
* ' mxmlSaveFd ( ) ' - Save an XML tree to a file descriptor .
*
* The callback argument specifies a function that returns a whitespace
2017-04-24 14:42:03 +00:00
* string or NULL before and after each element . If @ code MXML_NO_CALLBACK @
* is specified , whitespace will only be added before @ code MXML_TEXT @ nodes
2004-07-11 13:14:07 +00:00
* with leading whitespace and before attribute names inside opening
* element tags .
*/
int /* O - 0 on success, -1 on error. */
2007-04-23 21:48:03 +00:00
mxmlSaveFd ( mxml_node_t * node , /* I - Node to write */
int fd , /* I - File descriptor to write to */
2017-04-24 14:42:03 +00:00
mxml_save_cb_t cb ) /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */
2004-07-11 13:14:07 +00:00
{
int col ; /* Final column */
2007-04-23 21:48:03 +00:00
_mxml_fdbuf_t buf ; /* File descriptor buffer */
2007-09-21 04:46:02 +00:00
_mxml_global_t * global = _mxml_global ( ) ;
/* Global data */
2004-07-11 13:14:07 +00:00
/*
* Initialize the file descriptor buffer . . .
*/
buf . fd = fd ;
buf . current = buf . buffer ;
2009-03-21 05:51:01 +00:00
buf . end = buf . buffer + sizeof ( buf . buffer ) ;
2004-07-11 13:14:07 +00:00
/*
* Write the node . . .
*/
2007-09-21 04:46:02 +00:00
if ( ( col = mxml_write_node ( node , & buf , cb , 0 , mxml_fd_putc , global ) ) < 0 )
2004-07-11 13:14:07 +00:00
return ( - 1 ) ;
if ( col > 0 )
if ( mxml_fd_putc ( ' \n ' , & buf ) < 0 )
return ( - 1 ) ;
/*
* Flush and return . . .
*/
return ( mxml_fd_write ( & buf ) ) ;
}
2003-06-19 03:20:41 +00:00
/*
* ' mxmlSaveFile ( ) ' - Save an XML tree to a file .
*
* The callback argument specifies a function that returns a whitespace
2017-04-24 14:42:03 +00:00
* string or NULL before and after each element . If @ code MXML_NO_CALLBACK @
* is specified , whitespace will only be added before @ code MXML_TEXT @ nodes
2003-06-19 03:20:41 +00:00
* with leading whitespace and before attribute names inside opening
* element tags .
*/
int /* O - 0 on success, -1 on error. */
2007-04-23 21:48:03 +00:00
mxmlSaveFile ( mxml_node_t * node , /* I - Node to write */
FILE * fp , /* I - File to write to */
2017-04-24 14:42:03 +00:00
mxml_save_cb_t cb ) /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */
2003-06-19 03:20:41 +00:00
{
int col ; /* Final column */
2007-09-21 04:46:02 +00:00
_mxml_global_t * global = _mxml_global ( ) ;
/* Global data */
2003-06-19 03:20:41 +00:00
/*
* Write the node . . .
*/
2007-09-21 04:46:02 +00:00
if ( ( col = mxml_write_node ( node , fp , cb , 0 , mxml_file_putc , global ) ) < 0 )
2003-06-19 03:20:41 +00:00
return ( - 1 ) ;
if ( col > 0 )
if ( putc ( ' \n ' , fp ) < 0 )
return ( - 1 ) ;
/*
* Return 0 ( success ) . . .
*/
return ( 0 ) ;
}
/*
* ' mxmlSaveString ( ) ' - Save an XML node tree to a string .
*
* 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 .
2004-07-11 13:14:07 +00:00
*
* The callback argument specifies a function that returns a whitespace
2017-04-24 14:42:03 +00:00
* string or NULL before and after each element . If @ code MXML_NO_CALLBACK @
* is specified , whitespace will only be added before @ code MXML_TEXT @ nodes
2004-07-11 13:14:07 +00:00
* with leading whitespace and before attribute names inside opening
* element tags .
2003-06-19 03:20:41 +00:00
*/
int /* O - Size of string */
2007-04-23 21:48:03 +00:00
mxmlSaveString ( mxml_node_t * node , /* I - Node to write */
char * buffer , /* I - String buffer */
int bufsize , /* I - Size of string buffer */
2017-04-24 14:42:03 +00:00
mxml_save_cb_t cb ) /* I - Whitespace callback or @code MXML_NO_CALLBACK@ */
2003-06-19 03:20:41 +00:00
{
2003-06-19 04:25:12 +00:00
int col ; /* Final column */
char * ptr [ 2 ] ; /* Pointers for putc_cb */
2007-09-21 04:46:02 +00:00
_mxml_global_t * global = _mxml_global ( ) ;
/* Global data */
2003-06-19 04:25:12 +00:00
/*
* Write the node . . .
*/
ptr [ 0 ] = buffer ;
ptr [ 1 ] = buffer + bufsize ;
2007-09-21 04:46:02 +00:00
if ( ( col = mxml_write_node ( node , ptr , cb , 0 , mxml_string_putc , global ) ) < 0 )
2003-06-19 04:25:12 +00:00
return ( - 1 ) ;
if ( col > 0 )
mxml_string_putc ( ' \n ' , ptr ) ;
/*
* Nul - terminate the buffer . . .
*/
if ( ptr [ 0 ] > = ptr [ 1 ] )
buffer [ bufsize - 1 ] = ' \0 ' ;
else
ptr [ 0 ] [ 0 ] = ' \0 ' ;
/*
* Return the number of characters . . .
*/
2017-03-29 23:04:41 +00:00
return ( ( int ) ( ptr [ 0 ] - buffer ) ) ;
2003-06-19 03:20:41 +00:00
}
2007-04-23 21:48:03 +00:00
/*
* ' mxmlSAXLoadFd ( ) ' - Load a file descriptor into an XML node tree
* using a SAX callback .
*
* 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 .
2017-04-24 14:42:03 +00:00
* The constants @ code MXML_INTEGER_CALLBACK @ , @ code MXML_OPAQUE_CALLBACK @ ,
* @ code MXML_REAL_CALLBACK @ , and @ code MXML_TEXT_CALLBACK @ are defined for
* loading child nodes of the specified type .
2007-04-23 21:48:03 +00:00
*
2017-04-24 14:42:03 +00:00
* The SAX callback must call @ link mxmlRetain @ for any nodes that need to
2007-04-23 21:48:03 +00:00
* be kept for later use . Otherwise , nodes are deleted when the parent
* node is closed or after each data , comment , CDATA , or directive node .
*
* @ since Mini - XML 2.3 @
*/
2017-04-24 14:42:03 +00:00
mxml_node_t * /* O - First node or @code NULL@ if the file could not be read. */
2007-04-23 21:48:03 +00:00
mxmlSAXLoadFd ( mxml_node_t * top , /* I - Top node */
int fd , /* I - File descriptor to read from */
2017-04-24 14:42:03 +00:00
mxml_load_cb_t cb , /* I - Callback function or constant */
mxml_sax_cb_t sax_cb , /* I - SAX callback or @code MXML_NO_CALLBACK@ */
2007-04-23 21:48:03 +00:00
void * sax_data ) /* I - SAX user data */
{
_mxml_fdbuf_t buf ; /* File descriptor buffer */
/*
* Initialize the file descriptor buffer . . .
*/
buf . fd = fd ;
buf . current = buf . buffer ;
buf . end = buf . buffer ;
/*
* Read the XML data . . .
*/
return ( mxml_load_data ( top , & buf , cb , mxml_fd_getc , sax_cb , sax_data ) ) ;
}
/*
* ' mxmlSAXLoadFile ( ) ' - Load a file into an XML node tree
* using a SAX callback .
*
* 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 .
2017-04-24 14:42:03 +00:00
* The constants @ code MXML_INTEGER_CALLBACK @ , @ code MXML_OPAQUE_CALLBACK @ ,
* @ code MXML_REAL_CALLBACK @ , and @ code MXML_TEXT_CALLBACK @ are defined for
* loading child nodes of the specified type .
2007-04-23 21:48:03 +00:00
*
2017-04-24 14:42:03 +00:00
* The SAX callback must call @ link mxmlRetain @ for any nodes that need to
2007-04-23 21:48:03 +00:00
* be kept for later use . Otherwise , nodes are deleted when the parent
* node is closed or after each data , comment , CDATA , or directive node .
*
* @ since Mini - XML 2.3 @
*/
2017-04-24 14:42:03 +00:00
mxml_node_t * /* O - First node or @code NULL@ if the file could not be read. */
2007-04-23 21:48:03 +00:00
mxmlSAXLoadFile (
mxml_node_t * top , /* I - Top node */
FILE * fp , /* I - File to read from */
2017-04-24 14:42:03 +00:00
mxml_load_cb_t cb , /* I - Callback function or constant */
mxml_sax_cb_t sax_cb , /* I - SAX callback or @code MXML_NO_CALLBACK@ */
2007-04-23 21:48:03 +00:00
void * sax_data ) /* I - SAX user data */
{
/*
* Read the XML data . . .
*/
return ( mxml_load_data ( top , fp , cb , mxml_file_getc , sax_cb , sax_data ) ) ;
}
/*
* ' mxmlSAXLoadString ( ) ' - Load a string into an XML node tree
* using a SAX callback .
*
* 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 .
2017-04-24 14:42:03 +00:00
* The constants @ code MXML_INTEGER_CALLBACK @ , @ code MXML_OPAQUE_CALLBACK @ ,
* @ code MXML_REAL_CALLBACK @ , and @ code MXML_TEXT_CALLBACK @ are defined for
* loading child nodes of the specified type .
2007-04-23 21:48:03 +00:00
*
2017-04-24 14:42:03 +00:00
* The SAX callback must call @ link mxmlRetain @ for any nodes that need to
2007-04-23 21:48:03 +00:00
* be kept for later use . Otherwise , nodes are deleted when the parent
* node is closed or after each data , comment , CDATA , or directive node .
*
* @ since Mini - XML 2.3 @
*/
2017-04-24 14:42:03 +00:00
mxml_node_t * /* O - First node or @code NULL@ if the string has errors. */
2007-04-23 21:48:03 +00:00
mxmlSAXLoadString (
mxml_node_t * top , /* I - Top node */
const char * s , /* I - String to load */
2017-04-24 14:42:03 +00:00
mxml_load_cb_t cb , /* I - Callback function or constant */
mxml_sax_cb_t sax_cb , /* I - SAX callback or @code MXML_NO_CALLBACK@ */
2007-04-23 21:48:03 +00:00
void * sax_data ) /* I - SAX user data */
{
/*
* Read the XML data . . .
*/
2007-10-03 06:25:07 +00:00
return ( mxml_load_data ( top , ( void * ) & s , cb , mxml_string_getc , sax_cb , sax_data ) ) ;
2007-04-23 21:48:03 +00:00
}
2004-10-28 02:58:01 +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
2017-04-24 14:42:03 +00:00
* string on success and @ code NULL @ on error .
2013-11-12 05:03:47 +00:00
*
2004-10-28 02:58:01 +00:00
*/
void
2007-04-23 21:48:03 +00:00
mxmlSetCustomHandlers (
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 ( ) ;
/* Global data */
global - > custom_load_cb = load ;
global - > custom_save_cb = save ;
2004-10-28 02:58:01 +00:00
}
2003-12-03 03:59:04 +00:00
/*
* ' mxmlSetErrorCallback ( ) ' - Set the error message callback .
*/
void
2007-04-23 21:48:03 +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 ( ) ;
/* Global data */
global - > error_cb = cb ;
2003-12-03 03:59:04 +00:00
}
2007-04-18 01:08:58 +00:00
/*
2010-09-19 06:40:33 +00:00
* ' mxmlSetWrapMargin ( ) ' - Set the wrap margin when saving XML data .
2007-04-18 01:08:58 +00:00
*
2008-03-21 04:59:01 +00:00
* Wrapping is disabled when " column " is 0.
2007-04-18 01:55:03 +00:00
*
* @ since Mini - XML 2.3 @
2007-04-18 01:08:58 +00:00
*/
void
2008-03-21 04:59:01 +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 ( ) ;
/* Global data */
2008-03-21 04:59:01 +00:00
global - > wrap = column ;
2007-04-18 01:08:58 +00:00
}
2003-06-19 03:20:41 +00:00
/*
* ' mxml_add_char ( ) ' - Add a character to a buffer , expanding as needed .
*/
static int /* O - 0 on success, -1 on error */
mxml_add_char ( int ch , /* I - Character to add */
char * * bufptr , /* IO - Current position in buffer */
char * * buffer , /* IO - Current buffer */
int * bufsize ) /* IO - Current buffer size */
{
char * newbuffer ; /* New buffer value */
2003-12-21 15:01:15 +00:00
if ( * bufptr > = ( * buffer + * bufsize - 4 ) )
2003-06-19 03:20:41 +00:00
{
/*
* Increase the size of the buffer . . .
*/
if ( * bufsize < 1024 )
( * bufsize ) * = 2 ;
else
( * bufsize ) + = 1024 ;
if ( ( newbuffer = realloc ( * buffer , * bufsize ) ) = = NULL )
{
2021-10-26 17:44:00 +00:00
mxml_error ( " Unable to expand string buffer to %d bytes. " , * bufsize ) ;
2003-06-19 03:20:41 +00:00
return ( - 1 ) ;
}
* 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
{
/*
* Single byte ASCII . . .
*/
* ( * bufptr ) + + = ch ;
}
2004-10-28 01:07:00 +00:00
else if ( ch < 0x800 )
2003-12-21 15:01:15 +00:00
{
/*
* Two - byte UTF - 8. . .
*/
* ( * 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
{
/*
* Three - byte UTF - 8. . .
*/
* ( * bufptr ) + + = 0xe0 | ( ch > > 12 ) ;
* ( * bufptr ) + + = 0x80 | ( ( ch > > 6 ) & 0x3f ) ;
* ( * bufptr ) + + = 0x80 | ( ch & 0x3f ) ;
}
else
{
/*
* Four - byte UTF - 8. . .
*/
* ( * 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
return ( 0 ) ;
}
2003-12-21 15:01:15 +00:00
/*
2004-07-11 13:14:07 +00:00
* ' mxml_fd_getc ( ) ' - Read a character from a file descriptor .
2003-12-21 15:01:15 +00:00
*/
2004-07-11 13:14:07 +00:00
static int /* O - Character or EOF */
mxml_fd_getc ( void * p , /* I - File descriptor buffer */
int * encoding ) /* IO - Encoding */
2003-12-21 15:01:15 +00:00
{
2007-04-23 21:48:03 +00:00
_mxml_fdbuf_t * buf ; /* File descriptor buffer */
2004-07-11 13:14:07 +00:00
int ch , /* Current character */
temp ; /* Temporary character */
2003-12-21 15:01:15 +00:00
2004-07-11 13:14:07 +00:00
/*
* Grab the next character in the buffer . . .
*/
2003-12-21 15:01:15 +00:00
2007-04-23 21:48:03 +00:00
buf = ( _mxml_fdbuf_t * ) p ;
2003-12-21 15:01:15 +00:00
2004-07-11 13:14:07 +00:00
if ( buf - > current > = buf - > end )
if ( mxml_fd_read ( buf ) < 0 )
return ( EOF ) ;
2003-12-21 15:01:15 +00:00
2004-07-11 13:14:07 +00:00
ch = * ( buf - > current ) + + ;
switch ( * encoding )
2003-12-21 15:01:15 +00:00
{
2004-07-11 13:14:07 +00:00
case ENCODE_UTF8 :
/*
* Got a UTF - 8 character ; convert UTF - 8 to Unicode and return . . .
*/
if ( ! ( ch & 0x80 ) )
2005-01-29 17:03:33 +00:00
{
# if DEBUG > 1
printf ( " mxml_fd_getc: %c (0x%04x) \n " , ch < ' ' ? ' . ' : ch , ch ) ;
# endif /* DEBUG > 1 */
if ( mxml_bad_char ( ch ) )
{
2021-10-26 17:44:00 +00:00
mxml_error ( " Bad control character 0x%02x not allowed by XML standard. " ,
2005-01-29 17:03:33 +00:00
ch ) ;
return ( EOF ) ;
}
2004-07-11 13:14:07 +00:00
return ( ch ) ;
2005-01-29 17:03:33 +00:00
}
else if ( ch = = 0xfe )
2004-07-11 13:14:07 +00:00
{
/*
* UTF - 16 big - endian BOM ?
*/
if ( buf - > current > = buf - > end )
if ( mxml_fd_read ( buf ) < 0 )
return ( EOF ) ;
ch = * ( buf - > current ) + + ;
2013-11-12 05:03:47 +00:00
2004-07-11 13:14:07 +00:00
if ( ch ! = 0xff )
return ( EOF ) ;
* encoding = ENCODE_UTF16BE ;
return ( mxml_fd_getc ( p , encoding ) ) ;
}
else if ( ch = = 0xff )
{
/*
* UTF - 16 little - endian BOM ?
*/
if ( buf - > current > = buf - > end )
if ( mxml_fd_read ( buf ) < 0 )
return ( EOF ) ;
ch = * ( buf - > current ) + + ;
2013-11-12 05:03:47 +00:00
2004-07-11 13:14:07 +00:00
if ( ch ! = 0xfe )
return ( EOF ) ;
* encoding = ENCODE_UTF16LE ;
return ( mxml_fd_getc ( p , encoding ) ) ;
}
else if ( ( ch & 0xe0 ) = = 0xc0 )
{
/*
* Two - byte value . . .
*/
if ( buf - > current > = buf - > end )
if ( mxml_fd_read ( buf ) < 0 )
return ( EOF ) ;
temp = * ( buf - > current ) + + ;
if ( ( temp & 0xc0 ) ! = 0x80 )
return ( EOF ) ;
ch = ( ( ch & 0x1f ) < < 6 ) | ( temp & 0x3f ) ;
2004-10-28 01:07:00 +00:00
if ( ch < 0x80 )
2009-03-19 05:27:26 +00:00
{
2021-10-26 17:44:00 +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 )
{
/*
* Three - byte value . . .
*/
if ( buf - > current > = buf - > end )
if ( mxml_fd_read ( buf ) < 0 )
return ( EOF ) ;
temp = * ( buf - > current ) + + ;
if ( ( temp & 0xc0 ) ! = 0x80 )
return ( EOF ) ;
ch = ( ( ch & 0x0f ) < < 6 ) | ( temp & 0x3f ) ;
if ( buf - > current > = buf - > end )
if ( mxml_fd_read ( buf ) < 0 )
return ( EOF ) ;
temp = * ( buf - > current ) + + ;
if ( ( temp & 0xc0 ) ! = 0x80 )
return ( EOF ) ;
ch = ( ch < < 6 ) | ( temp & 0x3f ) ;
2004-10-28 01:07:00 +00:00
if ( ch < 0x800 )
2009-03-19 05:27:26 +00:00
{
2021-10-26 17:44:00 +00:00
mxml_error ( " Invalid UTF-8 sequence for character 0x%04x. " , ch ) ;
2009-03-19 05:27:26 +00:00
return ( EOF ) ;
}
2009-05-17 05:20:52 +00:00
/*
* Ignore ( strip ) Byte Order Mark ( BOM ) . . .
*/
if ( ch = = 0xfeff )
return ( mxml_fd_getc ( p , encoding ) ) ;
2004-07-11 13:14:07 +00:00
}
else if ( ( ch & 0xf8 ) = = 0xf0 )
{
/*
* Four - byte value . . .
*/
if ( buf - > current > = buf - > end )
if ( mxml_fd_read ( buf ) < 0 )
return ( EOF ) ;
temp = * ( buf - > current ) + + ;
if ( ( temp & 0xc0 ) ! = 0x80 )
return ( EOF ) ;
ch = ( ( ch & 0x07 ) < < 6 ) | ( temp & 0x3f ) ;
if ( buf - > current > = buf - > end )
if ( mxml_fd_read ( buf ) < 0 )
return ( EOF ) ;
temp = * ( buf - > current ) + + ;
if ( ( temp & 0xc0 ) ! = 0x80 )
return ( EOF ) ;
ch = ( ch < < 6 ) | ( temp & 0x3f ) ;
if ( buf - > current > = buf - > end )
if ( mxml_fd_read ( buf ) < 0 )
return ( EOF ) ;
temp = * ( buf - > current ) + + ;
if ( ( temp & 0xc0 ) ! = 0x80 )
return ( EOF ) ;
ch = ( ch < < 6 ) | ( temp & 0x3f ) ;
2004-10-28 01:07:00 +00:00
if ( ch < 0x10000 )
2009-03-19 05:27:26 +00:00
{
2021-10-26 17:44:00 +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
return ( EOF ) ;
break ;
case ENCODE_UTF16BE :
/*
* Read UTF - 16 big - endian char . . .
*/
if ( buf - > current > = buf - > end )
if ( mxml_fd_read ( buf ) < 0 )
return ( EOF ) ;
temp = * ( buf - > current ) + + ;
ch = ( ch < < 8 ) | temp ;
2005-01-29 17:03:33 +00:00
if ( mxml_bad_char ( ch ) )
{
2021-10-26 17:44:00 +00:00
mxml_error ( " Bad control character 0x%02x not allowed by XML standard. " ,
2005-01-29 17:03:33 +00:00
ch ) ;
return ( EOF ) ;
}
else if ( ch > = 0xd800 & & ch < = 0xdbff )
2004-07-11 13:14:07 +00:00
{
/*
* Multi - word UTF - 16 char . . .
*/
int lch ;
if ( buf - > current > = buf - > end )
if ( mxml_fd_read ( buf ) < 0 )
return ( EOF ) ;
lch = * ( buf - > current ) + + ;
if ( buf - > current > = buf - > end )
if ( mxml_fd_read ( buf ) < 0 )
return ( EOF ) ;
temp = * ( buf - > current ) + + ;
lch = ( lch < < 8 ) | temp ;
if ( lch < 0xdc00 | | lch > = 0xdfff )
return ( EOF ) ;
ch = ( ( ( ch & 0x3ff ) < < 10 ) | ( lch & 0x3ff ) ) + 0x10000 ;
}
break ;
case ENCODE_UTF16LE :
/*
* Read UTF - 16 little - endian char . . .
*/
if ( buf - > current > = buf - > end )
if ( mxml_fd_read ( buf ) < 0 )
return ( EOF ) ;
temp = * ( buf - > current ) + + ;
ch | = ( temp < < 8 ) ;
2005-01-29 17:03:33 +00:00
if ( mxml_bad_char ( ch ) )
{
2021-10-26 17:44:00 +00:00
mxml_error ( " Bad control character 0x%02x not allowed by XML standard. " ,
2005-01-29 17:03:33 +00:00
ch ) ;
return ( EOF ) ;
}
else if ( ch > = 0xd800 & & ch < = 0xdbff )
2004-07-11 13:14:07 +00:00
{
/*
* Multi - word UTF - 16 char . . .
*/
int lch ;
if ( buf - > current > = buf - > end )
if ( mxml_fd_read ( buf ) < 0 )
return ( EOF ) ;
lch = * ( buf - > current ) + + ;
if ( buf - > current > = buf - > end )
if ( mxml_fd_read ( buf ) < 0 )
return ( EOF ) ;
temp = * ( buf - > current ) + + ;
lch | = ( temp < < 8 ) ;
if ( lch < 0xdc00 | | lch > = 0xdfff )
return ( EOF ) ;
ch = ( ( ( ch & 0x3ff ) < < 10 ) | ( lch & 0x3ff ) ) + 0x10000 ;
}
break ;
2003-12-21 15:01:15 +00:00
}
2005-01-29 17:03:33 +00:00
# if DEBUG > 1
printf ( " mxml_fd_getc: %c (0x%04x) \n " , ch < ' ' ? ' . ' : ch , ch ) ;
# endif /* DEBUG > 1 */
2004-07-11 13:14:07 +00:00
return ( ch ) ;
}
/*
* ' mxml_fd_putc ( ) ' - Write a character to a file descriptor .
*/
static int /* O - 0 on success, -1 on error */
mxml_fd_putc ( int ch , /* I - Character */
void * p ) /* I - File descriptor buffer */
{
2007-04-23 21:48:03 +00:00
_mxml_fdbuf_t * buf ; /* File descriptor buffer */
2004-07-11 13:14:07 +00:00
/*
2009-03-21 05:51:01 +00:00
* Flush the write buffer as needed . . .
2004-07-11 13:14:07 +00:00
*/
2007-04-23 21:48:03 +00:00
buf = ( _mxml_fdbuf_t * ) p ;
2004-07-11 13:14:07 +00:00
if ( buf - > current > = buf - > end )
if ( mxml_fd_write ( buf ) < 0 )
return ( - 1 ) ;
2009-03-21 05:51:01 +00:00
* ( buf - > current ) + + = ch ;
2004-07-11 13:14:07 +00:00
/*
* Return successfully . . .
*/
return ( 0 ) ;
}
/*
* ' mxml_fd_read ( ) ' - Read a buffer of data from a file descriptor .
*/
static int /* O - 0 on success, -1 on error */
2007-04-23 21:48:03 +00:00
mxml_fd_read ( _mxml_fdbuf_t * buf ) /* I - File descriptor buffer */
2004-07-11 13:14:07 +00:00
{
int bytes ; /* Bytes read... */
/*
* Range check input . . .
*/
if ( ! buf )
return ( - 1 ) ;
/*
* Read from the file descriptor . . .
*/
2017-03-29 23:04:41 +00:00
while ( ( bytes = ( int ) read ( buf - > fd , buf - > buffer , sizeof ( buf - > buffer ) ) ) < 0 )
2005-12-07 15:01:08 +00:00
# ifdef EINTR
2004-07-11 13:14:07 +00:00
if ( errno ! = EAGAIN & & errno ! = EINTR )
2005-12-07 15:01:08 +00:00
# else
if ( errno ! = EAGAIN )
# endif /* EINTR */
2004-07-11 13:14:07 +00:00
return ( - 1 ) ;
if ( bytes = = 0 )
return ( - 1 ) ;
/*
* Update the pointers and return success . . .
*/
buf - > current = buf - > buffer ;
buf - > end = buf - > buffer + bytes ;
return ( 0 ) ;
}
/*
* ' mxml_fd_write ( ) ' - Write a buffer of data to a file descriptor .
*/
static int /* O - 0 on success, -1 on error */
2007-04-23 21:48:03 +00:00
mxml_fd_write ( _mxml_fdbuf_t * buf ) /* I - File descriptor buffer */
2004-07-11 13:14:07 +00:00
{
int bytes ; /* Bytes written */
unsigned char * ptr ; /* Pointer into buffer */
/*
* Range check . . .
*/
if ( ! buf )
return ( - 1 ) ;
/*
* Return 0 if there is nothing to write . . .
*/
if ( buf - > current = = buf - > buffer )
return ( 0 ) ;
/*
* Loop until we have written everything . . .
*/
for ( ptr = buf - > buffer ; ptr < buf - > current ; ptr + = bytes )
2017-03-29 23:04:41 +00:00
if ( ( bytes = ( int ) write ( buf - > fd , ptr , buf - > current - ptr ) ) < 0 )
2004-07-11 13:14:07 +00:00
return ( - 1 ) ;
/*
* All done , reset pointers and return success . . .
*/
buf - > current = buf - > buffer ;
return ( 0 ) ;
2003-12-21 15:01:15 +00:00
}
2003-06-19 03:20:41 +00:00
/*
* ' mxml_file_getc ( ) ' - Get a character from a file .
*/
2004-05-16 21:54:47 +00:00
static int /* O - Character or EOF */
mxml_file_getc ( void * p , /* I - Pointer to file */
int * encoding ) /* IO - Encoding */
2003-06-19 03:20:41 +00:00
{
2003-12-21 15:01:15 +00:00
int ch , /* Character from file */
temp ; /* Temporary character */
FILE * fp ; /* Pointer to file */
/*
* Read a character from the file and see if it is EOF or ASCII . . .
*/
fp = ( FILE * ) p ;
ch = getc ( fp ) ;
2004-05-16 21:54:47 +00:00
if ( ch = = EOF )
return ( EOF ) ;
2003-12-21 15:01:15 +00:00
2004-05-16 21:54:47 +00:00
switch ( * encoding )
2003-12-21 15:01:15 +00:00
{
2004-05-16 21:54:47 +00:00
case ENCODE_UTF8 :
/*
* Got a UTF - 8 character ; convert UTF - 8 to Unicode and return . . .
*/
2003-12-21 15:01:15 +00:00
2004-05-16 21:54:47 +00:00
if ( ! ( ch & 0x80 ) )
2005-01-29 07:19:38 +00:00
{
2005-01-29 17:03:33 +00:00
if ( mxml_bad_char ( ch ) )
{
2021-10-26 17:44:00 +00:00
mxml_error ( " Bad control character 0x%02x not allowed by XML standard. " ,
2005-01-29 17:03:33 +00:00
ch ) ;
return ( EOF ) ;
}
2005-01-29 07:19:38 +00:00
# if DEBUG > 1
printf ( " mxml_file_getc: %c (0x%04x) \n " , ch < ' ' ? ' . ' : ch , ch ) ;
# endif /* DEBUG > 1 */
2004-05-16 21:54:47 +00:00
return ( ch ) ;
2005-01-29 07:19:38 +00:00
}
else if ( ch = = 0xfe )
2004-05-16 21:54:47 +00:00
{
/*
* UTF - 16 big - endian BOM ?
*/
2003-12-21 15:01:15 +00:00
2004-05-16 21:54:47 +00:00
ch = getc ( fp ) ;
if ( ch ! = 0xff )
return ( EOF ) ;
* encoding = ENCODE_UTF16BE ;
2003-12-21 15:01:15 +00:00
2004-05-16 21:54:47 +00:00
return ( mxml_file_getc ( p , encoding ) ) ;
}
else if ( ch = = 0xff )
{
/*
* UTF - 16 little - endian BOM ?
*/
2003-12-21 15:01:15 +00:00
2004-05-16 21:54:47 +00:00
ch = getc ( fp ) ;
if ( ch ! = 0xfe )
return ( EOF ) ;
2003-12-21 15:01:15 +00:00
2004-05-16 21:54:47 +00:00
* encoding = ENCODE_UTF16LE ;
2003-12-21 15:01:15 +00:00
2004-05-16 21:54:47 +00:00
return ( mxml_file_getc ( p , encoding ) ) ;
}
else if ( ( ch & 0xe0 ) = = 0xc0 )
{
/*
* Two - byte value . . .
*/
if ( ( temp = getc ( fp ) ) = = EOF | | ( temp & 0xc0 ) ! = 0x80 )
return ( EOF ) ;
ch = ( ( ch & 0x1f ) < < 6 ) | ( temp & 0x3f ) ;
2004-10-28 01:07:00 +00:00
if ( ch < 0x80 )
2009-03-19 05:27:26 +00:00
{
2021-10-26 17:44:00 +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-05-16 21:54:47 +00:00
}
else if ( ( ch & 0xf0 ) = = 0xe0 )
{
/*
* Three - byte value . . .
*/
if ( ( temp = getc ( fp ) ) = = EOF | | ( temp & 0xc0 ) ! = 0x80 )
return ( EOF ) ;
ch = ( ( ch & 0x0f ) < < 6 ) | ( temp & 0x3f ) ;
if ( ( temp = getc ( fp ) ) = = EOF | | ( temp & 0xc0 ) ! = 0x80 )
return ( EOF ) ;
ch = ( ch < < 6 ) | ( temp & 0x3f ) ;
2004-10-28 01:07:00 +00:00
if ( ch < 0x800 )
2009-03-19 05:27:26 +00:00
{
2021-10-26 17:44:00 +00:00
mxml_error ( " Invalid UTF-8 sequence for character 0x%04x. " , ch ) ;
2009-03-19 05:27:26 +00:00
return ( EOF ) ;
}
2009-05-17 05:20:52 +00:00
/*
* Ignore ( strip ) Byte Order Mark ( BOM ) . . .
*/
if ( ch = = 0xfeff )
return ( mxml_file_getc ( p , encoding ) ) ;
2004-05-16 21:54:47 +00:00
}
else if ( ( ch & 0xf8 ) = = 0xf0 )
{
/*
* Four - byte value . . .
*/
if ( ( temp = getc ( fp ) ) = = EOF | | ( temp & 0xc0 ) ! = 0x80 )
return ( EOF ) ;
ch = ( ( ch & 0x07 ) < < 6 ) | ( temp & 0x3f ) ;
if ( ( temp = getc ( fp ) ) = = EOF | | ( temp & 0xc0 ) ! = 0x80 )
return ( EOF ) ;
ch = ( ch < < 6 ) | ( temp & 0x3f ) ;
if ( ( temp = getc ( fp ) ) = = EOF | | ( temp & 0xc0 ) ! = 0x80 )
return ( EOF ) ;
ch = ( ch < < 6 ) | ( temp & 0x3f ) ;
2004-10-28 01:07:00 +00:00
if ( ch < 0x10000 )
2009-03-19 05:27:26 +00:00
{
2021-10-26 17:44:00 +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-05-16 21:54:47 +00:00
}
else
return ( EOF ) ;
break ;
case ENCODE_UTF16BE :
/*
* Read UTF - 16 big - endian char . . .
*/
ch = ( ch < < 8 ) | getc ( fp ) ;
2003-12-21 15:01:15 +00:00
2005-01-29 17:03:33 +00:00
if ( mxml_bad_char ( ch ) )
{
2021-10-26 17:44:00 +00:00
mxml_error ( " Bad control character 0x%02x not allowed by XML standard. " ,
2005-01-29 17:03:33 +00:00
ch ) ;
return ( EOF ) ;
}
else if ( ch > = 0xd800 & & ch < = 0xdbff )
2004-05-16 21:54:47 +00:00
{
/*
* Multi - word UTF - 16 char . . .
*/
2003-12-21 15:01:15 +00:00
2013-11-12 05:03:47 +00:00
int lch = getc ( fp ) ;
lch = ( lch < < 8 ) | getc ( fp ) ;
2003-12-21 15:01:15 +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 ) ;
2003-12-21 15:01:15 +00:00
2004-05-16 21:54:47 +00:00
ch = ( ( ( ch & 0x3ff ) < < 10 ) | ( lch & 0x3ff ) ) + 0x10000 ;
}
break ;
2003-12-21 15:01:15 +00:00
2004-05-16 21:54:47 +00:00
case ENCODE_UTF16LE :
/*
* Read UTF - 16 little - endian char . . .
*/
2003-12-21 15:01:15 +00:00
2004-05-16 21:54:47 +00:00
ch | = ( getc ( fp ) < < 8 ) ;
2005-01-29 17:03:33 +00:00
if ( mxml_bad_char ( ch ) )
{
2021-10-26 17:44:00 +00:00
mxml_error ( " Bad control character 0x%02x not allowed by XML standard. " ,
2005-01-29 17:03:33 +00:00
ch ) ;
return ( EOF ) ;
}
else if ( ch > = 0xd800 & & ch < = 0xdbff )
2004-05-16 21:54:47 +00:00
{
/*
* Multi - word UTF - 16 char . . .
*/
2013-11-12 05:03:47 +00:00
int lch = getc ( fp ) ;
lch | = ( getc ( fp ) < < 8 ) ;
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
}
2005-01-29 07:19:38 +00:00
# if DEBUG > 1
printf ( " mxml_file_getc: %c (0x%04x) \n " , ch < ' ' ? ' . ' : ch , ch ) ;
# endif /* DEBUG > 1 */
2003-12-21 15:01:15 +00:00
return ( ch ) ;
2003-06-19 03:20:41 +00:00
}
2003-06-19 04:25:12 +00:00
/*
* ' mxml_file_putc ( ) ' - Write a character to a file .
*/
static int /* O - 0 on success, -1 on failure */
mxml_file_putc ( int ch , /* I - Character to write */
void * p ) /* I - Pointer to file */
{
2009-03-21 05:51:01 +00:00
return ( putc ( ch , ( FILE * ) p ) = = EOF ? - 1 : 0 ) ;
2003-06-19 04:25:12 +00:00
}
2004-07-11 13:14:07 +00:00
/*
* ' mxml_get_entity ( ) ' - Get the character corresponding to an entity . . .
*/
static int /* O - Character value or EOF on error */
mxml_get_entity ( mxml_node_t * parent , /* I - Parent node */
void * p , /* I - Pointer to source */
int * encoding , /* IO - Character encoding */
2019-01-05 17:23:17 +00:00
int ( * getc_cb ) ( void * , int * ) ,
2004-07-11 13:14:07 +00:00
/* I - Get character function */
2019-01-05 17:23:17 +00:00
int * line ) /* IO - Current line number */
2004-07-11 13:14:07 +00:00
{
int ch ; /* Current character */
char entity [ 64 ] , /* Entity string */
* entptr ; /* Pointer into entity */
entptr = entity ;
while ( ( ch = ( * getc_cb ) ( p , encoding ) ) ! = EOF )
2019-01-05 17:23:17 +00:00
{
2004-07-11 13:14:07 +00:00
if ( ch > 126 | | ( ! isalnum ( ch ) & & ch ! = ' # ' ) )
break ;
else if ( entptr < ( entity + sizeof ( entity ) - 1 ) )
* entptr + + = ch ;
else
{
2019-01-05 17:23:17 +00:00
mxml_error ( " Entity name too long under parent <%s> on line %d. " , parent ? parent - > value . element . name : " null " , * line ) ;
2004-07-11 13:14:07 +00:00
break ;
}
2019-01-05 17:23:17 +00:00
}
2004-07-11 13:14:07 +00:00
* entptr = ' \0 ' ;
if ( ch ! = ' ; ' )
{
2019-01-05 17:23:17 +00:00
mxml_error ( " Character entity '%s' not terminated under parent <%s> on line %d. " , entity , parent ? parent - > value . element . name : " null " , * line ) ;
if ( ch = = ' \n ' )
( * line ) + + ;
2004-07-11 13:14:07 +00:00
return ( EOF ) ;
}
2004-10-26 21:04:32 +00:00
if ( entity [ 0 ] = = ' # ' )
2004-07-11 13:14:07 +00:00
{
2004-10-26 21:04:32 +00:00
if ( entity [ 1 ] = = ' x ' )
2017-03-29 23:04:41 +00:00
ch = ( int ) strtol ( entity + 2 , NULL , 16 ) ;
2004-07-11 13:14:07 +00:00
else
2017-03-29 23:04:41 +00:00
ch = ( int ) strtol ( entity + 1 , NULL , 10 ) ;
2004-07-11 13:14:07 +00:00
}
else if ( ( ch = mxmlEntityGetValue ( entity ) ) < 0 )
2019-01-05 17:23:17 +00:00
mxml_error ( " Entity name '%s;' not supported under parent <%s> on line %d. " , entity , parent ? parent - > value . element . name : " null " , * line ) ;
2004-07-11 13:14:07 +00:00
2005-01-29 17:03:33 +00:00
if ( mxml_bad_char ( ch ) )
{
2019-01-05 17:23:17 +00:00
mxml_error ( " Bad control character 0x%02x under parent <%s> on line %d not allowed by XML standard. " , ch , parent ? parent - > value . element . name : " null " , * line ) ;
2005-01-29 17:03:33 +00:00
return ( EOF ) ;
}
2004-07-11 13:14:07 +00:00
return ( ch ) ;
}
2003-06-19 03:20:41 +00:00
/*
* ' mxml_load_data ( ) ' - Load data into an XML node tree .
*/
static mxml_node_t * /* O - First node or NULL if the file could not be read. */
2007-04-23 21:48:03 +00:00
mxml_load_data (
mxml_node_t * top , /* I - Top node */
void * p , /* I - Pointer to data */
mxml_load_cb_t cb , /* I - Callback function or MXML_NO_CALLBACK */
_mxml_getc_cb_t getc_cb , /* I - Read function */
mxml_sax_cb_t sax_cb , /* I - SAX callback or MXML_NO_CALLBACK */
void * sax_data ) /* I - SAX user data */
2003-06-03 19:46:29 +00:00
{
mxml_node_t * node , /* Current node */
2005-05-18 01:45:20 +00:00
* first , /* First node added */
2003-06-03 19:46:29 +00:00
* parent ; /* Current parent node */
2019-01-05 17:23:17 +00:00
int line = 1 , /* Current line number */
ch , /* Character from file */
2003-06-03 19:46:29 +00:00
whitespace ; /* Non-zero if whitespace seen */
2003-06-15 21:31:45 +00:00
char * buffer , /* String buffer */
2003-06-03 19:46:29 +00:00
* bufptr ; /* Pointer into buffer */
2003-06-15 21:31:45 +00:00
int bufsize ; /* Size of buffer */
2003-06-03 19:46:29 +00:00
mxml_type_t type ; /* Current node type */
2004-05-16 21:54:47 +00:00
int encoding ; /* Character encoding */
2007-09-21 04:46:02 +00:00
_mxml_global_t * global = _mxml_global ( ) ;
/* Global data */
2005-05-18 01:45:20 +00:00
static const char * const types [ ] = /* Type strings... */
{
" MXML_ELEMENT " , /* XML element with attributes */
" MXML_INTEGER " , /* Integer value */
" MXML_OPAQUE " , /* Opaque string */
" MXML_REAL " , /* Real value */
" MXML_TEXT " , /* Text fragment */
" MXML_CUSTOM " /* Custom data */
} ;
2003-06-03 19:46:29 +00:00
/*
* Read elements and other nodes from the file . . .
*/
2003-06-15 21:31:45 +00:00
if ( ( buffer = malloc ( 64 ) ) = = NULL )
{
2021-10-26 17:44:00 +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
whitespace = 0 ;
2004-05-16 21:54:47 +00:00
encoding = ENCODE_UTF8 ;
2003-06-03 19:46:29 +00:00
if ( cb & & parent )
type = ( * cb ) ( parent ) ;
2014-01-05 03:21:00 +00:00
else if ( parent )
2003-06-03 19:46:29 +00:00
type = MXML_TEXT ;
2014-01-05 03:21:00 +00:00
else
type = MXML_IGNORE ;
2003-06-03 19:46:29 +00:00
2019-07-04 02:27:11 +00:00
if ( ( ch = ( * getc_cb ) ( p , & encoding ) ) = = EOF )
{
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 ) ;
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
{
2004-10-28 02:58:01 +00:00
if ( ( ch = = ' < ' | |
2007-09-09 07:27:08 +00:00
( mxml_isspace ( ch ) & & type ! = MXML_OPAQUE & & type ! = MXML_CUSTOM ) ) & &
2004-10-28 02:58:01 +00:00
bufptr > buffer )
2003-06-03 19:46:29 +00:00
{
/*
* Add a new value node . . .
*/
* bufptr = ' \0 ' ;
switch ( type )
{
case MXML_INTEGER :
2017-03-29 23:04:41 +00:00
node = mxmlNewInteger ( parent , ( int ) strtol ( buffer , & bufptr , 0 ) ) ;
2003-06-03 19:46:29 +00:00
break ;
case MXML_OPAQUE :
node = mxmlNewOpaque ( parent , buffer ) ;
break ;
case MXML_REAL :
2003-06-04 02:34:30 +00:00
node = mxmlNewReal ( parent , strtod ( buffer , & bufptr ) ) ;
2003-06-03 19:46:29 +00:00
break ;
case MXML_TEXT :
node = mxmlNewText ( parent , whitespace , buffer ) ;
break ;
2004-10-28 02:58:01 +00:00
case MXML_CUSTOM :
2007-09-21 04:46:02 +00:00
if ( global - > custom_load_cb )
2004-10-28 02:58:01 +00:00
{
/*
* Use the callback to fill in the custom data . . .
*/
node = mxmlNewCustom ( parent , NULL , NULL ) ;
2007-09-21 04:46:02 +00:00
if ( ( * global - > custom_load_cb ) ( node , buffer ) )
2004-10-28 02:58:01 +00:00
{
2019-01-05 17:23:17 +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 ;
}
2005-06-07 23:43:45 +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 )
{
/*
* Bad integer / real number value . . .
*/
2019-01-05 17:23:17 +00:00
mxml_error ( " Bad %s value '%s' in parent <%s> on line %d. " , type = = MXML_INTEGER ? " integer " : " real " , buffer , parent ? parent - > value . element . name : " null " , line ) ;
2003-06-04 02:34:30 +00:00
break ;
}
bufptr = buffer ;
2007-09-09 07:27:08 +00:00
whitespace = mxml_isspace ( ch ) & & type = = MXML_TEXT ;
2003-06-03 19:46:29 +00:00
2005-06-07 23:43:45 +00:00
if ( ! node & & type ! = MXML_IGNORE )
2003-06-03 19:46:29 +00:00
{
/*
2005-05-18 01:45:20 +00:00
* Print error and return . . .
2003-06-03 19:46:29 +00:00
*/
2019-01-05 17:23:17 +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 )
{
( * sax_cb ) ( node , MXML_SAX_DATA , sax_data ) ;
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
}
2007-09-09 07:27:08 +00:00
else if ( mxml_isspace ( ch ) & & type = = MXML_TEXT )
2003-06-04 16:30:40 +00:00
whitespace = 1 ;
2019-01-05 17:23:17 +00:00
if ( ch = = ' \n ' )
line + + ;
2003-06-04 16:30:40 +00:00
/*
2003-06-19 03:20:41 +00:00
* Add lone whitespace node if we have an element and existing
* whitespace . . .
2003-06-04 16:30:40 +00:00
*/
if ( ch = = ' < ' & & whitespace & & type = = MXML_TEXT )
{
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 )
{
( * sax_cb ) ( node , MXML_SAX_DATA , sax_data ) ;
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
2003-06-19 03:20:41 +00:00
whitespace = 0 ;
2003-06-04 16:30:40 +00:00
}
2003-06-03 19:46:29 +00:00
if ( ch = = ' < ' )
{
/*
* Start of open / close tag . . .
*/
bufptr = buffer ;
2004-05-16 21:54:47 +00:00
while ( ( ch = ( * getc_cb ) ( p , & 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 ) )
2003-06-03 19:46:29 +00:00
break ;
2007-04-18 02:45:47 +00:00
else if ( ch = = ' < ' )
{
2021-10-26 17:44:00 +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
{
2019-01-05 17:23:17 +00:00
if ( ( ch = mxml_get_entity ( parent , p , & encoding , getc_cb , & line ) ) = = EOF )
2003-12-21 15:01:15 +00:00
goto error ;
if ( mxml_add_char ( ch , & bufptr , & buffer , & bufsize ) )
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 ! = ' / ' )
goto error ;
2003-12-21 15:01:15 +00:00
else if ( mxml_add_char ( ch , & bufptr , & buffer , & bufsize ) )
goto error ;
2005-01-29 07:19:38 +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 ;
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
{
/*
2003-06-04 16:30:40 +00:00
* Gather rest of comment . . .
2003-06-04 01:23:21 +00:00
*/
2004-05-16 21:54:47 +00:00
while ( ( ch = ( * getc_cb ) ( p , & encoding ) ) ! = EOF )
2003-06-04 01:23:21 +00:00
{
2003-06-04 16:30:40 +00:00
if ( ch = = ' > ' & & bufptr > ( buffer + 4 ) & &
2005-01-29 07:19:38 +00:00
bufptr [ - 3 ] ! = ' - ' & & bufptr [ - 2 ] = = ' - ' & & bufptr [ - 1 ] = = ' - ' )
2003-06-04 16:30:40 +00:00
break ;
2005-01-29 07:19:38 +00:00
else if ( mxml_add_char ( ch , & bufptr , & buffer , & bufsize ) )
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
2005-01-29 07:19:38 +00:00
/*
* Error out if we didn ' t get the whole comment . . .
*/
if ( ch ! = ' > ' )
2005-05-18 01:45:20 +00:00
{
/*
* Print error and return . . .
*/
2019-01-05 17:23:17 +00:00
mxml_error ( " Early EOF in comment node on line %d. " , line ) ;
2005-05-18 01:45:20 +00:00
goto error ;
}
2005-01-29 07:19:38 +00:00
/*
* Otherwise add this as an element under the current parent . . .
*/
* bufptr = ' \0 ' ;
2010-09-19 06:14:36 +00:00
if ( ! parent & & first )
{
/*
* There can only be one root element !
*/
2019-01-05 17:23:17 +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 )
2005-01-29 07:19:38 +00:00
{
/*
* Just print error for now . . .
*/
2019-01-05 17:23:17 +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
2007-04-23 21:48:03 +00:00
if ( sax_cb )
{
( * sax_cb ) ( node , MXML_SAX_COMMENT , sax_data ) ;
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[ " ) )
{
/*
* Gather CDATA section . . .
*/
while ( ( ch = ( * getc_cb ) ( p , & encoding ) ) ! = EOF )
{
if ( ch = = ' > ' & & ! strncmp ( bufptr - 2 , " ]] " , 2 ) )
2017-03-30 01:42:30 +00:00
{
/*
* Drop terminator from CDATA string . . .
*/
bufptr [ - 2 ] = ' \0 ' ;
2005-01-29 07:19:38 +00:00
break ;
2017-03-30 01:42:30 +00:00
}
2005-01-29 07:19:38 +00:00
else if ( mxml_add_char ( ch , & bufptr , & buffer , & bufsize ) )
goto error ;
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
2003-06-04 16:30:40 +00:00
/*
* Error out if we didn ' t get the whole comment . . .
*/
if ( ch ! = ' > ' )
2005-05-18 01:45:20 +00:00
{
/*
* Print error and return . . .
*/
2019-01-05 17:23:17 +00:00
mxml_error ( " Early EOF in CDATA node on line %d. " , line ) ;
2005-05-18 01:45:20 +00:00
goto error ;
}
2003-06-04 16:30:40 +00:00
/*
* Otherwise add this as an element under the current parent . . .
*/
* bufptr = ' \0 ' ;
2010-09-19 06:14:36 +00:00
if ( ! parent & & first )
{
/*
* There can only be one root element !
*/
2019-01-05 17:23:17 +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-04 16:30:40 +00:00
{
/*
2005-05-18 01:45:20 +00:00
* Print error and return . . .
2003-06-04 16:30:40 +00:00
*/
2019-01-05 17:23:17 +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
2007-04-23 21:48:03 +00:00
if ( sax_cb )
{
( * sax_cb ) ( node , MXML_SAX_CDATA , sax_data ) ;
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 ] = = ' ? ' )
{
/*
* Gather rest of processing instruction . . .
*/
while ( ( ch = ( * getc_cb ) ( p , & encoding ) ) ! = EOF )
{
if ( ch = = ' > ' & & bufptr > buffer & & bufptr [ - 1 ] = = ' ? ' )
break ;
else if ( mxml_add_char ( ch , & bufptr , & buffer , & bufsize ) )
goto error ;
2019-01-05 17:23:17 +00:00
if ( ch = = ' \n ' )
line + + ;
2005-01-29 07:19:38 +00:00
}
/*
2005-05-18 01:45:20 +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
{
/*
* Print error and return . . .
*/
2019-01-05 17:23:17 +00:00
mxml_error ( " Early EOF in processing instruction node on line %d. " , line ) ;
2005-05-18 01:45:20 +00:00
goto error ;
}
2005-01-29 07:19:38 +00:00
/*
* Otherwise add this as an element under the current parent . . .
*/
* bufptr = ' \0 ' ;
2019-07-08 18:15:19 +00:00
if ( ! parent & & first )
2010-09-19 06:14:36 +00:00
{
/*
* There can only be one root element !
*/
2019-01-05 17:23:17 +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
}
2007-04-23 21:48:03 +00:00
if ( ( node = mxmlNewElement ( parent , buffer ) ) = = NULL )
2005-01-29 07:19:38 +00:00
{
/*
2005-05-18 01:45:20 +00:00
* Print error and return . . .
2005-01-29 07:19:38 +00:00
*/
2019-01-05 17:23:17 +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
}
2007-04-23 21:48:03 +00:00
if ( sax_cb )
{
( * sax_cb ) ( node , MXML_SAX_DIRECTIVE , sax_data ) ;
2005-08-16 14:46:18 +00:00
2019-07-04 02:27:11 +00:00
if ( strncmp ( node - > value . element . name , " ?xml " , 5 ) & & ! 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
2008-01-13 00:42:35 +00:00
if ( cb )
type = ( * cb ) ( parent ) ;
2014-10-19 17:21:48 +00:00
else
type = MXML_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 ] = = ' ! ' )
{
/*
* Gather rest of declaration . . .
*/
do
{
if ( ch = = ' > ' )
break ;
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
{
if ( ( ch = mxml_get_entity ( parent , p , & encoding , getc_cb , & 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
if ( mxml_add_char ( ch , & bufptr , & buffer , & bufsize ) )
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
}
2004-05-16 21:54:47 +00:00
while ( ( ch = ( * getc_cb ) ( p , & encoding ) ) ! = EOF ) ;
2003-06-04 01:23:21 +00:00
2003-06-04 16:30:40 +00:00
/*
* Error out if we didn ' t get the whole declaration . . .
*/
2003-06-04 01:23:21 +00:00
2003-06-04 16:30:40 +00:00
if ( ch ! = ' > ' )
2005-05-18 01:45:20 +00:00
{
/*
* Print error and return . . .
*/
2019-01-05 17:23:17 +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
/*
* Otherwise add this as an element under the current parent . . .
*/
* bufptr = ' \0 ' ;
2010-09-19 06:14:36 +00:00
if ( ! parent & & first )
{
/*
* There can only be one root element !
*/
2019-01-05 17:23:17 +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-04 16:30:40 +00:00
{
/*
2005-05-18 01:45:20 +00:00
* Print error and return . . .
2003-06-04 16:30:40 +00:00
*/
2019-01-05 17:23:17 +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
}
2007-04-23 21:48:03 +00:00
if ( sax_cb )
{
( * sax_cb ) ( node , MXML_SAX_DIRECTIVE , sax_data ) ;
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 ;
if ( cb )
type = ( * cb ) ( parent ) ;
2014-10-19 17:21:48 +00:00
else
type = MXML_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
{
/*
* Handle close tag . . .
*/
if ( ! parent | | strcmp ( buffer + 1 , parent - > value . element . name ) )
{
/*
* Close tag doesn ' t match tree ; print an error for now . . .
*/
2019-01-05 17:23:17 +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
}
/*
* Keep reading until we see > . . .
*/
while ( ch ! = ' > ' & & ch ! = EOF )
2004-05-16 21:54:47 +00:00
ch = ( * getc_cb ) ( p , & 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 )
{
( * sax_cb ) ( node , MXML_SAX_ELEMENT_CLOSE , sax_data ) ;
2011-01-22 01:02:05 +00:00
if ( ! mxmlRelease ( node ) & & first = = node )
first = NULL ;
2007-04-23 21:48:03 +00:00
}
2003-06-03 19:46:29 +00:00
/*
* Ascend into the parent and set the value type as needed . . .
*/
2003-06-04 23:20:31 +00:00
if ( cb & & parent )
2003-06-03 19:46:29 +00:00
type = ( * cb ) ( parent ) ;
}
else
{
/*
* Handle open tag . . .
*/
2010-09-19 06:14:36 +00:00
if ( ! parent & & first )
{
/*
* There can only be one root element !
*/
2019-01-05 17:23:17 +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
{
/*
* Just print error for now . . .
*/
2019-01-05 17:23:17 +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
{
2019-01-05 17:23:17 +00:00
if ( ( ch = mxml_parse_element ( node , p , & encoding , getc_cb , & line ) ) = = EOF )
2007-09-09 08:11:25 +00:00
goto error ;
}
2003-06-03 19:46:29 +00:00
else if ( ch = = ' / ' )
{
2004-05-16 21:54:47 +00:00
if ( ( ch = ( * getc_cb ) ( p , & encoding ) ) ! = ' > ' )
2003-06-03 19:46:29 +00:00
{
2019-01-05 17:23:17 +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 ) ;
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 )
( * sax_cb ) ( node , MXML_SAX_ELEMENT_OPEN , sax_data ) ;
if ( ! first )
first = node ;
2003-06-03 19:46:29 +00:00
if ( ch = = EOF )
break ;
if ( ch ! = ' / ' )
{
/*
* Descend into this node , setting the value type as needed . . .
*/
parent = node ;
2003-06-04 23:20:31 +00:00
if ( cb & & parent )
2003-06-03 19:46:29 +00:00
type = ( * cb ) ( parent ) ;
2016-06-13 00:27:11 +00:00
else
type = MXML_TEXT ;
2003-06-03 19:46:29 +00:00
}
2007-04-23 21:48:03 +00:00
else if ( sax_cb )
{
( * sax_cb ) ( node , MXML_SAX_ELEMENT_CLOSE , sax_data ) ;
if ( ! mxmlRelease ( node ) & & first = = node )
first = NULL ;
}
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 = = ' & ' )
{
/*
2003-12-21 15:01:15 +00:00
* Add character entity to current buffer . . .
2003-06-03 19:46:29 +00:00
*/
2019-01-05 17:23:17 +00:00
if ( ( ch = mxml_get_entity ( parent , p , & encoding , getc_cb , & line ) ) = = EOF )
2003-12-21 15:01:15 +00:00
goto error ;
2003-06-03 19:46:29 +00:00
2003-12-21 15:01:15 +00:00
if ( mxml_add_char ( ch , & bufptr , & buffer , & bufsize ) )
goto error ;
2003-06-03 19:46:29 +00:00
}
2007-09-09 07:27:08 +00:00
else if ( type = = MXML_OPAQUE | | type = = MXML_CUSTOM | | ! mxml_isspace ( ch ) )
2003-06-03 19:46:29 +00:00
{
/*
* Add character to current buffer . . .
*/
2003-06-15 21:31:45 +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
}
}
2019-07-04 02:27:11 +00:00
while ( ( ch = ( * getc_cb ) ( p , & encoding ) ) ! = EOF ) ;
2003-06-03 19:46:29 +00:00
2003-06-15 21:31:45 +00:00
/*
* Free the string buffer - we don ' t need it anymore . . .
*/
free ( buffer ) ;
2003-06-03 19:46:29 +00:00
/*
* Find the top element and return it . . .
*/
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 )
{
2019-01-05 17:23:17 +00:00
mxml_error ( " Missing close tag </%s> under parent <%s> on line %d. " , node - > value . element . name , 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
/*
* 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
}
/*
* ' mxml_parse_element ( ) ' - Parse an element for any attributes . . .
*/
2004-05-16 21:54:47 +00:00
static int /* O - Terminating character */
2007-04-23 21:48:03 +00:00
mxml_parse_element (
mxml_node_t * node , /* I - Element node */
void * p , /* I - Data to read from */
int * encoding , /* IO - Encoding */
2019-01-05 17:23:17 +00:00
_mxml_getc_cb_t getc_cb , /* I - Data callback */
int * line ) /* IO - Current line number */
2003-06-03 19:46:29 +00:00
{
int ch , /* Current character in file */
quote ; /* Quoting character */
2003-06-15 21:31:45 +00:00
char * name , /* Attribute name */
* value , /* Attribute value */
2003-06-03 19:46:29 +00:00
* ptr ; /* Pointer into name/value */
2003-06-15 21:31:45 +00:00
int namesize , /* Size of name string */
valsize ; /* Size of value string */
2003-12-19 02:56:11 +00:00
2003-06-15 21:31:45 +00:00
/*
* Initialize the name and value buffers . . .
*/
if ( ( name = malloc ( 64 ) ) = = NULL )
{
2021-10-26 17:44:00 +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 ) ;
2021-10-26 17:44:00 +00:00
mxml_error ( " Unable to allocate memory for value. " ) ;
2003-06-15 21:31:45 +00:00
return ( EOF ) ;
}
valsize = 64 ;
2003-06-03 19:46:29 +00:00
/*
* Loop until we hit a > , / , ? , or EOF . . .
*/
2004-05-16 21:54:47 +00:00
while ( ( ch = ( * getc_cb ) ( p , encoding ) ) ! = EOF )
2003-06-03 19:46:29 +00:00
{
2003-12-03 03:59:04 +00:00
# if DEBUG > 1
2003-07-20 13:19:08 +00:00
fprintf ( stderr , " parse_element: ch='%c' \n " , ch ) ;
2003-12-03 03:59:04 +00:00
# endif /* DEBUG > 1 */
2003-06-19 04:25:12 +00:00
2003-06-03 19:46:29 +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
/*
* Stop at / , ? , or > . . .
*/
if ( ch = = ' / ' | | ch = = ' ? ' )
{
/*
* Grab the > character and print an error if it isn ' t there . . .
*/
2004-05-16 21:54:47 +00:00
quote = ( * getc_cb ) ( p , encoding ) ;
2003-06-03 19:46:29 +00:00
if ( quote ! = ' > ' )
{
2019-01-05 17:23:17 +00:00
mxml_error ( " Expected '>' after '%c' for element %s, but got '%c' on line %d. " , ch , node - > value . element . name , 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 = = ' < ' )
{
2019-01-05 17:23:17 +00:00
mxml_error ( " Bare < in element %s on line %d. " , node - > value . element . name , * line ) ;
2007-04-18 02:45:47 +00:00
goto error ;
}
2003-06-03 19:46:29 +00:00
else if ( ch = = ' > ' )
break ;
/*
* Read the attribute name . . .
*/
2020-10-02 20:36:19 +00:00
ptr = name ;
if ( mxml_add_char ( ch , & ptr , & name , & namesize ) )
goto error ;
2003-06-03 19:46:29 +00:00
2003-12-01 15:27:47 +00:00
if ( ch = = ' \" ' | | ch = = ' \' ' )
{
/*
* Name is in quotes , so get a quoted string . . .
*/
quote = ch ;
2004-05-16 21:54:47 +00:00
while ( ( ch = ( * getc_cb ) ( p , 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
{
if ( ( ch = mxml_get_entity ( node , p , encoding , getc_cb , line ) ) = = EOF )
2003-12-21 15:01:15 +00:00
goto error ;
2019-01-05 17:23:17 +00:00
}
else if ( ch = = ' \n ' )
( * line ) + + ;
2003-12-21 15:01:15 +00:00
2003-12-01 15:27:47 +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
{
/*
* Grab an normal , non - quoted name . . .
*/
2004-05-16 21:54:47 +00:00
while ( ( ch = ( * getc_cb ) ( p , 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 = = ' > ' | |
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
{
if ( ( ch = mxml_get_entity ( node , p , encoding , getc_cb , 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
if ( mxml_add_char ( ch , & ptr , & name , & namesize ) )
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
{
2019-11-17 13:38:38 +00:00
mxml_error ( " Duplicate attribute '%s' in element %s on line %d. " , name , node - > value . element . name , * 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
{
2008-01-13 00:42:35 +00:00
ch = ( * getc_cb ) ( p , encoding ) ;
2019-01-05 17:23:17 +00:00
if ( ch = = ' \n ' )
( * line ) + + ;
}
2003-06-03 19:46:29 +00:00
if ( ch = = ' = ' )
{
/*
* Read the attribute value . . .
*/
2019-01-05 17:23:17 +00:00
while ( ( ch = ( * getc_cb ) ( p , encoding ) ) ! = EOF & & mxml_isspace ( ch ) )
{
if ( ch = = ' \n ' )
( * line ) + + ;
}
2008-01-13 00:42:35 +00:00
if ( ch = = EOF )
2003-06-03 19:46:29 +00:00
{
2019-01-05 17:23:17 +00:00
mxml_error ( " Missing value for attribute '%s' in element %s on line %d. " , name , node - > value . element . name , * line ) ;
2007-09-09 08:22:12 +00:00
goto error ;
2003-06-03 19:46:29 +00:00
}
if ( ch = = ' \' ' | | ch = = ' \" ' )
{
/*
* Read quoted value . . .
*/
quote = ch ;
ptr = value ;
2004-05-16 21:54:47 +00:00
while ( ( ch = ( * getc_cb ) ( p , 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
{
if ( ( ch = mxml_get_entity ( node , p , encoding , getc_cb , line ) ) = = EOF )
2003-12-21 15:01:15 +00:00
goto error ;
2019-01-05 17:23:17 +00:00
}
else if ( ch = = ' \n ' )
( * line ) + + ;
2013-11-12 05:03:47 +00:00
2003-12-21 15:01:15 +00:00
if ( mxml_add_char ( ch , & ptr , & value , & valsize ) )
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
{
/*
* Read unquoted value . . .
*/
2020-01-10 19:55:59 +00:00
ptr = value ;
if ( mxml_add_char ( ch , & ptr , & value , & valsize ) )
goto error ;
2003-06-03 19:46:29 +00:00
2004-05-16 21:54:47 +00:00
while ( ( ch = ( * getc_cb ) ( p , 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
{
if ( ( ch = mxml_get_entity ( node , p , encoding , getc_cb , 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
2003-12-21 15:01:15 +00:00
if ( mxml_add_char ( ch , & ptr , & value , & valsize ) )
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
/*
* Set the attribute with the given string value . . .
*/
mxmlElementSetAttr ( node , name , value ) ;
2003-06-03 19:46:29 +00:00
}
else
2003-12-01 15:27:47 +00:00
{
2019-01-05 17:23:17 +00:00
mxml_error ( " Missing value for attribute '%s' in element %s on line %d. " , name , node - > value . element . name , * 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
/*
2003-12-01 15:27:47 +00:00
* Check the end character . . .
2003-06-03 19:46:29 +00:00
*/
2003-06-19 03:20:41 +00:00
if ( ch = = ' / ' | | ch = = ' ? ' )
{
/*
* Grab the > character and print an error if it isn ' t there . . .
*/
2004-05-16 21:54:47 +00:00
quote = ( * getc_cb ) ( p , encoding ) ;
2003-06-19 03:20:41 +00:00
if ( quote ! = ' > ' )
{
2019-01-05 17:23:17 +00:00
mxml_error ( " Expected '>' after '%c' for element %s, but got '%c' on line %d. " , ch , node - > value . element . name , 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
}
2003-06-15 21:31:45 +00:00
/*
* Free the name and value buffers and return . . .
*/
free ( name ) ;
free ( value ) ;
2003-06-03 19:46:29 +00:00
return ( ch ) ;
2003-12-21 15:01:15 +00:00
/*
* Common error return point . . .
*/
2019-01-05 17:23:17 +00:00
error :
2003-12-21 15:01:15 +00:00
free ( name ) ;
free ( value ) ;
return ( EOF ) ;
2003-06-03 19:46:29 +00:00
}
2003-06-19 03:20:41 +00:00
/*
* ' mxml_string_getc ( ) ' - Get a character from a string .
*/
2004-05-16 21:54:47 +00:00
static int /* O - Character or EOF */
mxml_string_getc ( void * p , /* I - Pointer to file */
int * encoding ) /* IO - Encoding */
2003-06-19 03:20:41 +00:00
{
int ch ; /* Character */
const char * * s ; /* Pointer to string pointer */
s = ( const char * * ) p ;
2004-10-26 21:04:32 +00:00
if ( ( ch = ( * s ) [ 0 ] & 255 ) ! = 0 | | * encoding = = ENCODE_UTF16LE )
2003-06-19 03:20:41 +00:00
{
2003-12-21 15:01:15 +00:00
/*
* Got character ; convert UTF - 8 to integer and return . . .
*/
2003-06-19 03:20:41 +00:00
( * s ) + + ;
2003-12-21 15:01:15 +00:00
2004-05-16 21:54:47 +00:00
switch ( * encoding )
2003-12-21 15:01:15 +00:00
{
2004-05-16 21:54:47 +00:00
case ENCODE_UTF8 :
if ( ! ( ch & 0x80 ) )
2005-01-29 07:19:38 +00:00
{
# if DEBUG > 1
printf ( " mxml_string_getc: %c (0x%04x) \n " , ch < ' ' ? ' . ' : ch , ch ) ;
# endif /* DEBUG > 1 */
2005-01-29 17:03:33 +00:00
if ( mxml_bad_char ( ch ) )
{
2021-10-26 17:44:00 +00:00
mxml_error ( " Bad control character 0x%02x not allowed by XML standard. " ,
2005-01-29 17:03:33 +00:00
ch ) ;
return ( EOF ) ;
}
2004-05-16 21:54:47 +00:00
return ( ch ) ;
2005-01-29 17:03:33 +00:00
}
2004-05-16 21:54:47 +00:00
else if ( ch = = 0xfe )
{
/*
* UTF - 16 big - endian BOM ?
*/
2003-12-21 15:01:15 +00:00
2004-10-26 21:04:32 +00:00
if ( ( ( * s ) [ 0 ] & 255 ) ! = 0xff )
2004-05-16 21:54:47 +00:00
return ( EOF ) ;
2003-12-21 15:01:15 +00:00
2004-05-16 21:54:47 +00:00
* encoding = ENCODE_UTF16BE ;
( * s ) + + ;
2003-12-21 15:01:15 +00:00
2004-05-16 21:54:47 +00:00
return ( mxml_string_getc ( p , encoding ) ) ;
}
else if ( ch = = 0xff )
{
/*
* UTF - 16 little - endian BOM ?
*/
2003-12-21 15:01:15 +00:00
2004-10-26 21:04:32 +00:00
if ( ( ( * s ) [ 0 ] & 255 ) ! = 0xfe )
2004-05-16 21:54:47 +00:00
return ( EOF ) ;
2003-12-21 15:01:15 +00:00
2004-05-16 21:54:47 +00:00
* encoding = ENCODE_UTF16LE ;
( * s ) + + ;
2003-12-21 15:01:15 +00:00
2004-05-16 21:54:47 +00:00
return ( mxml_string_getc ( p , encoding ) ) ;
}
else if ( ( ch & 0xe0 ) = = 0xc0 )
{
/*
* Two - byte value . . .
*/
2003-12-21 15:01:15 +00:00
2004-10-26 21:04:32 +00:00
if ( ( ( * s ) [ 0 ] & 0xc0 ) ! = 0x80 )
2004-05-16 21:54:47 +00:00
return ( EOF ) ;
2003-12-21 15:01:15 +00:00
2004-10-26 21:04:32 +00:00
ch = ( ( ch & 0x1f ) < < 6 ) | ( ( * s ) [ 0 ] & 0x3f ) ;
2003-12-21 15:01:15 +00:00
2004-05-16 21:54:47 +00:00
( * s ) + + ;
2004-10-28 01:07:00 +00:00
if ( ch < 0x80 )
2009-03-19 05:27:26 +00:00
{
2021-10-26 17:44:00 +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-10-28 01:07:00 +00:00
2005-01-29 07:19:38 +00:00
# if DEBUG > 1
printf ( " mxml_string_getc: %c (0x%04x) \n " , ch < ' ' ? ' . ' : ch , ch ) ;
# endif /* DEBUG > 1 */
2004-05-16 21:54:47 +00:00
return ( ch ) ;
}
else if ( ( ch & 0xf0 ) = = 0xe0 )
{
/*
* Three - byte value . . .
*/
2004-10-26 21:04:32 +00:00
if ( ( ( * s ) [ 0 ] & 0xc0 ) ! = 0x80 | |
( ( * s ) [ 1 ] & 0xc0 ) ! = 0x80 )
2004-05-16 21:54:47 +00:00
return ( EOF ) ;
2004-10-26 21:04:32 +00:00
ch = ( ( ( ( ch & 0x0f ) < < 6 ) | ( ( * s ) [ 0 ] & 0x3f ) ) < < 6 ) | ( ( * s ) [ 1 ] & 0x3f ) ;
2004-05-16 21:54:47 +00:00
( * s ) + = 2 ;
2004-10-28 01:07:00 +00:00
if ( ch < 0x800 )
2009-03-19 05:27:26 +00:00
{
2021-10-26 17:44:00 +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
}
2009-05-17 05:20:52 +00:00
/*
* Ignore ( strip ) Byte Order Mark ( BOM ) . . .
*/
if ( ch = = 0xfeff )
return ( mxml_string_getc ( p , encoding ) ) ;
2004-10-28 01:07:00 +00:00
2005-01-29 07:19:38 +00:00
# if DEBUG > 1
printf ( " mxml_string_getc: %c (0x%04x) \n " , ch < ' ' ? ' . ' : ch , ch ) ;
# endif /* DEBUG > 1 */
2004-05-16 21:54:47 +00:00
return ( ch ) ;
}
else if ( ( ch & 0xf8 ) = = 0xf0 )
{
/*
* Four - byte value . . .
*/
2004-10-26 21:04:32 +00:00
if ( ( ( * s ) [ 0 ] & 0xc0 ) ! = 0x80 | |
( ( * s ) [ 1 ] & 0xc0 ) ! = 0x80 | |
( ( * s ) [ 2 ] & 0xc0 ) ! = 0x80 )
2004-05-16 21:54:47 +00:00
return ( EOF ) ;
2004-10-26 21:04:32 +00:00
ch = ( ( ( ( ( ( ch & 0x07 ) < < 6 ) | ( ( * s ) [ 0 ] & 0x3f ) ) < < 6 ) |
( ( * s ) [ 1 ] & 0x3f ) ) < < 6 ) | ( ( * s ) [ 2 ] & 0x3f ) ;
2004-05-16 21:54:47 +00:00
( * s ) + = 3 ;
2004-10-28 01:07:00 +00:00
if ( ch < 0x10000 )
2009-03-19 05:27:26 +00:00
{
2021-10-26 17:44:00 +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-10-28 01:07:00 +00:00
2005-01-29 07:19:38 +00:00
# if DEBUG > 1
printf ( " mxml_string_getc: %c (0x%04x) \n " , ch < ' ' ? ' . ' : ch , ch ) ;
# endif /* DEBUG > 1 */
2004-05-16 21:54:47 +00:00
return ( ch ) ;
}
else
return ( EOF ) ;
case ENCODE_UTF16BE :
/*
* Read UTF - 16 big - endian char . . .
*/
2004-10-26 21:04:32 +00:00
ch = ( ch < < 8 ) | ( ( * s ) [ 0 ] & 255 ) ;
2004-05-16 21:54:47 +00:00
( * s ) + + ;
2005-01-29 17:03:33 +00:00
if ( mxml_bad_char ( ch ) )
{
2021-10-26 17:44:00 +00:00
mxml_error ( " Bad control character 0x%02x not allowed by XML standard. " ,
2005-01-29 17:03:33 +00:00
ch ) ;
return ( EOF ) ;
}
else if ( ch > = 0xd800 & & ch < = 0xdbff )
2004-05-16 21:54:47 +00:00
{
/*
* Multi - word UTF - 16 char . . .
*/
int lch ; /* Lower word */
2004-10-26 21:04:32 +00:00
if ( ! ( * s ) [ 0 ] )
2004-05-16 21:54:47 +00:00
return ( EOF ) ;
2004-10-26 21:04:32 +00:00
lch = ( ( ( * s ) [ 0 ] & 255 ) < < 8 ) | ( ( * s ) [ 1 ] & 255 ) ;
2004-05-16 21:54:47 +00:00
( * s ) + = 2 ;
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 ;
}
2005-01-29 07:19:38 +00:00
# if DEBUG > 1
printf ( " mxml_string_getc: %c (0x%04x) \n " , ch < ' ' ? ' . ' : ch , ch ) ;
# endif /* DEBUG > 1 */
2004-05-16 21:54:47 +00:00
return ( ch ) ;
case ENCODE_UTF16LE :
/*
* Read UTF - 16 little - endian char . . .
*/
2004-10-26 21:04:32 +00:00
ch = ch | ( ( ( * s ) [ 0 ] & 255 ) < < 8 ) ;
2004-05-16 21:54:47 +00:00
if ( ! ch )
{
( * s ) - - ;
return ( EOF ) ;
}
( * s ) + + ;
2005-01-29 17:03:33 +00:00
if ( mxml_bad_char ( ch ) )
{
2021-10-26 17:44:00 +00:00
mxml_error ( " Bad control character 0x%02x not allowed by XML standard. " ,
2005-01-29 17:03:33 +00:00
ch ) ;
return ( EOF ) ;
}
else if ( ch > = 0xd800 & & ch < = 0xdbff )
2004-05-16 21:54:47 +00:00
{
/*
* Multi - word UTF - 16 char . . .
*/
int lch ; /* Lower word */
2003-12-21 15:01:15 +00:00
2004-10-26 21:04:32 +00:00
if ( ! ( * s ) [ 1 ] )
2004-05-16 21:54:47 +00:00
return ( EOF ) ;
2003-12-21 15:01:15 +00:00
2004-10-26 21:04:32 +00:00
lch = ( ( ( * s ) [ 1 ] & 255 ) < < 8 ) | ( ( * s ) [ 0 ] & 255 ) ;
2004-05-16 21:54:47 +00:00
( * s ) + = 2 ;
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 ;
}
2005-01-29 07:19:38 +00:00
# if DEBUG > 1
printf ( " mxml_string_getc: %c (0x%04x) \n " , ch < ' ' ? ' . ' : ch , ch ) ;
# endif /* DEBUG > 1 */
2004-05-16 21:54:47 +00:00
return ( ch ) ;
2003-12-21 15:01:15 +00:00
}
2003-06-19 03:20:41 +00:00
}
2004-05-16 21:54:47 +00:00
return ( EOF ) ;
2003-06-19 03:20:41 +00:00
}
2003-06-19 04:25:12 +00:00
/*
* ' mxml_string_putc ( ) ' - Write a character to a string .
*/
static int /* O - 0 on success, -1 on failure */
mxml_string_putc ( int ch , /* I - Character to write */
void * p ) /* I - Pointer to string pointers */
{
char * * pp ; /* Pointer to string pointers */
pp = ( char * * ) p ;
2009-03-21 05:51:01 +00:00
if ( pp [ 0 ] < pp [ 1 ] )
pp [ 0 ] [ 0 ] = ch ;
2003-12-21 15:01:15 +00:00
2009-03-21 05:51:01 +00:00
pp [ 0 ] + + ;
2003-06-19 04:25:12 +00:00
return ( 0 ) ;
}
2003-12-01 15:27:47 +00:00
/*
* ' mxml_write_name ( ) ' - Write a name string .
*/
static int /* O - 0 on success, -1 on failure */
mxml_write_name ( const char * s , /* I - Name to write */
void * p , /* I - Write pointer */
int ( * putc_cb ) ( int , void * ) )
/* I - Write callback */
{
2003-12-18 04:16:37 +00:00
char quote ; /* Quote character */
const char * name ; /* Entity name */
2003-12-01 15:27:47 +00:00
if ( * s = = ' \" ' | | * s = = ' \' ' )
{
/*
* Write a quoted name string . . .
*/
if ( ( * putc_cb ) ( * s , p ) < 0 )
return ( - 1 ) ;
quote = * s + + ;
while ( * s & & * s ! = quote )
{
2003-12-18 04:16:37 +00:00
if ( ( name = mxmlEntityGetName ( * s ) ) ! = NULL )
2003-12-01 15:27:47 +00:00
{
if ( ( * putc_cb ) ( ' & ' , p ) < 0 )
return ( - 1 ) ;
2003-12-18 04:16:37 +00:00
while ( * name )
2003-12-01 15:27:47 +00:00
{
2003-12-18 04:16:37 +00:00
if ( ( * putc_cb ) ( * name , p ) < 0 )
2003-12-01 15:27:47 +00:00
return ( - 1 ) ;
2003-12-18 04:16:37 +00:00
name + + ;
2003-12-01 15:27:47 +00:00
}
2003-12-18 04:16:37 +00:00
if ( ( * putc_cb ) ( ' ; ' , p ) < 0 )
return ( - 1 ) ;
2003-12-01 15:27:47 +00:00
}
else if ( ( * putc_cb ) ( * s , p ) < 0 )
return ( - 1 ) ;
s + + ;
}
/*
* Write the end quote . . .
*/
if ( ( * putc_cb ) ( quote , p ) < 0 )
return ( - 1 ) ;
}
else
{
/*
* Write a non - quoted name string . . .
*/
while ( * s )
{
if ( ( * putc_cb ) ( * s , p ) < 0 )
return ( - 1 ) ;
s + + ;
}
}
return ( 0 ) ;
}
2003-06-04 02:34:30 +00:00
/*
* ' mxml_write_node ( ) ' - Save an XML node to a file .
*/
static int /* O - Column or -1 on error */
2007-04-23 21:48:03 +00:00
mxml_write_node ( mxml_node_t * node , /* I - Node to write */
void * p , /* I - File to write to */
mxml_save_cb_t cb , /* I - Whitespace callback */
int col , /* I - Current column */
2007-09-21 04:46:02 +00:00
_mxml_putc_cb_t putc_cb , /* I - Output callback */
_mxml_global_t * global ) /* I - Global data */
2003-06-04 02:34:30 +00:00
{
2016-06-12 21:12:11 +00:00
mxml_node_t * current , /* Current node */
* next ; /* Next node */
2003-12-01 15:27:47 +00:00
int i , /* Looping var */
width ; /* Width of attr + value */
2019-01-05 01:02:48 +00:00
_mxml_attr_t * attr ; /* Current attribute */
2003-06-19 04:25:12 +00:00
char s [ 255 ] ; /* Temporary string */
2003-06-04 02:34:30 +00:00
2010-09-19 07:27:48 +00:00
/*
2016-06-12 21:12:11 +00:00
* Loop through this node and all of its children . . .
2010-09-19 07:27:48 +00:00
*/
2016-06-12 21:12:11 +00:00
for ( current = node ; current ; current = next )
2003-06-04 02:34:30 +00:00
{
2016-06-12 21:12:11 +00:00
/*
* Print the node value . . .
*/
2010-09-19 07:27:48 +00:00
2016-06-12 21:12:11 +00:00
switch ( current - > type )
{
case MXML_ELEMENT :
col = mxml_write_ws ( current , p , cb , MXML_WS_BEFORE_OPEN , col , putc_cb ) ;
2003-06-04 02:34:30 +00:00
2016-06-12 21:12:11 +00:00
if ( ( * putc_cb ) ( ' < ' , p ) < 0 )
return ( - 1 ) ;
if ( current - > value . element . name [ 0 ] = = ' ? ' | |
2017-03-30 01:42:30 +00:00
! strncmp ( current - > value . element . name , " !-- " , 3 ) )
{
/*
* Comments and processing instructions do not use character
* entities .
*/
const char * ptr ; /* Pointer into name */
for ( ptr = current - > value . element . name ; * ptr ; ptr + + )
if ( ( * putc_cb ) ( * ptr , p ) < 0 )
return ( - 1 ) ;
}
else if ( ! strncmp ( current - > value . element . name , " ![CDATA[ " , 8 ) )
2016-06-12 21:12:11 +00:00
{
/*
2017-03-30 01:42:30 +00:00
* CDATA elements do not use character entities , but also need the
* " ]] " terminator added at the end .
2016-06-12 21:12:11 +00:00
*/
2003-06-04 17:37:23 +00:00
2016-06-12 21:12:11 +00:00
const char * ptr ; /* Pointer into name */
2005-01-29 07:19:38 +00:00
2016-06-12 21:12:11 +00:00
for ( ptr = current - > value . element . name ; * ptr ; ptr + + )
if ( ( * putc_cb ) ( * ptr , p ) < 0 )
return ( - 1 ) ;
2017-03-30 01:42:30 +00:00
if ( ( * putc_cb ) ( ' ] ' , p ) < 0 )
return ( - 1 ) ;
if ( ( * putc_cb ) ( ' ] ' , p ) < 0 )
return ( - 1 ) ;
2016-06-12 21:12:11 +00:00
}
else if ( mxml_write_name ( current - > value . element . name , p , putc_cb ) < 0 )
return ( - 1 ) ;
2005-01-29 07:19:38 +00:00
2016-06-12 21:12:11 +00:00
col + = strlen ( current - > value . element . name ) + 1 ;
2005-01-29 07:19:38 +00:00
2016-06-12 21:12:11 +00:00
for ( i = current - > value . element . num_attrs , attr = current - > value . element . attrs ;
i > 0 ;
i - - , attr + + )
{
2017-03-29 23:04:41 +00:00
width = ( int ) 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 )
{
if ( ( * putc_cb ) ( ' \n ' , p ) < 0 )
return ( - 1 ) ;
col = 0 ;
}
else
{
if ( ( * putc_cb ) ( ' ' , p ) < 0 )
return ( - 1 ) ;
col + + ;
}
if ( mxml_write_name ( attr - > name , p , putc_cb ) < 0 )
2010-09-19 07:27:48 +00:00
return ( - 1 ) ;
2003-06-04 02:34:30 +00:00
2016-06-12 21:12:11 +00:00
if ( attr - > value )
{
if ( ( * putc_cb ) ( ' = ' , p ) < 0 )
return ( - 1 ) ;
if ( ( * putc_cb ) ( ' \" ' , p ) < 0 )
return ( - 1 ) ;
if ( mxml_write_string ( attr - > value , p , putc_cb ) < 0 )
return ( - 1 ) ;
if ( ( * putc_cb ) ( ' \" ' , p ) < 0 )
return ( - 1 ) ;
}
col + = width ;
2010-09-19 07:27:48 +00:00
}
2016-06-12 21:12:11 +00:00
if ( current - > child )
2010-09-19 07:27:48 +00:00
{
2016-06-12 21:12:11 +00:00
/*
* Write children . . .
*/
if ( ( * putc_cb ) ( ' > ' , p ) < 0 )
2003-06-19 04:25:12 +00:00
return ( - 1 ) ;
2016-06-12 21:12:11 +00:00
else
col + + ;
2003-12-01 15:27:47 +00:00
2016-06-12 21:12:11 +00:00
col = mxml_write_ws ( current , p , cb , MXML_WS_AFTER_OPEN , col , putc_cb ) ;
2003-06-04 02:34:30 +00:00
}
2016-06-12 21:12:11 +00:00
else if ( current - > value . element . name [ 0 ] = = ' ! ' | |
current - > value . element . name [ 0 ] = = ' ? ' )
{
/*
* The ? and ! elements are special - cases . . .
*/
2003-06-04 02:34:30 +00:00
2016-06-12 21:12:11 +00:00
if ( ( * putc_cb ) ( ' > ' , p ) < 0 )
return ( - 1 ) ;
else
col + + ;
2003-06-04 02:34:30 +00:00
2016-06-12 21:12:11 +00:00
col = mxml_write_ws ( current , p , cb , MXML_WS_AFTER_OPEN , col , putc_cb ) ;
}
else
2010-09-19 07:27:48 +00:00
{
2016-06-12 21:12:11 +00:00
if ( ( * putc_cb ) ( ' ' , p ) < 0 )
2010-09-19 07:27:48 +00:00
return ( - 1 ) ;
2016-06-12 21:12:11 +00:00
if ( ( * putc_cb ) ( ' / ' , p ) < 0 )
2003-06-04 02:34:30 +00:00
return ( - 1 ) ;
2016-06-12 21:12:11 +00:00
if ( ( * putc_cb ) ( ' > ' , p ) < 0 )
2010-09-19 07:27:48 +00:00
return ( - 1 ) ;
2003-06-04 02:34:30 +00:00
2016-06-12 21:12:11 +00:00
col + = 3 ;
2003-06-04 21:19:00 +00:00
2016-06-12 21:12:11 +00:00
col = mxml_write_ws ( current , p , cb , MXML_WS_AFTER_OPEN , col , putc_cb ) ;
}
break ;
2003-06-04 02:34:30 +00:00
2016-06-12 21:12:11 +00:00
case MXML_INTEGER :
if ( current - > prev )
{
if ( global - > wrap > 0 & & col > global - > wrap )
{
if ( ( * putc_cb ) ( ' \n ' , p ) < 0 )
return ( - 1 ) ;
2005-01-29 07:19:38 +00:00
2016-06-12 21:12:11 +00:00
col = 0 ;
}
else if ( ( * putc_cb ) ( ' ' , p ) < 0 )
return ( - 1 ) ;
else
col + + ;
}
2003-06-04 21:19:00 +00:00
2018-12-03 16:21:39 +00:00
snprintf ( s , sizeof ( s ) , " %d " , current - > value . integer ) ;
2016-06-12 21:12:11 +00:00
if ( mxml_write_string ( s , p , putc_cb ) < 0 )
2010-09-19 07:27:48 +00:00
return ( - 1 ) ;
2003-06-04 02:34:30 +00:00
2016-06-12 21:12:11 +00:00
col + = strlen ( s ) ;
break ;
2003-06-04 21:19:00 +00:00
2016-06-12 21:12:11 +00:00
case MXML_OPAQUE :
if ( mxml_write_string ( current - > value . opaque , p , putc_cb ) < 0 )
return ( - 1 ) ;
2003-06-04 21:19:00 +00:00
2016-06-12 21:12:11 +00:00
col + = strlen ( current - > value . opaque ) ;
break ;
2010-09-19 07:27:48 +00:00
2016-06-12 21:12:11 +00:00
case MXML_REAL :
if ( current - > prev )
2003-06-04 21:19:00 +00:00
{
2016-06-12 21:12:11 +00:00
if ( global - > wrap > 0 & & col > global - > wrap )
{
if ( ( * putc_cb ) ( ' \n ' , p ) < 0 )
return ( - 1 ) ;
2010-09-19 07:27:48 +00:00
2016-06-12 21:12:11 +00:00
col = 0 ;
}
else if ( ( * putc_cb ) ( ' ' , p ) < 0 )
2003-07-20 13:19:08 +00:00
return ( - 1 ) ;
2016-06-12 21:12:11 +00:00
else
col + + ;
2003-06-04 17:37:23 +00:00
}
2003-06-04 02:34:30 +00:00
2018-12-03 16:21:39 +00:00
snprintf ( s , sizeof ( s ) , " %f " , current - > value . real ) ;
2016-06-12 21:12:11 +00:00
if ( mxml_write_string ( s , p , putc_cb ) < 0 )
2010-09-19 07:27:48 +00:00
return ( - 1 ) ;
2016-06-12 21:12:11 +00:00
col + = strlen ( s ) ;
break ;
2010-09-19 07:27:48 +00:00
2016-06-12 21:12:11 +00:00
case MXML_TEXT :
if ( current - > value . text . whitespace & & col > 0 )
2010-09-19 07:27:48 +00:00
{
2016-06-12 21:12:11 +00:00
if ( global - > wrap > 0 & & col > global - > wrap )
{
if ( ( * putc_cb ) ( ' \n ' , p ) < 0 )
return ( - 1 ) ;
2003-06-04 02:34:30 +00:00
2016-06-12 21:12:11 +00:00
col = 0 ;
}
else if ( ( * putc_cb ) ( ' ' , p ) < 0 )
return ( - 1 ) ;
else
col + + ;
2010-09-19 07:27:48 +00:00
}
2016-06-12 21:12:11 +00:00
if ( mxml_write_string ( current - > value . text . string , p , putc_cb ) < 0 )
2003-06-04 02:34:30 +00:00
return ( - 1 ) ;
2016-06-12 21:12:11 +00:00
col + = strlen ( current - > value . text . string ) ;
break ;
2003-06-04 02:34:30 +00:00
2016-06-12 21:12:11 +00:00
case MXML_CUSTOM :
if ( global - > custom_save_cb )
{
char * data ; /* Custom data string */
const char * newline ; /* Last newline in string */
2003-06-04 02:34:30 +00:00
2017-10-11 21:13:37 +00:00
if ( ( data = ( * global - > custom_save_cb ) ( current ) ) = = NULL )
2016-06-12 21:12:11 +00:00
return ( - 1 ) ;
2003-06-04 02:34:30 +00:00
2016-06-12 21:12:11 +00:00
if ( mxml_write_string ( data , p , putc_cb ) < 0 )
2003-06-04 02:34:30 +00:00
return ( - 1 ) ;
2016-06-12 21:12:11 +00:00
if ( ( newline = strrchr ( data , ' \n ' ) ) = = NULL )
col + = strlen ( data ) ;
else
2017-03-29 23:04:41 +00:00
col = ( int ) strlen ( newline ) ;
2016-06-12 21:12:11 +00:00
free ( data ) ;
break ;
2010-09-19 07:27:48 +00:00
}
2003-06-04 02:34:30 +00:00
2016-06-12 21:12:11 +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
2016-06-12 21:12:11 +00:00
/*
* Figure out the next node . . .
*/
2003-06-04 02:34:30 +00:00
2016-06-12 21:12:11 +00:00
if ( ( next = current - > child ) = = NULL )
{
2018-10-01 17:15:22 +00:00
if ( current = = node )
2016-06-12 21:12:11 +00:00
{
/*
2018-10-01 17:15:22 +00:00
* Don ' t traverse to sibling node if we are at the " root " node . . .
*/
2004-10-28 02:58:01 +00:00
2018-10-01 17:15:22 +00:00
next = NULL ;
}
else
{
/*
* Try the next sibling , and continue traversing upwards as needed . . .
*/
2004-10-28 02:58:01 +00:00
2018-10-01 17:15:22 +00:00
while ( ( next = current - > next ) = = NULL )
2010-09-19 07:27:48 +00:00
{
2018-10-01 17:15:22 +00:00
if ( current = = node | | ! current - > parent )
break ;
2004-10-28 02:58:01 +00:00
2018-10-01 17:15:22 +00:00
/*
* The ? and ! elements are special - cases and have no end tags . . .
*/
current = current - > parent ;
if ( current - > value . element . name [ 0 ] ! = ' ! ' & &
current - > value . element . name [ 0 ] ! = ' ? ' )
{
col = mxml_write_ws ( current , p , cb , MXML_WS_BEFORE_CLOSE , col , putc_cb ) ;
if ( ( * putc_cb ) ( ' < ' , p ) < 0 )
return ( - 1 ) ;
if ( ( * putc_cb ) ( ' / ' , p ) < 0 )
return ( - 1 ) ;
if ( mxml_write_string ( current - > value . element . name , p , putc_cb ) < 0 )
return ( - 1 ) ;
if ( ( * putc_cb ) ( ' > ' , p ) < 0 )
return ( - 1 ) ;
2004-10-28 02:58:01 +00:00
2018-10-01 17:15:22 +00:00
col + = strlen ( current - > value . element . name ) + 3 ;
2003-06-04 02:34:30 +00:00
2018-10-01 17:15:22 +00:00
col = mxml_write_ws ( current , p , cb , MXML_WS_AFTER_CLOSE , col , putc_cb ) ;
}
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 ) ;
}
2003-06-03 19:46:29 +00:00
/*
* ' mxml_write_string ( ) ' - Write a string , escaping & and < as needed .
*/
static int /* O - 0 on success, -1 on failure */
2007-04-23 21:48:03 +00:00
mxml_write_string (
const char * s , /* I - String to write */
void * p , /* I - Write pointer */
_mxml_putc_cb_t putc_cb ) /* I - Write callback */
2003-06-03 19:46:29 +00:00
{
2003-12-18 04:16:37 +00:00
const char * name ; /* Entity name, if any */
2003-06-19 04:25:12 +00:00
2003-06-03 19:46:29 +00:00
while ( * s )
{
2003-12-18 04:16:37 +00:00
if ( ( name = mxmlEntityGetName ( * s ) ) ! = NULL )
2003-06-03 19:46:29 +00:00
{
2003-06-19 04:25:12 +00:00
if ( ( * putc_cb ) ( ' & ' , p ) < 0 )
return ( - 1 ) ;
2003-06-04 16:30:40 +00:00
2003-12-18 04:16:37 +00:00
while ( * name )
2003-06-04 16:30:40 +00:00
{
2003-12-18 04:16:37 +00:00
if ( ( * putc_cb ) ( * name , p ) < 0 )
2003-06-19 04:25:12 +00:00
return ( - 1 ) ;
2003-12-18 04:16:37 +00:00
name + + ;
2003-06-19 04:25:12 +00:00
}
2003-12-18 04:16:37 +00:00
if ( ( * putc_cb ) ( ' ; ' , p ) < 0 )
return ( - 1 ) ;
2003-06-04 16:30:40 +00:00
}
2003-06-19 04:25:12 +00:00
else if ( ( * putc_cb ) ( * s , p ) < 0 )
2003-06-03 19:46:29 +00:00
return ( - 1 ) ;
s + + ;
}
return ( 0 ) ;
}
2003-06-04 21:19:00 +00:00
/*
* ' mxml_write_ws ( ) ' - Do whitespace callback . . .
*/
static int /* O - New column */
2007-04-23 21:48:03 +00:00
mxml_write_ws ( mxml_node_t * node , /* I - Current node */
void * p , /* I - Write pointer */
mxml_save_cb_t cb , /* I - Callback function */
int ws , /* I - Where value */
int col , /* I - Current column */
_mxml_putc_cb_t putc_cb ) /* I - Write callback */
2003-06-04 21:19:00 +00:00
{
2004-05-01 15:20:05 +00:00
const char * s ; /* Whitespace string */
2003-06-04 21:19:00 +00:00
2004-05-01 15:20:05 +00:00
if ( cb & & ( s = ( * cb ) ( node , ws ) ) ! = NULL )
2003-06-04 21:19:00 +00:00
{
2004-05-01 15:20:05 +00:00
while ( * s )
2003-06-04 21:19:00 +00:00
{
2004-05-01 15:20:05 +00:00
if ( ( * putc_cb ) ( * s , p ) < 0 )
return ( - 1 ) ;
else if ( * s = = ' \n ' )
col = 0 ;
else if ( * s = = ' \t ' )
{
col + = MXML_TAB ;
col = col - ( col % MXML_TAB ) ;
}
else
col + + ;
s + + ;
2003-06-04 21:19:00 +00:00
}
}
return ( col ) ;
}