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 #ifndef __DAE_ELEMENT_H__
10 #define __DAE_ELEMENT_H__
11 #include <string>
12 #include <dae/daeTypes.h>
13 #include <dae/daeMemorySystem.h>
14 #include <wchar.h>
15 #include <dae/daeArray.h>
16 #include <dae/daeRefCountedObj.h>
17 #include <dae/daeSmartRef.h>
18 
19 //#ifndef NO_MALLOC_HEADER
20 //#include <malloc.h>
21 //#endif
22 
23 //namespace COLLADA_TYPE
24 //{
25 //	typedef int TypeEnum;
26 //}
27 
28 class DAE;
29 class daeMetaElement;
30 class daeMetaAttribute;
31 class daeDocument;
32 class daeURI;
33 
34 /**
35  * The @c daeElement class represents an instance of a COLLADA "Element";
36  * it is the main base class for the COLLADA Dom.
37  * Features of this class include:
38  * - Uses factory concepts defined via daeMetaElement
39  * - Composed of attributes, content elements and content values
40  * - Reference counted via daeSmartRef
41  * - Contains information for XML base URI, and XML containing element
42  */
43 class DLLSPEC daeElement : public daeRefCountedObj
44 {
45 public:
46     /**
47      * Macro that defines new and delete overrides for this class
48      */
49     DAE_ALLOC
50 protected:
51     daeElement* _parent;
52     daeDocument* _document;
53     daeMetaElement* _meta;
54     daeString _elementName;
55     daeBoolArray _validAttributeArray; // This is now obsolete and can be removed
56     void* _userData;
57 
58 protected:
daeElement(const daeElement & cpy)59     daeElement( const daeElement &cpy ) : daeRefCountedObj() {
60         (void)cpy;
61     };
62     virtual daeElement &operator=( const daeElement &cpy ) {
63         (void)cpy; return *this;
64     }
65 
66     void init();
67 
68     // These functions are called internally.
69     void setDocument( daeDocument* c, bool notifyDocument );
70     daeElement* simpleAdd(daeString name, int index = -1);
71 
72 public:
73     /**
74      * Element Constructor.
75      * @note This should not be used externally.
76      * Use factories to create elements
77      */
78     daeElement();
79     /**
80      * Element Constructor.
81      * @note This should not be used externally.
82      * Use factories to create elements
83      */
84     daeElement(DAE& dae);
85 
86     /**
87      * Element Destructor.
88      * @note This should not be used externally,
89      * if daeSmartRefs are being used.
90      */
91     virtual ~daeElement();
92 
93     /**
94      * Sets up a @c daeElement. Called on all @c daeElements as part of their initialization.
95      * @param meta Meta element to use to configure this element.
96      * @note Should not be called externally.
97      */
98     void setup(daeMetaElement* meta);
99 
100     // These functions are for adding child elements. They return null if adding
101     // the element failed.
102     daeElement* add(daeString name, int index = -1);
103     daeElement* add(daeElement* elt, int index = -1);
104     daeElement* addBefore(daeElement* elt, daeElement* index);
105     daeElement* addAfter(daeElement* elt, daeElement* index);
106 
107     // These functions are deprecated. Use 'add' instead.
108     daeElement* createAndPlace(daeString elementName);
109     daeElement* createAndPlaceAt(daeInt index, daeString elementName);
110     daeBool placeElement(daeElement* element);
111     daeBool placeElementAt(daeInt index, daeElement* element);
112     daeBool placeElementBefore( daeElement* marker, daeElement *element );
113     daeBool placeElementAfter( daeElement* marker, daeElement *element );
114 
115     /**
116      * Finds the last index into the array of children of the name specified.
117      * @param elementName The name to look for.
118      * @return Returns the index into the children array of the last element with name elementName. -1 if
119      *         there are no children of name elementName.
120      */
121     daeInt findLastIndexOf( daeString elementName );
122 
123     /**
124      * Removes the specified element from it parent, the @c this element.
125      * This function is the opposite of @c placeElement().  It removes the specified
126      * element from the <tt><i> _contents </i></tt> array, and from wherever else it appears
127      * inside of the @c this element.  Use this function instead of @c clear(), @c remove() or @c delete()
128      * if you want to keep the <tt><i> _contents </i></tt> field up-to-date.
129      *
130      * @param element Element to be removed in the @c this container.
131      * @return Returns true if the element was successfully removed, false otherwise.
132      */
133     daeBool removeChildElement(daeElement* element);
134 
135     /**
136      * Removes the specified element from its parent element.
137      * This function is the opposite of @c placeElement().  It removes the specified
138      * element from both the <tt><i> _contents </i></tt> array and from wherever else it appears
139      * inside of its parent. The function itself finds the parent, and is defined as a static method,
140      * since removing the element from its parent may result in the deletion of the element.
141      * If the element has no parent, nothing is done.
142      *
143      * Use this function instead of @c clear(), @c remove() or @c delete()
144      * if you want to keep <tt><i> _contents </i></tt> up-to-date.
145      *
146      * @param element Element to remove from its parent container, the function finds the parent element.
147      * @return Returns true if the element was successfully removed, false otherwise.
148      */
removeFromParent(daeElement * element)149     static daeBool removeFromParent(daeElement* element)
150     {
151         if(element != NULL && element->_parent != NULL)
152             return(element->_parent->removeChildElement(element));
153         return false;
154     };
155 
156     /**
157      * Returns the number of attributes in this element.
158      * @return The number of attributes this element has.
159      */
160     size_t getAttributeCount();
161 
162     /**
163      * Returns the daeMetaAttribute object corresponding to the attribute specified.
164      * @param name The name of the attribute to find.
165      * @return Returns the corresponding daeMetaAttribute object or NULL if this element
166      * doesn't have the specified attribute.
167      */
168     daeMetaAttribute* getAttributeObject(daeString name);
169 
170     /**
171      * Returns the daeMetaAttribute object corresponding to attribute i.
172      * @param i The index of the attribute to find.
173      * @return Returns the corresponding daeMetaAttribute object
174      */
175     daeMetaAttribute* getAttributeObject(size_t i);
176 
177     /**
178      * Returns the name of the attribute at the specified index.
179      * @param i The index of the attribute whose name should be retrieved.
180      * @return Returns the name of the attribute, or "" if the index is out of range.
181      */
182     std::string getAttributeName(size_t i);
183 
184     /**
185      * Checks if this element can have the attribute specified.
186      * @param name The name of the attribute to look for.
187      * @return Returns true is this element can have an attribute with the name specified. False otherwise.
188      */
189     daeBool hasAttribute(daeString name);
190 
191     /**
192      * Checks if an attribute has been set either by being loaded from the COLLADA document or set
193      * programmatically.
194      * @param name The name of the attribute to check.
195      * @return Returns true if the attribute has been set. False if the attribute hasn't been set
196      * or doesn't exist for this element.
197      */
198     daeBool isAttributeSet(daeString name);
199 
200     /**
201      * Gets an attribute's value as a string.
202      * @param name The name of the attribute.
203      * @return The value of the attribute. Returns an empty string if this element doesn't
204      * have the specified attribute.
205      */
206     std::string getAttribute(daeString name);
207 
208     /**
209      * Just like the previous method, this method gets an attribute's value as a string. It
210      * takes the string as a reference parameter instead of returning it, for extra efficiency.
211      * @param name The name of the attribute.
212      * @param A string in which to store the value of the attribute. This will be set to an empty
213      * string if this element doesn't have the specified attribute.
214      */
215     void getAttribute(daeString name, std::string& value);
216 
217     /**
218      * Gets an attribute's value as a string.
219      * @param i The index of the attribute to retrieve.
220      * @return The value of the attribute.
221      */
222     std::string getAttribute(size_t i);
223 
224     /**
225      * Just like the previous method, this method gets an attribute's value as a string. It
226      * takes the string as a reference parameter instead of returning it, for extra efficiency.
227      * @param i The index of the attribute to retrieve.
228      * @param A string in which to store the value of the attribute.
229      */
230     void getAttribute(size_t i, std::string& value);
231 
232     struct DLLSPEC attr {
233         attr();
234         attr(const std::string& name, const std::string& value);
235 
236         std::string name;
237         std::string value;
238     };
239 
240     /**
241      * Returns an array containing all the attributes of this element.
242      * @return A daeArray of attr objects.
243      */
244     daeTArray<attr> getAttributes();
245 
246     /**
247      * Just like the previous method, this method returns an array containing all the attributes
248      * of this element. It returns the result via a reference parameter for extra efficiency.
249      * @param attrs The array of attr objects to return.
250      */
251     void getAttributes(daeTArray<attr>& attrs);
252 
253     /**
254      * Sets the attribute to the specified value.
255      * @param name Attribute to set.
256      * @param value Value to apply to the attribute.
257      * @return Returns true if the attribute was found and the value was set, false otherwise.
258      */
259     virtual daeBool setAttribute(daeString name, daeString value);
260 
261     /**
262      * Sets the attribute at the specified index to the given value.
263      * @param i Index of the attribute to set.
264      * @param value Value to apply to the attribute.
265      * @return Returns true if the attribute was found and the value was set, false otherwise.
266      */
267     virtual daeBool setAttribute(size_t i, daeString value);
268 
269     /**
270      * Returns the daeMetaAttribute object corresponding to the character data for this element.
271      * @return Returns a daeMetaAttribute object or NULL if this element doesn't have
272      * character data.
273      */
274     daeMetaAttribute* getCharDataObject();
275 
276     /**
277      * Checks if this element can have character data.
278      * @return Returns true if this element can have character data, false otherwise.
279      */
280     daeBool hasCharData();
281 
282     /**
283      * Returns this element's character data as a string.
284      * @return A string containing this element's character data, or an empty string
285      * if this element can't have character data.
286      */
287     std::string getCharData();
288 
289     /**
290      * Similar to the previous method, but fills a string passed in by the user for efficiency.
291      * @param data The string to be filled with this element's character content. The
292      * string is set to an empty string if this element can't have character data.
293      */
294     void getCharData(std::string& data);
295 
296     /**
297      * Sets this element's character data.
298      * @param data The new character data of this element.
299      * @return Returns true if this element can have character data and the character data
300      * was successfully changed, false otherwise.
301      */
302     daeBool setCharData(const std::string& data);
303 
304     // These functions are deprecated.
305     daeMemoryRef getAttributeValue(daeString name); // Use getAttribute or getAttributeObject instead.
306     daeBool hasValue(); // Use hasCharData instead.
307     daeMemoryRef getValuePointer(); // Use getCharData or getCharDataObject instead.
308 
309     /**
310      * Finds the database document associated with @c this element.
311      * @return Returns the @c daeDocument representing the containing file or database
312      * group.
313      */
getDocument()314     daeDocument* getDocument() const {
315         return _document;
316     }
317 
318     /**
319      * Deprecated.
320      */
getCollection()321     daeDocument* getCollection() const {
322         return _document;
323     }
324 
325     /**
326      * Get the associated DAE object.
327      * @return The associated DAE object.
328      */
329     DAE* getDAE();
330 
331     /**
332      * Sets the database document associated with this element.
333      * @param c The daeDocument to associate with this element.
334      */
setDocument(daeDocument * c)335     void setDocument(daeDocument* c) {
336         setDocument( c, true );
337     }
338     /**
339      * Deprecated.
340      */
341     void setCollection(daeDocument* c );
342 
343     /**
344      * Gets the URI of the document containing this element, note that this is NOT the URI of the element.
345      * @return Returns a pointer to the daeURI of the document containing this element.
346      */
347     daeURI* getDocumentURI() const;
348 
349     /**
350      * Creates an element via the element factory system.  This creation
351      * is based @em only on potential child elements of this element.
352      * @param elementName Class name of the subelement to create.
353      * @return Returns the created @c daeElement, if it was successfully created.
354      */
355     daeSmartRef<daeElement> createElement(daeString elementName);
356 
357     /**
358      * Gets the container element for @c this element.
359      * If @c createAndPlace() was used to create the element, its parent is the the caller of @c createAndPlace().
360      * @return Returns the parent element, if @c this is not the top level element.
361      */
getParentElement()362     daeElement* getParentElement() {
363         return _parent;
364     }
365     /**
366      * Deprecated. Use getParentElement()
367      * @deprecated
368      */
getXMLParentElement()369     daeElement* getXMLParentElement() {
370         return _parent;
371     }
372     /**
373      * Sets the parent element for this element.
374      * @param newParent The element which is the new parent element for this element.
375      * @note This function is called internally and not meant to be called form the client application.
376      */
setParentElement(daeElement * parent)377     void setParentElement( daeElement *parent ) {
378         _parent = parent;
379     }
380 
381     // These are helper structures to let the xml hierarchy search functions know when we've
382     // found a match. You can implement a custom matcher by inheriting from this structure,
383     // just like matchName and matchType.
384     struct DLLSPEC matchElement {
385         virtual bool operator()(daeElement* elt) const = 0;
~matchElementmatchElement386         virtual ~matchElement() {
387         };
388     };
389 
390     // Matches an element by name
391     struct DLLSPEC matchName : public matchElement {
392         matchName(daeString name);
393         virtual bool operator()(daeElement* elt) const;
394         std::string name;
395     };
396 
397     // Matches an element by schema type
398     struct DLLSPEC matchType : public matchElement {
399         matchType(daeInt typeID);
400         virtual bool operator()(daeElement* elt) const;
401         daeInt typeID;
402     };
403 
404     // Returns a matching child element. By "child", I mean one hierarchy level beneath the
405     // current element. This function is basically the same as getDescendant, except that it
406     // only goes one level deep.
407     daeElement* getChild(const matchElement& matcher);
408 
409     // Performs a breadth-first search and returns a matching descendant element. A "descendant
410     // element" is an element beneath the current element in the xml hierarchy.
411     daeElement* getDescendant(const matchElement& matcher);
412 
413     // Returns the parent element.
414     daeElement* getParent();
415 
416     // Searches up through the xml hiearchy and returns a matching element.
417     daeElement* getAncestor(const matchElement& matcher);
418 
419     // These functions perform the same as the functions above, except that they take the element
420     // name to match as a string. This makes these functions a little simpler to use if you're
421     // matching based on element name, which is assumed to be the most common case. Instead of
422     // "getChild(matchName(eltName))", you can just write "getChild(eltName)".
423     daeElement* getChild(daeString eltName);
424     daeElement* getDescendant(daeString eltName);
425     daeElement* getAncestor(daeString eltName);
426 
427     /**
428      * Gets the associated Meta information for this element.  This
429      * Meta also acts as a factory.  See @c daeMetaElement documentation for more
430      * information.
431      * @return Returns the associated meta information.
432      */
getMeta()433     inline daeMetaElement* getMeta() {
434         return _meta;
435     }
436 
437     // These functions are deprecated. Use typeID instead.
438     //virtual COLLADA_TYPE::TypeEnum getElementType() const { return (COLLADA_TYPE::TypeEnum)0; }
439     daeString getTypeName() const;
440 
441     /**
442      * Returns this element's type ID. Every element is an instance of a type specified in
443      * the Collada schema, and every schema type has a unique ID.
444      * @return The element's type ID.
445      */
446     virtual daeInt typeID() const = 0;
447 
448     /**
449      * Gets this element's name.
450      * @return Returns the string for the name.
451      * @remarks This function returns NULL if the element's name is identical to it's type's name.
452      */
453     daeString getElementName() const;
454     /**
455      * Sets this element's name.
456      * @param nm Specifies the string to use as the element's name.
457      * @remarks Use caution when using this function since you can easily create invalid COLLADA documents.
458      */
459     void setElementName( daeString nm );
460 
461     /**
462      * Gets the element ID if it exists.
463      * @return Returns the value of the ID attribute, if there is such
464      * an attribute on this element type.
465      * @return the string for the element ID if it exists.
466      */
467     daeString getID() const;
468 
469     /**
470      * Gets the children/sub-elements of this element.
471      * This is a helper function used to easily access an element's children without the use of the
472      * _meta objects.  This function adds the convenience of the _contents array to elements that do
473      * not contain a _contents array.
474      * @return The return value.  An elementref array to append this element's children to.
475      */
476     daeTArray< daeSmartRef<daeElement> > getChildren();
477 
478     /**
479      * Same as the previous function, but returns the result via a parameter instead
480      * of a return value, for extra efficiency.
481      * @param array The return value.  An elementref array to append this element's children to.
482      */
483     //void getChildren( daeElementRefArray &array );
484     void getChildren( daeTArray<daeSmartRef<daeElement> > &array );
485 
486     /**
487      * Gets all the children of a particular type.
488      * @return An array containing the matching child elements.
489      */
490     template<typename T>
getChildrenByType()491     daeTArray< daeSmartRef<T> > getChildrenByType() {
492         daeTArray< daeSmartRef<T> > result;
493         getChildrenByType(result);
494         return result;
495     }
496 
497     /**
498      * Same as the previous function, but returns the result via a parameter instead
499      * of a return value, for extra efficiency.
500      * @return An array containing the matching child elements.
501      */
502     template<typename T>
getChildrenByType(daeTArray<daeSmartRef<T>> & matchingChildren)503     void getChildrenByType(daeTArray< daeSmartRef<T> >& matchingChildren) {
504         matchingChildren.setCount(0);
505         daeTArray< daeSmartRef<daeElement> > children;
506         getChildren(children);
507         for (size_t i = 0; i < children.getCount(); i++)
508             if (children[i]->typeID() == T::ID())
509                 matchingChildren.append((T*)children[i].cast());
510     }
511 
512     /**
513      * Clones/deep copies this @c daeElement and all of it's subtree.
514      * @param idSuffix A string to append to the copied element's ID, if one exists.
515      *        Default is no ID mangling.
516      * @param nameSuffix A string to append to the copied element's name, if one exists.
517      *        Default is no name mangling.
518      * @return Returns a @c daeElement smartref of the copy of this element.
519      */
520     daeSmartRef<daeElement> clone( daeString idSuffix = NULL, daeString nameSuffix = NULL );
521 
522     // Class for reporting info about element comparisons
523     struct DLLSPEC compareResult {
524         int compareValue; // > 0 if elt1 > elt2,
525                           // < 0 if elt1 < elt2,
526                           // = 0 if elt1 = elt2
527         daeElement* elt1;
528         daeElement* elt2;
529         bool nameMismatch; // true if the names didn't match
530         std::string attrMismatch; // The name of the mismatched attribute, or "" if there was no attr mismatch
531         bool charDataMismatch; // true if the char data didn't match
532         bool childCountMismatch; // true if the number of children didn't match
533 
534         compareResult();
535         std::string format(); // Write to a string
536     };
537 
538     // Function for doing a generic, recursive comparison of two xml elements. It
539     // also provides a full element ordering, so that you could store elements in
540     // a map or a set. Return val is > 0 if elt1 > elt2, < 0 if elt1 < elt2, and 0
541     // if elt1 == elt2.
542     static int compare(daeElement& elt1, daeElement& elt2);
543 
544     // Same as the previous function, but returns a full compareResult object.
545     static compareResult compareWithFullResult(daeElement& elt1, daeElement& elt2);
546 
547     /**
548      * Sets the user data pointer attached to this element.
549      * @param data User's custom data to store.
550      */
551     void setUserData(void* data);
552 
553     /**
554      * Gets the user data pointer attached to this element.
555      * @return User data pointer previously set with setUserData.
556      */
557     void* getUserData();
558 
559 public:
560     // This function is called internally
561     static void deleteCMDataArray(daeTArray<daeCharArray*>& cmData);
562 };
563 
564 #include <dae/daeSmartRef.h>
565 typedef daeSmartRef<daeElement> daeElementRef;
566 typedef daeSmartRef<const daeElement> daeElementConstRef;
567 //#include <dae/daeArray.h>
568 typedef daeTArray<daeElementRef> daeElementRefArray;
569 
570 #endif //__DAE_ELEMENT_H__
571