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* pErr = p;
1108 p = attrib->Parse( p, data, encoding );
1112 if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, 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;
1323 tabsize = document->TabSize();
1328 data->Stamp( p, encoding );
1329 location = data->Cursor();
1332 const char* pErr = p;
1333 p = ReadName( p, &name, encoding );
1336 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
1339 p = SkipWhiteSpace( p, encoding );
1340 if ( !p || !*p || *p !=
'=' )
1342 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
1347 p = SkipWhiteSpace( p, encoding );
1350 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
1360 p = ReadText( p, &value,
false, end,
false, encoding );
1362 else if ( *p ==
'"' )
1366 p = ReadText( p, &value,
false, end,
false, encoding );
1375 && !IsWhiteSpace( *p ) && *p !=
'\n' && *p !=
'\r'
1376 && *p !=
'/' && *p !=
'>' )
1385 #ifdef TIXML_USE_STL
1386 void TiXmlText::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
1388 while ( in->good() )
1397 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
1407 const char* TiXmlText::Parse(
const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1413 data->Stamp( p, encoding );
1414 location = data->Cursor();
1416 bool ignoreWhite =
true;
1418 const char* end =
"<";
1419 p = ReadText( p, &value, ignoreWhite, end,
false, encoding );
1425 #ifdef TIXML_USE_STL
1426 void TiXmlDeclaration::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
1428 while ( in->good() )
1435 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
1449 const char* TiXmlDeclaration::Parse(
const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding )
1451 p = SkipWhiteSpace( p, _encoding );
1455 if ( !p || !*p || !StringEqual( p,
"<?xml",
true, _encoding ) )
1457 if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding );
1463 data->Stamp( p, _encoding );
1464 location = data->Cursor();
1480 p = SkipWhiteSpace( p, _encoding );
1481 if ( StringEqual( p,
"version",
true, _encoding ) )
1483 TiXmlAttribute attrib;
1484 p = attrib.Parse( p, data, _encoding );
1485 version = attrib.Value();
1487 else if ( StringEqual( p,
"encoding",
true, _encoding ) )
1489 TiXmlAttribute attrib;
1490 p = attrib.Parse( p, data, _encoding );
1491 encoding = attrib.Value();
1493 else if ( StringEqual( p,
"standalone",
true, _encoding ) )
1495 TiXmlAttribute attrib;
1496 p = attrib.Parse( p, data, _encoding );
1497 standalone = attrib.Value();
1502 while( p && *p && *p !=
'>' && !IsWhiteSpace( *p ) )
1509 bool TiXmlText::Blank()
const
1511 for (
unsigned i=0; i<value.length(); i++ )
1512 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.