30 #include "gearxml/tinyxml.h"
42 TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] =
47 {
""", 6,
'\"' },
61 const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
62 const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
63 const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
65 const int TiXmlBase::utf8ByteTable[256] =
68 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
69 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
70 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
71 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
72 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
73 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
74 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
75 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
76 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
77 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
78 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
79 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
80 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
81 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
82 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
83 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
87 void TiXmlBase::ConvertUTF32ToUTF8(
unsigned long input,
char* output,
int* length )
89 const unsigned long BYTE_MASK = 0xBF;
90 const unsigned long BYTE_MARK = 0x80;
91 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
95 else if ( input < 0x800 )
97 else if ( input < 0x10000 )
99 else if ( input < 0x200000 )
102 { *length = 0;
return; }
111 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
115 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
119 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
123 *output = (char)(input | FIRST_BYTE_MARK[*length]);
128 int TiXmlBase::IsAlpha(
unsigned char anyByte, TiXmlEncoding )
138 return isalpha( anyByte );
149 int TiXmlBase::IsAlphaNum(
unsigned char anyByte, TiXmlEncoding )
159 return isalnum( anyByte );
174 void Stamp(
const char* now, TiXmlEncoding encoding );
195 void TiXmlParsingData::Stamp(
const char* now, TiXmlEncoding encoding )
206 int row = cursor.row;
207 int col = cursor.col;
208 const char* p = stamp;
214 const unsigned char* pU = (
const unsigned char*)p;
257 col = (col / tabsize + 1) * tabsize;
260 case TIXML_UTF_LEAD_0:
261 if ( encoding == TIXML_ENCODING_UTF8 )
263 if ( *(p+1) && *(p+2) )
267 if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 )
269 else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU )
271 else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU )
285 if ( encoding == TIXML_ENCODING_UTF8 )
288 int step = TiXmlBase::utf8ByteTable[*((
unsigned char*)p)];
306 assert( cursor.row >= -1 );
307 assert( cursor.col >= -1 );
313 const char* TiXmlBase::SkipWhiteSpace(
const char* p, TiXmlEncoding encoding )
319 if ( encoding == TIXML_ENCODING_UTF8 )
323 const unsigned char* pU = (
const unsigned char*)p;
326 if ( *(pU+0)==TIXML_UTF_LEAD_0
327 && *(pU+1)==TIXML_UTF_LEAD_1
328 && *(pU+2)==TIXML_UTF_LEAD_2 )
333 else if(*(pU+0)==TIXML_UTF_LEAD_0
340 else if(*(pU+0)==TIXML_UTF_LEAD_0
348 if ( IsWhiteSpace( *p ) || *p ==
'\n' || *p ==
'\r' )
356 while ( ( *p && IsWhiteSpace( *p ) ) || *p ==
'\n' || *p ==
'\r' )
364 bool TiXmlBase::StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag )
368 if ( !in->good() )
return false;
372 if ( !IsWhiteSpace( c ) || c <= 0 )
375 *tag += (char) in->get();
379 bool TiXmlBase::StreamTo( TIXML_ISTREAM * in,
int character, TIXML_STRING * tag )
385 if ( c == character )
397 const char* TiXmlBase::ReadName(
const char* p, TIXML_STRING * name, TiXmlEncoding encoding )
410 && ( IsAlpha( (
unsigned char) *p, encoding ) || *p ==
'_' ) )
413 && ( IsAlphaNum( (
unsigned char ) *p, encoding )
427 const char* TiXmlBase::GetEntity(
const char* p,
char* value,
int* length, TiXmlEncoding encoding )
434 if ( *(p+1) && *(p+1) ==
'#' && *(p+2) )
436 unsigned long ucs = 0;
443 if ( !*(p+3) )
return 0;
446 q = strchr( q,
';' );
448 if ( !q || !*q )
return 0;
455 if ( *q >=
'0' && *q <=
'9' )
456 ucs += mult * (*q -
'0');
457 else if ( *q >=
'a' && *q <=
'f' )
458 ucs += mult * (*q -
'a' + 10);
459 else if ( *q >=
'A' && *q <=
'F' )
460 ucs += mult * (*q -
'A' + 10 );
470 if ( !*(p+2) )
return 0;
473 q = strchr( q,
';' );
475 if ( !q || !*q )
return 0;
482 if ( *q >=
'0' && *q <=
'9' )
483 ucs += mult * (*q -
'0');
490 if ( encoding == TIXML_ENCODING_UTF8 )
493 ConvertUTF32ToUTF8( ucs, value, length );
500 return p + delta + 1;
504 for( i=0; i<NUM_ENTITY; ++i )
506 if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )
508 assert( strlen( entity[i].str ) == entity[i].strLength );
509 *value = entity[i].chr;
511 return ( p + entity[i].strLength );
521 bool TiXmlBase::StringEqual(
const char* p,
524 TiXmlEncoding encoding )
538 while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) )
549 while ( *q && *tag && *q == *tag )
561 const char* TiXmlBase::ReadText(
const char* p,
565 bool caseInsensitive,
566 TiXmlEncoding encoding )
570 || !condenseWhiteSpace )
574 && !StringEqual( p, endTag, caseInsensitive, encoding )
578 char cArr[4] = { 0, 0, 0, 0 };
579 p = GetChar( p, cArr, &len, encoding );
580 text->append( cArr, len );
585 bool whitespace =
false;
588 p = SkipWhiteSpace( p, encoding );
590 && !StringEqual( p, endTag, caseInsensitive, encoding ) )
592 if ( *p ==
'\r' || *p ==
'\n' )
597 else if ( IsWhiteSpace( *p ) )
612 char cArr[4] = { 0, 0, 0, 0 };
613 p = GetChar( p, cArr, &len, encoding );
617 text->append( cArr, len );
621 return p + strlen( endTag );
626 void TiXmlDocument::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
635 if ( !StreamTo( in,
'<', tag ) )
637 SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
643 int tagIndex = (int) tag->length();
644 while ( in->good() && in->peek() !=
'>' )
649 SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
660 TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING );
664 node->StreamIn( in, tag );
665 bool isElement = node->ToElement() != 0;
678 SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
684 SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
698 SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
708 location.row = prevData->cursor.row;
709 location.col = prevData->cursor.col;
717 location = data.Cursor();
719 if ( encoding == TIXML_ENCODING_UNKNOWN )
722 const unsigned char* pU = (
const unsigned char*)p;
723 if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0
724 && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1
725 && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 )
727 encoding = TIXML_ENCODING_UTF8;
731 p = SkipWhiteSpace( p, encoding );
734 SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
740 TiXmlNode* node = Identify( p, encoding );
743 p = node->Parse( p, &data, encoding );
752 if ( encoding == TIXML_ENCODING_UNKNOWN
760 encoding = TIXML_ENCODING_UTF8;
761 else if ( StringEqual( enc,
"UTF-8",
true, TIXML_ENCODING_UNKNOWN ) )
762 encoding = TIXML_ENCODING_UTF8;
763 else if ( StringEqual( enc,
"UTF8",
true, TIXML_ENCODING_UNKNOWN ) )
764 encoding = TIXML_ENCODING_UTF8;
766 encoding = TIXML_ENCODING_LEGACY;
769 p = SkipWhiteSpace( p, encoding );
774 SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding );
782 void TiXmlDocument::SetError(
int err,
const char* pError,
TiXmlParsingData* data, TiXmlEncoding encoding )
788 assert( err > 0 && err < TIXML_ERROR_STRING_COUNT );
791 errorDesc = errorString[ errorId ];
793 errorLocation.Clear();
794 if ( pError && data )
797 data->Stamp( pError, encoding );
798 errorLocation = data->Cursor();
803 TiXmlNode* TiXmlNode::Identify(
const char* p, TiXmlEncoding encoding )
805 TiXmlNode* returnNode = 0;
807 p = SkipWhiteSpace( p, encoding );
808 if( !p || !*p || *p !=
'<' )
814 p = SkipWhiteSpace( p, encoding );
828 const char* xmlHeader = {
"<?xml" };
829 const char* commentHeader = {
"<!--" };
830 const char* dtdHeader = {
"<!" };
832 if ( StringEqual( p, xmlHeader,
true, encoding ) )
835 TIXML_LOG(
"XML parsing Declaration\n" );
837 returnNode =
new TiXmlDeclaration();
839 else if ( StringEqual( p, commentHeader,
false, encoding ) )
842 TIXML_LOG(
"XML parsing Comment\n" );
844 returnNode =
new TiXmlComment();
846 else if ( StringEqual( p, dtdHeader,
false, encoding ) )
849 TIXML_LOG(
"XML parsing Unknown(1)\n" );
851 returnNode =
new TiXmlUnknown();
853 else if ( IsAlpha( *(p+1), encoding )
857 TIXML_LOG(
"XML parsing Element\n" );
859 returnNode =
new TiXmlElement(
"" );
864 TIXML_LOG(
"XML parsing Unknown(2)\n" );
866 returnNode =
new TiXmlUnknown();
872 returnNode->parent =
this;
877 doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
884 void TiXmlElement::StreamIn (TIXML_ISTREAM * in, TIXML_STRING * tag)
895 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
904 if ( tag->length() < 3 )
return;
909 if ( tag->at( tag->length() - 1 ) ==
'>'
910 && tag->at( tag->length() - 2 ) ==
'/' )
915 else if ( tag->at( tag->length() - 1 ) ==
'>' )
923 StreamWhiteSpace( in, tag );
926 if ( in->good() && in->peek() !=
'<' )
929 TiXmlText text(
"" );
930 text.StreamIn( in, tag );
939 if ( !in->good() )
return;
940 assert( in->peek() ==
'<' );
941 int tagIndex = tag->length();
943 bool closingTag =
false;
944 bool firstCharFound =
false;
956 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
966 if ( !firstCharFound && c !=
'<' && !IsWhiteSpace( c ) )
968 firstCharFound =
true;
985 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
997 const char* tagloc = tag->c_str() + tagIndex;
998 TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING );
1001 node->StreamIn( in, tag );
1012 const char* TiXmlElement::Parse(
const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1014 p = SkipWhiteSpace( p, encoding );
1019 if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding );
1026 data->Stamp( p, encoding );
1027 location = data->Cursor();
1032 if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding );
1036 p = SkipWhiteSpace( p+1, encoding );
1039 const char* pErr = p;
1041 p = ReadName( p, &value, encoding );
1044 if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding );
1048 TIXML_STRING endTag (
"</");
1057 p = SkipWhiteSpace( p, encoding );
1060 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
1069 if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding );
1074 else if ( *p ==
'>' )
1080 p = ReadValue( p, data, encoding );
1085 if ( StringEqual( p, endTag.c_str(),
false, encoding ) )
1087 p += endTag.length();
1092 if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
1099 TiXmlAttribute* attrib =
new TiXmlAttribute();
1102 if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data, encoding );
1106 attrib->SetDocument( document );
1107 const char* ppErr = p;
1108 p = attrib->Parse( p, data, encoding );
1112 if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, ppErr, data, encoding );
1118 TiXmlAttribute* node = attributeSet.Find( attrib->Name() );
1126 attributeSet.Add( attrib );
1133 const char* TiXmlElement::ReadValue(
const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1137 const char* pWithWhiteSpace = p;
1139 p = SkipWhiteSpace( p, encoding );
1145 TiXmlText* textNode =
new TiXmlText(
"" );
1149 if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, encoding );
1155 p = textNode->Parse( p, data, encoding );
1161 p = textNode->Parse( pWithWhiteSpace, data, encoding );
1164 if ( !textNode->Blank() )
1173 if ( StringEqual( p,
"</",
false, encoding ) )
1179 TiXmlNode* node = Identify( p, encoding );
1182 p = node->Parse( p, data, encoding );
1191 p = SkipWhiteSpace( p, encoding );
1196 if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding );
1202 #ifdef TIXML_USE_STL
1203 void TiXmlUnknown::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
1205 while ( in->good() )
1212 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
1227 const char* TiXmlUnknown::Parse(
const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1230 p = SkipWhiteSpace( p, encoding );
1235 data->Stamp( p, encoding );
1236 location = data->Cursor();
1238 if ( !p || !*p || *p !=
'<' )
1240 if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding );
1246 while ( p && *p && *p !=
'>' )
1254 if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding );
1261 #ifdef TIXML_USE_STL
1262 void TiXmlComment::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
1264 while ( in->good() )
1271 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
1278 && tag->at( tag->length() - 2 ) ==
'-'
1279 && tag->at( tag->length() - 3 ) ==
'-' )
1289 const char* TiXmlComment::Parse(
const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1294 p = SkipWhiteSpace( p, encoding );
1299 data->Stamp( p, encoding );
1300 location = data->Cursor();
1302 const char* startTag =
"<!--";
1303 const char* endTag =
"-->";
1305 if ( !StringEqual( p, startTag,
false, encoding ) )
1307 document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding );
1310 p += strlen( startTag );
1311 p = ReadText( p, &value,
false, endTag,
false, encoding );
1316 const char* TiXmlAttribute::Parse(
const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1318 p = SkipWhiteSpace( p, encoding );
1319 if ( !p || !*p )
return 0;
1329 data->Stamp( p, encoding );
1330 location = data->Cursor();
1333 const char* pErr = p;
1334 p = ReadName( p, &name, encoding );
1337 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
1340 p = SkipWhiteSpace( p, encoding );
1341 if ( !p || !*p || *p !=
'=' )
1343 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
1348 p = SkipWhiteSpace( p, encoding );
1351 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
1361 p = ReadText( p, &value,
false, end,
false, encoding );
1363 else if ( *p ==
'"' )
1367 p = ReadText( p, &value,
false, end,
false, encoding );
1376 && !IsWhiteSpace( *p ) && *p !=
'\n' && *p !=
'\r'
1377 && *p !=
'/' && *p !=
'>' )
1386 #ifdef TIXML_USE_STL
1387 void TiXmlText::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
1389 while ( in->good() )
1398 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
1408 const char* TiXmlText::Parse(
const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1414 data->Stamp( p, encoding );
1415 location = data->Cursor();
1417 bool ignoreWhite =
true;
1419 const char* end =
"<";
1420 p = ReadText( p, &value, ignoreWhite, end,
false, encoding );
1426 #ifdef TIXML_USE_STL
1427 void TiXmlDeclaration::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
1429 while ( in->good() )
1436 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
1450 const char* TiXmlDeclaration::Parse(
const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding )
1452 p = SkipWhiteSpace( p, _encoding );
1456 if ( !p || !*p || !StringEqual( p,
"<?xml",
true, _encoding ) )
1458 if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding );
1464 data->Stamp( p, _encoding );
1465 location = data->Cursor();
1481 p = SkipWhiteSpace( p, _encoding );
1482 if ( StringEqual( p,
"version",
true, _encoding ) )
1484 TiXmlAttribute attrib;
1485 p = attrib.Parse( p, data, _encoding );
1486 version = attrib.Value();
1488 else if ( StringEqual( p,
"encoding",
true, _encoding ) )
1490 TiXmlAttribute attrib;
1491 p = attrib.Parse( p, data, _encoding );
1492 encoding = attrib.Value();
1494 else if ( StringEqual( p,
"standalone",
true, _encoding ) )
1496 TiXmlAttribute attrib;
1497 p = attrib.Parse( p, data, _encoding );
1498 standalone = attrib.Value();
1503 while( p && *p && *p !=
'>' && !IsWhiteSpace( *p ) )
1510 bool TiXmlText::Blank()
const
1512 for (
unsigned i=0; i<value.length(); i++ )
1513 if ( !IsWhiteSpace( value[i] ) )
virtual const char * Parse(const char *p, TiXmlParsingData *data=0, TiXmlEncoding encoding=TIXML_DEFAULT_ENCODING)
Parse the given null terminated block of xml data.
void SetValue(const char *_value)
Set the value.
TiXmlNode * LinkEndChild(TiXmlNode *addThis)
Add a new node related to this.
In correct XML the declaration is the first entry in the file.
static bool IsWhiteSpaceCondensed()
Return the current white space setting.
const char * Encoding() const
Encoding. Will return an empty string if none was found.
Always the top level node.
const TiXmlDeclaration * ToDeclaration() const
Cast to a more defined type. Will return null not of the requested type.
The parent class for everything in the Document Object Model.
void ClearError()
If you have handled the error, it can be reset with this call.
const TiXmlDocument * GetDocument() const
Return a pointer to the Document this node lives in.