KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_io_sprint_layout.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
22
23#include <board.h>
24#include <footprint.h>
25#include <zone.h>
26#include <font/fontconfig.h>
27#include <gestfich.h>
28#include <reporter.h>
29
30#include <ranges>
31#include <wx/filename.h>
32#include <wx/wfstream.h>
33#include <wx/dir.h>
34
35
37 PCB_IO( wxS( "Sprint Layout" ) )
38{
39}
40
41
42void PCB_IO_SPRINT_LAYOUT::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath,
43 bool aBestEfforts, const std::map<std::string, UTF8>* aProperties )
44{
45 wxFileName libFn( aLibraryPath );
46
47 if( libFn.FileExists() && libFn.GetExt().Upper() == wxS( "LMK" ) )
48 {
49 aFootprintNames.Add( libFn.GetName() );
50 return;
51 }
52
53 if( wxDir::Exists( aLibraryPath ) )
54 {
55 wxArrayString files;
56 CollectFilesLoopSafe( aLibraryPath, files, wxEmptyString, wxDIR_FILES | wxDIR_DIRS );
57
58 for( const wxString& filePath : files )
59 {
60 wxFileName file( filePath );
61
62 if( file.GetExt().Upper() != wxS( "LMK" ) )
63 continue;
64
65 file.MakeRelativeTo( aLibraryPath );
66 aFootprintNames.Add( file.GetFullPath().BeforeLast( '.' ) );
67 }
68 }
69}
70
71
72FOOTPRINT* PCB_IO_SPRINT_LAYOUT::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
73 bool aKeepUUID, const std::map<std::string, UTF8>* aProperties )
74{
75 wxFileName libFn( aLibraryPath );
76 wxFileName lmkPath;
77
78 if( libFn.FileExists() && libFn.GetExt().Upper() == wxS( "LMK" ) )
79 {
80 lmkPath = libFn;
81 }
82 else
83 {
84 if( !wxDir::Exists( aLibraryPath ) )
85 return nullptr;
86
87 lmkPath = wxFileName( aLibraryPath + wxFileName::GetPathSeparator() + aFootprintName + wxS( ".LMK" ) );
88
89 if( !lmkPath.FileExists() )
90 {
91 lmkPath.SetExt( "lmk" );
92
93 if( !lmkPath.FileExists() )
94 return nullptr;
95 }
96 }
97
99
100 if( !parser.ParseMacroFile( lmkPath.GetFullPath() ) )
101 return nullptr;
102
103 return parser.CreateFootprint();
104}
105
106
108{
109 for( std::unique_ptr<FOOTPRINT>& fp : m_loadedFootprints | std::views::values )
110 fp->SetParent( nullptr );
111}
112
113
114bool PCB_IO_SPRINT_LAYOUT::CanReadBoard( const wxString& aFileName ) const
115{
116 const wxFileName fn( aFileName );
117
118 if( !fn.FileExists() )
119 return false;
120
121 wxString ext = fn.GetExt().Lower();
122
123 if( ext != wxS( "lay6" ) && ext != wxS( "lay" ) )
124 return false;
125
126 // Check magic bytes: version (<=6), 0x33, 0xAA, 0xFF
127 wxFFileInputStream stream( aFileName );
128
129 if( !stream.IsOk() || stream.GetLength() < 8 )
130 return false;
131
132 uint8_t header[4];
133 stream.Read( header, 4 );
134
135 if( stream.LastRead() != 4 )
136 return false;
137
138 if( header[0] > 6 || header[1] != 0x33 || header[2] != 0xAA || header[3] != 0xFF )
139 return false;
140
141 return true;
142}
143
144
145BOARD* PCB_IO_SPRINT_LAYOUT::LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
146 const std::map<std::string, UTF8>* aProperties,
147 PROJECT* aProject )
148{
150
151 m_props = aProperties;
152 m_loadedFootprints.clear();
153
155
156 if( !parser.ParseBoard( aFileName ) )
157 {
158 THROW_IO_ERROR( wxString::Format( _( "Failed to parse Sprint Layout file '%s'" ),
159 aFileName ) );
160 }
161
162 const auto& fileData = parser.GetFileData();
163 size_t boardIndex = 0;
164
165 if( m_props && m_props->contains( "pcb_id" ) )
166 {
167 unsigned long idx = std::stoul( m_props->at( "pcb_id" ) );
168 boardIndex = static_cast<size_t>( idx );
169 }
170 else if( fileData.boards.size() > 1 && m_choose_project_handler )
171 {
172 std::vector<IMPORT_PROJECT_DESC> options;
173
174 for( size_t i = 0; i < fileData.boards.size(); i++ )
175 {
177 wxString name = wxString::FromUTF8( fileData.boards[i].name );
178
179 if( name.empty() )
180 name = wxString::Format( wxS( "Board %zu" ), i + 1 );
181
182 desc.PCBName = name;
183 desc.PCBId = wxString::Format( wxS( "%zu" ), i );
184 options.push_back( desc );
185 }
186
187 std::vector<IMPORT_PROJECT_DESC> chosen = m_choose_project_handler( options );
188
189 if( chosen.empty() )
190 return nullptr;
191
192 unsigned long idx = std::stoul( chosen[0].PCBId.ToStdString() );
193 boardIndex = static_cast<size_t>( idx );
194 }
195
196 std::unique_ptr<BOARD> newBoard( parser.CreateBoard( m_loadedFootprints, boardIndex ) );
197
198 if( !newBoard )
199 {
200 THROW_IO_ERROR( wxString::Format( _( "Failed to create board from Sprint Layout file '%s'" ),
201 aFileName ) );
202 }
203
204 if( aAppendToMe )
205 {
206 for( FOOTPRINT* fp : newBoard->Footprints() )
207 aAppendToMe->Add( static_cast<FOOTPRINT*>( fp->Clone() ) );
208
209 for( BOARD_ITEM* item : newBoard->Drawings() )
210 aAppendToMe->Add( static_cast<BOARD_ITEM*>( item->Clone() ) );
211
212 for( ZONE* zone : newBoard->Zones() )
213 aAppendToMe->Add( static_cast<ZONE*>( zone->Clone() ) );
214
215 return aAppendToMe;
216 }
217
218 newBoard->SetFileName( aFileName );
219 return newBoard.release();
220}
221
222
224{
225 std::vector<FOOTPRINT*> result;
226
227 for( auto& [name, footprint] : m_loadedFootprints )
228 result.push_back( static_cast<FOOTPRINT*>( footprint->Clone() ) );
229
230 return result;
231}
const char * name
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition board.cpp:1295
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:89
RAII class to set and restore the fontconfig reporter.
Definition reporter.h:332
static LOAD_INFO_REPORTER & GetInstance()
Definition reporter.cpp:247
std::vector< FOOTPRINT * > GetImportedCachedLibraryFootprints() override
Return a container with the cached library footprints generated in the last call to Load.
bool CanReadBoard(const wxString &aFileName) const override
Checks if this PCB_IO can read the specified board file.
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...
std::map< wxString, std::unique_ptr< FOOTPRINT > > m_loadedFootprints
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.
BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const std::map< std::string, UTF8 > *aProperties=nullptr, PROJECT *aProject=nullptr) override
Load information from some input file format that this PCB_IO implementation knows about into either ...
PCB_IO(const wxString &aName)
Definition pcb_io.h:342
const std::map< std::string, UTF8 > * m_props
Properties passed via Save() or Load(), no ownership, may be NULL.
Definition pcb_io.h:352
CHOOSE_PROJECT_HANDLER m_choose_project_handler
Callback to choose projects to import.
Container for project specific data.
Definition project.h:62
const SPRINT_LAYOUT::FILE_DATA & GetFileData() const
BOARD * CreateBoard(std::map< wxString, std::unique_ptr< FOOTPRINT > > &aFootprintMap, size_t aBoardIndex=0)
bool ParseMacroFile(const wxString &aFileName)
bool ParseBoard(const wxString &aFileName)
Handle a list of polygons defining a copper zone.
Definition zone.h:70
#define _(s)
void CollectFilesLoopSafe(const wxString &aRoot, wxArrayString &aFiles, const wxString &aFileSpec, int aFlags)
Recursively collect every file under aRoot, deduplicating subdirectories by their resolved path.
Definition gestfich.cpp:817
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
Describes how non-KiCad boards and schematics should be imported as KiCad projects.
std::vector< std::string > header
wxString result
Test unit parsing edge cases and error handling.