2021-04-28 20:30:34 +02:00
/*
*
* Copyright ( c ) 2020 Jief
* All rights reserved .
*
*/
# ifndef __XML_LITE_H__
# define __XML_LITE_H__
2021-09-28 15:54:31 +02:00
# include "../cpp_foundation/XBool.h"
2021-04-28 20:30:34 +02:00
# include "../cpp_foundation/XStringArray.h"
# include "../cpp_lib/XmlLiteSimpleTypes.h"
# include "../cpp_lib/XmlLiteParser.h"
2021-05-08 11:34:17 +02:00
# if defined(_MSC_VER) && !defined(__PRETTY_FUNCTION__)
# define __PRETTY_FUNCTION__ __FUNCSIG__
# endif
2021-09-28 15:54:31 +02:00
XBool strnnIsEqual ( const char * key , size_t keyLength , const char * value , size_t valueLength ) ;
XBool strnIsEqual ( const char * key , size_t keyLength , const char * value ) ;
XBool strnnIsEqualIC ( const char * key , size_t keyLength , const char * value , size_t valueLength ) ;
XBool strnIsEqualIC ( const char * key , size_t keyLength , const char * value ) ;
2021-04-28 20:30:34 +02:00
2021-10-19 19:57:27 +02:00
enum class XmlParserMessageType
{
error ,
warning ,
info
} ;
2021-04-28 20:30:34 +02:00
class XmlParserMessage
{
public :
2021-10-19 19:57:27 +02:00
XmlParserMessageType type ;
2021-04-28 20:30:34 +02:00
XString8 msg ;
2021-10-19 19:57:27 +02:00
XmlParserMessage ( XmlParserMessageType _type , const XString8 & _msg ) : type ( _type ) , msg ( _msg ) { } ;
XString8 getFormattedMsg ( ) const {
if ( type = = XmlParserMessageType : : info ) return S8Printf ( " Info: %s " , msg . c_str ( ) ) ;
if ( type = = XmlParserMessageType : : warning ) return S8Printf ( " Warning: %s " , msg . c_str ( ) ) ;
if ( type = = XmlParserMessageType : : error ) return S8Printf ( " Error: %s " , msg . c_str ( ) ) ;
return msg ;
}
2021-04-28 20:30:34 +02:00
} ;
class XmlLiteParser ;
class XmlParserPosition
{
friend class XmlLiteParser ;
public :
char * p ;
int line ;
protected :
int col ;
public :
XmlParserPosition ( ) : p ( NULL ) , line ( 1 ) , col ( 1 ) { } ;
XmlParserPosition ( char * _p ) : p ( _p ) , line ( 1 ) , col ( 1 ) { } ;
int getLine ( ) const { return line ; }
int getCol ( ) const { return col ; }
2021-09-28 15:54:31 +02:00
XBool operator = = ( const XmlParserPosition & other ) const {
2021-04-28 20:30:34 +02:00
return p = = other . p ;
}
} ;
class XmlLiteParser
{
friend class XmlParserPosition ;
char * p_start = NULL ;
char * p_end = NULL ;
XmlParserPosition currentPos = XmlParserPosition ( ) ;
2021-10-30 08:58:43 +02:00
XObjArray < XmlParserMessage > XmlParserMessageArray = XObjArray < XmlParserMessage > ( ) ;
2021-04-28 20:30:34 +02:00
2021-10-19 19:57:27 +02:00
XBool AddXmlParserMessage ( XmlParserMessage * msg ) {
2021-10-30 08:58:43 +02:00
if ( XmlParserMessageArray . size ( ) < 500 ) XmlParserMessageArray . AddReference ( msg , true ) ;
if ( XmlParserMessageArray . size ( ) = = 500 ) XmlParserMessageArray . AddReference ( new XmlParserMessage ( XmlParserMessageType : : error , " Too many error. Stopping " _XS8 ) , true ) ;
2021-04-28 20:30:34 +02:00
return false ;
}
public :
2021-09-28 15:54:31 +02:00
XBool xmlParsingError = false ;
2021-10-30 08:58:43 +02:00
XBool productNameNeeded = false ;
2021-04-28 20:30:34 +02:00
XmlLiteParser ( ) { } ;
XmlLiteParser ( char * _p ) : p_start ( _p )
{
p_end = p_start + strlen ( p_start ) ;
} ;
XmlLiteParser ( const XmlLiteParser & ) = delete ;
XmlLiteParser & operator = ( const XmlLiteParser & ) = delete ;
void init ( const char * buf , size_t size ) ;
void init ( const char * buf ) { init ( buf , strlen ( buf ) ) ; } ;
int getLine ( ) { return currentPos . line ; }
int getCol ( ) { return currentPos . col ; }
2021-10-30 08:58:43 +02:00
XObjArray < XmlParserMessage > & getXmlParserMessageArray ( ) { return XmlParserMessageArray ; }
size_t getXmlParserInfoMessageCount ( ) const { size_t n = 0 ; for ( size_t i = 0 ; i < XmlParserMessageArray . size ( ) ; i + + ) if ( XmlParserMessageArray [ i ] . type = = XmlParserMessageType : : info ) + + n ; return n ; }
2021-04-28 20:30:34 +02:00
// Add warning, error and xml error always return false so you can return addWarning(...) from validate function
2021-10-19 19:57:27 +02:00
XBool addInfo ( XBool generateErrors , const XString8 & warning ) { if ( generateErrors ) AddXmlParserMessage ( new XmlParserMessage ( XmlParserMessageType : : info , warning ) ) ; return false ; }
XBool addWarning ( XBool generateErrors , const XString8 & warning ) { if ( generateErrors ) AddXmlParserMessage ( new XmlParserMessage ( XmlParserMessageType : : warning , warning ) ) ; return false ; }
XBool addError ( XBool generateErrors , const XString8 & warning ) { if ( generateErrors ) AddXmlParserMessage ( new XmlParserMessage ( XmlParserMessageType : : error , warning ) ) ; return false ; }
2021-04-28 20:30:34 +02:00
// Xml stuctural error. Parsing should probably stop.
2021-09-28 15:54:31 +02:00
XBool addXmlError ( XBool generateErrors , const XString8 & warning ) {
2021-10-19 19:57:27 +02:00
if ( generateErrors ) { xmlParsingError = true ; AddXmlParserMessage ( new XmlParserMessage ( XmlParserMessageType : : error , warning ) ) ; }
2021-04-28 20:30:34 +02:00
return false ;
}
2021-10-19 19:57:27 +02:00
void printfXmlParserMessage ( ) {
for ( size_t idx = 0 ; idx < getXmlParserMessageArray ( ) . size ( ) ; idx + + ) {
printf ( " %s: %s \n " , getXmlParserMessageArray ( ) [ idx ] . type = = XmlParserMessageType : : error ? " Error "
: getXmlParserMessageArray ( ) [ idx ] . type = = XmlParserMessageType : : warning ? " Warning "
: getXmlParserMessageArray ( ) [ idx ] . type = = XmlParserMessageType : : info ? " Info "
: " "
, getXmlParserMessageArray ( ) [ idx ] . msg . c_str ( ) ) ;
2021-04-28 20:30:34 +02:00
}
}
XmlParserPosition getPosition ( ) ;
void restorePosition ( XmlParserPosition & xml_position ) ;
2021-09-28 15:54:31 +02:00
XBool isEof ( ) const { return currentPos . p > = p_end ; }
2021-04-28 20:30:34 +02:00
char getchar ( ) ;
char * getcharPtr ( ) { return currentPos . p ; } ;
char moveForward ( ) ;
char moveForward ( int n ) ;
char moveBackward ( ) ;
char moveForwardUntil ( char until ) ;
char moveBackwardUntil ( char until ) ;
char moveForwardPastNext ( char until ) ;
char moveForwardUntilSignificant ( ) ;
char moveBackwardUntilSignificant ( ) ;
void skipHeader ( ) ;
/*
* The opening tag has been read . Skip until the closing tag
*/
2021-09-28 15:54:31 +02:00
XBool skipUntilClosingTag ( const char * tagToSkip , size_t tagToSkipLength , XBool generateErrors ) ;
XBool skipNextTag ( XBool generateErrors ) ;
2021-04-28 20:30:34 +02:00
/*
* Get the string from current position until the next ' < ' , or end of buffer .
* Spaces at begining or end are skipped .
* If current char is ' < ' , empty string is returned . ( * string = NULL and * length = 0 ) .
* If current char is ' / ' , empty string is returned . This is because getNextTag leaves to pinter to the ' / ' for empty tag .
* If no ' < ' , false is returned .
* Position at the ' < ' when exit .
*/
void getString ( const char * * string , size_t * length ) ;
/*
* Get the next tag , either opening or closing tag .
* For empty tag ( < / true > ) , first call return that it ' s an opening tag . Second call return that it ' s a closing tag .
*/
2021-09-28 15:54:31 +02:00
XBool getNextTag ( const char * * tag , size_t * length , XBool * isOpeningTag , XBool * isClosingTag , XBool generateErrors ) ;
XBool getSimpleTag ( const char * * tag , size_t * tagLength , const char * * value , size_t * valueLength , const char * expectedTag /*, XBool valueCanBeEmpty*/ , XBool generateErrors ) ;
2021-04-28 20:30:34 +02:00
2021-09-28 15:54:31 +02:00
XBool getSimpleTagValue ( const char * tag , size_t tagLength , const char * * value , size_t * valueLength , XmlParserPosition * xmlParserPosition , XBool generateErrors ) ;
2021-04-28 20:30:34 +02:00
/*
* Get the next tag , check it ' s a key , get the value and consume the closing tag ( " </key> " ) .
*/
2021-09-28 15:54:31 +02:00
XBool getKeyTagValue ( const char * * value , size_t * valueLength , XmlParserPosition * xmlParserPosition , XBool generateErrors ) ;
2021-04-28 20:30:34 +02:00
/*
* Check and consume the tag
* Returns true if it ' s the expected opening tag
* Returns false , add error in error list and don ' t change position if it ' s not
*/
2021-09-28 15:54:31 +02:00
XBool consumeOpeningTag ( const char * expectedTag , XBool generateErrors = true ) ;
2021-04-28 20:30:34 +02:00
/*
* Check and consume the tag
* Returns true if it ' s the expected closing tag
* Returns false , add error in error list and don ' t change position if it ' s not
*/
2021-09-28 15:54:31 +02:00
XBool consumeClosingTag ( const char * expectedTag , XBool generateErrors ) ;
2021-04-28 20:30:34 +02:00
/*
* Check but do NOT consume the tag
* Returns true if it ' s the expected opening tag
* Returns false , DO NOT add error in error list and don ' t change position if it ' s not
*/
2021-09-28 15:54:31 +02:00
XBool nextTagIsOpeningTag ( const char * expectedTag ) ;
XBool nextTagIsClosingTag ( const char * expectedTag ) ;
2021-04-28 20:30:34 +02:00
2021-09-28 15:54:31 +02:00
// XBool getTagBool(XmlBool* XmlBoolean);
2021-04-28 20:30:34 +02:00
} ;
2021-09-28 15:54:31 +02:00
# define RETURN_IF_FALSE(Expression) do { XBool b = Expression; if ( !b ) return false; } while (0);
2021-04-28 20:30:34 +02:00
# endif // __XML_LITE_H__