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 #include <modules/daeSTLDatabase.h>
10 #include <dae/daeMetaElement.h>
11 
12 using namespace std;
13 
daeSTLDatabase(DAE & dae)14 daeSTLDatabase::daeSTLDatabase(DAE& dae) : daeDatabase(dae)
15 { }
16 
~daeSTLDatabase()17 daeSTLDatabase::~daeSTLDatabase()
18 {
19 	clear();
20 }
21 
setMeta(daeMetaElement * _topMeta)22 daeInt daeSTLDatabase::setMeta(daeMetaElement *_topMeta)
23 {
24 	topMeta = _topMeta;
25 	return DAE_OK;
26 }
27 
28 daeBool
isDocumentLoaded(daeString name)29 daeSTLDatabase::isDocumentLoaded(daeString name)
30 {
31 	daeDocument* document = getDocument(name);
32 	if(document)
33 		return(true);
34 	else
35 		return(false);
36 }
37 
38 // Element Types of all Elements
getTypeCount()39 daeUInt daeSTLDatabase::getTypeCount()
40 {
41 	return (daeUInt)elements.size();
42 }
43 
44 
getTypeName(daeUInt index)45 daeString daeSTLDatabase::getTypeName(daeUInt index)
46 {
47 	daeUInt count = 0;
48 
49 	map<string, vector< daeElement* > >::iterator iter = elements.begin();
50 	map<string, vector< daeElement* > >::iterator end = elements.end();
51 	while ( iter != end )
52 	{
53 		if ( count == index )
54 		{
55 			return (*iter).first.c_str();
56 		}
57 		++count;
58 		++iter;
59 	}
60 
61 	return NULL;
62 }
63 
64 // Documents
insertDocument(const char * name,daeElement * dom,daeDocument ** document,bool zaeRootDocument,const std::string & extractedFileURI)65 daeInt daeSTLDatabase::insertDocument(const char *name, daeElement* dom, daeDocument** document, bool zaeRootDocument, const std::string& extractedFileURI)
66 {
67 	return createDocument( name, dom, document, zaeRootDocument, extractedFileURI );
68 }
createDocument(const char * name,daeElement * dom,daeDocument ** document,bool zaeRootDocument,const std::string & extractedFileURI)69 daeInt daeSTLDatabase::createDocument(const char *name, daeElement* dom, daeDocument** document, bool zaeRootDocument, const std::string& extractedFileURI)
70 {
71 	// If a document already exists with the same name, error
72 	if(isDocumentLoaded(name))
73 	{
74 		if (document)
75 			*document = NULL;
76 		return DAE_ERR_COLLECTION_ALREADY_EXISTS;
77 	}
78 
79 	// Make a new document
80 	daeDocument *newDocument = new daeDocument(dae, zaeRootDocument, extractedFileURI);
81 	newDocument->getDocumentURI()->setURI(name);
82 	newDocument->setDomRoot(dom);
83 	// Push the connection into the database
84 	documents.push_back(newDocument);
85 
86 	if (document)
87 		*document = newDocument;
88 
89 	return DAE_OK;
90 }
91 // !!!GAC revised version of insertDocument, creates a domCollada and fills it in for you.
insertDocument(const char * name,daeDocument ** document)92 daeInt daeSTLDatabase::insertDocument(const char *name, daeDocument** document)
93 {
94 	return createDocument( name, document );
95 }
createDocument(const char * name,daeDocument ** document)96 daeInt daeSTLDatabase::createDocument(const char *name, daeDocument** document)
97 {
98 
99 	// If a document already exists with the same name, error
100 	if(isDocumentLoaded(name))
101 	{
102 		if (document)
103 			*document = NULL;
104 		return DAE_ERR_COLLECTION_ALREADY_EXISTS;
105 	}
106 	// Make the new document
107 	daeDocument *newDocument = new daeDocument(dae);
108 	// Make a domCOLLADA to be the root of this new document (this makes a reference so the domCOLLADA won't delete itself
109 	daeElementRef myCOLLADA = topMeta->create();
110 	myCOLLADA->setDocument(newDocument);
111 	newDocument->getDocumentURI()->setURI(name);
112 	newDocument->setDomRoot(myCOLLADA);
113 
114 	// Add this document to the list.
115 	documents.push_back(newDocument);
116 	// If the user gave us a place to put the document, send it back to them.
117 	if (document)
118 		*document = newDocument;
119 
120 	return DAE_OK;
121 }
122 
insertDocument(daeDocument * c)123 daeInt daeSTLDatabase::insertDocument( daeDocument *c ) {
124 	documents.push_back(c);
125 	insertElement( c, c->getDomRoot() );
126 	return DAE_OK;
127 }
128 
removeDocument(daeDocument * document)129 daeInt daeSTLDatabase::removeDocument(daeDocument *document)
130 {
131 	vector< daeDocument* >::iterator iter = documents.begin();
132 	while ( iter != documents.end() ) {
133 		if ( (*iter) == document ) {
134 			//delete all of its children
135 			removeElement( *iter, (*iter)->getDomRoot() );
136             delete *iter; // sthomas (see bug 1466019)
137 			iter = documents.erase(iter);
138 		}
139 		else {
140             iter++;
141 		}
142 	}
143 	return DAE_OK;
144 }
145 
getDocumentCount()146 daeUInt daeSTLDatabase::getDocumentCount()
147 {
148 	return (daeUInt)documents.size();
149 }
150 
getDocument(daeUInt index)151 daeDocument* daeSTLDatabase::getDocument(daeUInt index)
152 {
153 	if (index<documents.size())
154 		return (documents[index]);
155 	else
156 		return NULL;
157 }
158 
getDocument(daeString name_,bool skipUriNormalization)159 daeDocument* daeSTLDatabase::getDocument(daeString name_, bool skipUriNormalization)
160 {
161 	string name = name_;
162 	if (!skipUriNormalization) {
163 		// Normalize the input string to an absolute URI with no fragment
164 		name = daeURI(dae, name, true).str();
165 	}
166 
167 	// Try to find a document that matches
168 	daeDocument *document;
169 	int documentCount	= getDocumentCount();
170 	for (int i=0;i<documentCount;i++)
171 	{
172 		document = getDocument(i);
173 		if(document->getDocumentURI()->str() == name)
174 			return(document);
175 	}
176 	return(NULL);
177 }
178 
getDocumentName(daeUInt index)179 daeString daeSTLDatabase::getDocumentName(daeUInt index)
180 {
181 	if (index<documents.size())
182 		return getDocument(index)->getDocumentURI()->getURI();
183 	else
184 		return NULL;
185 }
186 
187 // Elements
insertElement(daeDocument * document,daeElement * element)188 daeInt daeSTLDatabase::insertElement(daeDocument* document,daeElement* element)
189 {
190 	insertChildren( document, element );
191 
192 	map<string, vector< daeElement* > >::iterator iter = elements.find( string( element->getTypeName() ) );
193 	if ( iter != elements.end() )
194 	{
195 		(*iter).second.push_back( element );
196 	}
197 	else
198 	{
199 		vector< daeElement* > vec;
200 		vec.push_back( element );
201 		elements.insert( make_pair( string( element->getTypeName() ), vec ) );
202 	}
203 
204 	// Insert into the type ID map
205 	typeMap.insert(make_pair(element->typeID(), element));
206 
207 	//insert into IDMap if element has an ID. IDMap is used to speed up URI resolution
208 	if ( element->getID() != NULL ) {
209 		elementsIDMap.insert( make_pair( string( element->getID() ), element ) );
210 	}
211 
212 	// Insert into sid map if the element has a sid
213 // 	string sid = element->getAttribute("sid");
214 // 	if (!sid.empty())
215 // 		sidMap.insert(sidMapPair(sid, element));
216 
217 	dae.getSidRefCache().clear();
218 
219 	return DAE_OK;
220 }
221 
insertChildren(daeDocument * c,daeElement * element)222 daeInt daeSTLDatabase::insertChildren( daeDocument *c, daeElement *element )
223 {
224 	daeElementRefArray era;
225 	element->getChildren( era );
226 	for ( unsigned int i = 0; i < era.getCount(); i++ ) {
227 		insertElement( c, era[i] );
228 	}
229 	return DAE_OK;
230 }
231 
removeElement(daeDocument * document,daeElement * element)232 daeInt daeSTLDatabase::removeElement(daeDocument* document,daeElement* element)
233 {
234 	if ( !element ) {
235 		return DAE_ERR_INVALID_CALL;
236 	}
237 	removeChildren( document, element );
238 
239 	map<string, vector< daeElement* > >::iterator iter = elements.find( string( element->getTypeName() ) );
240 	if ( iter != elements.end() )
241 	{
242 		vector< daeElement* > &vec = (*iter).second;
243 		vector< daeElement* >::iterator i = vec.begin();
244 		vector< daeElement* >::iterator end = vec.end();
245 		while( i != end )
246 		{
247 			if ( (*i) == element )
248 			{
249 				vec.erase( i );
250 				break;
251 			}
252 			++i;
253 		}
254 	}
255 
256 	typeMapRange range = typeMap.equal_range(element->typeID());
257 	for (typeMapIter iter = range.first; iter != range.second; iter++) {
258 		if (iter->second == element) {
259 			typeMap.erase(iter);
260 			break;
261 		}
262 	}
263 
264 	if ( element->getID() != NULL ) {
265 		idMapRange range = elementsIDMap.equal_range( string( element->getID() ) );
266 		multimap<string, daeElement* >::iterator iter = range.first;
267 		while( iter != range.second ) {
268 			if ( (*iter).second == element ) {
269 				elementsIDMap.erase( iter );
270 				break;
271 			}
272 			++iter;
273 		}
274 	}
275 
276 // 	string sid = element->getAttribute("sid");
277 // 	if (!sid.empty()) {
278 // 		pair<sidMapIter, sidMapIter> range = sidMap.equal_range(sid);
279 // 		for (sidMapIter iter = range.first; iter != range.second; iter++) {
280 // 			if (iter->second == element) {
281 // 				sidMap.erase(iter);
282 // 				break;
283 // 			}
284 // 		}
285 // 	}
286 
287 	dae.getSidRefCache().clear();
288 
289 	return DAE_OK;
290 }
291 
removeChildren(daeDocument * c,daeElement * element)292 daeInt daeSTLDatabase::removeChildren( daeDocument *c, daeElement *element )
293 {
294 	daeElementRefArray era;
295 	element->getChildren( era );
296 	for ( unsigned int i = 0; i < era.getCount(); i++ ) {
297 		removeElement( c, era[i] );
298 	}
299 	return DAE_OK;
300 }
301 
changeElementID(daeElement * element,daeString newID)302 daeInt daeSTLDatabase::changeElementID( daeElement* element, daeString newID )
303 {
304 	if ( !element ) {
305 		return DAE_ERR_INVALID_CALL;
306 	}
307 
308 	// Remove the current entry in the ID map if the element has an ID
309 	if ( element->getID() != NULL ) {
310 		pair< multimap<string, daeElement* >::iterator, multimap<string, daeElement* >::iterator> range;
311 		range = elementsIDMap.equal_range( string( element->getID() ) );
312 		multimap<string, daeElement* >::iterator iter = range.first;
313 		while( iter != range.second ) {
314 			if ( (*iter).second == element ) {
315 				elementsIDMap.erase( iter );
316 				break;
317 			}
318 			++iter;
319 		}
320 	}
321 
322 	// Add an entry to the ID map if the element will have an ID
323 	if ( newID != NULL ) {
324 		elementsIDMap.insert( make_pair( string( newID ), element ) );
325 	}
326 
327 	dae.getSidRefCache().clear();
328 
329 	return DAE_OK;
330 }
331 
changeElementSID(daeElement * element,daeString newSID)332 daeInt daeSTLDatabase::changeElementSID(daeElement* element, daeString newSID) {
333 	if (!element)
334 		return DAE_ERR_INVALID_CALL;
335 
336 // 	// Remove the current entry in the sid map if the element has a sid
337 // 	string sid = element->getAttribute("sid");
338 // 	if (!sid.empty()) {
339 // 		pair<sidMapIter, sidMapIter> range = sidMap.equal_range(sid);
340 // 		for (sidMapIter iter = range.first; iter != range.second; iter++) {
341 // 			if (iter->second == element) {
342 // 				sidMap.erase(iter);
343 // 				break;
344 // 			}
345 // 		}
346 // 	}
347 
348 // 	// Add an entry to the sid map if the element will have a sid
349 // 	if ( newSID != NULL )
350 // 		sidMap.insert(sidMapPair(newSID, element));
351 
352 	dae.getSidRefCache().clear();
353 
354 	return DAE_OK;
355 }
356 
clear()357 daeInt daeSTLDatabase::clear()
358 {
359 	elements.clear();
360 	typeMap.clear();
361 	elementsIDMap.clear();
362 	sidMap.clear();
363 	int i;
364 	for (i=0;i<(int)documents.size();i++)
365 		delete documents[i];
366 	documents.clear(); //this will free the daeElement
367 	dae.getRawRefCache().clear();
368 	dae.getSidRefCache().clear();
369 	return DAE_OK;
370 }
371 
getElementCount(daeString name,daeString type,daeString file)372 daeUInt daeSTLDatabase::getElementCount(daeString name,daeString type,daeString file)
373 {
374 	// If none of the search keys was specified, return the total element count in the database
375 	if ( !name && !type && !file )
376 	{
377 		daeUInt count = 0;
378 		map< string, vector< daeElement*> >::iterator iter = elements.begin();
379 		map< string, vector< daeElement*> >::iterator end = elements.end();
380 		while( iter != end )
381 		{
382 			count += (daeUInt)(*iter).second.size();
383 			++iter;
384 		}
385 		return count;
386 	}
387 
388 	if ( name )
389 	{
390 		// name specified
391 		int count = 0;
392 		if ( file )
393 		{
394 			// If a document URI was a search key (in file) resolve it to a text URI with no fragment
395 			daeURI tempURI(dae, file,true);
396 			daeDocument *col = getDocument( tempURI.getURI() );
397 			if ( col == NULL ) {
398 				return 0;
399 			}
400 			// a document was specified
401 			pair< multimap< string, daeElement* >::iterator, multimap< string, daeElement* >::iterator > range;
402 			range = elementsIDMap.equal_range( string( name ) );
403 			multimap< string, daeElement* >::iterator i = range.first;
404 			while ( i != range.second )
405 			{
406 				if ( col == (*i).second->getDocument() )
407 				{
408 					count++;
409 				}
410 				++i;
411 			}
412 			return count;
413 		}
414 		else
415 		{
416 			//no file specified - just name
417 			return (daeUInt)elementsIDMap.count( string( name ) );
418 		}
419 	}
420 
421 	if ( type )
422 	{
423 		// type specified
424 		map< string, vector< daeElement*> >::iterator iter = elements.find( string( type ) );
425 		if ( iter == elements.end() )
426 		{
427 			return 0;
428 		}
429 
430 		int count = 0;
431 		if ( file )
432 		{
433 			// If a document URI was a search key (in file) resolve it to a text URI with no fragment
434 			daeURI tempURI(dae, file,true);
435 			daeDocument *col = getDocument( tempURI.getURI() );
436 			if ( col == NULL ) {
437 				return 0;
438 			}
439 			// a document was specified
440 			vector< daeElement* > &vec = (*iter).second;
441 			vector< daeElement* >::iterator i = vec.begin();
442 			vector< daeElement* >::iterator end = vec.end();
443 			while( i != end )
444 			{
445 				if ( col == (*i)->getDocument() )
446 				{
447 					++count;
448 				}
449 				++i;
450 			}
451 			return count;
452 		}
453 		else
454 		{
455 			//no file specified - just type
456 			return (daeUInt)(*iter).second.size();
457 		}
458 	}
459 
460 	//if you get here only a file was specified
461 	daeURI tempURI(dae, file,true);
462 	daeDocument *col = getDocument( tempURI.getURI() );
463 	if ( col == NULL ) {
464 		return 0;
465 	}
466 	//a document was specified
467 	int count = 0;
468 	map< string, vector< daeElement*> >::iterator iter = elements.begin();
469 	map< string, vector< daeElement*> >::iterator end = elements.end();
470 	while( iter != end )
471 	{
472 		vector< daeElement* > &vec = (*iter).second;
473 		vector< daeElement* >::iterator i = vec.begin();
474 		vector< daeElement* >::iterator end2 = vec.end();
475 		while( i != end2 )
476 		{
477 			if( col == (*i)->getDocument() )
478 			{
479 				++count;
480 			}
481 			++i;
482 		}
483 		++iter;
484 	}
485 	return count;
486 
487 }
488 
getElement(daeElement ** pElement,daeInt index,daeString name,daeString type,daeString file)489 daeInt daeSTLDatabase::getElement(daeElement** pElement,daeInt index,daeString name,daeString type,daeString file)
490 {
491 	// If the index is out of range, there can be no match
492 	if ( index < 0 )
493 	{
494 		return DAE_ERR_QUERY_NO_MATCH;
495 	}
496 
497 	// If no name, type or file was specified we return the element at "index" - SLOW
498 	if ( !name && !type && !file )
499 	{
500 		daeUInt count = 0;
501 		map< string, vector< daeElement*> >::iterator iter = elements.begin();
502 		map< string, vector< daeElement*> >::iterator end = elements.end();
503 		while( iter != end )
504 		{
505 			count += (daeUInt)(*iter).second.size();
506 			if ( (daeInt)count > index )
507 			{
508 				*pElement = (*iter).second[index - (count - (*iter).second.size())] ;
509 				return DAE_OK;
510 			}
511 			++iter;
512 		}
513 		return DAE_ERR_QUERY_NO_MATCH;
514 	}
515 
516 	if ( name )
517 	{
518 		//name specified
519 		int count = 0;
520 		if ( file )
521 		{
522 			// If a document URI was a search key (in file) resolve it to a text URI with no fragment
523 			daeURI tempURI(dae, file, true);
524 			daeDocument *col = getDocument( tempURI.getURI() );
525 			if ( col == NULL ) {
526 				*pElement = NULL;
527 				return DAE_ERR_QUERY_NO_MATCH;
528 			}
529 			//a document was specified
530 			pair< multimap< string, daeElement* >::iterator, multimap< string, daeElement* >::iterator> range;
531 			range = elementsIDMap.equal_range( string( name ) );
532 			multimap< string, daeElement* >::iterator i = range.first;
533 			while ( i != range.second )
534 			{
535 				if ( col == (*i).second->getDocument() )
536 				{
537 					if ( count == index )
538 					{
539 						*pElement = (*i).second;
540 						return DAE_OK;
541 					}
542 					count++;
543 				}
544 				++i;
545 			}
546 			*pElement = NULL;
547 			return DAE_ERR_QUERY_NO_MATCH;
548 		}
549 		else
550 		{
551 			//no document specified
552 			multimap< string, daeElement* >::iterator i = elementsIDMap.find( string( name ) );
553 			if ( index > (daeInt)elementsIDMap.count( string( name ) ) || i == elementsIDMap.end() )
554 			{
555 				*pElement = NULL;
556 				return DAE_ERR_QUERY_NO_MATCH;
557 			}
558 			for ( int x = 0; x < index; x++ )
559 			{
560 				++i;
561 			}
562 			*pElement = i->second;
563 			return DAE_OK;
564 		}
565 	}
566 
567 	if ( type )
568 	{
569 		map< string, vector< daeElement*> >::iterator iter = elements.find( string( type ) );
570 		if ( iter == elements.end() )
571 		{
572 			*pElement = NULL;
573 			return DAE_ERR_QUERY_NO_MATCH;
574 		}
575 		//type specified
576 		int count = 0;
577 		if ( file )
578 		{
579 			// If a document URI was a search key (in file) resolve it to a text URI with no fragment
580 			daeURI tempURI(dae, file, true);
581 			daeDocument *col = getDocument( tempURI.getURI() );
582 			if ( col == NULL ) {
583 				return DAE_ERR_QUERY_NO_MATCH;
584 			}
585 			//a document was specified
586 			// a document was specified
587 			vector< daeElement* > &vec = (*iter).second;
588 			vector< daeElement* >::iterator i = vec.begin();
589 			vector< daeElement* >::iterator end = vec.end();
590 			while( i != end )
591 			{
592 				if ( col == (*i)->getDocument() )
593 				{
594 					if ( count == index )
595 					{
596 						*pElement = (*i);
597 						return DAE_OK;
598 					}
599 					++count;
600 				}
601 				++i;
602 			}
603 			return DAE_ERR_QUERY_NO_MATCH;
604 		}
605 		else
606 		{
607 			//no document specified
608 			if ( index >= (daeInt)(*iter).second.size() )
609 			{
610 				*pElement = NULL;
611 				return DAE_ERR_QUERY_NO_MATCH;
612 			}
613 			*pElement = (*iter).second[index];
614 			return DAE_OK;
615 		}
616 	}
617 
618 	//if you get here only the file was specified - SLOW
619 	daeURI tempURI(dae, file, true);
620 	daeDocument *col = getDocument( tempURI.getURI() );
621 	if ( col == NULL ) {
622 		return DAE_ERR_QUERY_NO_MATCH;
623 	}
624 	//a document was specified
625 	int count = 0;
626 	map< string, vector< daeElement*> >::iterator iter = elements.begin();
627 	map< string, vector< daeElement*> >::iterator end = elements.end();
628 	while( iter != end )
629 	{
630 		vector< daeElement* > &vec = (*iter).second;
631 		vector< daeElement* >::iterator i = vec.begin();
632 		vector< daeElement* >::iterator end2 = vec.end();
633 		while( i != end2 )
634 		{
635 			if( col == (*i)->getDocument() )
636 			{
637 				if( count == index )
638 				{
639 					*pElement = (*i);
640 					return DAE_OK;
641 				}
642 				++count;
643 			}
644 			++i;
645 		}
646 		++iter;
647 	}
648 	return DAE_ERR_QUERY_NO_MATCH;
649 
650 }
651 
idLookup(const string & id)652 vector<daeElement*> daeSTLDatabase::idLookup(const string& id) {
653 	vector<daeElement*> matchingElements;
654 	idMapRange range = elementsIDMap.equal_range(id);
655 	for (idMapIter iter = range.first; iter != range.second; iter++)
656 		matchingElements.push_back(iter->second);
657 	return matchingElements;
658 }
659 
typeLookup(daeInt typeID,vector<daeElement * > & matchingElements,daeDocument * doc)660 void daeSTLDatabase::typeLookup(daeInt typeID,
661                                 vector<daeElement*>& matchingElements,
662                                 daeDocument* doc) {
663 	matchingElements.clear();
664 	typeMapRange range = typeMap.equal_range(typeID);
665 	for (typeMapIter iter = range.first; iter != range.second; iter++)
666 		if (!doc  ||  doc == iter->second->getDocument())
667 			matchingElements.push_back(iter->second);
668 }
669 
sidLookup(const string & sid,vector<daeElement * > & matchingElements,daeDocument * doc)670 void daeSTLDatabase::sidLookup(const string& sid,
671                                vector<daeElement*>& matchingElements,
672                                daeDocument* doc) {
673 	matchingElements.clear();
674 	if (!sid.empty()) {
675 		sidMapRange range = sidMap.equal_range(sid);
676 		for (sidMapIter iter = range.first; iter != range.second; iter++)
677 			if (!doc  ||  doc == iter->second->getDocument())
678 				matchingElements.push_back(iter->second);
679 	}
680 }
681