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 /*!
34   \class SoField SoField.h Inventor/fields/SoField.h
35   \brief The SoField class is the top-level abstract base class for fields.
36 
37   \ingroup fields
38 
39   Fields is the mechanism used throughout Coin for encapsulating basic
40   data types to detect changes made to them, and to provide
41   conversion, import and export facilities.
42 
43   Almost all public properties in nodes are stored in fields, and so
44   are the inputs and outputs of engines. So fields can be viewed as
45   the major mechanism for scenegraph nodes and engines to expose their
46   public API.
47 
48   Forcing data modification to go through a public function interface
49   while hiding the data members makes it possible to automatically
50   detect and react upon changes in the data structures set up by the
51   application programmer.
52 
53   E.g. the default behavior when changing the value of a field in a
54   scenegraph node is that there'll automatically be a chain of
55   notifications -- from the field to the owner node, from that node to
56   it's parent node, etc all the way through to the top-most root node,
57   where the need for a rendering update will be signalled to the
58   application.
59 
60   (This notification mechanism is the underlying feature that makes the
61   Coin library classify as a so-called \e data-driven scenegraph API.
62 
63   The practical consequences of this is that rendering and many other
64   processing actions is default scheduled to \e only happen when
65   something has changed in the retained data structures, making the
66   Coin library under normal circumstances \e much less CPU intensive
67   than so-called "application-driven" scenegraph API, like for
68   instance SGI IRIS Performer, which are continuously re-rendering
69   even when nothing has changed in the data structures or with the
70   camera viewport.)
71 
72   Storing data members as fields also provides other conveniences for
73   the application programmer:
74 
75   \li Fields can be connected to other fields. This makes it for
76       instance possible to have "self-updating" scenes, ie you can set
77       up scenes where entities \e automatically react to changes in
78       other entities. This also provides a necessary mechanism for
79       having "auto-animating" scenes, as it is possible to connect any
80       field to the global field named \c realTime, providing a
81       wall-clock timer.
82 
83   \li When connecting fields to each other, Coin has built-in
84       mechanisms for automatically converting between different field
85       types.
86 
87   \li Fields provide persistance for scenegraph import (and export)
88       operations. This includes animating entities, so animations can
89       be stored within ordinary Inventor format files.
90 
91   \li Fields provides features for introspection: they have a
92       type-system, just like for nodes and actions, they are named,
93       and it is also possible to find out which node, engine or other
94       entity owns a field.
95 
96   \li Fields can hold multiple values. Multi-value fields comes with a
97       much higher level interface abstraction than standard C/C++
98       arrays.
99 
100   Note: there are some field classes which has been obsoleted from the
101   Open Inventor API. They are: SoSFLong, SoSFULong, SoMFLong and
102   SoMFULong. You should use these classes instead (respectively):
103   SoSFInt32, SoSFUInt32, SoMFInt32 and SoMFUInt32.
104 
105   \TOOLMAKER_REF
106 
107   \sa SoFieldContainer, SoFieldData
108 */
109 
110 #include <Inventor/fields/SoField.h>
111 
112 #include <cassert>
113 #include <cstring>
114 
115 #include <Inventor/fields/SoFields.h>
116 
117 #include <Inventor/SoDB.h>
118 #include <Inventor/SoInput.h>
119 #include <Inventor/SoOutput.h>
120 #include <Inventor/actions/SoWriteAction.h>
121 #include <Inventor/engines/SoNodeEngine.h>
122 #include <Inventor/errors/SoDebugError.h>
123 #include <Inventor/errors/SoReadError.h>
124 #include <Inventor/lists/SoEngineList.h>
125 #include <Inventor/lists/SoEngineOutputList.h>
126 #include <Inventor/misc/SoProtoInstance.h>
127 #include <Inventor/nodes/SoNode.h>
128 #include <Inventor/sensors/SoDataSensor.h>
129 
130 #ifdef HAVE_CONFIG_H
131 #include "config.h"
132 #endif // HAVE_CONFIG_H
133 #include "SbBasicP.h"
134 #include "engines/SoConvertAll.h"
135 #include "fields/SoGlobalField.h"
136 #include "io/SoWriterefCounter.h"
137 #include "misc/SoConfigSettings.h"
138 #include "threads/threadsutilp.h"
139 #include "tidbitsp.h"
140 inline unsigned int SbHashFunc(const void * key);
141 #include "misc/SbHash.h"
SbHashFunc(const void * key)142 inline unsigned int SbHashFunc(const void * key)
143 {
144   return SbHashFunc(reinterpret_cast<size_t>(key));
145 }
146 #include "coindefs.h" // COIN_STUB()
147 
148 #ifdef COIN_THREADSAFE
149 #include "threads/recmutexp.h"
150 #define SOFIELD_RECLOCK (void) cc_recmutex_internal_field_lock()
151 #define SOFIELD_RECUNLOCK (void) cc_recmutex_internal_field_unlock()
152 
153 #else // COIN_THREADSAFE
154 
155 #define SOFIELD_RECLOCK
156 #define SOFIELD_RECUNLOCK
157 
158 #endif // !COIN_THREADSAFE
159 
160 static const int SOFIELD_GET_STACKBUFFER_SIZE = 1024;
161 // need one static mutex for field_buffer in SoField::get(SbString &)
162 static void * sofield_mutex = NULL;
163 
164 // flags for this->statusbits
165 
166 static const char IGNOREDCHAR = '~';
167 static const char CONNECTIONCHAR = '=';
168 /*
169   This class is used to aid in "multiplexing" the pointer member of
170   SoField. This is a way to achieve the goal of using minimum storage
171   space for SoField classes in the default case (which is important,
172   as fields are ubiquitous in Coin). The default case means no
173   connections and only a field container given. If any connections are
174   made (either "to" or "from"), we allocate an SoConnectStorage and
175   move the field container pointer into it, while swapping in the
176   SoConnectStorage pointer where the field container pointer used to
177   be.
178 */
179 class SoConnectStorage {
180 public:
SoConnectStorage(SoFieldContainer * c,SoType t)181   SoConnectStorage(SoFieldContainer * c, SoType t)
182     : container(c),
183     lastnotify(NULL),
184     fieldtype(t),
185     maptoconverter(13) // save about ~1kB vs default nr of buckets
186     {
187     }
188 
189 #if COIN_DEBUG
190   // Check that everything has been emptied.
~SoConnectStorage()191   ~SoConnectStorage()
192   {
193     assert(this->maptoconverter.getNumElements() == 0);
194 
195     assert(masterfields.getLength() == 0);
196     assert(masterengineouts.getLength() == 0);
197 
198     assert(slaves.getLength() == 0);
199     assert(auditors.getLength() == 0);
200   }
201 #endif // COIN_DEBUG
202 
203   // The container this field is part of.
204   SoFieldContainer * container;
205 
206   // List of masters we're connected to as a slave. Use maptoconverter
207   // dict to find SoFieldConverter engine in the connection (if any).
208   SoFieldList masterfields;
209   SoEngineOutputList masterengineouts;
210   // Fields which are slaves to us. Use maptoconverter dict to find
211   // SoFieldConverter engine in the connection (if any).
212   SoFieldList slaves;
213   // Direct auditors of us.
214   SoAuditorList auditors;
215 
216   // used to track the last notification (for fanIn handling)
217   void * lastnotify;
218 
219   // Convenience functions for adding, removing and finding mappings.
220 
addConverter(const void * item,SoFieldConverter * converter)221   void addConverter(const void * item, SoFieldConverter * converter)
222   {
223     // "item" can be SoField* or SoEngineOutput*.
224 
225     // FIXME: this probably hashes horribly bad, as the item value is
226     // a pointer and is therefore address-aligned (lower 32 (?) bits
227     // are all 0).  20010911 mortene.
228     this->maptoconverter.put(item, converter);
229   }
230 
removeConverter(const void * item)231   void removeConverter(const void * item)
232   {
233     size_t ok = this->maptoconverter.erase(item);
234     assert(ok);
235   }
236 
findConverter(const void * item)237   SoFieldConverter * findConverter(const void * item)
238   {
239     SoFieldConverter * val;
240     if (!this->maptoconverter.get(item, val)) { return NULL; }
241     return val;
242   }
243 
hasFanIn(void)244   SbBool hasFanIn(void) {
245     return (this->masterfields.getLength() + this->masterengineouts.getLength()) > 1;
246   }
findFanInEngine(void) const247   int findFanInEngine(void) const {
248     for (int i = 0; i < this->masterengineouts.getLength(); i++) {
249       SoEngineOutput * o = this->masterengineouts[i];
250       if (o->isNodeEngineOutput()) {
251         if (static_cast<void *>(o->getNodeContainer()) == this->lastnotify) return i;
252       }
253       else {
254         if (static_cast<void *>(o->getContainer()) == this->lastnotify) return i;
255       }
256     }
257     return -1;
258   }
findFanInField(void) const259   int findFanInField(void) const {
260     for (int i = 0; i < this->masterfields.getLength(); i++) {
261       if (static_cast<void *>(this->masterfields[i]->getContainer()) == this->lastnotify) return i;
262     }
263     return -1;
264   }
265 
266 
267   // Provides us with a hack to get at a master field's type in code
268   // called from its constructor (SoField::getTypeId() is virtual and
269   // can't be used).
270   //
271   // (Used in the master::~SoField() -> slave::disconnect(master)
272   // chain.)
273   SoType fieldtype;
274   void add_vrml2_routes(SoOutput * out, const SoField * f);
275 
276 private:
277   // Dictionary of void* -> SoFieldConverter* mappings.
278   SbHash<const void *, SoFieldConverter *> maptoconverter;
279 
280 };
281 
282 // helper function. Used to check if field is in a vrml2 node
283 static SbBool
is_vrml2_field(const SoField * f)284 is_vrml2_field(const SoField * f)
285 {
286   assert(f);
287   SoFieldContainer * fc = f->getContainer();
288   // test fc to support fields with no container
289   if (fc && fc->isOfType(SoNode::getClassTypeId())) {
290     if (fc->isOfType(SoProtoInstance::getClassTypeId())) return TRUE;
291     if (coin_assert_cast<SoNode *>(fc)->getNodeType() & SoNode::VRML2) return TRUE;
292   }
293 
294   return FALSE;
295 }
296 
297 //
298 // add all connections to this field as routes in SoOutput.  SoOutput
299 // will decide when to write the ROUTEs.
300 //
301 void
add_vrml2_routes(SoOutput * out,const SoField * f)302 SoConnectStorage::add_vrml2_routes(SoOutput * out, const SoField * f)
303 {
304   SoFieldContainer * tofc = f->getContainer();
305   assert(tofc);
306   SbName toname, fromname;
307   (void) tofc->getFieldName(f, toname);
308 
309   int i;
310   for (i = 0; i < this->masterfields.getLength(); i++) {
311     SoField * master = this->masterfields[i];
312     SoFieldContainer * fc = master->getContainer();
313     assert(fc);
314     (void) fc->getFieldName(master, fromname);
315 
316     if (out->getStage() == SoOutput::COUNT_REFS) {
317       fc->addWriteReference(out, TRUE);
318       tofc->addWriteReference(out, TRUE);
319     }
320     else {
321       out->addRoute(fc, fromname, tofc, toname);
322     }
323   }
324   for (i = 0; i < this->masterengineouts.getLength(); i++) {
325     SoEngineOutput * engineout = this->masterengineouts[i];
326     SoFieldContainer * fc = engineout->getFieldContainer();
327     if (engineout->isNodeEngineOutput()) {
328       SoNodeEngine * engine = engineout->getNodeContainer();
329       assert(engine);
330       (void) engine->getOutputName(engineout, fromname);
331     }
332     else {
333       SoEngine * engine = engineout->getContainer();
334       assert(engine);
335       (void) engine->getOutputName(engineout, fromname);
336     }
337     if (out->getStage() == SoOutput::COUNT_REFS) {
338       fc->addWriteReference(out, TRUE);
339       tofc->addWriteReference(out, TRUE);
340     }
341     else {
342       out->addRoute(fc, fromname, tofc, toname);
343     }
344   }
345 }
346 
347 // Collects some private code for SoField.
348 //
349 // Note that there is no private implementation data pointer (aka
350 // "pimpl" or Cheshire Cat) for the SoField instances, as they should
351 // be as slim as possible. Therefore, this class only contains static
352 // functions.
353 class SoFieldP {
354 public:
355   // Convenience method to extract a string that identifies the field
356   // with as much relevant info as possible. Used from other debug
357   // output code.
getDebugIdString(const SoField * f)358   static SbString getDebugIdString(const SoField * f)
359   {
360     SoFieldContainer * fcontainer = f->getContainer();
361     SbName fname("<no-container>");
362     if (fcontainer) {
363       SbBool ok = fcontainer->getFieldName(f, fname);
364       if (!ok) { fname = "<not-yet-added>"; }
365     }
366     SbString s;
367     s.sprintf("field==%p/%s/'%s'",
368               f,
369               f->getTypeId().getName().getString(),
370               fname.getString());
371     return s;
372   }
373 
374   static SbHash<char *, char **> * getReallocHash(void);
375   static void * hashRealloc(void * bufptr, size_t size);
376 
377   static SbHash<char *, char **> * ptrhash;
378 };
379 
380 SbHash<char *, char **> * SoFieldP::ptrhash = NULL;
381 
382 extern "C" {
383 // atexit callbacks
384 static void SoField_cleanupClass(void);
385 static void hashExitCleanup(void);
386 static void field_mutex_cleanup(void);
387 }
388 
389 SbHash<char *, char **> *
getReallocHash(void)390 SoFieldP::getReallocHash(void)
391 {
392   // FIXME: protect with mutex?
393   if (SoFieldP::ptrhash == NULL) {
394     SoFieldP::ptrhash = new SbHash<char *, char **>;
395     coin_atexit(hashExitCleanup, CC_ATEXIT_NORMAL);
396   }
397   return SoFieldP::ptrhash;
398 }
399 
400 void
hashExitCleanup(void)401 hashExitCleanup(void)
402 {
403   assert(SoFieldP::ptrhash->getNumElements() == 0);
404   delete SoFieldP::ptrhash;
405   SoFieldP::ptrhash = NULL;
406 }
407 
408 void *
hashRealloc(void * bufptr,size_t size)409 SoFieldP::hashRealloc(void * bufptr, size_t size)
410 {
411   CC_MUTEX_LOCK(sofield_mutex);
412 
413   char ** bufptrptr = NULL;
414   SbBool ok = SoFieldP::ptrhash->get(static_cast<char *>(bufptr), bufptrptr);
415   assert(ok);
416 
417   // If *bufptrptr contains a NULL pointer, this is the first
418   // invocation and the initial memory buffer was on the stack.
419   char * newbuf;
420   if (*bufptrptr == NULL) {
421     // if initial buffer was on the stack, we need to manually copy
422     // the data into the new buffer.
423     newbuf = static_cast<char *>(malloc(size));
424     memcpy(newbuf, bufptr, SOFIELD_GET_STACKBUFFER_SIZE);
425   }
426   else {
427     newbuf = static_cast<char *>(realloc(bufptr, size));
428   }
429   if (newbuf != bufptr) {
430     size_t isok = SoFieldP::ptrhash->erase(static_cast<char *>(bufptr));
431     assert(isok);
432     *bufptrptr = newbuf;
433     SoFieldP::ptrhash->put(newbuf, bufptrptr);
434   }
435 
436   CC_MUTEX_UNLOCK(sofield_mutex);
437 
438   return newbuf;
439 }
440 
441 // *************************************************************************
442 
443 // Documentation for abstract methods.
444 
445 // FIXME: grab better version of getTypeId() doc from SoBase, SoAction
446 // and / or SoDetail. 20010913 mortene.
447 /*!
448   \fn SoType SoField::getTypeId(void) const
449 
450   Returns the type identification instance which uniquely identifies
451   the Coin field class the object belongs to.
452 
453   \sa getClassTypeId(), SoType
454 */
455 
456 /*!
457   \fn SbBool SoField::isSame(const SoField & f) const
458   Check for equal type and value(s).
459 */
460 
461 /*!
462   \fn void SoField::copyFrom(const SoField & f)
463 
464   Copy value(s) from \a f into this field. \a f must be of the same
465   type as this field.
466 */
467 
468 /*!
469   \fn SbBool SoField::readValue(SoInput * in)
470   Read field value(s).
471 */
472 
473 /*!
474   \fn void SoField::writeValue(SoOutput * out) const
475   Write field value(s).
476 */
477 
478 
479 // *************************************************************************
480 
481 SoType SoField::classTypeId STATIC_SOTYPE_INIT;
482 
483 // *************************************************************************
484 
485 // used to detect when a field that is already destructed is used
486 #define FLAG_ALIVE_PATTERN 0xbeef0000
487 
488 // private methods. Inlined inside this file only.
489 
490 // clear bits in statusbits
491 inline void
clearStatusBits(const unsigned int bits)492 SoField::clearStatusBits(const unsigned int bits)
493 {
494   this->statusbits &= ~bits;
495 }
496 
497 // sets bits in statusbits
498 inline void
setStatusBits(const unsigned int bits)499 SoField::setStatusBits(const unsigned int bits)
500 {
501   this->statusbits |= bits;
502 }
503 
504 // return TRUE if any of bits is set
505 inline SbBool
getStatus(const unsigned int bits) const506 SoField::getStatus(const unsigned int bits) const
507 {
508   return (this->statusbits & bits) != 0;
509 }
510 
511 // convenience method for clearing or setting based on boolean value
512 // returns TRUE if any bitflag changed value
513 inline SbBool
changeStatusBits(const unsigned int bits,const SbBool onoff)514 SoField::changeStatusBits(const unsigned int bits, const SbBool onoff)
515 {
516   unsigned int oldval = this->statusbits;
517   unsigned int newval = oldval;
518   if (onoff) newval |= bits;
519   else newval &= ~bits;
520   if (oldval != newval) {
521     this->statusbits = newval;
522     return TRUE;
523   }
524   return FALSE;
525 }
526 
527 // returns TRUE if this field has ext storage
528 inline SbBool
hasExtendedStorage(void) const529 SoField::hasExtendedStorage(void) const
530 {
531   return this->getStatus(FLAG_EXTSTORAGE);
532 }
533 
534 
535 /*!
536   This is the base constructor for field classes. It takes care of
537   doing the common parts of data initialization in fields.
538 */
SoField(void)539 SoField::SoField(void)
540   : container(NULL)
541 {
542   this->statusbits = 0;
543   this->setStatusBits(FLAG_DONOTIFY |
544                       FLAG_ISDEFAULT |
545                       FLAG_ENABLECONNECTS|
546                       FLAG_ALIVE_PATTERN);
547 }
548 
549 /*!
550   Destructor. Disconnects ourself from any connected field or engine
551   before we disconnect all auditors on the field.
552 */
~SoField()553 SoField::~SoField()
554 {
555   // set status bit to avoid evaluating this field while
556   // disconnecting connections.
557   this->setStatusBits(FLAG_ISDESTRUCTING);
558 
559 #if COIN_DEBUG_EXTRA
560   int wLevel =
561     SoConfigSettings::getInstance()->settingAsInt("COIN_WARNING_LEVEL");
562   if (wLevel>=3)
563     SoDebugError::postInfo("SoField::~SoField", "destructing %p", this);
564 #endif //COIN_DEBUG_EXTRA
565 
566   // Disconnect ourself from all connections where this field is the
567   // slave.
568   this->disconnect();
569 
570   if (this->hasExtendedStorage()) {
571 
572     // Disconnect slave fields using us as a master.
573     while (this->storage->slaves.getLength()) {
574       this->storage->slaves[0]->disconnect(this);
575     }
576 
577     // Disconnect other auditors.
578     while (this->storage->auditors.getLength()) {
579       SoNotRec::Type type = this->storage->auditors.getType(0);
580       void * obj = this->storage->auditors.getObject(0);
581 
582       switch (type) {
583       case SoNotRec::ENGINE:
584         static_cast<SoEngineOutput *>(obj)->removeConnection(this);
585         break;
586 
587       case SoNotRec::CONTAINER:
588         assert(FALSE && "Container should not be in auditorlist");
589         break;
590 
591       case SoNotRec::SENSOR:
592         static_cast<SoDataSensor *>(obj)->dyingReference();
593         break;
594 
595       case SoNotRec::FIELD:
596         assert(FALSE); // should not happen, as slave fields are removed first.
597         break;
598 
599       default:
600         assert(FALSE); // no other allowed types.
601         break;
602       }
603     }
604 
605     delete this->storage;
606   }
607 #if COIN_DEBUG_EXTRA
608   if (wLevel>=3)
609     SoDebugError::postInfo("SoField::~SoField", "%p done", this);
610 #endif //COIN_DEBUG_EXTRA
611 
612   this->clearStatusBits(FLAG_ALIVE_PATTERN);
613 }
614 
615 // atexit
616 void
field_mutex_cleanup(void)617 field_mutex_cleanup(void)
618 {
619   CC_MUTEX_DESTRUCT(sofield_mutex);
620 }
621 
622 /*!
623   Internal method called upon initialization of the library (from
624   SoDB::init()) to set up the type system.
625 */
626 void
initClass(void)627 SoField::initClass(void)
628 {
629   // Make sure we only initialize once.
630   assert(SoField::classTypeId == SoType::badType());
631 
632   CC_MUTEX_CONSTRUCT(sofield_mutex);
633   coin_atexit(field_mutex_cleanup, CC_ATEXIT_NORMAL);
634 
635   SoField::classTypeId = SoType::createType(SoType::badType(), "Field");
636   SoField::initClasses();
637   coin_atexit(SoField_cleanupClass, CC_ATEXIT_NORMAL);
638 }
639 
640 void
SoField_cleanupClass(void)641 SoField_cleanupClass(void)
642 {
643   SoField::cleanupClass();
644 }
645 
646 void
cleanupClass(void)647 SoField::cleanupClass(void)
648 {
649   SoField::classTypeId STATIC_SOTYPE_INIT;
650 }
651 
652 /*!
653   Sets the flag which indicates whether or not the field should be
654   ignored during certain operations.
655 
656   The effect of this flag depends on what type of field it is used on,
657   and the type of the node which includes the field.
658 
659   This flag is represented in Inventor files by a ~ behind the field
660   name.  The flag is in other words persistent.
661 
662   \sa isIgnored()
663 */
664 void
setIgnored(SbBool ignore)665 SoField::setIgnored(SbBool ignore)
666 {
667   if (this->changeStatusBits(FLAG_IGNORE, ignore)) {
668     this->valueChanged(FALSE);
669   }
670 }
671 
672 /*!
673   Returns the ignore flag.
674 
675   \sa setIgnored()
676 */
677 SbBool
isIgnored(void) const678 SoField::isIgnored(void) const
679 {
680   return this->getStatus(FLAG_IGNORE);
681 }
682 
683 /*!
684   Set whether or not this field should be marked as containing a
685   default value.
686 
687   \sa isDefault()
688 */
689 void
setDefault(SbBool def)690 SoField::setDefault(SbBool def)
691 {
692 #if COIN_DEBUG_EXTRA
693   int wLevel =
694     SoConfigSettings::getInstance()->settingAsInt("COIN_WARNING_LEVEL");
695   if (wLevel>=3) {
696     SbString finfo = SoFieldP::getDebugIdString(this);
697     SoDebugError::postInfo("SoField::setDefault", "%s, setDefault(%s)",
698                            finfo.getString(), def ? "TRUE" : "FALSE");
699   }
700 #endif //COIN_DEBUG_EXTRA
701 
702   (void) this->changeStatusBits(FLAG_ISDEFAULT, def);
703 }
704 
705 /*!
706   Check if the field contains its default value. Fields which has
707   their default value intact will normally not be included in the
708   output when writing scene graphs out to a file, for instance.
709 
710   \sa setDefault()
711 */
712 SbBool
isDefault(void) const713 SoField::isDefault(void) const
714 {
715   return this->getStatus(FLAG_ISDEFAULT);
716 }
717 
718 /*!
719   Returns a unique type identifier for this field class.
720 
721   \sa getTypeId(), SoType
722 */
723 SoType
getClassTypeId(void)724 SoField::getClassTypeId(void)
725 {
726   return SoField::classTypeId;
727 }
728 
729 /*!
730   Check if this instance is of a derived type or is the same type as
731   the one given with the \a type parameter.
732 */
733 SbBool
isOfType(const SoType type) const734 SoField::isOfType(const SoType type) const
735 {
736   return this->getTypeId().isDerivedFrom(type);
737 }
738 
739 /*!
740   This sets a \a flag value which indicates whether or not the set up
741   connection should be considered active. For as long as the "enable
742   connection" flag is \c FALSE, no value propagation will be done from
743   any connected source field, engine or interpolator into this field.
744 
745   If the connection is first disabled and then enabled again, the
746   field will automatically be synchronized with any master field,
747   engine or interpolator.
748 
749   \sa isConnectionEnabled()
750 */
751 void
enableConnection(SbBool flag)752 SoField::enableConnection(SbBool flag)
753 {
754   SbBool oldval = this->getStatus(FLAG_ENABLECONNECTS);
755   (void) this->changeStatusBits(FLAG_ENABLECONNECTS, flag);
756   if (!oldval && flag) this->setDirty(TRUE);
757 }
758 
759 /*!
760   Return the current status of the connection enabled flag.
761 
762   \sa enableConnection()
763 */
764 SbBool
isConnectionEnabled(void) const765 SoField::isConnectionEnabled(void) const
766 {
767   return this->getStatus(FLAG_ENABLECONNECTS);
768 }
769 
770 /*!
771   Connects this field as a slave to \a master. This means that the
772   value of this field will be automatically updated when \a master is
773   changed (as long as the connection also is enabled).
774 
775   If this field had any connections to master fields beforehand, these
776   are all broken up if \a append is \c FALSE.
777 
778   Call with \a notnotify if you want to avoid the initial notification
779   of connected auditors (a.k.a. \e slaves).
780 
781   Function will return \c TRUE unless:
782 
783   \li If the field connected \e from has a different type from the
784       field connected \e to, a field converter is inserted. For some
785       combinations of fields no such conversion is possible, and we'll
786       return \c FALSE.
787 
788   \li If this field is already connected to the \a master, we will
789       return \c FALSE.
790 
791   \sa enableConnection(), isConnectionEnabled(), isConnectedFromField()
792   \sa getConnectedField(), appendConnection(SoField *)
793 */
794 SbBool
connectFrom(SoField * master,SbBool notnotify,SbBool append)795 SoField::connectFrom(SoField * master, SbBool notnotify, SbBool append)
796 {
797   // detect and ref() global fields. This is done to automatically
798   // detect when the last reference to a global field is deleted
799   if (master->getContainer() && master->getContainer()->isOfType(SoGlobalField::getClassTypeId())) {
800     master->getContainer()->ref();
801   }
802   // Initialize.  /////////////////////////////////////////////////
803 
804   this->extendStorageIfNecessary();
805   master->extendStorageIfNecessary();
806 
807   SoType mastertype = master->getTypeId();
808   SoType thistype = this->getTypeId();
809   SbBool containerisconverter = this->getContainer() &&
810     this->getContainer()->getTypeId().isDerivedFrom(SoFieldConverter::getClassTypeId());
811 
812 
813   // Set up all links.  ///////////////////////////////////////////
814 
815   if (mastertype == thistype) { // Can do direct field-to-field link.
816     if (!append) this->disconnect();
817     else if (this->storage->masterfields.find(master) >= 0) {
818       // detect and avoid multiple connections between the same fields
819       // (a common bug in VRML files created by 3ds max).
820 #if COIN_DEBUG
821       SoFieldContainer * fc = master->getContainer();
822       SbName fcname = fc ? fc->getName() : SbName::empty();
823       if (fcname != SbName::empty()) {
824         SbName fieldname;
825         (void) fc->getFieldName(master, fieldname);
826         SoDebugError::postWarning("SoField::connectFrom",
827                                   "connection from %p (%s.%s) already made",
828                                   master,
829                                   fcname.getString(),
830                                   fieldname.getString());
831 
832       }
833       else {
834         SoDebugError::postWarning("SoField::connectFrom",
835                                   "connection from %p already made", master);
836       }
837 #endif // COIN_DEBUG
838       return FALSE;
839     }
840     // Set up the auditor link from the master to the slave field.
841     // (Note that the ``this'' slave field can also be an input field
842     // of an SoFieldConverter instance.)
843     master->addAuditor(this, SoNotRec::FIELD);
844   }
845   else { // Needs an SoFieldConverter between the fields.
846     SoFieldConverter * conv = this->createConverter(mastertype);
847     if (!conv) {
848       // Just return FALSE and don't bother to warn, as that is done
849       // by the createConverter() method.
850       return FALSE;
851     }
852 
853     if (!append) this->disconnect();
854 
855     SoField * converterinput = conv->getInput(mastertype);
856     SoEngineOutput * converteroutput = conv->getOutput(thistype);
857 
858 #if COIN_DEBUG
859     if (converterinput == NULL) {
860       SoDebugError::post("SoField::connectFrom",
861                          "input field returned from field converter is NULL");
862       return FALSE;
863     } else if (converteroutput == NULL) {
864       SoDebugError::post("SoField::connectFrom",
865                          "output returned from field converter is NULL");
866       return FALSE;
867     }
868 #endif // COIN_DEBUG
869 
870     // Link up the input SoField of the SoFieldConverter to the master
871     // field by recursively calling connectFrom().
872     // the converter engine should always be notified upon connection
873     // as it will never have a default value read in from a file.
874     converterinput->connectFrom(master, FALSE);
875 
876     // Connect from the SoFieldConverter output to the slave field.
877     converteroutput->addConnection(this);
878 
879     // Remember the connection from the slave field to the
880     // SoFieldConverter by setting up a dict entry.
881     this->storage->addConverter(master, conv);
882   }
883 
884   // Common bookkeeping.
885   this->storage->masterfields.append(master); // slave -> master link
886   if (!containerisconverter)
887     master->storage->slaves.append(this); // master -> slave link
888 
889 
890   // Notification.  ///////////////////////////////////////////////
891 
892   if ((notnotify == FALSE) && this->isConnectionEnabled()) {
893     this->setDirty(TRUE);
894     this->setDefault(FALSE);
895     this->startNotify();
896   }
897 
898   return TRUE;
899 }
900 
901 /*!
902   Connects this field as a slave to \a master. This means that the value
903   of this field will be automatically updated when \a master is changed (as
904   long as the connection also is enabled).
905 
906   If this field had any master-relationships beforehand, these are all
907   broken up if \a append is \c FALSE.
908 
909   Call with \a notnotify if you want to avoid the initial notification
910   of connected auditors (a.k.a. \e slaves).
911 
912   Function will return \c TRUE unless:
913 
914   \li If the field output connected \e from is of a different type
915       from the engine output field-type connected \e to, a field
916       converter is inserted. For some combinations of fields no such
917       conversion is possible, and we'll return \c FALSE.
918 
919   \li If this field is already connected to the \a master, we will
920       return \c FALSE.
921 
922   \sa enableConnection(), isConnectionEnabled(), isConnectedFromField()
923   \sa getConnectedField(), appendConnection(SoEngineOutput *)
924 */
925 SbBool
connectFrom(SoEngineOutput * master,SbBool notnotify,SbBool append)926 SoField::connectFrom(SoEngineOutput * master, SbBool notnotify, SbBool append)
927 {
928   // Initialize.  /////////////////////////////////////////////////
929 
930   this->extendStorageIfNecessary();
931 
932   SoType mastertype = master->getConnectionType();
933   SoType thistype = this->getTypeId();
934 
935   // If we connectFrom() on the same engine as the field is already
936   // connected to, we want to avoid the master container engine being
937   // unref()'ed down to ref-count 0 upon the disconnect().
938   SoFieldContainer * masterengine = master->getFieldContainer();
939 
940   if (masterengine) masterengine->ref();
941 
942 
943   // Set up all links.  ///////////////////////////////////////////
944 
945   if (mastertype == thistype) { // Can do direct field-to-engineout link.
946     if (!append) this->disconnect();
947     else {
948       // check if we're already connected
949       if (this->storage->masterengineouts.find(master) >= 0) {
950         // detect and avoid multiple connections between the same
951         // field and engine output (a common bug in VRML files
952         // created by 3ds max).
953 #if COIN_DEBUG
954         SoDebugError::postWarning("SoField::connectFrom",
955                                   "connection from %p already made", master);
956 #endif // COIN_DEBUG
957         // Match the ref() invocation.
958         if (masterengine) masterengine->unref();
959         return FALSE;
960       }
961     }
962     // Set up the auditor link from the master engineout to the slave
963     // field.  (Note that the ``this'' slave field can also be an
964     // input field of an SoFieldConverter instance.)
965 
966     // This is enough, the container SoEngine will automatically pick
967     // up on it.
968     master->addConnection(this);
969   }
970   else { // Needs an SoFieldConverter between this field and the SoEngineOutput
971     SoFieldConverter * conv = this->createConverter(mastertype);
972     if (!conv) { // Handle this exception.
973       // Clean up the ref().
974       if (masterengine) masterengine->unref();
975       // Sorry, can't connect. Don't bother to spit out a warning, as
976       // that is done in createConverter().
977       return FALSE;
978     }
979 
980     if (!append) this->disconnect();
981 
982     SoField * converterinput = conv->getInput(mastertype);
983     SoEngineOutput * converteroutput = conv->getOutput(thistype);
984 
985 #if COIN_DEBUG
986     if (converterinput == NULL) {
987       SoDebugError::post("SoField::connectFrom",
988                          "input field returned from field converter is NULL");
989       return FALSE;
990     } else if (converteroutput == NULL) {
991       SoDebugError::post("SoField::connectFrom",
992                          "output returned from field converter is NULL");
993       return FALSE;
994     }
995 #endif // COIN_DEBUG
996 
997     // Link up the input SoField of the SoFieldConverter to the master
998     // SoEngineOutput by recursively calling connectFrom().
999     // the converter engine should always be notified upon connection
1000     // as it will never have a default value read in from a file
1001     converterinput->connectFrom(master, FALSE);
1002 
1003     // Connect from the SoFieldConverter output to the slave field.
1004     converteroutput->addConnection(this);
1005 
1006     // Remember the connection from the slave field to the
1007     // SoFieldConverter by setting up a dict entry.
1008     this->storage->addConverter(master, conv);
1009   }
1010 
1011   // Match the ref() invocation.
1012   if (masterengine) masterengine->unref();
1013 
1014   // Common bookkeeping.
1015   this->storage->masterengineouts.append(master); // slave -> master link
1016 
1017   // Notification.  ///////////////////////////////////////////////
1018 
1019   if ((notnotify == FALSE) && this->isConnectionEnabled()) {
1020     this->setDirty(TRUE);
1021     this->setDefault(FALSE);
1022     this->startNotify();
1023   }
1024 
1025   return TRUE;
1026 }
1027 
1028 
1029 /*!
1030   Disconnect this field as a slave from \a master.
1031 */
1032 void
disconnect(SoField * master)1033 SoField::disconnect(SoField * master)
1034 {
1035 #if COIN_DEBUG_EXTRA
1036   int wLevel =
1037     SoConfigSettings::getInstance()->settingAsInt("COIN_WARNING_LEVEL");
1038   if (wLevel>=3)
1039     SoDebugError::postInfo("SoField::disconnect",
1040                          "removing slave field %p from master field %p",
1041                          this, master);
1042 #endif //COIN_DEBUG_EXTRA
1043 
1044   const int idx = this->storage->masterfields.find(master);
1045   if (idx == -1) {
1046     SoDebugError::post("SoField::disconnect",
1047                        "can't disconnect from a field which we're not connected to!");
1048     return;
1049   }
1050 
1051   this->evaluate();
1052 
1053   SbBool containerisconverter = this->getContainer() &&
1054     this->getContainer()->getTypeId().isDerivedFrom(SoFieldConverter::getClassTypeId());
1055 
1056 
1057   // Decouple links. ///////////////////////////////////////////////////
1058 
1059   // Remove bookkeeping material.
1060   if (!containerisconverter) master->storage->slaves.removeItem(this);
1061 
1062   this->storage->masterfields.remove(idx);
1063 
1064   SoFieldConverter * converter = this->storage->findConverter(master);
1065   if (converter) { // There's a converter engine between the fields.
1066 
1067     SoField * converterinput =
1068       converter->getInput(SoType::badType()); // dummy type
1069     converterinput->disconnect(master);
1070 
1071     SoEngineOutput * converteroutput =
1072       converter->getOutput(SoType::badType()); // dummy type
1073     converteroutput->removeConnection(this);
1074 
1075     this->storage->removeConverter(master);
1076     converter->unref();
1077   }
1078   else { // No converter, just a direct link.
1079     master->removeAuditor(this, SoNotRec::FIELD);
1080   }
1081 
1082   // detect and unref() global fields. This is done to detect when the
1083   // last reference to a global fields is deleted.
1084   if (master->getContainer() && master->getContainer()->isOfType(SoGlobalField::getClassTypeId())) {
1085     master->getContainer()->unref();
1086   }
1087 }
1088 
1089 /*!
1090   Disconnect this field as a slave from \a master.
1091 */
1092 void
disconnect(SoEngineOutput * master)1093 SoField::disconnect(SoEngineOutput * master)
1094 {
1095   // First check to see we're the input field of an
1096   // SoFieldConverter. If so, recursively call disconnect() with the
1097   // field on "the other side" of the converter.
1098 
1099   SoType fieldconvtype = SoFieldConverter::getClassTypeId();
1100   SbBool containerisconverter =
1101     this->getContainer() &&
1102     this->getContainer()->getTypeId().isDerivedFrom(fieldconvtype);
1103   if (containerisconverter) {
1104     SoFieldConverter * converter =
1105       coin_assert_cast<SoFieldConverter *>(this->getContainer());
1106     SoEngineOutput * converterout =
1107       converter->getOutput(SoType::badType()); // dummy type
1108     SoFieldList fl;
1109     converterout->getForwardConnections(fl);
1110     fl[0]->disconnect(master);
1111     return;
1112   }
1113 
1114 
1115 #if COIN_DEBUG_EXTRA
1116   int wLevel =
1117     SoConfigSettings::getInstance()->settingAsInt("COIN_WARNING_LEVEL");
1118   if (wLevel>=3)
1119     SoDebugError::postInfo("SoField::disconnect",
1120                            "removing slave field %p (%s.%s) from master "
1121                            "engineout %p",
1122                            this,
1123                            this->storage->container->getTypeId().getName().getString(),
1124                            this->storage->fieldtype.getName().getString(),
1125                            master);
1126 #endif //COIN_DEBUG_EXTRA
1127 
1128 
1129   // Check the enabled flag to avoid evaluating from engines which are
1130   // being destructed. This is a bit of a hack, but I don't think it
1131   // matters.   -- mortene.
1132   if (master->isEnabled()) this->evaluate();
1133 
1134   // Decouple links. ///////////////////////////////////////////////////
1135 
1136   // Remove bookkeeping material.
1137   this->storage->masterengineouts.removeItem(master);
1138 
1139   SoFieldConverter * converter = this->storage->findConverter(master);
1140   if (converter) { // There's a converter engine between the fields.
1141     SoField * converterinput =
1142       converter->getInput(SoType::badType()); // dummy type
1143     converterinput->storage->masterengineouts.removeItem(master);
1144     master->removeConnection(converterinput);
1145 
1146     SoEngineOutput * converteroutput =
1147       converter->getOutput(SoType::badType()); // dummy type
1148     converteroutput->removeConnection(this);
1149 
1150     this->storage->removeConverter(master);
1151     converter->unref();
1152   }
1153   else { // No converter, just a direct link.
1154     master->removeConnection(this);
1155   }
1156 }
1157 
1158 /*!
1159   Returns number of fields this field is a slave of.
1160 
1161   \sa getConnections()
1162 */
1163 int
getNumConnections(void) const1164 SoField::getNumConnections(void) const
1165 {
1166   return this->hasExtendedStorage() ?
1167     this->storage->masterfields.getLength() : 0;
1168 }
1169 
1170 /*!
1171   Returns number of masters this field is connected to, and places
1172   pointers to all of them into \a masterlist.
1173 
1174   Note that we replace the contents of \a masterlist, i.e. we're \e
1175   not appending new data.
1176 
1177   \sa getNumConnections()
1178 */
1179 int
getConnections(SoFieldList & masterlist) const1180 SoField::getConnections(SoFieldList & masterlist) const
1181 {
1182   if (!this->hasExtendedStorage()) return 0;
1183 
1184   masterlist = this->storage->masterfields;
1185   return masterlist.getLength();
1186 }
1187 
1188 /*!
1189   Disconnect all connections from this field as a slave to master
1190   fields or engine outputs.
1191 */
1192 void
disconnect(void)1193 SoField::disconnect(void)
1194 {
1195   // Disconnect us from all master fields.
1196   while (this->isConnectedFromField())
1197     this->disconnect(this->storage->masterfields[0]);
1198 
1199   // Disconnect us from all master engine outputs.
1200   while (this->isConnectedFromEngine())
1201     this->disconnect(this->storage->masterengineouts[0]);
1202 
1203   assert(this->isConnected() == FALSE);
1204 }
1205 
1206 /*!
1207   Returns \c TRUE if we're connected from another field, engine or
1208   interpolator.
1209 
1210   \sa isConnectedFromField(), isConnectedFromEngine()
1211   \sa connectFrom()
1212 */
1213 SbBool
isConnected(void) const1214 SoField::isConnected(void) const
1215 {
1216   return (this->isConnectedFromField() ||
1217           this->isConnectedFromEngine());
1218 }
1219 
1220 /*!
1221   Returns \c TRUE if we're a slave of at least one field.
1222 
1223   \sa isConnected(), isConnectedFromEngine()
1224   \sa connectFrom(SoField *)
1225 */
1226 SbBool
isConnectedFromField(void) const1227 SoField::isConnectedFromField(void) const
1228 {
1229   return (this->hasExtendedStorage() &&
1230           this->storage->masterfields.getLength() > 0);
1231 }
1232 
1233 /*!
1234   Returns \c TRUE if we're connected from an engine.
1235 
1236   \sa isConnected(), isConnectedFromField()
1237   \sa connectFrom(SoEngineOutput *)
1238 */
1239 SbBool
isConnectedFromEngine(void) const1240 SoField::isConnectedFromEngine(void) const
1241 {
1242   return (this->hasExtendedStorage() &&
1243           this->storage->masterengineouts.getLength() > 0);
1244 }
1245 
1246 // Simplify by collecting common code for SoField::getConnected*() methods.
1247 #define SOFIELD_GETCONNECTED(_masterlist_) \
1248   if (!this->hasExtendedStorage()) return FALSE; \
1249   int nrmasters = this->storage->_masterlist_.getLength(); \
1250   if (nrmasters < 1) return FALSE; \
1251   master = this->storage->_masterlist_[nrmasters - 1]; \
1252   return TRUE
1253 
1254 /*!
1255   Returns \c TRUE if we are connected as a slave to at least one other
1256   field.  \a master will be set to the source field in the last field
1257   connection made.
1258 
1259   \sa isConnectedFromField(), connectFrom(SoField *),
1260   \sa appendConnection(SoField *)
1261 */
1262 SbBool
getConnectedField(SoField * & master) const1263 SoField::getConnectedField(SoField *& master) const
1264 {
1265   SOFIELD_GETCONNECTED(masterfields);
1266 }
1267 
1268 /*!
1269   Returns \c TRUE if we are connected as a slave to at least one
1270   engine. \a master will be set to the source of the last engine
1271   connection made.
1272 
1273   \sa isConnectedFromEngine(), connectFrom(SoEngineOutput *)
1274   \sa appendConnection(SoEngineOutput *)
1275 */
1276 SbBool
getConnectedEngine(SoEngineOutput * & master) const1277 SoField::getConnectedEngine(SoEngineOutput *& master) const
1278 {
1279   SOFIELD_GETCONNECTED(masterengineouts);
1280 }
1281 
1282 #undef SOFIELD_GETCONNECTED
1283 
1284 /*!
1285   Appends all the fields which are auditing this field in \a
1286   slavelist, and returns the number of fields which are our slaves.
1287 */
1288 int
getForwardConnections(SoFieldList & slavelist) const1289 SoField::getForwardConnections(SoFieldList & slavelist) const
1290 {
1291   if (!this->hasExtendedStorage()) return 0;
1292 
1293   int nr = 0;
1294 
1295   for (int i=0; i < this->storage->slaves.getLength(); i++) {
1296     slavelist.append(this->storage->slaves[i]);
1297     nr++;
1298   }
1299 
1300   return nr;
1301 }
1302 
1303 /*!
1304   Let the field know to which container it belongs.
1305 
1306   \sa getContainer(), SoFieldContainer
1307 */
1308 void
setContainer(SoFieldContainer * cont)1309 SoField::setContainer(SoFieldContainer * cont)
1310 {
1311   if (!this->hasExtendedStorage()) this->container = cont;
1312   else this->storage->container = cont;
1313 
1314   // The field should have been set to its default value before it is
1315   // added to the container.
1316   //
1317   // This might seem strange, but it looks like it is necessary to do
1318   // it this way to be compatible with Open Inventor.
1319   this->setDefault(TRUE);
1320 }
1321 
1322 /*!
1323   Returns the SoFieldContainer object "owning" this field.
1324 
1325   \sa SoFieldContainer, setContainer()
1326 */
1327 SoFieldContainer *
getContainer(void) const1328 SoField::getContainer(void) const
1329 {
1330   if (!this->hasExtendedStorage()) return this->container;
1331   else return this->storage->container;
1332 }
1333 
1334 /*!
1335   Set the field's value through the given \a valuestring. The format
1336   of the string must adhere to the ASCII format used in Coin data
1337   format files.
1338 
1339   Only the value should be specified - \e not the name of the field.
1340 
1341   \c FALSE is returned if the field value is invalid for the field
1342   type and can't be parsed in any sensible way.
1343 
1344   \sa get()
1345 */
1346 SbBool
set(const char * valuestring)1347 SoField::set(const char * valuestring)
1348 {
1349   // Note that it is not necessary to set a header identification line
1350   // for this to work.
1351   SoInput in;
1352   in.setBuffer(const_cast<char *>(valuestring), strlen(valuestring));
1353   if (!this->readValue(&in)) return FALSE;
1354 
1355   this->valueChanged();
1356   return TRUE;
1357 }
1358 
1359 /*!
1360   Returns the field's value as an ASCII string in the export data
1361   format for Inventor files.
1362 
1363   \sa set()
1364 */
1365 void
get(SbString & valuestring)1366 SoField::get(SbString & valuestring)
1367 {
1368   // FIXME: this function should be const! 20050607 mortene.
1369 
1370   // NOTE: this code has an almost verbatim copy in SoMField::get1(),
1371   // so remember to update both places if any fixes are done.
1372 
1373   // Initial buffer setup.
1374   SoOutput out;
1375   char initbuffer[SOFIELD_GET_STACKBUFFER_SIZE];
1376   char * bufferptr = NULL; // indicates that initial buffer is on the stack
1377 
1378   CC_MUTEX_LOCK(sofield_mutex);
1379   SbBool ok = SoFieldP::getReallocHash()->put(initbuffer, &bufferptr);
1380   assert(ok);
1381   CC_MUTEX_UNLOCK(sofield_mutex);
1382 
1383   out.setBuffer(initbuffer, sizeof(initbuffer), SoFieldP::hashRealloc);
1384 
1385   // Record offset to skip header.
1386   out.write("");
1387   size_t offset;
1388   void * buffer;
1389   out.getBuffer(buffer, offset);
1390 
1391   // Write field..
1392   out.setStage(SoOutput::COUNT_REFS);
1393   this->countWriteRefs(&out);
1394   out.setStage(SoOutput::WRITE);
1395   this->writeValue(&out);
1396 
1397   // ..then read it back into the SbString.
1398   size_t size;
1399   out.getBuffer(buffer, size);
1400   valuestring = static_cast<char *>(buffer) + offset;
1401 
1402   // dealloc tmp memory buffer
1403   if (bufferptr) { free(bufferptr); }
1404 
1405   CC_MUTEX_LOCK(sofield_mutex);
1406   size_t isok = SoFieldP::getReallocHash()->erase(bufferptr ? bufferptr : initbuffer);
1407   assert(isok);
1408   CC_MUTEX_UNLOCK(sofield_mutex);
1409 }
1410 
1411 /*!
1412   Notify the field as well as the field's owner / container that it
1413   has been changed.
1414 
1415   Touching a field which is part of any component (engine or node) in
1416   a scene graph will lead to a forced redraw. This is useful if you
1417   have been doing several updates to the field wrapped in a pair of
1418   enableNotify() calls to notify the field's auditors that its value
1419   has changed.
1420 
1421   \sa setValue(), enableNotify()
1422 */
1423 void
touch(void)1424 SoField::touch(void)
1425 {
1426   if (this->container) this->startNotify();
1427 }
1428 
1429 /*!
1430   Trigger a notification sequence.
1431 
1432   At the end of a notification sequence, all "immediate" sensors
1433   (i.e. sensors set up with a zero priority) are triggered.
1434 */
1435 void
startNotify(void)1436 SoField::startNotify(void)
1437 {
1438   SoNotList l;
1439 #if COIN_DEBUG_EXTRA
1440   int wLevel =
1441     SoConfigSettings::getInstance()->settingAsInt("COIN_WARNING_LEVEL");
1442   if (wLevel>=3)
1443     SoDebugError::postInfo("SoField::startNotify", "field %p (%s), list %p",
1444                          this, this->getTypeId().getName().getString(), &l);
1445 #endif //COIN_DEBUG_EXTRA
1446 
1447   SoDB::startNotify();
1448   this->notify(&l);
1449   SoDB::endNotify();
1450 
1451 #if COIN_DEBUG_EXTRA
1452   if (wLevel>=3)
1453     SoDebugError::postInfo("SoField::startNotify", "DONE\n\n");
1454 #endif //COIN_DEBUG_EXTRA
1455 }
1456 
1457 /*!
1458   Notify auditors that this field has changed.
1459 */
1460 void
notify(SoNotList * nlist)1461 SoField::notify(SoNotList * nlist)
1462 {
1463   assert((this->statusbits & FLAG_ALIVE_PATTERN) == FLAG_ALIVE_PATTERN);
1464 #if COIN_DEBUG
1465   if (this->getContainer()) {
1466     this->getContainer()->assertAlive();
1467   }
1468 #endif // COIN_DEBUG
1469 
1470   // check NotRec type to find if the notification was from a
1471   // connection. If someone changes the field directly we should
1472   // just continue.
1473 
1474   SoNotRec * rec = nlist->getLastRec();
1475   if (rec) {
1476     SoNotRec::Type t = nlist->getLastRec()->getType();
1477     if (t == SoNotRec::ENGINE || t == SoNotRec::FIELD) {
1478       if (this->hasExtendedStorage()) {
1479         this->storage->lastnotify = static_cast<void *>(rec->getBase());
1480       }
1481       // don't process the notification if we're notified from a
1482       // connection, and connection is disabled (through
1483       // enableConnection())
1484       if (!this->isConnectionEnabled()) return;
1485     }
1486   }
1487 
1488   // In Inventor it is legal to have circular field connections. This
1489   // test stops the notification from entering into an infinite
1490   // recursion because of such connections. The flag is set/cleared
1491   // before/after progagating the notification.
1492   if (this->getStatus(FLAG_ISNOTIFIED)) return;
1493 
1494   // needed because of the So[SF|MF]Node fields. When a node inside
1495   // such a field is changed we must mark the field as not default so
1496   // that SoWriteAction will export it. We can safely call
1497   // setDefault(FALSE) for other field types as well, since the only
1498   // other reason for entering here is if the field is connected from
1499   // an engine output or from another field.
1500   this->setDefault(FALSE);
1501 
1502 #if COIN_DEBUG_EXTRA
1503   int wLevel =
1504     SoConfigSettings::getInstance()->settingAsInt("COIN_WARNING_LEVEL");
1505   if (wLevel>=3)
1506     if (this != SoDB::getGlobalField("realTime")) {
1507       SoDebugError::postInfo("SoField::notify", "%p (%s (%s '%s')) -- start",
1508                              this,
1509                              this->getTypeId().getName().getString(),
1510                              this->getContainer() ? this->getContainer()->getTypeId().getName().getString() : "*none*",
1511                              this->getContainer() ? this->getContainer()->getName().getString() : "*none*");
1512     }
1513 #endif //COIN_DEBUG_EXTRA
1514 
1515   // If we're not the originator of the notification process, we need
1516   // to be marked dirty, as it means something we're connected to as a
1517   // slave has changed and our value needs to be updated.
1518   //
1519   // Note: don't try to "optimize" code here by moving the setDirty()
1520   // call down into the isNotifyEnabled() check, as setDirty()
1521   // _should_ happen if we're not the originator -- no matter what the
1522   // status of the notification enable flag is.
1523   if (nlist->getFirstRec()) this->setDirty(TRUE);
1524 
1525   if (this->isNotifyEnabled()) {
1526     SoFieldContainer * cont = this->getContainer();
1527     this->setStatusBits(FLAG_ISNOTIFIED);
1528     SoNotRec rec(createNotRec(cont));
1529     nlist->append(&rec, this);
1530     nlist->setLastType(SoNotRec::CONTAINER); // FIXME: Not sure about this. 20000304 mortene.
1531 
1532 #if COIN_DEBUG_EXTRA
1533   int wLevel =
1534     SoConfigSettings::getInstance()->settingAsInt("COIN_WARNING_LEVEL");
1535   if (wLevel>=3)
1536     SoDebugError::postInfo("SoField::notify",
1537                            "field %p, list %p", this, nlist);
1538 #endif //COIN_DEBUG_EXTRA
1539 
1540     if (this->hasExtendedStorage() && this->storage->auditors.getLength()) {
1541       // need to copy list first if we're going to notify the auditors
1542       SoNotList listcopy(*nlist);
1543       if (cont) cont->notify(nlist);
1544       this->notifyAuditors(&listcopy);
1545     }
1546     else {
1547       if (cont) cont->notify(nlist);
1548     }
1549     this->clearStatusBits(FLAG_ISNOTIFIED);
1550   }
1551 
1552 #if COIN_DEBUG_EXTRA
1553   if (wLevel>=3)
1554     if (this != SoDB::getGlobalField("realTime")) {
1555       SoDebugError::postInfo("SoField::notify", "%p (%s (%s '%s')) -- done",
1556                              this,
1557                              this->getTypeId().getName().getString(),
1558                              this->getContainer() ? this->getContainer()->getTypeId().getName().getString() : "*none*",
1559                              this->getContainer() ? this->getContainer()->getName().getString() : "*none*");
1560     }
1561 #endif //COIN_DEBUG_EXTRA
1562 }
1563 
1564 /*!
1565   This method sets whether notification will be propagated on changing
1566   the value of the field.  The old value of the setting is returned.
1567 
1568   \sa isNotifyEnabled()
1569 */
1570 SbBool
enableNotify(SbBool on)1571 SoField::enableNotify(SbBool on)
1572 {
1573   const SbBool old = this->getStatus(FLAG_DONOTIFY);
1574   (void) this->changeStatusBits(FLAG_DONOTIFY, on);
1575   return old;
1576 }
1577 
1578 /*!
1579   This method returns whether notification of changes to the field
1580   value are propagated to the auditors.
1581 
1582   \sa enableNotify()
1583 */
1584 SbBool
isNotifyEnabled(void) const1585 SoField::isNotifyEnabled(void) const
1586 {
1587   return this->getStatus(FLAG_DONOTIFY);
1588 }
1589 
1590 // Makes an extended storage block on first connection.
1591 void
extendStorageIfNecessary(void)1592 SoField::extendStorageIfNecessary(void)
1593 {
1594   if (!this->hasExtendedStorage()) {
1595     this->storage = new SoConnectStorage(this->container, this->getTypeId());
1596     this->setStatusBits(FLAG_EXTSTORAGE);
1597   }
1598 }
1599 
1600 /*!
1601   Add an auditor to the list. All auditors will be notified whenever
1602   this field changes its value(s).
1603 */
1604 void
addAuditor(void * f,SoNotRec::Type type)1605 SoField::addAuditor(void * f, SoNotRec::Type type)
1606 {
1607   this->extendStorageIfNecessary();
1608   this->storage->auditors.append(f, type);
1609   this->connectionStatusChanged(+1);
1610 }
1611 
1612 /*!
1613   Remove an auditor from the list.
1614 */
1615 void
removeAuditor(void * f,SoNotRec::Type type)1616 SoField::removeAuditor(void * f, SoNotRec::Type type)
1617 {
1618 #if COIN_DEBUG_EXTRA
1619   int wLevel =
1620     SoConfigSettings::getInstance()->settingAsInt("COIN_WARNING_LEVEL");
1621   if (wLevel>=3)
1622     SoDebugError::postInfo("SoField::removeAuditor",
1623                            "%p removing %p", this, f);
1624 #endif //COIN_DEBUG_EXTRA
1625 
1626   assert(this->hasExtendedStorage());
1627   this->storage->auditors.remove(f, type);
1628   this->connectionStatusChanged(-1);
1629 }
1630 
1631 /*!
1632   Checks for equality. Returns \c 0 if the fields are of different
1633   type or the field's value(s) are not equal.
1634 */
1635 int
operator ==(const SoField & f) const1636 SoField::operator ==(const SoField & f) const
1637 {
1638   return this->isSame(f);
1639 }
1640 
1641 /*!
1642   Returns \c TRUE if the fields are of different type or has different
1643   value.
1644 */
1645 int
operator !=(const SoField & f) const1646 SoField::operator !=(const SoField & f) const
1647 {
1648   return !this->isSame(f);
1649 }
1650 
1651 /*!
1652   Returns \c TRUE if it is necessary to write the field when dumping a
1653   scene graph. This needs to be done if the field is not default (it
1654   has been changed from its default value), if it's ignored, or if
1655   it's connected from another field or engine.
1656 */
1657 SbBool
shouldWrite(void) const1658 SoField::shouldWrite(void) const
1659 {
1660 #if COIN_DEBUG_EXTRA
1661   int wLevel =
1662     SoConfigSettings::getInstance()->settingAsInt("COIN_WARNING_LEVEL");
1663   if (wLevel>=3) {
1664     SbString finfo = SoFieldP::getDebugIdString(this);
1665     SoDebugError::postInfo("SoField::shouldWrite",
1666                            "%s: isDefault==%d, isIgnored==%d, isConnected==%d",
1667                            finfo.getString(), this->isDefault(),
1668                            this->isIgnored(), this->isConnected());
1669   }
1670 #endif //COIN_DEBUG_EXTRA
1671 
1672   if (!this->isDefault()) return TRUE;
1673   if (this->isIgnored()) return TRUE;
1674 
1675   if (this->isConnected()) {
1676 #if 0 // disabled (was only needed for bidirectional connections in PROTOs)
1677     // I suspect this code was here only to make the bidirectional
1678     // connection hack in SoProto work. Connected PROTO instance
1679     // fields should be written even if they have the default value
1680     // (just like any other field). pederb, 2005-12-20
1681     SoFieldContainer * thecontainer = this->getContainer();
1682     if ( thecontainer != NULL &&
1683          thecontainer->isOfType(SoProtoInstance::getClassTypeId()) ) {
1684       // PROTO instance fields are usually connected, but we don't want to
1685       // write out PROTO instance fields that contain default values - they
1686       // will be hooked up and get the default value from the PROTO interface
1687       // when they are read in again later anyways. -- 20040115 larsa
1688       return FALSE;
1689     }
1690 #endif // disabled PROTO hack
1691     return TRUE;
1692   }
1693 
1694   // SGI Inventor seems to test forward connections here also. We
1695   // consider this is bug, since this field should not write just
1696   // because some field is connected from this field.  pederb.
1697 
1698   return FALSE;
1699 }
1700 
1701 /*!
1702   Called whenever another slave attaches or detaches itself to us.  \a
1703   numconnections is the difference in number of connections made
1704   (i.e. if stuff is \e disconnected, \a numconnections will be a
1705   negative number).
1706 
1707   The default method is empty. Override in subclasses if you want do
1708   something special on connections/deconnections.
1709 */
1710 void
connectionStatusChanged(int COIN_UNUSED_ARG (numconnections))1711 SoField::connectionStatusChanged(int COIN_UNUSED_ARG(numconnections))
1712 {
1713 }
1714 
1715 /*!
1716   Returns \c TRUE if this field should not be written into at the
1717   moment the method is called.
1718 
1719   This method is used internally in Coin during notification and
1720   evaluation processes, and should normally not be of interest to the
1721   application programmer.
1722 */
1723 SbBool
isReadOnly(void) const1724 SoField::isReadOnly(void) const
1725 {
1726   return this->getStatus(FLAG_READONLY);
1727 }
1728 
1729 /*!
1730   This method is internally called after SoField::copyFrom() during
1731   scene graph copies, and should do the operations necessary for
1732   fixing up the field instance after it has gotten a new value.
1733 
1734   The default method in the SoField superclass does nothing.
1735 
1736   The application programmer should normally not need to consider this
1737   method, unless he constructs a complex field type which contains new
1738   references to container instances (i.e. nodes or
1739   engines). Overriding this method is then necessary to update the
1740   reference pointers, as they could have been duplicated during the
1741   copy operation.
1742 */
1743 void
fixCopy(SbBool COIN_UNUSED_ARG (copyconnections))1744 SoField::fixCopy(SbBool COIN_UNUSED_ARG(copyconnections))
1745 {
1746 }
1747 
1748 /*!
1749   Returns \c TRUE if this field has references to any containers in
1750   the scene graph which are also duplicated during the copy operation.
1751 
1752   Note that this method \e only is valid to call during copy
1753   operations.
1754 
1755   See also the note about the relevance of the fixCopy() method for
1756   application programmers, as it is applicable on this method aswell.
1757 */
1758 SbBool
referencesCopy(void) const1759 SoField::referencesCopy(void) const
1760 {
1761   int i, n;
1762   if (!this->hasExtendedStorage()) return FALSE;
1763 
1764   const SoFieldList & masterfields = this->storage->masterfields;
1765   n = masterfields.getLength();
1766   for (i = 0; i < n; i++) {
1767     SoFieldContainer * fc = masterfields[i]->getContainer();
1768     if (SoFieldContainer::checkCopy(fc)) return TRUE;
1769   }
1770 
1771   const SoEngineOutputList & masterengineouts =
1772     this->storage->masterengineouts;
1773   n = masterengineouts.getLength();
1774   for (i = 0; i < n; i++) {
1775     SoEngineOutput * eout = masterengineouts[i];
1776     SbBool isengine = ! eout->isNodeEngineOutput();
1777     SoFieldContainer * fc = isengine ?
1778       coin_assert_cast<SoFieldContainer *>(eout->getContainer()) :
1779       coin_assert_cast<SoFieldContainer *>(eout->getNodeContainer());
1780     if (SoFieldContainer::checkCopy(fc)) return TRUE;
1781     if (isengine || (fc->isOfType(SoEngine::getClassTypeId()) &&
1782                      coin_assert_cast<SoEngine *>(fc)->shouldCopy())) return TRUE;
1783   }
1784   return FALSE;
1785 }
1786 
1787 /*!
1788   If \a fromfield contains a connection to another field, make this
1789   field also use the same connection.
1790 */
1791 void
copyConnection(const SoField * fromfield)1792 SoField::copyConnection(const SoField * fromfield)
1793 {
1794   // Consider most common case first.
1795   if (!fromfield->isConnected()) return;
1796 
1797   // first, disconnect all existing connections (engines often
1798   // connect to the realTime global field in the constructor).
1799   this->disconnect();
1800 
1801   assert(fromfield->hasExtendedStorage());
1802   int i;
1803 
1804   for (i = 0; i < fromfield->storage->masterfields.getLength(); i++) {
1805     SoField * master = fromfield->storage->masterfields[i];
1806     SoFieldContainer * masterfc = master->getContainer();
1807     SbName fieldname;
1808     (void) masterfc->getFieldName(master, fieldname);
1809     SoFieldContainer * copyfc = masterfc->copyThroughConnection();
1810     SoField * copyfield = copyfc->getField(fieldname);
1811 
1812     SbBool notnotify = FALSE;
1813     switch (master->getFieldType()) {
1814     case EVENTIN_FIELD:
1815     case EVENTOUT_FIELD:
1816       notnotify = TRUE;
1817       break;
1818     default:
1819       break;
1820     }
1821     (void) this->connectFrom(copyfield, notnotify, TRUE);
1822   }
1823   for (i = 0; i < fromfield->storage->masterengineouts.getLength(); i++) {
1824     SoEngineOutput * master = fromfield->storage->masterengineouts[i];
1825     SoEngineOutput * copyeo = NULL;
1826 
1827     if (master->isNodeEngineOutput()) {
1828       SbName name;
1829       SoNodeEngine * masterengine = master->getNodeContainer();
1830       (void) masterengine->getOutputName(master, name);
1831       SoNodeEngine * copyengine =
1832        coin_assert_cast<SoNodeEngine *>(masterengine->copyThroughConnection());
1833       copyeo = copyengine->getOutput(name);
1834     }
1835     else {
1836       SbName name;
1837       SoEngine * masterengine = master->getContainer();
1838       (void) masterengine->getOutputName(master, name);
1839       SoEngine * copyengine =
1840        coin_assert_cast<SoEngine *>(masterengine->copyThroughConnection());
1841       copyeo = copyengine->getOutput(name);
1842     }
1843     assert(copyeo);
1844     (void) this->connectFrom(copyeo, FALSE, TRUE);
1845   }
1846 }
1847 
1848 // This templatized inline is just a convenience function for reading
1849 // with error detection.
1850 template <class Type>
1851 static inline SbBool
READ_VAL(SoInput * in,Type & val)1852 READ_VAL(SoInput * in, Type & val)
1853 {
1854   if (!in->read(val)) {
1855     SoReadError::post(in, "Premature end of file");
1856     return FALSE;
1857   }
1858   return TRUE;
1859 }
1860 
1861 
1862 /*!
1863   Reads and sets the value of this field from the given SoInput
1864   instance.  Returns \c FALSE if the field value can not be parsed
1865   from the input.
1866 
1867   The second argument is the field's context-specific \a name, which
1868   is typically its unique identifier in its field container.
1869 
1870   \sa set(), write()
1871 */
1872 SbBool
read(SoInput * in,const SbName & name)1873 SoField::read(SoInput * in, const SbName & name)
1874 {
1875   SbBool readok = TRUE;
1876   SbBool oldnotify = this->enableNotify(FALSE);
1877   SbBool didreadvalue = FALSE;
1878 
1879   if (in->checkISReference(this->getContainer(), name, readok) || readok == FALSE) {
1880     if (!readok) {
1881       SoFieldContainer * fc = this->getContainer();
1882       SbString s("");
1883       if (fc) { s.sprintf(" of %s", fc->getTypeId().getName().getString()); }
1884       SoReadError::post(in, "Couldn't read value for field \"%s\"%s",
1885                         name.getString(), s.getString());
1886     }
1887     goto sofield_read_return;
1888   }
1889 
1890   this->setDefault(FALSE);
1891   this->setDirty(FALSE);
1892 
1893   if (!in->isBinary()) { // ASCII file format.
1894     char c;
1895     // Check for the ignored flag first, as it is valid to let the
1896     // field data be just the ignored flag and nothing else.
1897     if (!READ_VAL(in, c)) { readok = FALSE; goto sofield_read_return; }
1898 
1899     if (c == IGNOREDCHAR) this->setIgnored(TRUE);
1900     else {
1901       // First check if there's a field-to-field connection here as
1902       // the default value following the field can be omitted.
1903       if (c == CONNECTIONCHAR) {
1904         // There's potential for an obscure bug to happen here: if the
1905         // field is an SoSFString where the string is unquoted and
1906         // starts with a CONNECTIONCHAR (i.e. '='), it will lead to a
1907         // false positive for the if()-check below, which again causes a
1908         // rather obtuse error message:
1909         //
1910         // Coin read error: Expected '{'; got '}'
1911         //     Occurred at line   3 in hepp.iv
1912         //
1913         // For the following test file:
1914         //
1915         // ----8<---- [snip] -------8<----
1916         // #Inventor V2.1 ascii
1917         //
1918         // Info { string =moo }
1919         // ----8<---- [snip] -------8<----
1920         //
1921         // Tamer Fahmy investigated and found this behavior to also
1922         // happen for SGI Inventor. Since that is the case, we won't
1923         // try to handle this as a valid file construct.
1924         //
1925         // FIXME: it would be nice if we could improve the error
1926         // message, to let the app programmer actually stand a chance
1927         // of debugging this when it happens. 20030811 mortene.
1928         if (!this->readConnection(in)) { readok = FALSE; goto sofield_read_return; }
1929         goto sofield_read_return;
1930       }
1931       else in->putBack(c);
1932 
1933       // Read field value(s).
1934       if (!this->readValue(in)) {
1935         SoFieldContainer * fc = this->getContainer();
1936         SbString s("");
1937         if (fc) { s.sprintf(" of %s", fc->getTypeId().getName().getString()); }
1938         SoReadError::post(in, "Couldn't read value for field \"%s\"%s",
1939                           name.getString(), s.getString());
1940         readok = FALSE;
1941         goto sofield_read_return;
1942       }
1943       else didreadvalue = TRUE;
1944 
1945       // Check again for the ignored flag indicator after the field
1946       // value.
1947       if (in->read(c)) { // if-check in case EOF on an SoField::set() invocation
1948         if (c == IGNOREDCHAR) this->setIgnored(TRUE);
1949         else in->putBack(c);
1950       }
1951     }
1952 
1953     // Check field-to-field connection indicator again /after/ the
1954     // field (start-)value.
1955     if (in->read(c)) { // if-check in case EOF on an SoField::set() invocation
1956       if (c == CONNECTIONCHAR) { if (!this->readConnection(in)) { readok = FALSE; goto sofield_read_return; } }
1957       else { in->putBack(c); }
1958     }
1959   }
1960   else { // Binary file format.
1961     // Read field value(s).
1962     if (!this->readValue(in)) {
1963       SoFieldContainer * fc = this->getContainer();
1964       SbString s("");
1965       if (fc) { s.sprintf(" of %s", fc->getTypeId().getName().getString()); }
1966       SoReadError::post(in, "Couldn't read value for field \"%s\"%s",
1967                         name.getString(), s.getString());
1968       readok = FALSE;
1969       goto sofield_read_return;
1970     }
1971     else didreadvalue = TRUE;
1972 
1973     // Check for the "ignored", "connection" and "default" flags.
1974     unsigned int flags;
1975     if (!READ_VAL(in, flags)) { readok = FALSE; goto sofield_read_return; }
1976 
1977     if (flags & SoField::IGNORED) this->setIgnored(TRUE);
1978     if (flags & SoField::CONNECTED) { if (!this->readConnection(in)) { readok = FALSE; goto sofield_read_return; }}
1979     if (flags & SoField::DEFAULT) this->setDefault(TRUE);
1980 
1981 #if COIN_DEBUG
1982     if (flags & ~SoField::ALLFILEFLAGS) {
1983       SoDebugError::postWarning("SoField::read",
1984                                 "unknown field flags (0x%x) -- "
1985                                 "please report to <coin-support@coin3d.org>",
1986                                 flags);
1987     }
1988 #endif // COIN_DEBUG
1989   }
1990 
1991  sofield_read_return:
1992   (void) this->enableNotify(oldnotify);
1993 
1994   if (readok) {
1995     if (didreadvalue) this->valueChanged(FALSE);
1996     else {
1997       // we called setDirty(FALSE) in the beginning of the function.
1998       // Since this field is read without a value (just connected to
1999       // some other field/engine), we need to mark the field as dirty
2000       // so that it's evaluated the next time the field is read
2001       this->setDirty(TRUE);
2002       this->startNotify();
2003     }
2004   }
2005   return readok;
2006 }
2007 
2008 /*!
2009   Write the value of the field to the given SoOutput instance (which
2010   can be either a memory buffer or a file, in ASCII or in binary
2011   format).
2012 
2013   \sa get(), read(), SoOutput
2014 */
2015 void
write(SoOutput * out,const SbName & name) const2016 SoField::write(SoOutput * out, const SbName & name) const
2017 {
2018   if (out->getStage() == SoOutput::COUNT_REFS) {
2019     // Handle first stage of write operations.
2020     this->countWriteRefs(out);
2021     return;
2022   }
2023 
2024   // Ok, we've passed the first write stage and is _really_ writing.
2025 
2026   // Check connection (this is common code for ASCII and binary
2027   // write).
2028   SbBool writeconnection = FALSE;
2029   SbName dummy;
2030   SoFieldContainer * fc = this->resolveWriteConnection(dummy);
2031 
2032   if (fc && (SoWriterefCounter::instance(out)->shouldWrite(fc) || fc->isOfType(SoEngine::getClassTypeId())))
2033     writeconnection = TRUE;
2034 
2035   // check VRML2 connections. Since VRML2 fields can have multiple
2036   // master fields/engines, the field can still be default even though
2037   // it is connected, and we should _not_ write the field. The ROUTEs
2038   // should be added though. pederb, 2002-06-13
2039 
2040   if (is_vrml2_field(this)) {
2041     if (writeconnection) {
2042       writeconnection = FALSE;
2043       this->storage->add_vrml2_routes(out, this);
2044       // if no value has been set, don't write field even if it's
2045       // connected
2046       if (this->isDefault()) return;
2047     }
2048     // never write eventIn or eventOut fields
2049     if ((this->getFieldType() == SoField::EVENTIN_FIELD) ||
2050         (this->getFieldType() == SoField::EVENTOUT_FIELD)) return;
2051   }
2052 
2053   // ASCII write.
2054   if (!out->isBinary()) {
2055     out->indent();
2056     // Cast to avoid "'s.
2057     out->write(static_cast<const char *>(name));
2058     if (!this->isDefault()) {
2059       out->write(' ');
2060       this->writeValue(out);
2061     }
2062     if (this->isIgnored()) {
2063       out->write(' ');
2064       out->write(IGNOREDCHAR);
2065     }
2066 
2067     if (writeconnection) this->writeConnection(out);
2068     out->write('\n');
2069   }
2070   // Binary write.
2071   else {
2072     // Cast to avoid "'s.
2073     out->write(static_cast<const char *>(name));
2074     this->writeValue(out);
2075 
2076     unsigned int flags = 0;
2077     if (this->isIgnored()) flags |= SoField::IGNORED;
2078     if (writeconnection) flags |= SoField::CONNECTED;
2079     if (this->isDefault()) flags |= SoField::DEFAULT;
2080 
2081     out->write(flags);
2082 
2083     if (writeconnection) this->writeConnection(out);
2084   }
2085 }
2086 
2087 #include <cstdio>
2088 
2089 /*!
2090   This method is called during the first pass of write operations, to
2091   count the number of write references to this field and to "forward"
2092   the reference counting operation to the field containers we're
2093   connected to.
2094 */
2095 void
countWriteRefs(SoOutput * out) const2096 SoField::countWriteRefs(SoOutput * out) const
2097 {
2098   // Count all connected fields/engines. Inventor only allows one
2099   // master field/engine, but VRML2 can have multiple. This code
2100   // should work for both Inventor and VRML2 scene graphs
2101   // though. pederb, 2002-06-13
2102   if (this->isConnected()) {
2103     if (is_vrml2_field(this)) {
2104       this->storage->add_vrml2_routes(out, this);
2105     }
2106     else {
2107       int i;
2108       for (i = 0; i < this->storage->masterfields.getLength(); i++) {
2109         SoField * master = this->storage->masterfields[i];
2110         SoFieldContainer * fc = master->getContainer();
2111         assert(fc);
2112         // TRUE = reference is from field connection. This is needed
2113         // so that the fields inside 'fc' is counted only once
2114         fc->addWriteReference(out, TRUE);
2115       }
2116       for (i = 0; i < this->storage->masterengineouts.getLength(); i++) {
2117         SoEngineOutput * engineout = this->storage->masterengineouts[i];
2118         SoFieldContainer * fc = engineout->getFieldContainer();
2119         assert(fc);
2120         // since engines are always connected directly to the field
2121         // (they're not nodes), engines are always counted with
2122         // isfromfield = FALSE
2123         fc->addWriteReference(out, FALSE);
2124       }
2125     }
2126   }
2127 }
2128 
2129 /*!
2130   \fn void SoField::evaluate(void) const
2131 
2132   Re-evaluates the value of this field any time a getValue() call is
2133   made and the field is marked dirty. This is done in this way to gain
2134   the advantages of having lazy evaluation.
2135 */
2136 
2137 //
2138 // private method called from SoField::evaluate() when the field is
2139 // connected and dirty
2140 //
2141 void
evaluateField(void) const2142 SoField::evaluateField(void) const
2143 {
2144   // if we're destructing, don't continue as this would cause
2145   // a call to the virtual evaluateConnection()
2146   if (this->getStatus(FLAG_ISDESTRUCTING)) {
2147 #if COIN_DEBUG_EXTRA
2148   int wLevel =
2149     SoConfigSettings::getInstance()->settingAsInt("COIN_WARNING_LEVEL");
2150   if (wLevel>=3) {
2151     SoDebugError::postInfo("SoField::evaluate",
2152                            "Stopped evaluate while destructing.");
2153   }
2154 #endif //COIN_DEBUG_EXTRA
2155     return;
2156   }
2157 
2158   if (!this->isConnected()) return;
2159 
2160   assert(this->storage != NULL);
2161 
2162   // lock _before_ testing FLAG_ISEVALUATING to be thread safe
2163   SOFIELD_RECLOCK;
2164   // Recursive calls to SoField::evalute() should _absolutely_ not
2165   // happen, as the state of the field variables might not be
2166   // consistent while evaluating.
2167   //
2168   // This is an error which is not too hard to bump into, and the
2169   // _immediate_ repercussions are non-fatal, so we just spit out this
2170   // error message and carry on -- to not cause any more application
2171   // programmer frustrations than necessary.
2172 
2173   if (this->getStatus(FLAG_ISEVALUATING)) {
2174 #if COIN_DEBUG
2175     SoDebugError::post("SoField::evaluate",
2176                        "Detected indirectly recursive call to "
2177                        "SoField::evaluate() -- which is a *bad* thing."
2178                        "This indicates a non-trivial programming error "
2179                        "somewhere either in the application (most likely) "
2180                        "or the library code itself (less likely). "
2181                        "We strongly advise you to investigate and resolve "
2182                        "this issue before moving on.");
2183 #endif // COIN_DEBUG
2184     SOFIELD_RECUNLOCK;
2185     return;
2186   }
2187 
2188   // Cast away the const. (evaluate() must be const, since we're using
2189   // evaluate() from getValue().)
2190   SoField * that = const_cast<SoField *>(this);
2191 
2192   // Check the NEEDEVALUATION flag in case some other thread has just
2193   // evaluated the field. The flag is checked in SoField::evaluate(),
2194   // but it is possible that two (or more) threads might enter
2195   // evaluateField() simultaneously, so this test is necessary.
2196   // pederb, 2002-10-04
2197   if (this->getStatus(FLAG_NEEDEVALUATION) && this->getStatus(FLAG_ENABLECONNECTS)) {
2198     that->setStatusBits(FLAG_ISEVALUATING);
2199     this->evaluateConnection();
2200     that->clearStatusBits(FLAG_ISEVALUATING);
2201     // this will clear the NEEDEVALUATION flag
2202     that->setDirty(FALSE);
2203   }
2204   SOFIELD_RECUNLOCK;
2205 }
2206 
2207 /*!
2208   Do we need re-evaluation?
2209 */
2210 SbBool
getDirty(void) const2211 SoField::getDirty(void) const
2212 {
2213   return this->getStatus(FLAG_NEEDEVALUATION);
2214 }
2215 
2216 /*!
2217   Mark field for re-evaluation (upon next read operation), but do not
2218   trigger a notification.
2219 */
2220 void
setDirty(SbBool dirty)2221 SoField::setDirty(SbBool dirty)
2222 {
2223   (void) this->changeStatusBits(FLAG_NEEDEVALUATION, dirty);
2224 }
2225 
2226 /*!
2227   Connect ourself as slave to another object, while still keeping the
2228   other connections currently in place.
2229 
2230   \sa connectFrom()
2231 */
2232 SbBool
appendConnection(SoEngineOutput * master,SbBool notnotify)2233 SoField::appendConnection(SoEngineOutput * master, SbBool notnotify)
2234 {
2235   return this->connectFrom(master, notnotify, TRUE);
2236 }
2237 
2238 /*!
2239   Connect ourself as slave to another object, while still keeping the
2240   other connections currently in place.
2241 
2242   \sa connectFrom()
2243 */
2244 SbBool
appendConnection(SoField * master,SbBool notnotify)2245 SoField::appendConnection(SoField * master, SbBool notnotify)
2246 {
2247   return this->connectFrom(master, notnotify, TRUE);
2248 }
2249 
2250 // Make a converter from value(s) of the given field type and the
2251 // value(s) of this type. Returns NULL if no value conversion between
2252 // types is possible.
2253 SoFieldConverter *
createConverter(SoType from) const2254 SoField::createConverter(SoType from) const
2255 {
2256   SoType thistype = this->getTypeId();
2257   assert(from != thistype);
2258   SoType convtype = SoDB::getConverter(from, thistype);
2259   if (convtype == SoType::badType()) {
2260 #if COIN_DEBUG // COIN_DEBUG
2261     SoDebugError::postWarning("SoField::createConverter",
2262                               "no converter for %s to %s",
2263                               from.getName().getString(),
2264                               thistype.getName().getString());
2265 #endif // COIN_DEBUG
2266     return NULL;
2267   }
2268 
2269   SoFieldConverter * fc;
2270 
2271   if (convtype == SoConvertAll::getClassTypeId())
2272     fc = new SoConvertAll(from, this->getTypeId());
2273   else
2274     fc = static_cast<SoFieldConverter *>(convtype.createInstance());
2275 
2276   fc->ref();
2277   return fc;
2278 }
2279 
2280 
2281 /*!
2282   Read the master field of a field-to-field connection (and its field
2283   container).
2284 
2285   If input parsing is successful, this field will be connected as a
2286   slave to the master field.
2287 
2288   Note that this slave field will \e not be marked as "dirty" upon
2289   connection, i.e. it will retain its value until the first update of
2290   the master field is made \e after the connection was set up. This to
2291   be in conformance with how the Inventor Mentor specifies how field
2292   connections should be imported (see page 270).
2293 */
2294 SbBool
readConnection(SoInput * in)2295 SoField::readConnection(SoInput * in)
2296 {
2297   // For debugging purposes, here's a handy test case for checking
2298   // that a field-field connection, where an initial value for the
2299   // slave is given, will behave according to the Mentor, as mentioned
2300   // above in the function API documentation:
2301   //
2302   // -----8<------- [snip] -----------------8<------- [snip] -----------
2303   // #Inventor V2.1 ascii
2304   //
2305   // DEF SCENE_ROOT Separator {
2306   //    ## on startup this should give a green cube
2307   //    Switch {
2308   //       whichChild 0 = SelectOne { type SoMFInt32 index 1 input [ 0,1 ] }.output
2309   //       Material { diffuseColor 0.1 1.0 0.1 }
2310   //       Material { diffuseColor 1.0 0.1 0.1 }
2311   //    }
2312   //    Cone {}
2313   // } # SCENE_ROOT
2314   // -----8<------- [snip] -----------------8<------- [snip] -----------
2315   //
2316   // (Provided by Gerhard Reitmayr.)
2317 
2318   // ***********************************************************************
2319 
2320   // Read the fieldcontainer instance containing the master field
2321   // we're connected to.
2322   SoBase * bp;
2323   if (!SoBase::read(in, bp, SoFieldContainer::getClassTypeId())) return FALSE;
2324   if (!bp) {
2325     SoReadError::post(in, "couldn't read field-to-field connection");
2326     return FALSE;
2327   }
2328 
2329   SoFieldContainer * fc = coin_assert_cast<SoFieldContainer *>(bp);
2330 
2331   // Scan past the '.' character for ASCII format.
2332   if (!in->isBinary()) {
2333     char c;
2334     if (!in->read(c)) {
2335       SoReadError::post(in, "premature EOF");
2336       return FALSE;
2337     }
2338     if (c != '.') {
2339       SoReadError::post(in, "expected field connection token '.', "
2340                         "but got '%c'", c);
2341       return FALSE;
2342     }
2343   }
2344 
2345   // Read name of master field.
2346   SbName mastername;
2347   if (!in->read(mastername, TRUE)) {
2348     SoReadError::post(in, "premature EOF");
2349     return FALSE;
2350   }
2351 
2352   // Get pointer to master field or engine output and connect.
2353 
2354   SoEngineOutput * masteroutput = NULL;
2355   SoField * masterfield = fc->getField(mastername);
2356 
2357   if (!masterfield) {
2358     masteroutput =
2359       fc->isOfType(SoEngine::getClassTypeId()) ?
2360       coin_safe_cast<SoEngine*>(fc)->getOutput(mastername) : NULL;
2361 
2362     if (!masteroutput) {
2363       masteroutput =
2364         fc->isOfType(SoNodeEngine::getClassTypeId()) ?
2365         coin_safe_cast<SoNodeEngine *>(fc)->getOutput(mastername) : NULL;
2366     }
2367   }
2368 
2369   if (!masterfield && !masteroutput) {
2370     SoReadError::post(in, "no field or output ``%s'' in ``%s''",
2371                       mastername.getString(),
2372                       fc->getTypeId().getName().getString());
2373     return FALSE;
2374   }
2375 
2376   SbBool ok = FALSE;
2377 
2378   // Make connection, with "do not notify" flag set to TRUE, to avoid
2379   // making ourselves "dirty" (i.e.: we will continue using our
2380   // current value until the master is updated).
2381   if (masterfield) { ok = this->connectFrom(masterfield, TRUE); }
2382   else if (masteroutput) { ok = this->connectFrom(masteroutput, TRUE); }
2383 
2384   if (!ok) {
2385     SoReadError::post(in, "couldn't connect ``%s'' field to ``%s'', "
2386                       "connection will be ignored",
2387                       this->getTypeId().getName().getString(),
2388                       mastername.getString());
2389   }
2390 
2391   return TRUE;
2392 }
2393 
2394 /*!
2395   Write out information about this field's connection.
2396 */
2397 void
writeConnection(SoOutput * out) const2398 SoField::writeConnection(SoOutput * out) const
2399 {
2400   SbName mastername;
2401   SoFieldContainer * fc = this->resolveWriteConnection(mastername);
2402   assert(fc);
2403 
2404   if (!out->isBinary()) {
2405     out->write(' ');
2406     out->write(CONNECTIONCHAR);
2407   }
2408 
2409   if (fc->isOfType(SoNode::getClassTypeId())) {
2410     SoWriteAction wa(out);
2411     wa.continueToApply(coin_assert_cast<SoNode *>(fc));
2412   }
2413   else {
2414     // Note: for this to work, classes inheriting SoFieldContainer
2415     // which are _not_ also inheriting from SoNode must call
2416     // SoBase::writeHeader() and SoBase::writeFooter().
2417     fc->writeInstance(out);
2418     // FIXME: does this work for engines? 20000131 mortene.
2419   }
2420 
2421   if (!out->isBinary()) {
2422     out->indent();
2423     out->write(". ");
2424   }
2425 
2426   out->write(mastername.getString());
2427 }
2428 
2429 // Check if this field should write a connection upon export. Returns
2430 // a pointer to the fieldcontainer with the master field we're
2431 // connected to (or NULL if none, or if the master field's container
2432 // is not within the scenegraph). If the return value is non-NULL, the
2433 // name of the master field is copied to the mastername argument.
2434 SoFieldContainer *
resolveWriteConnection(SbName & mastername) const2435 SoField::resolveWriteConnection(SbName & mastername) const
2436 {
2437   if (!this->isConnected()) return NULL;
2438 
2439   SoFieldContainer * fc = NULL;
2440   SoField * fieldmaster;
2441   SoEngineOutput * enginemaster;
2442 
2443   if (this->getConnectedField(fieldmaster)) {
2444     fc = fieldmaster->getContainer();
2445     assert(fc);
2446     SbBool ok = fc->getFieldName(fieldmaster, mastername);
2447     assert(ok);
2448   }
2449   else if (this->getConnectedEngine(enginemaster)) {
2450     fc = enginemaster->getFieldContainer();
2451     assert(fc);
2452     // FIXME: couldn't we use getFieldName()? 20000129 mortene.
2453     SbBool ok =
2454       enginemaster->isNodeEngineOutput() ?
2455       coin_assert_cast<SoNodeEngine *>(fc)->getOutputName(enginemaster, mastername) :
2456       coin_assert_cast<SoEngine *>(fc)->getOutputName(enginemaster, mastername);
2457     assert(ok);
2458   }
2459   else assert(FALSE);
2460 
2461   return fc;
2462 }
2463 
2464 
2465 /*!
2466   If we're connected to a field/engine/interpolator, copy the value
2467   from the master source.
2468 */
2469 void
evaluateConnection(void) const2470 SoField::evaluateConnection(void) const
2471 {
2472   SbBool fanin = this->storage->hasFanIn();
2473   SbBool didevaluate = FALSE;
2474 
2475   // FIXME: should we evaluate from all masters in turn? 19990623 mortene.
2476   if (this->isConnectedFromField()) {
2477     int idx = fanin ? this->storage->findFanInField() : this->storage->masterfields.getLength() - 1;
2478     if (idx >= 0) {
2479       didevaluate = TRUE;
2480       SoField * master = this->storage->masterfields[idx];
2481       // don't copy if master is destructing, or if master is currently
2482       // evaluating. The master might be evaluating if we have circular
2483       // field connections. If this is the case, the field will already
2484       // contain the correct value, and we should not copy again.
2485       if (!master->isDestructing() && !master->getStatus(FLAG_ISEVALUATING)) {
2486         SoFieldConverter * converter = this->storage->findConverter(master);
2487         if (converter) converter->evaluateWrapper();
2488         else {
2489           SoField * that = const_cast<SoField *>(this); // cast away const
2490           // Copy data. Disable notification first since notification
2491           // has already been sent from the master.
2492           SbBool oldnotify = that->enableNotify(FALSE);
2493           that->copyFrom(*master);
2494           (void) that->enableNotify(oldnotify);
2495         }
2496       }
2497     }
2498   }
2499   if (this->isConnectedFromEngine() && !didevaluate) {
2500     int idx = fanin ? this->storage->findFanInEngine() : this->storage->masterengineouts.getLength() - 1;
2501     if (idx >= 0) {
2502       SoEngineOutput * master = this->storage->masterengineouts[idx];
2503       SoFieldConverter * converter = this->storage->findConverter(master);
2504       if (converter) converter->evaluateWrapper();
2505       else if (master->isNodeEngineOutput()) {
2506         master->getNodeContainer()->evaluateWrapper();
2507       }
2508       else {
2509         master->getContainer()->evaluateWrapper();
2510       }
2511     }
2512   }
2513 }
2514 
2515 /*!
2516   This method is always called whenever the field's value has been
2517   changed by direct invocation of setValue() or some such. You should
2518   \e never call this method from anywhere in the code where the field
2519   value is being set through an evaluation of its connections.
2520 
2521   If \a resetdefault is \c TRUE, the flag marking whether or not the
2522   field has its default value will be set to \c FALSE.
2523 
2524   The method will also notify any auditors that the field's value has
2525   changed.
2526 */
2527 void
valueChanged(SbBool resetdefault)2528 SoField::valueChanged(SbBool resetdefault)
2529 {
2530   if (this->changeStatusBits(FLAG_READONLY, TRUE)) {
2531     this->setDirty(FALSE);
2532     if (resetdefault) this->setDefault(FALSE);
2533     if (this->container) this->startNotify();
2534     this->clearStatusBits(FLAG_READONLY);
2535   }
2536 }
2537 
2538 // Notify any auditors by marking them dirty - i.e. ready for
2539 // re-evaluation.  Auditors include connected fields, sensors,
2540 // containers (nodes/engines), ...
2541 void
notifyAuditors(SoNotList * l)2542 SoField::notifyAuditors(SoNotList * l)
2543 {
2544 #if COIN_DEBUG_EXTRA
2545   int wLevel =
2546     SoConfigSettings::getInstance()->settingAsInt("COIN_WARNING_LEVEL");
2547   if (wLevel>=3)
2548     SoDebugError::postInfo("SoField::notifyAuditors",
2549                            "field %p, list %p", this, l);
2550 #endif //COIN_DEBUG_EXTRA
2551   if (this->hasExtendedStorage() && this->storage->auditors.getLength())
2552     this->storage->auditors.notify(l);
2553 }
2554 
2555 /*!
2556   Set type of this field.
2557 
2558   The possible values for \a type is: 0 for ordinary fields, 1 for
2559   eventIn fields, 2 for eventOut fields, 3 for internal fields, 4 for
2560   VRML2 exposedField fields. There are also enum values in SoField.h.
2561 */
2562 void
setFieldType(int type)2563 SoField::setFieldType(int type)
2564 {
2565   this->clearStatusBits(FLAG_TYPEMASK);
2566   assert(type >=0 && type <= FLAG_TYPEMASK);
2567   this->setStatusBits(static_cast<unsigned int>(type));
2568 }
2569 
2570 /*!
2571   Return the type of this field.
2572 
2573   \sa setFieldType()
2574 */
2575 int
getFieldType(void) const2576 SoField::getFieldType(void) const
2577 {
2578   return this->statusbits & FLAG_TYPEMASK;
2579 }
2580 
2581 /*!
2582   Can be used to check if a field is being destructed.
2583 */
2584 SbBool
isDestructing(void) const2585 SoField::isDestructing(void) const
2586 {
2587   return this->getStatus(FLAG_ISDESTRUCTING);
2588 }
2589 
2590 /*!
2591   \internal
2592 */
2593 SoNotRec
createNotRec(SoBase * cont)2594 SoField::createNotRec(SoBase * cont)
2595 {
2596   SoNotRec rec(cont);
2597   rec.setOperationType(SoNotRec::FIELD_UPDATE);
2598   return rec;
2599 }
2600 
2601 /*!
2602   Initialize all the field classes.
2603 */
2604 void
initClasses(void)2605 SoField::initClasses(void)
2606 {
2607   SoSField::initClass();
2608   SoSFBox2s::initClass();
2609   SoSFBox2i32::initClass();
2610   SoSFBox2f::initClass();
2611   SoSFBox2d::initClass();
2612   SoSFBox3s::initClass();
2613   SoSFBox3i32::initClass();
2614   SoSFBox3f::initClass();
2615   SoSFBox3d::initClass();
2616   SoSFBool::initClass();
2617   SoSFColor::initClass();
2618   SoSFColorRGBA::initClass();
2619   SoSFDouble::initClass();
2620   SoSFEngine::initClass();
2621   SoSFFloat::initClass();
2622   SoSFShort::initClass();
2623   SoSFUShort::initClass();
2624   SoSFInt32::initClass();
2625   SoSFUInt32::initClass();
2626   SoSFVec2b::initClass();
2627   SoSFVec2s::initClass();
2628   SoSFVec2i32::initClass();
2629   SoSFVec2f::initClass();
2630   SoSFVec2d::initClass();
2631   SoSFVec3b::initClass();
2632   SoSFVec3s::initClass();
2633   SoSFVec3i32::initClass();
2634   SoSFVec3f::initClass();
2635   SoSFVec3d::initClass();
2636   SoSFVec4b::initClass();
2637   SoSFVec4ub::initClass();
2638   SoSFVec4s::initClass();
2639   SoSFVec4us::initClass();
2640   SoSFVec4i32::initClass();
2641   SoSFVec4ui32::initClass();
2642   SoSFVec4f::initClass();
2643   SoSFVec4d::initClass();
2644   SoSFMatrix::initClass();
2645   SoSFEnum::initClass();
2646   SoSFBitMask::initClass();
2647   SoSFImage::initClass();
2648   SoSFImage3::initClass();
2649   SoSFName::initClass();
2650   SoSFNode::initClass();
2651   SoSFPath::initClass();
2652   SoSFPlane::initClass();
2653   SoSFRotation::initClass();
2654   SoSFString::initClass();
2655   SoSFTime::initClass();
2656   SoSFTrigger::initClass();
2657 
2658   SoMField::initClass();
2659   SoMFBool::initClass();
2660   SoMFColor::initClass();
2661   SoMFColorRGBA::initClass();
2662   SoMFDouble::initClass();
2663   SoMFEngine::initClass();
2664   SoMFEnum::initClass();
2665   SoMFBitMask::initClass();
2666   SoMFFloat::initClass();
2667   SoMFInt32::initClass();
2668   SoMFMatrix::initClass();
2669   SoMFName::initClass();
2670   SoMFNode::initClass();
2671   SoMFPath::initClass();
2672   SoMFPlane::initClass();
2673   SoMFRotation::initClass();
2674   SoMFShort::initClass();
2675   SoMFString::initClass();
2676   SoMFTime::initClass();
2677   SoMFUInt32::initClass();
2678   SoMFUShort::initClass();
2679   SoMFVec2b::initClass();
2680   SoMFVec2s::initClass();
2681   SoMFVec2i32::initClass();
2682   SoMFVec2f::initClass();
2683   SoMFVec2d::initClass();
2684   SoMFVec3b::initClass();
2685   SoMFVec3s::initClass();
2686   SoMFVec3i32::initClass();
2687   SoMFVec3f::initClass();
2688   SoMFVec3d::initClass();
2689   SoMFVec4b::initClass();
2690   SoMFVec4ub::initClass();
2691   SoMFVec4s::initClass();
2692   SoMFVec4us::initClass();
2693   SoMFVec4i32::initClass();
2694   SoMFVec4ui32::initClass();
2695   SoMFVec4f::initClass();
2696   SoMFVec4d::initClass();
2697 
2698   // Create these obsoleted types for backwards compatibility. They
2699   // are typedef'ed to the types which obsoleted them, but this is
2700   // needed so it will also be possible to use SoType::fromName() with
2701   // the old names and create instances in that manner.
2702   //
2703   // FIXME: SoType::fromName("oldname") == SoType::fromName("newname")
2704   // will fail, but this can be solved with a hack in
2705   // SoType::operator==(). Do we _want_ to implement this hack,
2706   // though? It'd be ugly as hell.  19991109 mortene.
2707   // Does it need to be so ugly?  == could compare createInstance
2708   // pointers if both have is set?  But would it be correct, and would
2709   // any code depend on or benefit from such behaviour?  20070518 larsa
2710   SoType::createType(SoSField::getClassTypeId(), "SFLong",
2711                      &SoSFInt32::createInstance);
2712   SoType::createType(SoSField::getClassTypeId(), "SFULong",
2713                      &SoSFUInt32::createInstance);
2714   SoType::createType(SoMField::getClassTypeId(), "MFLong",
2715                      &SoMFInt32::createInstance);
2716   SoType::createType(SoMField::getClassTypeId(), "MFULong",
2717                      &SoMFUInt32::createInstance);
2718 }
2719 
2720 #undef FLAG_ALIVE_PATTERN
2721 #undef SOFIELD_RECLOCK
2722 #undef SOFIELD_RECUNLOCK
2723