tamlXmlParser.cpp
Engine/source/persistence/taml/xml/tamlXmlParser.cpp
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2013 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "persistence/taml/xml/tamlXmlParser.h" 25#include "persistence/taml/tamlVisitor.h" 26#include "console/console.h" 27 28// Debug Profiling. 29#include "platform/profiler.h" 30 31#ifndef _FILESTREAM_H_ 32#include "core/stream/fileStream.h" 33#endif 34 35//----------------------------------------------------------------------------- 36 37bool TamlXmlParser::accept( const char* pFilename, TamlVisitor& visitor ) 38{ 39 // Debug Profiling. 40 PROFILE_SCOPE(TamlXmlParser_Accept); 41 42 // Sanity! 43 AssertFatal( pFilename != NULL, "Cannot parse a NULL filename." ); 44 45 // Expand the file-path. 46 char filenameBuffer[1024]; 47 // TODO: Make sure this is a proper substitute for 48 // Con::expandPath (T2D) 49 Con::expandToolScriptFilename( filenameBuffer, sizeof(filenameBuffer), pFilename ); 50 /** T2D uses a custom version of TinyXML that supports FileStream. 51 * We don't so we can't do this 52 * 53 FileStream stream; 54 55#ifdef TORQUE_OS_ANDROID 56 if (strlen(pFilename) > strlen(filenameBuffer)) { 57 dStrcpy(filenameBuffer, pFilename, 1024); 58 } 59#endif 60 61 // File open for read? 62 if ( !stream.open( filenameBuffer, Torque::FS::File::AccessMode::Read ) ) 63 { 64 // No, so warn. 65 Con::warnf("TamlXmlParser::parse() - Could not open filename '%s' for parse.", filenameBuffer ); 66 return false; 67 } 68 69 */ 70 71 TiXmlDocument xmlDocument; 72 73 // Load document from stream. 74 if ( !xmlDocument.LoadFile( filenameBuffer ) ) 75 { 76 // Warn! 77 Con::warnf("TamlXmlParser: Could not load Taml XML file from stream."); 78 return false; 79 } 80 81 // Close the stream. 82 // stream.close(); 83 84 // Set parsing filename. 85 setParsingFilename( filenameBuffer ); 86 87 // Flag document as not dirty. 88 mDocumentDirty = false; 89 90 // Parse root element. 91 parseElement( xmlDocument.RootElement(), visitor ); 92 93 // Reset parsing filename. 94 setParsingFilename( StringTable->EmptyString() ); 95 96 // Finish if the document is not dirty. 97 if ( !mDocumentDirty ) 98 return true; 99 100 // Open for write? 101 /*if ( !stream.open( filenameBuffer, FileStream::StreamWrite ) ) 102 { 103 // No, so warn. 104 Con::warnf("TamlXmlParser::parse() - Could not open filename '%s' for write.", filenameBuffer ); 105 return false; 106 }*/ 107 108 // Yes, so save the document. 109 if ( !xmlDocument.SaveFile( filenameBuffer ) ) 110 { 111 // Warn! 112 Con::warnf("TamlXmlParser: Could not save Taml XML document."); 113 return false; 114 } 115 116 // Close the stream. 117 //stream.close(); 118 119 return true; 120} 121 122//----------------------------------------------------------------------------- 123 124inline bool TamlXmlParser::parseElement( TiXmlElement* pXmlElement, TamlVisitor& visitor ) 125{ 126 // Debug Profiling. 127 PROFILE_SCOPE(TamlXmlParser_ParseElement); 128 129 // Parse attributes (stop processing if instructed). 130 if ( !parseAttributes( pXmlElement, visitor ) ) 131 return false; 132 133 // Finish if only the root is needed. 134 if ( visitor.wantsRootOnly() ) 135 return false; 136 137 // Fetch any children. 138 TiXmlNode* pChildXmlNode = pXmlElement->FirstChild(); 139 140 // Do we have any element children? 141 if ( pChildXmlNode != NULL && pChildXmlNode->Type() == TiXmlNode::TINYXML_ELEMENT ) 142 { 143 // Iterate children. 144 for ( TiXmlElement* pChildXmlElement = dynamic_cast<TiXmlElement*>( pChildXmlNode ); pChildXmlElement; pChildXmlElement = pChildXmlElement->NextSiblingElement() ) 145 { 146 // Parse element (stop processing if instructed). 147 if ( !parseElement( pChildXmlElement, visitor ) ) 148 return false; 149 } 150 } 151 152 return true; 153} 154 155//----------------------------------------------------------------------------- 156 157inline bool TamlXmlParser::parseAttributes( TiXmlElement* pXmlElement, TamlVisitor& visitor ) 158{ 159 // Debug Profiling. 160 PROFILE_SCOPE(TamlXmlParser_ParseAttribute); 161 162 // Calculate if element is at the root or not. 163 const bool isRoot = pXmlElement->GetDocument()->RootElement() == pXmlElement; 164 165 // Create a visitor property state. 166 TamlVisitor::PropertyState propertyState; 167 propertyState.setObjectName( pXmlElement->Value(), isRoot ); 168 169 // Iterate attributes. 170 for ( TiXmlAttribute* pAttribute = pXmlElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->Next() ) 171 { 172 // Configure property state. 173 propertyState.setProperty( pAttribute->Name(), pAttribute->Value() ); 174 175 // Visit this attribute. 176 const bool visitStatus = visitor.visit( *this, propertyState ); 177 178 // Was the property value changed? 179 if ( propertyState.getPropertyValueDirty() ) 180 { 181 // Yes, so update the attribute. 182 pAttribute->SetValue( propertyState.getPropertyValue() ); 183 184 // Flag the document as dirty. 185 mDocumentDirty = true; 186 } 187 188 // Finish if requested. 189 if ( !visitStatus ) 190 return false; 191 } 192 193 return true; 194} 195