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