1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 #include <Inventor/scxml/ScXMLElt.h>
34 #include "coindefs.h"
35 
36 /*!
37   \class ScXMLElt ScXMLElt.h Inventor/scxml/ScXMLElt.h
38   \brief base class for all SCXML elements.
39 
40   This is a common base class for all SCXML document element classes.
41   It manages XML attributes at the generic level, has utilities for
42   checking document containment, and provides some infrastructure hooks.
43 
44   \since Coin 3.1
45   \ingroup scxml
46 */
47 
48 /*!
49   \class ScXMLEltReader ScXMLElt.h Inventor/scxml/ScXMLElt.h
50   \brief base class for element reader objects
51 
52   \since Coin 3.1
53   \ingroup scxml
54 */
55 
56 #ifdef _MSC_VER
57 #pragma warning(disable:4786) // symbol truncated
58 #endif // _MSC_VER
59 
60 #include <cstring>
61 #include <cassert>
62 #include <map>
63 
64 #include <Inventor/SbName.h>
65 #include <Inventor/errors/SoDebugError.h>
66 #include <Inventor/C/XML/element.h>
67 #include <Inventor/C/XML/attribute.h>
68 #include <Inventor/scxml/ScXML.h>
69 
70 #include "scxml/ScXMLP.h"
71 
72 // *************************************************************************
73 
ScXMLEltReader(const char * eltname)74 ScXMLEltReader::ScXMLEltReader(const char * eltname)
75 : element(eltname)
76 {
77 }
78 
~ScXMLEltReader(void)79 ScXMLEltReader::~ScXMLEltReader(void)
80 {
81 }
82 
83 void
setXMLAttributes(ScXMLElt * scxmlelt,cc_xml_elt * xmlelt)84 ScXMLEltReader::setXMLAttributes(ScXMLElt * scxmlelt, cc_xml_elt * xmlelt)
85 {
86   const int numattrs = cc_xml_elt_get_num_attributes(xmlelt);
87   const cc_xml_attr ** attrs = cc_xml_elt_get_attributes(xmlelt);
88   for (int c = 0; c < numattrs; ++c) {
89     const char * attrname = cc_xml_attr_get_name(attrs[c]);
90     const char * attrvalue = cc_xml_attr_get_value(attrs[c]);
91     scxmlelt->setXMLAttribute(attrname, attrvalue);
92   }
93 }
94 
95 // *************************************************************************
96 
97 class ScXMLElt::PImpl {
98 public:
99   typedef std::map<const char *, char *> AttributeMap;
100   typedef std::pair<const char *, char *> AttributeEntry;
101   AttributeMap attributemap;
102 
~PImpl(void)103   ~PImpl(void)
104   {
105     AttributeMap::iterator it = this->attributemap.begin();
106     while (it != this->attributemap.end()) {
107       delete [] it->second;
108       ++it;
109     }
110     this->attributemap.clear();
111   }
112 };
113 
114 #define PRIVATE(obj) ((obj)->pimpl)
115 
116 SCXML_ELEMENT_ABSTRACT_SOURCE(ScXMLElt);
117 
118 void
initClass(void)119 ScXMLElt::initClass(void)
120 {
121   SCXML_OBJECT_INIT_ABSTRACT_CLASS(ScXMLElt, ScXMLObject, "ScXMLObject");
122 }
123 
124 void
cleanClass(void)125 ScXMLElt::cleanClass(void)
126 {
127   ScXMLElt::classTypeId = SoType::badType();
128 }
129 
ScXMLElt(void)130 ScXMLElt::ScXMLElt(void)
131 : containerptr(NULL)
132 {
133 }
134 
~ScXMLElt(void)135 ScXMLElt::~ScXMLElt(void)
136 {
137   this->containerptr = NULL;
138 }
139 
140 /*!
141   This method associates a value with an attribute name.  This is
142   used for parameter passing while reading by the SCXML reader, but
143   can be used as a general-purpose attribute dictionary outside of
144   that.
145 
146   If NULL is passed as the value, the attribute is removed.
147 */
148 void
setXMLAttribute(const char * attribute,const char * value)149 ScXMLElt::setXMLAttribute(const char * attribute, const char * value)
150 {
151   assert(attribute);
152   const SbName attrname(attribute); // uniqify on string pointer
153   PImpl::AttributeMap::iterator it =
154     PRIVATE(this)->attributemap.find(attrname.getString());
155   if (it == PRIVATE(this)->attributemap.end()) {
156     if (value) {
157       char * valuedup = new char [ strlen(value) + 1 ];
158       strcpy(valuedup, value);
159       PRIVATE(this)->attributemap.insert(
160         PImpl::AttributeEntry(attrname.getString(), valuedup));
161     }
162   } else {
163     delete [] it->second;
164     it->second = NULL;
165     if (!value) {
166       PRIVATE(this)->attributemap.erase(it);
167     } else {
168       it->second = new char [ strlen(value) + 1 ];
169       strcpy(it->second, value);
170     }
171   }
172 }
173 
174 /*!
175   This method returns the string value set for an attribute, or
176   NULL if not set.
177 */
178 const char *
getXMLAttribute(const char * attribute) const179 ScXMLElt::getXMLAttribute(const char * attribute) const
180 {
181   const SbName attrname(attribute);
182   PImpl::AttributeMap::const_iterator it =
183     PRIVATE(this)->attributemap.find(attrname.getString());
184   if (it != PRIVATE(this)->attributemap.end()) {
185     return it->second;
186   }
187   return NULL;
188 }
189 
190 /*!
191   This method is called when the file reader has set all the XML
192   attributes on the object, and wants the object to handle them and
193   report if the values were ok or if a read error should be produced.
194 
195   \return TRUE if the attributes are ok, and FALSE on error.
196 
197   This base class implementation does nothing and just returns TRUE.
198 */
199 SbBool
handleXMLAttributes(void)200 ScXMLElt::handleXMLAttributes(void)
201 {
202   return TRUE;
203 }
204 
205 /*!
206   This method searches the SCXML structure for an element with the
207   given attributevalue for the given attribute.
208 
209   Returns NULL if nothing was found.
210 
211   This function needs to be reimplemented to traverse child elements.
212 */
213 const ScXMLElt *
search(const char * attrname,const char * attrvalue) const214 ScXMLElt::search(const char * attrname, const char * attrvalue) const
215 {
216   assert(attrname && attrvalue);
217   if (strstr(attrname, ":")) { // namespace attribute
218     const char * val = this->getXMLAttribute(attrname);
219     if (val != NULL) {
220       if (strcmp(val, attrvalue) == 0) {
221         return this;
222       }
223     }
224   }
225   return NULL;
226 }
227 
228 /*!
229   Returns a deep copy of the given SCXML element.
230 */
231 ScXMLElt *
clone(void) const232 ScXMLElt::clone(void) const
233 {
234   SoType elementtype(getTypeId());
235   if (!elementtype.canCreateInstance()) { return NULL; }
236   ScXMLElt * copy = static_cast<ScXMLElt *>(elementtype.createInstance());
237   copy->copyContents(this);
238   return copy;
239 }
240 
241 void
copyContents(const ScXMLElt * COIN_UNUSED_ARG (rhs))242 ScXMLElt::copyContents(const ScXMLElt * COIN_UNUSED_ARG(rhs))
243 {
244   // FIXME: copy XMLattribute map, otherwise xmlns attrs will be lost.
245 }
246 
247 /*!
248   Set the pointer to the parent ScXML object.
249 */
250 void
setContainer(ScXMLElt * container)251 ScXMLElt::setContainer(ScXMLElt * container)
252 {
253   this->containerptr = container;
254 }
255 
256 /*!
257   This method returns TRUE if the object is contained within the given
258   \a object argument. Also if they are the same, TRUE will be returned.
259   Otherwise, FALSE is retured.
260 */
261 SbBool
isContainedIn(const ScXMLElt * element) const262 ScXMLElt::isContainedIn(const ScXMLElt * element) const
263 {
264   const ScXMLElt * lineageobj = this;
265   while (lineageobj) {
266     if (lineageobj == element) return TRUE;
267     lineageobj = lineageobj->getContainer();
268   }
269   return FALSE;
270 }
271 
272 #undef PRIVATE
273