Add support for PCB and footprint format versioning
Currently, kicad_pcb files have a (version ...) tag, but it is ignored. This commit does the following: 1. Parse the version. If it's later than the last supported version, present an alternative error message suggesting an upgrade if the file does not load correctly. The version will be interpreted as an integer YYYYMMDD to suggest a KiCad release date. 2. Accept a (version ...) tag also in kicad_mod files, but do not write them yet. If no version tag is present in these files, assume the version to be that of the current format version at the time of this commit. This is meant to be merged to the 4.x stable series, and preps for KiCad 5 which will start emitting version tags also in footprints - users with what will then be 'old stable' will not get a parse error when we introduce this for footprints, and we can safely increment the format version later.
This commit is contained in:
parent
35fe82739b
commit
f9386fcbc0
|
@ -1,9 +1,8 @@
|
|||
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2007-2011 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2015 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2016 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
|
||||
|
@ -36,11 +35,6 @@
|
|||
#endif
|
||||
|
||||
|
||||
// This file defines 3 classes and some functions useful for working with text files
|
||||
// and is named "richio" after its author, Richard Hollenbeck, aka Dick Hollenbeck.
|
||||
|
||||
|
||||
|
||||
static int vprint( std::string* result, const char* format, va_list ap )
|
||||
{
|
||||
char msg[512];
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2007-2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2007 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2016 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
|
||||
|
@ -192,7 +192,10 @@ struct PARSE_ERROR : public IO_ERROR
|
|||
const char* aInputLine,
|
||||
int aLineNumber, int aByteIndex );
|
||||
|
||||
~PARSE_ERROR() throw ( /*none*/ ){}
|
||||
virtual ~PARSE_ERROR() throw ( /*none*/ ){}
|
||||
|
||||
protected:
|
||||
PARSE_ERROR(): IO_ERROR() {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -200,6 +203,36 @@ struct PARSE_ERROR : public IO_ERROR
|
|||
throw PARSE_ERROR( __FILE__, __LOC__, aMsg, aSource, aInputLine, aLineNumber, aByteIndex )
|
||||
|
||||
|
||||
/**
|
||||
* Struct FUTURE_FORMAT_ERROR
|
||||
* variant of PARSE_ERROR indicating that a syntax or related error was likely caused
|
||||
* by a file generated by a newer version of KiCad than this. Can be used to generate
|
||||
* more informative error messages.
|
||||
*/
|
||||
struct FUTURE_FORMAT_ERROR : public PARSE_ERROR
|
||||
{
|
||||
wxString requiredVersion; ///< version or date of KiCad required to open file
|
||||
|
||||
FUTURE_FORMAT_ERROR( const PARSE_ERROR& aParseError, const wxString& aRequiredVersion ) :
|
||||
PARSE_ERROR(), requiredVersion( aRequiredVersion )
|
||||
{
|
||||
errorText.Printf( _(
|
||||
"KiCad was unable to open this file, as it was created with a more "
|
||||
"recent version than the one you are running. To open it, you'll need "
|
||||
"to upgrade KiCad to a more recent version.\n\n"
|
||||
"Date of KiCad version required (or newer): %s\n\n"
|
||||
"Full error text:\n%s" ),
|
||||
requiredVersion, aParseError.errorText );
|
||||
|
||||
lineNumber = aParseError.lineNumber;
|
||||
byteIndex = aParseError.byteIndex;
|
||||
inputLine = aParseError.inputLine;
|
||||
}
|
||||
|
||||
~FUTURE_FORMAT_ERROR() throw () {}
|
||||
};
|
||||
|
||||
|
||||
/** @} exception_types */
|
||||
|
||||
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2012-2015 KiCad Developers, see change_log.txt for contributors.
|
||||
|
||||
* Copyright (C) 2012-2016 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
|
||||
|
@ -3121,7 +3120,8 @@ wxArrayString EAGLE_PLUGIN::FootprintEnumerate( const wxString& aLibraryPath, co
|
|||
}
|
||||
|
||||
|
||||
MODULE* EAGLE_PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName, const PROPERTIES* aProperties )
|
||||
MODULE* EAGLE_PLUGIN::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
|
||||
const PROPERTIES* aProperties )
|
||||
{
|
||||
init( aProperties );
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2012-2015 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2012-2016 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
|
||||
|
@ -87,7 +87,8 @@ public:
|
|||
|
||||
wxArrayString FootprintEnumerate( const wxString& aLibraryPath, const PROPERTIES* aProperties = NULL);
|
||||
|
||||
MODULE* FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName, const PROPERTIES* aProperties = NULL );
|
||||
MODULE* FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
|
||||
const PROPERTIES* aProperties = NULL );
|
||||
|
||||
bool IsFootprintLibWritable( const wxString& aLibraryPath )
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2011-2015 Wayne Stambaugh <stambaughw@verizon.net>
|
||||
* Copyright (C) 2015 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2016 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
|
||||
|
@ -518,7 +518,6 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
|
|||
GetChars( ioe.errorText )
|
||||
);
|
||||
DisplayError( this, msg );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2016 KiCad Developers, see CHANGELOG.TXT for contributors.
|
||||
* Copyright (C) 2016 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
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2013 KiCad Developers, see CHANGELOG.TXT for contributors.
|
||||
* Copyright (C) 2016 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
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
|
||||
* Copyright (C) 1992-2015 KiCad Developers, see change_log.txt for contributors.
|
||||
*
|
||||
* Copyright (C) 1992-2016 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
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
|
||||
* Copyright (C) 1992-2012 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 1992-2016 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
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2011-2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2011 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2016 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
|
||||
|
@ -98,6 +98,9 @@ PLUGIN* IO_MGR::PluginFind( PCB_FILE_T aFileType )
|
|||
#else
|
||||
THROW_IO_ERROR( "BUILD_GITHUB_PLUGIN not enabled in cmake build environment" );
|
||||
#endif
|
||||
|
||||
case FILE_TYPE_NONE:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2011-2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2011 Kicad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2016 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
|
||||
|
@ -83,6 +83,8 @@ public:
|
|||
|
||||
// ALTIUM,
|
||||
// etc.
|
||||
|
||||
FILE_TYPE_NONE
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 CERN
|
||||
* Copyright (C) 1992-2011 KiCad Developers, see change_log.txt for contributors.
|
||||
*
|
||||
* Copyright (C) 1992-2016 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
|
||||
|
@ -418,7 +417,8 @@ void PCB_IO::Save( const wxString& aFileName, BOARD* aBoard, const PROPERTIES* a
|
|||
}
|
||||
|
||||
|
||||
BOARD_ITEM* PCB_IO::Parse( const wxString& aClipboardSourceInput ) throw( PARSE_ERROR, IO_ERROR )
|
||||
BOARD_ITEM* PCB_IO::Parse( const wxString& aClipboardSourceInput )
|
||||
throw( FUTURE_FORMAT_ERROR, PARSE_ERROR, IO_ERROR )
|
||||
{
|
||||
std::string input = TO_UTF8( aClipboardSourceInput );
|
||||
|
||||
|
@ -426,8 +426,18 @@ BOARD_ITEM* PCB_IO::Parse( const wxString& aClipboardSourceInput ) throw( PARSE_
|
|||
|
||||
m_parser->SetLineReader( &reader );
|
||||
|
||||
try
|
||||
{
|
||||
return m_parser->Parse();
|
||||
}
|
||||
catch( const PARSE_ERROR& parse_error )
|
||||
{
|
||||
if( m_parser->IsTooRecent() )
|
||||
throw FUTURE_FORMAT_ERROR( parse_error, m_parser->GetRequiredVersion() );
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PCB_IO::Format( BOARD_ITEM* aItem, int aNestLevel ) const
|
||||
|
@ -1721,7 +1731,20 @@ BOARD* PCB_IO::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPER
|
|||
m_parser->SetLineReader( &reader );
|
||||
m_parser->SetBoard( aAppendToMe );
|
||||
|
||||
BOARD* board = dyn_cast<BOARD*>( m_parser->Parse() );
|
||||
BOARD* board;
|
||||
|
||||
try
|
||||
{
|
||||
board = dynamic_cast<BOARD*>( m_parser->Parse() );
|
||||
}
|
||||
catch( const PARSE_ERROR& parse_error )
|
||||
{
|
||||
if( m_parser->IsTooRecent() )
|
||||
throw FUTURE_FORMAT_ERROR( parse_error, m_parser->GetRequiredVersion() );
|
||||
else
|
||||
throw;
|
||||
}
|
||||
|
||||
wxASSERT( board );
|
||||
|
||||
// Give the filename to the board if it's new
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 CERN.
|
||||
* Copyright (C) 1992-2016 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
|
||||
|
@ -108,7 +109,8 @@ public:
|
|||
|
||||
BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties = NULL );
|
||||
|
||||
wxArrayString FootprintEnumerate( const wxString& aLibraryPath, const PROPERTIES* aProperties = NULL);
|
||||
wxArrayString FootprintEnumerate( const wxString& aLibraryPath,
|
||||
const PROPERTIES* aProperties = NULL );
|
||||
|
||||
MODULE* FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
|
||||
const PROPERTIES* aProperties = NULL );
|
||||
|
@ -153,7 +155,7 @@ public:
|
|||
void SetOutputFormatter( OUTPUTFORMATTER* aFormatter ) { m_out = aFormatter; }
|
||||
|
||||
BOARD_ITEM* Parse( const wxString& aClipboardSourceInput )
|
||||
throw( PARSE_ERROR, IO_ERROR );
|
||||
throw( FUTURE_FORMAT_ERROR, PARSE_ERROR, IO_ERROR );
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* Copyright (C) 2007-2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2004 Jean-Pierre Charras, jp.charras@wanadoo.fr
|
||||
* Copyright (C) 1992-2015 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 1992-2016 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
|
||||
|
@ -387,7 +387,8 @@ static inline long hexParse( const char* next, const char** out = NULL )
|
|||
}
|
||||
|
||||
|
||||
BOARD* LEGACY_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties )
|
||||
BOARD* LEGACY_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe,
|
||||
const PROPERTIES* aProperties )
|
||||
{
|
||||
LOCALE_IO toggle; // toggles on, then off, the C locale.
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2012 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2016 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
|
||||
|
@ -30,10 +30,12 @@
|
|||
#include <string>
|
||||
#include <layers_id_colors_and_visibility.h>
|
||||
|
||||
// FOOTPRINT_LIBRARY_HEADER_CNT gives the number of characters to compare to detect
|
||||
// a footprint library. A few variants may have been used, and so we can only be
|
||||
// sure that the header contains "PCBNEW-LibModule-V", not "PCBNEW-LibModule-V1".
|
||||
#define FOOTPRINT_LIBRARY_HEADER "PCBNEW-LibModule-V1"
|
||||
#define FOOTPRINT_LIBRARY_HEADER_CNT 18
|
||||
|
||||
|
||||
class PCB_TARGET;
|
||||
class MODULE;
|
||||
class DRAWSEGMENT;
|
||||
|
@ -77,9 +79,11 @@ public:
|
|||
return wxT( "brd" );
|
||||
}
|
||||
|
||||
BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties = NULL );
|
||||
BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe,
|
||||
const PROPERTIES* aProperties = NULL );
|
||||
|
||||
wxArrayString FootprintEnumerate( const wxString& aLibraryPath, const PROPERTIES* aProperties = NULL);
|
||||
wxArrayString FootprintEnumerate( const wxString& aLibraryPath,
|
||||
const PROPERTIES* aProperties = NULL );
|
||||
|
||||
MODULE* FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
|
||||
const PROPERTIES* aProperties = NULL );
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 1992-2015 KiCad Developers, see change_log.txt for contributors.
|
||||
*
|
||||
* Copyright (C) 1992-2016 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
|
||||
|
@ -99,19 +98,14 @@ static const wxString ModImportFileWildcard( _( "GPcb foot print files (*)|*" )
|
|||
#define EXPORT_IMPORT_LASTPATH_KEY wxT( "import_last_path" )
|
||||
|
||||
|
||||
MODULE* FOOTPRINT_EDIT_FRAME::Import_Module()
|
||||
/**
|
||||
* Prompt the user for a module file to open.
|
||||
* @param aParent - parent window for the dialog
|
||||
* @param aLastPath - last opened path
|
||||
*/
|
||||
static wxFileName prompt_for_module( wxWindow* aParent, const wxString& aLastPath )
|
||||
{
|
||||
// use the clipboard for this in the future?
|
||||
|
||||
// Some day it might be useful save the last library type selected along with the path.
|
||||
static int lastFilterIndex = 0;
|
||||
|
||||
wxString lastOpenedPathForLoading = m_mruPath;
|
||||
wxConfigBase* config = Kiface().KifaceSettings();
|
||||
|
||||
if( config )
|
||||
config->Read( EXPORT_IMPORT_LASTPATH_KEY, &lastOpenedPathForLoading );
|
||||
|
||||
wxString wildCard;
|
||||
|
||||
wildCard << wxGetTranslation( KiCadFootprintLibFileWildcard ) << wxChar( '|' )
|
||||
|
@ -119,90 +113,196 @@ MODULE* FOOTPRINT_EDIT_FRAME::Import_Module()
|
|||
<< wxGetTranslation( ModImportFileWildcard ) << wxChar( '|' )
|
||||
<< wxGetTranslation( GedaPcbFootprintLibFileWildcard );
|
||||
|
||||
wxFileDialog dlg( this, FMT_IMPORT_MODULE,
|
||||
lastOpenedPathForLoading, wxEmptyString,
|
||||
wildCard, wxFD_OPEN | wxFD_FILE_MUST_EXIST );
|
||||
wxFileDialog dlg( aParent, FMT_IMPORT_MODULE, aLastPath, wxEmptyString, wildCard,
|
||||
wxFD_OPEN | wxFD_FILE_MUST_EXIST );
|
||||
|
||||
dlg.SetFilterIndex( lastFilterIndex );
|
||||
|
||||
if( dlg.ShowModal() == wxID_CANCEL )
|
||||
return NULL;
|
||||
return wxFileName();
|
||||
|
||||
lastFilterIndex = dlg.GetFilterIndex();
|
||||
|
||||
FILE* fp = wxFopen( dlg.GetPath(), wxT( "rt" ) );
|
||||
return wxFileName( dlg.GetPath() );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a file to detect the type.
|
||||
* @param aFile - open file to be read. File pointer will be closed.
|
||||
* @param aFileName - file name to be read
|
||||
* @param aName - wxString to receive the module name iff type is LEGACY
|
||||
*/
|
||||
static IO_MGR::PCB_FILE_T detect_file_type( FILE* aFile, const wxFileName& aFileName, wxString* aName )
|
||||
{
|
||||
FILE_LINE_READER freader( aFile, aFileName.GetFullPath() );
|
||||
WHITESPACE_FILTER_READER reader( freader );
|
||||
IO_MGR::PCB_FILE_T file_type;
|
||||
|
||||
wxASSERT( aName );
|
||||
|
||||
reader.ReadLine();
|
||||
char* line = reader.Line();
|
||||
|
||||
if( !strnicmp( line, "(module", strlen( "(module" ) ) )
|
||||
{
|
||||
file_type = IO_MGR::KICAD;
|
||||
*aName = aFileName.GetName();
|
||||
}
|
||||
else if( !strnicmp( line, FOOTPRINT_LIBRARY_HEADER, FOOTPRINT_LIBRARY_HEADER_CNT ) )
|
||||
{
|
||||
file_type = IO_MGR::LEGACY;
|
||||
while( reader.ReadLine() )
|
||||
{
|
||||
if( !strnicmp( line, "$MODULE", strlen( "$MODULE" ) ) )
|
||||
{
|
||||
*aName = FROM_UTF8( StrPurge( line + strlen( "$MODULE" ) ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( !strnicmp( line, "Element", strlen( "Element" ) ) )
|
||||
{
|
||||
file_type = IO_MGR::GEDA_PCB;
|
||||
*aName = aFileName.GetName();
|
||||
}
|
||||
else
|
||||
{
|
||||
file_type = IO_MGR::FILE_TYPE_NONE;
|
||||
}
|
||||
|
||||
return file_type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse a footprint using a PLUGIN.
|
||||
* @param aFileName - file name to parse
|
||||
* @param aFileType - type of the file
|
||||
* @param aName - name of the footprint
|
||||
*/
|
||||
static MODULE* parse_module_with_plugin(
|
||||
const wxFileName& aFileName, IO_MGR::PCB_FILE_T aFileType,
|
||||
const wxString& aName )
|
||||
{
|
||||
wxString path;
|
||||
|
||||
switch( aFileType )
|
||||
{
|
||||
case IO_MGR::GEDA_PCB:
|
||||
path = aFileName.GetPath();
|
||||
break;
|
||||
case IO_MGR::LEGACY:
|
||||
path = aFileName.GetFullPath();
|
||||
break;
|
||||
default:
|
||||
wxFAIL_MSG( wxT( "unexpected IO_MGR::PCB_FILE_T" ) );
|
||||
}
|
||||
|
||||
PLUGIN::RELEASER pi( IO_MGR::PluginFind( aFileType ) );
|
||||
|
||||
return pi->FootprintLoad( path, aName );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse a KICAD footprint.
|
||||
* @param aFileName - file name to parse
|
||||
*/
|
||||
static MODULE* parse_module_kicad( const wxFileName& aFileName )
|
||||
{
|
||||
wxString fcontents;
|
||||
PCB_IO pcb_io;
|
||||
wxFFile f( aFileName.GetFullPath() );
|
||||
|
||||
if( !f.IsOpened() )
|
||||
return NULL;
|
||||
|
||||
f.ReadAll( &fcontents );
|
||||
|
||||
return dynamic_cast<MODULE*>( pcb_io.Parse( fcontents ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try to load a footprint, returning NULL if the file couldn't be accessed.
|
||||
* @param aFileName - file name to load
|
||||
* @param aFileType - type of the file to load
|
||||
* @param aName - footprint name
|
||||
*/
|
||||
MODULE* try_load_footprint( const wxFileName& aFileName, IO_MGR::PCB_FILE_T aFileType,
|
||||
const wxString& aName )
|
||||
{
|
||||
MODULE* module;
|
||||
|
||||
switch( aFileType )
|
||||
{
|
||||
case IO_MGR::GEDA_PCB:
|
||||
case IO_MGR::LEGACY:
|
||||
module = parse_module_with_plugin( aFileName, aFileType, aName );
|
||||
break;
|
||||
|
||||
case IO_MGR::KICAD:
|
||||
module = parse_module_kicad( aFileName );
|
||||
break;
|
||||
|
||||
default:
|
||||
wxFAIL_MSG( wxT( "unexpected IO_MGR::PCB_FILE_T" ) );
|
||||
module = NULL;
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
|
||||
MODULE* FOOTPRINT_EDIT_FRAME::Import_Module()
|
||||
{
|
||||
wxString lastOpenedPathForLoading = m_mruPath;
|
||||
wxConfigBase* config = Kiface().KifaceSettings();
|
||||
|
||||
if( config )
|
||||
config->Read( EXPORT_IMPORT_LASTPATH_KEY, &lastOpenedPathForLoading );
|
||||
|
||||
wxFileName fn = prompt_for_module( this, lastOpenedPathForLoading );
|
||||
|
||||
if( !fn.IsOk() )
|
||||
return NULL;
|
||||
|
||||
FILE* fp = wxFopen( fn.GetFullPath(), wxT( "rt" ) );
|
||||
|
||||
if( !fp )
|
||||
{
|
||||
wxString msg = wxString::Format( FMT_FILE_NOT_FOUND, GetChars( dlg.GetPath() ) );
|
||||
wxString msg = wxString::Format( FMT_FILE_NOT_FOUND, GetChars( fn.GetFullPath() ) );
|
||||
DisplayError( this, msg );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( config ) // Save file path
|
||||
{
|
||||
lastOpenedPathForLoading = wxPathOnly( dlg.GetPath() );
|
||||
lastOpenedPathForLoading = fn.GetPath();
|
||||
config->Write( EXPORT_IMPORT_LASTPATH_KEY, lastOpenedPathForLoading );
|
||||
}
|
||||
|
||||
wxString moduleName;
|
||||
IO_MGR::PCB_FILE_T fileType = detect_file_type( fp, fn.GetFullPath(), &moduleName );
|
||||
|
||||
bool isGeda = false;
|
||||
bool isLegacy = false;
|
||||
|
||||
{
|
||||
FILE_LINE_READER freader( fp, dlg.GetPath() ); // I own fp, and will close it.
|
||||
WHITESPACE_FILTER_READER reader( freader ); // skip blank lines
|
||||
|
||||
reader.ReadLine();
|
||||
char* line = reader.Line();
|
||||
|
||||
if( !strnicmp( line, "(module", 7 ) )
|
||||
{
|
||||
// isKicad = true;
|
||||
}
|
||||
else if( !strnicmp( line, FOOTPRINT_LIBRARY_HEADER, FOOTPRINT_LIBRARY_HEADER_CNT ) )
|
||||
{
|
||||
isLegacy = true;
|
||||
|
||||
while( reader.ReadLine() )
|
||||
{
|
||||
if( !strnicmp( line, "$MODULE", 7 ) )
|
||||
{
|
||||
moduleName = FROM_UTF8( StrPurge( line + sizeof( "$MODULE" ) -1 ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( !strnicmp( line, "Element", 7 ) )
|
||||
{
|
||||
isGeda = true;
|
||||
}
|
||||
else
|
||||
if( fileType == IO_MGR::FILE_TYPE_NONE )
|
||||
{
|
||||
DisplayError( this, FMT_NOT_MODULE );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// fp is closed here by ~FILE_LINE_READER()
|
||||
}
|
||||
|
||||
MODULE* module;
|
||||
wxString errMessage;
|
||||
|
||||
if( isGeda )
|
||||
{
|
||||
try
|
||||
{
|
||||
wxFileName fn = dlg.GetPath();
|
||||
PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::GEDA_PCB ) );
|
||||
|
||||
moduleName = fn.GetName();
|
||||
module = pi->FootprintLoad( fn.GetPath(), moduleName );
|
||||
module = try_load_footprint( fn, fileType, moduleName );
|
||||
|
||||
if( !module )
|
||||
{
|
||||
wxString msg = wxString::Format(
|
||||
FMT_MOD_NOT_FOUND, GetChars( moduleName ), GetChars( fn.GetPath() ) );
|
||||
|
||||
FMT_MOD_NOT_FOUND, GetChars( moduleName ), GetChars( fn.GetFullPath() ) );
|
||||
DisplayError( this, msg );
|
||||
return NULL;
|
||||
}
|
||||
|
@ -212,67 +312,6 @@ MODULE* FOOTPRINT_EDIT_FRAME::Import_Module()
|
|||
DisplayError( this, ioe.errorText );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if( isLegacy )
|
||||
{
|
||||
try
|
||||
{
|
||||
PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) );
|
||||
|
||||
module = pi->FootprintLoad( dlg.GetPath(), moduleName );
|
||||
|
||||
if( !module )
|
||||
{
|
||||
wxString msg = wxString::Format(
|
||||
FMT_MOD_NOT_FOUND, GetChars( moduleName ), GetChars( dlg.GetPath() ) );
|
||||
|
||||
DisplayError( this, msg );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
DisplayError( this, ioe.errorText );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else // if( isKicad )
|
||||
{
|
||||
try
|
||||
{
|
||||
// This technique was chosen to create an example of how reading
|
||||
// the s-expression format from clipboard could be done.
|
||||
|
||||
wxString fcontents;
|
||||
PCB_IO pcb_io;
|
||||
wxFFile f( dlg.GetPath() );
|
||||
|
||||
if( !f.IsOpened() )
|
||||
{
|
||||
wxString msg = wxString::Format( FMT_BAD_PATH, GetChars( dlg.GetPath() ) );
|
||||
|
||||
DisplayError( this, msg );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f.ReadAll( &fcontents );
|
||||
|
||||
module = dyn_cast<MODULE*>( pcb_io.Parse( fcontents ) );
|
||||
|
||||
if( !module )
|
||||
{
|
||||
wxString msg = wxString::Format( FMT_BAD_PATH, GetChars( dlg.GetPath() ) );
|
||||
|
||||
DisplayError( this, msg );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
DisplayError( this, ioe.errorText );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert footprint in list
|
||||
GetBoard()->Add( module );
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 CERN
|
||||
* Copyright (C) 2012-2015 KiCad Developers, see change_log.txt for contributors.
|
||||
* @author Wayne Stambaugh <stambaughw@verizon.net>
|
||||
* Copyright (C) 2012-2016 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
|
||||
|
@ -60,6 +59,8 @@ using namespace PCB_KEYS_T;
|
|||
|
||||
void PCB_PARSER::init()
|
||||
{
|
||||
m_tooRecent = false;
|
||||
m_requiredVersion = 0;
|
||||
m_layerIndices.clear();
|
||||
m_layerMasks.clear();
|
||||
|
||||
|
@ -169,6 +170,43 @@ bool PCB_PARSER::parseBool() throw( PARSE_ERROR )
|
|||
}
|
||||
|
||||
|
||||
int PCB_PARSER::parseVersion() throw( IO_ERROR, PARSE_ERROR )
|
||||
{
|
||||
if( NextTok() != T_version )
|
||||
Expecting( GetTokenText( T_version ) );
|
||||
|
||||
int pcb_version = parseInt( FromUTF8() );
|
||||
|
||||
NeedRIGHT();
|
||||
|
||||
return pcb_version;
|
||||
}
|
||||
|
||||
|
||||
wxString PCB_PARSER::GetRequiredVersion()
|
||||
{
|
||||
int year, month, day;
|
||||
|
||||
year = m_requiredVersion / 10000;
|
||||
month = ( m_requiredVersion / 100 ) - ( year * 100 );
|
||||
day = m_requiredVersion - ( year * 10000 ) - ( month * 100 );
|
||||
|
||||
// wx throws an assertion, not a catchable exception, when the date is invalid.
|
||||
// User input shouldn't give wx asserts, so check manually and throw a proper
|
||||
// error instead
|
||||
if( day <= 0 || month <= 0 || month > 12 ||
|
||||
day > wxDateTime::GetNumberOfDays( (wxDateTime::Month)( month - 1 ), year ) )
|
||||
{
|
||||
wxString err;
|
||||
err.Printf( _( "cannot interpret date code %d" ), m_requiredVersion );
|
||||
THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
|
||||
}
|
||||
|
||||
wxDateTime date( day, (wxDateTime::Month)( month - 1 ), year, 0, 0, 0, 0 );
|
||||
return date.FormatDate();
|
||||
}
|
||||
|
||||
|
||||
wxPoint PCB_PARSER::parseXY() throw( PARSE_ERROR, IO_ERROR )
|
||||
{
|
||||
if( CurTok() != T_LEFT )
|
||||
|
@ -411,7 +449,23 @@ BOARD_ITEM* PCB_PARSER::Parse() throw( IO_ERROR, PARSE_ERROR )
|
|||
}
|
||||
|
||||
|
||||
BOARD* PCB_PARSER::parseBOARD() throw( IO_ERROR, PARSE_ERROR )
|
||||
BOARD* PCB_PARSER::parseBOARD() throw( IO_ERROR, PARSE_ERROR, FUTURE_FORMAT_ERROR )
|
||||
{
|
||||
try
|
||||
{
|
||||
return parseBOARD_unchecked();
|
||||
}
|
||||
catch( const PARSE_ERROR& parse_error )
|
||||
{
|
||||
if( m_tooRecent )
|
||||
throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOARD* PCB_PARSER::parseBOARD_unchecked() throw( IO_ERROR, PARSE_ERROR )
|
||||
{
|
||||
T token;
|
||||
|
||||
|
@ -506,25 +560,35 @@ void PCB_PARSER::parseHeader() throw( IO_ERROR, PARSE_ERROR )
|
|||
wxCHECK_RET( CurTok() == T_kicad_pcb,
|
||||
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a header." ) );
|
||||
|
||||
T token;
|
||||
|
||||
NeedLEFT();
|
||||
token = NextTok();
|
||||
|
||||
if( token != T_version )
|
||||
Expecting( GetTokenText( T_version ) );
|
||||
|
||||
// Get the file version.
|
||||
m_board->SetFileFormatVersionAtLoad( parseInt( GetTokenText( T_version ) ) );
|
||||
T tok = NextTok();
|
||||
if( tok == T_version )
|
||||
{
|
||||
m_requiredVersion = parseInt( FromUTF8() );
|
||||
m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
|
||||
NeedRIGHT();
|
||||
|
||||
// Skip the host name and host build version information.
|
||||
NeedRIGHT();
|
||||
NeedLEFT();
|
||||
NeedSYMBOL();
|
||||
NeedSYMBOL();
|
||||
NeedSYMBOL();
|
||||
NeedRIGHT();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_requiredVersion = SEXPR_BOARD_FILE_VERSION;
|
||||
m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
|
||||
|
||||
// Skip the host name and host build version information.
|
||||
NeedSYMBOL();
|
||||
NeedSYMBOL();
|
||||
NeedRIGHT();
|
||||
}
|
||||
|
||||
m_board->SetFileFormatVersionAtLoad( m_requiredVersion );
|
||||
}
|
||||
|
||||
|
||||
void PCB_PARSER::parseGeneralSection() throw( IO_ERROR, PARSE_ERROR )
|
||||
|
@ -1651,7 +1715,25 @@ DIMENSION* PCB_PARSER::parseDIMENSION() throw( IO_ERROR, PARSE_ERROR )
|
|||
}
|
||||
|
||||
|
||||
MODULE* PCB_PARSER::parseMODULE( wxArrayString* aInitialComments ) throw( IO_ERROR, PARSE_ERROR )
|
||||
MODULE* PCB_PARSER::parseMODULE( wxArrayString* aInitialComments )
|
||||
throw( IO_ERROR, PARSE_ERROR, FUTURE_FORMAT_ERROR )
|
||||
{
|
||||
try
|
||||
{
|
||||
return parseMODULE_unchecked( aInitialComments );
|
||||
}
|
||||
catch( const PARSE_ERROR& parse_error )
|
||||
{
|
||||
if( m_tooRecent )
|
||||
throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MODULE* PCB_PARSER::parseMODULE_unchecked( wxArrayString* aInitialComments )
|
||||
throw( IO_ERROR, PARSE_ERROR )
|
||||
{
|
||||
wxCHECK_MSG( CurTok() == T_module, NULL,
|
||||
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as MODULE." ) );
|
||||
|
@ -1665,7 +1747,11 @@ MODULE* PCB_PARSER::parseMODULE( wxArrayString* aInitialComments ) throw( IO_ERR
|
|||
|
||||
module->SetInitialComments( aInitialComments );
|
||||
|
||||
NeedSYMBOLorNUMBER();
|
||||
token = NextTok();
|
||||
|
||||
if( !IsSymbol( token ) && token != T_NUMBER )
|
||||
Expecting( "symbol|number" );
|
||||
|
||||
name = FromUTF8();
|
||||
|
||||
if( !name.IsEmpty() && fpid.Parse( FromUTF8() ) >= 0 )
|
||||
|
@ -1683,6 +1769,18 @@ MODULE* PCB_PARSER::parseMODULE( wxArrayString* aInitialComments ) throw( IO_ERR
|
|||
|
||||
switch( token )
|
||||
{
|
||||
case T_version:
|
||||
{
|
||||
// Theoretically a module nested in a PCB could declare its own version, though
|
||||
// as of writing this comment we don't do that. Just in case, take the greater
|
||||
// version.
|
||||
int this_version = parseInt( FromUTF8() );
|
||||
NeedRIGHT();
|
||||
m_requiredVersion = std::max( m_requiredVersion, this_version );
|
||||
m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
|
||||
break;
|
||||
}
|
||||
|
||||
case T_locked:
|
||||
module->SetLocked( true );
|
||||
break;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 CERN
|
||||
* Copyright (C) 2012-2016 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
|
||||
|
@ -68,6 +69,8 @@ class PCB_PARSER : public PCB_LEXER
|
|||
LAYER_ID_MAP m_layerIndices; ///< map layer name to it's index
|
||||
LSET_MAP m_layerMasks; ///< map layer names to their masks
|
||||
std::vector<int> m_netCodes; ///< net codes mapping for boards being loaded
|
||||
bool m_tooRecent; ///< true if version parses as later than supported
|
||||
int m_requiredVersion; ///< set to the KiCad format version this board requires
|
||||
|
||||
///> Converts net code using the mapping table if available,
|
||||
///> otherwise returns unchanged net code if < 0 or if is is out of range
|
||||
|
@ -113,12 +116,20 @@ class PCB_PARSER : public PCB_LEXER
|
|||
DIMENSION* parseDIMENSION() throw( IO_ERROR, PARSE_ERROR );
|
||||
|
||||
/**
|
||||
* Function parseModule
|
||||
* Function parseMODULE
|
||||
* @param aInitialComments may be a pointer to a heap allocated initial comment block
|
||||
* or NULL. If not NULL, then caller has given ownership of a wxArrayString to
|
||||
* this function and care must be taken to delete it even on exception.
|
||||
*/
|
||||
MODULE* parseMODULE( wxArrayString* aInitialComments = 0 ) throw( IO_ERROR, PARSE_ERROR );
|
||||
MODULE* parseMODULE( wxArrayString* aInitialComments = 0 )
|
||||
throw( IO_ERROR, PARSE_ERROR, FUTURE_FORMAT_ERROR );
|
||||
|
||||
/**
|
||||
* Function parseMODULE_unchecked
|
||||
* Parse a module, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERROR automatically.
|
||||
*/
|
||||
MODULE* parseMODULE_unchecked( wxArrayString* aInitialComments = 0 )
|
||||
throw( IO_ERROR, PARSE_ERROR );
|
||||
TEXTE_MODULE* parseTEXTE_MODULE() throw( IO_ERROR, PARSE_ERROR );
|
||||
EDGE_MODULE* parseEDGE_MODULE() throw( IO_ERROR, PARSE_ERROR );
|
||||
D_PAD* parseD_PAD( MODULE* aParent = NULL ) throw( IO_ERROR, PARSE_ERROR );
|
||||
|
@ -126,7 +137,13 @@ class PCB_PARSER : public PCB_LEXER
|
|||
VIA* parseVIA() throw( IO_ERROR, PARSE_ERROR );
|
||||
ZONE_CONTAINER* parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR );
|
||||
PCB_TARGET* parsePCB_TARGET() throw( IO_ERROR, PARSE_ERROR );
|
||||
BOARD* parseBOARD() throw( IO_ERROR, PARSE_ERROR );
|
||||
BOARD* parseBOARD() throw( IO_ERROR, PARSE_ERROR, FUTURE_FORMAT_ERROR );
|
||||
|
||||
/**
|
||||
* Function parseBOARD_unchecked
|
||||
* Parse a module, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERROR automatically.
|
||||
*/
|
||||
BOARD* parseBOARD_unchecked() throw( IO_ERROR, PARSE_ERROR );
|
||||
|
||||
|
||||
/**
|
||||
|
@ -252,6 +269,11 @@ class PCB_PARSER : public PCB_LEXER
|
|||
|
||||
bool parseBool() throw( PARSE_ERROR );
|
||||
|
||||
/**
|
||||
* Parse a format version tag like (version 20160417) return the version.
|
||||
* Expects to start on 'version', and eats the closing paren.
|
||||
*/
|
||||
int parseVersion() throw( IO_ERROR, PARSE_ERROR );
|
||||
|
||||
public:
|
||||
|
||||
|
@ -284,6 +306,21 @@ public:
|
|||
}
|
||||
|
||||
BOARD_ITEM* Parse() throw( IO_ERROR, PARSE_ERROR );
|
||||
|
||||
/**
|
||||
* Return whether a version number, if any was parsed, was too recent
|
||||
*/
|
||||
bool IsTooRecent()
|
||||
{
|
||||
return m_tooRecent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representing the version of kicad required to open this
|
||||
* file. Not particularly meaningful if IsTooRecent() returns false.
|
||||
*/
|
||||
wxString GetRequiredVersion();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2011-2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2011 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2016 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
|
||||
|
|
Loading…
Reference in New Issue