Add IO_MGR::FindPluginTypeFromBoardPath (+QA tests)
This commit is contained in:
parent
8d5ebf5e30
commit
dbfb7880b5
|
@ -66,7 +66,6 @@
|
|||
|
||||
#include <wx/stdpaths.h>
|
||||
#include <wx/filedlg.h>
|
||||
#include <wx/wfstream.h>
|
||||
#include <wx/txtstrm.h>
|
||||
|
||||
#if wxCHECK_VERSION( 3, 1, 7 )
|
||||
|
@ -444,32 +443,6 @@ bool PCB_EDIT_FRAME::Files_io_from_id( int id )
|
|||
}
|
||||
|
||||
|
||||
// The KIWAY_PLAYER::OpenProjectFiles() API knows nothing about plugins, so
|
||||
// determine how to load the BOARD here
|
||||
IO_MGR::PCB_FILE_T FindBoardPlugin( const wxString& aFileName, int aCtl = 0 )
|
||||
{
|
||||
const auto& plugins = IO_MGR::PLUGIN_REGISTRY::Instance()->AllPlugins();
|
||||
|
||||
for( const auto& plugin : plugins )
|
||||
{
|
||||
bool isKiCad = plugin.m_type == IO_MGR::KICAD_SEXP || plugin.m_type == IO_MGR::LEGACY;
|
||||
|
||||
if( ( aCtl & KICTL_KICAD_ONLY ) && !isKiCad )
|
||||
continue;
|
||||
|
||||
if( ( aCtl & KICTL_NONKICAD_ONLY ) && isKiCad )
|
||||
continue;
|
||||
|
||||
PLUGIN::RELEASER pi( plugin.m_createFunc() );
|
||||
|
||||
if( pi->CanReadBoard( aFileName ) )
|
||||
return plugin.m_type;
|
||||
}
|
||||
|
||||
return IO_MGR::FILE_TYPE_NONE;
|
||||
}
|
||||
|
||||
|
||||
int PCB_EDIT_FRAME::inferLegacyEdgeClearance( BOARD* aBoard )
|
||||
{
|
||||
PCB_LAYER_COLLECTOR collector;
|
||||
|
@ -592,7 +565,7 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
|
|||
// No save prompt (we already prompted above), and only reset to a new blank board if new
|
||||
Clear_Pcb( false, !is_new );
|
||||
|
||||
IO_MGR::PCB_FILE_T pluginType = FindBoardPlugin( fullFileName, aCtl );
|
||||
IO_MGR::PCB_FILE_T pluginType = IO_MGR::FindPluginTypeFromBoardPath( fullFileName, aCtl );
|
||||
|
||||
bool converted = pluginType != IO_MGR::LEGACY && pluginType != IO_MGR::KICAD_SEXP;
|
||||
|
||||
|
|
|
@ -26,9 +26,12 @@
|
|||
#include <wx/uri.h>
|
||||
|
||||
#include <config.h>
|
||||
#include <kiway_player.h>
|
||||
#include <io_mgr.h>
|
||||
#include <wildcards_and_files_ext.h>
|
||||
|
||||
#include <plugins/eagle/eagle_plugin.h>
|
||||
#include <plugins/geda/gpcb_plugin.h>
|
||||
#include <io_mgr.h>
|
||||
#include <plugins/kicad/pcb_plugin.h>
|
||||
#include <plugins/legacy/legacy_plugin.h>
|
||||
#include <plugins/pcad/pcad_plugin.h>
|
||||
|
@ -38,7 +41,6 @@
|
|||
#include <plugins/altium/solidworks_pcb_plugin.h>
|
||||
#include <plugins/cadstar/cadstar_pcb_archive_plugin.h>
|
||||
#include <plugins/fabmaster/fabmaster_plugin.h>
|
||||
#include <wildcards_and_files_ext.h>
|
||||
|
||||
#define FMT_UNIMPLEMENTED _( "Plugin \"%s\" does not implement the \"%s\" function." )
|
||||
#define FMT_NOTFOUND _( "Plugin type \"%s\" is not found." )
|
||||
|
@ -113,6 +115,32 @@ IO_MGR::PCB_FILE_T IO_MGR::EnumFromStr( const wxString& aType )
|
|||
}
|
||||
|
||||
|
||||
// The KIWAY_PLAYER::OpenProjectFiles() API knows nothing about plugins, so
|
||||
// determine how to load the BOARD here
|
||||
IO_MGR::PCB_FILE_T IO_MGR::FindPluginTypeFromBoardPath( const wxString& aFileName, int aCtl )
|
||||
{
|
||||
const auto& plugins = IO_MGR::PLUGIN_REGISTRY::Instance()->AllPlugins();
|
||||
|
||||
for( const auto& plugin : plugins )
|
||||
{
|
||||
bool isKiCad = plugin.m_type == IO_MGR::KICAD_SEXP || plugin.m_type == IO_MGR::LEGACY;
|
||||
|
||||
if( ( aCtl & KICTL_KICAD_ONLY ) && !isKiCad )
|
||||
continue;
|
||||
|
||||
if( ( aCtl & KICTL_NONKICAD_ONLY ) && isKiCad )
|
||||
continue;
|
||||
|
||||
PLUGIN::RELEASER pi( plugin.m_createFunc() );
|
||||
|
||||
if( pi->CanReadBoard( aFileName ) )
|
||||
return plugin.m_type;
|
||||
}
|
||||
|
||||
return IO_MGR::FILE_TYPE_NONE;
|
||||
}
|
||||
|
||||
|
||||
IO_MGR::PCB_FILE_T IO_MGR::GuessPluginTypeFromLibPath( const wxString& aLibPath )
|
||||
{
|
||||
PCB_FILE_T ret = KICAD_SEXP; // default guess, unless detected otherwise.
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <vector>
|
||||
#include <wx/arrstr.h>
|
||||
#include <i18n_utility.h>
|
||||
|
@ -175,6 +176,11 @@ public:
|
|||
*/
|
||||
static PCB_FILE_T EnumFromStr( const wxString& aFileType );
|
||||
|
||||
/**
|
||||
* Return a plugin type given a path for a board file. FILE_TYPE_NONE if the file is not known.
|
||||
*/
|
||||
static PCB_FILE_T FindPluginTypeFromBoardPath( const wxString& aFileName, int aCtl = 0 );
|
||||
|
||||
/**
|
||||
* Return a plugin type given a footprint library's libPath.
|
||||
*/
|
||||
|
@ -669,6 +675,10 @@ public:
|
|||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
protected:
|
||||
static bool fileStartsWithPrefix( const wxString& aFilePath, const wxString& aPrefix,
|
||||
bool aIgnoreWhitespace );
|
||||
};
|
||||
|
||||
#endif // IO_MGR_H_
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#include <wx/translation.h>
|
||||
#include <wx/filename.h>
|
||||
#include <wx/dir.h>
|
||||
#include <wx/wfstream.h>
|
||||
#include <wx/txtstrm.h>
|
||||
|
||||
|
||||
#define FMT_UNIMPLEMENTED wxT( "Plugin \"%s\" does not implement the \"%s\" function." )
|
||||
|
@ -291,3 +293,28 @@ void PLUGIN::FootprintLibOptions( STRING_UTF8_MAP* aListToAppendTo ) const
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool PLUGIN::fileStartsWithPrefix( const wxString& aFilePath, const wxString& aPrefix,
|
||||
bool aIgnoreWhitespace )
|
||||
{
|
||||
wxFileInputStream input( aFilePath );
|
||||
|
||||
if( input.IsOk() && !input.Eof() )
|
||||
{
|
||||
// Find first non-empty line
|
||||
wxTextInputStream text( input );
|
||||
wxString line = text.ReadLine();
|
||||
|
||||
if( aIgnoreWhitespace )
|
||||
{
|
||||
while( line.IsEmpty() )
|
||||
line = text.ReadLine().Trim( false /*trim from left*/ );
|
||||
}
|
||||
|
||||
if( line.StartsWith( aPrefix ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -740,6 +740,26 @@ FP_3DMODEL* PCB_PARSER::parse3DModel()
|
|||
}
|
||||
|
||||
|
||||
bool PCB_PARSER::IsValidBoardHeader()
|
||||
{
|
||||
LOCALE_IO toggle;
|
||||
|
||||
m_groupInfos.clear();
|
||||
|
||||
// See Parse() - FOOTPRINTS can be prefixed with an initial block of single line comments,
|
||||
// eventually BOARD might be the same
|
||||
ReadCommentLines();
|
||||
|
||||
if( CurTok() != T_LEFT )
|
||||
return false;
|
||||
|
||||
if( NextTok() != T_kicad_pcb)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
BOARD_ITEM* PCB_PARSER::Parse()
|
||||
{
|
||||
T token;
|
||||
|
|
|
@ -113,6 +113,12 @@ public:
|
|||
*/
|
||||
wxString GetRequiredVersion();
|
||||
|
||||
/**
|
||||
* Partially parse the input and check if it matches expected header
|
||||
* @return true if expected header matches
|
||||
*/
|
||||
bool IsValidBoardHeader();
|
||||
|
||||
private:
|
||||
///< Convert net code using the mapping table if available,
|
||||
///< otherwise returns unchanged net code if < 0 or if it's out of range
|
||||
|
|
|
@ -415,15 +415,18 @@ bool LEGACY_PLUGIN::CanReadBoard( const wxString& aFileName ) const
|
|||
if( !PLUGIN::CanReadBoard( aFileName ) )
|
||||
return false;
|
||||
|
||||
wxFileInputStream input( aFileName );
|
||||
FILE_LINE_READER tempReader( aFileName );
|
||||
|
||||
if( !input.IsOk() || input.Eof() )
|
||||
try
|
||||
{
|
||||
getVersion( &tempReader );
|
||||
}
|
||||
catch( const IO_ERROR& e )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
wxTextInputStream text( input );
|
||||
wxString line = text.ReadLine();
|
||||
|
||||
return line.StartsWith( wxS( "PCBNEW" ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -486,7 +489,8 @@ BOARD* LEGACY_PLUGIN::LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
|
|||
m_reader = &reader;
|
||||
m_progressReporter = aProgressReporter;
|
||||
|
||||
checkVersion();
|
||||
m_loading_format_version = getVersion( m_reader );
|
||||
m_board->SetFileFormatVersionAtLoad( m_loading_format_version );
|
||||
|
||||
if( m_progressReporter )
|
||||
{
|
||||
|
@ -618,14 +622,14 @@ void LEGACY_PLUGIN::loadAllSections( bool doAppend )
|
|||
}
|
||||
|
||||
|
||||
void LEGACY_PLUGIN::checkVersion()
|
||||
int LEGACY_PLUGIN::getVersion( LINE_READER* aReader )
|
||||
{
|
||||
// Read first line and TEST if it is a PCB file format header like this:
|
||||
// "PCBNEW-BOARD Version 1 ...."
|
||||
|
||||
m_reader->ReadLine();
|
||||
aReader->ReadLine();
|
||||
|
||||
char* line = m_reader->Line();
|
||||
char* line = aReader->Line();
|
||||
|
||||
if( !TESTLINE( "PCBNEW-BOARD" ) )
|
||||
{
|
||||
|
@ -635,18 +639,15 @@ void LEGACY_PLUGIN::checkVersion()
|
|||
int ver = 1; // if sccanf fails
|
||||
sscanf( line, "PCBNEW-BOARD Version %d", &ver );
|
||||
|
||||
#if !defined(DEBUG)
|
||||
#if !defined( DEBUG )
|
||||
if( ver > LEGACY_BOARD_FILE_VERSION )
|
||||
{
|
||||
m_error.Printf( _( "File '%s' has an unrecognized version: %d." ),
|
||||
m_reader->GetSource().GetData(),
|
||||
ver );
|
||||
THROW_IO_ERROR( m_error );
|
||||
THROW_IO_ERROR( wxString::Format( _( "File '%s' has an unrecognized version: %d." ),
|
||||
aReader->GetSource().GetData(), ver ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_loading_format_version = ver;
|
||||
m_board->SetFileFormatVersionAtLoad( m_loading_format_version );
|
||||
return ver;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ protected:
|
|||
*/
|
||||
EDA_ANGLE degParse( const char* aValue, const char** nptrptr = nullptr );
|
||||
|
||||
void checkVersion();
|
||||
static int getVersion( LINE_READER* aReader );
|
||||
|
||||
void loadAllSections( bool doAppend );
|
||||
|
||||
|
|
|
@ -54,15 +54,12 @@ PCAD_PLUGIN::~PCAD_PLUGIN()
|
|||
}
|
||||
|
||||
|
||||
const wxString PCAD_PLUGIN::PluginName() const
|
||||
bool PCAD_PLUGIN::CanReadBoard( const wxString& aFileName ) const
|
||||
{
|
||||
return wxT( "P-Cad" );
|
||||
}
|
||||
if( !PLUGIN::CanReadBoard( aFileName ) )
|
||||
return false;
|
||||
|
||||
|
||||
PLUGIN_FILE_DESC PCAD_PLUGIN::GetBoardFileDesc() const
|
||||
{
|
||||
return PLUGIN_FILE_DESC( _HKI( "P-Cad 200x ASCII PCB files" ), { "pcb" } );
|
||||
return fileStartsWithPrefix( aFileName, wxT( "ACCEL_ASCII" ), false );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -38,9 +38,14 @@ public:
|
|||
PCAD_PLUGIN();
|
||||
~PCAD_PLUGIN();
|
||||
|
||||
const wxString PluginName() const override;
|
||||
const wxString PluginName() const { return wxT( "P-Cad" ); }
|
||||
|
||||
PLUGIN_FILE_DESC GetBoardFileDesc() const override;
|
||||
PLUGIN_FILE_DESC GetBoardFileDesc() const
|
||||
{
|
||||
return PLUGIN_FILE_DESC( _HKI( "P-Cad 200x ASCII PCB files" ), { "pcb" } );
|
||||
}
|
||||
|
||||
bool CanReadBoard( const wxString& aFileName ) const override;
|
||||
|
||||
BOARD* LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
|
||||
const STRING_UTF8_MAP* aProperties = nullptr, PROJECT* aProject = nullptr,
|
||||
|
|
|
@ -68,8 +68,6 @@ using namespace std::placeholders;
|
|||
// files.cpp
|
||||
extern bool AskLoadBoardFileName( PCB_EDIT_FRAME* aParent, wxString* aFileName, int aCtl = 0 );
|
||||
|
||||
extern IO_MGR::PCB_FILE_T FindBoardPlugin( const wxString& aFileName, int aCtl = 0 );
|
||||
|
||||
|
||||
PCB_CONTROL::PCB_CONTROL() :
|
||||
PCB_TOOL_BASE( "pcbnew.Control" ),
|
||||
|
@ -1018,7 +1016,8 @@ int PCB_CONTROL::AppendBoardFromFile( const TOOL_EVENT& aEvent )
|
|||
if( !AskLoadBoardFileName( editFrame, &fileName, true ) )
|
||||
return 1;
|
||||
|
||||
IO_MGR::PCB_FILE_T pluginType = FindBoardPlugin( fileName, KICTL_KICAD_ONLY );
|
||||
IO_MGR::PCB_FILE_T pluginType =
|
||||
IO_MGR::FindPluginTypeFromBoardPath( fileName, KICTL_KICAD_ONLY );
|
||||
PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) );
|
||||
|
||||
return AppendBoard( *pi, fileName );
|
||||
|
@ -1559,7 +1558,7 @@ int PCB_CONTROL::DdAppendBoard( const TOOL_EVENT& aEvent )
|
|||
return 1;
|
||||
|
||||
wxString filePath = fileName.GetFullPath();
|
||||
IO_MGR::PCB_FILE_T pluginType = FindBoardPlugin( filePath );
|
||||
IO_MGR::PCB_FILE_T pluginType = IO_MGR::FindPluginTypeFromBoardPath( filePath );
|
||||
PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) );
|
||||
|
||||
return AppendBoard( *pi, filePath );
|
||||
|
|
|
@ -34,6 +34,7 @@ set( QA_PCBNEW_SRCS
|
|||
test_array_pad_name_provider.cpp
|
||||
test_board_item.cpp
|
||||
test_graphics_import_mgr.cpp
|
||||
test_io_mgr.cpp
|
||||
test_lset.cpp
|
||||
test_pns_basics.cpp
|
||||
test_pad_numbering.cpp
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2023 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <pcbnew_utils/board_test_utils.h>
|
||||
#include <pcbnew_utils/board_file_utils.h>
|
||||
#include <qa_utils/wx_utils/unit_test_utils.h>
|
||||
|
||||
#include <pcbnew/io_mgr.h>
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE( IOMGR )
|
||||
|
||||
|
||||
struct BOARD_PLUGIN_CASE
|
||||
{
|
||||
std::string m_case_name;
|
||||
std::string m_file_rel_path;
|
||||
IO_MGR::PCB_FILE_T m_expected_type;
|
||||
};
|
||||
|
||||
|
||||
static const std::vector<BOARD_PLUGIN_CASE> BoardPluginCases = {
|
||||
|
||||
//
|
||||
// FAKE Boards (should return FILE_TYPE_NONE):
|
||||
//
|
||||
{
|
||||
"Fake Board file (KiCad *Legacy* / EAGLE file ext)",
|
||||
"plugins/fakeboard.brd",
|
||||
IO_MGR::FILE_TYPE_NONE
|
||||
},
|
||||
{
|
||||
"Fake Board file (KiCad file ext)",
|
||||
"plugins/fakeboard.kicad_pcb",
|
||||
IO_MGR::FILE_TYPE_NONE
|
||||
},
|
||||
{
|
||||
"Fake Board file (PCAD file ext)",
|
||||
"plugins/fakeboard.pcb",
|
||||
IO_MGR::FILE_TYPE_NONE
|
||||
},
|
||||
{
|
||||
"Fake Board file (CADSTAR file ext)",
|
||||
"plugins/fakeboard.cpa",
|
||||
IO_MGR::FILE_TYPE_NONE
|
||||
},
|
||||
|
||||
//
|
||||
// REAL Boards:
|
||||
//
|
||||
|
||||
{
|
||||
"Basic KiCad *Legacy* board file",
|
||||
"plugins/legacy_demos/flat_hierarchy/flat_hierarchy.brd",
|
||||
IO_MGR::LEGACY
|
||||
},
|
||||
{
|
||||
"Basic KiCad board file",
|
||||
"complex_hierarchy.kicad_pcb",
|
||||
IO_MGR::KICAD_SEXP
|
||||
},
|
||||
{
|
||||
"Basic Eagle board file",
|
||||
"plugins/eagle/Adafruit-AHT20-PCB/Adafruit AHT20 Temperature & Humidity.brd",
|
||||
IO_MGR::EAGLE
|
||||
},
|
||||
{
|
||||
"Basic PCAD board file",
|
||||
"plugins/pcad/pcad_4layer_glyph_test_ascii.PCB",
|
||||
IO_MGR::PCAD
|
||||
},
|
||||
{
|
||||
"Basic CADSTAR board file",
|
||||
"plugins/cadstar/route_offset/minimal_route_offset_curved_track.cpa",
|
||||
IO_MGR::CADSTAR_PCB_ARCHIVE
|
||||
}
|
||||
// Todo: Add Altium (+derivatives) and Fabmaster tests
|
||||
};
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( FindBoardPluginType )
|
||||
{
|
||||
for( auto& c : BoardPluginCases )
|
||||
{
|
||||
BOOST_TEST_CONTEXT( c.m_case_name )
|
||||
{
|
||||
std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + c.m_file_rel_path;
|
||||
|
||||
BOOST_CHECK_EQUAL( IO_MGR::FindPluginTypeFromBoardPath( dataPath ),
|
||||
c.m_expected_type );
|
||||
|
||||
// Todo add tests to check if it still works with upper/lower case ext.
|
||||
// ( FindPluginTypeFromBoardPath should be case insensitive)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( CheckCanReadBoard )
|
||||
{
|
||||
for( auto& c : BoardPluginCases )
|
||||
{
|
||||
BOOST_TEST_CONTEXT( c.m_case_name )
|
||||
{
|
||||
std::string dataPath = KI_TEST::GetPcbnewTestDataDir() + c.m_file_rel_path;
|
||||
|
||||
auto& pluginEntries = IO_MGR::PLUGIN_REGISTRY::Instance()->AllPlugins();
|
||||
|
||||
for( auto& entry : pluginEntries )
|
||||
{
|
||||
BOOST_TEST_CONTEXT( entry.m_name )
|
||||
{
|
||||
auto plugin = PLUGIN::RELEASER( IO_MGR::PluginFind( entry.m_type ) );
|
||||
bool expectValidHeader = c.m_expected_type == entry.m_type;
|
||||
|
||||
BOOST_CHECK_EQUAL( plugin->CanReadBoard( dataPath ), expectValidHeader );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
Loading…
Reference in New Issue