48#include <wx/filename.h>
49#include <wx/wfstream.h>
50#include <boost/ptr_container/ptr_map.hpp>
54static inline long parseInt(
const wxString& aValue,
double aScalar )
56 double value = std::numeric_limits<double>::max();
79 if( aValue.EndsWith( wxT(
"mm" ) ) )
81 aScalar *= 100000.0 / 25.4;
83 else if( aValue.EndsWith( wxT(
"mil" ) ) )
90 aValue.ToCDouble(&value);
92 if( value == std::numeric_limits<double>::max() )
94 THROW_IO_ERROR( wxString::Format(
_(
"Cannot convert '%s' to an integer." ),
98 return KiROUND( value * aScalar );
125 m_filename( aFileName ),
126 m_footprint( aFootprint )
151 void Remove(
const wxString& aFootprintName );
159 static long long GetTimestamp(
const wxString& aLibPath );
179 bool testFlags(
const wxString& aFlag,
long aMask,
const wxChar* aName );
228 if( !dir.IsOpened() )
230 THROW_IO_ERROR( wxString::Format(
_(
"Footprint library '%s' not found." ),
241 if( !dir.GetFirst( &fullName, fileSpec ) )
244 wxString cacheErrorMsg;
264 if( !cacheErrorMsg.IsEmpty() )
265 cacheErrorMsg += wxT(
"\n\n" );
267 cacheErrorMsg += ioe.
What();
269 }
while( dir.GetNext( &fullName ) );
271 if( !cacheErrorMsg.IsEmpty() )
278 std::string footprintName =
TO_UTF8( aFootprintName );
280 FOOTPRINT_MAP::const_iterator it =
m_footprints.find( footprintName );
284 THROW_IO_ERROR( wxString::Format(
_(
"Library '%s' has no footprint '%s'." ),
286 aFootprintName.GetData() ) );
290 wxString fullPath = it->second->GetFileName().GetFullPath();
292 wxRemoveFile( fullPath );
314 #define TEXT_DEFAULT_SIZE ( 40*pcbIUScale.IU_PER_MILS )
315 #define OLD_GPCB_UNIT_CONV pcbIUScale.IU_PER_MILS
318 #define NEW_GPCB_UNIT_CONV ( 0.01*pcbIUScale.IU_PER_MILS )
325 wxArrayString parameters;
326 std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>(
nullptr );
328 if( aLineReader->
ReadLine() ==
nullptr )
330 msg = aLineReader->
GetSource() + wxT(
": empty file" );
336 paramCnt = parameters.GetCount();
346 if( parameters[0].CmpNoCase( wxT(
"Element" ) ) != 0 )
348 msg.Printf(
_(
"Unknown token '%s'" ), parameters[0] );
353 if( paramCnt < 10 || paramCnt > 14 )
355 msg.Printf(
_(
"Element token contains %d parameters." ), paramCnt );
361 if( parameters[1] == wxT(
"(" ) )
366 footprint->SetLibDescription( parameters[3] );
367 footprint->SetReference( parameters[4] );
371 footprint->SetLibDescription( parameters[2] );
372 footprint->SetReference( parameters[3] );
377 footprint->SetValue( parameters[5] );
381 if( footprint->Value().GetText().IsEmpty() )
382 footprint->Value().SetText( wxT(
"VAL**" ) );
384 if( footprint->Reference().GetText().IsEmpty() )
385 footprint->Reference().SetText( wxT(
"REF**" ) );
392 if( parameters.IsEmpty() || parameters[0] == wxT(
"(" ) )
395 if( parameters[0] == wxT(
")" ) )
398 paramCnt = parameters.GetCount();
403 if( parameters[1] == wxT(
"(" ) )
410 parameters[0], paramCnt );
413 if( parameters[0].CmpNoCase( wxT(
"ElementLine" ) ) == 0 )
417 msg.Printf( wxT(
"ElementLine token contains %d parameters." ), paramCnt );
425 parseInt( parameters[3], conv_unit ) ) );
427 parseInt( parameters[5], conv_unit ) ) );
429 LINE_STYLE::SOLID ) );
431 shape->
Rotate( { 0, 0 }, footprint->GetOrientation() );
432 shape->
Move( footprint->GetPosition() );
434 footprint->Add( shape );
439 if( parameters[0].CmpNoCase( wxT(
"ElementArc" ) ) == 0 )
443 msg.Printf( wxT(
"ElementArc token contains %d parameters." ), paramCnt );
451 footprint->Add( shape );
454 int radius = (
parseInt( parameters[4], conv_unit ) +
455 parseInt( parameters[5], conv_unit ) ) / 2;
458 parseInt( parameters[3], conv_unit ) );
480 shape->
SetStart( arcStart + centre );
487 LINE_STYLE::SOLID ) );
489 shape->
Rotate( { 0, 0 }, footprint->GetOrientation() );
490 shape->
Move( footprint->GetPosition() );
499 if( parameters[0].CmpNoCase( wxT(
"Pad" ) ) == 0 )
501 if( paramCnt < 10 || paramCnt > 13 )
503 msg.Printf( wxT(
"Pad token contains %d parameters." ), paramCnt );
508 std::unique_ptr<PAD>
pad = std::make_unique<PAD>( footprint.get() );
514 pad->SetAttribute( PAD_ATTRIB::SMD );
515 pad->SetLayerSet( pad_front );
517 if(
testFlags( parameters[paramCnt-2], 0x0080, wxT(
"onsolder" ) ) )
518 pad->SetLayerSet( pad_back );
528 pad->SetNumber( parameters[paramCnt-3] );
530 int x1 =
parseInt( parameters[2], conv_unit );
531 int x2 =
parseInt( parameters[4], conv_unit );
532 int y1 =
parseInt( parameters[3], conv_unit );
533 int y2 =
parseInt( parameters[5], conv_unit );
534 int width =
parseInt( parameters[6], conv_unit );
536 double angle = atan2( (
double)
delta.y, (
double)
delta.x );
541 int clearance =
parseInt( parameters[7], conv_unit );
545 pad->SetLocalClearance( clearance / 2 );
550 int maskMargin =
parseInt( parameters[8], conv_unit );
551 maskMargin = ( maskMargin - width ) / 2;
552 pad->SetLocalSolderMaskMargin( maskMargin );
557 pad->SetOrientation( orient );
559 VECTOR2I padPos( ( x1 + x2 ) / 2, ( y1 + y2 ) / 2 );
563 padPos += footprint->GetPosition();
564 pad->SetPosition( padPos );
566 if( !
testFlags( parameters[paramCnt-2], 0x0100, wxT(
"square" ) ) )
574 if(
pad->GetSizeX() > 0 &&
pad->GetSizeY() > 0 )
576 footprint->Add(
pad.release() );
580 wxLogError(
_(
"Invalid zero-sized pad ignored in\nfile: %s" ),
593 if( parameters[0].CmpNoCase( wxT(
"Pin" ) ) == 0 )
595 if( paramCnt < 8 || paramCnt > 12 )
597 msg.Printf( wxT(
"Pin token contains %d parameters." ), paramCnt );
608 pad->SetLayerSet( pad_set );
610 if(
testFlags( parameters[paramCnt-2], 0x0100, wxT(
"square" ) ) )
617 pad->SetNumber( parameters[paramCnt-3] );
620 parseInt( parameters[3], conv_unit ) );
622 int padSize =
parseInt( parameters[4], conv_unit );
631 int clearance =
parseInt( parameters[5], conv_unit );
635 pad->SetLocalClearance( clearance / 2 );
640 int maskMargin =
parseInt( parameters[6], conv_unit );
641 maskMargin = ( maskMargin - padSize ) / 2;
642 pad->SetLocalSolderMaskMargin( maskMargin );
644 drillSize =
parseInt( parameters[7], conv_unit );
648 drillSize =
parseInt( parameters[5], conv_unit );
651 pad->SetDrillSize(
VECTOR2I( drillSize, drillSize ) );
653 padPos += footprint->GetPosition();
654 pad->SetPosition( padPos );
662 footprint->Add(
pad );
667 footprint->AutoPositionFields();
669 return footprint.release();
677 char* line = aLineReader->
Line();
691 aParameterList.Add( tmp );
696 aParameterList.Add( tmp );
701 if( aParameterList.GetCount() == 1 )
713 aParameterList.Add( tmp );
718 aParameterList.Add( tmp );
732 aParameterList.Add( tmp );
744 aParameterList.Add( wxEmptyString );
755 aParameterList.Add( tmp );
783 if( aFlag.StartsWith( wxT(
"0x" ), &number ) || aFlag.StartsWith( wxT(
"0X" ), &number ) )
787 if( number.ToLong( &lflags, 16 ) && ( lflags & aMask ) )
790 else if( aFlag.Contains( aName ) )
810 m_ctl( aControlFlags )
842 wxString& aFootprintNameOut,
843 const std::map<std::string, UTF8>* aProperties )
845 wxFileName fn( aFootprintPath );
851 char* line = reader.
Line();
856 if( strncasecmp( line,
"Element", strlen(
"Element" ) ) != 0 )
859 aFootprintNameOut = fn.GetName();
866 bool aBestEfforts,
const std::map<std::string, UTF8>* aProperties )
869 wxDir dir( aLibraryPath );
872 if( !dir.IsOpened() )
878 THROW_IO_ERROR( wxString::Format(
_(
"Footprint library '%s' not found." ),
891 errorMsg = ioe.
What();
898 aFootprintNames.Add(
From_UTF8( footprint.first.c_str() ) );
900 if( !errorMsg.IsEmpty() && !aBestEfforts )
906 const wxString& aFootprintName,
907 const std::map<std::string, UTF8>* aProperties,
918 FOOTPRINT_MAP::const_iterator it = mods.find(
TO_UTF8( aFootprintName ) );
920 if( it == mods.end() )
923 return it->second->GetFootprint();
928 const wxString& aFootprintName,
930 const std::map<std::string, UTF8>* aProperties )
939 copy->SetParent(
nullptr );
948 const std::map<std::string, UTF8>* aProperties )
959 aLibraryPath.GetData() ) );
969 fn.SetPath( aLibraryPath );
972 if( !fn.DirExists() )
975 if( !fn.IsDirWritable() )
977 THROW_IO_ERROR( wxString::Format(
_(
"Insufficient permissions to delete folder '%s'." ),
978 aLibraryPath.GetData() ) );
981 wxDir dir( aLibraryPath );
983 if( dir.HasSubDirs() )
985 THROW_IO_ERROR( wxString::Format(
_(
"Library folder '%s' has unexpected sub-folders." ),
986 aLibraryPath.GetData() ) );
996 wxDir::GetAllFiles( aLibraryPath, &files );
998 for( i = 0; i < files.GetCount(); i++ )
1004 THROW_IO_ERROR( wxString::Format(
_(
"Unexpected file '%s' found in library '%s'." ),
1006 aLibraryPath.GetData() ) );
1010 for( i = 0; i < files.GetCount(); i++ )
1012 wxRemoveFile( files[i] );
1017 aLibraryPath.GetData() );
1021 if( !wxRmdir( aLibraryPath ) )
1023 THROW_IO_ERROR( wxString::Format(
_(
"Footprint library '%s' cannot be deleted." ),
1024 aLibraryPath.GetData() ) );
1031 wxMilliSleep( 250L );
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
void SetCenter(const VECTOR2I &aCenter)
void SetStart(const VECTOR2I &aStart)
void SetShape(SHAPE_T aShape)
void SetEnd(const VECTOR2I &aEnd)
void SetArcAngleAndEnd(const EDA_ANGLE &aAngle, bool aCheckNegativeAngle=false)
Set the end point from the angle center and start.
A LINE_READER that reads from an open file.
helper class for creating a footprint library cache.
FOOTPRINT * GetFootprint() const
GPCB_FPL_CACHE_ITEM(FOOTPRINT *aFootprint, const WX_FILENAME &aFileName)
WX_FILENAME GetFileName() const
std::unique_ptr< FOOTPRINT > m_footprint
WX_FILENAME m_filename
The full file name and path of the footprint to cache.
FOOTPRINT * parseFOOTPRINT(LINE_READER *aLineReader)
FOOTPRINT_MAP & GetFootprints()
void Remove(const wxString &aFootprintName)
FOOTPRINT_MAP m_footprints
Map of footprint file name to FOOTPRINT*.
GPCB_FPL_CACHE(PCB_IO_GEDA *aOwner, const wxString &aLibraryPath)
bool IsModified()
Return true if the cache is not up-to-date.
static long long GetTimestamp(const wxString &aLibPath)
Generate a timestamp representing all source files in the cache (including the parent directory).
PCB_IO_GEDA * m_owner
Plugin object that owns the cache.
void parseParameters(wxArrayString &aParameterList, LINE_READER *aLineReader)
Extract parameters and tokens from aLineReader and adds them to aParameterList.
long long m_cache_timestamp
A hash of the timestamps for all the footprint files.
wxFileName m_lib_path
The path of the library.
bool m_cache_dirty
Stored separately because it's expensive to check m_cache_timestamp against all the files.
void Load()
Save not implemented for the Geda PCB footprint library format.
bool testFlags(const wxString &aFlag, long aMask, const wxChar *aName)
Test aFlag for aMask or aName.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
A logical library item identifier and consists of various portions much like a URI.
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
virtual char * ReadLine()=0
Read a line of text into the buffer and increments the line number counter.
virtual const wxString & GetSource() const
Returns the name of the source of the lines in an abstract sense.
virtual unsigned LineNumber() const
Return the line number of the last line read from this LINE_READER.
char * Line() const
Return a pointer to the last line that was read in.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
LSET is a set of PCB_LAYER_IDs.
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
A #PLUGIN derivation for saving and loading Geda PCB files.
void FootprintDelete(const wxString &aLibraryPath, const wxString &aFootprintName, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Delete aFootprintName from the library at aLibraryPath.
bool IsLibraryWritable(const wxString &aLibraryPath) override
Return true if the library at aLibraryPath is writable.
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, bool aBestEfforts, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Return a list of footprint names contained within the library at aLibraryPath.
long long GetLibraryTimestamp(const wxString &aLibraryPath) const override
Generate a timestamp representing all the files in the library (including the library directory).
bool DeleteLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Delete an existing library and returns true, or if library does not exist returns false,...
FOOTPRINT * FootprintLoad(const wxString &aLibraryPath, const wxString &aFootprintName, bool aKeepUUID=false, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load a footprint having aFootprintName from the aLibraryPath containing a library format that this PC...
void init(const std::map< std::string, UTF8 > *aProperties)
GPCB_FPL_CACHE * m_cache
Footprint library cache.
void validateCache(const wxString &aLibraryPath, bool checkModified=true)
LINE_READER * m_reader
no ownership here.
friend class GPCB_FPL_CACHE
FOOTPRINT * ImportFootprint(const wxString &aFootprintPath, wxString &aFootprintNameOut, const std::map< std::string, UTF8 > *aProperties) override
Load a single footprint from aFootprintPath and put its name in aFootprintNameOut.
const FOOTPRINT * getFootprint(const wxString &aLibraryPath, const wxString &aFootprintName, const std::map< std::string, UTF8 > *aProperties, bool checkModified)
A base class that BOARD loading and saving plugins should derive from.
const std::map< std::string, UTF8 > * m_props
Properties passed via Save() or Load(), no ownership, may be NULL.
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void Move(const VECTOR2I &aMoveVector) override
Move this object.
void SetStroke(const STROKE_PARAMS &aStroke) override
Simple container to manage line stroke parameters.
Read lines of text from another LINE_READER but only returns non-comment lines and non-blank lines wi...
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
A wrapper around a wxFileName which is much more performant with a subset of the API.
void SetFullName(const wxString &aFileNameAndExtension)
wxString GetFullPath() const
static void SetReporter(REPORTER *aReporter)
Set the reporter to use for reporting font substitution warnings.
long long TimestampDir(const wxString &aDirPath, const wxString &aFilespec)
A copy of ConvertFileTimeToWx() because wxWidgets left it as a static function private to src/common/...
static constexpr EDA_ANGLE ANGLE_360
static constexpr EDA_ANGLE ANGLE_180
static const std::string GedaPcbFootprintLibFileExtension
static const std::string KiCadFootprintFileExtension
const wxChar *const traceGedaPcbPlugin
Flag to enable GEDA PCB plugin debug output.
#define THROW_IO_ERROR(msg)
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
std::map< wxString, FOOTPRINT * > FOOTPRINT_MAP
static long parseInt(const wxString &aValue, double aScalar)
#define NEW_GPCB_UNIT_CONV
#define OLD_GPCB_UNIT_CONV
boost::ptr_map< std::string, GPCB_FPL_CACHE_ITEM > FOOTPRINT_MAP
wxString From_UTF8(const char *cstring)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
wxString dump(const wxArrayString &aArray)
Debug helper for printing wxArrayString contents.
wxLogTrace helper definitions.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
VECTOR2< int32_t > VECTOR2I
Definition of file extensions used in Kicad.