Exemple #1
0
Matrix COLLADAImporter::LoadXMLMatrix(tinyxml2::XMLElement* matrix)
{
	XMLText* text = matrix->FirstChild()->ToText();
	if(text == NULL)
		return mat4::IdentityMatrix();
	std::vector<float> elements = StringHelper::ConvertStringToTArray<float>(text->Value());
	if(elements.size() != 16)
		return mat4::IdentityMatrix();
	mat4 mat;
	mat(0,0) = elements[0];
	mat(0,1) = elements[1];
	mat(0,2) = elements[2];
	mat(0,3) = elements[3];
	mat(1,0) = elements[4];
	mat(1,1) = elements[5];
	mat(1,2) = elements[6];
	mat(1,3) = elements[7];
	mat(2,0) = elements[8];
	mat(2,1) = elements[9];
	mat(2,2) = elements[10];
	mat(2,3) = elements[11];
	mat(3,0) = elements[12];
	mat(3,1) = elements[13];
	mat(3,2) = elements[14];
	mat(3,3) = elements[15];
	return Matrix(mat);
}
Exemple #2
0
Scale COLLADAImporter::LoadXMLScale(tinyxml2::XMLElement* scale)
{
	XMLText* text = scale->FirstChild()->ToText();
	if(text == NULL)
		return Scale();
	std::vector<float> elements = StringHelper::ConvertStringToTArray<float>(text->Value());
	if(elements.size() != 3)
		return Scale();
	vec3 t(elements[0],elements[1],elements[2]);
	return Scale(t);
}
Exemple #3
0
Rotate COLLADAImporter::LoadXMLRotation(tinyxml2::XMLElement* rotation)
{
	XMLText* text = rotation->FirstChild()->ToText();
	if(text == NULL)
		return Rotate();
	std::vector<float> elements = StringHelper::ConvertStringToTArray<float>(text->Value());
	if(elements.size() != 4)
		return Rotate();
	vec3 axis(elements[0],elements[1],elements[2]);	
	return Rotate(axis,elements[3]);
}
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;
}
Exemple #5
0
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();
}
Exemple #6
0
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;
				}
			}
		}
	}
}
Exemple #7
0
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 );
}
Exemple #8
0
	bool XMLPrinter::Visit( const XMLText& text )
	{
		PushText( text.Value(), text.CData() );
		return true;
	}
Exemple #9
0
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 &amp; That.</element>",
										"<element attrib='This&lt;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 &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
				" It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </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 &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
					 " It also has &lt;, &gt;, and &amp;, 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 &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
			"</passages>";

		XMLDocument doc( false );
		doc.Parse( passages );

		XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ),
				 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;." );
		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&#xA;</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>&#x0e;</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 &amp; 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 &amp; 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 &apos;  text  &apos; </a>"
							"<b>  This is &apos; text &apos;  \n</b>"
							"<c>This  is  &apos;  \n\n text &apos;</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;
}
Exemple #10
0
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 &amp; That.</element>",
										"<element attrib='This&lt;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 &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
				" It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </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 &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
					 " It also has &lt;, &gt;, and &amp;, 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 &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
			"</passages>";
		
		XMLDocument doc( false );
		doc.Parse( passages );

		XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ), 
				 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;." );
		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&#xA;</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>&#x0e;</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 &amp; 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 &amp; 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;

        }
Exemple #12
0
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;	
}
Exemple #13
0
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 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;
}
Exemple #15
0
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);
}