2024-12-21 10:04:04 +08:00
// ===================================================================
// Class: COXParser (including COXParserObject, COXAttribute, COXParserElement and COXToken)
// File: OXParser.cpp
// Purpose: Parser for XML like structures
// Version: 9.3
// This software along with its related components, documentation and files ("The Libraries")
// is <20> 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office. For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
//
//////////////////////////////////////////////////////////////////////
# include "stdafx.h"
# include "OXParser.h"
# include "UTBStrop.h"
# ifndef CSTR_EQUAL
# define CSTR_EQUAL 2 // string 1 equal to string 2
# endif
//////////////////////////////////////////////////////////////////////
// Macros for debugging
//////////////////////////////////////////////////////////////////////
# ifndef TRACE0 // If this isn't defined, a whole bunch of stuff isn't defined
# undef TRACE1
# undef TRACE2
# undef TRACE3
# undef UNUSED_ALWAYS
# undef UNUSED
# define UNUSED_ALWAYS(x) (x);
# ifdef _DEBUG
# define UNUSED(x)
# include <crtdbg.h>
# define TRACE0(text) _RPT0(_CRT_WARN, text)
# define TRACE1(format, a1) _RPT1(_CRT_WARN, format, a1)
# define TRACE2(format, a1, a2) _RPT2(_CRT_WARN, format, a1, a2)
# define TRACE3(format, a1, a2, a3) _RPT3(_CRT_WARN, format, a1, a2, a3)
# else
# define UNUSED(x) (x);
# define TRACE0(text)
# define TRACE1(format, a1)
# define TRACE2(format, a1, a2)
# define TRACE3(format, a1, a2, a3)
# endif
# endif
# ifdef _DEBUG
# define TRACE4(format, a1, a2, a3, a4 ) _RPT4(_CRT_WARN, format, a1, a2, a3, a4)
# else
# define TRACE4(format, a1, a2, a3, a4)
# endif
//////////////////////////////////////////////////////////////////////
// Static data
//////////////////////////////////////////////////////////////////////
// This is the list of default entities. Just add entities to this list
// and they will be automatically encoded/decoded during text processing.
// Note that when the parser writes out text, it will only convert from
// text to entity (eg '>' ==> >) when the literal text is a single character
// (so if you add "date == "10 May" and "10 May" appears in text, it won't
// be converted to "&date;")
ParserEntity COXParser : : m_Entity [ ] =
{
{ TEXT ( " gt " ) , TEXT ( " > " ) } ,
{ TEXT ( " lt " ) , TEXT ( " < " ) } ,
{ TEXT ( " amp " ) , TEXT ( " & " ) } ,
{ TEXT ( " apos " ) , TEXT ( " \' " ) } ,
{ TEXT ( " quot " ) , TEXT ( " \" " ) } ,
{ TEXT ( " quot " ) , TEXT ( " \" " ) } ,
{ TEXT ( " amp " ) , TEXT ( " & " ) } ,
{ TEXT ( " apos " ) , TEXT ( " \' " ) } ,
{ TEXT ( " lt " ) , TEXT ( " < " ) } ,
{ TEXT ( " gt " ) , TEXT ( " > " ) } ,
{ TEXT ( " nbsp " ) , TEXT ( " " ) } ,
{ TEXT ( " iexcl " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " cent " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " pound " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " curren " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " yen " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " brvbar " ) , TEXT ( " | " ) } ,
{ TEXT ( " sect " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " uml " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " copy " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " ordf " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " laquo " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " not " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " shy " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " reg " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " macr " ) , TEXT ( " - " ) } , // TEXT("?") -> "?"<22> <> Macron, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "?"<22> <> ǥ<> õ<EFBFBD> "-"<22> <> <20> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD>
{ TEXT ( " deg " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " plusmn " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " sup2 " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " sup3 " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " acute " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " micro " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " para " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " middot " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " cedil " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " sup1 " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " ordm " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " raquo " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " frac14 " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " frac12 " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " frac34 " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " iquest " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " Agrave " ) , TEXT ( " A " ) } , // "A"<22> <> LATIN CAPITAL LETTER A WITH GRAVE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "A"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Aacute " ) , TEXT ( " A " ) } , // "A"<22> <> LATIN CAPITAL LETTER A WITH ACUTE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "A"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Acirc " ) , TEXT ( " A " ) } , // "A"<22> <> LATIN CAPITAL LETTER A WITH CIRCUMFLEX, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "A"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Atilde " ) , TEXT ( " A " ) } , // "A"<22> <> LATIN CAPITAL LETTER A WITH TILDE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "A"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Auml " ) , TEXT ( " A " ) } , // "A"<22> <> LATIN CAPITAL LETTER A WITH DIAERESIS, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "A"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Aring " ) , TEXT ( " A " ) } , // "A"<22> <> LATIN CAPITAL LETTER A WITH ABOVE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "A"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " AElig " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " Ccedil " ) , TEXT ( " C " ) } , // "C"<22> <> LATIN CAPITAL LETTER C WITH CEDILLA, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "C"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Egrave " ) , TEXT ( " E " ) } , // "E"<22> <> LATIN CAPITAL LETTER E WITH GRAVE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "E"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Eacute " ) , TEXT ( " E " ) } , // "E"<22> <> LATIN CAPITAL LETTER E WITH ACUTE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "E"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Ecirc " ) , TEXT ( " E " ) } , // "E"<22> <> LATIN CAPITAL LETTER E WITH CIRCUMFLEX, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "E"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Euml " ) , TEXT ( " E " ) } , // "E"<22> <> LATIN CAPITAL LETTER E WITH DIAERESIS, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "E"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Igrave " ) , TEXT ( " I " ) } , // "I"<22> <> LATIN CAPTIAL LETTER I WITH GRAVE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "I"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Iacute " ) , TEXT ( " I " ) } , // "I"<22> <> LATIN CAPTIAL LETTER I WITH ACUTE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "I"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Icirc " ) , TEXT ( " I " ) } , // "I"<22> <> LATIN CAPTIAL LETTER I WITH CIRCUMFLEX, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "I"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Iuml " ) , TEXT ( " I " ) } , // "I"<22> <> LATIN CAPTIAL LETTER I WITH DIAERESIS, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "I"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " ETH " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " Ntilde " ) , TEXT ( " N " ) } , // "N"<22> <> LATIN CAPTIAL LETTER O WITH TILDE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "N"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Ograve " ) , TEXT ( " O " ) } , // "O"<22> <> LATIN CAPTIAL LETTER O WITH GRAVE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "O"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Oacute " ) , TEXT ( " O " ) } , // "O"<22> <> LATIN CAPTIAL LETTER O WITH ACUTE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "O"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Ocirc " ) , TEXT ( " O " ) } , // "O"<22> <> LATIN CAPTIAL LETTER O WITH CIRCUMFLEX, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "O"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Otilde " ) , TEXT ( " O " ) } , // "O"<22> <> LATIN CAPTIAL LETTER O WITH TILDE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "O"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Ouml " ) , TEXT ( " O " ) } , // "O"<22> <> LATIN CAPTIAL LETTER O WITH DIAERESIS, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "O"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " times " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " Oslash " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " Ugrave " ) , TEXT ( " U " ) } , // "U"<22> <> LATIN CAPTIAL LETTER U WITH GRAVE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "U"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Uacute " ) , TEXT ( " U " ) } , // "U"<22> <> LATIN CAPTIAL LETTER U WITH ACUTE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "U"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Ucirc " ) , TEXT ( " U " ) } , // "U"<22> <> LATIN CAPTIAL LETTER U WITH CIRCUMFLEX, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "U"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Uuml " ) , TEXT ( " U " ) } , // "U"<22> <> LATIN CAPTIAL LETTER U WITH DIAERESIS, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "U"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " Yacute " ) , TEXT ( " Y " ) } , // "Y"<22> <> LATIN CAPTIAL LETTER Y WITH ACUTE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "Y"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " THORN " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " szlig " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " agrave " ) , TEXT ( " a " ) } , // "a"<22> <> LATIN SMALL CAPTIAL LETTER a WITH GRAVE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "a"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " aacute " ) , TEXT ( " a " ) } , // "a"<22> <> LATIN SMALL CAPTIAL LETTER a WITH ACUTE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "a"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " acirc " ) , TEXT ( " a " ) } , // "a"<22> <> LATIN SMALL CAPTIAL LETTER a WITH CIRCUMFLEX, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "a"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " atilde " ) , TEXT ( " a " ) } , // "a"<22> <> LATIN SMALL CAPTIAL LETTER a WITH TILDE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "a"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " auml " ) , TEXT ( " a " ) } , // "a"<22> <> LATIN SMALL CAPTIAL LETTER a WITH DIAERESIS, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "a"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " aring " ) , TEXT ( " a " ) } , // "a"<22> <> LATIN SMALL CAPTIAL LETTER a WITH GRAVE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "a"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " aelig " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " ccedil " ) , TEXT ( " c " ) } , // "c"<22> <> LATIN SMALL CAPITAL LETTER c WITH CEDILLA, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "c"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " egrave " ) , TEXT ( " e " ) } , // "e"<22> <> LATIN SMALL CAPITAL LETTER e WITH GRAVE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "e"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " eacute " ) , TEXT ( " e " ) } , // "e"<22> <> LATIN SMALL CAPITAL LETTER e WITH ACUTE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "e"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " ecirc " ) , TEXT ( " e " ) } , // "e"<22> <> LATIN SMALL CAPITAL LETTER e WITH CIRCUMFLEX, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "e"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " euml " ) , TEXT ( " e " ) } , // "e"<22> <> LATIN SMALL CAPITAL LETTER e WITH DIAERESIS, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "e"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " igrave " ) , TEXT ( " i " ) } , // "i"<22> <> LATIN SMALL CAPITAL LETTER i WITH GRAVE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "i"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " iacute " ) , TEXT ( " i " ) } , // "i"<22> <> LATIN SMALL CAPITAL LETTER i WITH ACUTE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "i"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " icirc " ) , TEXT ( " i " ) } , // "i"<22> <> LATIN SMALL CAPITAL LETTER i WITH CIRCUMFLEX, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "i"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " iuml " ) , TEXT ( " i " ) } , // "i"<22> <> LATIN SMALL CAPITAL LETTER i WITH DIAERESIS, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "i"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " eth " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " ntilde " ) , TEXT ( " n " ) } , // "n"<22> <> LATIN SMALL CAPITAL LETTER n WITH TILDE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "n"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " ograve " ) , TEXT ( " o " ) } , // "o"<22> <> LATIN SMALL CAPITAL LETTER o WITH GRAVE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "o"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " oacute " ) , TEXT ( " o " ) } , // "o"<22> <> LATIN SMALL CAPITAL LETTER o WITH ACUTE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "o"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " ocirc " ) , TEXT ( " o " ) } , // "o"<22> <> LATIN SMALL CAPITAL LETTER o WITH CIRCUMFLEX, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "o"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " otilde " ) , TEXT ( " o " ) } , // "o"<22> <> LATIN SMALL CAPITAL LETTER o WITH TILDE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "o"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " ouml " ) , TEXT ( " o " ) } , // "o"<22> <> LATIN SMALL CAPITAL LETTER o WITH DIAERESIS, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "o"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " divide " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " oslash " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " ugrave " ) , TEXT ( " u " ) } , // "u"<22> <> LATIN SMALL CAPITAL LETTER o WITH GRAVE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "u"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " uacute " ) , TEXT ( " u " ) } , // "u"<22> <> LATIN SMALL CAPITAL LETTER o WITH ACUTE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "u"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " ucirc " ) , TEXT ( " u " ) } , // "u"<22> <> LATIN SMALL CAPITAL LETTER o WITH CIRCUMFLEX, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "u"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " uuml " ) , TEXT ( " u " ) } , // "u"<22> <> LATIN SMALL CAPITAL LETTER o WITH DIAERESIS, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "u"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " yacute " ) , TEXT ( " y " ) } , // "y"<22> <> LATIN SMALL CAPITAL LETTER y WITH ACUTE, VC6.0<EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> "y"<22> <> ǥ<> õ<EFBFBD>
{ TEXT ( " thorn " ) , TEXT ( " <EFBFBD> <EFBFBD> " ) } ,
{ TEXT ( " yuml " ) , TEXT ( " <EFBFBD> " ) } ,
{ NULL , NULL } // must be last
} ;
//////////////////////////////////////////////////////////////////////
// COXToken
//////////////////////////////////////////////////////////////////////
COXToken : : COXToken ( )
{
Clear ( ) ;
}
COXToken : : ~ COXToken ( )
{
Clear ( ) ;
}
// --- In<49> :
// --- Out :
// --- Returns :
// --- Effect : Resets the token to an empty state
void COXToken : : Clear ( )
{
m_nType = UNKNOWN ;
}
//////////////////////////////////////////////////////////////////////
// COXParserObject
//////////////////////////////////////////////////////////////////////
COXParserObject : : COXParserObject ( )
{
m_nType = UNKNOWN ;
m_pParent = NULL ;
m_nFlags = 0 ;
}
COXParserObject : : COXParserObject ( COXParserElement * pParent , int nType ,
LPCTSTR szText )
{
m_pParent = pParent ;
m_nType = nType ;
m_nFlags = 0 ;
SetText ( szText ) ;
}
COXParserObject : : ~ COXParserObject ( )
{
}
COXParserElement * COXParserObject : : GetParent ( ) const
{
if ( m_pParent & & m_pParent - > GetType ( ) = = ELEMENT )
return m_pParent ;
else
return NULL ;
}
BOOL COXParserObject : : SetText ( LPCTSTR szText )
{
return m_Text . SetString ( szText ) ;
}
BOOL COXParserObject : : IsText ( LPCTSTR szText ,
BOOL bCaseSensitive /*=FALSE*/ )
{
return m_Text . Compare ( szText , bCaseSensitive ) ;
}
//////////////////////////////////////////////////////////////////////
// COXAttribute
//////////////////////////////////////////////////////////////////////
COXAttribute : : COXAttribute ( )
{
m_nValue = 0 ;
SetType ( ATTRIBUTE ) ;
SetAttributeType ( ATTR_UNKNOWN ) ;
}
COXAttribute : : COXAttribute ( LPCTSTR szName , LPCTSTR szValue )
{
m_nValue = 0 ;
SetName ( szName ) ;
SetValue ( szValue ) ;
}
COXAttribute : : COXAttribute ( LPCTSTR szName , int nValue )
{
SetName ( szName ) ;
SetValue ( nValue ) ;
}
COXAttribute : : ~ COXAttribute ( )
{
m_szValue . Empty ( ) ;
}
LPCTSTR COXAttribute : : GetStringValue ( )
{
static TCHAR strValue [ 20 ] ;
if ( GetAttributeType ( ) = = ATTR_INTEGER )
{
UTBStr : : stprintf ( strValue , 20 , TEXT ( " %d " ) , m_nValue ) ;
return strValue ;
}
else if ( m_szValue . IsEmpty ( ) )
{
strValue [ 0 ] = TEXT ( ' \0 ' ) ;
return strValue ;
}
else
return m_szValue . GetString ( ) ;
}
int COXAttribute : : GetIntValue ( ) const
{
if ( GetAttributeType ( ) = = ATTR_STRING )
return 0 ;
else
return m_nValue ;
}
void COXAttribute : : SetValue ( LPCTSTR szValue )
{
m_szValue . SetString ( szValue ) ;
SetAttributeType ( ATTR_STRING ) ;
}
void COXAttribute : : SetValue ( int nValue )
{
if ( GetAttributeType ( ) = = ATTR_STRING )
m_szValue . Empty ( ) ;
m_nValue = nValue ;
SetAttributeType ( ATTR_INTEGER ) ;
}
BOOL COXAttribute : : IsValue ( LPCTSTR szValue ,
BOOL bCaseSensitive /*=FALSE*/ )
{
if ( ! szValue | | GetAttributeType ( ) ! = ATTR_STRING | | ! m_szValue )
return FALSE ;
BOOL bFound = FALSE ;
if ( ! bCaseSensitive )
bFound = ( _tcsicmp ( m_szValue , szValue ) = = 0 ) ;
else
bFound = ( _tcscmp ( m_szValue , szValue ) = = 0 ) ;
return bFound ;
}
void COXAttribute : : operator = ( COXAttribute & Attr )
{
SetType ( Attr . GetType ( ) ) ;
SetName ( Attr . GetName ( ) ) ;
if ( Attr . GetAttributeType ( ) = = ATTR_STRING )
SetValue ( Attr . GetStringValue ( ) ) ;
else
SetValue ( Attr . GetIntValue ( ) ) ;
}
//////////////////////////////////////////////////////////////////////
// COXParserElement
//////////////////////////////////////////////////////////////////////
COXParserElement : : COXParserElement ( )
{
SetType ( ELEMENT ) ;
}
COXParserElement : : COXParserElement ( COXParserElement * pParent ,
LPCTSTR szName )
{
SetParent ( pParent ) ;
SetType ( ELEMENT ) ;
SetName ( szName ) ;
}
COXParserElement : : ~ COXParserElement ( )
{
Clear ( ) ;
}
COXParserObject * COXParserElement : : AddObject ( COXParserObject * pObject )
{
pObject - > SetParent ( this ) ;
m_Objects . push_back ( pObject ) ;
return pObject ;
}
COXParserElement * COXParserElement : : AddElement ( LPCTSTR szName )
{
COXParserElement * pElement = new COXParserElement ( this , szName ) ;
if ( ! pElement )
return NULL ;
return ( COXParserElement * ) AddObject ( pElement ) ;
}
COXParserObject * COXParserElement : : InsertObject ( int nIndex ,
COXParserObject * pObject )
{
pObject - > SetParent ( this ) ;
m_Objects . insert ( m_Objects . begin ( ) + nIndex , pObject ) ;
return pObject ;
}
COXParserObject * COXParserElement : : MoveObject ( int nIndex ,
COXParserObject * pObject )
{
if ( ! pObject )
return FALSE ;
// Find object and remove it from the list
for ( int i = 0 ; i < NumObjects ( ) ; i + + )
{
if ( Object ( i ) = = pObject )
{
m_Objects . erase ( m_Objects . begin ( ) + i ) ;
break ;
}
}
return InsertObject ( nIndex , pObject ) ;
}
COXParserElement * COXParserElement : : InsertElement ( int nIndex ,
LPCTSTR szName )
{
COXParserElement * pElement = new COXParserElement ( this , szName ) ;
if ( ! pElement )
return NULL ;
return ( COXParserElement * ) InsertObject ( nIndex , pElement ) ;
}
BOOL COXParserElement : : DelObject ( int nIndex )
{
if ( nIndex > = NumObjects ( ) )
return FALSE ;
COXParserObject * pObject = Object ( nIndex ) ;
if ( pObject )
delete pObject ;
m_Objects . erase ( m_Objects . begin ( ) + nIndex ) ;
return TRUE ;
}
BOOL COXParserElement : : DelObject ( COXParserObject * pObject )
{
if ( ! pObject )
return FALSE ;
for ( int i = 0 ; i < NumObjects ( ) ; i + + )
{
if ( Object ( i ) = = pObject )
return DelObject ( i ) ;
}
return FALSE ;
}
void COXParserElement : : ClearObjects ( )
{
for ( int i = 0 ; i < NumObjects ( ) ; i + + )
{
COXParserObject * pObject = Object ( i ) ;
if ( pObject )
delete pObject ;
}
m_Objects . clear ( ) ;
}
# if _MSC_VER >=1200
# pragma warning(push)
# endif
# pragma warning(disable:4239)
COXParserElement * COXParserElement : : FindElement ( LPCTSTR szName ,
BOOL bCaseSensitive /*=FALSE*/ )
{
COXQuickString str = szName ;
UINT nLevel = 0 ;
COXQuickString strFolderName = str . GetToken ( nLevel + + , TEXT ( ' \\ ' ) ) ;
if ( strFolderName . IsEmpty ( ) )
return NULL ;
COXParserElement * pElement = this ;
COXParserElement * pTargetElement = NULL ;
while ( ! strFolderName . IsEmpty ( ) )
{
pTargetElement = NULL ;
for ( int i = 0 ; i < pElement - > NumObjects ( ) ; i + + )
{
COXParserElement * pSearchElement =
( COXParserElement * ) pElement - > Object ( i ) ;
if ( ! pSearchElement | | pSearchElement - > GetType ( ) ! = ELEMENT )
continue ;
// Found folder
if ( pSearchElement - > IsName ( strFolderName , bCaseSensitive ) )
{
pTargetElement = pSearchElement ;
pElement = pTargetElement ;
break ;
}
}
strFolderName = str . GetToken ( nLevel + + , TEXT ( ' \\ ' ) ) ;
}
return pTargetElement ;
}
# if _MSC_VER >=1200
# pragma warning(pop)
# else
# pragma warning(default:4239)
# endif
COXAttribute * COXParserElement : : AddAttribute ( COXAttribute * pAttribute )
{
pAttribute - > SetParent ( this ) ;
m_Attributes . push_back ( pAttribute ) ;
return pAttribute ;
}
COXAttribute * COXParserElement : : AddAttribute ( LPCTSTR szName ,
LPCTSTR szValue )
{
COXAttribute * pAttribute = new COXAttribute ;
if ( ! pAttribute )
return NULL ;
pAttribute - > SetName ( szName ) ;
pAttribute - > SetValue ( szValue ) ;
pAttribute - > SetParent ( this ) ;
return AddAttribute ( pAttribute ) ;
}
COXAttribute * COXParserElement : : AddAttribute ( LPCTSTR szName ,
int nValue )
{
COXAttribute * pAttribute = new COXAttribute ;
if ( ! pAttribute )
return NULL ;
pAttribute - > SetName ( szName ) ;
pAttribute - > SetValue ( nValue ) ;
pAttribute - > SetParent ( this ) ;
return AddAttribute ( pAttribute ) ;
}
BOOL COXParserElement : : DelAttribute ( int nIndex )
{
if ( nIndex > = NumAttributes ( ) )
return FALSE ;
COXAttribute * pAttribute = Attribute ( nIndex ) ;
delete pAttribute ;
m_Attributes . erase ( m_Attributes . begin ( ) + nIndex ) ;
return TRUE ;
}
BOOL COXParserElement : : DelAttribute ( COXAttribute * pAttribute )
{
if ( ! pAttribute )
return FALSE ;
for ( int i = 0 ; i < NumAttributes ( ) ; i + + )
{
if ( Attribute ( i ) = = pAttribute )
return DelAttribute ( i ) ;
}
return FALSE ;
}
void COXParserElement : : ClearAttributes ( )
{
for ( int i = 0 ; i < NumAttributes ( ) ; i + + )
{
COXAttribute * pAttribute = Attribute ( i ) ;
delete pAttribute ;
}
m_Attributes . clear ( ) ;
}
COXAttribute * COXParserElement : : FindAttribute ( LPCTSTR szName ,
bool bCaseSensitive /*=false*/ )
{
if ( ! szName )
return NULL ;
for ( int i = 0 ; i < NumAttributes ( ) ; i + + )
{
COXAttribute * pAttribute = Attribute ( i ) ;
if ( pAttribute - > IsName ( szName , ( BOOL ) bCaseSensitive ) )
return pAttribute ;
}
return NULL ;
}
COXAttribute * COXParserElement : : FindAttribute ( LPCTSTR szName ,
LPCTSTR szValue ,
bool bCaseSensitive /*=false*/ )
{
if ( ! szName | | ! szValue )
return NULL ;
for ( int i = 0 ; i < NumAttributes ( ) ; i + + )
{
COXAttribute * pAttribute = Attribute ( i ) ;
if ( ! pAttribute | |
pAttribute - > GetAttributeType ( ) ! = COXAttribute : : ATTR_STRING )
continue ;
if ( pAttribute - > IsName ( szName , ( BOOL ) bCaseSensitive ) & &
pAttribute - > IsValue ( szValue , ( BOOL ) bCaseSensitive ) )
return pAttribute ;
}
return NULL ;
}
COXAttribute * COXParserElement : : FindAttribute ( LPCTSTR szName , int nValue ,
bool bCaseSensitive /*=false*/ )
{
if ( ! szName )
return NULL ;
for ( int i = 0 ; i < NumAttributes ( ) ; i + + )
{
COXAttribute * pAttribute = Attribute ( i ) ;
if ( ! pAttribute | |
pAttribute - > GetAttributeType ( ) ! = COXAttribute : : ATTR_INTEGER )
continue ;
if ( pAttribute - > IsName ( szName , ( BOOL ) bCaseSensitive ) & &
pAttribute - > GetIntValue ( ) = = nValue )
return pAttribute ;
}
return NULL ;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
COXParser : : COXParser ( )
{
m_chStartDelim = TEXT ( ' < ' ) ;
m_chEndDelim = TEXT ( ' > ' ) ;
m_chTagEnd = TEXT ( ' / ' ) ;
m_chProcInstr = TEXT ( ' ? ' ) ;
m_chMarkup = TEXT ( ' ! ' ) ;
m_chDash = TEXT ( ' - ' ) ;
m_chCR = TEXT ( ' \r ' ) ;
m_chLF = TEXT ( ' \n ' ) ;
m_chNULL = TEXT ( ' \0 ' ) ;
m_chEsc = TEXT ( ' & ' ) ;
m_szTab = TEXT ( " " ) ; // indent tab when writing XML files
m_nLineLength = 80 ; // Max length of a line of text when writing files
m_bErrorOnMissingTag = TRUE ;
m_bCaseSensitive = TRUE ;
m_nLine = 0 ;
m_nColumn = 0 ;
m_pfnErrorFn = NULL ;
m_dwErrData = 0 ;
// Fill hash table with special characters
for ( int i = 0 ; m_Entity [ i ] . szName ; i + + )
m_EntityTable . Add ( m_Entity [ i ] . szName ,
( DWORD ) ( INT_PTR ) m_Entity [ i ] . szLiteral ) ;
}
COXParser : : ~ COXParser ( )
{
Clear ( ) ;
}
//////////////////////////////////////////////////////////////////////
// Parsing routines
//////////////////////////////////////////////////////////////////////
void COXParser : : Clear ( )
{
m_Token . Clear ( ) ;
m_Root . ClearObjects ( ) ;
m_Root . ClearAttributes ( ) ;
m_nLine = 0 ;
m_nColumn = 0 ;
m_pBuf = m_pBufStart = NULL ;
}
BOOL COXParser : : Initialize ( )
{
m_pBuf = m_pBufStart ;
m_nLine = 1 ;
m_nColumn = 1 ;
m_Root . SetName ( TEXT ( " [Root] " ) ) ;
m_Root . SetParent ( NULL ) ;
return TRUE ;
}
BOOL COXParser : : Cleanup ( )
{
return TRUE ;
}
BOOL COXParser : : IsEmpty ( ) const
{
return ( ! m_Root . NumAttributes ( ) & & ! m_Root . NumObjects ( ) ) ;
}
void COXParser : : SetErrorRptFunction ( ParserErrorFn pFn , DWORD dwData )
{
m_pfnErrorFn = pFn ;
m_dwErrData = dwData ;
}
BOOL COXParser : : Parse ( LPTSTR pBuf )
{
if ( ! pBuf )
return FALSE ;
Clear ( ) ;
m_pBufStart = pBuf ;
Initialize ( ) ;
BOOL bResult = ParseElement ( & m_Root , 0 ) ;
Cleanup ( ) ;
return bResult ;
}
TCHAR COXParser : : GetNextChar ( int nSteps /*=1*/ ,
BOOL bWarnOnError /*=FALSE*/ )
{
ASSERT ( m_pBuf ) ;
if ( ! m_pBuf )
{
if ( bWarnOnError )
ReportError ( ERROR_NULL_BUFFER , TEXT ( " NULL buffer supplied. " ) ) ;
return m_chNULL ;
}
TCHAR ch = * m_pBuf ;
for ( int i = 0 ; i < nSteps & & ch ; i + + )
{
ch = * m_pBuf ;
if ( ! ch )
break ;
m_pBuf + + ;
// Convert CRLF's to LF's, and CR's to LF's
if ( ch = = m_chCR )
{
ch = m_chLF ;
if ( * m_pBuf = = m_chLF )
m_pBuf + + ;
}
m_nColumn + + ;
if ( ch = = m_chLF )
{
m_nLine + + ;
m_nColumn = 0 ;
}
}
if ( ch = = m_chNULL )
{
if ( bWarnOnError )
ReportError ( ERROR_END_OF_BUFFER ,
TEXT ( " Unexpected end of buffer. " ) ) ;
return m_chNULL ;
}
return ch ;
}
void COXParser : : UngetChar ( int nSteps /*=1*/ )
{
for ( int i = 0 ; i < nSteps ; i + + )
{
if ( m_pBuf < = m_pBufStart )
break ;
m_pBuf - - ;
if ( * m_pBuf = = m_chLF | |
( * m_pBuf = = m_chCR & & * ( m_pBuf + 1 ) ! = m_chLF ) )
{
m_nLine - - ;
m_nColumn = 0 ;
for ( LPTSTR ptr = m_pBuf ;
ptr > = m_pBufStart & & * ptr ! = m_chLF & & * ptr ! = m_chCR ;
ptr - - )
m_nColumn + + ;
}
else
m_nColumn - - ;
}
}
BOOL COXParser : : RemoveWhiteSpace ( )
{
TCHAR ch = GetNextChar ( ) ;
while ( ch & & _istspace ( ch ) )
ch = GetNextChar ( ) ;
if ( ch )
{
UngetChar ( ) ;
return TRUE ;
}
else
{
return FALSE ;
}
}
void COXParser : : SaveBufferPos ( SAVEPOS & pos )
{
pos . pBuf = m_pBuf ;
pos . nLine = m_nLine ;
pos . nCol = m_nColumn ;
}
void COXParser : : RestoreBufferPos ( SAVEPOS & pos )
{
m_pBuf = pos . pBuf ;
m_nLine = pos . nLine ;
m_nColumn = pos . nCol ;
}
BOOL COXParser : : GetNameToken ( COXQuickString & str )
{
str . Empty ( ) ;
str . SetLength ( 100 ) ;
TCHAR ch = GetNextChar ( ) ;
while ( ch & & ! _istspace ( ch ) & &
( _istalnum ( ch ) | | ch = = TEXT ( ' : ' ) | |
ch = = TEXT ( ' _ ' ) | | ch = = TEXT ( ' - ' ) ) )
{
str . Append ( ch ) ;
ch = GetNextChar ( ) ;
}
BOOL bResult = TRUE ;
if ( ch = = m_chNULL )
{
ReportError ( ERROR_END_OF_BUFFER ,
TEXT ( " Unexpected end of buffer while name. " ) ) ;
bResult = FALSE ;
}
else if ( ch ! = m_chEndDelim & & ch ! = m_chTagEnd & &
ch ! = TEXT ( ' = ' ) & & ! _istspace ( ch ) )
{
ReportError ( ERROR_ILLEGAL_CHAR ,
TEXT ( " Illegal character (%c) encountered while parsing name. " ) , ch ) ;
bResult = FALSE ;
}
if ( bResult )
UngetChar ( ) ;
else
str . Empty ( ) ;
return bResult ;
}
BOOL COXParser : : GetNumberToken ( int & nNumber )
{
COXQuickString str ;
str . SetLength ( 20 ) ;
int nMultiplier = 1 ;
TCHAR ch = GetNextChar ( ) ;
if ( ch = = TEXT ( ' - ' ) )
{
nMultiplier = - 1 ;
ch = GetNextChar ( ) ;
}
else if ( ch = = TEXT ( ' + ' ) )
ch = GetNextChar ( ) ;
while ( _istdigit ( ch ) )
{
str . Append ( ch ) ;
ch = GetNextChar ( ) ;
}
if ( ch = = m_chNULL )
{
ReportError ( ERROR_END_OF_BUFFER ,
TEXT ( " Unexpected end of buffer while parsing integer. " ) ) ;
str . Empty ( ) ;
return FALSE ;
}
UngetChar ( ) ;
nNumber = _ttoi ( ( LPCTSTR ) str ) * nMultiplier ;
return TRUE ;
}
BOOL COXParser : : GetStringToken ( COXQuickString & str , TCHAR chQuoteChar )
{
str . Empty ( ) ;
str . SetLength ( 100 ) ;
TCHAR ch = GetNextChar ( ) ;
while ( ch & & ch ! = chQuoteChar )
{
# ifdef OXPARSER_CONVERT_ENTITY
if ( ch ! = m_chEsc )
{
# endif
str . Append ( ch ) ;
ch = GetNextChar ( ) ;
# ifdef OXPARSER_CONVERT_ENTITY
}
else
{
BOOL bContinue = TRUE ;
COXQuickString sEsc ;
do
{
ch = GetNextChar ( ) ;
if ( ! ch | | ch = = chQuoteChar )
bContinue = FALSE ;
else
if ( ch ! = TEXT ( ' ; ' ) )
sEsc . Append ( ch ) ;
}
while ( bContinue & & ch ! = TEXT ( ' ; ' ) ) ;
if ( bContinue )
{
LPCTSTR lpSymb = GetLiteralString ( ( LPCTSTR ) sEsc ) ;
if ( lpSymb )
{
str . Append ( * lpSymb ) ;
}
else
{
str . Append ( TEXT ( ' & ' ) ) ;
str . AddString ( ( LPCTSTR ) sEsc ) ;
str . Append ( TEXT ( ' ; ' ) ) ;
}
ch = GetNextChar ( ) ;
}
}
# endif
}
if ( ch ! = chQuoteChar )
{
ReportError ( ERROR_END_OF_BUFFER ,
TEXT ( " Unexpected end of buffer while parsing string. " ) ) ;
str . Empty ( ) ;
return FALSE ;
}
TRACE1 ( " %s \n " , ( LPCTSTR ) str ) ;
return TRUE ;
}
BOOL COXParser : : GetToken ( COXToken & token , BOOL bWarnOnEOF /*=FALSE*/ )
{
if ( ! RemoveWhiteSpace ( ) )
return FALSE ;
token . SetType ( COXToken : : UNKNOWN ) ;
TCHAR ch = GetNextChar ( 1 , bWarnOnEOF ) ;
if ( ! ch )
return FALSE ;
// "<"
if ( ch = = m_chStartDelim )
{
ch = GetNextChar ( 1 , bWarnOnEOF ) ;
if ( ! ch )
return FALSE ;
// "<?"
if ( ch = = m_chProcInstr )
{
token . SetType ( COXToken : : OPEN_PROCINSTR_BRACKET ) ;
}
// "</"
else if ( ch = = m_chTagEnd )
{
token . SetType ( COXToken : : OPEN_ENDTAG_BRACKET ) ;
}
// "<!"
else if ( ch = = m_chMarkup )
{
token . SetType ( COXToken : : OPEN_MARKUP_BRACKET ) ;
ch = GetNextChar ( 1 , bWarnOnEOF ) ;
if ( ch ! = m_chDash )
UngetChar ( ) ;
else
{
ch = GetNextChar ( 1 , bWarnOnEOF ) ;
if ( ch ! = m_chDash )
UngetChar ( 2 ) ;
else
token . SetType ( COXToken : : OPEN_COMMENT_BRACKET ) ;
}
}
else
{
UngetChar ( ) ;
token . SetType ( COXToken : : OPEN_TAG_BRACKET ) ;
}
}
// ">"
else if ( ch = = m_chEndDelim )
{
token . SetType ( COXToken : : CLOSE_TAG_BRACKET ) ;
}
// "/>"
else if ( ch = = m_chTagEnd )
{
ch = GetNextChar ( 1 , bWarnOnEOF ) ;
if ( ! ch )
return FALSE ;
if ( ch = = m_chEndDelim )
token . SetType ( COXToken : : CLOSE_EMPTYTAG_BRACKET ) ;
else
{
UngetChar ( 2 ) ;
token . SetType ( COXToken : : STRING ) ;
}
}
// "="
else if ( ch = = TEXT ( ' = ' ) )
{
token . SetType ( COXToken : : EQUAL_SIGN ) ;
}
// """
else if ( ch = = TEXT ( ' " ' ) )
{
token . SetType ( COXToken : : QUOTE ) ;
}
// "'"
else if ( ch = = TEXT ( ' \' ' ) )
{
token . SetType ( COXToken : : APOSTROPHE ) ;
}
// "-->"
else if ( ch = = m_chDash )
{
ch = GetNextChar ( 1 , bWarnOnEOF ) ;
if ( ch ! = m_chDash )
{
UngetChar ( 2 ) ;
token . SetType ( COXToken : : STRING ) ;
}
else
{
ch = GetNextChar ( 1 , bWarnOnEOF ) ;
if ( ch ! = m_chEndDelim )
{
UngetChar ( 3 ) ;
token . SetType ( COXToken : : STRING ) ;
}
else
token . SetType ( COXToken : : CLOSE_COMMENT_BRACKET ) ;
}
}
// Plain ol' text
else
{
UngetChar ( ) ;
token . SetType ( COXToken : : STRING ) ;
}
# if defined(_DEBUG) && 0
USES_CONVERSION ;
LPCSTR strToken = NULL ;
switch ( token . GetType ( ) )
{
case COXToken : : OPEN_PROCINSTR_BRACKET :
strToken = " OPEN_PROCINSTR_BRACKET " ;
break ;
case COXToken : : OPEN_ENDTAG_BRACKET :
strToken = " OPEN_ENDTAG_BRACKET " ;
break ;
case COXToken : : OPEN_COMMENT_BRACKET :
strToken = " OPEN_COMMENT_BRACKET " ;
break ;
case COXToken : : OPEN_MARKUP_BRACKET :
strToken = " OPEN_MARKUP_BRACKET " ;
break ;
case COXToken : : OPEN_TAG_BRACKET :
strToken = " OPEN_TAG_BRACKET " ;
break ;
case COXToken : : CLOSE_TAG_BRACKET :
strToken = " CLOSE_TAG_BRACKET " ;
break ;
case COXToken : : CLOSE_EMPTYTAG_BRACKET :
strToken = " CLOSE_EMPTYTAG_BRACKET " ;
break ;
case COXToken : : EQUAL_SIGN :
strToken = " EQUAL_SIGN " ;
break ;
case COXToken : : QUOTE :
strToken = " QUOTE " ;
break ;
case COXToken : : APOSTROPHE :
strToken = " APOSTROPHE " ;
break ;
case COXToken : : CLOSE_COMMENT_BRACKET :
strToken = " CLOSE_COMMENT_BRACKET " ;
break ;
case COXToken : : STRING :
strToken = " STRING " ;
break ;
case COXToken : : UNKNOWN :
default :
ASSERT ( FALSE ) ;
}
TRACE3 ( " COXParser: Found %s token at Line %d, Col %d. \n " ,
( LPCSTR ) strToken , m_nLine , m_nColumn ) ;
# endif
return TRUE ;
}
void COXParser : : AddObjectToElement ( COXParserElement * pElement ,
COXParserObject * pObject )
{
if ( pObject )
pElement - > AddObject ( pObject ) ;
}
BOOL COXParser : : ParseAttributes ( COXParserElement * pElement )
{
BOOL bResult = FALSE ;
COXAttribute * pAttribute = NULL ;
do
{
// What is next in line? If it's not a string value,
//it's not a name/value pair
pAttribute = NULL ;
bResult = GetToken ( m_Token , TRUE ) ;
if ( ! bResult | | m_Token . GetType ( ) ! = COXToken : : STRING )
break ;
// Create a new name Attribute
pAttribute = new COXAttribute ;
if ( ! pAttribute )
{
ReportError ( ERROR_OUT_OF_MEMORY ,
TEXT ( " Unable to create new attribute (element %s) " ) ,
pElement - > GetName ( ) ) ;
bResult = FALSE ;
break ;
}
// Get the name of the name/value pair
COXQuickString str ;
if ( ! GetNameToken ( str ) )
{
bResult = FALSE ;
break ;
}
pAttribute - > SetName ( str ) ;
// Search for a "=" sign next
if ( ! GetToken ( m_Token ) )
{
ReportError ( ERROR_BAD_TOKEN ,
TEXT ( " Error while parsing attribute (element %s, name %s). " ) ,
pElement - > GetName ( ) , pAttribute - > GetName ( ) ) ;
bResult = FALSE ;
break ;
}
if ( m_Token . GetType ( ) ! = COXToken : : EQUAL_SIGN )
{
ReportError ( ERROR_UNEXPECTED_TOKEN ,
TEXT ( " Unexpected token while parsing attribute (element %s, name %s). " ) ,
pElement - > GetName ( ) , pAttribute - > GetName ( ) ) ;
bResult = FALSE ;
break ;
}
// Should have a number, "string" or 'string' value next.
if ( ! GetToken ( m_Token ) )
{
ReportError ( ERROR_BAD_TOKEN ,
TEXT ( " Error while parsing attribute (element %s, name %s). " ) ,
pElement - > GetName ( ) , pAttribute - > GetName ( ) ) ;
bResult = FALSE ;
break ;
}
if ( m_Token . GetType ( ) = = COXToken : : STRING )
{
int nValue ;
if ( ! GetNumberToken ( nValue ) )
{
bResult = FALSE ;
break ;
}
pAttribute - > SetValue ( nValue ) ;
}
else if ( m_Token . GetType ( ) = = COXToken : : QUOTE )
{
if ( ! GetStringToken ( str , TEXT ( ' " ' ) ) )
{
bResult = FALSE ;
break ;
}
pAttribute - > SetValue ( str ) ;
}
else if ( m_Token . GetType ( ) = = COXToken : : APOSTROPHE )
{
if ( ! GetStringToken ( str , TEXT ( ' \' ' ) ) )
{
bResult = FALSE ;
break ;
}
pAttribute - > SetValue ( str ) ;
}
else
{
ReportError ( ERROR_UNEXPECTED_TOKEN ,
TEXT ( " Unexpected token while parsing attribute (element %s, name %s). " ) ,
pElement - > GetName ( ) , pAttribute - > GetName ( ) ) ;
bResult = FALSE ;
break ;
}
if ( bResult )
pElement - > AddAttribute ( pAttribute ) ;
} while ( bResult ) ;
if ( bResult )
return TRUE ;
else
{
delete pAttribute ;
return FALSE ;
}
}
COXParserElement * COXParser : : ParseStartTag ( COXParserElement * pParent ,
BOOL & bEmptyTag )
{
// Get tag name
if ( ! GetToken ( m_Token ) )
{
ReportError ( ERROR_END_OF_BUFFER ,
TEXT ( " Unexpected end of buffer while searching for tag name. " ) ) ;
return NULL ;
}
if ( m_Token . GetType ( ) ! = COXToken : : STRING )
{
ReportError ( ERROR_UNEXPECTED_TOKEN ,
TEXT ( " Expecting tag name - none found. " ) ) ;
return NULL ;
}
// Get the name of the name/value pair
COXQuickString str ;
if ( ! GetNameToken ( str ) )
return NULL ;
COXParserElement * pElement = new COXParserElement ( pParent , str ) ;
if ( ! pElement )
{
ReportError ( ERROR_OUT_OF_MEMORY ,
TEXT ( " Unable to create new parser Element " ) ) ;
return NULL ;
}
// Search through for attributes
BOOL bResult = ParseAttributes ( pElement ) ;
if ( bResult )
{
bEmptyTag = FALSE ;
if ( m_Token . GetType ( ) = = COXToken : : CLOSE_TAG_BRACKET )
/* do nothing */ ;
else if ( m_Token . GetType ( ) = = COXToken : : CLOSE_EMPTYTAG_BRACKET )
bEmptyTag = TRUE ;
else
{
bResult = FALSE ;
ReportError ( ERROR_MISSING_END_BRACKET ,
TEXT ( " Closing bracket for start tag '%s' not found. " ) ,
pElement - > GetName ( ) ) ;
}
}
if ( ! bResult )
{
delete pElement ;
return NULL ;
}
else
return pElement ;
}
BOOL COXParser : : IsEndTagMissing ( LPCTSTR szCurrentTag , LPCTSTR szNewTag ,
BOOL NewTagIsEndTag )
{
UNUSED_ALWAYS ( szCurrentTag ) ;
UNUSED_ALWAYS ( szNewTag ) ;
UNUSED_ALWAYS ( NewTagIsEndTag ) ;
return FALSE ;
}
BOOL COXParser : : IgnoreStartTag ( COXParserElement * pElement ,
BOOL bEmptyTag )
{
UNUSED_ALWAYS ( pElement ) ;
UNUSED_ALWAYS ( bEmptyTag ) ;
return FALSE ;
}
BOOL COXParser : : IgnoreEndTag ( LPCTSTR szEndTag )
{
UNUSED_ALWAYS ( szEndTag ) ;
return FALSE ;
}
BOOL COXParser : : ParseEndTag ( COXParserElement * pElement ,
COXQuickString & strEndTag )
{
UNUSED_ALWAYS ( pElement ) ;
if ( ! GetToken ( m_Token , TRUE ) )
{
ReportError ( ERROR_BAD_TOKEN ,
TEXT ( " Unexpected end of buffer while parsing endtag. " ) ) ;
return FALSE ;
}
if ( m_Token . GetType ( ) ! = COXToken : : STRING )
{
ReportError ( ERROR_UNEXPECTED_TOKEN , TEXT ( " Missing end tag name. " ) ) ;
return FALSE ;
}
// Get the end tag name
if ( ! GetNameToken ( strEndTag ) )
return FALSE ;
// peel off the final ">"
if ( ! GetToken ( m_Token ) | | m_Token . GetType ( ) ! = COXToken : : CLOSE_TAG_BRACKET )
{
ReportError ( ERROR_BAD_TOKEN ,
TEXT ( " Missing end bracket while parsing end tag '%s'. " ) ,
( LPCTSTR ) strEndTag ) ;
return FALSE ;
}
return TRUE ;
}
COXParserObject * COXParser : : ParseProcessingInstruction (
COXParserElement * pParent )
{
COXQuickString str ;
str . SetLength ( 100 ) ;
TCHAR ch = GetNextChar ( ) ;
while ( ch )
{
TCHAR chNextChar = GetNextChar ( ) ;
if ( ! chNextChar )
{
ReportError ( ERROR_END_OF_BUFFER ,
TEXT ( " Unexpected end of buffer while parsing processing instruction. " ) ) ;
return NULL ;
}
if ( ch = = m_chProcInstr & & chNextChar = = m_chEndDelim )
ch = m_chNULL ;
else
{
str . Append ( ch ) ;
ch = chNextChar ;
}
}
return new COXParserObject ( pParent , COXParserObject : : PROCINSTR , str ) ;
}
COXParserObject * COXParser : : ParseMarkup ( COXParserElement * pParent )
{
int nMarkupType = COXParserObject : : MARKUP ;
COXQuickString str ;
str . SetLength ( 100 ) ;
if ( ! _tcsncmp ( m_pBuf , TEXT ( " DOCTYPE " ) , 7 ) )
{
TCHAR ch = GetNextChar ( ) ;
// Parse initial bit before DTD info
while ( ch & & ch ! = m_chEndDelim & & ch ! = TEXT ( ' [ ' ) )
{
str . Append ( ch ) ;
ch = GetNextChar ( ) ;
}
// Parse DTD info
if ( ch = = TEXT ( ' [ ' ) )
{
BOOL bOpened = FALSE ;
CString sEntity ;
LPTSTR pData = m_pBuf ;
TCHAR chSpace = TEXT ( ' ' ) ;
TCHAR chTab = TEXT ( ' \t ' ) ;
while ( ch & & ch ! = TEXT ( ' ] ' ) )
{
if ( ! bOpened )
{
if ( ch = = TCHAR ( 0x3c ) )
{
bOpened = TRUE ;
pData = m_pBuf ;
}
}
else
{
if ( ch = = TCHAR ( 0x3e ) )
{
if ( sEntity . GetLength ( ) > 8 )
{
int nRet = CompareString ( LOCALE_SYSTEM_DEFAULT ,
NORM_IGNORECASE , ( LPCTSTR ) sEntity , 8 ,
_T ( " !ENTITY " ) , 8 ) ;
if ( CSTR_EQUAL = = nRet )
{
//found entity
sEntity = sEntity . Right ( sEntity . GetLength ( ) - 8 ) ;
CString sLiteral = sEntity ;
int nSpace = sEntity . Find ( _T ( " " ) ) ;
if ( nSpace ! = - 1 )
{
pData = pData + nSpace + 8 ;
while ( * pData = = chSpace | |
* pData = = chTab )
pData + + ;
sEntity = sEntity . Left ( nSpace ) ;
sLiteral = sLiteral . Right ( sLiteral . GetLength ( ) - nSpace ) ;
sLiteral . TrimLeft ( ) ;
m_EntityTable . Add ( ( LPCTSTR ) sEntity , ( DWORD ) ( INT_PTR ) pData ) ;
}
}
}
sEntity = " " ;
bOpened = FALSE ;
}
else
{
sEntity + = ch ;
}
}
ch = GetNextChar ( ) ;
}
}
// Parse any remaining left over stuff
while ( ch & & ch ! = m_chEndDelim )
{
str . Append ( ch ) ;
ch = GetNextChar ( ) ;
}
if ( ! ch )
{
ReportError ( ERROR_END_OF_BUFFER ,
TEXT ( " Unexpected end of buffer while parsing DOCTYPE entry. " ) ) ;
return NULL ;
}
}
else if ( ! _tcsncmp ( m_pBuf , TEXT ( " [CDATA[ " ) , 7 ) )
{
TCHAR ch = GetNextChar ( 7 + 1 ) ;
while ( ch )
{
TCHAR chNextChar1 = GetNextChar ( ) ;
TCHAR chNextChar2 = GetNextChar ( ) ;
if ( ! chNextChar1 | | ! chNextChar2 )
{
ReportError ( ERROR_END_OF_BUFFER ,
TEXT ( " Unexpected end of buffer while CDATA. " ) ) ;
return NULL ;
}
if ( ch = = TEXT ( ' ] ' ) & & chNextChar1 = = TEXT ( ' ] ' ) & & chNextChar2 = = m_chEndDelim )
ch = m_chNULL ;
else
{
str . Append ( ch ) ;
ch = chNextChar1 ;
UngetChar ( ) ;
}
}
nMarkupType = COXParserObject : : CDATA ;
}
else
{
TCHAR ch = GetNextChar ( ) ;
while ( ch & & ch ! = m_chEndDelim )
{
str . Append ( ch ) ;
ch = GetNextChar ( ) ;
}
if ( ! ch )
{
ReportError ( ERROR_END_OF_BUFFER ,
TEXT ( " Unexpected end of buffer while parsing markup. " ) ) ;
return NULL ;
}
}
return new COXParserObject ( pParent , nMarkupType , str ) ;
}
COXParserObject * COXParser : : ParseComment ( COXParserElement * pParent )
{
COXQuickString str ;
str . SetLength ( 100 ) ;
TCHAR ch = GetNextChar ( ) ;
while ( ch )
{
TCHAR chNextChar1 = GetNextChar ( ) ;
TCHAR chNextChar2 = GetNextChar ( ) ;
if ( ! chNextChar1 | | ! chNextChar2 )
{
ReportError ( ERROR_END_OF_BUFFER ,
TEXT ( " Unexpected end of buffer while parsing comment. " ) ) ;
return NULL ;
}
if ( ch = = m_chDash & & chNextChar1 = = m_chDash & & chNextChar2 = = m_chEndDelim )
ch = m_chNULL ;
else
{
str . Append ( ch ) ;
ch = chNextChar1 ;
UngetChar ( ) ;
}
}
return new COXParserObject ( pParent , COXParserObject : : COMMENT , str ) ;
}
LPCTSTR COXParser : : GetLiteralString ( LPCTSTR szStr )
{
static TCHAR szLiteral [ 2 ] = { 0 , 0 } ;
szLiteral [ 0 ] = TCHAR ( 0 ) ;
// Decode numeric character references
if ( szStr [ 0 ] = = TEXT ( ' # ' ) )
{
BOOL bHexValue = ( szStr [ 1 ] = = TEXT ( ' x ' ) | | szStr [ 1 ] = = TEXT ( ' X ' ) ) ;
LPCTSTR szNumber = ( bHexValue ) ? szStr + 2 : szStr + 1 ;
// Check it's valid
for ( LPCTSTR ptr = szNumber ; * ptr ; ptr + + )
{
if ( ! ( ( bHexValue ) ? _istxdigit ( * ptr ) : _istdigit ( * ptr ) ) )
return NULL ;
}
TCHAR ch ;
# if _MSC_VER >= 1400
if ( ! _stscanf_s ( szNumber , ( bHexValue ) ? TEXT ( " %x " ) : TEXT ( " %d " ) , & ch ) )
# else
if ( ! _stscanf ( szNumber , ( bHexValue ) ? TEXT ( " %x " ) : TEXT ( " %d " ) , & ch ) )
# endif
return NULL ;
szLiteral [ 0 ] = ch ;
return szLiteral ;
}
// Decode character entity references
DWORD dw ;
if ( ! m_EntityTable . Lookup ( szStr , dw ) )
return NULL ;
return ( LPCTSTR ) ( INT_PTR ) dw ;
}
LPTSTR COXParser : : GetCharEntity ( TCHAR ch )
{
static TCHAR szEntity [ 256 ] ;
HASH_POS pos = m_EntityTable . GetStartPosition ( ) ;
while ( pos )
{
LPCTSTR szName = NULL ;
DWORD dwData = 0 ;
m_EntityTable . GetNextAssoc ( pos , szName , dwData ) ;
LPCTSTR szLiteral = ( LPCTSTR ) ( INT_PTR ) dwData ;
if ( ch = = szLiteral [ 0 ] & & szLiteral [ 1 ] = = m_chNULL )
{
UTBStr : : stprintf ( szEntity , 256 , TEXT ( " &%s; " ) , szName ) ;
return szEntity ;
}
}
// unable to find - so just return the character as a string
szEntity [ 0 ] = ch ;
szEntity [ 1 ] = TEXT ( ' \0 ' ) ;
return szEntity ;
}
const COXQuickString COXParser : : EncodeText ( LPCTSTR szStr )
{
COXQuickString str ;
if ( ! szStr | | ! szStr [ 0 ] )
return str ;
// An initial guess of the string size
str . SetLength ( PtrToUint ( _tcslen ( szStr ) + 1 ) ) ;
while ( * szStr )
str . AddString ( GetCharEntity ( * szStr + + ) ) ;
return str ;
}
COXParserObject * COXParser : : ParseText ( COXParserElement * pParent )
{
COXQuickString str ;
str . SetLength ( 100 ) ;
TCHAR ch = GetNextChar ( ) ;
while ( ch & & ch ! = m_chStartDelim )
{
// Process any entities found
if ( ch = = m_chEsc )
{
// Move past the '&'
ch = GetNextChar ( ) ;
COXQuickString strEntity ;
while ( ch & & ch ! = m_chStartDelim & & ch ! = TEXT ( ' ; ' ) & & ! _istspace ( ch ) )
{
strEntity . Append ( ch ) ;
ch = GetNextChar ( ) ;
}
// Final char should be the ';'
if ( ch ! = TEXT ( ' ; ' ) )
{
ReportError ( ERROR_BAD_ENTITY ,
TEXT ( " Missing ';' on character entity '&%s'. " ) ,
( LPCTSTR ) strEntity ) ;
str . Append ( TEXT ( ' & ' ) ) ;
str + = strEntity ;
}
else
{
LPCTSTR szEntity = GetLiteralString ( strEntity ) ;
if ( szEntity )
InsertEntityValue ( str , szEntity ) ;
else
{
ReportError ( ERROR_BAD_ENTITY ,
TEXT ( " Bad character entity '&%s;' encountered. " ) ,
( LPCTSTR ) strEntity ) ;
str . Append ( TEXT ( ' & ' ) ) ;
str + = strEntity ;
str . Append ( TEXT ( ' ; ' ) ) ;
}
ch = GetNextChar ( ) ;
}
// finished processing entity - ch will be the char directly
// after the entity
}
else
{
str . Append ( ch ) ;
ch = GetNextChar ( ) ;
}
}
if ( ! ch )
{
//ReportError(ERROR_END_OF_BUFFER,
// TEXT("Unexpected end of buffer while parsing text."));
//return NULL;
}
else
UngetChar ( ) ;
str . Trim ( ) ;
return new COXParserObject ( pParent ,
COXParserObject : : PLAINTEXT , str . GetString ( ) ) ;
}
BOOL COXParser : : ParseElement ( COXParserElement * pElement , int nLevel )
{
SAVEPOS pos ;
SaveBufferPos ( pos ) ;
COXParserObject * pObject ;
BOOL bFoundMatchingEndTag ;
BOOL bContinue = TRUE ;
BOOL bResult = FALSE ;
do
{
// The new object that will be added to this element
pObject = NULL ;
bFoundMatchingEndTag = FALSE ;
// Get the first token of the next object. Only report errors for
// elements that are at least a level above the root element
bResult = GetToken ( m_Token , FALSE ) ;
if ( ! bResult )
{
bContinue = FALSE ;
bResult = TRUE ;
break ;
}
switch ( m_Token . GetType ( ) )
{
case COXToken : : OPEN_PROCINSTR_BRACKET : // Processing instruction
pObject = ParseProcessingInstruction ( pElement ) ;
bResult = bContinue = ( pObject ! = NULL ) ;
break ;
case COXToken : : OPEN_MARKUP_BRACKET : // Markup
pObject = ParseMarkup ( pElement ) ;
bResult = bContinue = ( pObject ! = NULL ) ;
break ;
case COXToken : : OPEN_COMMENT_BRACKET : // Comment
pObject = ParseComment ( pElement ) ;
bResult = bContinue = ( pObject ! = NULL ) ;
break ;
case COXToken : : QUOTE :
case COXToken : : APOSTROPHE :
UngetChar ( ) ;
// Fall through
case COXToken : : STRING : // Plain ol' text
case COXToken : : EQUAL_SIGN :
pObject = ParseText ( pElement ) ;
bResult = bContinue = ( pObject ! = NULL ) ;
break ;
case COXToken : : OPEN_TAG_BRACKET : // New element
{
BOOL bEmptyTag = FALSE ;
pObject = ParseStartTag ( pElement , bEmptyTag ) ;
if ( ! pObject )
{
bResult = bContinue = FALSE ;
break ;
}
// Allow derived classes to simply ignore this element. This is
// useful if you wish to treat tags as "toggles" (eg <b> in
// HTML), instead of actual XML nodes.
if ( IgnoreStartTag ( ( COXParserElement * ) pObject ,
bEmptyTag ) )
{
delete pObject ;
pObject = NULL ;
break ;
}
// Allow derived classes to close off this element and start a
// new one if there is a missing end tag.
// If we have a missing end tag, then we end processing of the
// current element, restore the buffer to the point just before
// this open tag, and return from this function
if ( nLevel > 0 & &
IsEndTagMissing ( pElement - > GetName ( ) ,
pObject - > GetText ( ) , FALSE ) )
{
// Pretend we never saw this tag, and just quit as if
// we had reached an end tag
RestoreBufferPos ( pos ) ;
delete pObject ;
pObject = NULL ;
bFoundMatchingEndTag = TRUE ;
bResult = TRUE ;
bContinue = FALSE ;
break ;
}
// If not an empty element, then try and parse the element.
if ( ! bEmptyTag & &
! ParseElement ( ( COXParserElement * ) pObject ,
nLevel + 1 ) )
{
delete pObject ;
pObject = NULL ;
bResult = bContinue = FALSE ;
break ;
}
bResult = TRUE ;
}
break ;
// An end tag should halt processing - but we allow some leniency here.
// We allow derived classes to decide when to cease processing this
// element, by either return FALSE in ParseEndTag, or setting
// bFoundMatchingEndTag to TRUE (useful for HTML...)
case COXToken : : OPEN_ENDTAG_BRACKET : // </...
{
// Get the end tag
COXQuickString strEndTag ;
if ( ! ParseEndTag ( pElement , strEndTag ) )
{
bResult = bContinue = FALSE ;
break ;
}
// Allow derived classes to simply ignore this tag. This is
// useful if you wish to treat tags as "toggles" (eg </b> in
// HTML), instead of actual XML nodes.
if ( IgnoreEndTag ( strEndTag ) )
break ;
// If we are at top level, then issue a warning but continue
if ( nLevel = = 0 )
{
ReportError ( WARNING_UNEXPECTED_END_TAG ,
TEXT ( " Unexpected end tag '%s'. " ) , ( LPCTSTR ) strEndTag ) ;
break ;
}
// If it matches the current element, then we finish processing here
if ( strEndTag . Compare ( pElement - > GetName ( ) , FALSE ) )
{
bFoundMatchingEndTag = TRUE ;
bContinue = FALSE ;
break ;
}
if ( IsEndTagMissing ( pElement - > GetName ( ) ,
strEndTag , TRUE ) )
{
// Pretend we never saw this tag, and just quit as if
// we had reached an end tag
RestoreBufferPos ( pos ) ;
bFoundMatchingEndTag = TRUE ;
bContinue = FALSE ;
break ;
}
ReportError ( ERROR_MISSING_END_TAG ,
TEXT ( " Expecting end tag '%s'. Found end tag '%s' instead. " ) ,
pElement - > GetName ( ) , ( LPCTSTR ) strEndTag ) ;
if ( m_bErrorOnMissingTag )
bContinue = bResult = FALSE ;
}
break ;
default :
ReportError ( ERROR_UNEXPECTED_TOKEN , TEXT ( " Unexpected token. " ) ) ;
//ReportError(ERROR_UNEXPECTED_TOKEN, TEXT("Unexpected token '%s'."),
// m_Token.GetText());
bResult = bContinue = FALSE ;
}
if ( bResult )
AddObjectToElement ( pElement , pObject ) ;
SaveBufferPos ( pos ) ;
} while ( bContinue ) ;
// Error?
if ( ! bResult )
{
delete pObject ;
return FALSE ;
}
// Will only get this far if all tags for all elements have been closed, or
// if the trailing end tags for elements are missing
// If this is the root element, then there is no need to check for missing end tags
if ( nLevel = = 0 )
return TRUE ;
else
{
// Derived classes may wish to allow missing end tags
if ( ! bFoundMatchingEndTag & & ! IsEndTagMissing ( pElement - > GetName ( ) , NULL , TRUE ) )
{
ReportError ( ERROR_MISSING_END_TAG , TEXT ( " Missing end tag '%s'. " ) ,
pElement - > GetText ( ) ) ;
return FALSE ;
}
else
return TRUE ;
}
}
BOOL COXParser : : ParseFile ( LPCTSTR szFile )
{
LPTSTR ptr = LoadFile ( szFile ) ;
if ( ! ptr )
return FALSE ;
BOOL bResult = Parse ( ptr ) ;
GlobalFree ( ptr ) ;
return bResult ;
}
//////////////////////////////////////////////////////////////////////
// File handling routines
//////////////////////////////////////////////////////////////////////
BOOL COXParser : : WriteFile ( LPCTSTR szFile )
{
if ( ! Root ( ) | | ! Root ( ) - > NumObjects ( ) )
return FALSE ;
HANDLE hFile = CreateFile ( szFile , GENERIC_WRITE ,
0 , NULL , CREATE_ALWAYS ,
FILE_ATTRIBUTE_NORMAL ,
NULL ) ;
if ( INVALID_HANDLE_VALUE = = hFile )
return FALSE ;
for ( int i = 0 ; i < Root ( ) - > NumObjects ( ) ; i + + )
WriteObject ( hFile , Root ( ) - > Object ( i ) , 0 ) ;
CloseHandle ( hFile ) ;
return TRUE ;
}
BOOL COXParser : : WriteTabs ( HANDLE hFile , int nLevel )
{
USES_CONVERSION ;
DWORD nCount ;
for ( int i = 0 ; i < nLevel ; i + + )
{
if ( ! : : WriteFile ( hFile , T2A ( ( LPTSTR ) m_szTab ) ,
PtrToLong ( _tcslen ( m_szTab ) ) , & nCount , NULL ) )
return FALSE ;
}
return TRUE ;
}
BOOL COXParser : : WriteAttributes ( HANDLE hFile ,
COXParserElement * pElement )
{
USES_CONVERSION ;
static char buffer [ 512 ] ;
static DWORD nCount ;
for ( int i = 0 ; i < pElement - > NumAttributes ( ) ; i + + )
{
COXAttribute * pAttribute = pElement - > Attribute ( i ) ;
if ( ! pAttribute ) continue ;
UTBStr : : sprintf ( buffer , 512 , " %s= " , T2A ( ( LPTSTR ) pAttribute - > GetName ( ) ) ) ;
if ( ! : : WriteFile ( hFile , buffer , PtrToLong ( strlen ( buffer ) ) , & nCount , NULL ) )
return FALSE ;
if ( pAttribute - > GetAttributeType ( ) = = COXAttribute : : ATTR_STRING )
UTBStr : : sprintf ( buffer , 512 , " \" %s \" " , T2A ( ( LPTSTR ) pAttribute - > GetStringValue ( ) ) ) ;
else if ( pAttribute - > GetAttributeType ( ) = = COXAttribute : : ATTR_INTEGER )
UTBStr : : sprintf ( buffer , 512 , " %d " , pAttribute - > GetIntValue ( ) ) ;
else
UTBStr : : sprintf ( buffer , 512 , " \" \" " ) ;
if ( ! : : WriteFile ( hFile , buffer , PtrToLong ( strlen ( buffer ) ) , & nCount , NULL ) )
return FALSE ;
}
return TRUE ;
}
BOOL COXParser : : WriteCData ( HANDLE hFile , COXParserObject * pObject ,
int nLevel )
{
USES_CONVERSION ;
if ( pObject - > GetType ( ) ! = COXParserObject : : CDATA )
return FALSE ;
if ( ! WriteTabs ( hFile , nLevel ) )
return FALSE ;
DWORD nCount ;
if ( ! : : WriteFile ( hFile , " <![CDATA[ " , 9 , & nCount , NULL ) )
return FALSE ;
if ( ! : : WriteFile ( hFile , T2A ( ( LPTSTR ) pObject - > GetText ( ) ) ,
PtrToLong ( _tcslen ( pObject - > GetText ( ) ) ) , & nCount , NULL ) )
return FALSE ;
if ( ! : : WriteFile ( hFile , " ]]> \r \n " , 5 , & nCount , NULL ) )
return FALSE ;
return TRUE ;
}
BOOL COXParser : : WriteComment ( HANDLE hFile , COXParserObject * pObject ,
int nLevel )
{
USES_CONVERSION ;
if ( pObject - > GetType ( ) ! = COXParserObject : : COMMENT )
return FALSE ;
if ( ! WriteTabs ( hFile , nLevel ) )
return FALSE ;
DWORD nCount ;
if ( ! : : WriteFile ( hFile , " <!-- " , 4 , & nCount , NULL ) )
return FALSE ;
if ( ! : : WriteFile ( hFile , T2A ( ( LPTSTR ) pObject - > GetText ( ) ) ,
PtrToLong ( _tcslen ( pObject - > GetText ( ) ) ) , & nCount , NULL ) )
return FALSE ;
if ( ! : : WriteFile ( hFile , " --> \r \n " , 5 , & nCount , NULL ) )
return FALSE ;
return TRUE ;
}
BOOL COXParser : : WriteElement ( HANDLE hFile , COXParserElement * pElement ,
int nLevel )
{
USES_CONVERSION ;
static char buffer [ 512 ] ;
static DWORD nCount ;
if ( pElement - > GetType ( ) ! = COXParserObject : : ELEMENT )
return FALSE ;
if ( ! WriteTabs ( hFile , nLevel ) )
return FALSE ;
UTBStr : : sprintf ( buffer , 512 , " <%s " , T2A ( ( LPTSTR ) pElement - > GetName ( ) ) ) ;
if ( ! : : WriteFile ( hFile , buffer , PtrToLong ( strlen ( buffer ) ) , & nCount , NULL ) )
return FALSE ;
if ( ! WriteAttributes ( hFile , pElement ) )
return FALSE ;
if ( pElement - > NumObjects ( ) = = 0 ) // empty tag
{
if ( ! : : WriteFile ( hFile , " /> \r \n " , 4 , & nCount , NULL ) )
return FALSE ;
}
else
{
if ( ! : : WriteFile ( hFile , " > \r \n " , 3 , & nCount , NULL ) )
return FALSE ;
for ( int i = 0 ; i < pElement - > NumObjects ( ) ; i + + )
WriteObject ( hFile , pElement - > Object ( i ) , nLevel + 1 ) ;
if ( ! WriteTabs ( hFile , nLevel ) )
return FALSE ;
UTBStr : : sprintf ( buffer , 512 , " </%s> \r \n " , T2A ( ( LPTSTR ) pElement - > GetName ( ) ) ) ;
if ( ! : : WriteFile ( hFile , buffer , PtrToLong ( strlen ( buffer ) ) , & nCount , NULL ) )
return FALSE ;
}
return TRUE ;
}
BOOL COXParser : : WriteMarkup ( HANDLE hFile , COXParserObject * pObject ,
int nLevel )
{
USES_CONVERSION ;
if ( pObject - > GetType ( ) ! = COXParserObject : : MARKUP )
return FALSE ;
if ( ! WriteTabs ( hFile , nLevel ) )
return FALSE ;
DWORD nCount ;
if ( ! : : WriteFile ( hFile , " <! " , 2 , & nCount , NULL ) )
return FALSE ;
if ( ! : : WriteFile ( hFile , T2A ( ( LPTSTR ) pObject - > GetText ( ) ) ,
PtrToLong ( _tcslen ( pObject - > GetText ( ) ) ) , & nCount , NULL ) )
return FALSE ;
if ( ! : : WriteFile ( hFile , " > \r \n " , 3 , & nCount , NULL ) )
return FALSE ;
return TRUE ;
}
BOOL COXParser : : WriteProcessingInstruction ( HANDLE hFile ,
COXParserObject * pObject , int nLevel )
{
USES_CONVERSION ;
if ( pObject - > GetType ( ) ! = COXParserObject : : PROCINSTR )
return FALSE ;
if ( ! WriteTabs ( hFile , nLevel ) )
return FALSE ;
DWORD nCount ;
if ( ! : : WriteFile ( hFile , " <? " , 2 , & nCount , NULL ) )
return FALSE ;
if ( ! : : WriteFile ( hFile , T2A ( ( LPTSTR ) pObject - > GetText ( ) ) ,
PtrToLong ( _tcslen ( pObject - > GetText ( ) ) ) , & nCount , NULL ) )
return FALSE ;
if ( ! : : WriteFile ( hFile , " ?> \r \n " , 4 , & nCount , NULL ) )
return FALSE ;
return TRUE ;
}
BOOL COXParser : : WriteText ( HANDLE hFile , COXParserObject * pObject ,
int nLevel )
{
USES_CONVERSION ;
if ( pObject - > GetType ( ) ! = COXParserObject : : PLAINTEXT & &
pObject - > GetType ( ) ! = COXParserObject : : RAWTEXT )
return FALSE ;
COXQuickString str ;
if ( pObject - > GetType ( ) = = COXParserObject : : RAWTEXT )
str = pObject - > GetText ( ) ;
else
str = EncodeText ( pObject - > GetText ( ) ) ;
str . Trim ( ) ;
if ( str . IsEmpty ( ) )
return FALSE ;
LPCTSTR ptr = str . GetString ( ) ;
COXQuickString strLine ;
LPCTSTR pStart ;
while ( * ptr )
{
strLine . Empty ( ) ;
BOOL bContinue = TRUE ;
while ( bContinue )
{
pStart = ptr ;
// Search for the next white space
while ( * ptr & & ! _istspace ( * ptr ) ) ptr + + ;
//if (*ptr) ptr++;
int nCharsStepped = PtrToInt ( ptr - pStart + 1 ) ;
// If we have less than a lines worth, or if we have more than a lines
// worth and have not added anything previously, add to the current line
if ( strLine . GetLength ( ) + nCharsStepped < m_nLineLength | |
strLine . IsEmpty ( ) )
{
strLine . AddString ( pStart , nCharsStepped ) ;
// If we've still got room on the line, and we are not at EOF or EOL
// then continue on
bContinue = ( strLine . GetLength ( ) < m_nLineLength & &
* ptr & & * ptr ! = TEXT ( ' \n ' ) ) ;
if ( * ptr ) ptr + + ;
bContinue = ( bContinue & & * ptr ) ;
}
else
{
// We could not add this section - so go back to the start of it
// and print out what we already have.
ptr = pStart ;
bContinue = FALSE ;
}
}
if ( ! WriteTabs ( hFile , nLevel ) )
return FALSE ;
DWORD nCount ;
if ( ! : : WriteFile ( hFile , T2A ( ( LPTSTR ) strLine . GetString ( ) ) ,
strLine . GetLength ( ) , & nCount , NULL ) )
return FALSE ;
if ( ! : : WriteFile ( hFile , " \r \n " , 2 , & nCount , NULL ) )
return FALSE ;
}
return TRUE ;
}
BOOL COXParser : : WriteObject ( HANDLE hFile , COXParserObject * pObject ,
int nLevel )
{
BOOL bResult = FALSE ;
switch ( pObject - > GetType ( ) )
{
case COXParserObject : : CDATA :
bResult = WriteCData ( hFile , pObject , nLevel ) ;
break ;
case COXParserObject : : COMMENT :
bResult = WriteComment ( hFile , pObject , nLevel ) ;
break ;
case COXParserObject : : ELEMENT :
bResult = WriteElement ( hFile , ( COXParserElement * ) pObject ,
nLevel ) ;
break ;
case COXParserObject : : MARKUP :
bResult = WriteMarkup ( hFile , pObject , nLevel ) ;
break ;
case COXParserObject : : PLAINTEXT :
case COXParserObject : : RAWTEXT :
bResult = WriteText ( hFile , pObject , nLevel ) ;
break ;
case COXParserObject : : PROCINSTR :
bResult = WriteProcessingInstruction ( hFile , pObject , nLevel ) ;
break ;
default : /*nothing*/ ;
}
return bResult ;
}
LPTSTR COXParser : : LoadFile ( LPCTSTR szFile )
{
HANDLE hFile = CreateFile ( szFile , GENERIC_READ ,
0 , NULL , OPEN_EXISTING ,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS ,
NULL ) ;
if ( INVALID_HANDLE_VALUE = = hFile )
return NULL ;
DWORD size = GetFileSize ( hFile , NULL ) ;
if ( - 1 = = size )
{
CloseHandle ( hFile ) ;
return NULL ;
}
LPSTR ptr = ( LPSTR ) : : GlobalAlloc ( GMEM_FIXED , size + 1 ) ;
DWORD nCount ;
if ( ! ReadFile ( hFile , ptr , size , & nCount , NULL ) )
{
CloseHandle ( hFile ) ;
return NULL ;
}
CloseHandle ( hFile ) ;
ptr [ nCount ] = ' \0 ' ;
# ifdef _UNICODE
LPTSTR tptr = ( LPTSTR ) : : GlobalAlloc ( GMEM_FIXED ,
( nCount + 1 ) * sizeof ( TCHAR ) ) ;
UTBStr : : mbstowcs ( tptr , nCount + 1 , ptr , nCount ) ;
: : GlobalFree ( ptr ) ;
tptr [ nCount ] = m_chNULL ;
return tptr ;
# else
return ptr ;
# endif
}
//////////////////////////////////////////////////////////////////////
// Error handling routines
//////////////////////////////////////////////////////////////////////
BOOL COXParser : : ReportError ( UINT nErrorCode , LPCTSTR fmt , . . . )
{
va_list args ;
TCHAR buffer [ 512 ] ;
va_start ( args , fmt ) ;
# if _MSC_VER >= 1400
_vstprintf_s_l ( buffer , 512 , fmt , NULL , args ) ;
# else
_vstprintf ( buffer , fmt , args ) ;
# endif
va_end ( args ) ;
if ( m_pfnErrorFn )
return ( * m_pfnErrorFn ) ( nErrorCode , buffer , m_nLine ,
m_nColumn , m_dwErrData ) ;
else
return DefErrorHandler ( nErrorCode , buffer , m_nLine ,
m_nColumn , m_dwErrData ) ;
}
BOOL COXParser : : DefErrorHandler ( UINT nErrorCode , LPCTSTR szError ,
int nLine , int nColumn ,
DWORD dwData )
{
UNUSED_ALWAYS ( dwData ) ;
UNUSED ( nErrorCode ) ;
UNUSED ( szError ) ;
UNUSED ( nLine ) ;
UNUSED ( nColumn ) ;
# ifdef _DEBUG
# if _MSC_VER >= 1200
# pragma warning(push)
# endif
# pragma warning(disable:4127) // conditional expression is constant
if ( ERROR_FIRST < nErrorCode & & nErrorCode < ERROR_LAST )
{
_RPT4 ( _CRT_WARN , " COXParser: Error (%d) at line %d, col %d: %s \n " ,
nErrorCode , nLine , nColumn , szError ) ;
}
else if ( WARNING_FIRST < nErrorCode & & nErrorCode < WARNING_LAST )
{
_RPT4 ( _CRT_WARN , " COXParser: Warning (%d) at line %d, col %d: %s \n " ,
nErrorCode , nLine , nColumn , szError ) ;
}
else
_RPT4 ( _CRT_WARN , " COXParser: line %d, col %d: %s \n " ,
nErrorCode , nLine , nColumn , szError ) ;
# if _MSC_VER >= 1200
# pragma warning(pop)
# else
# pragma warning(default:4127)
# endif
# endif
return FALSE ;
}
LPCTSTR COXParser : : TranslateErrorCode ( int nErrorCode )
{
switch ( nErrorCode )
{
case ERROR_NULL_BUFFER :
return TEXT ( " NULL buffer passed in " ) ;
case ERROR_END_OF_BUFFER :
return TEXT ( " Unexpected end of buffer " ) ;
case ERROR_OUT_OF_MEMORY :
return TEXT ( " Out of memory " ) ;
case ERROR_BAD_TOKEN :
return TEXT ( " Unable to retrieve a token " ) ;
case ERROR_ILLEGAL_CHAR :
return TEXT ( " Illegal characters encountered in token " ) ;
case ERROR_UNEXPECTED_TOKEN :
return TEXT ( " Unexpected token type " ) ;
case ERROR_MISSING_END_TAG :
return TEXT ( " Missing end tag " ) ;
case ERROR_BAD_ENTITY :
return TEXT ( " Bad entity string " ) ;
case ERROR_BAD_INTEGER :
return TEXT ( " Bad integer value " ) ;
case ERROR_MISSING_END_BRACKET :
return TEXT ( " Missing end bracket in tag " ) ;
case WARNING_UNEXPECTED_END_TAG :
return TEXT ( " Unexpected end tag " ) ;
default :
return TEXT ( " Unknown Error " ) ;
}
}
void COXParser : : InsertEntityValue ( COXQuickString & str ,
LPCTSTR lpszEntity )
{
LPCTSTR lpszSeek = lpszEntity ;
TCHAR chSpace = TEXT ( ' ' ) ;
while ( * ( lpszSeek ) & & * ( lpszSeek ) ! = m_chEndDelim & & * ( lpszSeek ) ! = chSpace )
{
str . Append ( * lpszSeek ) ;
lpszSeek + + ;
}
}