187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk/*
287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk* Copyright 2006 Sony Computer Entertainment Inc.
387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk*
487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk* Licensed under the MIT Open Source License, for details please see license.txt or the website
587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk* http://www.opensource.org/licenses/mit-license.php
687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk*
787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk*/
887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk// The user can choose whether or not to include libxml support in the DOM. Supporting libxml will
1087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk// require linking against it. By default libxml support is included.
1187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#if defined(DOM_INCLUDE_LIBXML)
1287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
1387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk// This is a rework of the XML plugin that contains a complete interface to libxml2 "readXML"
1487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk// This is intended to be a seperate plugin but I'm starting out by rewriting it in daeLIBXMLPlugin
1587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk// because I'm not sure if all the plugin handling stuff has been tested.  Once I get a working
1687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk// plugin I'll look into renaming it so the old daeLIBXMLPlugin can coexist with it.
1787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk//
1887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#include <string>
1987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#include <sstream>
2087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#include <modules/daeLIBXMLPlugin.h>
2187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#include <dae.h>
2287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#include <dom.h>
2387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#include <dae/daeDatabase.h>
2487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#include <dae/daeMetaElement.h>
2587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#include <libxml/xmlreader.h>
2687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#include <libxml/xmlwriter.h>
2787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#include <libxml/xmlmemory.h>
2887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#include <dae/daeErrorHandler.h>
2987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#include <dae/daeMetaElementAttribute.h>
3087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
3187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchoukusing namespace std;
3287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
3387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
3487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk// Some helper functions for working with libxml
3587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouknamespace {
3687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	daeInt getCurrentLineNumber(xmlTextReaderPtr reader) {
3787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#if LIBXML_VERSION >= 20620
3887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	return xmlTextReaderGetParserLineNumber(reader);
3987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#else
4087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	return -1;
4187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#endif
4287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
4387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
4487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	// Return value should be freed by caller with delete[]. Passed in value should not
4587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	// be null.
4687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlChar* utf8ToLatin1(const xmlChar* utf8) {
4787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		int inLen = xmlStrlen(utf8);
4887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		int outLen = (inLen+1) * 2;
4987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		xmlChar* latin1 = new xmlChar[outLen];
5087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		int numBytes = UTF8Toisolat1(latin1, &outLen, utf8, &inLen);
5187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if (numBytes < 0)
5287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			// Failed. Return an empty string instead.
5387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			numBytes = 0;
5487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
5587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		latin1[numBytes] = '\0';
5687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		return latin1;
5787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
5887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
5987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	// Return value should be freed by caller with delete[].
6087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlChar* latin1ToUtf8(const string& latin1) {
6187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		int inLen = (int)latin1.length();
6287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		int outLen = (inLen+1) * 2;
6387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		xmlChar* utf8 = new xmlChar[outLen];
6487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		int numBytes = isolat1ToUTF8(utf8, &outLen, (xmlChar*)latin1.c_str(), &inLen);
6587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if (numBytes < 0)
6687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			// Failed. Return an empty string instead.
6787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			numBytes = 0;
6887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
6987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		utf8[numBytes] = '\0';
7087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		return utf8;
7187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
7287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
7387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	typedef pair<daeString, daeString> stringPair;
7487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
7587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	// The attributes vector passed in should be empty. If 'encoding' is anything
7687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	// other than utf8 the caller should free the returned attribute value
7787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	// strings. The 'freeAttrValues' function is provided for that purpose.
7887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	void packageCurrentAttributes(xmlTextReaderPtr reader,
7987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	                              DAE::charEncoding encoding,
8087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	                              /* out */ vector<stringPair>& attributes) {
8187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		int numAttributes = xmlTextReaderAttributeCount(reader);
8287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if (numAttributes == -1 || numAttributes == 0)
8387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			return;
8487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		attributes.reserve(numAttributes);
8587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
8687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		while (xmlTextReaderMoveToNextAttribute(reader) == 1) {
8787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			const xmlChar* xmlName = xmlTextReaderConstName(reader);
8887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			const xmlChar* xmlValue = xmlTextReaderConstValue(reader);
8987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			if (encoding == DAE::Latin1)
9087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				attributes.push_back(stringPair((daeString)xmlName, (daeString)utf8ToLatin1(xmlValue)));
9187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			else
9287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				attributes.push_back(stringPair((daeString)xmlName, (daeString)xmlValue));
9387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
9487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
9587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
9687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	void freeAttrValues(vector<stringPair>& pairs) {
9787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		for(size_t i=0, size=pairs.size(); i<size; ++i) {
9887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			delete[] pairs[i].second;
9987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			pairs[i].second = 0;
10087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
10187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
10287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk}
10387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
10487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex SakhartchoukdaeLIBXMLPlugin::daeLIBXMLPlugin(DAE& dae) : dae(dae), rawRelPath(dae)
10587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk{
10687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	supportedProtocols.push_back("*");
10787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlInitParser();
10887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	rawFile = NULL;
10987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	rawByteCount = 0;
11087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	saveRawFile = false;
11187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk}
11287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
11387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex SakhartchoukdaeLIBXMLPlugin::~daeLIBXMLPlugin()
11487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk{
11587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	 xmlCleanupParser();
11687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk}
11787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
11887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex SakhartchoukdaeInt daeLIBXMLPlugin::setOption( daeString option, daeString value )
11987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk{
12087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if ( strcmp( option, "saveRawBinary" ) == 0 )
12187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	{
12287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if ( strcmp( value, "true" ) == 0 || strcmp( value, "TRUE" ) == 0 )
12387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		{
12487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			saveRawFile = true;
12587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
12687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		else
12787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		{
12887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			saveRawFile = false;
12987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
13087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		return DAE_OK;
13187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
13287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	return DAE_ERR_INVALID_CALL;
13387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk}
13487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
13587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex SakhartchoukdaeString daeLIBXMLPlugin::getOption( daeString option )
13687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk{
13787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if ( strcmp( option, "saveRawBinary" ) == 0 )
13887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	{
13987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if ( saveRawFile )
14087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		{
14187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			return "true";
14287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
14387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		return "false";
14487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
14587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	return NULL;
14687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk}
14787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
14887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouknamespace {
14987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	void libxmlErrorHandler(void* arg,
15087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	                        const char* msg,
15187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	                        xmlParserSeverities severity,
15287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	                        xmlTextReaderLocatorPtr locator) {
15387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if(severity == XML_PARSER_SEVERITY_VALIDITY_WARNING  ||
15487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		   severity == XML_PARSER_SEVERITY_WARNING) {
15587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			daeErrorHandler::get()->handleWarning(msg);
15687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
15787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		else
15887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			daeErrorHandler::get()->handleError(msg);
15987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
16087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk}
16187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
16287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk// A simple structure to help alloc/free xmlTextReader objects
16387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchoukstruct xmlTextReaderHelper {
16487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlTextReaderHelper(const daeURI& uri) {
16587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if((reader = xmlReaderForFile(cdom::fixUriForLibxml(uri.str()).c_str(), NULL, 0)))
16687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		   xmlTextReaderSetErrorHandler(reader, libxmlErrorHandler, NULL);
16787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
16887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
16987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlTextReaderHelper(daeString buffer, const daeURI& baseUri) {
17087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if((reader = xmlReaderForDoc((xmlChar*)buffer, cdom::fixUriForLibxml(baseUri.str()).c_str(), NULL, 0)))
17187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			xmlTextReaderSetErrorHandler(reader, libxmlErrorHandler, NULL);
17287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	};
17387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
17487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	~xmlTextReaderHelper() {
17587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if (reader)
17687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			xmlFreeTextReader(reader);
17787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
17887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
17987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlTextReaderPtr reader;
18087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk};
18187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
18287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex SakhartchoukdaeElementRef daeLIBXMLPlugin::readFromFile(const daeURI& uri) {
18387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlTextReaderHelper readerHelper(uri);
18487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if (!readerHelper.reader) {
18587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		daeErrorHandler::get()->handleError((string("Failed to open ") + uri.str() +
18687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		                                    " in daeLIBXMLPlugin::readFromFile\n").c_str());
18787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		return NULL;
18887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
18987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	return read(readerHelper.reader);
19087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk}
19187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
19287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex SakhartchoukdaeElementRef daeLIBXMLPlugin::readFromMemory(daeString buffer, const daeURI& baseUri) {
19387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlTextReaderHelper readerHelper(buffer, baseUri);
19487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if (!readerHelper.reader) {
19587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		daeErrorHandler::get()->handleError("Failed to open XML document from memory buffer in "
19687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		                                    "daeLIBXMLPlugin::readFromMemory\n");
19787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		return NULL;
19887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
19987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	return read(readerHelper.reader);
20087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk}
20187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
20287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex SakhartchoukdaeElementRef daeLIBXMLPlugin::read(_xmlTextReader* reader) {
20387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	// Drop everything up to the first element. In the future, we should try to store header comments somewhere.
20487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	while(xmlTextReaderNodeType(reader) != XML_READER_TYPE_ELEMENT)
20587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	{
20687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if (xmlTextReaderRead(reader) != 1) {
20787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			daeErrorHandler::get()->handleError("Error parsing XML in daeLIBXMLPlugin::read\n");
20887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			return NULL;
20987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
21087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
21187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
21287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	int readRetVal = 0;
21387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	return readElement(reader, NULL, readRetVal);
21487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk}
21587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
21687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex SakhartchoukdaeElementRef daeLIBXMLPlugin::readElement(_xmlTextReader* reader,
21787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk                                           daeElement* parentElement,
21887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk                                           /* out */ int& readRetVal) {
21987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	assert(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT);
22087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	daeString elementName = (daeString)xmlTextReaderConstName(reader);
22187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	bool empty = xmlTextReaderIsEmptyElement(reader) != 0;
22287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
22387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	vector<attrPair> attributes;
22487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	packageCurrentAttributes(reader, dae.getCharEncoding(), /* out */ attributes);
22587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
22687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	daeElementRef element = beginReadElement(parentElement, elementName, attributes, getCurrentLineNumber(reader));
22787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if (dae.getCharEncoding() != DAE::Utf8)
22887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		freeAttrValues(attributes);
22987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
23087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if (!element) {
23187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		// We couldn't create the element. beginReadElement already printed an error message. Just make sure
23287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		// to skip ahead past the bad element.
23387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		xmlTextReaderNext(reader);
23487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		return NULL;
23587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
23687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
23787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if ((readRetVal = xmlTextReaderRead(reader)) == -1)
23887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		return NULL;
23987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if (empty)
24087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		return element;
24187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
24287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	int nodeType = xmlTextReaderNodeType(reader);
24387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	while (readRetVal == 1  &&  nodeType != XML_READER_TYPE_END_ELEMENT) {
24487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if (nodeType == XML_READER_TYPE_ELEMENT) {
24587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			element->placeElement(readElement(reader, element, readRetVal));
24687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
24787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		else if (nodeType == XML_READER_TYPE_TEXT) {
24887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			const xmlChar* xmlText = xmlTextReaderConstValue(reader);
24987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			if (dae.getCharEncoding() == DAE::Latin1)
25087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				xmlText = utf8ToLatin1(xmlText);
25187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			readElementText(element, (daeString)xmlText, getCurrentLineNumber(reader));
25287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			if (dae.getCharEncoding() == DAE::Latin1)
25387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				delete[] xmlText;
25487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
25587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			readRetVal = xmlTextReaderRead(reader);
25687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
25787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		else
25887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			readRetVal = xmlTextReaderRead(reader);
25987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
26087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		nodeType = xmlTextReaderNodeType(reader);
26187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
26287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
26387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if (nodeType == XML_READER_TYPE_END_ELEMENT)
26487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		readRetVal = xmlTextReaderRead(reader);
26587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
26687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if (readRetVal == -1) // Something went wrong (bad xml probably)
26787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		return NULL;
26887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
26987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	return element;
27087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk}
27187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
27287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex SakhartchoukdaeInt daeLIBXMLPlugin::write(const daeURI& name, daeDocument *document, daeBool replace)
27387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk{
27487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	// Make sure database and document are both set
27587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if (!database)
27687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		return DAE_ERR_INVALID_CALL;
27787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if(!document)
27887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		return DAE_ERR_COLLECTION_DOES_NOT_EXIST;
27987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
28087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	// Convert the URI to a file path, to see if we're about to overwrite a file
28187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	string file = cdom::uriToNativePath(name.str());
28287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if (file.empty()  &&  saveRawFile)
28387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	{
28487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		daeErrorHandler::get()->handleError( "can't get path in write\n" );
28587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		return DAE_ERR_BACKEND_IO;
28687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
28787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
28887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	// If replace=false, don't replace existing files
28987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if(!replace)
29087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	{
29187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		// Using "stat" would be better, but it's not available on all platforms
29287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		FILE *tempfd = fopen(file.c_str(), "r");
29387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if(tempfd != NULL)
29487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		{
29587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			// File exists, return error
29687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			fclose(tempfd);
29787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			return DAE_ERR_BACKEND_FILE_EXISTS;
29887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
29987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		fclose(tempfd);
30087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
30187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if ( saveRawFile )
30287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	{
30387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		string rawFilePath = file + ".raw";
30487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if ( !replace )
30587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		{
30687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			rawFile = fopen(rawFilePath.c_str(), "rb" );
30787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			if ( rawFile != NULL )
30887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			{
30987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				fclose(rawFile);
31087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				return DAE_ERR_BACKEND_FILE_EXISTS;
31187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			}
31287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			fclose(rawFile);
31387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
31487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		rawFile = fopen(rawFilePath.c_str(), "wb");
31587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if ( rawFile == NULL )
31687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		{
31787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			return DAE_ERR_BACKEND_IO;
31887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
31987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		rawRelPath.set(cdom::nativePathToUri(rawFilePath));
32087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		rawRelPath.makeRelativeTo( &name );
32187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
32287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
32387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	// Open the file we will write to
32487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	writer = xmlNewTextWriterFilename(cdom::fixUriForLibxml(name.str()).c_str(), 0);
32587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if ( !writer ) {
32687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		ostringstream msg;
32787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		msg << "daeLIBXMLPlugin::write(" << name.str() << ") failed\n";
32887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		daeErrorHandler::get()->handleError(msg.str().c_str());
32987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		return DAE_ERR_BACKEND_IO;
33087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
33187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlTextWriterSetIndentString( writer, (const xmlChar*)"\t" ); // Don't change this to spaces
33287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlTextWriterSetIndent( writer, 1 ); // Turns indentation on
33387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk    xmlTextWriterStartDocument( writer, "1.0", "UTF-8", NULL );
33487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
33587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	writeElement( document->getDomRoot() );
33687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
33787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlTextWriterEndDocument( writer );
33887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlTextWriterFlush( writer );
33987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlFreeTextWriter( writer );
34087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
34187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if ( saveRawFile && rawFile != NULL )
34287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	{
34387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		fclose( rawFile );
34487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
34587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
34687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	return DAE_OK;
34787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk}
34887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
34987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchoukvoid daeLIBXMLPlugin::writeElement( daeElement* element )
35087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk{
35187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	daeMetaElement* _meta = element->getMeta();
35287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
35387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	//intercept <source> elements for special handling
35487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if ( saveRawFile )
35587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	{
35687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if ( strcmp( element->getTypeName(), "source" ) == 0 )
35787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		{
35887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			daeElementRefArray children;
35987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			element->getChildren( children );
36087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			bool validArray = false, teqCommon = false;
36187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			for ( unsigned int i = 0; i < children.getCount(); i++ )
36287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			{
36387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				if ( strcmp( children[i]->getTypeName(), "float_array" ) == 0 ||
36487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk					 strcmp( children[i]->getTypeName(), "int_array" ) == 0 )
36587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				{
36687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk					validArray = true;
36787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				}
36887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				else if ( strcmp( children[i]->getTypeName(), "technique_common" ) == 0 )
36987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				{
37087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk					teqCommon = true;
37187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				}
37287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			}
37387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			if ( validArray && teqCommon )
37487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			{
37587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				writeRawSource( element );
37687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				return;
37787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			}
37887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
37987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
38087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
38187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if (!_meta->getIsTransparent() ) {
38287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		xmlTextWriterStartElement(writer, (xmlChar*)element->getElementName());
38387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		daeMetaAttributeRefArray& attrs = _meta->getMetaAttributes();
38487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
38587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		int acnt = (int)attrs.getCount();
38687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
38787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		for(int i=0;i<acnt;i++) {
38887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			writeAttribute(attrs[i], element);
38987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
39087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
39187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	writeValue(element);
39287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
39387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	daeElementRefArray children;
39487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	element->getChildren( children );
39587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	for ( size_t x = 0; x < children.getCount(); x++ ) {
39687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		writeElement( children.get(x) );
39787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
39887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
39987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	/*if (_meta->getContents() != NULL) {
40087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		daeElementRefArray* era = (daeElementRefArray*)_meta->getContents()->getWritableMemory(element);
40187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		int elemCnt = (int)era->getCount();
40287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		for(int i = 0; i < elemCnt; i++) {
40387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			daeElementRef elem = (daeElementRef)era->get(i);
40487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			if (elem != NULL) {
40587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				writeElement( elem );
40687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			}
40787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
40887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
40987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	else
41087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	{
41187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		daeMetaElementAttributeArray& children = _meta->getMetaElements();
41287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		int cnt = (int)children.getCount();
41387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		for(int i=0;i<cnt;i++) {
41487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			daeMetaElement *type = children[i]->getElementType();
41587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			if ( !type->getIsAbstract() ) {
41687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				for (int c = 0; c < children[i]->getCount(element); c++ ) {
41787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk					writeElement( *(daeElementRef*)children[i]->get(element,c) );
41887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				}
41987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			}
42087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
42187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}*/
42287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if (!_meta->getIsTransparent() ) {
42387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		xmlTextWriterEndElement(writer);
42487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
42587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk}
42687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
42787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchoukvoid daeLIBXMLPlugin::writeAttribute( daeMetaAttribute* attr, daeElement* element)
42887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk{
42987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	ostringstream buffer;
43087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	attr->memoryToString(element, buffer);
43187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	string str = buffer.str();
43287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
43387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	// Don't write the attribute if
43487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	//  - The attribute isn't required AND
43587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	//     - The attribute has no default value and the current value is ""
43687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	//     - The attribute has a default value and the current value matches the default
43787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if (!attr->getIsRequired()) {
43887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if(!attr->getDefaultValue()  &&  str.empty())
43987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			return;
44087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if(attr->getDefaultValue()  &&  attr->compareToDefault(element) == 0)
44187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			return;
44287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
44387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
44487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlTextWriterStartAttribute(writer, (xmlChar*)(daeString)attr->getName());
44587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlChar* utf8 = (xmlChar*)str.c_str();
44687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if (dae.getCharEncoding() == DAE::Latin1)
44787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		utf8 = latin1ToUtf8(str);
44887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlTextWriterWriteString(writer, utf8);
44987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if (dae.getCharEncoding() == DAE::Latin1)
45087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		delete[] utf8;
45187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
45287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	xmlTextWriterEndAttribute(writer);
45387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk}
45487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
45587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchoukvoid daeLIBXMLPlugin::writeValue(daeElement* element) {
45687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if (daeMetaAttribute* attr = element->getMeta()->getValueAttribute()) {
45787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		ostringstream buffer;
45887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		attr->memoryToString(element, buffer);
45987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		string s = buffer.str();
46087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if (!s.empty()) {
46187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			xmlChar* str = (xmlChar*)s.c_str();
46287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			if (dae.getCharEncoding() == DAE::Latin1)
46387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				str = latin1ToUtf8(s);
46487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			xmlTextWriterWriteString(writer, (xmlChar*)s.c_str());
46587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			if (dae.getCharEncoding() == DAE::Latin1)
46687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk				delete[] str;
46787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
46887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
46987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk}
47087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
47187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchoukvoid daeLIBXMLPlugin::writeRawSource( daeElement *src )
47287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk{
47387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	daeElementRef newSrc = src->clone();
47487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	daeElementRef array = NULL;
47587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	daeElement *accessor = NULL;
47687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	daeElementRefArray children;
47787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	newSrc->getChildren( children );
47887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	bool isInt = false;
47987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	for ( int i = 0; i < (int)children.getCount(); i++ )
48087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	{
48187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		if ( strcmp( children[i]->getTypeName(), "float_array" ) == 0 )
48287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		{
48387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			array = children[i];
48487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			newSrc->removeChildElement( array );
48587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
48687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		else if ( strcmp( children[i]->getTypeName(), "int_array" ) == 0 )
48787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		{
48887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			array = children[i];
48987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			isInt = true;
49087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			newSrc->removeChildElement( array );
49187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
49287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		else if ( strcmp( children[i]->getTypeName(), "technique_common" ) == 0 )
49387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		{
49487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			children[i]->getChildren( children );
49587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
49687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		else if ( strcmp( children[i]->getTypeName(), "accessor" ) == 0 )
49787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		{
49887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			accessor = children[i];
49987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
50087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
50187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
50287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	daeULong *countPtr = (daeULong*)array->getAttributeValue( "count" );
50387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	daeULong count = countPtr != NULL ? *countPtr : 0;
50487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
50587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	daeULong *stridePtr = (daeULong*)accessor->getAttributeValue( "stride" );
50687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	daeULong stride = stridePtr != NULL ? *stridePtr : 1;
50787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
50887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	children.clear();
50987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	accessor->getChildren( children );
51087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if ( children.getCount() > stride ) {
51187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		*stridePtr = children.getCount();
51287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
51387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
51487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	daeFixedName newURI;
51587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	sprintf( newURI, "%s#%ld", rawRelPath.getOriginalURI(), rawByteCount );
51687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	accessor->setAttribute( "source", newURI );
51787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
51887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	daeArray *valArray = (daeArray*)array->getValuePointer();
51987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
52087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	//TODO: pay attention to precision for the array.
52187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	if ( isInt )
52287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	{
52387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		for( size_t i = 0; i < count; i++ )
52487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		{
52587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			daeInt tmp = (daeInt)*(daeLong*)(valArray->getRaw(i));
52687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			rawByteCount += (unsigned long)(fwrite( &tmp, sizeof(daeInt), 1, rawFile ) * sizeof(daeInt));
52787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
52887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
52987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	else
53087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	{
53187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		for( size_t i = 0; i < count; i++ )
53287ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		{
53387ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			daeFloat tmp = (daeFloat)*(daeDouble*)(valArray->getRaw(i));
53487ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk			rawByteCount += (unsigned long)(fwrite( &tmp, sizeof(daeFloat), 1, rawFile ) * sizeof(daeFloat));
53587ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk		}
53687ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	}
53787ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
53887ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk	writeElement( newSrc );
53987ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk}
54087ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk
54187ac3e2db6d5ae163131102c066e9d19bdfdc139Alex Sakhartchouk#endif // DOM_INCLUDE_LIBXML
542