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 // This is an internal class for holding user extension nodes from .iv
34 // files. The header file for this node is not exported at ``make
35 // install'', and the class is not documented for application
36 // programmers.
37 
38 // FIXME: copy operations doesn't work as expected on this node. I
39 // think both the copyContents() and addToCopyDict() methods needs to
40 // be overridden.  20000404 mortene.
41 
42 #include "nodes/SoUnknownNode.h"
43 
44 #include <Inventor/SoInput.h>
45 #include <Inventor/SoOutput.h>
46 #include <Inventor/actions/SoGLRenderAction.h>
47 #include <Inventor/actions/SoGetBoundingBoxAction.h>
48 #include <Inventor/actions/SoPickAction.h>
49 #include <Inventor/actions/SoSearchAction.h>
50 #include <Inventor/actions/SoWriteAction.h>
51 #include <Inventor/errors/SoDebugError.h>
52 #include <Inventor/errors/SoReadError.h>
53 #include <Inventor/fields/SoSFNode.h>
54 #include <Inventor/misc/SoChildList.h>
55 #include <Inventor/nodes/SoGroup.h>
56 #include <Inventor/C/tidbits.h>
57 
58 #include "io/SoWriterefCounter.h"
59 #include "io/SoInputP.h"
60 #include "tidbitsp.h"
61 
62 // *************************************************************************
63 
64 class SoUnknownNodeP {
65 public:
66   SbName classname;
67   SoChildList * privatechildren, * alternate;
68 };
69 
70 // *************************************************************************
71 
72 // The following code is used instead of SO_NODE_SOURCE() to let
73 // SoUnknownNodes have dynamic handling of SoFieldData objects.
74 
75 PRIVATE_NODE_TYPESYSTEM_SOURCE(SoUnknownNode);
76 
getFieldData(void) const77 const SoFieldData * SoUnknownNode::getFieldData(void) const
78 {
79   return this->classfielddata;
80 }
81 
82 void *
createInstance(void)83 SoUnknownNode::createInstance(void)
84 {
85   return new SoUnknownNode;
86 }
87 
88 #define PRIVATE(p) ((p)->pimpl)
89 
90 // Node implementation starts "proper".
91 
SoUnknownNode(void)92 SoUnknownNode::SoUnknownNode(void)
93 {
94   PRIVATE(this) = new SoUnknownNodeP;
95 
96   /* Catch attempts to use a node class which has not been initialized. */
97   assert(SoUnknownNode::classTypeId != SoType::badType());
98   /* Initialize a fielddata container for the instance. */
99   this->classfielddata = new SoFieldData;
100 
101   this->isBuiltIn = FALSE;
102   PRIVATE(this)->privatechildren = NULL;
103   PRIVATE(this)->alternate = new SoChildList(this, 1);
104 }
105 
~SoUnknownNode()106 SoUnknownNode::~SoUnknownNode()
107 {
108   for (int i=0; i < this->classfielddata->getNumFields(); i++)
109     delete this->classfielddata->getField(this, i);
110 
111   delete this->classfielddata;
112   delete PRIVATE(this)->privatechildren;
113   delete PRIVATE(this)->alternate;
114   delete PRIVATE(this);
115 }
116 
117 // doc in super
118 void
initClass(void)119 SoUnknownNode::initClass(void)
120 {
121   /* Make sure we only initialize once. */
122   assert(SoUnknownNode::classTypeId == SoType::badType());
123   /* Make sure superclass gets initialized before subclass. */
124   assert(inherited::getClassTypeId() != SoType::badType());
125 
126   /* Set up entry in the type system. */
127   SoUnknownNode::classTypeId =
128     SoType::createType(inherited::getClassTypeId(),
129                        "UnknownNode",
130                        &SoUnknownNode::createInstance,
131                        SoNode::nextActionMethodIndex++);
132   coin_atexit((coin_atexit_f*)SoUnknownNode::atexit_cleanup, CC_ATEXIT_NORMAL);
133 }
134 
135 void
atexit_cleanup(void)136 SoUnknownNode::atexit_cleanup(void)
137 {
138   SoUnknownNode::classTypeId STATIC_SOTYPE_INIT;
139 }
140 
141 SbBool
readInstance(SoInput * in,unsigned short flags)142 SoUnknownNode::readInstance(SoInput * in, unsigned short flags)
143 {
144   if (SoInputP::debug()) {
145     SoDebugError::postInfo("SoUnknownNode::readInstance",
146                            "Reading extension node ``%s'' as SoUnknownNode.",
147                            PRIVATE(this)->classname.getString());
148   }
149 
150 
151   SbBool notbuiltin;
152   // The "error on unknown field" is FALSE, in case we are a group
153   // node with children specified in the file.
154   if (!this->classfielddata->read(in, this, FALSE, notbuiltin)) return FALSE;
155 
156   if (notbuiltin == FALSE) {
157     SoReadError::post(in, "Node type ``%s'' not recognized.",
158                       PRIVATE(this)->classname.getString());
159     return FALSE;
160   }
161 
162   // Set pointer to alternateRep node, if SoSFNode field with this
163   // name is present.
164   int i;
165   for (i=0; i < this->classfielddata->getNumFields(); i++) {
166     if (this->classfielddata->getFieldName(i) == "alternateRep") {
167       SoSFNode * f = (SoSFNode *)this->classfielddata->getField(this, i);
168       if (f->isOfType(SoSFNode::getClassTypeId())) {
169 #if COIN_DEBUG && 0 // debug
170         SoDebugError::postInfo("SoUnknownNode::readInstance",
171                                "found alternate representation");
172 #endif // debug
173         if (!f->getValue()) break;
174         PRIVATE(this)->alternate->truncate(0);
175         PRIVATE(this)->alternate->append(f->getValue());
176       }
177       break;
178     }
179   }
180 
181   // Read children, if necessary.
182   if (!in->isBinary() || (flags & SoBase::IS_GROUP)) {
183     SoGroup * g = new SoGroup;
184     g->ref();
185     if (!g->readChildren(in)) {
186       g->unref();
187       return FALSE;
188     }
189 
190 #if COIN_DEBUG && 0 // debug
191     SoDebugError::postInfo("SoUnknownNode::readInstance",
192                            "read %d children successfully",
193                            g->getNumChildren());
194 #endif // debug
195 
196     delete PRIVATE(this)->privatechildren;
197     PRIVATE(this)->privatechildren = new SoChildList(this, * g->getChildren());
198     g->unref();
199   }
200 
201   // Check that all field descriptions did actually get a value
202   // set. It is not a fatal error if this didn't happen, but: 1) on
203   // subsequent write operations, information will be lost, and 2) the
204   // field value will probably be completely random because we're
205   // reading from uninitialized memory.
206   if (SoInputP::debug()) {
207     for (i=0; i < this->classfielddata->getNumFields(); i++) {
208       const SoField * f = this->classfielddata->getField(this, i);
209       if (f->isDefault()) {
210         SoReadError::post(in, "Field ``%s'' in extension node ``%s'' not "
211                           "given any value.",
212                           this->classfielddata->getFieldName(i).getString(),
213                           PRIVATE(this)->classname.getString());
214       }
215     }
216   }
217 
218   return TRUE;
219 }
220 
221 // The name used for the nodes of this type in scene file.
222 void
setNodeClassName(const SbName & name)223 SoUnknownNode::setNodeClassName(const SbName & name)
224 {
225   PRIVATE(this)->classname = name;
226 }
227 
228 // Overridden from SoBase.
229 const char *
getFileFormatName(void) const230 SoUnknownNode::getFileFormatName(void) const
231 {
232   return PRIVATE(this)->classname.getString();
233 }
234 
235 // Overridden from SoNode. SoChildList contains either 0 or 1
236 // elements, depending on if an alternate representation was
237 // specified.
238 SoChildList *
getChildren(void) const239 SoUnknownNode::getChildren(void) const
240 {
241   return PRIVATE(this)->alternate;
242 }
243 
244 // Write action method is overridden from SoNode to handle children.
245 void
write(SoWriteAction * action)246 SoUnknownNode::write(SoWriteAction * action)
247 {
248   SoOutput * out = action->getOutput();
249   if (out->getStage() == SoOutput::COUNT_REFS) {
250     inherited::write(action);
251     // Only increase number of writereferences to the top level node
252     // in a tree which is used multiple times.
253     if (!SoWriterefCounter::instance(out)->hasMultipleWriteRefs(this))
254       if (PRIVATE(this)->privatechildren) PRIVATE(this)->privatechildren->traverse(action);
255   }
256   else if (out->getStage() == SoOutput::WRITE) {
257     if (this->writeHeader(out, PRIVATE(this)->privatechildren ? TRUE : FALSE, FALSE))
258       return;
259     this->getFieldData()->write(out, this);
260     if (out->isBinary())
261       if (PRIVATE(this)->privatechildren) out->write(PRIVATE(this)->privatechildren->getLength());
262     if (PRIVATE(this)->privatechildren) PRIVATE(this)->privatechildren->traverse(action);
263     this->writeFooter(out);
264   }
265   else assert(0 && "unknown stage");
266 }
267 
268 // Action methods overridden from SoNode to traverse alternateRep (and
269 // below, if alternateRep is a group node).
270 
271 void
search(SoSearchAction * action)272 SoUnknownNode::search(SoSearchAction * action)
273 {
274   inherited::search(action);
275   if (action->isFound()) return;
276   PRIVATE(this)->alternate->traverse(action);
277 }
278 
279 void
GLRender(SoGLRenderAction * action)280 SoUnknownNode::GLRender(SoGLRenderAction * action)
281 {
282   PRIVATE(this)->alternate->traverse(action);
283 }
284 
285 void
getBoundingBox(SoGetBoundingBoxAction * action)286 SoUnknownNode::getBoundingBox(SoGetBoundingBoxAction * action)
287 {
288   PRIVATE(this)->alternate->traverse(action);
289 }
290 
291 void
pick(SoPickAction * action)292 SoUnknownNode::pick(SoPickAction * action)
293 {
294   PRIVATE(this)->alternate->traverse(action);
295 }
296 
297 SoNode *
addToCopyDict(void) const298 SoUnknownNode::addToCopyDict(void) const
299 {
300   // This function is copied from SoNode::addToCopyDict() and
301   // modified to handle the private children.
302 
303 #if COIN_DEBUG && 0 // debug
304   SoDebugError::postInfo("SoUnknownNode::addToCopyDict",
305                          "Name: %s", PRIVATE(this)->classname.getString());
306 #endif // debug
307 
308   SoNode * cp = (SoNode *)SoFieldContainer::checkCopy(this);
309   if (!cp) {
310     cp = new SoUnknownNode;
311     SoFieldContainer::addCopy(this, cp);
312 
313     if (PRIVATE(this)->privatechildren) {
314       for (int i = 0; i < PRIVATE(this)->privatechildren->getLength(); i++) {
315         (void) (*(PRIVATE(this)->privatechildren))[i]->addToCopyDict();
316       }
317     }
318   }
319 
320   return cp;
321 }
322 
323 void
copyContents(const SoFieldContainer * from,SbBool copyconnections)324 SoUnknownNode::copyContents(const SoFieldContainer * from,
325                             SbBool copyconnections)
326 {
327   int i;
328   const SoUnknownNode * src = (const SoUnknownNode *) from;
329   this->setNodeClassName(PRIVATE(src)->classname);
330 
331   const SoFieldData * srcdata = src->getFieldData();
332   SoFieldData * dstdata = (SoFieldData*) this->getFieldData();
333 
334   for (i = 0; i < srcdata->getNumFields(); i++) {
335     const SoField * srcfield = srcdata->getField(src, i);
336     SoField * dstfield = (SoField*) srcfield->getTypeId().createInstance();
337 
338     // add new field to field data
339     dstfield->setContainer(this);
340     dstdata->addField(this, srcdata->getFieldName(i), dstfield);
341     // copy field contents
342     dstfield->copyFrom(*srcfield);
343     // copy flags
344     dstfield->setIgnored(srcfield->isIgnored());
345     dstfield->setDefault(srcfield->isDefault());
346     dstfield->enableNotify(srcfield->isNotifyEnabled());
347     // fix complex fields (node, engine, and path fields)
348     dstfield->fixCopy(copyconnections);
349     // handle connections
350     if (copyconnections && srcfield->isConnected()) {
351       dstfield->copyConnection(dstfield);
352     }
353   }
354   if (PRIVATE(src)->privatechildren == NULL) return;
355 
356   if (PRIVATE(this)->privatechildren == NULL) {
357     PRIVATE(this)->privatechildren = new SoChildList(this);
358   }
359 
360   // copy private children, which we added to the copy dict in
361   // addToCopyDict()
362   for (i = 0; i < PRIVATE(src)->privatechildren->getLength(); i++) {
363     SoNode * copy = (SoNode*)
364       this->findCopy((*(PRIVATE(src)->privatechildren))[i],
365                      copyconnections);
366     assert(copy && "unexpected error");
367     PRIVATE(this)->privatechildren->append(copy);
368   }
369 }
370 
371 #undef PRIVATE
372