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