int example_3() { static const char* xml = "<?xml version=\"1.0\"?>" "<!DOCTYPE PLAY SYSTEM \"play.dtd\">" "<PLAY>" "<TITLE>A Midsummer Night's Dream</TITLE>" "</PLAY>"; XMLDocument doc; doc.Parse( xml ); XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" ); const char* title = titleElement->GetText(); printf( "Name of play (1): %s\n", title ); XMLText* textNode = titleElement->FirstChild()->ToText(); title = textNode->Value(); printf( "Name of play (2): %s\n", title ); return doc.ErrorID(); }
void COLLADAImporter::LoadFloatArrays(XMLElement *geometryNode, boost::unordered_map<std::string, std::vector<float> >& map) { std::vector<XMLElement *> geometries = XMLHelper::GetChildElements(geometryNode,"geometry"); std::vector<XMLElement *> meshes; for(std::vector<XMLElement *>::const_iterator it = geometries.begin(); it != geometries.end(); it++) { XMLElement *mesh; if((mesh = XMLHelper::GetChildElement(*it,"mesh")) != NULL) { meshes.push_back(mesh); } } std::string id; for(std::vector<XMLElement *>::const_iterator mit = meshes.begin(); mit != meshes.end(); mit++){ std::vector<XMLElement *> sources = XMLHelper::GetChildElements(*mit,"source"); for(std::vector<XMLElement *>::const_iterator it = sources.begin(); it != sources.end(); it++) { XMLElement *float_array = XMLHelper::GetChildElement(*it,"float_array"); if(float_array != NULL) { if(XMLHelper::GetElementAttribute(float_array,"id",id)) { XMLText *innerText = float_array->FirstChild()->ToText(); std::string farray(innerText->Value()); std::vector<float> fvalues; //fvalues = StringHelper::ConvertStringToFloatArray(farray); fvalues = StringHelper::ConvertStringToTArray<float>(farray); int arraycount; if(!StringHelper::from_string<int>(arraycount,float_array->Attribute("count"))) { continue; } while(fvalues.size() < arraycount) { fvalues.push_back(0.0f); } map[id] = fvalues; } } } } }
int main() { XMLDocument doc; //bii://examples/tinyxml2/dream.xml doc.LoadFile( "examples/tinyxml2/dream.xml" ); // Structure of the XML file: // - Element "PLAY" the root Element, which is the // FirstChildElement of the Document // - - Element "TITLE" child of the root PLAY Element // - - - Text child of the TITLE Element // Navigate to the title, using the convenience function, // with a dangerous lack of error checking. const char* title = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" )->GetText(); printf( "Name of play (1): %s\n", title ); // Text is just another Node to TinyXML-2. The more // general way to get to the XMLText: XMLText* textNode = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" )->FirstChild()->ToText(); title = textNode->Value(); printf( "Name of play (2): %s\n", title ); }
bool TextVisitor::Visit(const XMLText& text) { std::string t = " "; t = text.Value(); // break text strings into 57 character lengths to fit on the screen. for (unsigned int i = 0; i < t.length(); i += 57) { bookText.push_back(t.substr(i, 57)); } return true; }
char* XMLDocument::Identify( char* p, XMLNode** node ) { XMLNode* returnNode = 0; char* start = p; p = XMLUtil::SkipWhiteSpace( p ); if( !p || !*p ) { return p; } // What is this thing? // - Elements start with a letter or underscore, but xml is reserved. // - Comments: <!-- // - Declaration: <? // - Everything else is unknown to tinyxml. // static const char* xmlHeader = { "<?" }; static const char* commentHeader = { "<!--" }; static const char* dtdHeader = { "<!" }; static const char* cdataHeader = { "<![CDATA[" }; static const char* elementHeader = { "<" }; // and a header for everything else; check last. static const int xmlHeaderLen = 2; static const int commentHeaderLen = 4; static const int dtdHeaderLen = 2; static const int cdataHeaderLen = 9; static const int elementHeaderLen = 1; #if defined(_MSC_VER) #pragma warning ( push ) #pragma warning ( disable : 4127 ) #endif TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool #if defined(_MSC_VER) #pragma warning (pop) #endif if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) { returnNode = new (_commentPool.Alloc()) XMLDeclaration( this ); returnNode->_memPool = &_commentPool; p += xmlHeaderLen; } else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { returnNode = new (_commentPool.Alloc()) XMLComment( this ); returnNode->_memPool = &_commentPool; p += commentHeaderLen; } else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) { XMLText* text = new (_textPool.Alloc()) XMLText( this ); returnNode = text; returnNode->_memPool = &_textPool; p += cdataHeaderLen; text->SetCData( true ); } else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { returnNode = new (_commentPool.Alloc()) XMLUnknown( this ); returnNode->_memPool = &_commentPool; p += dtdHeaderLen; } else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { returnNode = new (_elementPool.Alloc()) XMLElement( this ); returnNode->_memPool = &_elementPool; p += elementHeaderLen; } else { returnNode = new (_textPool.Alloc()) XMLText( this ); returnNode->_memPool = &_textPool; p = start; // Back it up, all the text counts. } *node = returnNode; return p; }
bool XMLPrinter::Visit( const XMLText& text ) { PushText( text.Value(), text.CData() ); return true; }
int main( int argc, const char ** argv ) { #if defined( _MSC_VER ) && defined( DEBUG ) _CrtMemCheckpoint( &startMemState ); #endif #if defined(_MSC_VER) || defined(MINGW32) || defined(__MINGW32__) #if defined __MINGW64_VERSION_MAJOR && defined __MINGW64_VERSION_MINOR //MINGW64: both 32 and 64-bit mkdir( "resources/out/" ); #else _mkdir( "resources/out/" ); #endif #else mkdir( "resources/out/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); #endif if ( argc > 1 ) { XMLDocument* doc = new XMLDocument(); clock_t startTime = clock(); doc->LoadFile( argv[1] ); clock_t loadTime = clock(); int errorID = doc->ErrorID(); delete doc; doc = 0; clock_t deleteTime = clock(); printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID ); if ( !errorID ) { printf( "Load time=%u\n", (unsigned)(loadTime - startTime) ); printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) ); printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) ); } exit(0); } FILE* fp = fopen( "resources/dream.xml", "r" ); if ( !fp ) { printf( "Error opening test file 'dream.xml'.\n" "Is your working directory the same as where \n" "the xmltest.cpp and dream.xml file are?\n\n" #if defined( _MSC_VER ) "In windows Visual Studio you may need to set\n" "Properties->Debugging->Working Directory to '..'\n" #endif ); exit( 1 ); } fclose( fp ); XMLTest( "Example-1", 0, example_1() ); XMLTest( "Example-2", 0, example_2() ); XMLTest( "Example-3", 0, example_3() ); XMLTest( "Example-4", true, example_4() ); /* ------ Example 2: Lookup information. ---- */ { static const char* test[] = { "<element />", "<element></element>", "<element><subelement/></element>", "<element><subelement></subelement></element>", "<element><subelement><subsub/></subelement></element>", "<!--comment beside elements--><element><subelement></subelement></element>", "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>", "<element attrib1='foo' attrib2=\"bar\" ></element>", "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>", "<element>Text inside element.</element>", "<element><b></b></element>", "<element>Text inside and <b>bolded</b> in the element.</element>", "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>", "<element>This & That.</element>", "<element attrib='This<That' />", 0 }; for( int i=0; test[i]; ++i ) { XMLDocument doc; doc.Parse( test[i] ); doc.Print(); printf( "----------------------------------------------\n" ); } } #if 1 { static const char* test = "<!--hello world\n" " line 2\r" " line 3\r\n" " line 4\n\r" " line 5\r-->"; XMLDocument doc; doc.Parse( test ); doc.Print(); } { static const char* test = "<element>Text before.</element>"; XMLDocument doc; doc.Parse( test ); XMLElement* root = doc.FirstChildElement(); XMLElement* newElement = doc.NewElement( "Subelement" ); root->InsertEndChild( newElement ); doc.Print(); } { XMLDocument* doc = new XMLDocument(); static const char* test = "<element><sub/></element>"; doc->Parse( test ); delete doc; } { // Test: Programmatic DOM // Build: // <element> // <!--comment--> // <sub attrib="1" /> // <sub attrib="2" /> // <sub attrib="3" >& Text!</sub> // <element> XMLDocument* doc = new XMLDocument(); XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) ); XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) }; for( int i=0; i<3; ++i ) { sub[i]->SetAttribute( "attrib", i ); } element->InsertEndChild( sub[2] ); XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) ); element->InsertAfterChild( comment, sub[0] ); element->InsertAfterChild( sub[0], sub[1] ); sub[2]->InsertFirstChild( doc->NewText( "& Text!" )); doc->Print(); XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() ); XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) ); XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) ); XMLTest( "Programmatic DOM", "& Text!", doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() ); // And now deletion: element->DeleteChild( sub[2] ); doc->DeleteNode( comment ); element->FirstChildElement()->SetAttribute( "attrib", true ); element->LastChildElement()->DeleteAttribute( "attrib" ); XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) ); int value = 10; int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value ); XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE ); XMLTest( "Programmatic DOM", value, 10 ); doc->Print(); { XMLPrinter streamer; doc->Print( &streamer ); printf( "%s", streamer.CStr() ); } { XMLPrinter streamer( 0, true ); doc->Print( &streamer ); XMLTest( "Compact mode", "<element><sub attrib=\"1\"/><sub/></element>", streamer.CStr(), false ); } doc->SaveFile( "./resources/out/pretty.xml" ); doc->SaveFile( "./resources/out/compact.xml", true ); delete doc; } { // Test: Dream // XML1 : 1,187,569 bytes in 31,209 allocations // XML2 : 469,073 bytes in 323 allocations //int newStart = gNew; XMLDocument doc; doc.LoadFile( "resources/dream.xml" ); doc.SaveFile( "resources/out/dreamout.xml" ); doc.PrintError(); XMLTest( "Dream", "xml version=\"1.0\"", doc.FirstChild()->ToDeclaration()->Value() ); XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false ); XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"", doc.FirstChild()->NextSibling()->ToUnknown()->Value() ); XMLTest( "Dream", "And Robin shall restore amends.", doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() ); XMLTest( "Dream", "And Robin shall restore amends.", doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() ); XMLDocument doc2; doc2.LoadFile( "resources/out/dreamout.xml" ); XMLTest( "Dream-out", "xml version=\"1.0\"", doc2.FirstChild()->ToDeclaration()->Value() ); XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false ); XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"", doc2.FirstChild()->NextSibling()->ToUnknown()->Value() ); XMLTest( "Dream-out", "And Robin shall restore amends.", doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() ); //gNewTotal = gNew - newStart; } { const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n" "<passages count=\"006\" formatversion=\"20020620\">\n" " <wrong error>\n" "</passages>"; XMLDocument doc; doc.Parse( error ); XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE ); } { const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />"; XMLDocument doc; doc.Parse( str ); XMLElement* ele = doc.FirstChildElement(); int iVal, result; double dVal; result = ele->QueryDoubleAttribute( "attr0", &dVal ); XMLTest( "Query attribute: int as double", result, (int)XML_NO_ERROR ); XMLTest( "Query attribute: int as double", (int)dVal, 1 ); result = ele->QueryDoubleAttribute( "attr1", &dVal ); XMLTest( "Query attribute: double as double", result, (int)XML_NO_ERROR ); XMLTest( "Query attribute: double as double", (int)dVal, 2 ); result = ele->QueryIntAttribute( "attr1", &iVal ); XMLTest( "Query attribute: double as int", result, (int)XML_NO_ERROR ); XMLTest( "Query attribute: double as int", iVal, 2 ); result = ele->QueryIntAttribute( "attr2", &iVal ); XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE ); result = ele->QueryIntAttribute( "bar", &iVal ); XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE ); } { const char* str = "<doc/>"; XMLDocument doc; doc.Parse( str ); XMLElement* ele = doc.FirstChildElement(); int iVal, iVal2; double dVal, dVal2; ele->SetAttribute( "str", "strValue" ); ele->SetAttribute( "int", 1 ); ele->SetAttribute( "double", -1.0 ); const char* cStr = ele->Attribute( "str" ); ele->QueryIntAttribute( "int", &iVal ); ele->QueryDoubleAttribute( "double", &dVal ); ele->QueryAttribute( "int", &iVal2 ); ele->QueryAttribute( "double", &dVal2 ); XMLTest( "Attribute match test", ele->Attribute( "str", "strValue" ), "strValue" ); XMLTest( "Attribute round trip. c-string.", "strValue", cStr ); XMLTest( "Attribute round trip. int.", 1, iVal ); XMLTest( "Attribute round trip. double.", -1, (int)dVal ); XMLTest( "Alternate query", true, iVal == iVal2 ); XMLTest( "Alternate query", true, dVal == dVal2 ); } { XMLDocument doc; doc.LoadFile( "resources/utf8test.xml" ); // Get the attribute "value" from the "Russian" element and check it. XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" ); const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU, 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 }; XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) ); const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U, 0xd1U, 0x81U, 0xd1U, 0x81U, 0xd0U, 0xbaU, 0xd0U, 0xb8U, 0xd0U, 0xb9U, 0 }; const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>"; XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText(); XMLTest( "UTF-8: Browsing russian element name.", russianText, text->Value() ); // Now try for a round trip. doc.SaveFile( "resources/out/utf8testout.xml" ); // Check the round trip. int okay = 0; FILE* saved = fopen( "resources/out/utf8testout.xml", "r" ); FILE* verify = fopen( "resources/utf8testverify.xml", "r" ); if ( saved && verify ) { okay = 1; char verifyBuf[256]; while ( fgets( verifyBuf, 256, verify ) ) { char savedBuf[256]; fgets( savedBuf, 256, saved ); NullLineEndings( verifyBuf ); NullLineEndings( savedBuf ); if ( strcmp( verifyBuf, savedBuf ) ) { printf( "verify:%s<\n", verifyBuf ); printf( "saved :%s<\n", savedBuf ); okay = 0; break; } } } if ( saved ) fclose( saved ); if ( verify ) fclose( verify ); XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay ); } // --------GetText()----------- { const char* str = "<foo>This is text</foo>"; XMLDocument doc; doc.Parse( str ); const XMLElement* element = doc.RootElement(); XMLTest( "GetText() normal use.", "This is text", element->GetText() ); str = "<foo><b>This is text</b></foo>"; doc.Parse( str ); element = doc.RootElement(); XMLTest( "GetText() contained element.", element->GetText() == 0, true ); } // ---------- CDATA --------------- { const char* str = "<xmlElement>" "<![CDATA[" "I am > the rules!\n" "...since I make symbolic puns" "]]>" "</xmlElement>"; XMLDocument doc; doc.Parse( str ); doc.Print(); XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(), "I am > the rules!\n...since I make symbolic puns", false ); } // ----------- CDATA ------------- { const char* str = "<xmlElement>" "<![CDATA[" "<b>I am > the rules!</b>\n" "...since I make symbolic puns" "]]>" "</xmlElement>"; XMLDocument doc; doc.Parse( str ); doc.Print(); XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(), "<b>I am > the rules!</b>\n...since I make symbolic puns", false ); } // InsertAfterChild causes crash. { // InsertBeforeChild and InsertAfterChild causes crash. XMLDocument doc; XMLElement* parent = doc.NewElement( "Parent" ); doc.InsertFirstChild( parent ); XMLElement* childText0 = doc.NewElement( "childText0" ); XMLElement* childText1 = doc.NewElement( "childText1" ); XMLNode* childNode0 = parent->InsertEndChild( childText0 ); XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 ); XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true ); } { // Entities not being written correctly. // From Lynn Allen const char* passages = "<?xml version=\"1.0\" standalone=\"no\" ?>" "<passages count=\"006\" formatversion=\"20020620\">" "<psg context=\"Line 5 has "quotation marks" and 'apostrophe marks'." " It also has <, >, and &, as well as a fake copyright ©.\"> </psg>" "</passages>"; XMLDocument doc; doc.Parse( passages ); XMLElement* psg = doc.RootElement()->FirstChildElement(); const char* context = psg->Attribute( "context" ); const char* expected = "Line 5 has \"quotation marks\" and 'apostrophe marks'. It also has <, >, and &, as well as a fake copyright \xC2\xA9."; XMLTest( "Entity transformation: read. ", expected, context, true ); FILE* textfile = fopen( "resources/out/textfile.txt", "w" ); if ( textfile ) { XMLPrinter streamer( textfile ); psg->Accept( &streamer ); fclose( textfile ); } textfile = fopen( "resources/out/textfile.txt", "r" ); TIXMLASSERT( textfile ); if ( textfile ) { char buf[ 1024 ]; fgets( buf, 1024, textfile ); XMLTest( "Entity transformation: write. ", "<psg context=\"Line 5 has "quotation marks" and 'apostrophe marks'." " It also has <, >, and &, as well as a fake copyright \xC2\xA9.\"/>\n", buf, false ); fclose( textfile ); } } { // Suppress entities. const char* passages = "<?xml version=\"1.0\" standalone=\"no\" ?>" "<passages count=\"006\" formatversion=\"20020620\">" "<psg context=\"Line 5 has "quotation marks" and 'apostrophe marks'.\">Crazy &ttk;</psg>" "</passages>"; XMLDocument doc( false ); doc.Parse( passages ); XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ), "Line 5 has "quotation marks" and 'apostrophe marks'." ); XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(), "Crazy &ttk;" ); doc.Print(); } { const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>"; XMLDocument doc; doc.Parse( test ); XMLTest( "dot in names", doc.Error(), false ); XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" ); XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" ); } { const char* test = "<element><Name>1.1 Start easy ignore fin thickness
</Name></element>"; XMLDocument doc; doc.Parse( test ); XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText(); XMLTest( "Entity with one digit.", text->Value(), "1.1 Start easy ignore fin thickness\n", false ); } { // DOCTYPE not preserved (950171) // const char* doctype = "<?xml version=\"1.0\" ?>" "<!DOCTYPE PLAY SYSTEM 'play.dtd'>" "<!ELEMENT title (#PCDATA)>" "<!ELEMENT books (title,authors)>" "<element />"; XMLDocument doc; doc.Parse( doctype ); doc.SaveFile( "resources/out/test7.xml" ); doc.DeleteChild( doc.RootElement() ); doc.LoadFile( "resources/out/test7.xml" ); doc.Print(); const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown(); XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() ); } { // Comments do not stream out correctly. const char* doctype = "<!-- Somewhat<evil> -->"; XMLDocument doc; doc.Parse( doctype ); XMLComment* comment = doc.FirstChild()->ToComment(); XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() ); } { // Double attributes const char* doctype = "<element attr='red' attr='blue' />"; XMLDocument doc; doc.Parse( doctype ); XMLTest( "Parsing repeated attributes.", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() ); // is an error to tinyxml (didn't use to be, but caused issues) doc.PrintError(); } { // Embedded null in stream. const char* doctype = "<element att\0r='red' attr='blue' />"; XMLDocument doc; doc.Parse( doctype ); XMLTest( "Embedded null throws error.", true, doc.Error() ); } { // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717 const char* str = " "; XMLDocument doc; doc.Parse( str ); XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() ); } { // Low entities XMLDocument doc; doc.Parse( "<test></test>" ); const char result[] = { 0x0e, 0 }; XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result ); doc.Print(); } { // Attribute values with trailing quotes not handled correctly XMLDocument doc; doc.Parse( "<foo attribute=bar\" />" ); XMLTest( "Throw error with bad end quotes.", doc.Error(), true ); } { // [ 1663758 ] Failure to report error on bad XML XMLDocument xml; xml.Parse("<x>"); XMLTest("Missing end tag at end of input", xml.Error(), true); xml.Parse("<x> "); XMLTest("Missing end tag with trailing whitespace", xml.Error(), true); xml.Parse("<x></y>"); XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT); } { // [ 1475201 ] TinyXML parses entities in comments XMLDocument xml; xml.Parse("<!-- declarations for <head> & <body> -->" "<!-- far & away -->" ); XMLNode* e0 = xml.FirstChild(); XMLNode* e1 = e0->NextSibling(); XMLComment* c0 = e0->ToComment(); XMLComment* c1 = e1->ToComment(); XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true ); XMLTest( "Comments ignore entities.", " far & away ", c1->Value(), true ); } { XMLDocument xml; xml.Parse( "<Parent>" "<child1 att=''/>" "<!-- With this comment, child2 will not be parsed! -->" "<child2 att=''/>" "</Parent>" ); xml.Print(); int count = 0; for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild(); ele; ele = ele->NextSibling() ) { ++count; } XMLTest( "Comments iterate correctly.", 3, count ); } { // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well. unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl"; buf[60] = 239; buf[61] = 0; XMLDocument doc; doc.Parse( (const char*)buf); } { // bug 1827248 Error while parsing a little bit malformed file // Actually not malformed - should work. XMLDocument xml; xml.Parse( "<attributelist> </attributelist >" ); XMLTest( "Handle end tag whitespace", false, xml.Error() ); } { // This one must not result in an infinite loop XMLDocument xml; xml.Parse( "<infinite>loop" ); XMLTest( "Infinite loop test.", true, true ); } #endif { const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>"; XMLDocument doc; doc.Parse( pub ); XMLDocument clone; for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) { XMLNode* copy = node->ShallowClone( &clone ); clone.InsertEndChild( copy ); } clone.Print(); int count=0; const XMLNode* a=clone.FirstChild(); const XMLNode* b=doc.FirstChild(); for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) { ++count; XMLTest( "Clone and Equal", true, a->ShallowEqual( b )); } XMLTest( "Clone and Equal", 4, count ); } { // This shouldn't crash. XMLDocument doc; if(XML_NO_ERROR != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" )) { doc.PrintError(); } XMLTest( "Error in snprinf handling.", true, doc.Error() ); } { // Attribute ordering. static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />"; XMLDocument doc; doc.Parse( xml ); XMLElement* ele = doc.FirstChildElement(); const XMLAttribute* a = ele->FirstAttribute(); XMLTest( "Attribute order", "1", a->Value() ); a = a->Next(); XMLTest( "Attribute order", "2", a->Value() ); a = a->Next(); XMLTest( "Attribute order", "3", a->Value() ); XMLTest( "Attribute order", "attrib3", a->Name() ); ele->DeleteAttribute( "attrib2" ); a = ele->FirstAttribute(); XMLTest( "Attribute order", "1", a->Value() ); a = a->Next(); XMLTest( "Attribute order", "3", a->Value() ); ele->DeleteAttribute( "attrib1" ); ele->DeleteAttribute( "attrib3" ); XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false ); } { // Make sure an attribute with a space in it succeeds. static const char* xml0 = "<element attribute1= \"Test Attribute\"/>"; static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>"; static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>"; XMLDocument doc0; doc0.Parse( xml0 ); XMLDocument doc1; doc1.Parse( xml1 ); XMLDocument doc2; doc2.Parse( xml2 ); XMLElement* ele = 0; ele = doc0.FirstChildElement(); XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) ); ele = doc1.FirstChildElement(); XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) ); ele = doc2.FirstChildElement(); XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) ); } { // Make sure we don't go into an infinite loop. static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>"; XMLDocument doc; doc.Parse( xml ); XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement(); XMLElement* ele1 = ele0->NextSiblingElement(); bool equal = ele0->ShallowEqual( ele1 ); XMLTest( "Infinite loop in shallow equal.", true, equal ); } // -------- Handles ------------ { static const char* xml = "<element attrib='bar'><sub>Text</sub></element>"; XMLDocument doc; doc.Parse( xml ); XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement(); XMLTest( "Handle, success, mutable", ele->Value(), "sub" ); XMLHandle docH( doc ); ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement(); XMLTest( "Handle, dne, mutable", false, ele != 0 ); } { static const char* xml = "<element attrib='bar'><sub>Text</sub></element>"; XMLDocument doc; doc.Parse( xml ); XMLConstHandle docH( doc ); const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement(); XMLTest( "Handle, success, const", ele->Value(), "sub" ); ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement(); XMLTest( "Handle, dne, const", false, ele != 0 ); } { // Default Declaration & BOM XMLDocument doc; doc.InsertEndChild( doc.NewDeclaration() ); doc.SetBOM( true ); XMLPrinter printer; doc.Print( &printer ); static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; XMLTest( "BOM and default declaration", printer.CStr(), result, false ); XMLTest( "CStrSize", printer.CStrSize(), 42, false ); } { const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>"; XMLDocument doc; doc.Parse( xml ); XMLTest( "Ill formed XML", true, doc.Error() ); } // QueryXYZText { const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>"; XMLDocument doc; doc.Parse( xml ); const XMLElement* pointElement = doc.RootElement(); int intValue = 0; unsigned unsignedValue = 0; float floatValue = 0; double doubleValue = 0; bool boolValue = false; pointElement->FirstChildElement( "y" )->QueryIntText( &intValue ); pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue ); pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue ); pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue ); pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue ); XMLTest( "QueryIntText", intValue, 1, false ); XMLTest( "QueryUnsignedText", unsignedValue, (unsigned)1, false ); XMLTest( "QueryFloatText", floatValue, 1.2f, false ); XMLTest( "QueryDoubleText", doubleValue, 1.2, false ); XMLTest( "QueryBoolText", boolValue, true, false ); } { const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>"; XMLDocument doc; doc.Parse( xml ); XMLTest( "Non-alpha element lead letter parses.", doc.Error(), false ); } { const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>"; XMLDocument doc; doc.Parse( xml ); XMLTest("Non-alpha attribute lead character parses.", doc.Error(), false); } { const char* xml = "<3lement></3lement>"; XMLDocument doc; doc.Parse( xml ); XMLTest("Element names with lead digit fail to parse.", doc.Error(), true); } { const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE"; XMLDocument doc; doc.Parse( xml, 10 ); XMLTest( "Set length of incoming data", doc.Error(), false ); } { XMLDocument doc; doc.LoadFile( "resources/dream.xml" ); doc.Clear(); XMLTest( "Document Clear()'s", doc.NoChildren(), true ); } // ----------- Whitespace ------------ { const char* xml = "<element>" "<a> This \nis ' text ' </a>" "<b> This is ' text ' \n</b>" "<c>This is ' \n\n text '</c>" "</element>"; XMLDocument doc( true, COLLAPSE_WHITESPACE ); doc.Parse( xml ); const XMLElement* element = doc.FirstChildElement(); for( const XMLElement* parent = element->FirstChildElement(); parent; parent = parent->NextSiblingElement() ) { XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() ); } } #if 0 { // Passes if assert doesn't fire. XMLDocument xmlDoc; xmlDoc.NewDeclaration(); xmlDoc.NewComment("Configuration file"); XMLElement *root = xmlDoc.NewElement("settings"); root->SetAttribute("version", 2); } #endif { const char* xml = "<element> </element>"; XMLDocument doc( true, COLLAPSE_WHITESPACE ); doc.Parse( xml ); XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() ); } #if 0 // the question being explored is what kind of print to use: // https://github.com/leethomason/tinyxml2/issues/63 { const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9'/>"; XMLDocument doc; doc.Parse( xml ); doc.FirstChildElement()->SetAttribute( "attrA", 123456789.123456789 ); doc.FirstChildElement()->SetAttribute( "attrB", 1.001e9 ); doc.Print(); } #endif { // An assert should not fire. const char* xml = "<element/>"; XMLDocument doc; doc.Parse( xml ); XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope. XMLTest( "Tracking unused elements", true, ele != 0, false ); } { const char* xml = "<parent><child>abc</child></parent>"; XMLDocument doc; doc.Parse( xml ); XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child"); XMLPrinter printer; ele->Accept( &printer ); XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false ); } { XMLDocument doc; XMLError error = doc.LoadFile( "resources/empty.xml" ); XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error ); } { // BOM preservation static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n"; { XMLDocument doc; XMLTest( "BOM preservation (parse)", XML_NO_ERROR, doc.Parse( xml_bom_preservation ), false ); XMLPrinter printer; doc.Print( &printer ); XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true ); doc.SaveFile( "resources/bomtest.xml" ); } { XMLDocument doc; doc.LoadFile( "resources/bomtest.xml" ); XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false ); XMLPrinter printer; doc.Print( &printer ); XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true ); } } { // Insertion with Removal const char* xml = "<?xml version=\"1.0\" ?>" "<root>" "<one>" "<subtree>" "<elem>element 1</elem>text<!-- comment -->" "</subtree>" "</one>" "<two/>" "</root>"; const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>" "<root>" "<one/>" "<two>" "<subtree>" "<elem>element 1</elem>text<!-- comment -->" "</subtree>" "</two>" "</root>"; const char* xmlAfterOne = "<?xml version=\"1.0\" ?>" "<root>" "<one/>" "<subtree>" "<elem>element 1</elem>text<!-- comment -->" "</subtree>" "<two/>" "</root>"; const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>" "<root>" "<one/>" "<two/>" "<subtree>" "<elem>element 1</elem>text<!-- comment -->" "</subtree>" "</root>"; XMLDocument doc; doc.Parse( xml ); XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree"); XMLElement* two = doc.RootElement()->FirstChildElement("two"); two->InsertFirstChild(subtree); XMLPrinter printer1( 0, true ); doc.Accept( &printer1 ); XMLTest( "Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr()); doc.Parse( xml ); subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree"); two = doc.RootElement()->FirstChildElement("two"); doc.RootElement()->InsertAfterChild(two, subtree); XMLPrinter printer2( 0, true ); doc.Accept( &printer2 ); XMLTest( "Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false ); doc.Parse( xml ); XMLNode* one = doc.RootElement()->FirstChildElement("one"); subtree = one->FirstChildElement("subtree"); doc.RootElement()->InsertAfterChild(one, subtree); XMLPrinter printer3( 0, true ); doc.Accept( &printer3 ); XMLTest( "Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false ); doc.Parse( xml ); subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree"); two = doc.RootElement()->FirstChildElement("two"); doc.RootElement()->InsertEndChild(subtree); XMLPrinter printer4( 0, true ); doc.Accept( &printer4 ); XMLTest( "Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false ); } // ----------- Performance tracking -------------- { #if defined( _MSC_VER ) __int64 start, end, freq; QueryPerformanceFrequency( (LARGE_INTEGER*) &freq ); #endif FILE* fp = fopen( "resources/dream.xml", "r" ); fseek( fp, 0, SEEK_END ); long size = ftell( fp ); fseek( fp, 0, SEEK_SET ); char* mem = new char[size+1]; fread( mem, size, 1, fp ); fclose( fp ); mem[size] = 0; #if defined( _MSC_VER ) QueryPerformanceCounter( (LARGE_INTEGER*) &start ); #else clock_t cstart = clock(); #endif static const int COUNT = 10; for( int i=0; i<COUNT; ++i ) { XMLDocument doc; doc.Parse( mem ); } #if defined( _MSC_VER ) QueryPerformanceCounter( (LARGE_INTEGER*) &end ); #else clock_t cend = clock(); #endif delete [] mem; static const char* note = #ifdef DEBUG "DEBUG"; #else "Release"; #endif #if defined( _MSC_VER ) printf( "\nParsing %s of dream.xml: %.3f milli-seconds\n", note, 1000.0 * (double)(end-start) / ( (double)freq * (double)COUNT) ); #else printf( "\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart)/(double)COUNT ); #endif } #if defined( _MSC_VER ) && defined( DEBUG ) _CrtMemCheckpoint( &endMemState ); //_CrtMemDumpStatistics( &endMemState ); _CrtMemState diffMemState; _CrtMemDifference( &diffMemState, &startMemState, &endMemState ); _CrtMemDumpStatistics( &diffMemState ); //printf( "new total=%d\n", gNewTotal ); #endif printf ("\nPass %d, Fail %d\n", gPass, gFail); return gFail; }
int main( int /*argc*/, const char ** /*argv*/ ) { #if defined( _MSC_VER ) && defined( DEBUG ) _CrtMemCheckpoint( &startMemState ); #endif #if defined(_MSC_VER) #pragma warning ( push ) #pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated. #endif FILE* fp = fopen( "dream.xml", "r" ); if ( !fp ) { printf( "Error opening test file 'dream.xml'.\n" "Is your working directory the same as where \n" "the xmltest.cpp and dream.xml file are?\n\n" #if defined( _MSC_VER ) "In windows Visual Studio you may need to set\n" "Properties->Debugging->Working Directory to '..'\n" #endif ); exit( 1 ); } fclose( fp ); #if defined(_MSC_VER) #pragma warning ( pop ) #endif /* ------ Example 1: Load and parse an XML file. ---- */ { XMLDocument doc; doc.LoadFile( "dream.xml" ); } /* ------ Example 2: Lookup information. ---- */ { XMLDocument doc; doc.LoadFile( "dream.xml" ); // Structure of the XML file: // - Element "PLAY" the root Element // - - Element "TITLE" child of the root PLAY Element // - - - Text child of the TITLE Element // Navigate to the title, using the convenience function, with a dangerous lack of error checking. const char* title = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" )->GetText(); printf( "Name of play (1): %s\n", title ); // Text is just another Node to TinyXML-2. The more general way to get to the XMLText: XMLText* textNode = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" )->FirstChild()->ToText(); title = textNode->Value(); printf( "Name of play (2): %s\n", title ); } { static const char* test[] = { "<element />", "<element></element>", "<element><subelement/></element>", "<element><subelement></subelement></element>", "<element><subelement><subsub/></subelement></element>", "<!--comment beside elements--><element><subelement></subelement></element>", "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>", "<element attrib1='foo' attrib2=\"bar\" ></element>", "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>", "<element>Text inside element.</element>", "<element><b></b></element>", "<element>Text inside and <b>bolded</b> in the element.</element>", "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>", "<element>This & That.</element>", "<element attrib='This<That' />", 0 }; for( int i=0; test[i]; ++i ) { XMLDocument doc; doc.Parse( test[i] ); doc.Print(); printf( "----------------------------------------------\n" ); } } #if 1 { static const char* test = "<!--hello world\n" " line 2\r" " line 3\r\n" " line 4\n\r" " line 5\r-->"; XMLDocument doc; doc.Parse( test ); doc.Print(); } { static const char* test = "<element>Text before.</element>"; XMLDocument doc; doc.Parse( test ); XMLElement* root = doc.FirstChildElement(); XMLElement* newElement = doc.NewElement( "Subelement" ); root->InsertEndChild( newElement ); doc.Print(); } { XMLDocument* doc = new XMLDocument(); static const char* test = "<element><sub/></element>"; doc->Parse( test ); delete doc; } { // Test: Programmatic DOM // Build: // <element> // <!--comment--> // <sub attrib="1" /> // <sub attrib="2" /> // <sub attrib="3" >& Text!</sub> // <element> XMLDocument* doc = new XMLDocument(); XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) ); XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) }; for( int i=0; i<3; ++i ) { sub[i]->SetAttribute( "attrib", i ); } element->InsertEndChild( sub[2] ); XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) ); element->InsertAfterChild( comment, sub[0] ); element->InsertAfterChild( sub[0], sub[1] ); sub[2]->InsertFirstChild( doc->NewText( "& Text!" )); doc->Print(); XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() ); XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) ); XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) ); XMLTest( "Programmatic DOM", "& Text!", doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() ); // And now deletion: element->DeleteChild( sub[2] ); doc->DeleteNode( comment ); element->FirstChildElement()->SetAttribute( "attrib", true ); element->LastChildElement()->DeleteAttribute( "attrib" ); XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) ); int value = 10; int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value ); XMLTest( "Programmatic DOM", result, XML_NO_ATTRIBUTE ); XMLTest( "Programmatic DOM", value, 10 ); doc->Print(); XMLPrinter streamer; doc->Print( &streamer ); printf( "%s", streamer.CStr() ); delete doc; } { // Test: Dream // XML1 : 1,187,569 bytes in 31,209 allocations // XML2 : 469,073 bytes in 323 allocations //int newStart = gNew; XMLDocument doc; doc.LoadFile( "dream.xml" ); doc.SaveFile( "dreamout.xml" ); doc.PrintError(); XMLTest( "Dream", "xml version=\"1.0\"", doc.FirstChild()->ToDeclaration()->Value() ); XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false ); XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"", doc.FirstChild()->NextSibling()->ToUnknown()->Value() ); XMLTest( "Dream", "And Robin shall restore amends.", doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() ); XMLTest( "Dream", "And Robin shall restore amends.", doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() ); XMLDocument doc2; doc2.LoadFile( "dreamout.xml" ); XMLTest( "Dream-out", "xml version=\"1.0\"", doc2.FirstChild()->ToDeclaration()->Value() ); XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false ); XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"", doc2.FirstChild()->NextSibling()->ToUnknown()->Value() ); XMLTest( "Dream-out", "And Robin shall restore amends.", doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() ); //gNewTotal = gNew - newStart; } { const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n" "<passages count=\"006\" formatversion=\"20020620\">\n" " <wrong error>\n" "</passages>"; XMLDocument doc; doc.Parse( error ); XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE ); } { const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />"; XMLDocument doc; doc.Parse( str ); XMLElement* ele = doc.FirstChildElement(); int iVal, result; double dVal; result = ele->QueryDoubleAttribute( "attr0", &dVal ); XMLTest( "Query attribute: int as double", result, XML_NO_ERROR ); XMLTest( "Query attribute: int as double", (int)dVal, 1 ); result = ele->QueryDoubleAttribute( "attr1", &dVal ); XMLTest( "Query attribute: double as double", (int)dVal, 2 ); result = ele->QueryIntAttribute( "attr1", &iVal ); XMLTest( "Query attribute: double as int", result, XML_NO_ERROR ); XMLTest( "Query attribute: double as int", iVal, 2 ); result = ele->QueryIntAttribute( "attr2", &iVal ); XMLTest( "Query attribute: not a number", result, XML_WRONG_ATTRIBUTE_TYPE ); result = ele->QueryIntAttribute( "bar", &iVal ); XMLTest( "Query attribute: does not exist", result, XML_NO_ATTRIBUTE ); } { const char* str = "<doc/>"; XMLDocument doc; doc.Parse( str ); XMLElement* ele = doc.FirstChildElement(); int iVal; double dVal; ele->SetAttribute( "str", "strValue" ); ele->SetAttribute( "int", 1 ); ele->SetAttribute( "double", -1.0 ); const char* cStr = ele->Attribute( "str" ); ele->QueryIntAttribute( "int", &iVal ); ele->QueryDoubleAttribute( "double", &dVal ); XMLTest( "Attribute match test", ele->Attribute( "str", "strValue" ), "strValue" ); XMLTest( "Attribute round trip. c-string.", "strValue", cStr ); XMLTest( "Attribute round trip. int.", 1, iVal ); XMLTest( "Attribute round trip. double.", -1, (int)dVal ); } { XMLDocument doc; doc.LoadFile( "utf8test.xml" ); // Get the attribute "value" from the "Russian" element and check it. XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" ); const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU, 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 }; XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) ); const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U, 0xd1U, 0x81U, 0xd1U, 0x81U, 0xd0U, 0xbaU, 0xd0U, 0xb8U, 0xd0U, 0xb9U, 0 }; const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>"; XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText(); XMLTest( "UTF-8: Browsing russian element name.", russianText, text->Value() ); // Now try for a round trip. doc.SaveFile( "utf8testout.xml" ); // Check the round trip. char savedBuf[256]; char verifyBuf[256]; int okay = 0; #if defined(_MSC_VER) #pragma warning ( push ) #pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated. #endif FILE* saved = fopen( "utf8testout.xml", "r" ); FILE* verify = fopen( "utf8testverify.xml", "r" ); #if defined(_MSC_VER) #pragma warning ( pop ) #endif if ( saved && verify ) { okay = 1; while ( fgets( verifyBuf, 256, verify ) ) { fgets( savedBuf, 256, saved ); NullLineEndings( verifyBuf ); NullLineEndings( savedBuf ); if ( strcmp( verifyBuf, savedBuf ) ) { printf( "verify:%s<\n", verifyBuf ); printf( "saved :%s<\n", savedBuf ); okay = 0; break; } } } if ( saved ) fclose( saved ); if ( verify ) fclose( verify ); XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay ); } // --------GetText()----------- { const char* str = "<foo>This is text</foo>"; XMLDocument doc; doc.Parse( str ); const XMLElement* element = doc.RootElement(); XMLTest( "GetText() normal use.", "This is text", element->GetText() ); str = "<foo><b>This is text</b></foo>"; doc.Parse( str ); element = doc.RootElement(); XMLTest( "GetText() contained element.", element->GetText() == 0, true ); } // ---------- CDATA --------------- { const char* str = "<xmlElement>" "<![CDATA[" "I am > the rules!\n" "...since I make symbolic puns" "]]>" "</xmlElement>"; XMLDocument doc; doc.Parse( str ); doc.Print(); XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(), "I am > the rules!\n...since I make symbolic puns", false ); } // ----------- CDATA ------------- { const char* str = "<xmlElement>" "<![CDATA[" "<b>I am > the rules!</b>\n" "...since I make symbolic puns" "]]>" "</xmlElement>"; XMLDocument doc; doc.Parse( str ); doc.Print(); XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(), "<b>I am > the rules!</b>\n...since I make symbolic puns", false ); } // InsertAfterChild causes crash. { // InsertBeforeChild and InsertAfterChild causes crash. XMLDocument doc; XMLElement* parent = doc.NewElement( "Parent" ); doc.InsertFirstChild( parent ); XMLElement* childText0 = doc.NewElement( "childText0" ); XMLElement* childText1 = doc.NewElement( "childText1" ); XMLNode* childNode0 = parent->InsertEndChild( childText0 ); XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 ); XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true ); } { // Entities not being written correctly. // From Lynn Allen const char* passages = "<?xml version=\"1.0\" standalone=\"no\" ?>" "<passages count=\"006\" formatversion=\"20020620\">" "<psg context=\"Line 5 has "quotation marks" and 'apostrophe marks'." " It also has <, >, and &, as well as a fake copyright ©.\"> </psg>" "</passages>"; XMLDocument doc; doc.Parse( passages ); XMLElement* psg = doc.RootElement()->FirstChildElement(); const char* context = psg->Attribute( "context" ); const char* expected = "Line 5 has \"quotation marks\" and 'apostrophe marks'. It also has <, >, and &, as well as a fake copyright \xC2\xA9."; XMLTest( "Entity transformation: read. ", expected, context, true ); #if defined(_MSC_VER) #pragma warning ( push ) #pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated. #endif FILE* textfile = fopen( "textfile.txt", "w" ); #if defined(_MSC_VER) #pragma warning ( pop ) #endif if ( textfile ) { XMLPrinter streamer( textfile ); psg->Accept( &streamer ); fclose( textfile ); } #if defined(_MSC_VER) #pragma warning ( push ) #pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated. #endif textfile = fopen( "textfile.txt", "r" ); #if defined(_MSC_VER) #pragma warning ( pop ) #endif TIXMLASSERT( textfile ); if ( textfile ) { char buf[ 1024 ]; fgets( buf, 1024, textfile ); XMLTest( "Entity transformation: write. ", "<psg context=\"Line 5 has "quotation marks" and 'apostrophe marks'." " It also has <, >, and &, as well as a fake copyright \xC2\xA9.\"/>\n", buf, false ); } fclose( textfile ); } { // Suppress entities. const char* passages = "<?xml version=\"1.0\" standalone=\"no\" ?>" "<passages count=\"006\" formatversion=\"20020620\">" "<psg context=\"Line 5 has "quotation marks" and 'apostrophe marks'.\">Crazy &ttk;</psg>" "</passages>"; XMLDocument doc( false ); doc.Parse( passages ); XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ), "Line 5 has "quotation marks" and 'apostrophe marks'." ); XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(), "Crazy &ttk;" ); doc.Print(); } { const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>"; XMLDocument doc; doc.Parse( test ); XMLTest( "dot in names", doc.Error(), 0); XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" ); XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" ); } { const char* test = "<element><Name>1.1 Start easy ignore fin thickness
</Name></element>"; XMLDocument doc; doc.Parse( test ); XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText(); XMLTest( "Entity with one digit.", text->Value(), "1.1 Start easy ignore fin thickness\n", false ); } { // DOCTYPE not preserved (950171) // const char* doctype = "<?xml version=\"1.0\" ?>" "<!DOCTYPE PLAY SYSTEM 'play.dtd'>" "<!ELEMENT title (#PCDATA)>" "<!ELEMENT books (title,authors)>" "<element />"; XMLDocument doc; doc.Parse( doctype ); doc.SaveFile( "test7.xml" ); doc.DeleteChild( doc.RootElement() ); doc.LoadFile( "test7.xml" ); doc.Print(); const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown(); XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() ); } { // Comments do not stream out correctly. const char* doctype = "<!-- Somewhat<evil> -->"; XMLDocument doc; doc.Parse( doctype ); XMLComment* comment = doc.FirstChild()->ToComment(); XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() ); } { // Double attributes const char* doctype = "<element attr='red' attr='blue' />"; XMLDocument doc; doc.Parse( doctype ); XMLTest( "Parsing repeated attributes.", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() ); // is an error to tinyxml (didn't use to be, but caused issues) doc.PrintError(); } { // Embedded null in stream. const char* doctype = "<element att\0r='red' attr='blue' />"; XMLDocument doc; doc.Parse( doctype ); XMLTest( "Embedded null throws error.", true, doc.Error() ); } { // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717 const char* str = " "; XMLDocument doc; doc.Parse( str ); XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() ); } { // Low entities XMLDocument doc; doc.Parse( "<test></test>" ); const char result[] = { 0x0e, 0 }; XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result ); doc.Print(); } { // Attribute values with trailing quotes not handled correctly XMLDocument doc; doc.Parse( "<foo attribute=bar\" />" ); XMLTest( "Throw error with bad end quotes.", doc.Error(), true ); } { // [ 1663758 ] Failure to report error on bad XML XMLDocument xml; xml.Parse("<x>"); XMLTest("Missing end tag at end of input", xml.Error(), true); xml.Parse("<x> "); XMLTest("Missing end tag with trailing whitespace", xml.Error(), true); xml.Parse("<x></y>"); XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT); } { // [ 1475201 ] TinyXML parses entities in comments XMLDocument xml; xml.Parse("<!-- declarations for <head> & <body> -->" "<!-- far & away -->" ); XMLNode* e0 = xml.FirstChild(); XMLNode* e1 = e0->NextSibling(); XMLComment* c0 = e0->ToComment(); XMLComment* c1 = e1->ToComment(); XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true ); XMLTest( "Comments ignore entities.", " far & away ", c1->Value(), true ); } { XMLDocument xml; xml.Parse( "<Parent>" "<child1 att=''/>" "<!-- With this comment, child2 will not be parsed! -->" "<child2 att=''/>" "</Parent>" ); xml.Print(); int count = 0; for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild(); ele; ele = ele->NextSibling() ) { ++count; } XMLTest( "Comments iterate correctly.", 3, count ); } { // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well. unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl"; buf[60] = 239; buf[61] = 0; XMLDocument doc; doc.Parse( (const char*)buf); } { // bug 1827248 Error while parsing a little bit malformed file // Actually not malformed - should work. XMLDocument xml; xml.Parse( "<attributelist> </attributelist >" ); XMLTest( "Handle end tag whitespace", false, xml.Error() ); } { // This one must not result in an infinite loop XMLDocument xml; xml.Parse( "<infinite>loop" ); XMLTest( "Infinite loop test.", true, true ); } #endif { const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>"; XMLDocument doc; doc.Parse( pub ); XMLDocument clone; for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) { XMLNode* copy = node->ShallowClone( &clone ); clone.InsertEndChild( copy ); } clone.Print(); int count=0; const XMLNode* a=clone.FirstChild(); const XMLNode* b=doc.FirstChild(); for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) { ++count; XMLTest( "Clone and Equal", true, a->ShallowEqual( b )); } XMLTest( "Clone and Equal", 4, count ); } // ----------- Performance tracking -------------- { #if defined( _MSC_VER ) __int64 start, end, freq; QueryPerformanceFrequency( (LARGE_INTEGER*) &freq ); #endif #if defined(_MSC_VER) #pragma warning ( push ) #pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated. #endif FILE* fp = fopen( "dream.xml", "r" ); #if defined(_MSC_VER) #pragma warning ( pop ) #endif fseek( fp, 0, SEEK_END ); long size = ftell( fp ); fseek( fp, 0, SEEK_SET ); char* mem = new char[size+1]; fread( mem, size, 1, fp ); fclose( fp ); mem[size] = 0; #if defined( _MSC_VER ) QueryPerformanceCounter( (LARGE_INTEGER*) &start ); #else clock_t cstart = clock(); #endif static const int COUNT = 10; for( int i=0; i<COUNT; ++i ) { XMLDocument doc; doc.Parse( mem ); } #if defined( _MSC_VER ) QueryPerformanceCounter( (LARGE_INTEGER*) &end ); #else clock_t cend = clock(); #endif delete [] mem; static const char* note = #ifdef DEBUG "DEBUG"; #else "Release"; #endif #if defined( _MSC_VER ) printf( "\nParsing %s of dream.xml: %.3f milli-seconds\n", note, 1000.0 * (double)(end-start) / ( (double)freq * (double)COUNT) ); #else printf( "\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart)/(double)COUNT ); #endif } #if defined( _MSC_VER ) && defined( DEBUG ) _CrtMemCheckpoint( &endMemState ); //_CrtMemDumpStatistics( &endMemState ); _CrtMemState diffMemState; _CrtMemDifference( &diffMemState, &startMemState, &endMemState ); _CrtMemDumpStatistics( &diffMemState ); //printf( "new total=%d\n", gNewTotal ); #endif printf ("\nPass %d, Fail %d\n", gPass, gFail); return 0; }
bool parse(const char *buffer) { // TODO: Restructure parse code so all checks occur in beginning // before any values are changed // TODO: catch lexical_cast exception doc.Parse( buffer ); XMLHandle docHandle( &doc ); XMLText *nodeval = docHandle.FirstChildElement( "ExternalData" ) .FirstChildElement( "TString" ) .FirstChild() // this is a text, not an element .ToText(); if( nodeval ) { if ( nodeval->Value() ) { estr = nodeval->Value(); } else { // something wrong with xml malformedXMLError("TString Value"); return false; } } else { // something wrong with xml malformedXMLError("TString"); return false; } nodeval = docHandle.FirstChildElement( "ExternalData" ) .FirstChildElement( "Position" ) .FirstChildElement("XPos") // this is a text, not an element .FirstChild() .ToText(); if( nodeval ) { if ( nodeval->Value() ) { xPos = boost::lexical_cast<double>(nodeval->Value()); } else { // something wrong with xml malformedXMLError("XPos Value"); return false; } } else { // something wrong with xml malformedXMLError("XPos"); return false; } nodeval = docHandle.FirstChildElement( "ExternalData" ) .FirstChildElement( "Position" ) .FirstChildElement("YPos") // this is a text, not an element .FirstChild() .ToText(); if( nodeval ) { if ( nodeval->Value() ) { yPos = boost::lexical_cast<double>(nodeval->Value()); } else { // something wrong with xml malformedXMLError("YPos Value"); return false; } } else { // something wrong with xml malformedXMLError("YPos"); return false; } nodeval = docHandle.FirstChildElement( "ExternalData" ) .FirstChildElement( "Position" ) .FirstChildElement("ZPos") // this is a text, not an element .FirstChild() .ToText(); if( nodeval ) { if ( nodeval->Value() ) { zPos = boost::lexical_cast<double>(nodeval->Value()); } else { // something wrong with xml malformedXMLError("ZPos Value"); return false; } } else { // something wrong with xml malformedXMLError("ZPos"); return false; } nodeval = docHandle.FirstChildElement( "ExternalData" ) .FirstChildElement( "Temperature" ) .FirstChildElement("Cpu") // this is a text, not an element .FirstChild() .ToText(); if( nodeval ) { if ( nodeval->Value() ) { cpu = boost::lexical_cast<double>(nodeval->Value()); } else { // something wrong with xml malformedXMLError("Cpu Value"); return false; } } else { // something wrong with xml malformedXMLError("Cpu"); return false; } nodeval = docHandle.FirstChildElement( "ExternalData" ) .FirstChildElement( "Temperature" ) .FirstChildElement("Fan") // this is a text, not an element .FirstChild() .ToText(); if( nodeval ) { if ( nodeval->Value() ) { fan = boost::lexical_cast<double>(nodeval->Value()); } else { // something wrong with xml malformedXMLError("Fan Value"); return false; } } else { // something wrong with xml malformedXMLError("Fan"); return false; } nodeval = docHandle.FirstChildElement( "ExternalData" ) .FirstChildElement( "Ints" ) .FirstChildElement("AState") // this is a text, not an element .FirstChild() .ToText(); if( nodeval ) { if ( nodeval->Value() ) { astate = boost::lexical_cast<int>(nodeval->Value()); } else { // something wrong with xml malformedXMLError("AState Value"); return false; } } else { // something wrong with xml malformedXMLError("AState"); return false; } nodeval = docHandle.FirstChildElement( "ExternalData" ) .FirstChildElement( "Ints" ) .FirstChildElement("BState") // this is a text, not an element .FirstChild() .ToText(); if( nodeval ) { if ( nodeval->Value() ) { bstate = boost::lexical_cast<int>(nodeval->Value()); } else { // something wrong with xml malformedXMLError("BState Value"); return false; } } else { // something wrong with xml malformedXMLError("BState"); return false; } nodeval = docHandle.FirstChildElement( "ExternalData" ) .FirstChildElement( "Boolean" ) .FirstChildElement("CState") // this is a text, not an element .FirstChild() .ToText(); if( nodeval ) { if ( nodeval->Value() ) { cstate = boost::lexical_cast<bool>(nodeval->Value()); } else { // something wrong with xml malformedXMLError("CState Value"); return false; } } else { // something wrong with xml malformedXMLError("BState"); return false; } XMLElement *xframe1 = docHandle.FirstChildElement( "ExternalData" ). FirstChildElement( "Frames" ). FirstChildElement("XFrame"). ToElement(); if ( xframe1 ) { // check for nulpointer int xmlerr = 0; xmlerr += xframe1->QueryDoubleAttribute( "XPos",&xPos1 ); // errorcode 0 if ok xmlerr += xframe1->QueryDoubleAttribute( "YPos",&yPos1 ); xmlerr += xframe1->QueryDoubleAttribute( "ZPos",&zPos1 ); xmlerr += xframe1->QueryDoubleAttribute( "ARot",&aRot1 ); // errorcode 0 if ok xmlerr += xframe1->QueryDoubleAttribute( "BRot",&bRot1 ); xmlerr += xframe1->QueryDoubleAttribute( "CRot",&cRot1 ); if (xmlerr != 0) { malformedXMLError("XFrame 1 Attributes"); } } else { // something wrong with xml malformedXMLError("XFrame 1"); return false; } XMLElement *xframe2 = docHandle.FirstChildElement( "ExternalData" ). FirstChildElement( "Frames" ). NextSiblingElement(). FirstChildElement("XFrame"). ToElement(); if ( xframe2 ) { // check for nullpointer int xmlerr = 0; xmlerr += xframe2->QueryDoubleAttribute( "XPos",&xPos2 ); // errorcode 0 if ok xmlerr += xframe2->QueryDoubleAttribute( "YPos",&yPos2 ); xmlerr += xframe2->QueryDoubleAttribute( "ZPos",&zPos2 ); xmlerr += xframe2->QueryDoubleAttribute( "ARot",&aRot2 ); // errorcode 0 if ok xmlerr += xframe2->QueryDoubleAttribute( "BRot",&bRot2 ); xmlerr += xframe2->QueryDoubleAttribute( "CRot",&cRot2 ); if (xmlerr != 0) { malformedXMLError("XFrame 2 Attributes"); } } else { // something wrong with xml malformedXMLError("XFrame 2"); return false; } XMLElement *xframe3 = docHandle.FirstChildElement( "ExternalData" ). FirstChildElement( "Frames" ). NextSiblingElement(). NextSiblingElement(). FirstChildElement("XFrame"). ToElement(); if ( xframe3 ) { // check for nullpointer int xmlerr = 0; xmlerr += xframe3->QueryDoubleAttribute( "XPos",&xPos3 ); // errorcode 0 if ok xmlerr += xframe3->QueryDoubleAttribute( "YPos",&yPos3 ); xmlerr += xframe3->QueryDoubleAttribute( "ZPos",&zPos3 ); xmlerr += xframe3->QueryDoubleAttribute( "ARot",&aRot3 ); // errorcode 0 if ok xmlerr += xframe3->QueryDoubleAttribute( "BRot",&bRot3 ); xmlerr += xframe3->QueryDoubleAttribute( "CRot",&cRot3 ); if (xmlerr != 0) { malformedXMLError("XFrame 3 Attributes"); } } else { // something wrong with xml malformedXMLError("XFrame 3"); return false; } return true; }
bool COLLADAImporter::LoadGeometry(XMLElement* geometryNode,boost::unordered_map<std::string, std::vector<float> >& floatarrays) { boost::unordered_map<std::string,Source> sources; XMLElement *mesh = XMLHelper::GetChildElement(geometryNode,"mesh"); if(mesh == NULL) mesh = XMLHelper::GetChildElement(geometryNode,"convex_mesh"); if(mesh == NULL) return false; // load all source elements under <mesh> std::vector<XMLElement*> xmlsources = XMLHelper::GetChildElements(mesh,"source"); for(std::vector<XMLElement*>::iterator it = xmlsources.begin();it != xmlsources.end(); it++) { Source s; if(s.parseXML(*it,floatarrays)) sources[s.getID()] = s; else return false; } XMLElement* xmlvertices = XMLHelper::GetChildElement(mesh,"vertices"); if(xmlvertices == NULL) return false; if(xmlvertices->Attribute("id") == NULL) return false; // get <vertrices> id std::string verticesid = xmlvertices->Attribute("id"); // get <vertices>, <input> with semantic="POSITION" XMLElement *positionInput = XMLHelper::GetChildElement(xmlvertices,"input","semantic","POSITION"); std::string positionid; if(!XMLHelper::GetElementAttribute(positionInput,"source",positionid)) return false; positionid = positionid.substr(1); // remove leading "#" Mesh mmesh; std::string geometryid; if(XMLHelper::GetElementAttribute(geometryNode,"id",geometryid)) mmesh.setID(geometryid); std::string geometryName; if(XMLHelper::GetElementAttribute(geometryNode,"name",geometryName)) mmesh.setName(geometryName); Source& vertices = sources[positionid]; int ucount = vertices.getUnitCount(); if(ucount < 3) return false; int vcount = vertices.getArrayValues().size() / ucount; for(int i=0;i<vcount;i++) { int idx = ucount*i; vec3 v(vertices.getArrayValues()[idx],vertices.getArrayValues()[idx+1],vertices.getArrayValues()[idx+2]); mmesh.getVertices().push_back(v); } // get <triangles> nodes std::vector<XMLElement*> xmltriangles = XMLHelper::GetChildElements(mesh,"triangles"); for(std::vector<XMLElement*>::iterator it = xmltriangles.begin();it!=xmltriangles.end();it++){ XMLElement * triangles = *it; if(triangles->Attribute("count") != NULL) { // get triangle count int tricount=0; if(!StringHelper::from_string<int>(tricount,std::string(triangles->Attribute("count")))) continue; std::string materialsymbol; if(!XMLHelper::GetElementAttribute(triangles,"material",materialsymbol)) materialsymbol = ""; std::string temp; int vertices_offset; // get vertices <input> XMLElement* verticesInput = XMLHelper::GetChildElement(triangles,"input","semantic","VERTEX"); if(!XMLHelper::GetElementAttribute(verticesInput,"source",temp)) return false; temp = temp.substr(1); if(temp != verticesid) // verify source is the same as vertices id loaded above in current mesh return false; if(!XMLHelper::GetElementAttribute(verticesInput,"offset",temp)) // get vertices offset in <p> element return false; if(!StringHelper::from_string(vertices_offset,temp)) return false; std::string normalid; int normal_offset; bool hasNormals; // get normals <input> XMLElement* normalInput = XMLHelper::GetChildElement(triangles,"input","semantic","NORMAL"); if(!XMLHelper::GetElementAttribute(normalInput,"source",normalid)) hasNormals = false; else { normalid = normalid.substr(1); hasNormals = true; } if(hasNormals && !XMLHelper::GetElementAttribute(normalInput,"offset",temp)) // get offset for normals in <p> element return false; else { if(!StringHelper::from_string<int>(normal_offset,temp)) return false; } XMLElement *pelement = XMLHelper::GetChildElement(triangles,"p"); if(pelement == NULL) return false; XMLText *innerText = pelement->FirstChild()->ToText(); if(innerText == NULL) return false; std::string tarray(innerText->Value()); std::vector<int> IndexArray = StringHelper::ConvertStringToTArray<int>(tarray); int indexcount = IndexArray.size(); if((indexcount % (3*tricount)) != 0) return false; int indexstride = indexcount/(3*tricount); TriangleGroup trigroup; trigroup.setMaterialSymbol(materialsymbol); // TODO: add check for positionid & normalid if(hasNormals) { Source& vertices = sources[normalid]; ucount = vertices.getUnitCount(); if(ucount < 3) return false; int vcount = vertices.getArrayValues().size() / ucount; for(int i=0;i<vcount;i++) { int idx = ucount*i; vec3 v(vertices.getArrayValues()[idx],vertices.getArrayValues()[idx+1],vertices.getArrayValues()[idx+2]); trigroup.getNormals().push_back(v); } } for(int i=0;i<tricount*3;i++) { int vpos = i*indexstride + vertices_offset; trigroup.getTriangleIndices().push_back(IndexArray[vpos]); if(hasNormals) { vpos = i*indexstride + normal_offset; trigroup.getNormalIndices().push_back(IndexArray[vpos]); } } mmesh.getTriangleGroups().push_back(trigroup); } else continue; } // get <polygons> nodes std::vector<XMLElement*> xmlpolygons = XMLHelper::GetChildElements(mesh,"polygons"); for(std::vector<XMLElement*>::iterator it = xmlpolygons.begin(); it != xmlpolygons.end(); it++) { XMLElement * polygons = *it; if(polygons->Attribute("count") != NULL) { // get polygon count int polycount=0; if(!StringHelper::from_string<int>(polycount,std::string(polygons->Attribute("count")))) continue; std::string materialsymbol; if(!XMLHelper::GetElementAttribute(polygons,"material",materialsymbol)) materialsymbol = ""; std::string temp; int vertices_offset; // get vertices <input> XMLElement* verticesInput = XMLHelper::GetChildElement(polygons,"input","semantic","VERTEX"); if(!XMLHelper::GetElementAttribute(verticesInput,"source",temp)) return false; temp = temp.substr(1); if(temp != verticesid) // verify source is the same as vertices id loaded above in current mesh return false; if(!XMLHelper::GetElementAttribute(verticesInput,"offset",temp)) // get vertices offset in <p> element return false; if(!StringHelper::from_string(vertices_offset,temp)) return false; std::string normalid; int normal_offset; bool hasNormals; // get normals <input> XMLElement* normalInput = XMLHelper::GetChildElement(polygons,"input","semantic","NORMAL"); if(!XMLHelper::GetElementAttribute(normalInput,"source",normalid)) hasNormals = false; else { normalid = normalid.substr(1); hasNormals = true; } if(hasNormals && !XMLHelper::GetElementAttribute(normalInput,"offset",temp)) // get offset for normals in <p> element return false; else { if(!StringHelper::from_string<int>(normal_offset,temp)) return false; } int stridepervertex = 0; std::vector<XMLElement*> inputs = XMLHelper::GetChildElements(polygons,"input"); for(std::vector<XMLElement*>::const_iterator it = inputs.begin(); it != inputs.end(); it++) { if(!XMLHelper::GetElementAttribute(*it,"offset",temp)) return false; int offset=0; if(!StringHelper::from_string<int>(offset,temp)) return false; stridepervertex = std::max(stridepervertex,offset); } stridepervertex ++; PolygonGroup polygroup; polygroup.setMaterialSymbol(materialsymbol); if(hasNormals) { Source& vertices = sources[normalid]; ucount = vertices.getUnitCount(); if(ucount < 3) // normals have at least 3 components (X,Y,Z) return false; int vcount = vertices.getArrayValues().size() / ucount; for(int i=0;i<vcount;i++) { int idx = ucount*i; vec3 v(vertices.getArrayValues()[idx],vertices.getArrayValues()[idx+1],vertices.getArrayValues()[idx+2]); polygroup.getNormals().push_back(v); } } std::vector<XMLElement *> pelements = XMLHelper::GetChildElements(polygons,"p"); for(std::vector<XMLElement*>::iterator it = pelements.begin(); it != pelements.end(); it++) { XMLElement *pelement = *it; XMLText *innerText = pelement->FirstChild()->ToText(); if(innerText == NULL) return false; std::string tarray(innerText->Value()); std::vector<int> IndexArray = StringHelper::ConvertStringToTArray<int>(tarray); if((IndexArray.size() % stridepervertex) != 0) continue; int currentIndexOffset = 0; int vertexCount = IndexArray.size() / stridepervertex; PPolygon poly; for(int i=0;i<vertexCount;i++) { poly.getVertexIndices().push_back(IndexArray[currentIndexOffset+vertices_offset]); if(hasNormals) { poly.getNormalIndices().push_back(IndexArray[currentIndexOffset+normal_offset]); } currentIndexOffset += stridepervertex; } polygroup.getPolygons().push_back(poly); } mmesh.getPolygonGroups().push_back(polygroup); } else continue; } // get <polylist> nodes std::vector<XMLElement*> xmlpolylist = XMLHelper::GetChildElements(mesh,"polylist"); for(std::vector<XMLElement*>::iterator it = xmlpolylist.begin();it!=xmlpolylist.end();it++){ XMLElement * polylist = *it; if(polylist->Attribute("count") != NULL) { // get polygon count int polycount=0; if(!StringHelper::from_string<int>(polycount,std::string(polylist->Attribute("count")))) continue; std::string materialsymbol; if(!XMLHelper::GetElementAttribute(polylist,"material",materialsymbol)) materialsymbol = ""; std::string temp; int vertices_offset; // get vertices <input> XMLElement* verticesInput = XMLHelper::GetChildElement(polylist,"input","semantic","VERTEX"); if(!XMLHelper::GetElementAttribute(verticesInput,"source",temp)) return false; temp = temp.substr(1); if(temp != verticesid) // verify source is the same as vertices id loaded above in current mesh return false; if(!XMLHelper::GetElementAttribute(verticesInput,"offset",temp)) // get vertices offset in <p> element return false; if(!StringHelper::from_string(vertices_offset,temp)) return false; std::string normalid; int normal_offset; bool hasNormals; // get normals <input> XMLElement* normalInput = XMLHelper::GetChildElement(polylist,"input","semantic","NORMAL"); if(!XMLHelper::GetElementAttribute(normalInput,"source",normalid)) hasNormals = false; else { normalid = normalid.substr(1); hasNormals = true; } if(hasNormals && !XMLHelper::GetElementAttribute(normalInput,"offset",temp)) // get offset for normals in <p> element return false; else { if(!StringHelper::from_string<int>(normal_offset,temp)) return false; } XMLElement *vcountelement = XMLHelper::GetChildElement(polylist,"vcount"); if(vcountelement == NULL) return false; XMLText *vcountinnerText = vcountelement->FirstChild()->ToText(); if(vcountinnerText == NULL) return false; std::string vcarray(vcountinnerText->Value()); std::vector<int> vCountArray = StringHelper::ConvertStringToTArray<int>(vcarray); if(vCountArray.size() != polycount) return false; int totalVertices = 0; for(std::vector<int>::const_iterator it = vCountArray.begin(); it != vCountArray.end(); it++) { totalVertices += *it; } XMLElement *pelement = XMLHelper::GetChildElement(polylist,"p"); if(pelement == NULL) return false; XMLText *innerText = pelement->FirstChild()->ToText(); if(innerText == NULL) return false; std::string tarray(innerText->Value()); std::vector<int> IndexArray = StringHelper::ConvertStringToTArray<int>(tarray); int indexcount = IndexArray.size(); if((indexcount % totalVertices) != 0) return false; PolygonGroup polygroup; polygroup.setMaterialSymbol(materialsymbol); // TODO: add check for positionid & normalid if(hasNormals) { Source& vertices = sources[normalid]; ucount = vertices.getUnitCount(); if(ucount < 3) // normals have at least 3 components (X,Y,Z) return false; int vcount = vertices.getArrayValues().size() / ucount; for(int i=0;i<vcount;i++) { int idx = ucount*i; vec3 v(vertices.getArrayValues()[idx],vertices.getArrayValues()[idx+1],vertices.getArrayValues()[idx+2]); polygroup.getNormals().push_back(v); } } int stridepervertex = 0; std::vector<XMLElement*> inputs = XMLHelper::GetChildElements(polylist,"input"); for(std::vector<XMLElement*>::const_iterator it = inputs.begin(); it != inputs.end(); it++) { if(!XMLHelper::GetElementAttribute(*it,"offset",temp)) return false; int offset=0; if(!StringHelper::from_string<int>(offset,temp)) return false; stridepervertex = std::max(stridepervertex,offset); } stridepervertex ++; if(IndexArray.size() != totalVertices*stridepervertex) return false; int currentIndexOffset = 0; for(int i=0;i<polycount;i++) { PPolygon poly; for(int j=0;j<vCountArray[i];j++) { poly.getVertexIndices().push_back(IndexArray[currentIndexOffset+vertices_offset]); if(hasNormals) { poly.getNormalIndices().push_back(IndexArray[currentIndexOffset+normal_offset]); } currentIndexOffset += stridepervertex; } polygroup.getPolygons().push_back(poly); } mmesh.getPolygonGroups().push_back(polygroup); } else continue; } if((mmesh.getTriangleGroups().size()>0) || (mmesh.getPolygonGroups().size() > 0)) { m_Meshes.push_back(mmesh); return true; } else return false; }
bool COLLADAImporter::LoadMaterial(XMLElement* colladaRootNode,const std::string& id) { if(m_Materials.find(id) != m_Materials.end()) // material already loaded return true; XMLElement *materials = XMLHelper::GetChildElement(colladaRootNode,"library_materials"); if(materials == NULL) return false; XMLElement *material = XMLHelper::GetChildElement(materials,"material","id",id); if(material == NULL) return false; XMLElement *effect = XMLHelper::GetChildElement(material,"instance_effect"); if(effect == NULL) return false; std::string effectid; if(!XMLHelper::GetElementAttribute(effect,"url",effectid)) return false; effectid = effectid.substr(1); // remove leading "#" XMLElement *effects = XMLHelper::GetChildElement(colladaRootNode,"library_effects"); if(effects == NULL) return false; effect = XMLHelper::GetChildElement(effects,"id",effectid); if(effect == NULL) return false; XMLElement *profile = XMLHelper::GetChildElement(effect,"profile_COMMON"); if(profile == NULL) return false; XMLElement *technique = XMLHelper::GetChildElement(profile,"technique"); if(technique == NULL) return false; XMLElement *bp = XMLHelper::GetChildElement(technique,"blinn"); if(bp == NULL) { bp = XMLHelper::GetChildElement(technique,"phong"); if(bp == NULL) { bp = XMLHelper::GetChildElement(technique,"lambert"); if(bp == NULL) return false; } } Material mat; // ambient XMLElement *ambient = XMLHelper::GetChildElement(bp,"ambient"); if(ambient != NULL) { XMLElement *color = XMLHelper::GetChildElement(ambient,"color"); if(color != NULL) { XMLText *value = color->FirstChild()->ToText(); if(value != NULL) { std::vector<float> c = StringHelper::ConvertStringToTArray<float>(value->Value()); if(c.size() >= 3 ) mat.m_Ambient = vec3(c[0],c[1],c[2]); } } } //diffuse XMLElement *diffuse = XMLHelper::GetChildElement(bp,"diffuse"); if(diffuse != NULL) { XMLElement* color = XMLHelper::GetChildElement(diffuse,"color"); if(color != NULL) { XMLText* value = color->FirstChild()->ToText(); if(value != NULL) { std::vector<float> c = StringHelper::ConvertStringToTArray<float>(value->Value()); if(c.size() >= 3 ) mat.m_Diffuse = vec3(c[0],c[1],c[2]); } } } //specular XMLElement *specular = XMLHelper::GetChildElement(bp,"specular"); if(specular != NULL) { XMLElement* color = XMLHelper::GetChildElement(specular,"color"); if(color != NULL) { XMLText* value = color->FirstChild()->ToText(); if(value != NULL) { std::vector<float> c = StringHelper::ConvertStringToTArray<float>(value->Value()); if(c.size() >= 3 ) mat.m_Specular = vec3(c[0],c[1],c[2]); } } } //emission XMLElement *emission = XMLHelper::GetChildElement(bp,"emission"); if(emission != NULL) { XMLElement* color = XMLHelper::GetChildElement(emission,"color"); if(color != NULL) { XMLText* value = color->FirstChild()->ToText(); if(value != NULL) { std::vector<float> c = StringHelper::ConvertStringToTArray<float>(value->Value()); if(c.size() >= 3 ) mat.m_Emmission = vec3(c[0],c[1],c[2]); } } } m_Materials[id] = mat; return true; }
bool FractalConfiguration::save(string filename) { if(invalidID()) return true; // Check filename and append .xml if(!endsWith(filename, ".xml")) filename += ".xml"; // Create document XMLDocument doc; // Root element XMLElement *root = doc.NewElement("fractal"); root->SetAttribute("id", m_id.c_str()); doc.InsertEndChild(root); // Add properties iterate(); while(true) { if(!next()) break; XMLElement *prop = doc.NewElement("property"); prop->SetAttribute("name", getName().c_str()); XMLText *text = doc.NewText(""); if(isString()) { prop->SetAttribute("type", "string"); text->SetValue(getString().c_str()); } else if(isInt()) { prop->SetAttribute("type", "int"); stringstream ss; ss << getInt(); text->SetValue(ss.str().c_str()); } else if(isDouble()) { prop->SetAttribute("type", "double"); stringstream ss; ss << getDouble(); text->SetValue(ss.str().c_str()); } else if(isBool()) { prop->SetAttribute("type", "bool"); if(getBool()) text->SetValue("1"); else text->SetValue("0"); } prop->InsertEndChild(text); root->InsertEndChild(prop); } // Save to file if(doc.SaveFile(filename.c_str()) != XML_NO_ERROR) { m_last_error = doc.GetErrorStr1(); return true; } resetDirty(); return false; }
bool XmlHandler::ReadFile(const char* fileName, OVR::Render::RenderDevice* pRender, OVR::Render::Scene* pScene, OVR::Array<Ptr<CollisionModel> >* pCollisions, OVR::Array<Ptr<CollisionModel> >* pGroundCollisions, bool srgbAware /*= false*/, bool anisotropic /*= false*/) { if(pXmlDocument->LoadFile(fileName) != 0) { return false; } // Extract the relative path to our working directory for loading textures filePath[0] = 0; intptr_t pos = 0; intptr_t len = strlen(fileName); for(intptr_t i = len; i > 0; i--) { if (fileName[i-1]=='\\' || fileName[i-1]=='/') { memcpy(filePath, fileName, i); filePath[i] = 0; break; } } // Load the textures OVR_DEBUG_LOG_TEXT(("Loading textures...")); XMLElement* pXmlTexture = pXmlDocument->FirstChildElement("scene")->FirstChildElement("textures"); OVR_ASSERT(pXmlTexture); if (pXmlTexture) { pXmlTexture->QueryIntAttribute("count", &textureCount); pXmlTexture = pXmlTexture->FirstChildElement("texture"); } for(int i = 0; i < textureCount; ++i) { const char* textureName = pXmlTexture->Attribute("fileName"); intptr_t dotpos = strcspn(textureName, "."); char fname[300]; if (pos == len) { OVR_sprintf(fname, 300, "%s", textureName); } else { OVR_sprintf(fname, 300, "%s%s", filePath, textureName); } int textureLoadFlags = 0; textureLoadFlags |= srgbAware ? TextureLoad_SrgbAware : 0; textureLoadFlags |= anisotropic ? TextureLoad_Anisotropic : 0; SysFile* pFile = new SysFile(fname); Ptr<Texture> texture; if (textureName[dotpos + 1] == 'd' || textureName[dotpos + 1] == 'D') { // DDS file Texture* tmp_ptr = LoadTextureDDSTopDown(pRender, pFile, textureLoadFlags); if(tmp_ptr) { texture.SetPtr(*tmp_ptr); } } else { Texture* tmp_ptr = LoadTextureTgaTopDown(pRender, pFile, textureLoadFlags, 255); if(tmp_ptr) { texture.SetPtr(*tmp_ptr); } } Textures.PushBack(texture); pFile->Close(); pFile->Release(); pXmlTexture = pXmlTexture->NextSiblingElement("texture"); } OVR_DEBUG_LOG_TEXT(("Done.\n")); // Load the models pXmlDocument->FirstChildElement("scene")->FirstChildElement("models")-> QueryIntAttribute("count", &modelCount); OVR_DEBUG_LOG(("Loading models... %i models to load...", modelCount)); XMLElement* pXmlModel = pXmlDocument->FirstChildElement("scene")-> FirstChildElement("models")->FirstChildElement("model"); for(int i = 0; i < modelCount; ++i) { if (i % 15 == 0) { OVR_DEBUG_LOG_TEXT(("%i models remaining...", modelCount - i)); } const char* name = pXmlModel->Attribute("name"); Models.PushBack(*new Model(Prim_Triangles, name)); bool isCollisionModel = false; pXmlModel->QueryBoolAttribute("isCollisionModel", &isCollisionModel); Models[i]->IsCollisionModel = isCollisionModel; if (isCollisionModel) { Models[i]->Visible = false; } bool tree_c = (strcmp(name, "tree_C") == 0) || (strcmp(name, "Object03") == 0); //read the vertices OVR::Array<Vector3f> *vertices = new OVR::Array<Vector3f>(); ParseVectorString(pXmlModel->FirstChildElement("vertices")->FirstChild()-> ToText()->Value(), vertices); for (unsigned int vertexIndex = 0; vertexIndex < vertices->GetSize(); ++vertexIndex) { vertices->At(vertexIndex).x *= -1.0f; if (tree_c) { // Move the terrace tree closer to the house vertices->At(vertexIndex).z += 0.5; } } //read the normals OVR::Array<Vector3f> *normals = new OVR::Array<Vector3f>(); ParseVectorString(pXmlModel->FirstChildElement("normals")->FirstChild()-> ToText()->Value(), normals); for (unsigned int normalIndex = 0; normalIndex < normals->GetSize(); ++normalIndex) { normals->At(normalIndex).z *= -1.0f; } //read the textures OVR::Array<Vector3f> *diffuseUVs = new OVR::Array<Vector3f>(); OVR::Array<Vector3f> *lightmapUVs = new OVR::Array<Vector3f>(); int diffuseTextureIndex = -1; int lightmapTextureIndex = -1; XMLElement* pXmlCurMaterial = pXmlModel->FirstChildElement("material"); while(pXmlCurMaterial != NULL) { if(pXmlCurMaterial->Attribute("name", "diffuse")) { pXmlCurMaterial->FirstChildElement("texture")-> QueryIntAttribute("index", &diffuseTextureIndex); if(diffuseTextureIndex > -1) { ParseVectorString(pXmlCurMaterial->FirstChildElement("texture")-> FirstChild()->ToText()->Value(), diffuseUVs, true); } } else if(pXmlCurMaterial->Attribute("name", "lightmap")) { pXmlCurMaterial->FirstChildElement("texture")-> QueryIntAttribute("index", &lightmapTextureIndex); if(lightmapTextureIndex > -1) { XMLElement* firstChildElement = pXmlCurMaterial->FirstChildElement("texture"); XMLNode* firstChild = firstChildElement->FirstChild(); XMLText* text = firstChild->ToText(); const char* value = text->Value(); ParseVectorString(value, lightmapUVs, true); } } pXmlCurMaterial = pXmlCurMaterial->NextSiblingElement("material"); } //set up the shader Ptr<ShaderFill> shader = *new ShaderFill(*pRender->CreateShaderSet()); shader->GetShaders()->SetShader(pRender->LoadBuiltinShader(Shader_Vertex, VShader_MVP)); if(diffuseTextureIndex > -1) { shader->SetTexture(0, Textures[diffuseTextureIndex]); if(lightmapTextureIndex > -1) { shader->GetShaders()->SetShader(pRender->LoadBuiltinShader(Shader_Fragment, FShader_MultiTexture)); shader->SetTexture(1, Textures[lightmapTextureIndex]); } else { shader->GetShaders()->SetShader(pRender->LoadBuiltinShader(Shader_Fragment, FShader_Texture)); } } else { shader->GetShaders()->SetShader(pRender->LoadBuiltinShader(Shader_Fragment, FShader_LitGouraud)); } Models[i]->Fill = shader; //add all the vertices to the model const size_t numVerts = vertices->GetSize(); for(size_t v = 0; v < numVerts; ++v) { if(diffuseTextureIndex > -1) { if(lightmapTextureIndex > -1) { Models[i]->AddVertex(vertices->At(v).z, vertices->At(v).y, vertices->At(v).x, Color(255, 255, 255), diffuseUVs->At(v).x, diffuseUVs->At(v).y, lightmapUVs->At(v).x, lightmapUVs->At(v).y, normals->At(v).x, normals->At(v).y, normals->At(v).z); } else { Models[i]->AddVertex(vertices->At(v).z, vertices->At(v).y, vertices->At(v).x, Color(255, 255, 255), diffuseUVs->At(v).x, diffuseUVs->At(v).y, 0, 0, normals->At(v).x, normals->At(v).y, normals->At(v).z); } } else { Models[i]->AddVertex(vertices->At(v).z, vertices->At(v).y, vertices->At(v).x, Color(255, 255, 255, 255), 0, 0, 0, 0, normals->At(v).x, normals->At(v).y, normals->At(v).z); } } // Read the vertex indices for the triangles const char* indexStr = pXmlModel->FirstChildElement("indices")-> FirstChild()->ToText()->Value(); size_t stringLength = strlen(indexStr); for(size_t j = 0; j < stringLength; ) { size_t k = j + 1; for(; k < stringLength; ++k) { if (indexStr[k] == ' ') break; } char text[20]; for(size_t l = 0; l < k - j; ++l) { text[l] = indexStr[j + l]; } text[k - j] = '\0'; Models[i]->Indices.PushBack((unsigned short)atoi(text)); j = k + 1; } // Reverse index order to match original expected orientation Array<uint16_t>& indices = Models[i]->Indices; size_t indexCount = indices.GetSize(); for (size_t revIndex = 0; revIndex < indexCount/2; revIndex++) { unsigned short itemp = indices[revIndex]; indices[revIndex] = indices[indexCount - revIndex - 1]; indices[indexCount - revIndex - 1] = itemp; } delete vertices; delete normals; delete diffuseUVs; delete lightmapUVs; pScene->World.Add(Models[i]); pScene->Models.PushBack(Models[i]); pXmlModel = pXmlModel->NextSiblingElement("model"); } OVR_DEBUG_LOG(("Done.")); //load the collision models OVR_DEBUG_LOG(("Loading collision models... ")); XMLElement* pXmlCollisionModel = pXmlDocument->FirstChildElement("scene")->FirstChildElement("collisionModels"); if (pXmlCollisionModel) { pXmlCollisionModel->QueryIntAttribute("count", &collisionModelCount); pXmlCollisionModel = pXmlCollisionModel->FirstChildElement("collisionModel"); } XMLElement* pXmlPlane = NULL; for(int i = 0; i < collisionModelCount; ++i) { Ptr<CollisionModel> cm = *new CollisionModel(); int planeCount = 0; OVR_ASSERT(pXmlCollisionModel != NULL); // collisionModelCount should guarantee this. if (pXmlCollisionModel) { pXmlCollisionModel->QueryIntAttribute("planeCount", &planeCount); pXmlPlane = pXmlCollisionModel->FirstChildElement("plane"); for(int j = 0; j < planeCount; ++j) { Vector3f norm; pXmlPlane->QueryFloatAttribute("nx", &norm.x); pXmlPlane->QueryFloatAttribute("ny", &norm.y); pXmlPlane->QueryFloatAttribute("nz", &norm.z); float D; pXmlPlane->QueryFloatAttribute("d", &D); D -= 0.5f; if (i == 26) D += 0.5f; // tighten the terrace collision so player can move right up to rail Planef p(norm.z, norm.y, norm.x * -1.0f, D); cm->Add(p); pXmlPlane = pXmlPlane->NextSiblingElement("plane"); } if (pCollisions) pCollisions->PushBack(cm); pXmlCollisionModel = pXmlCollisionModel->NextSiblingElement("collisionModel"); } } OVR_DEBUG_LOG(("done.")); //load the ground collision models OVR_DEBUG_LOG(("Loading ground collision models...")); pXmlCollisionModel = pXmlDocument->FirstChildElement("scene")->FirstChildElement("groundCollisionModels"); OVR_ASSERT(pXmlCollisionModel); if (pXmlCollisionModel) { pXmlCollisionModel->QueryIntAttribute("count", &groundCollisionModelCount); pXmlCollisionModel = pXmlCollisionModel->FirstChildElement("collisionModel"); pXmlPlane = NULL; for(int i = 0; i < groundCollisionModelCount; ++i) { Ptr<CollisionModel> cm = *new CollisionModel(); int planeCount = 0; pXmlCollisionModel->QueryIntAttribute("planeCount", &planeCount); pXmlPlane = pXmlCollisionModel->FirstChildElement("plane"); for(int j = 0; j < planeCount; ++j) { Vector3f norm; pXmlPlane->QueryFloatAttribute("nx", &norm.x); pXmlPlane->QueryFloatAttribute("ny", &norm.y); pXmlPlane->QueryFloatAttribute("nz", &norm.z); float D = 0.f; pXmlPlane->QueryFloatAttribute("d", &D); Planef p(norm.z, norm.y, norm.x * -1.0f, D); cm->Add(p); pXmlPlane = pXmlPlane->NextSiblingElement("plane"); } if (pGroundCollisions) pGroundCollisions->PushBack(cm); pXmlCollisionModel = pXmlCollisionModel->NextSiblingElement("collisionModel"); } } OVR_DEBUG_LOG(("done.")); return true; }
TEST(XMLNodeTest, prependText) { XMLElement root("root"); root.prepend(util::make_unique<XMLText>("first string")); EXPECT_EQ(number_of_children(root), 1); XMLText *firstChild = root.firstChild()->toText(); ASSERT_NE(firstChild, nullptr); EXPECT_EQ(firstChild->getText(), "first string"); EXPECT_EQ(firstChild->parent(), &root); EXPECT_EQ(firstChild->prev(), nullptr); EXPECT_EQ(firstChild->next(), nullptr); root.prepend(util::make_unique<XMLText>("second string,")); EXPECT_EQ(number_of_children(root), 1); firstChild = root.firstChild()->toText(); ASSERT_NE(firstChild, nullptr); EXPECT_EQ(firstChild->getText(), "second string,first string"); EXPECT_EQ(firstChild->parent(), &root); EXPECT_EQ(firstChild->prev(), nullptr); EXPECT_EQ(firstChild->next(), nullptr); root.prepend(util::make_unique<XMLElement>("separator")); root.prepend(util::make_unique<XMLText>("third string,")); EXPECT_EQ(number_of_children(root), 3); firstChild = root.firstChild()->toText(); ASSERT_NE(firstChild, nullptr); EXPECT_EQ(firstChild->getText(), "third string,"); EXPECT_EQ(firstChild->parent(), &root); EXPECT_EQ(firstChild->prev(), nullptr); EXPECT_EQ(firstChild->next()->next(), root.lastChild()); EXPECT_EQ(root.lastChild()->prev()->prev(), root.firstChild()); }
TEST(XMLNodeTest, appendText) { XMLElement root("root"); root.append(util::make_unique<XMLText>("first string")); EXPECT_EQ(number_of_children(root), 1); XMLText *lastChild = root.lastChild()->toText(); ASSERT_NE(lastChild, nullptr); EXPECT_EQ(lastChild->getText(), "first string"); EXPECT_EQ(lastChild->parent(), &root); EXPECT_EQ(lastChild->prev(), nullptr); EXPECT_EQ(lastChild->next(), nullptr); EXPECT_EQ(root.firstChild(), root.lastChild()); root.append(util::make_unique<XMLText>(",second string")); EXPECT_EQ(number_of_children(root), 1); lastChild = root.lastChild()->toText(); ASSERT_NE(lastChild, nullptr); EXPECT_EQ(lastChild->getText(), "first string,second string"); EXPECT_EQ(lastChild->parent(), &root); EXPECT_EQ(lastChild->prev(), nullptr); EXPECT_EQ(lastChild->next(), nullptr); EXPECT_EQ(root.firstChild(), root.lastChild()); root.append(",third string"); EXPECT_EQ(number_of_children(root), 1); lastChild = root.lastChild()->toText(); ASSERT_NE(lastChild, nullptr); EXPECT_EQ(lastChild->getText(), "first string,second string,third string"); EXPECT_EQ(lastChild->parent(), &root); EXPECT_EQ(lastChild->prev(), nullptr); EXPECT_EQ(lastChild->next(), nullptr); root.append(util::make_unique<XMLElement>("separator")); root.append(",fourth string"); EXPECT_EQ(number_of_children(root), 3); lastChild = root.lastChild()->toText(); ASSERT_NE(lastChild, nullptr); EXPECT_EQ(lastChild->getText(), ",fourth string"); root.append(util::make_unique<XMLElement>("separator")); root.append(util::make_unique<XMLText>(",fifth string")); EXPECT_EQ(number_of_children(root), 5); lastChild = root.lastChild()->toText(); ASSERT_NE(lastChild, nullptr); EXPECT_EQ(lastChild->getText(), ",fifth string"); root.clear(); EXPECT_TRUE(root.empty()); }
void LevelParser::parseTileLayer(XMLElement* pTileElement, Level *pLevel) { // New TileLayer instance TileLayer* pTileLayer = new TileLayer(m_tileSize, m_width, m_height, TheGame::Instance().getTilesets()); // local temporary variable bool collidable = false; // A multidimensional array of int values to hold our final decoded and uncompressed tile data std::vector<std::vector<int>> data; // xml data node XMLElement* pDataNode = nullptr; // to store base64 decoded information std::string decodedIDs; // We search for the node we need for (XMLElement* e = pTileElement->FirstChildElement(); e != NULL; e = e->NextSiblingElement()) { // check if layer has properties if (e->Value() == std::string("properties")) { for (XMLElement* property = e->FirstChildElement(); property != NULL; property = property->NextSiblingElement()) { if (property->Value() == std::string("property")) { // Check if it is a collision layer if (property->Attribute("name") == std::string("collidable")) { collidable = true; } } } } if (e->Value() == std::string("data")) { pDataNode = e; } } // Tile information not encoded nor compressed if (pDataNode->Attribute("encoding") == nullptr) { std::vector<int> layerRow(m_width); for (int rows = 0; rows < m_height; rows++) { data.push_back(layerRow); } XMLElement* tile = pDataNode->FirstChildElement(); int id; for (int rows = 0; rows < m_height; rows++) { for (int cols = 0; cols < m_width ; cols++) { tile->QueryAttribute("gid", &data[rows][cols]); tile = tile->NextSiblingElement(); } } } else { // We get the text (our encoded/compressed data) from the data node and use the base64 decoder to decode it for (XMLNode* e = pDataNode->FirstChild(); e != NULL; e = e->NextSibling()) { XMLText* text = e->ToText(); std::string t = text->Value(); decodedIDs = base64_decode(t); } // We use the zlib library to decompress our data once again uLongf sizeofids = m_width * m_height * sizeof(int); std::vector<unsigned> gids(sizeofids); uncompress((Bytef*)&gids[0], &sizeofids, (const Bytef*)decodedIDs.c_str(), decodedIDs.size()); // gids now contains all of our tile IDs, so we fill our data array with the correct values std::vector<int> layerRow(m_width); for (int j = 0; j < m_height; j++) { data.push_back(layerRow); } for (int rows = 0; rows < m_height; rows++) { for (int cols = 0; cols < m_width; cols++) { data[rows][cols] = gids[rows * m_width + cols]; } } } pTileLayer->setTileIDs(data); pTileLayer->setMapWidth(m_width); // push into collision array and mark the layer as collidable if necessary if (collidable) { pTileLayer->setCollidable(true); pLevel->getCollisionLayers()->push_back(pTileLayer); } pLevel->getLayers()->push_back(pTileLayer); }