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