Home | History | Annotate | Download | only in dae
      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