33static const char LINE_FEED = (char)0x0a;
34static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d;
36static const char CR = CARRIAGE_RETURN;
37static const char SINGLE_QUOTE =
'\'';
38static const char DOUBLE_QUOTE =
'\"';
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
49#define DELETE_NODE( node ) { \
51 MemPool* pool = node->_memPool; \
56#define DELETE_ATTRIBUTE( attrib ) { \
58 MemPool* pool = attrib->_memPool; \
59 attrib->~XMLAttribute(); \
60 pool->Free( attrib ); \
73static const int NUM_ENTITIES = 5;
74static const Entity entities[NUM_ENTITIES] = {
75 {
"quot", 4, DOUBLE_QUOTE },
77 {
"apos", 4, SINGLE_QUOTE },
91 if ( _flags & NEEDS_DELETE ) {
103 size_t len = strlen(
str );
104 _start =
new char[ len+1 ];
105 memcpy( _start,
str, len+1 );
107 _flags =
flags | NEEDS_DELETE;
113 TIXMLASSERT( endTag && *endTag );
116 char endChar = *endTag;
117 size_t length = strlen( endTag );
121 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
122 Set( start, p, strFlags );
135 if ( !start || !(*start) ) {
151void StrPair::CollapseWhitespace()
156 if ( _start && *_start ) {
180 if ( _flags & NEEDS_FLUSH ) {
182 _flags ^= NEEDS_FLUSH;
193 if ( *(p+1) == LF ) {
202 if ( *(p+1) == CR ) {
216 if ( *(p+1) ==
'#' ) {
217 char buf[10] = { 0 };
220 for(
int i=0; i<len; ++i ) {
223 TIXMLASSERT( q <= p );
227 for(; i<NUM_ENTITIES; ++i ) {
228 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
229 && *(p+entities[i].length+1) ==
';' ) {
231 *q = entities[i].value;
233 p += entities[i].length + 2;
237 if ( i == NUM_ENTITIES ) {
255 CollapseWhitespace();
257 _flags = (_flags & NEEDS_DELETE);
270 const unsigned char* pu =
reinterpret_cast<const unsigned char*
>(p);
272 if ( *(pu+0) == TIXML_UTF_LEAD_0
273 && *(pu+1) == TIXML_UTF_LEAD_1
274 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
284 const unsigned long BYTE_MASK = 0xBF;
285 const unsigned long BYTE_MARK = 0x80;
286 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
291 else if ( input < 0x800 ) {
294 else if ( input < 0x10000 ) {
297 else if ( input < 0x200000 ) {
311 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
315 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
319 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
323 *output = (char)(input | FIRST_BYTE_MARK[*length]);
335 if ( *(p+1) ==
'#' && *(p+2) ) {
336 unsigned long ucs = 0;
340 if ( *(p+2) ==
'x' ) {
347 q = strchr( q,
';' );
356 while ( *q !=
'x' ) {
357 if ( *q >=
'0' && *q <=
'9' ) {
358 ucs += mult * (*q -
'0');
360 else if ( *q >=
'a' && *q <=
'f' ) {
361 ucs += mult * (*q -
'a' + 10);
363 else if ( *q >=
'A' && *q <=
'F' ) {
364 ucs += mult * (*q -
'A' + 10 );
380 q = strchr( q,
';' );
389 while ( *q !=
'#' ) {
390 if ( *q >=
'0' && *q <=
'9' ) {
391 ucs += mult * (*q -
'0');
402 return p + delta + 1;
443 if ( TIXML_SSCANF(
str,
"%d", value ) == 1 ) {
451 if ( TIXML_SSCANF(
str,
"%u", value ) == 1 ) {
461 *value = (ival==0) ?
false : true;
478 if ( TIXML_SSCANF(
str,
"%f", value ) == 1 ) {
486 if ( TIXML_SSCANF(
str,
"%lf", value ) == 1 ) {
504 static const char* xmlHeader = {
"<?" };
505 static const char* commentHeader = {
"<!--" };
506 static const char* dtdHeader = {
"<!" };
507 static const char* cdataHeader = {
"<![CDATA[" };
508 static const char* elementHeader = {
"<" };
510 static const int xmlHeaderLen = 2;
511 static const int commentHeaderLen = 4;
512 static const int dtdHeaderLen = 2;
513 static const int cdataHeaderLen = 9;
514 static const int elementHeaderLen = 1;
517#pragma warning ( push )
518#pragma warning ( disable : 4127 )
520 TIXMLASSERT(
sizeof( XMLComment ) ==
sizeof( XMLUnknown ) );
521 TIXMLASSERT(
sizeof( XMLComment ) ==
sizeof( XMLDeclaration ) );
526 returnNode =
new (_commentPool.Alloc()) XMLDeclaration(
this );
527 returnNode->_memPool = &_commentPool;
531 returnNode =
new (_commentPool.Alloc()) XMLComment(
this );
532 returnNode->_memPool = &_commentPool;
533 p += commentHeaderLen;
536 XMLText* text =
new (_textPool.Alloc()) XMLText(
this );
538 returnNode->_memPool = &_textPool;
540 text->SetCData(
true );
543 returnNode =
new (_commentPool.Alloc()) XMLUnknown(
this );
544 returnNode->_memPool = &_commentPool;
548 returnNode =
new (_elementPool.Alloc())
XMLElement(
this );
549 returnNode->_memPool = &_elementPool;
550 p += elementHeaderLen;
553 returnNode =
new (_textPool.Alloc()) XMLText(
this );
554 returnNode->_memPool = &_textPool;
565 if ( visitor->VisitEnter( *
this ) ) {
567 if ( !node->Accept( visitor ) ) {
572 return visitor->VisitExit( *
this );
581 _firstChild( 0 ), _lastChild( 0 ),
582 _prev( 0 ), _next( 0 ),
592 _parent->Unlink(
this );
596const char* XMLNode::Value()
const
598 return _value.GetStr();
601void XMLNode::SetValue(
const char*
str,
bool staticMem )
604 _value.SetInternedStr(
str );
607 _value.SetStr(
str );
612void XMLNode::DeleteChildren()
614 while( _firstChild ) {
615 XMLNode* node = _firstChild;
620 _firstChild = _lastChild = 0;
624void XMLNode::Unlink( XMLNode* child )
626 if ( child == _firstChild ) {
627 _firstChild = _firstChild->_next;
629 if ( child == _lastChild ) {
630 _lastChild = _lastChild->_prev;
633 if ( child->_prev ) {
634 child->_prev->_next = child->_next;
636 if ( child->_next ) {
637 child->_next->_prev = child->_prev;
643void XMLNode::DeleteChild( XMLNode* node )
645 TIXMLASSERT( node->_parent ==
this );
650XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
652 if (addThis->_document != _document)
655 if (addThis->_parent)
656 addThis->_parent->Unlink( addThis );
658 addThis->_memPool->SetTracked();
661 TIXMLASSERT( _firstChild );
662 TIXMLASSERT( _lastChild->_next == 0 );
663 _lastChild->_next = addThis;
664 addThis->_prev = _lastChild;
665 _lastChild = addThis;
670 TIXMLASSERT( _firstChild == 0 );
671 _firstChild = _lastChild = addThis;
676 addThis->_parent =
this;
681XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
683 if (addThis->_document != _document)
686 if (addThis->_parent)
687 addThis->_parent->Unlink( addThis );
689 addThis->_memPool->SetTracked();
692 TIXMLASSERT( _lastChild );
693 TIXMLASSERT( _firstChild->_prev == 0 );
695 _firstChild->_prev = addThis;
696 addThis->_next = _firstChild;
697 _firstChild = addThis;
702 TIXMLASSERT( _lastChild == 0 );
703 _firstChild = _lastChild = addThis;
708 addThis->_parent =
this;
713XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
715 if (addThis->_document != _document)
718 TIXMLASSERT( afterThis->_parent ==
this );
720 if ( afterThis->_parent !=
this ) {
724 if ( afterThis->_next == 0 ) {
726 return InsertEndChild( addThis );
728 if (addThis->_parent)
729 addThis->_parent->Unlink( addThis );
731 addThis->_memPool->SetTracked();
732 addThis->_prev = afterThis;
733 addThis->_next = afterThis->_next;
734 afterThis->_next->_prev = addThis;
735 afterThis->_next = addThis;
736 addThis->_parent =
this;
743const XMLElement* XMLNode::FirstChildElement(
const char* value )
const
745 for( XMLNode* node=_firstChild; node; node=node->_next ) {
746 XMLElement* element = node->ToElement();
748 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
757const XMLElement* XMLNode::LastChildElement(
const char* value )
const
759 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
760 XMLElement* element = node->ToElement();
762 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
771const XMLElement* XMLNode::NextSiblingElement(
const char* value )
const
773 for( XMLNode* element=this->_next; element; element = element->_next ) {
774 if ( element->ToElement()
775 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
776 return element->ToElement();
783const XMLElement* XMLNode::PreviousSiblingElement(
const char* value )
const
785 for( XMLNode* element=_prev; element; element = element->_prev ) {
786 if ( element->ToElement()
787 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
788 return element->ToElement();
795char* XMLNode::ParseDeep(
char* p, StrPair* parentEnd )
817 p = _document->Identify( p, &node );
818 if ( p == 0 || node == 0 ) {
823 p = node->ParseDeep( p, &endTag );
827 if ( !_document->Error() ) {
828 _document->SetError( XML_ERROR_PARSING, 0, 0 );
834 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
836 *parentEnd =
static_cast<XMLElement*
>(node)->_value;
838 node->_memPool->SetTracked();
845 XMLElement* ele = node->ToElement();
847 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
848 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
851 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
852 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
855 else if ( !endTag.Empty() ) {
856 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
857 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
867 this->InsertEndChild( node );
874char* XMLText::ParseDeep(
char* p, StrPair* )
876 const char* start = p;
877 if ( this->CData() ) {
878 p = _value.ParseText( p,
"]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
880 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
885 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
886 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
887 flags |= StrPair::COLLAPSE_WHITESPACE;
890 p = _value.ParseText( p,
"<",
flags );
892 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
902XMLNode* XMLText::ShallowClone( XMLDocument* doc )
const
907 XMLText* text = doc->NewText( Value() );
908 text->SetCData( this->CData() );
913bool XMLText::ShallowEqual(
const XMLNode* compare )
const
915 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
919bool XMLText::Accept( XMLVisitor* visitor )
const
921 return visitor->Visit( *
this );
927XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
932XMLComment::~XMLComment()
937char* XMLComment::ParseDeep(
char* p, StrPair* )
940 const char* start = p;
941 p = _value.ParseText( p,
"-->", StrPair::COMMENT );
943 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
949XMLNode* XMLComment::ShallowClone( XMLDocument* doc )
const
954 XMLComment* comment = doc->NewComment( Value() );
959bool XMLComment::ShallowEqual(
const XMLNode* compare )
const
961 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
965bool XMLComment::Accept( XMLVisitor* visitor )
const
967 return visitor->Visit( *
this );
973XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
978XMLDeclaration::~XMLDeclaration()
984char* XMLDeclaration::ParseDeep(
char* p, StrPair* )
987 const char* start = p;
988 p = _value.ParseText( p,
"?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
990 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
996XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc )
const
1001 XMLDeclaration* dec = doc->NewDeclaration( Value() );
1006bool XMLDeclaration::ShallowEqual(
const XMLNode* compare )
const
1008 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
1013bool XMLDeclaration::Accept( XMLVisitor* visitor )
const
1015 return visitor->Visit( *
this );
1020XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1025XMLUnknown::~XMLUnknown()
1030char* XMLUnknown::ParseDeep(
char* p, StrPair* )
1033 const char* start = p;
1035 p = _value.ParseText( p,
">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
1037 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
1043XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc )
const
1048 XMLUnknown* text = doc->NewUnknown( Value() );
1053bool XMLUnknown::ShallowEqual(
const XMLNode* compare )
const
1055 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
1059bool XMLUnknown::Accept( XMLVisitor* visitor )
const
1061 return visitor->Visit( *
this );
1066const char* XMLAttribute::Name()
const
1068 return _name.GetStr();
1071const char* XMLAttribute::Value()
const
1073 return _value.GetStr();
1076char* XMLAttribute::ParseDeep(
char* p,
bool processEntities )
1079 p = _name.ParseName( p );
1085 p = XMLUtil::SkipWhiteSpace( p );
1086 if ( !p || *p !=
'=' ) {
1091 p = XMLUtil::SkipWhiteSpace( p );
1092 if ( *p !=
'\"' && *p !=
'\'' ) {
1096 char endTag[2] = { *p, 0 };
1099 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
1104void XMLAttribute::SetName(
const char* n )
1110XMLError XMLAttribute::QueryIntValue(
int* value )
const
1112 if ( XMLUtil::ToInt( Value(), value )) {
1119XMLError XMLAttribute::QueryUnsignedValue(
unsigned int* value )
const
1121 if ( XMLUtil::ToUnsigned( Value(), value )) {
1128XMLError XMLAttribute::QueryBoolValue(
bool* value )
const
1130 if ( XMLUtil::ToBool( Value(), value )) {
1137XMLError XMLAttribute::QueryFloatValue(
float* value )
const
1139 if ( XMLUtil::ToFloat( Value(), value )) {
1146XMLError XMLAttribute::QueryDoubleValue(
double* value )
const
1148 if ( XMLUtil::ToDouble( Value(), value )) {
1155void XMLAttribute::SetAttribute(
const char* v )
1161void XMLAttribute::SetAttribute(
int v )
1164 XMLUtil::ToStr( v, buf, BUF_SIZE );
1165 _value.SetStr( buf );
1169void XMLAttribute::SetAttribute(
unsigned v )
1172 XMLUtil::ToStr( v, buf, BUF_SIZE );
1173 _value.SetStr( buf );
1177void XMLAttribute::SetAttribute(
bool v )
1180 XMLUtil::ToStr( v, buf, BUF_SIZE );
1181 _value.SetStr( buf );
1184void XMLAttribute::SetAttribute(
double v )
1187 XMLUtil::ToStr( v, buf, BUF_SIZE );
1188 _value.SetStr( buf );
1191void XMLAttribute::SetAttribute(
float v )
1194 XMLUtil::ToStr( v, buf, BUF_SIZE );
1195 _value.SetStr( buf );
1200XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
1207XMLElement::~XMLElement()
1209 while( _rootAttribute ) {
1210 XMLAttribute* next = _rootAttribute->_next;
1211 DELETE_ATTRIBUTE( _rootAttribute );
1212 _rootAttribute = next;
1217XMLAttribute* XMLElement::FindAttribute(
const char* name )
1219 XMLAttribute* a = 0;
1220 for( a=_rootAttribute; a; a = a->_next ) {
1221 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1229const XMLAttribute* XMLElement::FindAttribute(
const char* name )
const
1231 XMLAttribute* a = 0;
1232 for( a=_rootAttribute; a; a = a->_next ) {
1233 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1241const char* XMLElement::Attribute(
const char* name,
const char* value )
const
1243 const XMLAttribute* a = FindAttribute( name );
1247 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1254const char* XMLElement::GetText()
const
1256 if ( FirstChild() && FirstChild()->ToText() ) {
1257 return FirstChild()->ToText()->Value();
1263void XMLElement::SetText(
const char* inText )
1265 if ( FirstChild() && FirstChild()->ToText() )
1266 FirstChild()->SetValue( inText );
1268 XMLText* theText = GetDocument()->NewText( inText );
1269 InsertFirstChild( theText );
1274void XMLElement::SetText(
int v )
1277 XMLUtil::ToStr( v, buf, BUF_SIZE );
1282void XMLElement::SetText(
unsigned v )
1285 XMLUtil::ToStr( v, buf, BUF_SIZE );
1290void XMLElement::SetText(
bool v )
1293 XMLUtil::ToStr( v, buf, BUF_SIZE );
1298void XMLElement::SetText(
float v )
1301 XMLUtil::ToStr( v, buf, BUF_SIZE );
1306void XMLElement::SetText(
double v )
1309 XMLUtil::ToStr( v, buf, BUF_SIZE );
1314XMLError XMLElement::QueryIntText(
int* ival )
const
1316 if ( FirstChild() && FirstChild()->ToText() ) {
1317 const char* t = FirstChild()->ToText()->Value();
1318 if ( XMLUtil::ToInt( t, ival ) ) {
1327XMLError XMLElement::QueryUnsignedText(
unsigned* uval )
const
1329 if ( FirstChild() && FirstChild()->ToText() ) {
1330 const char* t = FirstChild()->ToText()->Value();
1331 if ( XMLUtil::ToUnsigned( t, uval ) ) {
1340XMLError XMLElement::QueryBoolText(
bool* bval )
const
1342 if ( FirstChild() && FirstChild()->ToText() ) {
1343 const char* t = FirstChild()->ToText()->Value();
1344 if ( XMLUtil::ToBool( t, bval ) ) {
1353XMLError XMLElement::QueryDoubleText(
double* dval )
const
1355 if ( FirstChild() && FirstChild()->ToText() ) {
1356 const char* t = FirstChild()->ToText()->Value();
1357 if ( XMLUtil::ToDouble( t, dval ) ) {
1366XMLError XMLElement::QueryFloatText(
float* fval )
const
1368 if ( FirstChild() && FirstChild()->ToText() ) {
1369 const char* t = FirstChild()->ToText()->Value();
1370 if ( XMLUtil::ToFloat( t, fval ) ) {
1380XMLAttribute* XMLElement::FindOrCreateAttribute(
const char* name )
1382 XMLAttribute* last = 0;
1383 XMLAttribute* attrib = 0;
1384 for( attrib = _rootAttribute;
1386 last = attrib, attrib = attrib->_next ) {
1387 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1392 attrib =
new (_document->_attributePool.Alloc() ) XMLAttribute();
1393 attrib->_memPool = &_document->_attributePool;
1395 last->_next = attrib;
1398 _rootAttribute = attrib;
1400 attrib->SetName( name );
1401 attrib->_memPool->SetTracked();
1407void XMLElement::DeleteAttribute(
const char* name )
1409 XMLAttribute* prev = 0;
1410 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
1411 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1413 prev->_next = a->_next;
1416 _rootAttribute = a->_next;
1418 DELETE_ATTRIBUTE( a );
1426char* XMLElement::ParseAttributes(
char* p )
1428 const char* start = p;
1429 XMLAttribute* prevAttribute = 0;
1433 p = XMLUtil::SkipWhiteSpace( p );
1434 if ( !p || !(*p) ) {
1435 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
1440 if (XMLUtil::IsNameStartChar( *p ) ) {
1441 XMLAttribute* attrib =
new (_document->_attributePool.Alloc() ) XMLAttribute();
1442 attrib->_memPool = &_document->_attributePool;
1443 attrib->_memPool->SetTracked();
1445 p = attrib->ParseDeep( p, _document->ProcessEntities() );
1446 if ( !p || Attribute( attrib->Name() ) ) {
1447 DELETE_ATTRIBUTE( attrib );
1448 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
1456 if ( prevAttribute ) {
1457 prevAttribute->_next = attrib;
1460 _rootAttribute = attrib;
1462 prevAttribute = attrib;
1465 else if ( *p ==
'/' && *(p+1) ==
'>' ) {
1466 _closingType = CLOSED;
1470 else if ( *p ==
'>' ) {
1475 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
1487char* XMLElement::ParseDeep(
char* p, StrPair* strPair )
1490 p = XMLUtil::SkipWhiteSpace( p );
1499 _closingType = CLOSING;
1503 p = _value.ParseName( p );
1504 if ( _value.Empty() ) {
1508 p = ParseAttributes( p );
1509 if ( !p || !*p || _closingType ) {
1513 p = XMLNode::ParseDeep( p, strPair );
1519XMLNode* XMLElement::ShallowClone( XMLDocument* doc )
const
1524 XMLElement* element = doc->NewElement( Value() );
1525 for(
const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1526 element->SetAttribute( a->Name(), a->Value() );
1532bool XMLElement::ShallowEqual(
const XMLNode* compare )
const
1534 const XMLElement* other = compare->ToElement();
1535 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
1537 const XMLAttribute* a=FirstAttribute();
1538 const XMLAttribute* b=other->FirstAttribute();
1541 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1557bool XMLElement::Accept( XMLVisitor* visitor )
const
1559 if ( visitor->VisitEnter( *
this, _rootAttribute ) ) {
1560 for (
const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1561 if ( !node->Accept( visitor ) ) {
1566 return visitor->VisitExit( *
this );
1571XMLDocument::XMLDocument(
bool processEntities, Whitespace whitespace ) :
1574 _processEntities( processEntities ),
1576 _whitespace( whitespace ),
1585XMLDocument::~XMLDocument()
1588 delete [] _charBuffer;
1591 _textPool.Trace(
"text" );
1592 _elementPool.Trace(
"element" );
1593 _commentPool.Trace(
"comment" );
1594 _attributePool.Trace(
"attribute" );
1598 if ( Error() ==
false ) {
1599 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1600 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1601 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1602 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1608void XMLDocument::Clear()
1616 delete [] _charBuffer;
1621XMLElement* XMLDocument::NewElement(
const char* name )
1623 XMLElement* ele =
new (_elementPool.Alloc()) XMLElement(
this );
1624 ele->_memPool = &_elementPool;
1625 ele->SetName( name );
1630XMLComment* XMLDocument::NewComment(
const char*
str )
1632 XMLComment* comment =
new (_commentPool.Alloc()) XMLComment(
this );
1633 comment->_memPool = &_commentPool;
1634 comment->SetValue(
str );
1639XMLText* XMLDocument::NewText(
const char*
str )
1641 XMLText* text =
new (_textPool.Alloc()) XMLText(
this );
1642 text->_memPool = &_textPool;
1643 text->SetValue(
str );
1648XMLDeclaration* XMLDocument::NewDeclaration(
const char*
str )
1650 XMLDeclaration* dec =
new (_commentPool.Alloc()) XMLDeclaration(
this );
1651 dec->_memPool = &_commentPool;
1652 dec->SetValue(
str ?
str :
"xml version=\"1.0\" encoding=\"UTF-8\"" );
1657XMLUnknown* XMLDocument::NewUnknown(
const char*
str )
1659 XMLUnknown* unk =
new (_commentPool.Alloc()) XMLUnknown(
this );
1660 unk->_memPool = &_commentPool;
1661 unk->SetValue(
str );
1666XMLError XMLDocument::LoadFile(
const char* filename )
1671#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1672 errno_t err = fopen_s(&fp, filename,
"rb" );
1675 fp = fopen( filename,
"rb" );
1678 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
1687XMLError XMLDocument::LoadFile( FILE* fp )
1691 fseek( fp, 0, SEEK_SET );
1693 if ( ferror( fp ) != 0 ) {
1694 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1698 fseek( fp, 0, SEEK_END );
1699 size_t size = ftell( fp );
1700 fseek( fp, 0, SEEK_SET );
1703 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1707 _charBuffer =
new char[size+1];
1708 size_t read = fread( _charBuffer, 1, size, fp );
1709 if ( read != size ) {
1710 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1714 _charBuffer[size] = 0;
1716 const char* p = _charBuffer;
1717 p = XMLUtil::SkipWhiteSpace( p );
1718 p = XMLUtil::ReadBOM( p, &_writeBOM );
1720 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1724 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1729XMLError XMLDocument::SaveFile(
const char* filename,
bool compact )
1732#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1733 errno_t err = fopen_s(&fp, filename,
"w" );
1736 fp = fopen( filename,
"w" );
1739 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
1742 SaveFile(fp, compact);
1748XMLError XMLDocument::SaveFile( FILE* fp,
bool compact )
1750 XMLPrinter stream( fp, compact );
1756XMLError XMLDocument::Parse(
const char* p,
size_t len )
1758 const char* start = p;
1761 if ( len == 0 || !p || !*p ) {
1762 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1765 if ( len == (
size_t)(-1) ) {
1768 _charBuffer =
new char[ len+1 ];
1769 memcpy( _charBuffer, p, len );
1770 _charBuffer[len] = 0;
1772 p = XMLUtil::SkipWhiteSpace( p );
1773 p = XMLUtil::ReadBOM( p, &_writeBOM );
1775 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1779 ptrdiff_t delta = p - start;
1780 ParseDeep( _charBuffer+delta, 0 );
1785void XMLDocument::Print( XMLPrinter* streamer )
const
1787 XMLPrinter stdStreamer( stdout );
1789 streamer = &stdStreamer;
1795void XMLDocument::SetError( XMLError error,
const char* str1,
const char* str2 )
1803void XMLDocument::PrintError()
const
1806 static const int LEN = 20;
1807 char buf1[LEN] = { 0 };
1808 char buf2[LEN] = { 0 };
1817 printf(
"XMLDocument error id=%d str1=%s str2=%s\n",
1818 _errorID, buf1, buf2 );
1823XMLPrinter::XMLPrinter( FILE* file,
bool compact,
int depth ) :
1824 _elementJustOpened( false ),
1825 _firstElement( true ),
1829 _processEntities( true ),
1830 _compactMode( compact )
1832 for(
int i=0; i<ENTITY_RANGE; ++i ) {
1833 _entityFlag[i] =
false;
1834 _restrictedEntityFlag[i] =
false;
1836 for(
int i=0; i<NUM_ENTITIES; ++i ) {
1837 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1838 if ( entities[i].value < ENTITY_RANGE ) {
1839 _entityFlag[ (int)entities[i].value ] =
true;
1842 _restrictedEntityFlag[(int)
'&'] =
true;
1843 _restrictedEntityFlag[(int)
'<'] =
true;
1844 _restrictedEntityFlag[(int)
'>'] =
true;
1849void XMLPrinter::Print(
const char* format, ... )
1852 va_start( va, format );
1855 vfprintf( _fp, format, va );
1858#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1859 int len = _vscprintf( format, va );
1861 int len = vsnprintf( 0, 0, format, va );
1865 va_start( va, format );
1866 char* p = _buffer.PushArr( len ) - 1;
1867#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1868 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
1870 vsnprintf( p, len+1, format, va );
1877void XMLPrinter::PrintSpace(
int depth )
1879 for(
int i=0; i<depth; ++i ) {
1885void XMLPrinter::PrintString(
const char* p,
bool restricted )
1889 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
1891 if ( _processEntities ) {
1894 if ( *q > 0 && *q < ENTITY_RANGE ) {
1898 if ( flag[(
unsigned)(*q)] ) {
1903 for(
int i=0; i<NUM_ENTITIES; ++i ) {
1904 if ( entities[i].value == *q ) {
1905 Print(
"&%s;", entities[i].pattern );
1917 if ( !_processEntities || (q-p > 0) ) {
1923void XMLPrinter::PushHeader(
bool writeBOM,
bool writeDec )
1926 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1930 PushDeclaration(
"xml version=\"1.0\"" );
1935void XMLPrinter::OpenElement(
const char* name,
bool compactMode )
1937 if ( _elementJustOpened ) {
1940 _stack.Push( name );
1942 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
1945 if ( !compactMode ) {
1946 PrintSpace( _depth );
1949 Print(
"<%s", name );
1950 _elementJustOpened =
true;
1951 _firstElement =
false;
1956void XMLPrinter::PushAttribute(
const char* name,
const char* value )
1958 TIXMLASSERT( _elementJustOpened );
1959 Print(
" %s=\"", name );
1960 PrintString( value,
false );
1965void XMLPrinter::PushAttribute(
const char* name,
int v )
1968 XMLUtil::ToStr( v, buf, BUF_SIZE );
1969 PushAttribute( name, buf );
1973void XMLPrinter::PushAttribute(
const char* name,
unsigned v )
1976 XMLUtil::ToStr( v, buf, BUF_SIZE );
1977 PushAttribute( name, buf );
1981void XMLPrinter::PushAttribute(
const char* name,
bool v )
1984 XMLUtil::ToStr( v, buf, BUF_SIZE );
1985 PushAttribute( name, buf );
1989void XMLPrinter::PushAttribute(
const char* name,
double v )
1992 XMLUtil::ToStr( v, buf, BUF_SIZE );
1993 PushAttribute( name, buf );
1997void XMLPrinter::CloseElement(
bool compactMode )
2000 const char* name = _stack.Pop();
2002 if ( _elementJustOpened ) {
2006 if ( _textDepth < 0 && !compactMode) {
2008 PrintSpace( _depth );
2010 Print(
"</%s>", name );
2013 if ( _textDepth == _depth ) {
2016 if ( _depth == 0 && !compactMode) {
2019 _elementJustOpened =
false;
2023void XMLPrinter::SealElement()
2025 _elementJustOpened =
false;
2030void XMLPrinter::PushText(
const char* text,
bool cdata )
2032 _textDepth = _depth-1;
2034 if ( _elementJustOpened ) {
2038 Print(
"<![CDATA[" );
2039 Print(
"%s", text );
2043 PrintString( text,
true );
2047void XMLPrinter::PushText(
int value )
2050 XMLUtil::ToStr( value, buf, BUF_SIZE );
2051 PushText( buf,
false );
2055void XMLPrinter::PushText(
unsigned value )
2058 XMLUtil::ToStr( value, buf, BUF_SIZE );
2059 PushText( buf,
false );
2063void XMLPrinter::PushText(
bool value )
2066 XMLUtil::ToStr( value, buf, BUF_SIZE );
2067 PushText( buf,
false );
2071void XMLPrinter::PushText(
float value )
2074 XMLUtil::ToStr( value, buf, BUF_SIZE );
2075 PushText( buf,
false );
2079void XMLPrinter::PushText(
double value )
2082 XMLUtil::ToStr( value, buf, BUF_SIZE );
2083 PushText( buf,
false );
2087void XMLPrinter::PushComment(
const char* comment )
2089 if ( _elementJustOpened ) {
2092 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
2094 PrintSpace( _depth );
2096 _firstElement =
false;
2097 Print(
"<!--%s-->", comment );
2101void XMLPrinter::PushDeclaration(
const char* value )
2103 if ( _elementJustOpened ) {
2106 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
2108 PrintSpace( _depth );
2110 _firstElement =
false;
2111 Print(
"<?%s?>", value );
2115void XMLPrinter::PushUnknown(
const char* value )
2117 if ( _elementJustOpened ) {
2120 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
2122 PrintSpace( _depth );
2124 _firstElement =
false;
2125 Print(
"<!%s>", value );
2129bool XMLPrinter::VisitEnter(
const XMLDocument& doc )
2131 _processEntities = doc.ProcessEntities();
2132 if ( doc.HasBOM() ) {
2133 PushHeader(
true,
false );
2139bool XMLPrinter::VisitEnter(
const XMLElement& element,
const XMLAttribute* attribute )
2141 const XMLElement* parentElem = element.Parent()->ToElement();
2142 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2143 OpenElement( element.Name(), compactMode );
2144 while ( attribute ) {
2145 PushAttribute( attribute->Name(), attribute->Value() );
2146 attribute = attribute->Next();
2152bool XMLPrinter::VisitExit(
const XMLElement& element )
2154 CloseElement( CompactMode(element) );
2159bool XMLPrinter::Visit(
const XMLText& text )
2161 PushText( text.Value(), text.CData() );
2166bool XMLPrinter::Visit(
const XMLComment& comment )
2168 PushComment( comment.Value() );
2172bool XMLPrinter::Visit(
const XMLDeclaration& declaration )
2174 PushDeclaration( declaration.Value() );
2179bool XMLPrinter::Visit(
const XMLUnknown& unknown )
2181 PushUnknown( unknown.Value() );
void SetStr(const char *str, int flags=0)
void Set(char *start, char *end, int flags)
char * ParseName(char *in)
@ NEEDS_ENTITY_PROCESSING
@ NEEDS_NEWLINE_NORMALIZATION
char * ParseText(char *in, const char *endTag, int strFlags)
char * Identify(char *p, XMLNode **node)
virtual bool Accept(XMLVisitor *visitor) const
const XMLNode * FirstChild() const
Get the first child node, or null if none exists.
const XMLNode * NextSibling() const
Get the next (right) sibling node of this node.
static const char * GetCharacterRef(const char *p, char *value, int *length)
static const char * SkipWhiteSpace(const char *p)
static bool IsWhiteSpace(char p)
static bool ToUnsigned(const char *str, unsigned *value)
static void ToStr(int v, char *buffer, int bufferSize)
static bool ToDouble(const char *str, double *value)
static void ConvertUTF32ToUTF8(unsigned long input, char *output, int *length)
static bool IsNameStartChar(unsigned char ch)
static bool ToFloat(const char *str, float *value)
static bool ToInt(const char *str, int *value)
static bool StringEqual(const char *p, const char *q, int nChar=INT_MAX)
static const char * ReadBOM(const char *p, bool *hasBOM)
static bool ToBool(const char *str, bool *value)
@ XML_WRONG_ATTRIBUTE_TYPE
@ XML_CAN_NOT_CONVERT_TEXT
STBI_EXTERN unsigned long const char * str
STBI_EXTERN unsigned long flags
int TIXML_SNPRINTF(char *buffer, size_t size, const char *format,...)