From 8dd744f6354d364c6b3b05c75d6b6fb6c7c8e977 Mon Sep 17 00:00:00 2001 From: Cirilo Bernardo Date: Sun, 31 Jan 2016 13:21:12 +1100 Subject: [PATCH] Improved 3D cache manager's ability to replace outdated cache models --- 3d-viewer/3d_cache/3d_cache.cpp | 21 +++-- 3d-viewer/3d_cache/3d_plugin_manager.cpp | 50 +++++++++++- 3d-viewer/3d_cache/3d_plugin_manager.h | 12 ++- 3d-viewer/3d_cache/sg/ifsg_api.cpp | 97 +++++++++++++++++++++++- 3d-viewer/3d_cache/sg/scenegraph.cpp | 34 --------- include/plugins/3dapi/ifsg_api.h | 6 +- plugins/3d/vrml/v1/vrml1_base.cpp | 9 +++ plugins/ldr/pluginldr.cpp | 18 ++++- plugins/ldr/pluginldr.h | 7 +- 9 files changed, 202 insertions(+), 52 deletions(-) diff --git a/3d-viewer/3d_cache/3d_cache.cpp b/3d-viewer/3d_cache/3d_cache.cpp index 75f9ce686c..ae3155cb29 100644 --- a/3d-viewer/3d_cache/3d_cache.cpp +++ b/3d-viewer/3d_cache/3d_cache.cpp @@ -51,6 +51,15 @@ #define CACHE_CONFIG_NAME wxT( "cache.cfg" ) +static bool checkTag( const char* aTag, void* aPluginMgrPtr ) +{ + if( NULL == aTag || NULL == aPluginMgrPtr ) + return false; + + S3D_PLUGIN_MANAGER *pp = (S3D_PLUGIN_MANAGER*) aPluginMgrPtr; + + return pp->CheckTag( aTag ); +} static const wxString sha1ToWXString( const unsigned char* aSHA1Sum ) { @@ -136,8 +145,9 @@ public: const wxString GetCacheBaseName( void ); unsigned char sha1sum[20]; - SCENEGRAPH* sceneData; - S3DMODEL* renderData; + std::string pluginInfo; // PluginName:Version string + SCENEGRAPH* sceneData; + S3DMODEL* renderData; }; @@ -310,7 +320,7 @@ SCENEGRAPH* S3D_CACHE::checkCache( const wxString& aFileName, S3D_CACHE_ENTRY** if( wxFileName::FileExists( cachename ) && loadCacheData( ep ) ) return ep->sceneData; - ep->sceneData = m_Plugins->Load3DModel( aFileName ); + ep->sceneData = m_Plugins->Load3DModel( aFileName, ep->pluginInfo ); if( NULL != ep->sceneData ) saveCacheData( ep ); @@ -405,7 +415,7 @@ bool S3D_CACHE::loadCacheData( S3D_CACHE_ENTRY* aCacheItem ) if( NULL != aCacheItem->sceneData ) S3D::DestroyNode( (SGNODE*) aCacheItem->sceneData ); - aCacheItem->sceneData = (SCENEGRAPH*)S3D::ReadCache( fname.ToUTF8() ); + aCacheItem->sceneData = (SCENEGRAPH*)S3D::ReadCache( fname.ToUTF8(), m_Plugins, checkTag ); if( NULL == aCacheItem->sceneData ) return false; @@ -475,7 +485,8 @@ bool S3D_CACHE::saveCacheData( S3D_CACHE_ENTRY* aCacheItem ) } } - return S3D::WriteCache( fname.ToUTF8(), true, (SGNODE*)aCacheItem->sceneData ); + return S3D::WriteCache( fname.ToUTF8(), true, (SGNODE*)aCacheItem->sceneData, + aCacheItem->pluginInfo.c_str() ); } diff --git a/3d-viewer/3d_cache/3d_plugin_manager.cpp b/3d-viewer/3d_cache/3d_plugin_manager.cpp index a6c1836515..db58705664 100644 --- a/3d-viewer/3d_cache/3d_plugin_manager.cpp +++ b/3d-viewer/3d_cache/3d_plugin_manager.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2015 Cirilo Bernardo + * Copyright (C) 2015-2016 Cirilo Bernardo * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -398,7 +399,7 @@ std::list< wxString > const* S3D_PLUGIN_MANAGER::GetFileFilters( void ) const } -SCENEGRAPH* S3D_PLUGIN_MANAGER::Load3DModel( const wxString& aFileName ) +SCENEGRAPH* S3D_PLUGIN_MANAGER::Load3DModel( const wxString& aFileName, std::string& aPluginInfo ) { wxFileName raw( aFileName ); wxString ext = raw.GetExt(); @@ -416,7 +417,10 @@ SCENEGRAPH* S3D_PLUGIN_MANAGER::Load3DModel( const wxString& aFileName ) SCENEGRAPH* sp = sL->second->Load( aFileName.ToUTF8() ); if( NULL != sp ) + { + sL->second->GetPluginInfo( aPluginInfo ); return sp; + } } ++sL; @@ -444,3 +448,45 @@ void S3D_PLUGIN_MANAGER::ClosePlugins( void ) return; } + + +bool S3D_PLUGIN_MANAGER::CheckTag( const char* aTag ) +{ + if( NULL == aTag || aTag[0] == 0 || m_Plugins.empty() ) + return false; + + std::string tname = aTag; + std::string pname; // plugin name + + size_t cpos = tname.find( ':' ); + + // if there is no colon or plugin name then the tag is bad + if( cpos == std::string::npos || cpos == 0 ) + return false; + + pname = tname.substr( 0, cpos ); + std::string ptag; // tag from the plugin + + std::list< KICAD_PLUGIN_LDR_3D* >::iterator pS = m_Plugins.begin(); + std::list< KICAD_PLUGIN_LDR_3D* >::iterator pE = m_Plugins.end(); + + while( pS != pE ) + { + ptag.clear(); + (*pS)->GetPluginInfo( ptag ); + + // if the plugin name matches then the version + // must also match + if( !ptag.compare( 0, pname.size(), pname ) ) + { + if( ptag.compare( tname ) ) + return false; + + return true; + } + + ++pS; + } + + return true; +} diff --git a/3d-viewer/3d_cache/3d_plugin_manager.h b/3d-viewer/3d_cache/3d_plugin_manager.h index 76d0afc62f..a1257e7cfa 100644 --- a/3d-viewer/3d_cache/3d_plugin_manager.h +++ b/3d-viewer/3d_cache/3d_plugin_manager.h @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2015 Cirilo Bernardo + * Copyright (C) 2016 Cirilo Bernardo * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -31,6 +31,7 @@ #include #include +#include #include class wxWindow; @@ -82,7 +83,7 @@ public: */ std::list< wxString > const* GetFileFilters( void ) const; - SCENEGRAPH* Load3DModel( const wxString& aFileName ); + SCENEGRAPH* Load3DModel( const wxString& aFileName, std::string& aPluginInfo ); /** * Function ClosePlugins @@ -91,6 +92,13 @@ public: * reloaded as calls are made to load specific models. */ void ClosePlugins( void ); + + /** + * Function CheckTag + * checks the given tag and returns true if the plugin named in the tag + * is not loaded or the plugin is loaded and the version matches + */ + bool CheckTag( const char* aTag ); }; #endif // PLUGIN_MANAGER_3D_H diff --git a/3d-viewer/3d_cache/sg/ifsg_api.cpp b/3d-viewer/3d_cache/sg/ifsg_api.cpp index 721dfc359e..bcf4913c2a 100644 --- a/3d-viewer/3d_cache/sg/ifsg_api.cpp +++ b/3d-viewer/3d_cache/sg/ifsg_api.cpp @@ -48,6 +48,10 @@ static char BadNode[] = " * [BUG] NULL pointer passed for aNode\n"; #endif +// version format of the cache file +#define SG_VERSION_TAG "VERSION:2" + + static void formatMaterial( SMATERIAL& mat, SGAPPEARANCE const* app ) { float v0, v1, v2; @@ -229,7 +233,8 @@ void S3D::DestroyNode( SGNODE* aNode ) } -bool S3D::WriteCache( const char* aFileName, bool overwrite, SGNODE* aNode ) +bool S3D::WriteCache( const char* aFileName, bool overwrite, SGNODE* aNode, + const char* aPluginInfo ) { if( NULL == aFileName || aFileName[0] == 0 ) return false; @@ -281,23 +286,34 @@ bool S3D::WriteCache( const char* aFileName, bool overwrite, SGNODE* aNode ) return false; } + output << "(" << SG_VERSION_TAG << ")"; + + if( NULL != aPluginInfo && aPluginInfo[0] != 0 ) + output << "(" << aPluginInfo << ")"; + else + output << "(INTERNAL:0.0.0.0)"; + bool rval = aNode->WriteCache( output, NULL ); output.close(); - #ifdef DEBUG if( !rval ) { + #ifdef DEBUG std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; std::cerr << " * [INFO] problems encountered writing cache file '"; std::cerr << aFileName << "'\n"; + #endif + + // delete the defective file + wxRemoveFile( ofile ); } - #endif return rval; } -SGNODE* S3D::ReadCache( const char* aFileName ) +SGNODE* S3D::ReadCache( const char* aFileName, void* aPluginMgr, + bool (*aTagCheck)( const char*, void* ) ) { if( NULL == aFileName || aFileName[0] == 0 ) return NULL; @@ -336,6 +352,79 @@ SGNODE* S3D::ReadCache( const char* aFileName ) return NULL; } + // from SG_VERSION_TAG 1, read the version tag; if it's not the expected tag + // then we fail to read the cache file + do + { + std::string name; + char schar; + file.get( schar ); + + if( '(' != schar ) + { + #ifdef DEBUG + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [INFO] corrupt data; missing left parenthesis at position "; + std::cerr << file.tellg() << "\n"; + #endif + + file.close(); + return NULL; + } + + file.get( schar ); + + while( ')' != schar && file.good() ) + { + name.push_back( schar ); + file.get( schar ); + } + + if( name.compare( SG_VERSION_TAG ) ) + { + file.close(); + return NULL; + } + + } while( 0 ); + + // from SG_VERSION_TAG 2, read the PluginInfo string and check that it matches + // version tag; if it's not the expected tag then we fail to read the file + do + { + std::string name; + char schar; + file.get( schar ); + + if( '(' != schar ) + { + #ifdef DEBUG + std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; + std::cerr << " * [INFO] corrupt data; missing left parenthesis at position "; + std::cerr << file.tellg() << "\n"; + #endif + + file.close(); + return NULL; + } + + file.get( schar ); + + while( ')' != schar && file.good() ) + { + name.push_back( schar ); + file.get( schar ); + } + + // check the plugin tag + if( NULL != aTagCheck && NULL != aPluginMgr && !aTagCheck( name.c_str(), aPluginMgr ) ) + { + file.close(); + return NULL; + } + + } while( 0 ); + bool rval = np->ReadCache( file, NULL ); file.close(); diff --git a/3d-viewer/3d_cache/sg/scenegraph.cpp b/3d-viewer/3d_cache/sg/scenegraph.cpp index 280a318a84..1d201e1e27 100644 --- a/3d-viewer/3d_cache/sg/scenegraph.cpp +++ b/3d-viewer/3d_cache/sg/scenegraph.cpp @@ -33,9 +33,6 @@ #include "3d_cache/sg/sg_helpers.h" -// version format of the cache file -#define SG_VERSION_TAG "VERSION:1" - SCENEGRAPH::SCENEGRAPH( SGNODE* aParent ) : SGNODE( aParent ) { m_SGtype = S3D::SGTYPE_TRANSFORM; @@ -370,7 +367,6 @@ bool SCENEGRAPH::WriteCache( std::ofstream& aFile, SGNODE* parentNode ) // ensure unique node names ResetNodeIndex(); ReNameNodes(); - aFile << "[" << SG_VERSION_TAG << "]"; } if( aFile.fail() ) @@ -467,36 +463,6 @@ bool SCENEGRAPH::ReadCache( std::ifstream& aFile, SGNODE* parentNode ) if( NULL == parentNode ) { - // read the tag; if it's not the expected tag then we fail to read the cache file - do - { - char schar; - aFile.get( schar ); - - if( '[' != schar ) - { - #ifdef DEBUG - std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; - std::cerr << " * [INFO] corrupt data; missing left bracket at position "; - std::cerr << aFile.tellg() << "\n"; - #endif - - return false; - } - - aFile.get( schar ); - - while( ']' != schar && aFile.good() ) - { - name.push_back( schar ); - aFile.get( schar ); - } - - if( name.compare( SG_VERSION_TAG ) ) - return false; - - } while( 0 ); - // we need to read the tag and verify its type if( S3D::SGTYPE_TRANSFORM != S3D::ReadTag( aFile, name ) ) { diff --git a/include/plugins/3dapi/ifsg_api.h b/include/plugins/3dapi/ifsg_api.h index eca853a2b2..7779528e59 100644 --- a/include/plugins/3dapi/ifsg_api.h +++ b/include/plugins/3dapi/ifsg_api.h @@ -69,7 +69,8 @@ namespace S3D * @param aNode is any node within the node tree which is to be written * @return true on success */ - SGLIB_API bool WriteCache( const char* aFileName, bool overwrite, SGNODE* aNode ); + SGLIB_API bool WriteCache( const char* aFileName, bool overwrite, SGNODE* aNode, + const char* aPluginInfo ); /** * Function ReadCache @@ -80,7 +81,8 @@ namespace S3D * if desired this node can be associated with an IFSG_TRANSFORM wrapper via * the IFSG_TRANSFORM::Attach() function. */ - SGLIB_API SGNODE* ReadCache( const char* aFileName ); + SGLIB_API SGNODE* ReadCache( const char* aFileName, void* aPluginMgr, + bool (*aTagCheck)( const char*, void* ) ); /** * Function WriteVRML diff --git a/plugins/3d/vrml/v1/vrml1_base.cpp b/plugins/3d/vrml/v1/vrml1_base.cpp index 018da0ef93..54b47f3422 100644 --- a/plugins/3d/vrml/v1/vrml1_base.cpp +++ b/plugins/3d/vrml/v1/vrml1_base.cpp @@ -143,6 +143,11 @@ bool WRL1BASE::Read( WRLPROC& proc ) std::string glob; WRL1NODES ntype; + // Note: according to the VRML1 specification, a file may contain + // only one grouping node at the top level. The following code + // supports non-conformant VRML1 files by processing all top level + // grouping nodes. + while( proc.ReadName( glob ) ) { @@ -728,6 +733,10 @@ SGNODE* WRL1BASE::TranslateToSG( SGNODE* aParent, WRL1STATUS* /*sp*/ ) if( m_Items.size() == 1 ) return (*m_Items.begin())->TranslateToSG( NULL, NULL ); + // Note: according to the VRML1 specification, a file may contain + // only one grouping node at the top level. The following code + // supports non-conformant VRML1 files. + m_current.Init(); IFSG_TRANSFORM txNode( true ); diff --git a/plugins/ldr/pluginldr.cpp b/plugins/ldr/pluginldr.cpp index 1a64724bc3..041d2133f3 100644 --- a/plugins/ldr/pluginldr.cpp +++ b/plugins/ldr/pluginldr.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2015 Cirilo Bernardo + * Copyright (C) 2015-2016 Cirilo Bernardo * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -241,6 +241,16 @@ bool KICAD_PLUGIN_LDR::open( const wxString& aFullFileName, const char* aPluginC #endif ok = true; + + // set the plugin info string + m_pluginInfo = GetKicadPluginName(); + std::ostringstream ostr; + unsigned char r0, r1, r2, r3; + GetVersion( &r0, &r1, &r2, &r3 ); + ostr << ":" << (unsigned int)r0 << "." << (unsigned int)r1; + ostr << "." << (unsigned int)r2 << "." << (unsigned int)r3; + m_pluginInfo.append( ostr.str() ); + return true; } @@ -452,3 +462,9 @@ bool KICAD_PLUGIN_LDR::GetVersion( unsigned char* Major, unsigned char* Minor, return true; } + + +void KICAD_PLUGIN_LDR::GetPluginInfo( std::string& aPluginInfo ) +{ + aPluginInfo = m_pluginInfo; +} diff --git a/plugins/ldr/pluginldr.h b/plugins/ldr/pluginldr.h index dc22d36ae7..4523e00d47 100644 --- a/plugins/ldr/pluginldr.h +++ b/plugins/ldr/pluginldr.h @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2015 Cirilo Bernardo + * Copyright (C) 2015-2016 Cirilo Bernardo * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -63,7 +63,8 @@ private: GET_PLUGIN_NAME m_getPluginName; GET_VERSION m_getVersion; - wxString m_fileName; // name of last opened Plugin + wxString m_fileName; // name of last opened Plugin + std::string m_pluginInfo; // Name:Version tag for plugin protected: std::string m_error; // error message @@ -144,6 +145,8 @@ public: // returns false if no plugin is loaded bool GetVersion( unsigned char* Major, unsigned char* Minor, unsigned char* Patch, unsigned char* Revision ); + + void GetPluginInfo( std::string& aPluginInfo ); }; #endif // PLUGINLDR_H