35static const char LINE_FEED = (char)0x0a;
36static const char LF = LINE_FEED;
37static const char CARRIAGE_RETURN = (char)0x0d;
38static const char CR = CARRIAGE_RETURN;
39static const char SINGLE_QUOTE =
'\'';
40static const char DOUBLE_QUOTE =
'\"';
46static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
47static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
48static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
51#define DELETE_NODE( node ) { \
53 MemPool* pool = node->_memPool; \
58#define DELETE_ATTRIBUTE( attrib ) { \
60 MemPool* pool = attrib->_memPool; \
61 attrib->~XMLAttribute(); \
62 pool->Free( attrib ); \
75static const int NUM_ENTITIES = 5;
76static const Entity entities[NUM_ENTITIES] = {
77 {
"quot", 4, DOUBLE_QUOTE },
79 {
"apos", 4, SINGLE_QUOTE },
93 if ( _flags & NEEDS_DELETE ) {
102void StrPair::SetStr(
const char* str,
int flags )
105 size_t len = strlen( str );
106 _start =
new char[ len+1 ];
107 memcpy( _start, str, len+1 );
109 _flags = flags | NEEDS_DELETE;
113char* StrPair::ParseText(
char* p,
const char* endTag,
int strFlags )
115 TIXMLASSERT( endTag && *endTag );
118 char endChar = *endTag;
119 size_t length = strlen( endTag );
123 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
124 Set( start, p, strFlags );
133char* StrPair::ParseName(
char* p )
137 if ( !start || !(*start) ) {
142 XMLUtil::IsAlphaNum( (
unsigned char) *p )
145 || (*p ==
'-' && p>start )
146 || (*p ==
'.' && p>start ) )) {
158void StrPair::CollapseWhitespace()
161 _start = XMLUtil::SkipWhiteSpace( _start );
163 if ( _start && *_start ) {
168 if ( XMLUtil::IsWhiteSpace( *p )) {
169 p = XMLUtil::SkipWhiteSpace( p );
185const char* StrPair::GetStr()
187 if ( _flags & NEEDS_FLUSH ) {
189 _flags ^= NEEDS_FLUSH;
196 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
200 if ( *(p+1) == LF ) {
208 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
209 if ( *(p+1) == CR ) {
217 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p ==
'&' ) {
223 if ( *(p+1) ==
'#' ) {
224 char buf[10] = { 0 };
226 p =
const_cast<char*
>( XMLUtil::GetCharacterRef( p, buf, &len ) );
227 for(
int i=0; i<len; ++i ) {
230 TIXMLASSERT( q <= p );
234 for(; i<NUM_ENTITIES; ++i ) {
235 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
236 && *(p+entities[i].length+1) ==
';' ) {
238 *q = entities[i].value;
240 p += entities[i].length + 2;
244 if ( i == NUM_ENTITIES ) {
261 if ( _flags & COLLAPSE_WHITESPACE ) {
262 CollapseWhitespace();
264 _flags = (_flags & NEEDS_DELETE);
274const char* XMLUtil::ReadBOM(
const char* p,
bool* bom )
277 const unsigned char* pu =
reinterpret_cast<const unsigned char*
>(p);
279 if ( *(pu+0) == TIXML_UTF_LEAD_0
280 && *(pu+1) == TIXML_UTF_LEAD_1
281 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
289void XMLUtil::ConvertUTF32ToUTF8(
unsigned long input,
char* output,
int* length )
291 const unsigned long BYTE_MASK = 0xBF;
292 const unsigned long BYTE_MARK = 0x80;
293 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
298 else if ( input < 0x800 ) {
301 else if ( input < 0x10000 ) {
304 else if ( input < 0x200000 ) {
318 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
322 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
326 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
330 *output = (char)(input | FIRST_BYTE_MARK[*length]);
335const char* XMLUtil::GetCharacterRef(
const char* p,
char* value,
int* length )
340 if ( *(p+1) ==
'#' && *(p+2) ) {
341 unsigned long ucs = 0;
345 if ( *(p+2) ==
'x' ) {
352 q = strchr( q,
';' );
361 while ( *q !=
'x' ) {
362 if ( *q >=
'0' && *q <=
'9' ) {
363 ucs += mult * (*q -
'0');
365 else if ( *q >=
'a' && *q <=
'f' ) {
366 ucs += mult * (*q -
'a' + 10);
368 else if ( *q >=
'A' && *q <=
'F' ) {
369 ucs += mult * (*q -
'A' + 10 );
385 q = strchr( q,
';' );
394 while ( *q !=
'#' ) {
395 if ( *q >=
'0' && *q <=
'9' ) {
396 ucs += mult * (*q -
'0');
406 ConvertUTF32ToUTF8( ucs, value, length );
407 return p + delta + 1;
413void XMLUtil::ToStr(
int v,
char* buffer,
int bufferSize )
415 TIXML_SNPRINTF( buffer, bufferSize,
"%d", v );
419void XMLUtil::ToStr(
unsigned v,
char* buffer,
int bufferSize )
421 TIXML_SNPRINTF( buffer, bufferSize,
"%u", v );
425void XMLUtil::ToStr(
bool v,
char* buffer,
int bufferSize )
427 TIXML_SNPRINTF( buffer, bufferSize,
"%d", v ? 1 : 0 );
431void XMLUtil::ToStr(
float v,
char* buffer,
int bufferSize )
433 TIXML_SNPRINTF( buffer, bufferSize,
"%g", v );
437void XMLUtil::ToStr(
double v,
char* buffer,
int bufferSize )
439 TIXML_SNPRINTF( buffer, bufferSize,
"%g", v );
443bool XMLUtil::ToInt(
const char* str,
int* value )
445 if ( TIXML_SSCANF( str,
"%d", value ) == 1 ) {
451bool XMLUtil::ToUnsigned(
const char* str,
unsigned *value )
453 if ( TIXML_SSCANF( str,
"%u", value ) == 1 ) {
459bool XMLUtil::ToBool(
const char* str,
bool* value )
462 if ( ToInt( str, &ival )) {
463 *value = (ival==0) ?
false : true;
466 if ( StringEqual( str,
"true" ) ) {
470 else if ( StringEqual( str,
"false" ) ) {
478bool XMLUtil::ToFloat(
const char* str,
float* value )
480 if ( TIXML_SSCANF( str,
"%f", value ) == 1 ) {
486bool XMLUtil::ToDouble(
const char* str,
double* value )
488 if ( TIXML_SSCANF( str,
"%lf", value ) == 1 ) {
495char* XMLDocument::Identify(
char* p, XMLNode** node )
497 XMLNode* returnNode = 0;
499 p = XMLUtil::SkipWhiteSpace( p );
511 static const char* xmlHeader = {
"<?" };
512 static const char* commentHeader = {
"<!--" };
513 static const char* dtdHeader = {
"<!" };
514 static const char* cdataHeader = {
"<![CDATA[" };
515 static const char* elementHeader = {
"<" };
517 static const int xmlHeaderLen = 2;
518 static const int commentHeaderLen = 4;
519 static const int dtdHeaderLen = 2;
520 static const int cdataHeaderLen = 9;
521 static const int elementHeaderLen = 1;
524#pragma warning ( push )
525#pragma warning ( disable : 4127 )
527 TIXMLASSERT(
sizeof( XMLComment ) ==
sizeof( XMLUnknown ) );
528 TIXMLASSERT(
sizeof( XMLComment ) ==
sizeof( XMLDeclaration ) );
532 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
533 returnNode =
new (_commentPool.Alloc()) XMLDeclaration(
this );
534 returnNode->_memPool = &_commentPool;
537 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
538 returnNode =
new (_commentPool.Alloc()) XMLComment(
this );
539 returnNode->_memPool = &_commentPool;
540 p += commentHeaderLen;
542 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
543 XMLText* text =
new (_textPool.Alloc()) XMLText(
this );
545 returnNode->_memPool = &_textPool;
547 text->SetCData(
true );
549 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
550 returnNode =
new (_commentPool.Alloc()) XMLUnknown(
this );
551 returnNode->_memPool = &_commentPool;
554 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
555 returnNode =
new (_elementPool.Alloc()) XMLElement(
this );
556 returnNode->_memPool = &_elementPool;
557 p += elementHeaderLen;
560 returnNode =
new (_textPool.Alloc()) XMLText(
this );
561 returnNode->_memPool = &_textPool;
572 if (
visitor->VisitEnter( *
this ) ) {
579 return visitor->VisitExit( *
this );
588 _firstChild( 0 ), _lastChild( 0 ),
589 _prev( 0 ), _next( 0 )
598 _parent->Unlink(
this );
606 _value.SetInternedStr(
str );
609 _value.SetStr(
str );
616 while( _firstChild ) {
622 _firstChild = _lastChild = 0;
628 TIXMLASSERT(
child->_parent ==
this );
629 if (
child == _firstChild ) {
630 _firstChild = _firstChild->_next;
632 if ( child == _lastChild ) {
633 _lastChild = _lastChild->_prev;
636 if ( child->_prev ) {
637 child->_prev->_next = child->_next;
639 if ( child->_next ) {
640 child->_next->_prev = child->_prev;
648 TIXMLASSERT(
node->_parent ==
this );
656 TIXMLASSERT( _firstChild );
657 TIXMLASSERT( _lastChild->_next == 0 );
665 TIXMLASSERT( _firstChild == 0 );
666 _firstChild = _lastChild =
addThis;
679 TIXMLASSERT( _lastChild );
680 TIXMLASSERT( _firstChild->_prev == 0 );
689 TIXMLASSERT( _lastChild == 0 );
690 _firstChild = _lastChild =
addThis;
702 TIXMLASSERT(
afterThis->_parent ==
this );
727 if ( !value || XMLUtil::StringEqual(
element->Name(), value ) ) {
741 if ( !value || XMLUtil::StringEqual(
element->Name(), value ) ) {
754 && (!value || XMLUtil::StringEqual( value,
element->Value() ))) {
766 && (!value || XMLUtil::StringEqual( value,
element->Value() ))) {
796 p = _document->Identify(
p, &
node );
797 if (
p == 0 ||
node == 0 ) {
802 p = node->ParseDeep( p, &endTag );
806 if ( !_document->
Error() ) {
807 _document->SetError( XML_ERROR_PARSING, 0, 0 );
815 *parentEnd =
static_cast<XMLElement*
>(node)->_value;
825 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
826 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->
Value(), 0 );
829 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
830 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->
Value(), 0 );
833 else if ( !endTag.Empty() ) {
834 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->
Value() )) {
835 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->
Value(), 0 );
852char* XMLText::ParseDeep(
char* p, StrPair* )
854 const char* start = p;
855 if ( this->
CData() ) {
856 p = _value.ParseText( p,
"]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
858 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
863 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
864 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
865 flags |= StrPair::COLLAPSE_WHITESPACE;
868 p = _value.ParseText( p,
"<", flags );
870 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
893 return (
compare->ToText() && XMLUtil::StringEqual(
compare->ToText()->Value(),
Value() ));
899 return visitor->Visit( *
this );
910XMLComment::~XMLComment()
915char* XMLComment::ParseDeep(
char* p, StrPair* )
918 const char* start = p;
919 p = _value.ParseText( p,
"-->", StrPair::COMMENT );
921 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
939 return (
compare->ToComment() && XMLUtil::StringEqual(
compare->ToComment()->Value(),
Value() ));
945 return visitor->Visit( *
this );
956XMLDeclaration::~XMLDeclaration()
962char* XMLDeclaration::ParseDeep(
char* p, StrPair* )
965 const char* start = p;
966 p = _value.ParseText( p,
"?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
968 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
986 return (
compare->ToDeclaration() && XMLUtil::StringEqual(
compare->ToDeclaration()->Value(),
Value() ));
993 return visitor->Visit( *
this );
1003XMLUnknown::~XMLUnknown()
1008char* XMLUnknown::ParseDeep(
char* p, StrPair* )
1011 const char* start = p;
1013 p = _value.ParseText( p,
">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
1015 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
1033 return (
compare->ToUnknown() && XMLUtil::StringEqual(
compare->ToUnknown()->Value(),
Value() ));
1039 return visitor->Visit( *
this );
1046 p = _name.ParseName(
p );
1052 p = XMLUtil::SkipWhiteSpace( p );
1053 if ( !p || *p !=
'=' ) {
1058 p = XMLUtil::SkipWhiteSpace( p );
1059 if ( *p !=
'\"' && *p !=
'\'' ) {
1063 char endTag[2] = { *p, 0 };
1066 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
1071void XMLAttribute::SetName(
const char* n )
1079 if ( XMLUtil::ToInt(
Value(), value )) {
1080 return XML_NO_ERROR;
1082 return XML_WRONG_ATTRIBUTE_TYPE;
1088 if ( XMLUtil::ToUnsigned(
Value(), value )) {
1089 return XML_NO_ERROR;
1091 return XML_WRONG_ATTRIBUTE_TYPE;
1097 if ( XMLUtil::ToBool(
Value(), value )) {
1098 return XML_NO_ERROR;
1100 return XML_WRONG_ATTRIBUTE_TYPE;
1106 if ( XMLUtil::ToFloat(
Value(), value )) {
1107 return XML_NO_ERROR;
1109 return XML_WRONG_ATTRIBUTE_TYPE;
1115 if ( XMLUtil::ToDouble(
Value(), value )) {
1116 return XML_NO_ERROR;
1118 return XML_WRONG_ATTRIBUTE_TYPE;
1131 XMLUtil::ToStr(
v,
buf, BUF_SIZE );
1132 _value.SetStr(
buf );
1139 XMLUtil::ToStr(
v,
buf, BUF_SIZE );
1140 _value.SetStr(
buf );
1147 XMLUtil::ToStr(
v,
buf, BUF_SIZE );
1148 _value.SetStr(
buf );
1154 XMLUtil::ToStr(
v,
buf, BUF_SIZE );
1155 _value.SetStr(
buf );
1161 XMLUtil::ToStr(
v,
buf, BUF_SIZE );
1162 _value.SetStr(
buf );
1174XMLElement::~XMLElement()
1176 while( _rootAttribute ) {
1177 XMLAttribute* next = _rootAttribute->_next;
1178 DELETE_ATTRIBUTE( _rootAttribute );
1179 _rootAttribute = next;
1186 XMLAttribute* a = 0;
1187 for( a=_rootAttribute; a; a = a->_next ) {
1188 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1199 for(
a=_rootAttribute;
a;
a =
a->_next ) {
1200 if ( XMLUtil::StringEqual(
a->Name(),
name ) ) {
1214 if ( !value || XMLUtil::StringEqual(
a->Value(), value )) {
1234 if ( XMLUtil::ToInt(
t, _value ) ) {
1237 return XML_CAN_NOT_CONVERT_TEXT;
1239 return XML_NO_TEXT_NODE;
1247 if ( XMLUtil::ToUnsigned(
t, _value ) ) {
1250 return XML_CAN_NOT_CONVERT_TEXT;
1252 return XML_NO_TEXT_NODE;
1260 if ( XMLUtil::ToBool(
t, _value ) ) {
1263 return XML_CAN_NOT_CONVERT_TEXT;
1265 return XML_NO_TEXT_NODE;
1273 if ( XMLUtil::ToDouble(
t, _value ) ) {
1276 return XML_CAN_NOT_CONVERT_TEXT;
1278 return XML_NO_TEXT_NODE;
1286 if ( XMLUtil::ToFloat(
t, _value ) ) {
1289 return XML_CAN_NOT_CONVERT_TEXT;
1291 return XML_NO_TEXT_NODE;
1300 for(
attrib = _rootAttribute;
1303 if ( XMLUtil::StringEqual(
attrib->Name(),
name ) ) {
1308 attrib =
new (_document->_attributePool.Alloc() ) XMLAttribute();
1309 attrib->_memPool = &_document->_attributePool;
1311 last->_next = attrib;
1314 _rootAttribute = attrib;
1316 attrib->SetName( name );
1326 if ( XMLUtil::StringEqual(
name,
a->Name() ) ) {
1328 prev->_next =
a->_next;
1331 _rootAttribute =
a->_next;
1333 DELETE_ATTRIBUTE(
a );
1341char* XMLElement::ParseAttributes(
char*
p )
1348 p = XMLUtil::SkipWhiteSpace(
p );
1349 if ( !
p || !(*
p) ) {
1350 _document->SetError( XML_ERROR_PARSING_ELEMENT,
start,
Name() );
1355 if ( XMLUtil::IsAlpha( *p ) ) {
1356 XMLAttribute* attrib =
new (_document->_attributePool.Alloc() ) XMLAttribute();
1357 attrib->_memPool = &_document->_attributePool;
1359 p = attrib->ParseDeep( p, _document->ProcessEntities() );
1360 if ( !p ||
Attribute( attrib->Name() ) ) {
1361 DELETE_ATTRIBUTE( attrib );
1362 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
1370 if ( prevAttribute ) {
1371 prevAttribute->_next = attrib;
1374 _rootAttribute = attrib;
1376 prevAttribute = attrib;
1379 else if ( *p ==
'/' && *(p+1) ==
'>' ) {
1380 _closingType = CLOSED;
1384 else if ( *p ==
'>' ) {
1389 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
1401char* XMLElement::ParseDeep(
char* p, StrPair* strPair )
1404 p = XMLUtil::SkipWhiteSpace( p );
1413 _closingType = CLOSING;
1417 p = _value.ParseName( p );
1418 if ( _value.Empty() ) {
1422 p = ParseAttributes( p );
1423 if ( !p || !*p || _closingType ) {
1427 p = XMLNode::ParseDeep( p, strPair );
1440 element->SetAttribute(
a->Name(),
a->Value() );
1455 if ( !XMLUtil::StringEqual(
a->Value(),
b->Value() ) ) {
1473 if (
visitor->VisitEnter( *
this, _rootAttribute ) ) {
1480 return visitor->VisitExit( *
this );
1489 _errorID( XML_NO_ERROR ),
1499XMLDocument::~XMLDocument()
1502 delete [] _charBuffer;
1511 TIXMLASSERT( _textPool.CurrentAllocs() == 0 );
1512 TIXMLASSERT( _elementPool.CurrentAllocs() == 0 );
1513 TIXMLASSERT( _commentPool.CurrentAllocs() == 0 );
1514 TIXMLASSERT( _attributePool.CurrentAllocs() == 0 );
1518void XMLDocument::InitDocument()
1520 _errorID = XML_NO_ERROR;
1524 delete [] _charBuffer;
1532 ele->_memPool = &_elementPool;
1541 comment->_memPool = &_commentPool;
1550 text->_memPool = &_textPool;
1559 dec->_memPool = &_commentPool;
1560 dec->SetValue(
str ?
str :
"xml version=\"1.0\" encoding=\"UTF-8\"" );
1568 unk->_memPool = &_commentPool;
1582#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1590 SetError( XML_ERROR_FILE_NOT_FOUND,
filename, 0 );
1612 _charBuffer =
new char[
size+1];
1615 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1619 _charBuffer[
size] = 0;
1621 const char*
p = _charBuffer;
1622 p = XMLUtil::SkipWhiteSpace(
p );
1623 p = XMLUtil::ReadBOM(
p, &_writeBOM );
1625 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1629 ParseDeep( _charBuffer + (
p-_charBuffer), 0 );
1637#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1644 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED,
filename, 0 );
1667 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1670 if (
len == (
size_t)(-1) ) {
1673 _charBuffer =
new char[
len+1 ];
1675 _charBuffer[
len] = 0;
1677 p = XMLUtil::SkipWhiteSpace(
p );
1678 p = XMLUtil::ReadBOM(
p, &_writeBOM );
1680 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1684 ParseDeep( _charBuffer, 0 );
1699void XMLDocument::SetError( XMLError
error,
const char*
str1,
const char*
str2 )
1710 static const int LEN = 20;
1715 TIXML_SNPRINTF(
buf1,
LEN,
"%s", _errorStr1 );
1718 TIXML_SNPRINTF(
buf2,
LEN,
"%s", _errorStr2 );
1721 printf(
"XMLDocument error id=%d str1=%s str2=%s\n",
1728 _elementJustOpened(
false ),
1729 _firstElement(
true ),
1733 _processEntities(
true ),
1736 for(
int i=0;
i<ENTITY_RANGE; ++
i ) {
1737 _entityFlag[
i] =
false;
1738 _restrictedEntityFlag[
i] =
false;
1740 for(
int i=0;
i<NUM_ENTITIES; ++
i ) {
1741 TIXMLASSERT( entities[
i].value < ENTITY_RANGE );
1742 if ( entities[
i].value < ENTITY_RANGE ) {
1743 _entityFlag[ (
int)entities[
i].value ] =
true;
1746 _restrictedEntityFlag[(
int)
'&'] =
true;
1747 _restrictedEntityFlag[(
int)
'<'] =
true;
1748 _restrictedEntityFlag[(
int)
'>'] =
true;
1753void XMLPrinter::Print(
const char*
format, ... )
1768 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
1771 _accumulator.PushArr( expand );
1774 char* p = _buffer.PushArr( len ) - 1;
1775 memcpy( p, _accumulator.Mem(), len+1 );
1777 int len = vsnprintf( 0, 0, format, va );
1780 va_start( va, format );
1781 char* p = _buffer.PushArr( len ) - 1;
1782 vsnprintf( p, len+1, format, va );
1789void XMLPrinter::PrintSpace(
int depth )
1791 for(
int i=0; i<depth; ++i ) {
1797void XMLPrinter::PrintString(
const char* p,
bool restricted )
1801 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
1803 if ( _processEntities ) {
1806 if ( *q > 0 && *q < ENTITY_RANGE ) {
1810 if ( flag[(
unsigned)(*q)] ) {
1815 for(
int i=0; i<NUM_ENTITIES; ++i ) {
1816 if ( entities[i].value == *q ) {
1817 Print(
"&%s;", entities[i].pattern );
1829 if ( !_processEntities || (q-p > 0) ) {
1837 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1842 PushDeclaration(
"xml version=\"1.0\"" );
1849 if ( _elementJustOpened ) {
1852 _stack.Push(
name );
1854 if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
1856 PrintSpace( _depth );
1859 Print(
"<%s",
name );
1860 _elementJustOpened =
true;
1861 _firstElement =
false;
1868 TIXMLASSERT( _elementJustOpened );
1869 Print(
" %s=\"",
name );
1870 PrintString( value,
false );
1878 XMLUtil::ToStr(
v,
buf, BUF_SIZE );
1886 XMLUtil::ToStr( v, buf, BUF_SIZE );
1894 XMLUtil::ToStr( v, buf, BUF_SIZE );
1902 XMLUtil::ToStr( v, buf, BUF_SIZE );
1910 const char*
name = _stack.Pop();
1912 if ( _elementJustOpened ) {
1916 if ( _textDepth < 0 && !_compactMode) {
1918 PrintSpace( _depth );
1920 Print(
"</%s>",
name );
1923 if ( _textDepth == _depth ) {
1926 if ( _depth == 0 && !_compactMode) {
1929 _elementJustOpened =
false;
1933void XMLPrinter::SealElement()
1935 _elementJustOpened =
false;
1942 _textDepth = _depth-1;
1944 if ( _elementJustOpened ) {
1948 Print(
"<![CDATA[" );
1949 Print(
"%s",
text );
1953 PrintString(
text,
true );
1960 XMLUtil::ToStr( value,
buf, BUF_SIZE );
1968 XMLUtil::ToStr( value,
buf, BUF_SIZE );
1976 XMLUtil::ToStr( value,
buf, BUF_SIZE );
1984 XMLUtil::ToStr( value,
buf, BUF_SIZE );
1992 XMLUtil::ToStr( value,
buf, BUF_SIZE );
1999 if ( _elementJustOpened ) {
2002 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
2004 PrintSpace( _depth );
2006 _firstElement =
false;
2007 Print(
"<!--%s-->",
comment );
2011void XMLPrinter::PushDeclaration(
const char* value )
2013 if ( _elementJustOpened ) {
2016 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
2018 PrintSpace( _depth );
2020 _firstElement =
false;
2021 Print(
"<?%s?>", value );
2025void XMLPrinter::PushUnknown(
const char* value )
2027 if ( _elementJustOpened ) {
2030 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
2032 PrintSpace( _depth );
2034 _firstElement =
false;
2035 Print(
"<!%s>", value );
2041 _processEntities =
doc.ProcessEntities();
2042 if (
doc.HasBOM() ) {
2089 PushUnknown(
unknown.Value() );
XMLError QueryFloatValue(float *value) const
See QueryIntAttribute.
XMLError QueryDoubleValue(double *value) const
See QueryIntAttribute.
void SetAttribute(const char *value)
Set the attribute to a string value.
XMLError QueryUnsignedValue(unsigned int *value) const
See QueryIntAttribute.
XMLError QueryBoolValue(bool *value) const
See QueryIntAttribute.
XMLError QueryIntValue(int *value) const
const char * Value() const
The value of the attribute.
virtual bool Accept(XMLVisitor *visitor) const
virtual XMLNode * ShallowClone(XMLDocument *document) const
virtual bool ShallowEqual(const XMLNode *compare) const
XMLError Parse(const char *xml, size_t nBytes=(size_t)(-1))
void PrintError() const
If there is an error, print it to stdout.
void Print(XMLPrinter *streamer=0)
XMLError LoadFile(const char *filename)
bool Error() const
Return true if there was an error parsing the document.
XMLComment * NewComment(const char *comment)
XMLElement * NewElement(const char *name)
XMLUnknown * NewUnknown(const char *text)
XMLError SaveFile(const char *filename, bool compact=false)
virtual bool Accept(XMLVisitor *visitor) const
XMLText * NewText(const char *text)
XMLDeclaration * NewDeclaration(const char *text=0)
XMLError QueryDoubleText(double *_value) const
See QueryIntText()
const char * GetText() const
const XMLAttribute * FindAttribute(const char *name) const
Query a specific attribute in the list.
XMLError QueryUnsignedText(unsigned *_value) const
See QueryIntText()
XMLError QueryFloatText(float *_value) const
See QueryIntText()
const char * Attribute(const char *name, const char *value=0) const
const XMLAttribute * FirstAttribute() const
Return the first attribute in the list.
XMLError QueryIntText(int *_value) const
virtual bool ShallowEqual(const XMLNode *compare) const
virtual bool Accept(XMLVisitor *visitor) const
XMLError QueryBoolText(bool *_value) const
See QueryIntText()
virtual XMLNode * ShallowClone(XMLDocument *document) const
const char * Name() const
Get the name of an element (which is the Value() of the node.)
void DeleteAttribute(const char *name)
const char * Value() const
void SetValue(const char *val, bool staticMem=false)
virtual XMLText * ToText()
Safely cast to Text, or null.
const XMLElement * LastChildElement(const char *value=0) const
void DeleteChild(XMLNode *node)
const XMLElement * NextSiblingElement(const char *value=0) const
Get the next (right) sibling element of this node, with an opitionally supplied name.
const XMLElement * FirstChildElement(const char *value=0) const
XMLNode * InsertAfterChild(XMLNode *afterThis, XMLNode *addThis)
virtual XMLElement * ToElement()
Safely cast to an Element, or null.
const XMLElement * PreviousSiblingElement(const char *value=0) const
Get the previous (left) sibling element of this node, with an opitionally supplied name.
const XMLNode * FirstChild() const
Get the first child node, or null if none exists.
XMLNode * InsertFirstChild(XMLNode *addThis)
XMLNode * InsertEndChild(XMLNode *addThis)
virtual bool VisitExit(const XMLDocument &)
Visit a document.
void PushHeader(bool writeBOM, bool writeDeclaration)
void PushText(const char *text, bool cdata=false)
Add a text node.
void PushAttribute(const char *name, const char *value)
If streaming, add an attribute to an open element.
virtual bool VisitEnter(const XMLDocument &)
Visit a document.
void OpenElement(const char *name)
XMLPrinter(std::FILE *file=0, bool compact=false)
virtual bool Visit(const XMLText &text)
Visit a text node.
void CloseElement()
If streaming, close the Element.
void PushComment(const char *comment)
Add a comment.
virtual bool Accept(XMLVisitor *visitor) const
virtual XMLNode * ShallowClone(XMLDocument *document) const
virtual bool ShallowEqual(const XMLNode *compare) const
bool CData() const
Returns true if this is a CDATA text element.
virtual bool Accept(XMLVisitor *visitor) const
virtual XMLNode * ShallowClone(XMLDocument *document) const
virtual bool ShallowEqual(const XMLNode *compare) const