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/ScXML.h>
34 
35 /*!
36   \class ScXML ScXML.h Inventor/scxml/ScXML.h
37   \brief namespace for static ScXML-related functions.
38 
39   This is a static namespace class for ScXML-related functions.
40 
41   \since Coin 3.0
42   \ingroup scxml
43 */
44 
45 #ifdef _MSC_VER
46 #pragma warning(disable:4786) // symbol truncated
47 #endif // _MSC_VER
48 
49 #include <Inventor/SbName.h>
50 #include <Inventor/errors/SoDebugError.h>
51 
52 #include <Inventor/misc/CoinResources.h>
53 
54 #include <Inventor/scxml/ScXML.h>
55 #include <Inventor/scxml/ScXMLObject.h>
56 #include <Inventor/scxml/ScXMLEvent.h>
57 #include <Inventor/scxml/ScXMLEventTarget.h>
58 #include <Inventor/scxml/ScXMLDocument.h>
59 
60 #include <Inventor/scxml/ScXMLElt.h>
61 #include <Inventor/scxml/ScXMLScxmlElt.h>
62 #include <Inventor/scxml/ScXMLInitialElt.h>
63 #include <Inventor/scxml/ScXMLAbstractStateElt.h>
64 #include <Inventor/scxml/ScXMLStateElt.h>
65 #include <Inventor/scxml/ScXMLParallelElt.h>
66 #include <Inventor/scxml/ScXMLFinalElt.h>
67 #include <Inventor/scxml/ScXMLOnEntryElt.h>
68 #include <Inventor/scxml/ScXMLOnExitElt.h>
69 #include <Inventor/scxml/ScXMLTransitionElt.h>
70 #include <Inventor/scxml/ScXMLHistoryElt.h>
71 
72 #include <Inventor/scxml/ScXMLExecutableElt.h>
73 #include <Inventor/scxml/ScXMLEventElt.h>
74 #include <Inventor/scxml/ScXMLIfElt.h>
75 #include <Inventor/scxml/ScXMLElseIfElt.h>
76 #include <Inventor/scxml/ScXMLElseElt.h>
77 #include <Inventor/scxml/ScXMLLogElt.h>
78 
79 #include <Inventor/scxml/ScXMLDataModelElt.h>
80 #include <Inventor/scxml/ScXMLDataElt.h>
81 #include <Inventor/scxml/ScXMLAssignElt.h>
82 #include <Inventor/scxml/ScXMLValidateElt.h>
83 
84 #include <Inventor/scxml/ScXMLSendElt.h>
85 #include <Inventor/scxml/ScXMLInvokeElt.h>
86 #include <Inventor/scxml/ScXMLParamElt.h>
87 #include <Inventor/scxml/ScXMLFinalizeElt.h>
88 #include <Inventor/scxml/ScXMLContentElt.h>
89 
90 #include <Inventor/scxml/ScXMLAnchorElt.h>
91 
92 #include <Inventor/scxml/ScXMLEvaluator.h>
93 #include <Inventor/scxml/ScXMLMinimumEvaluator.h>
94 #include <Inventor/scxml/ScXMLXPathEvaluator.h>
95 #include <Inventor/scxml/ScXMLECMAScriptEvaluator.h>
96 #include <Inventor/scxml/ScXMLCoinEvaluator.h>
97 
98 #include <Inventor/scxml/SoScXMLEvent.h>
99 #include <Inventor/scxml/SoScXMLStateMachine.h>
100 
101 #include "tidbitsp.h"
102 
103 #include "scxml/ScXMLP.h"
104 
105 // *************************************************************************
106 
107 /*!
108   \page scxml State Chart XML
109 
110   The ScXML part of Coin is a basic, non-conformant, partial
111   implementation of State Chart XML, based on the W3C Working Draft
112   16 May 2008 of SCXML <http://www.w3.org/TR/2008/WD-scxml-20080516/>.
113   The latest version should be at <http://www.w3.org/TR/scxml/>.
114   Read that document for a basic understanding how SCXML documents
115   should be constructed.
116 
117   Coin uses SCXML for setting up its navigation systems, to be able to
118   remove hardcoded logic for user navigation and externalize it into XML
119   files.  This makes it easy for users to customize the navigation
120   system for their own purposes.
121 
122   Unsupported Items:
123 
124   - The &lt;parallel&gt; element is not supported as intended with
125     parallel states.  Coin will just treat it as an ordinary
126     &lt;state&gt; element for now.  Parallel states is not high up on
127     the priority list, so expect this to be handled after a lot of
128     other functionality is in place.
129 
130   - The &lt;datamodel&gt;-related part of the specification is not
131     fully supported.
132 
133   - The 'target' attribute in the &lt;transition&gt; element can only
134     identify a single state currently, not multiple as you would have
135     to when having support for &lt;parallel&gt; elements (which we
136     don't have).
137 
138   - The virtual state elements like &lt;history&gt; and &lt;anchor&gt;
139     are just implemented as dummy states for now and do not do
140     anything in relation to what they should actually do.
141 
142   For learning more about how ScXML is implemented and used in Coin,
143   take a look at $COINDIR/scxml/navigation/examiner.xml (or in the
144   Coin source directory, data/scxml/navigation/examiner.xml) for an
145   example of how an SCXML system for camera navigation looks,
146   and look at the source files in src/navigation/ for the C++ counterparts
147   to the same SCXML navigation system.
148 
149   \ingroup scxml
150   \since Coin 3.0
151 */
152 
153 // *************************************************************************
154 
155 extern "C" {
156 static void scxml_cleanup(void);
157 }
158 
159 /*!
160   Initializes the basic ScXML classes.
161 */
162 void
initClasses(void)163 ScXML::initClasses(void)
164 {
165   ScXMLP::init();
166   ScXMLObject::initClass();
167   ScXMLEvent::initClass();
168   ScXMLEventTarget::initClass();
169   ScXMLStateMachine::initClass();
170   ScXMLDocument::initClass();
171 
172   ScXMLElt::initClass();
173   ScXMLScxmlElt::initClass();
174   ScXMLInitialElt::initClass();
175   ScXMLAbstractStateElt::initClass();
176   ScXMLStateElt::initClass();
177   ScXMLParallelElt::initClass();
178   ScXMLFinalElt::initClass();
179   ScXMLOnEntryElt::initClass();
180   ScXMLOnExitElt::initClass();
181   ScXMLTransitionElt::initClass();
182   ScXMLHistoryElt::initClass();
183 
184   ScXMLExecutableElt::initClass();
185   ScXMLEventElt::initClass();
186   ScXMLIfElt::initClass();
187   ScXMLElseIfElt::initClass();
188   ScXMLElseElt::initClass();
189   ScXMLLogElt::initClass();
190 
191   ScXMLDataModelElt::initClass();
192   ScXMLDataElt::initClass();
193   ScXMLAssignElt::initClass();
194   ScXMLValidateElt::initClass();
195 
196   ScXMLSendElt::initClass();
197   ScXMLInvokeElt::initClass();
198   ScXMLParamElt::initClass();
199   ScXMLFinalizeElt::initClass();
200   ScXMLContentElt::initClass();
201 
202   ScXMLAnchorElt::initClass();
203 
204   // evaluators also inits data-objs
205   ScXMLEvaluator::initClass();
206   ScXMLMinimumEvaluator::initClass();
207   ScXMLXPathEvaluator::initClass();
208   ScXMLECMAScriptEvaluator::initClass();
209   ScXMLCoinEvaluator::initClass();
210 
211   SoScXMLEvent::initClass();
212   SoScXMLStateMachine::initClass();
213 
214   coin_atexit(scxml_cleanup, CC_ATEXIT_NORMAL);
215 }
216 
217 void
scxml_cleanup(void)218 scxml_cleanup(void)
219 {
220   ScXML::cleanClasses();
221 }
222 
223 void
cleanClasses(void)224 ScXML::cleanClasses(void)
225 {
226   SoScXMLStateMachine::cleanClass();
227   SoScXMLEvent::cleanClass();
228 
229   ScXMLCoinEvaluator::cleanClass();
230   ScXMLECMAScriptEvaluator::cleanClass();
231   ScXMLXPathEvaluator::cleanClass();
232   ScXMLMinimumEvaluator::cleanClass();
233   ScXMLEvaluator::cleanClass();
234 
235   ScXMLAnchorElt::cleanClass();
236 
237   ScXMLContentElt::cleanClass();
238   ScXMLFinalizeElt::cleanClass();
239   ScXMLParamElt::cleanClass();
240   ScXMLInvokeElt::cleanClass();
241   ScXMLSendElt::cleanClass();
242 
243   ScXMLValidateElt::cleanClass();
244   ScXMLAssignElt::cleanClass();
245   ScXMLDataElt::cleanClass();
246   ScXMLDataModelElt::cleanClass();
247 
248   ScXMLLogElt::cleanClass();
249   ScXMLElseElt::cleanClass();
250   ScXMLElseIfElt::cleanClass();
251   ScXMLIfElt::cleanClass();
252   ScXMLEventElt::cleanClass();
253   ScXMLExecutableElt::cleanClass();
254 
255   ScXMLHistoryElt::cleanClass();
256   ScXMLTransitionElt::cleanClass();
257   ScXMLOnExitElt::cleanClass();
258   ScXMLOnEntryElt::cleanClass();
259   ScXMLFinalElt::cleanClass();
260   ScXMLParallelElt::cleanClass();
261   ScXMLStateElt::cleanClass();
262   ScXMLAbstractStateElt::cleanClass();
263   ScXMLInitialElt::cleanClass();
264   ScXMLScxmlElt::cleanClass();
265   ScXMLElt::cleanClass();
266 
267   ScXMLDocument::cleanClass();
268   ScXMLStateMachine::cleanClass();
269   ScXMLEventTarget::cleanClass();
270   ScXMLEvent::cleanClass();
271   ScXMLObject::cleanClass();
272   ScXMLP::cleanup();
273 }
274 
275 // *************************************************************************
276 
277 SbBool
registerEvaluatorType(SbName profilename,SoType evaluatortype)278 ScXML::registerEvaluatorType(SbName profilename, SoType evaluatortype)
279 {
280   assert(!evaluatortype.isBad());
281   assert(ScXMLP::profileevaluators);
282   if (!evaluatortype.isDerivedFrom(ScXMLEvaluator::getClassTypeId())) {
283     SoDebugError::post("ScXMLStateMachine::registerEvaluator",
284                        "Evaluator type must be derived from ScXMLEvaluator");
285     return FALSE;
286   }
287   ScXMLP::TypeDict::iterator it = ScXMLP::profileevaluators->find(profilename.getString());
288   if (it != ScXMLP::profileevaluators->end()) {
289     SoDebugError::post("ScXML::registerEvaluatorType",
290                        "Evaluator for profile '%s' already registered.\n",
291                        profilename.getString());
292     return FALSE;
293   }
294   ScXMLP::TypeEntry entry(profilename.getString(), evaluatortype);
295   ScXMLP::profileevaluators->insert(entry);
296   return TRUE;
297 }
298 
299 SbBool
unregisterEvaluatorType(SbName profilename,SoType evaluatortype)300 ScXML::unregisterEvaluatorType(SbName profilename, SoType evaluatortype)
301 {
302   assert(!evaluatortype.isBad());
303   assert(ScXMLP::profileevaluators);
304 
305   ScXMLP::TypeDict::iterator it = ScXMLP::profileevaluators->find(profilename.getString());
306   if (it == ScXMLP::profileevaluators->end()) {
307     SoDebugError::post("ScXML::unregisterEvaluatorType",
308                        "No evaluator type is registered for profile '%s'.\n",
309                        profilename.getString());
310     return FALSE;
311   }
312   if (it->second != evaluatortype) {
313     SoDebugError::post("ScXML::unregisterEvaluatorType",
314                        "Different evaluator type registered for profile '%s'.\n",
315                        profilename.getString());
316     return FALSE;
317   }
318   ScXMLP::profileevaluators->erase(it);
319   return TRUE;
320 }
321 
322 SoType
getEvaluatorTypeForProfile(SbName profilename)323 ScXML::getEvaluatorTypeForProfile(SbName profilename)
324 {
325   assert(ScXMLP::profileevaluators);
326 
327   ScXMLP::TypeDict::iterator it = ScXMLP::profileevaluators->find(profilename.getString());
328   if (it == ScXMLP::profileevaluators->end()) {
329     // no type registered for profile
330     return SoType::badType();
331   }
332   return it->second;
333 }
334 
335 // *************************************************************************
336 // SCXML FILE INPUT
337 // *************************************************************************
338 
339 /*!
340   This function reads in an SCXML document from a file.
341 
342   \returns an ScXMLDocument-derived statemachine object hierarchy.
343 */
344 ScXMLStateMachine *
readFile(const char * filename)345 ScXML::readFile(const char * filename)
346 {
347   ScXMLDocument * doc = ScXMLDocument::readFile(filename);
348   if (!doc) {
349     return NULL;
350   }
351 
352   ScXMLStateMachine * statemachine = new SoScXMLStateMachine;
353   statemachine->setDescription(doc);
354   statemachine->setName(filename);
355 
356   return statemachine;
357 }
358 
359 /*!
360   This function reads in an SCXML document residing in memory.
361 
362   \returns an ScXMLDocument-derived statemachine object hierarchy.
363 */
364 ScXMLStateMachine *
readBuffer(const SbByteBuffer & bufferdata)365 ScXML::readBuffer(const SbByteBuffer & bufferdata)
366 {
367   ScXMLDocument * doc = ScXMLDocument::readBuffer(bufferdata);
368   if (!doc) {
369     return NULL;
370   }
371 
372   ScXMLStateMachine * statemachine = new SoScXMLStateMachine;
373   statemachine->setDescription(doc);
374   statemachine->setName("<memory buffer>");
375 
376   return statemachine;
377 }
378 
379 // *************************************************************************
380