1 /* 2 * Copyright 2006 Sony Computer Entertainment Inc. 3 * 4 * Licensed under the MIT Open Source License, for details please see license.txt or the website 5 * http://www.opensource.org/licenses/mit-license.php 6 * 7 */ 8 9 // The user can choose whether or not to include TinyXML support in the DOM. Supporting TinyXML will 10 // require linking against it. By default TinyXML support isn't included. 11 #if defined(DOM_INCLUDE_TINYXML) 12 13 #if defined(DOM_DYNAMIC) && defined(_MSC_VER) 14 #pragma comment(lib, "tinyxml.lib") 15 #endif 16 17 #if defined(_MSC_VER) 18 #pragma warning(disable: 4100) // warning C4100: 'element' : unreferenced formal parameter 19 #endif 20 21 #include <string> 22 #include <tinyxml.h> 23 #include <dae.h> 24 #include <dom.h> 25 #include <dae/daeMetaElement.h> 26 #include <dae/daeErrorHandler.h> 27 #include <dae/daeMetaElementAttribute.h> 28 #include <dae/daeTinyXMLPlugin.h> 29 #include <dae/daeDocument.h> 30 31 using namespace std; 32 33 namespace { 34 daeInt getCurrentLineNumber(TiXmlElement* element) { 35 return -1; 36 } 37 } 38 39 daeTinyXMLPlugin::daeTinyXMLPlugin() 40 { 41 m_doc = NULL; 42 supportedProtocols.push_back("*"); 43 } 44 45 daeTinyXMLPlugin::~daeTinyXMLPlugin() 46 { 47 } 48 49 daeInt daeTinyXMLPlugin::setOption( daeString option, daeString value ) 50 { 51 return DAE_ERR_INVALID_CALL; 52 } 53 54 daeString daeTinyXMLPlugin::getOption( daeString option ) 55 { 56 return NULL; 57 } 58 59 daeElementRef daeTinyXMLPlugin::readFromFile(const daeURI& uri) { 60 string file = cdom::uriToNativePath(uri.str()); 61 if (file.empty()) 62 return NULL; 63 TiXmlDocument doc; 64 doc.LoadFile(file.c_str()); 65 if (!doc.RootElement()) { 66 daeErrorHandler::get()->handleError((std::string("Failed to open ") + uri.str() + 67 " in daeTinyXMLPlugin::readFromFile\n").c_str()); 68 return NULL; 69 } 70 return readElement(doc.RootElement(), NULL); 71 } 72 73 daeElementRef daeTinyXMLPlugin::readFromMemory(daeString buffer, const daeURI& baseUri) { 74 TiXmlDocument doc; 75 doc.Parse(buffer); 76 if (!doc.RootElement()) { 77 daeErrorHandler::get()->handleError("Failed to open XML document from memory buffer in " 78 "daeTinyXMLPlugin::readFromMemory\n"); 79 return NULL; 80 } 81 return readElement(doc.RootElement(), NULL); 82 } 83 84 daeElementRef daeTinyXMLPlugin::readElement(TiXmlElement* tinyXmlElement, daeElement* parentElement) { 85 std::vector<attrPair> attributes; 86 for (TiXmlAttribute* attrib = tinyXmlElement->FirstAttribute(); attrib != NULL; attrib = attrib->Next()) 87 attributes.push_back(attrPair(attrib->Name(), attrib->Value())); 88 89 daeElementRef element = beginReadElement(parentElement, tinyXmlElement->Value(), 90 attributes, getCurrentLineNumber(tinyXmlElement)); 91 if (!element) { 92 // We couldn't create the element. beginReadElement already printed an error message. 93 return NULL; 94 } 95 96 if (tinyXmlElement->GetText() != NULL) 97 readElementText(element, tinyXmlElement->GetText(), getCurrentLineNumber(tinyXmlElement)); 98 99 // Recurse children 100 for (TiXmlElement* child = tinyXmlElement->FirstChildElement(); child != NULL; child = child->NextSiblingElement()) 101 element->placeElement(readElement(child, element)); 102 103 return element; 104 } 105 106 daeInt daeTinyXMLPlugin::write(const daeURI& name, daeDocument *document, daeBool replace) 107 { 108 // Make sure database and document are both set 109 if (!database) 110 return DAE_ERR_INVALID_CALL; 111 if(!document) 112 return DAE_ERR_COLLECTION_DOES_NOT_EXIST; 113 114 string fileName = cdom::uriToNativePath(name.str()); 115 if (fileName.empty()) 116 { 117 daeErrorHandler::get()->handleError( "can't get path in write\n" ); 118 return DAE_ERR_BACKEND_IO; 119 } 120 // If replace=false, don't replace existing files 121 if(!replace) 122 { 123 // Using "stat" would be better, but it's not available on all platforms 124 FILE *tempfd = fopen(fileName.c_str(), "r"); 125 if(tempfd != NULL) 126 { 127 // File exists, return error 128 fclose(tempfd); 129 return DAE_ERR_BACKEND_FILE_EXISTS; 130 } 131 fclose(tempfd); 132 } 133 134 m_doc = new TiXmlDocument(name.getURI()); 135 if (m_doc) 136 { 137 m_doc->SetTabSize(4); 138 139 TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" ); 140 m_doc->LinkEndChild( decl ); 141 142 writeElement(document->getDomRoot()); 143 144 m_doc->SaveFile(fileName.c_str()); 145 delete m_doc; 146 m_doc = NULL; 147 } 148 return DAE_OK; 149 } 150 151 void daeTinyXMLPlugin::writeElement( daeElement* element ) 152 { 153 daeMetaElement* _meta = element->getMeta(); 154 if (!_meta->getIsTransparent() ) 155 { 156 TiXmlElement* tiElm = new TiXmlElement( element->getElementName() ); 157 158 if (m_elements.empty() == true) { 159 m_doc->LinkEndChild(tiElm); 160 } else { 161 TiXmlElement* first = m_elements.front(); 162 first->LinkEndChild(tiElm); 163 } 164 m_elements.push_front(tiElm); 165 166 daeMetaAttributeRefArray& attrs = _meta->getMetaAttributes(); 167 168 int acnt = (int)attrs.getCount(); 169 170 for(int i=0;i<acnt;i++) 171 { 172 writeAttribute( attrs[i], element ); 173 } 174 } 175 writeValue(element); 176 177 daeElementRefArray children; 178 element->getChildren( children ); 179 for ( size_t x = 0; x < children.getCount(); x++ ) 180 { 181 writeElement( children.get(x) ); 182 } 183 184 if (!_meta->getIsTransparent() ) 185 { 186 m_elements.pop_front(); 187 } 188 } 189 190 191 void daeTinyXMLPlugin::writeValue( daeElement* element ) 192 { 193 if (daeMetaAttribute* attr = element->getMeta()->getValueAttribute()) { 194 std::ostringstream buffer; 195 attr->memoryToString(element, buffer); 196 std::string s = buffer.str(); 197 if (!s.empty()) 198 m_elements.front()->LinkEndChild( new TiXmlText(buffer.str().c_str()) ); 199 } 200 } 201 202 void daeTinyXMLPlugin::writeAttribute( daeMetaAttribute* attr, daeElement* element ) 203 { 204 ostringstream buffer; 205 attr->memoryToString(element, buffer); 206 string str = buffer.str(); 207 208 // Don't write the attribute if 209 // - The attribute isn't required AND 210 // - The attribute has no default value and the current value is "" 211 // - The attribute has a default value and the current value matches the default 212 if (!attr->getIsRequired()) { 213 if(!attr->getDefaultValue() && str.empty()) 214 return; 215 if(attr->getDefaultValue() && attr->compareToDefault(element) == 0) 216 return; 217 } 218 219 m_elements.front()->SetAttribute(attr->getName(), str.c_str()); 220 } 221 222 #endif // DOM_INCLUDE_TINYXML 223