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