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 <iomanip>
10 #include <dae/daeElement.h>
11 #include <dae/daeArray.h>
12 #include <dae/daeMetaAttribute.h>
13 #include <dae/daeMetaElementAttribute.h>
14 #include <dae/daeMetaElement.h>
15 #include <dae/daeDatabase.h>
16 #include <dae/daeErrorHandler.h>
17 #include <dae/daeURI.h>
18 #include <dae/daeUtils.h>
19 #include <dae/daeDom.h>
20 
21 #include <limits>
22 #include <iomanip>
23 
24 using namespace std;
25 
simpleAdd(daeString name,int index)26 daeElement* daeElement::simpleAdd(daeString name, int index) {
27     if (daeElementRef elt = _meta->create(name))
28         return add(elt, index);
29     return NULL;
30 }
31 
add(daeString names_,int index)32 daeElement* daeElement::add(daeString names_, int index) {
33     list<string> names;
34     cdom::tokenize(names_, " ", names);
35     cdom::tokenIter iter = names.begin();
36     daeElement* root = simpleAdd(iter->c_str(), index);
37     if (!root)
38         return NULL;
39 
40     iter++;
41     daeElement* elt = root;
42     for (; iter != names.end(); iter++) {
43         elt = elt->simpleAdd(iter->c_str());
44         if (!elt) {
45             removeChildElement(root);
46             return NULL;
47         }
48     }
49 
50     return elt;
51 }
52 
add(daeElement * elt,int index)53 daeElement* daeElement::add(daeElement* elt, int index) {
54     if (!elt)
55         return NULL;
56     if (elt == this)
57         return this;
58     bool result = (index == -1 ? _meta->place(this, elt) : _meta->placeAt(index, this, elt));
59     return result ? elt : NULL;
60 }
61 
addBefore(daeElement * elt,daeElement * index)62 daeElement* daeElement::addBefore(daeElement* elt, daeElement* index) {
63     if (!index || !elt || index->getParent() != this)
64         return NULL;
65     return _meta->placeBefore(index, this, elt) ? elt : NULL;
66 }
67 
addAfter(daeElement * elt,daeElement * index)68 daeElement* daeElement::addAfter(daeElement* elt, daeElement* index) {
69     if (!index || !elt || index->getParent() != this)
70         return NULL;
71     return _meta->placeAfter(index, this, elt) ? elt : NULL;
72 }
73 
74 daeElementRef
createElement(daeString className)75 daeElement::createElement(daeString className)
76 {
77     daeElementRef elem = _meta->create(className);
78     // Bug #225 work around
79 //	if ( elem != NULL)
80 //		elem->ref(); // change premature delete into memory leak.
81     return elem;
82 }
83 
createAndPlace(daeString className)84 daeElement* daeElement::createAndPlace(daeString className) {
85     return add(className);
86 }
87 
createAndPlaceAt(daeInt index,daeString className)88 daeElement* daeElement::createAndPlaceAt(daeInt index, daeString className) {
89     return add(className, index);
90 }
91 
placeElement(daeElement * e)92 daeBool daeElement::placeElement(daeElement* e) {
93     return add(e) != NULL;
94 }
95 
placeElementAt(daeInt index,daeElement * e)96 daeBool daeElement::placeElementAt(daeInt index, daeElement* e) {
97     return add(e, index) != NULL;
98 }
99 
placeElementBefore(daeElement * marker,daeElement * element)100 daeBool daeElement::placeElementBefore( daeElement *marker, daeElement *element ) {
101     return addBefore(element, marker) != NULL;
102 }
103 
placeElementAfter(daeElement * marker,daeElement * element)104 daeBool daeElement::placeElementAfter( daeElement *marker, daeElement *element ) {
105     return addAfter(element, marker) != NULL;
106 }
107 
findLastIndexOf(daeString elementName)108 daeInt daeElement::findLastIndexOf( daeString elementName ) {
109     if ( _meta->getContents() != NULL ) {
110         daeElementRefArray* contents =
111             (daeElementRefArray*)_meta->getContents()->getWritableMemory(this);
112         for ( int i = (int)contents->getCount()-1; i >= 0; --i ) {
113             if ( strcmp( contents->get(i)->getElementName(), elementName ) == 0 ) {
114                 return i;
115             }
116         }
117     }
118     return -1;
119 }
120 
121 daeBool
removeChildElement(daeElement * element)122 daeElement::removeChildElement(daeElement* element)
123 {
124     // error traps
125     if(element==NULL)
126         return false;
127     if(element->_parent != this)
128         return false;
129 
130     return _meta->remove( this, element );
131 }
132 
setDocument(daeDocument * c,bool notifyDocument)133 void daeElement::setDocument( daeDocument *c, bool notifyDocument ) {
134     if( _document == c )
135         return;
136 
137     // Notify our parent document if necessary.
138     if ( _document != NULL && notifyDocument )
139         _document->removeElement(this);
140     _document = c;
141     if ( _document != NULL && notifyDocument )
142         _document->insertElement(this);
143 
144     // Notify our attributes
145     daeMetaAttributeRefArray& metaAttrs = getMeta()->getMetaAttributes();
146     for (size_t i = 0; i < metaAttrs.getCount(); i++)
147         metaAttrs[i]->setDocument(this, c);
148 
149     // Notify our char data object
150     if (getCharDataObject())
151         getCharDataObject()->setDocument(this, c);
152 
153     // Notify our children
154     daeElementRefArray ea;
155     getChildren( ea );
156     for ( size_t x = 0; x < ea.getCount(); x++ ) {
157         // Since inserting and removing elements works recursively in the database,
158         // we don't need to notify it about inserts/removals as we process the
159         // children of this element.
160         ea[x]->setDocument( c, false );
161     }
162 }
163 
deleteCMDataArray(daeTArray<daeCharArray * > & cmData)164 void daeElement::deleteCMDataArray(daeTArray<daeCharArray*>& cmData) {
165     for (unsigned int i = 0; i < cmData.getCount(); i++)
166         delete cmData.get(i);
167     cmData.clear();
168 }
169 
getAttributeCount()170 size_t daeElement::getAttributeCount() {
171     return getMeta()->getMetaAttributes().getCount();
172 }
173 
174 namespace {
175 // A helper function to get the index of an attribute given the attribute name.
getAttributeIndex(daeElement & el,daeString name)176 size_t getAttributeIndex(daeElement& el, daeString name) {
177     if (el.getMeta()) {
178         daeMetaAttributeRefArray& metaAttrs = el.getMeta()->getMetaAttributes();
179         for (size_t i = 0; i < metaAttrs.getCount(); i++)
180             if (metaAttrs[i]->getName()  &&  strcmp(metaAttrs[i]->getName(), name) == 0)
181                 return i;
182     }
183     return (size_t)-1;
184 }
185 }
186 
getAttributeObject(size_t i)187 daeMetaAttribute* daeElement::getAttributeObject(size_t i) {
188     daeMetaAttributeRefArray& attrs = getMeta()->getMetaAttributes();
189     if (i >= attrs.getCount())
190         return NULL;
191     return attrs[i];
192 }
193 
getAttributeObject(daeString name)194 daeMetaAttribute* daeElement::getAttributeObject(daeString name) {
195     return getAttributeObject(getAttributeIndex(*this, name));
196 }
197 
getAttributeName(size_t i)198 std::string daeElement::getAttributeName(size_t i) {
199     if (daeMetaAttribute* attr = getAttributeObject(i))
200         return (daeString)attr->getName();
201     return "";
202 }
203 
hasAttribute(daeString name)204 daeBool daeElement::hasAttribute(daeString name) {
205     return getAttributeObject(name) != 0;
206 }
207 
isAttributeSet(daeString name)208 daeBool daeElement::isAttributeSet(daeString name) {
209     size_t i = getAttributeIndex(*this, name);
210     if (i != (size_t)-1)
211         return _validAttributeArray[i];
212     return false;
213 }
214 
getAttribute(size_t i)215 std::string daeElement::getAttribute(size_t i) {
216     std::string value;
217     getAttribute(i, value);
218     return value;
219 }
220 
getAttribute(size_t i,std::string & value)221 void daeElement::getAttribute(size_t i, std::string& value) {
222     value = "";
223     if (daeMetaAttribute* attr = getAttributeObject(i)) {
224         std::ostringstream buffer;
225 #ifdef COLLADA_DOM_DAEFLOAT_IS64
226         buffer << std::setprecision(std::numeric_limits<PLATFORM_FLOAT64>::digits10+1); // set the default precision to daeFloat digit
227 #endif
228         attr->memoryToString(this, buffer);
229         value = buffer.str();
230     }
231 }
232 
getAttribute(daeString name)233 std::string daeElement::getAttribute(daeString name) {
234     std::string value;
235     getAttribute(name, value);
236     return value;
237 }
238 
getAttribute(daeString name,std::string & value)239 void daeElement::getAttribute(daeString name, std::string& value) {
240     getAttribute(getAttributeIndex(*this, name), value);
241 }
242 
attr()243 daeElement::attr::attr() {
244 }
attr(const std::string & name,const std::string & value)245 daeElement::attr::attr(const std::string& name, const std::string& value)
246     : name(name), value(value) {
247 }
248 
getAttributes()249 daeTArray<daeElement::attr> daeElement::getAttributes() {
250     daeTArray<daeElement::attr> attrs;
251     getAttributes(attrs);
252     return attrs;
253 }
254 
getAttributes(daeTArray<attr> & attrs)255 void daeElement::getAttributes(daeTArray<attr>& attrs) {
256     attrs.clear();
257     for (size_t i = 0; i < getAttributeCount(); i++) {
258         std::string value;
259         getAttribute(i, value);
260         attrs.append(attr(getAttributeName(i), value));
261     }
262 }
263 
setAttribute(size_t i,daeString value)264 daeBool daeElement::setAttribute(size_t i, daeString value) {
265     if (daeMetaAttribute* attr = getAttributeObject(i)) {
266         if (attr->getType()) {
267             attr->stringToMemory(this, value);
268             _validAttributeArray.set(i, true);
269             return true;
270         }
271     }
272     return false;
273 }
274 
setAttribute(daeString name,daeString value)275 daeBool daeElement::setAttribute(daeString name, daeString value) {
276     return setAttribute(getAttributeIndex(*this, name), value);
277 }
278 
279 // Deprecated
getAttributeValue(daeString name)280 daeMemoryRef daeElement::getAttributeValue(daeString name) {
281     if (daeMetaAttribute* attr = getAttributeObject(name))
282         return attr->get(this);
283     return NULL;
284 }
285 
getCharDataObject()286 daeMetaAttribute* daeElement::getCharDataObject() {
287     if (_meta)
288         return _meta->getValueAttribute();
289     return NULL;
290 }
291 
hasCharData()292 daeBool daeElement::hasCharData() {
293     return getCharDataObject() != NULL;
294 }
295 
getCharData()296 std::string daeElement::getCharData() {
297     std::string result;
298     getCharData(result);
299     return result;
300 }
301 
getCharData(std::string & data)302 void daeElement::getCharData(std::string& data) {
303     data = "";
304     if (daeMetaAttribute* charDataAttr = getCharDataObject()) {
305         std::ostringstream buffer; // no need to setprecision since this is char data?
306         charDataAttr->memoryToString(this, buffer);
307         data = buffer.str();
308     }
309 }
310 
setCharData(const std::string & data)311 daeBool daeElement::setCharData(const std::string& data) {
312     if (daeMetaAttribute* charDataAttr = getCharDataObject()) {
313         charDataAttr->stringToMemory(this, data.c_str());
314         return true;
315     }
316     return false;
317 }
318 
hasValue()319 daeBool daeElement::hasValue() {
320     return hasCharData();
321 }
322 
getValuePointer()323 daeMemoryRef daeElement::getValuePointer() {
324     if (daeMetaAttribute* charDataAttr = getCharDataObject())
325         return charDataAttr->get(this);
326     return NULL;
327 }
328 
329 void
setup(daeMetaElement * meta)330 daeElement::setup(daeMetaElement* meta)
331 {
332     if (_meta)
333         return;
334     _meta = meta;
335     daeMetaAttributeRefArray& attrs = meta->getMetaAttributes();
336     int macnt = (int)attrs.getCount();
337 
338     _validAttributeArray.setCount(macnt, false);
339 
340     for (int i = 0; i < macnt; i++) {
341         if (attrs[i]->getDefaultValue() != NULL)
342             attrs[i]->copyDefault(this);
343     }
344 
345     //set up the _CMData array if there is one
346     if ( _meta->getMetaCMData() != NULL )
347     {
348         daeTArray< daeCharArray *> *CMData = (daeTArray< daeCharArray *>*)_meta->getMetaCMData()->getWritableMemory(this);
349         CMData->setCount( _meta->getNumChoices() );
350         for ( unsigned int i = 0; i < _meta->getNumChoices(); i++ )
351         {
352             CMData->set( i, new daeCharArray() );
353         }
354     }
355 }
356 
init()357 void daeElement::init() {
358     _parent = NULL;
359     _document = NULL;
360     _meta = NULL;
361     _elementName = NULL;
362     _userData = NULL;
363 }
364 
daeElement()365 daeElement::daeElement() {
366     init();
367 }
368 
daeElement(DAE & dae)369 daeElement::daeElement(DAE& dae) {
370     init();
371 }
372 
~daeElement()373 daeElement::~daeElement()
374 {
375     if (_elementName) {
376         delete[] _elementName;
377         _elementName = NULL;
378     }
379 }
380 
381 //function used until we clarify what's a type and what's a name for an element
getTypeName() const382 daeString daeElement::getTypeName() const
383 {
384     return _meta->getName();
385 }
getElementName() const386 daeString daeElement::getElementName() const
387 {
388     return _elementName ? _elementName : (daeString)_meta->getName();
389 }
setElementName(daeString nm)390 void daeElement::setElementName( daeString nm ) {
391     if ( nm == NULL ) {
392         if ( _elementName ) delete[] _elementName;
393         _elementName = NULL;
394         return;
395     }
396     if ( !_elementName ) _elementName = new daeChar[128];
397     strcpy( (char*)_elementName, nm );
398 }
399 
getID() const400 daeString daeElement::getID() const {
401     daeElement* this_ = const_cast<daeElement*>(this);
402     if (_meta)
403         if (daeMetaAttribute* idAttr = this_->getAttributeObject("id"))
404             return *(daeStringRef*)idAttr->get(this_);
405     return NULL;
406 }
407 
getChildren()408 daeElementRefArray daeElement::getChildren() {
409     daeElementRefArray array;
410     getChildren(array);
411     return array;
412 }
413 
getChildren(daeElementRefArray & array)414 void daeElement::getChildren( daeElementRefArray &array ) {
415     _meta->getChildren( this, array );
416 }
417 
clone(daeString idSuffix,daeString nameSuffix)418 daeSmartRef<daeElement> daeElement::clone(daeString idSuffix, daeString nameSuffix) {
419     // Use the meta object system to create a new instance of this element. We need to
420     // create a new meta if we're cloning a domAny object because domAnys never share meta objects.
421     // Ideally we'd be able to clone the _meta for domAny objects. Then we wouldn't need
422     // any additional special case code for cloning domAny. Unfortunately, we don't have a
423     // daeMetaElement::clone method.
424     bool any = typeID() == getDomAnyID(*getDAE());
425     daeElementRef ret = any ? registerElementAny(*getDAE())->create() : _meta->create();
426     ret->setElementName( _elementName );
427 
428     // Copy the attributes and character data. Requires special care for domAny.
429     if (any) {
430         copyElementAny(ret, this);
431     } else {
432         // Use the meta system to copy attributes
433         daeMetaAttributeRefArray &attrs = _meta->getMetaAttributes();
434         for (unsigned int i = 0; i < attrs.getCount(); i++) {
435             attrs[i]->copy( ret, this );
436             ret->_validAttributeArray[i] = _validAttributeArray[i];
437         }
438         if (daeMetaAttribute* valueAttr = getCharDataObject())
439             valueAttr->copy( ret, this );
440     }
441 
442     daeElementRefArray children;
443     _meta->getChildren( this, children );
444     for ( size_t x = 0; x < children.getCount(); x++ ) {
445         ret->placeElement( children.get(x)->clone( idSuffix, nameSuffix ) );
446     }
447 
448     // Mangle the id
449     if (idSuffix) {
450         std::string id = ret->getAttribute("id");
451         if (!id.empty())
452             ret->setAttribute("id", (id + idSuffix).c_str());
453     }
454     // Mangle the name
455     if (nameSuffix) {
456         std::string name = ret->getAttribute("name");
457         if (!name.empty())
458             ret->setAttribute("name", (name + nameSuffix).c_str());
459     }
460     return ret;
461 }
462 
463 
464 // Element comparison
465 
466 namespace { // Utility functions
getNecessaryColumnWidth(const vector<string> & tokens)467 int getNecessaryColumnWidth(const vector<string>& tokens) {
468     int result = 0;
469     for (size_t i = 0; i < tokens.size(); i++) {
470         int tokenLength = int(tokens[i].length() > 0 ? tokens[i].length()+2 : 0);
471         result = max(tokenLength, result);
472     }
473     return result;
474 }
475 
formatToken(const string & token)476 string formatToken(const string& token) {
477     if (token.length() <= 50)
478         return token;
479     return token.substr(0, 47) + "...";
480 }
481 } // namespace {
482 
compareResult()483 daeElement::compareResult::compareResult()
484     : compareValue(0),
485     elt1(NULL),
486     elt2(NULL),
487     nameMismatch(false),
488     attrMismatch(""),
489     charDataMismatch(false),
490     childCountMismatch(false) {
491 }
492 
format()493 string daeElement::compareResult::format() {
494     if (!elt1 || !elt2)
495         return "";
496 
497     // Gather the data we'll be printing
498     string name1 = formatToken(elt1->getElementName()),
499            name2 = formatToken(elt2->getElementName()),
500            type1 = formatToken(elt1->getTypeName()),
501            type2 = formatToken(elt2->getTypeName()),
502            id1 = formatToken(elt1->getAttribute("id")),
503            id2 = formatToken(elt2->getAttribute("id")),
504            attrName1 = formatToken(attrMismatch),
505            attrName2 = formatToken(attrMismatch),
506            attrValue1 = formatToken(elt1->getAttribute(attrMismatch.c_str())),
507            attrValue2 = formatToken(elt2->getAttribute(attrMismatch.c_str())),
508            charData1 = formatToken(elt1->getCharData()),
509            charData2 = formatToken(elt2->getCharData()),
510            childCount1 = formatToken(cdom::toString(elt1->getChildren().getCount())),
511            childCount2 = formatToken(cdom::toString(elt2->getChildren().getCount()));
512 
513     // Compute formatting information
514     vector<string> col1Tokens = cdom::makeStringArray("Name", "Type", "ID",
515                                                       "Attr name", "Attr value", "Char data", "Child count", 0);
516     vector<string> col2Tokens = cdom::makeStringArray("Element 1", name1.c_str(),
517                                                       type1.c_str(), id1.c_str(), attrName1.c_str(), attrValue1.c_str(),
518                                                       charData1.c_str(), childCount1.c_str(), 0);
519 
520     int c1w = getNecessaryColumnWidth(col1Tokens),
521         c2w = getNecessaryColumnWidth(col2Tokens);
522     ostringstream msg;
523     msg << setw(c1w) << left << ""            << setw(c2w) << left << "Element 1" << "Element 2\n"
524         << setw(c1w) << left << ""            << setw(c2w) << left << "---------" << "---------\n"
525         << setw(c1w) << left << "Name"        << setw(c2w) << left << name1 << name2 << endl
526         << setw(c1w) << left << "Type"        << setw(c2w) << left << type1 << type2 << endl
527         << setw(c1w) << left << "ID"          << setw(c2w) << left << id1 << id2 << endl
528         << setw(c1w) << left << "Attr name"   << setw(c2w) << left << attrName1 << attrName2 << endl
529         << setw(c1w) << left << "Attr value"  << setw(c2w) << left << attrValue1 << attrValue2 << endl
530         << setw(c1w) << left << "Char data"   << setw(c2w) << left << charData1 << charData2 << endl
531         << setw(c1w) << left << "Child count" << setw(c2w) << left << childCount1 << childCount2;
532 
533     return msg.str();
534 }
535 
536 namespace {
compareMatch()537 daeElement::compareResult compareMatch() {
538     daeElement::compareResult result;
539     result.compareValue = 0;
540     return result;
541 }
542 
nameMismatch(daeElement & elt1,daeElement & elt2)543 daeElement::compareResult nameMismatch(daeElement& elt1, daeElement& elt2) {
544     daeElement::compareResult result;
545     result.elt1 = &elt1;
546     result.elt2 = &elt2;
547     result.compareValue = strcmp(elt1.getElementName(), elt2.getElementName());
548     result.nameMismatch = true;
549     return result;
550 }
551 
attrMismatch(daeElement & elt1,daeElement & elt2,const string & attr)552 daeElement::compareResult attrMismatch(daeElement& elt1, daeElement& elt2, const string& attr) {
553     daeElement::compareResult result;
554     result.elt1 = &elt1;
555     result.elt2 = &elt2;
556     result.compareValue = strcmp(elt1.getAttribute(attr.c_str()).c_str(),
557                                  elt2.getAttribute(attr.c_str()).c_str());
558     result.attrMismatch = attr;
559     return result;
560 }
561 
charDataMismatch(daeElement & elt1,daeElement & elt2)562 daeElement::compareResult charDataMismatch(daeElement& elt1, daeElement& elt2) {
563     daeElement::compareResult result;
564     result.elt1 = &elt1;
565     result.elt2 = &elt2;
566     result.compareValue = strcmp(elt1.getCharData().c_str(),
567                                  elt2.getCharData().c_str());
568     result.charDataMismatch = true;
569     return result;
570 }
571 
childCountMismatch(daeElement & elt1,daeElement & elt2)572 daeElement::compareResult childCountMismatch(daeElement& elt1, daeElement& elt2) {
573     daeElement::compareResult result;
574     result.elt1 = &elt1;
575     result.elt2 = &elt2;
576     daeElementRefArray children1 = elt1.getChildren(),
577                        children2 = elt2.getChildren();
578     result.compareValue = int(children1.getCount()) - int(children2.getCount());
579     result.childCountMismatch = true;
580     return result;
581 }
582 
compareElementsSameType(daeElement & elt1,daeElement & elt2)583 daeElement::compareResult compareElementsSameType(daeElement& elt1, daeElement& elt2) {
584     // Compare attributes
585     for (size_t i = 0; i < elt1.getAttributeCount(); i++)
586         if (elt1.getAttributeObject(i)->compare(&elt1, &elt2) != 0)
587             return attrMismatch(elt1, elt2, elt1.getAttributeName(i));
588 
589     // Compare character data
590     if (elt1.getCharDataObject())
591         if (elt1.getCharDataObject()->compare(&elt1, &elt2) != 0)
592             return charDataMismatch(elt1, elt2);
593 
594     // Compare children
595     daeElementRefArray children1 = elt1.getChildren(),
596                        children2 = elt2.getChildren();
597     if (children1.getCount() != children2.getCount())
598         return childCountMismatch(elt1, elt2);
599     for (size_t i = 0; i < children1.getCount(); i++) {
600         daeElement::compareResult result = daeElement::compareWithFullResult(*children1[i], *children2[i]);
601         if (result.compareValue != 0)
602             return result;
603     }
604 
605     return compareMatch();
606 }
607 
compareElementsDifferentTypes(daeElement & elt1,daeElement & elt2)608 daeElement::compareResult compareElementsDifferentTypes(daeElement& elt1, daeElement& elt2) {
609     string value1, value2;
610 
611     // Compare attributes. Be careful because each element could have a
612     // different number of attributes.
613     if (elt1.getAttributeCount() > elt2.getAttributeCount())
614         return attrMismatch(elt1, elt2, elt1.getAttributeName(elt2.getAttributeCount()));
615     if (elt2.getAttributeCount() > elt1.getAttributeCount())
616         return attrMismatch(elt1, elt2, elt2.getAttributeName(elt1.getAttributeCount()));
617     for (size_t i = 0; i < elt1.getAttributeCount(); i++) {
618         elt1.getAttribute(i, value1);
619         elt2.getAttribute(elt1.getAttributeName(i).c_str(), value2);
620         if (value1 != value2)
621             return attrMismatch(elt1, elt2, elt1.getAttributeName(i));
622     }
623 
624     // Compare character data
625     elt1.getCharData(value1);
626     elt2.getCharData(value2);
627     if (value1 != value2)
628         return charDataMismatch(elt1, elt2);
629 
630     // Compare children
631     daeElementRefArray children1 = elt1.getChildren(),
632                        children2 = elt2.getChildren();
633     if (children1.getCount() != children2.getCount())
634         return childCountMismatch(elt1, elt2);
635     for (size_t i = 0; i < children1.getCount(); i++) {
636         daeElement::compareResult result = daeElement::compareWithFullResult(*children1[i], *children2[i]);
637         if (result.compareValue != 0)
638             return result;
639     }
640 
641     return compareMatch();
642 }
643 } // namespace {
644 
compare(daeElement & elt1,daeElement & elt2)645 int daeElement::compare(daeElement& elt1, daeElement& elt2) {
646     return compareWithFullResult(elt1, elt2).compareValue;
647 }
648 
compareWithFullResult(daeElement & elt1,daeElement & elt2)649 daeElement::compareResult daeElement::compareWithFullResult(daeElement& elt1, daeElement& elt2) {
650     // Check the element name
651     if (strcmp(elt1.getElementName(), elt2.getElementName()) != 0)
652         return nameMismatch(elt1, elt2);
653 
654     // Dispatch to a specific function based on whether or not the types are the same
655     if ((elt1.typeID() != elt2.typeID())  ||  elt1.typeID() == getDomAnyID(*elt1.getDAE()))
656         return compareElementsDifferentTypes(elt1, elt2);
657     else
658         return compareElementsSameType(elt1, elt2);
659 }
660 
661 
getDocumentURI() const662 daeURI *daeElement::getDocumentURI() const {
663     if ( _document == NULL ) {
664         return NULL;
665     }
666     return _document->getDocumentURI();
667 }
668 
669 
matchName(daeString name)670 daeElement::matchName::matchName(daeString name) : name(name) {
671 }
672 
operator ()(daeElement * elt) const673 bool daeElement::matchName::operator()(daeElement* elt) const {
674     return strcmp(elt->getElementName(), name.c_str()) == 0;
675 }
676 
matchType(daeInt typeID)677 daeElement::matchType::matchType(daeInt typeID) : typeID(typeID) {
678 }
679 
operator ()(daeElement * elt) const680 bool daeElement::matchType::operator()(daeElement* elt) const {
681     return elt->typeID() == typeID;
682 }
683 
getChild(const matchElement & matcher)684 daeElement* daeElement::getChild(const matchElement& matcher) {
685     daeElementRefArray children;
686     getChildren(children);
687     for (size_t i = 0; i < children.getCount(); i++)
688         if (matcher(children[i]))
689             return children[i];
690 
691     return NULL;
692 }
693 
getDescendant(const matchElement & matcher)694 daeElement* daeElement::getDescendant(const matchElement& matcher) {
695     daeElementRefArray elts;
696     getChildren(elts);
697 
698     for (size_t i = 0; i < elts.getCount(); i++) {
699         // Check the current element for a match
700         if (matcher(elts[i]))
701             return elts[i];
702 
703         // Append the element's children to the queue
704         daeElementRefArray children;
705         elts[i]->getChildren(children);
706         size_t oldCount = elts.getCount();
707         elts.setCount(elts.getCount() + children.getCount());
708         for (size_t j = 0; j < children.getCount(); j++)
709             elts[oldCount + j] = children[j];
710     }
711 
712     return NULL;
713 }
714 
getAncestor(const matchElement & matcher)715 daeElement* daeElement::getAncestor(const matchElement& matcher) {
716     daeElement* elt = getParent();
717     while (elt) {
718         if (matcher(elt))
719             return elt;
720         elt = elt->getParent();
721     }
722 
723     return NULL;
724 }
725 
getParent()726 daeElement* daeElement::getParent() {
727     return _parent;
728 }
729 
getChild(daeString eltName)730 daeElement* daeElement::getChild(daeString eltName) {
731     if (!eltName)
732         return NULL;
733     matchName test(eltName);
734     return getChild(matchName(eltName));
735 }
736 
getDescendant(daeString eltName)737 daeElement* daeElement::getDescendant(daeString eltName) {
738     if (!eltName)
739         return NULL;
740     return getDescendant(matchName(eltName));
741 }
742 
getAncestor(daeString eltName)743 daeElement* daeElement::getAncestor(daeString eltName) {
744     if (!eltName)
745         return NULL;
746     return getAncestor(matchName(eltName));
747 }
748 
getDAE()749 DAE* daeElement::getDAE() {
750     return _meta->getDAE();
751 }
752 
setUserData(void * data)753 void daeElement::setUserData(void* data) {
754     _userData = data;
755 }
756 
getUserData()757 void* daeElement::getUserData() {
758     return _userData;
759 }
760