blob: c8eb0eaa7e03ee958fe54d5e8643665374981392 [file] [log] [blame]
/*
* Copyright 2006 Sony Computer Entertainment Inc.
*
* Licensed under the MIT Open Source License, for details please see license.txt or the website
* http://www.opensource.org/licenses/mit-license.php
*
*/
#include <modules/daeSTLDatabase.h>
#include <dae/daeMetaElement.h>
using namespace std;
daeSTLDatabase::daeSTLDatabase(DAE& dae) : daeDatabase(dae)
{ }
daeSTLDatabase::~daeSTLDatabase()
{
clear();
}
daeInt daeSTLDatabase::setMeta(daeMetaElement *_topMeta)
{
topMeta = _topMeta;
return DAE_OK;
}
daeBool
daeSTLDatabase::isDocumentLoaded(daeString name)
{
daeDocument* document = getDocument(name);
if(document)
return(true);
else
return(false);
}
// Element Types of all Elements
daeUInt daeSTLDatabase::getTypeCount()
{
return (daeUInt)elements.size();
}
daeString daeSTLDatabase::getTypeName(daeUInt index)
{
daeUInt count = 0;
map<string, vector< daeElement* > >::iterator iter = elements.begin();
map<string, vector< daeElement* > >::iterator end = elements.end();
while ( iter != end )
{
if ( count == index )
{
return (*iter).first.c_str();
}
++count;
++iter;
}
return NULL;
}
// Documents
daeInt daeSTLDatabase::insertDocument(const char *name, daeElement* dom, daeDocument** document, bool zaeRootDocument, const std::string& extractedFileURI)
{
return createDocument( name, dom, document, zaeRootDocument, extractedFileURI );
}
daeInt daeSTLDatabase::createDocument(const char *name, daeElement* dom, daeDocument** document, bool zaeRootDocument, const std::string& extractedFileURI)
{
// If a document already exists with the same name, error
if(isDocumentLoaded(name))
{
if (document)
*document = NULL;
return DAE_ERR_COLLECTION_ALREADY_EXISTS;
}
// Make a new document
daeDocument *newDocument = new daeDocument(dae, zaeRootDocument, extractedFileURI);
newDocument->getDocumentURI()->setURI(name);
newDocument->setDomRoot(dom);
// Push the connection into the database
documents.push_back(newDocument);
if (document)
*document = newDocument;
return DAE_OK;
}
// !!!GAC revised version of insertDocument, creates a domCollada and fills it in for you.
daeInt daeSTLDatabase::insertDocument(const char *name, daeDocument** document)
{
return createDocument( name, document );
}
daeInt daeSTLDatabase::createDocument(const char *name, daeDocument** document)
{
// If a document already exists with the same name, error
if(isDocumentLoaded(name))
{
if (document)
*document = NULL;
return DAE_ERR_COLLECTION_ALREADY_EXISTS;
}
// Make the new document
daeDocument *newDocument = new daeDocument(dae);
// Make a domCOLLADA to be the root of this new document (this makes a reference so the domCOLLADA won't delete itself
daeElementRef myCOLLADA = topMeta->create();
myCOLLADA->setDocument(newDocument);
newDocument->getDocumentURI()->setURI(name);
newDocument->setDomRoot(myCOLLADA);
// Add this document to the list.
documents.push_back(newDocument);
// If the user gave us a place to put the document, send it back to them.
if (document)
*document = newDocument;
return DAE_OK;
}
daeInt daeSTLDatabase::insertDocument( daeDocument *c ) {
documents.push_back(c);
insertElement( c, c->getDomRoot() );
return DAE_OK;
}
daeInt daeSTLDatabase::removeDocument(daeDocument *document)
{
vector< daeDocument* >::iterator iter = documents.begin();
while ( iter != documents.end() ) {
if ( (*iter) == document ) {
//delete all of its children
removeElement( *iter, (*iter)->getDomRoot() );
delete *iter; // sthomas (see bug 1466019)
iter = documents.erase(iter);
}
else {
iter++;
}
}
return DAE_OK;
}
daeUInt daeSTLDatabase::getDocumentCount()
{
return (daeUInt)documents.size();
}
daeDocument* daeSTLDatabase::getDocument(daeUInt index)
{
if (index<documents.size())
return (documents[index]);
else
return NULL;
}
daeDocument* daeSTLDatabase::getDocument(daeString name_, bool skipUriNormalization)
{
string name = name_;
if (!skipUriNormalization) {
// Normalize the input string to an absolute URI with no fragment
name = daeURI(dae, name, true).str();
}
// Try to find a document that matches
daeDocument *document;
int documentCount = getDocumentCount();
for (int i=0;i<documentCount;i++)
{
document = getDocument(i);
if(document->getDocumentURI()->str() == name)
return(document);
}
return(NULL);
}
daeString daeSTLDatabase::getDocumentName(daeUInt index)
{
if (index<documents.size())
return getDocument(index)->getDocumentURI()->getURI();
else
return NULL;
}
// Elements
daeInt daeSTLDatabase::insertElement(daeDocument* document,daeElement* element)
{
insertChildren( document, element );
map<string, vector< daeElement* > >::iterator iter = elements.find( string( element->getTypeName() ) );
if ( iter != elements.end() )
{
(*iter).second.push_back( element );
}
else
{
vector< daeElement* > vec;
vec.push_back( element );
elements.insert( make_pair( string( element->getTypeName() ), vec ) );
}
// Insert into the type ID map
typeMap.insert(make_pair(element->typeID(), element));
//insert into IDMap if element has an ID. IDMap is used to speed up URI resolution
if ( element->getID() != NULL ) {
elementsIDMap.insert( make_pair( string( element->getID() ), element ) );
}
// Insert into sid map if the element has a sid
// string sid = element->getAttribute("sid");
// if (!sid.empty())
// sidMap.insert(sidMapPair(sid, element));
dae.getSidRefCache().clear();
return DAE_OK;
}
daeInt daeSTLDatabase::insertChildren( daeDocument *c, daeElement *element )
{
daeElementRefArray era;
element->getChildren( era );
for ( unsigned int i = 0; i < era.getCount(); i++ ) {
insertElement( c, era[i] );
}
return DAE_OK;
}
daeInt daeSTLDatabase::removeElement(daeDocument* document,daeElement* element)
{
if ( !element ) {
return DAE_ERR_INVALID_CALL;
}
removeChildren( document, element );
map<string, vector< daeElement* > >::iterator iter = elements.find( string( element->getTypeName() ) );
if ( iter != elements.end() )
{
vector< daeElement* > &vec = (*iter).second;
vector< daeElement* >::iterator i = vec.begin();
vector< daeElement* >::iterator end = vec.end();
while( i != end )
{
if ( (*i) == element )
{
vec.erase( i );
break;
}
++i;
}
}
typeMapRange range = typeMap.equal_range(element->typeID());
for (typeMapIter iter = range.first; iter != range.second; iter++) {
if (iter->second == element) {
typeMap.erase(iter);
break;
}
}
if ( element->getID() != NULL ) {
idMapRange range = elementsIDMap.equal_range( string( element->getID() ) );
multimap<string, daeElement* >::iterator iter = range.first;
while( iter != range.second ) {
if ( (*iter).second == element ) {
elementsIDMap.erase( iter );
break;
}
++iter;
}
}
// string sid = element->getAttribute("sid");
// if (!sid.empty()) {
// pair<sidMapIter, sidMapIter> range = sidMap.equal_range(sid);
// for (sidMapIter iter = range.first; iter != range.second; iter++) {
// if (iter->second == element) {
// sidMap.erase(iter);
// break;
// }
// }
// }
dae.getSidRefCache().clear();
return DAE_OK;
}
daeInt daeSTLDatabase::removeChildren( daeDocument *c, daeElement *element )
{
daeElementRefArray era;
element->getChildren( era );
for ( unsigned int i = 0; i < era.getCount(); i++ ) {
removeElement( c, era[i] );
}
return DAE_OK;
}
daeInt daeSTLDatabase::changeElementID( daeElement* element, daeString newID )
{
if ( !element ) {
return DAE_ERR_INVALID_CALL;
}
// Remove the current entry in the ID map if the element has an ID
if ( element->getID() != NULL ) {
pair< multimap<string, daeElement* >::iterator, multimap<string, daeElement* >::iterator> range;
range = elementsIDMap.equal_range( string( element->getID() ) );
multimap<string, daeElement* >::iterator iter = range.first;
while( iter != range.second ) {
if ( (*iter).second == element ) {
elementsIDMap.erase( iter );
break;
}
++iter;
}
}
// Add an entry to the ID map if the element will have an ID
if ( newID != NULL ) {
elementsIDMap.insert( make_pair( string( newID ), element ) );
}
dae.getSidRefCache().clear();
return DAE_OK;
}
daeInt daeSTLDatabase::changeElementSID(daeElement* element, daeString newSID) {
if (!element)
return DAE_ERR_INVALID_CALL;
// // Remove the current entry in the sid map if the element has a sid
// string sid = element->getAttribute("sid");
// if (!sid.empty()) {
// pair<sidMapIter, sidMapIter> range = sidMap.equal_range(sid);
// for (sidMapIter iter = range.first; iter != range.second; iter++) {
// if (iter->second == element) {
// sidMap.erase(iter);
// break;
// }
// }
// }
// // Add an entry to the sid map if the element will have a sid
// if ( newSID != NULL )
// sidMap.insert(sidMapPair(newSID, element));
dae.getSidRefCache().clear();
return DAE_OK;
}
daeInt daeSTLDatabase::clear()
{
elements.clear();
typeMap.clear();
elementsIDMap.clear();
sidMap.clear();
int i;
for (i=0;i<(int)documents.size();i++)
delete documents[i];
documents.clear(); //this will free the daeElement
dae.getRawRefCache().clear();
dae.getSidRefCache().clear();
return DAE_OK;
}
daeUInt daeSTLDatabase::getElementCount(daeString name,daeString type,daeString file)
{
// If none of the search keys was specified, return the total element count in the database
if ( !name && !type && !file )
{
daeUInt count = 0;
map< string, vector< daeElement*> >::iterator iter = elements.begin();
map< string, vector< daeElement*> >::iterator end = elements.end();
while( iter != end )
{
count += (daeUInt)(*iter).second.size();
++iter;
}
return count;
}
if ( name )
{
// name specified
int count = 0;
if ( file )
{
// If a document URI was a search key (in file) resolve it to a text URI with no fragment
daeURI tempURI(dae, file,true);
daeDocument *col = getDocument( tempURI.getURI() );
if ( col == NULL ) {
return 0;
}
// a document was specified
pair< multimap< string, daeElement* >::iterator, multimap< string, daeElement* >::iterator > range;
range = elementsIDMap.equal_range( string( name ) );
multimap< string, daeElement* >::iterator i = range.first;
while ( i != range.second )
{
if ( col == (*i).second->getDocument() )
{
count++;
}
++i;
}
return count;
}
else
{
//no file specified - just name
return (daeUInt)elementsIDMap.count( string( name ) );
}
}
if ( type )
{
// type specified
map< string, vector< daeElement*> >::iterator iter = elements.find( string( type ) );
if ( iter == elements.end() )
{
return 0;
}
int count = 0;
if ( file )
{
// If a document URI was a search key (in file) resolve it to a text URI with no fragment
daeURI tempURI(dae, file,true);
daeDocument *col = getDocument( tempURI.getURI() );
if ( col == NULL ) {
return 0;
}
// a document was specified
vector< daeElement* > &vec = (*iter).second;
vector< daeElement* >::iterator i = vec.begin();
vector< daeElement* >::iterator end = vec.end();
while( i != end )
{
if ( col == (*i)->getDocument() )
{
++count;
}
++i;
}
return count;
}
else
{
//no file specified - just type
return (daeUInt)(*iter).second.size();
}
}
//if you get here only a file was specified
daeURI tempURI(dae, file,true);
daeDocument *col = getDocument( tempURI.getURI() );
if ( col == NULL ) {
return 0;
}
//a document was specified
int count = 0;
map< string, vector< daeElement*> >::iterator iter = elements.begin();
map< string, vector< daeElement*> >::iterator end = elements.end();
while( iter != end )
{
vector< daeElement* > &vec = (*iter).second;
vector< daeElement* >::iterator i = vec.begin();
vector< daeElement* >::iterator end2 = vec.end();
while( i != end2 )
{
if( col == (*i)->getDocument() )
{
++count;
}
++i;
}
++iter;
}
return count;
}
daeInt daeSTLDatabase::getElement(daeElement** pElement,daeInt index,daeString name,daeString type,daeString file)
{
// If the index is out of range, there can be no match
if ( index < 0 )
{
return DAE_ERR_QUERY_NO_MATCH;
}
// If no name, type or file was specified we return the element at "index" - SLOW
if ( !name && !type && !file )
{
daeUInt count = 0;
map< string, vector< daeElement*> >::iterator iter = elements.begin();
map< string, vector< daeElement*> >::iterator end = elements.end();
while( iter != end )
{
count += (daeUInt)(*iter).second.size();
if ( (daeInt)count > index )
{
*pElement = (*iter).second[index - (count - (*iter).second.size())] ;
return DAE_OK;
}
++iter;
}
return DAE_ERR_QUERY_NO_MATCH;
}
if ( name )
{
//name specified
int count = 0;
if ( file )
{
// If a document URI was a search key (in file) resolve it to a text URI with no fragment
daeURI tempURI(dae, file, true);
daeDocument *col = getDocument( tempURI.getURI() );
if ( col == NULL ) {
*pElement = NULL;
return DAE_ERR_QUERY_NO_MATCH;
}
//a document was specified
pair< multimap< string, daeElement* >::iterator, multimap< string, daeElement* >::iterator> range;
range = elementsIDMap.equal_range( string( name ) );
multimap< string, daeElement* >::iterator i = range.first;
while ( i != range.second )
{
if ( col == (*i).second->getDocument() )
{
if ( count == index )
{
*pElement = (*i).second;
return DAE_OK;
}
count++;
}
++i;
}
*pElement = NULL;
return DAE_ERR_QUERY_NO_MATCH;
}
else
{
//no document specified
multimap< string, daeElement* >::iterator i = elementsIDMap.find( string( name ) );
if ( index > (daeInt)elementsIDMap.count( string( name ) ) || i == elementsIDMap.end() )
{
*pElement = NULL;
return DAE_ERR_QUERY_NO_MATCH;
}
for ( int x = 0; x < index; x++ )
{
++i;
}
*pElement = i->second;
return DAE_OK;
}
}
if ( type )
{
map< string, vector< daeElement*> >::iterator iter = elements.find( string( type ) );
if ( iter == elements.end() )
{
*pElement = NULL;
return DAE_ERR_QUERY_NO_MATCH;
}
//type specified
int count = 0;
if ( file )
{
// If a document URI was a search key (in file) resolve it to a text URI with no fragment
daeURI tempURI(dae, file, true);
daeDocument *col = getDocument( tempURI.getURI() );
if ( col == NULL ) {
return DAE_ERR_QUERY_NO_MATCH;
}
//a document was specified
// a document was specified
vector< daeElement* > &vec = (*iter).second;
vector< daeElement* >::iterator i = vec.begin();
vector< daeElement* >::iterator end = vec.end();
while( i != end )
{
if ( col == (*i)->getDocument() )
{
if ( count == index )
{
*pElement = (*i);
return DAE_OK;
}
++count;
}
++i;
}
return DAE_ERR_QUERY_NO_MATCH;
}
else
{
//no document specified
if ( index >= (daeInt)(*iter).second.size() )
{
*pElement = NULL;
return DAE_ERR_QUERY_NO_MATCH;
}
*pElement = (*iter).second[index];
return DAE_OK;
}
}
//if you get here only the file was specified - SLOW
daeURI tempURI(dae, file, true);
daeDocument *col = getDocument( tempURI.getURI() );
if ( col == NULL ) {
return DAE_ERR_QUERY_NO_MATCH;
}
//a document was specified
int count = 0;
map< string, vector< daeElement*> >::iterator iter = elements.begin();
map< string, vector< daeElement*> >::iterator end = elements.end();
while( iter != end )
{
vector< daeElement* > &vec = (*iter).second;
vector< daeElement* >::iterator i = vec.begin();
vector< daeElement* >::iterator end2 = vec.end();
while( i != end2 )
{
if( col == (*i)->getDocument() )
{
if( count == index )
{
*pElement = (*i);
return DAE_OK;
}
++count;
}
++i;
}
++iter;
}
return DAE_ERR_QUERY_NO_MATCH;
}
vector<daeElement*> daeSTLDatabase::idLookup(const string& id) {
vector<daeElement*> matchingElements;
idMapRange range = elementsIDMap.equal_range(id);
for (idMapIter iter = range.first; iter != range.second; iter++)
matchingElements.push_back(iter->second);
return matchingElements;
}
void daeSTLDatabase::typeLookup(daeInt typeID,
vector<daeElement*>& matchingElements,
daeDocument* doc) {
matchingElements.clear();
typeMapRange range = typeMap.equal_range(typeID);
for (typeMapIter iter = range.first; iter != range.second; iter++)
if (!doc || doc == iter->second->getDocument())
matchingElements.push_back(iter->second);
}
void daeSTLDatabase::sidLookup(const string& sid,
vector<daeElement*>& matchingElements,
daeDocument* doc) {
matchingElements.clear();
if (!sid.empty()) {
sidMapRange range = sidMap.equal_range(sid);
for (sidMapIter iter = range.first; iter != range.second; iter++)
if (!doc || doc == iter->second->getDocument())
matchingElements.push_back(iter->second);
}
}