KiCad PCB EDA Suite
vrml2_node.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 
25 #include <set>
26 #include <map>
27 #include <utility>
28 #include <iterator>
29 #include <cctype>
30 #include <iostream>
31 #include <sstream>
32 #include <algorithm>
33 #include <wx/log.h>
34 
35 #include "vrml2_node.h"
36 
37 
38 static std::set< std::string > badNames;
39 
40 typedef std::pair< std::string, WRL2NODES > NODEITEM;
41 typedef std::map< std::string, WRL2NODES > NODEMAP;
43 
44 
46 {
47  m_sgNode = NULL;
48  m_Parent = NULL;
49  m_Type = WRL2_END;
50 
51  if( badNames.empty() )
52  {
53  badNames.insert( "DEF" );
54  badNames.insert( "EXTERNPROTO" );
55  badNames.insert( "FALSE" );
56  badNames.insert( "IS" );
57  badNames.insert( "NULL" );
58  badNames.insert( "PROTO" );
59  badNames.insert( "ROUTE" );
60  badNames.insert( "TO" );
61  badNames.insert( "TRUE" );
62  badNames.insert( "USE" );
63  badNames.insert( "eventIn" );
64  badNames.insert( "eventOut" );
65  badNames.insert( "exposedField" );
66  badNames.insert( "field" );
67  }
68 
69  if( nodenames.empty() )
70  {
71  nodenames.insert( NODEITEM( "Anchor", WRL2_ANCHOR ) );
72  nodenames.insert( NODEITEM( "Appearance", WRL2_APPEARANCE ) );
73  nodenames.insert( NODEITEM( "Audioclip", WRL2_AUDIOCLIP ) );
74  nodenames.insert( NODEITEM( "Background", WRL2_BACKGROUND ) );
75  nodenames.insert( NODEITEM( "Billboard", WRL2_BILLBOARD ) );
76  nodenames.insert( NODEITEM( "Box", WRL2_BOX ) );
77  nodenames.insert( NODEITEM( "Collision", WRL2_COLLISION ) );
78  nodenames.insert( NODEITEM( "Color", WRL2_COLOR ) );
79  nodenames.insert( NODEITEM( "ColorInterpolator", WRL2_COLORINTERPOLATOR ) );
80  nodenames.insert( NODEITEM( "Cone", WRL2_CONE ) );
81  nodenames.insert( NODEITEM( "Coordinate", WRL2_COORDINATE ) );
82  nodenames.insert( NODEITEM( "CoordinateInterpolator", WRL2_COORDINATEINTERPOLATOR ) );
83  nodenames.insert( NODEITEM( "Cylinder", WRL2_CYLINDER ) );
84  nodenames.insert( NODEITEM( "CylinderSensor", WRL2_CYLINDERSENSOR ) );
85  nodenames.insert( NODEITEM( "DirectionalLight", WRL2_DIRECTIONALLIGHT ) );
86  nodenames.insert( NODEITEM( "ElevationGrid", WRL2_ELEVATIONGRID ) );
87  nodenames.insert( NODEITEM( "Extrusion", WRL2_EXTRUSION ) );
88  nodenames.insert( NODEITEM( "Fog", WRL2_FOG ) );
89  nodenames.insert( NODEITEM( "FontStyle", WRL2_FONTSTYLE ) );
90  nodenames.insert( NODEITEM( "Group", WRL2_GROUP ) );
91  nodenames.insert( NODEITEM( "ImageTexture", WRL2_IMAGETEXTURE ) );
92  nodenames.insert( NODEITEM( "IndexedFaceSet", WRL2_INDEXEDFACESET ) );
93  nodenames.insert( NODEITEM( "IndexedLineSet", WRL2_INDEXEDLINESET ) );
94  nodenames.insert( NODEITEM( "Inline", WRL2_INLINE ) );
95  nodenames.insert( NODEITEM( "LOD", WRL2_LOD ) );
96  nodenames.insert( NODEITEM( "Material", WRL2_MATERIAL ) );
97  nodenames.insert( NODEITEM( "MovieTexture", WRL2_MOVIETEXTURE ) );
98  nodenames.insert( NODEITEM( "NavigationInfo", WRL2_NAVIGATIONINFO ) );
99  nodenames.insert( NODEITEM( "Normal", WRL2_NORMAL ) );
100  nodenames.insert( NODEITEM( "NormalInterpolator", WRL2_NORMALINTERPOLATOR ) );
101  nodenames.insert( NODEITEM( "OrientationInterpolator", WRL2_ORIENTATIONINTERPOLATOR ) );
102  nodenames.insert( NODEITEM( "PixelTexture", WRL2_PIXELTEXTURE ) );
103  nodenames.insert( NODEITEM( "PlaneSensor", WRL2_PLANESENSOR ) );
104  nodenames.insert( NODEITEM( "PointLight", WRL2_POINTLIGHT ) );
105  nodenames.insert( NODEITEM( "PointSet", WRL2_POINTSET ) );
106  nodenames.insert( NODEITEM( "PositionInterpolator", WRL2_POSITIONINTERPOLATOR ) );
107  nodenames.insert( NODEITEM( "ProximitySensor", WRL2_PROXIMITYSENSOR ) );
108  nodenames.insert( NODEITEM( "ScalarInterpolator", WRL2_SCALARINTERPOLATOR ) );
109  nodenames.insert( NODEITEM( "Script", WRL2_SCRIPT ) );
110  nodenames.insert( NODEITEM( "Shape", WRL2_SHAPE ) );
111  nodenames.insert( NODEITEM( "Sound", WRL2_SOUND ) );
112  nodenames.insert( NODEITEM( "Sphere", WRL2_SPHERE ) );
113  nodenames.insert( NODEITEM( "SphereSensor", WRL2_SPHERESENSOR ) );
114  nodenames.insert( NODEITEM( "SpotLight", WRL2_SPOTLIGHT ) );
115  nodenames.insert( NODEITEM( "Switch", WRL2_SWITCH ) );
116  nodenames.insert( NODEITEM( "Text", WRL2_TEXT ) );
117  nodenames.insert( NODEITEM( "TextureCoordinate", WRL2_TEXTURECOORDINATE ) );
118  nodenames.insert( NODEITEM( "TextureTransform", WRL2_TEXTURETRANSFORM ) );
119  nodenames.insert( NODEITEM( "TimeSensor", WRL2_TIMESENSOR ) );
120  nodenames.insert( NODEITEM( "TouchSensor", WRL2_TOUCHSENSOR ) );
121  nodenames.insert( NODEITEM( "Transform", WRL2_TRANSFORM ) );
122  nodenames.insert( NODEITEM( "ViewPoint", WRL2_VIEWPOINT ) );
123  nodenames.insert( NODEITEM( "VisibilitySensor", WRL2_VISIBILITYSENSOR ) );
124  nodenames.insert( NODEITEM( "WorldInfo", WRL2_WORLDINFO ) );
125  }
126 
127  return;
128 }
129 
130 
132 {
133  if( m_Parent )
134  m_Parent->unlinkChildNode( this );
135 
136  std::list< WRL2NODE* >::iterator sBP = m_BackPointers.begin();
137  std::list< WRL2NODE* >::iterator eBP = m_BackPointers.end();
138 
139  while( sBP != eBP )
140  {
141  (*sBP)->unlinkRefNode( this );
142  ++sBP;
143  }
144 
145  std::list< WRL2NODE* >::iterator sC = m_Refs.begin();
146  std::list< WRL2NODE* >::iterator eC = m_Refs.end();
147 
148  while( sC != eC )
149  {
150  (*sC)->delNodeRef( this );
151  ++sC;
152  }
153 
154  m_Refs.clear();
155  sC = m_Children.begin();
156  eC = m_Children.end();
157 
158  while( sC != eC )
159  {
160  (*sC)->SetParent( NULL, false );
161  delete *sC;
162  ++sC;
163  }
164 
165  m_Children.clear();
166  return;
167 }
168 
169 
171 {
172  // the parent node must never be added as a backpointer
173  if( aNode == m_Parent )
174  return;
175 
176  std::list< WRL2NODE* >::iterator np =
177  std::find( m_BackPointers.begin(), m_BackPointers.end(), aNode );
178 
179  if( np != m_BackPointers.end() )
180  return;
181 
182  m_BackPointers.push_back( aNode );
183 
184  return;
185 }
186 
187 
189 {
190  std::list< WRL2NODE* >::iterator np =
191  std::find( m_BackPointers.begin(), m_BackPointers.end(), aNode );
192 
193  if( np != m_BackPointers.end() )
194  {
195  m_BackPointers.erase( np );
196  return;
197  }
198 
199  #ifdef DEBUG_VRML2
200  do {
201  std::ostringstream ostr;
202  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
203  ostr << " * [BUG] delNodeRef() did not find its target";
204  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
205  } while( 0 );
206  #endif
207 
208  return;
209 }
210 
211 
213 {
214  return m_Type;
215 }
216 
217 
219 {
220  return m_Parent;
221 }
222 
223 
224 std::string WRL2NODE::GetName( void )
225 {
226  return m_Name;
227 }
228 
229 
230 bool WRL2NODE::SetName( const std::string& aName )
231 {
232  if( aName.empty() )
233  return false;
234 
235  std::set< std::string >::iterator item = badNames.find( aName );
236 
237  if( item != badNames.end() )
238  {
239  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 )
240  do {
241  std::ostringstream ostr;
242  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
243  ostr << " * [INFO] invalid node name '" << *item << "' (matches restricted word)";
244  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
245  } while( 0 );
246  #endif
247 
248  return false;
249  }
250 
251 
252  if( isdigit( aName[0] ) )
253  {
254  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 )
255  do {
256  std::ostringstream ostr;
257  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
258  ostr << " * [INFO] invalid node name '" << *item << "' (begins with digit)";
259  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
260  } while( 0 );
261  #endif
262 
263  return false;
264  }
265 
266  // The characters '+' and '-' are not allowed in names as per the VRML2 specification;
267  // however many parsers accept them and many bad generators use them so the rules
268  // have been relaxed here.
269  // #define BAD_CHARS1 "\"\'#+,-.\\[]{}\x00\x01\x02\x03\x04\x05\x06\x09\x0A\x0B\x0C\x0D\x0E\x0F"
270  #define BAD_CHARS1 "\"\'#,.\\[]{}\x00\x01\x02\x03\x04\x05\x06\x09\x0A\x0B\x0C\x0D\x0E\x0F"
271  #define BAD_CHARS2 "\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
272 
273  if( std::string::npos != aName.find_first_of( BAD_CHARS1 )
274  || std::string::npos != aName.find_first_of( BAD_CHARS2 ) )
275  {
276  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 )
277  do {
278  std::ostringstream ostr;
279  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
280  ostr << " * [INFO] invalid node name '" << aName;
281  ostr << "' (contains invalid character)";
282  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
283  } while( 0 );
284  #endif
285 
286  return false;
287  }
288 
289  m_Name = aName;
290 
291  return true;
292 }
293 
294 
295 const char* WRL2NODE::GetNodeTypeName( WRL2NODES aNodeType ) const
296 {
297  if( aNodeType < WRL2_BASE || aNodeType >= WRL2_END )
298  return "*INVALID_TYPE*";
299 
300  if( aNodeType == WRL2_BASE )
301  return "*VIRTUAL_BASE*";
302 
303  NODEMAP::iterator it = nodenames.begin();
304  advance( it, (aNodeType - WRL2_BEGIN) );
305 
306  return it->first.c_str();
307 }
308 
309 
310 WRL2NODES WRL2NODE::getNodeTypeID( const std::string& aNodeName )
311 {
312  NODEMAP::iterator it = nodenames.find( aNodeName );
313 
314  if( nodenames.end() != it )
315  return it->second;
316 
317  return WRL2_INVALID;
318 }
319 
320 
321 std::string WRL2NODE::GetError( void )
322 {
323  return m_error;
324 }
325 
326 
327 WRL2NODE* WRL2NODE::FindNode( const std::string& aNodeName, const WRL2NODE *aCaller )
328 {
329  if( aNodeName.empty() )
330  return NULL;
331 
332  if( !m_Name.compare( aNodeName ) )
333  return this;
334 
335  std::list< WRL2NODE* >::iterator sLA = m_Children.begin();
336  std::list< WRL2NODE* >::iterator eLA = m_Children.end();
337 
338  WRL2NODE* psg = NULL;
339 
340  while( sLA != eLA )
341  {
342  if( *sLA != aCaller )
343  {
344  psg = (*sLA)->FindNode( aNodeName, this );
345 
346  if( NULL != psg)
347  return psg;
348 
349  }
350  ++sLA;
351  }
352 
353  if( NULL != m_Parent && aCaller != m_Parent )
354  return m_Parent->FindNode( aNodeName, this );
355 
356  return NULL;
357 }
358 
359 
360 bool WRL2NODE::SetParent( WRL2NODE* aParent, bool doUnlink )
361 {
362  if( aParent == m_Parent )
363  return true;
364 
365  if( NULL != m_Parent && doUnlink )
366  m_Parent->unlinkChildNode( this );
367 
368  m_Parent = aParent;
369 
370  if( NULL != m_Parent )
371  m_Parent->AddChildNode( this );
372 
373  return true;
374 }
375 
376 
378 {
379  if( aNode == NULL )
380  return false;
381 
382  if( aNode->GetNodeType() == WRL2_BASE )
383  {
384  #ifdef DEBUG_VRML2
385  do {
386  std::ostringstream ostr;
387  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
388  ostr << " * [BUG] attempting to add a base node to another node";
389  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
390  } while( 0 );
391  #endif
392 
393  return false;
394  }
395 
396  std::list< WRL2NODE* >::iterator sC = m_Children.begin();
397  std::list< WRL2NODE* >::iterator eC = m_Children.end();
398 
399  while( sC != eC )
400  {
401  if( *sC == aNode )
402  return false;
403 
404  ++sC;
405  }
406 
407  m_Children.push_back( aNode );
408 
409  if( aNode->GetParent() != this )
410  aNode->SetParent( this );
411 
412  return true;
413 }
414 
415 
417 {
418  if( NULL == aNode )
419  {
420  #ifdef DEBUG_VRML2
421  do {
422  std::ostringstream ostr;
423  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
424  ostr << " * [BUG] NULL passed as node pointer";
425  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
426  } while( 0 );
427  #endif
428 
429  return false;
430  }
431 
432  if( aNode->GetNodeType() == WRL2_BASE )
433  {
434  #ifdef DEBUG_VRML2
435  do {
436  std::ostringstream ostr;
437  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
438  ostr << " * [BUG] attempting to add a base node ref to another base node";
439  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
440  } while( 0 );
441  #endif
442 
443  return false;
444  }
445 
446  std::list< WRL2NODE* >::iterator sR = m_Refs.begin();
447  std::list< WRL2NODE* >::iterator eR = m_Refs.end();
448 
449  while( sR != eR )
450  {
451  if( *sR == aNode )
452  return true;
453 
454  ++sR;
455  }
456 
457  m_Refs.push_back( aNode );
458  aNode->addNodeRef( this );
459 
460  return true;
461 }
462 
463 
465 {
466  std::list< WRL2NODE* >::iterator sL = m_Children.begin();
467  std::list< WRL2NODE* >::iterator eL = m_Children.end();
468 
469  while( sL != eL )
470  {
471  if( *sL == aNode )
472  {
473  m_Children.erase( sL );
474  return;
475  }
476 
477  ++sL;
478  }
479 
480  return;
481 }
482 
483 
484 void WRL2NODE::unlinkRefNode( const WRL2NODE* aNode )
485 {
486  std::list< WRL2NODE* >::iterator sL = m_Refs.begin();
487  std::list< WRL2NODE* >::iterator eL = m_Refs.end();
488 
489  while( sL != eL )
490  {
491  if( *sL == aNode )
492  {
493  m_Refs.erase( sL );
494  return;
495  }
496 
497  ++sL;
498  }
499 
500  return;
501 }
#define BAD_CHARS1
void addNodeRef(WRL2NODE *aNode)
Function addNodeRef adds a pointer to a node which references, but does not own, this node.
Definition: vrml2_node.cpp:170
#define BAD_CHARS2
virtual bool SetParent(WRL2NODE *aParent, bool doUnlink=true)
Function SetParent sets the parent WRL2NODE of this object.
Definition: vrml2_node.cpp:360
WRL2NODE represents the base class of all VRML2 nodes.
Definition: vrml2_node.h:58
std::pair< std::string, WRL2NODES > NODEITEM
Definition: vrml2_node.cpp:40
std::list< WRL2NODE * > m_Children
Definition: vrml2_node.h:66
std::string m_Name
Definition: vrml2_node.h:63
std::string GetError(void)
Definition: vrml2_node.cpp:321
#define MASK_VRML
Definition: wrltypes.h:37
virtual std::string GetName(void)
Definition: vrml2_node.cpp:224
std::list< WRL2NODE * > m_Refs
Definition: vrml2_node.h:67
WRL2NODES m_Type
Definition: vrml2_node.h:62
virtual bool SetName(const std::string &aName)
Definition: vrml2_node.cpp:230
WRL2NODES getNodeTypeID(const std::string &aNodeName)
Function getNodeTypeID returns the ID based on the given aNodeName or WRL2_INVALID (WRL2_END) if no s...
Definition: vrml2_node.cpp:310
std::map< std::string, std::vector< SGNODE * > > NODEMAP
Definition: loadmodel.cpp:91
void delNodeRef(WRL2NODE *aNode)
Function delNodeRef removes a pointer to a node which references, but does not own,...
Definition: vrml2_node.cpp:188
virtual ~WRL2NODE()
Definition: vrml2_node.cpp:131
#define NULL
WRL2NODE * m_Parent
Definition: vrml2_node.h:61
static NODEMAP nodenames
Definition: vrml2_node.cpp:42
SGNODE * m_sgNode
Definition: vrml2_node.h:70
std::list< WRL2NODE * > m_BackPointers
Definition: vrml2_node.h:65
WRL2NODES GetNodeType(void) const
Function GetNodeType returns the type of this node instance.
Definition: vrml2_node.cpp:212
const char * GetNodeTypeName(WRL2NODES aNodeType) const
Definition: vrml2_node.cpp:295
virtual bool AddChildNode(WRL2NODE *aNode)
Definition: vrml2_node.cpp:377
std::map< std::string, WRL2NODES > NODEMAP
Definition: vrml2_node.cpp:41
virtual void unlinkRefNode(const WRL2NODE *aNode)
Function unlinkRef removes pointers to a referenced node; it is invoked by the referenced node upon d...
Definition: vrml2_node.cpp:484
static std::set< std::string > badNames
Definition: vrml2_node.cpp:38
WRL2NODE * GetParent(void) const
Function GetParent returns a pointer to the parent SGNODE of this object or NULL if the object has no...
Definition: vrml2_node.cpp:218
WRL2NODES
Definition: wrltypes.h:121
virtual void unlinkChildNode(const WRL2NODE *aNode)
Function unlinkChild removes references to an owned child; it is invoked by the child upon destructio...
Definition: vrml2_node.cpp:464
std::string m_error
Definition: vrml2_node.h:68
virtual bool AddRefNode(WRL2NODE *aNode)
Definition: vrml2_node.cpp:416
virtual WRL2NODE * FindNode(const std::string &aNodeName, const WRL2NODE *aCaller)
Function FindNode searches the tree of linked nodes and returns a reference to the first node found w...
Definition: vrml2_node.cpp:327