KiCad PCB EDA Suite
Loading...
Searching...
No Matches
altium_designer_plugin.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 (C) 2019 Thomas Pointhuber <[email protected]>
5 * Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
30#include <wx/string.h>
31
33#include <altium_pcb.h>
35
36#include <board.h>
37
38#include <compoundfilereader.h>
39#include <utf.h>
40
42{
43 m_board = nullptr;
44 m_props = nullptr;
45}
46
47
49{
50}
51
52
53bool ALTIUM_DESIGNER_PLUGIN::checkFileHeader( const wxString& aFileName )
54{
55 // Compound File Binary Format header
56 return fileStartsWithBinaryHeader( aFileName, { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1} );
57}
58
59
60bool ALTIUM_DESIGNER_PLUGIN::CanReadBoard( const wxString& aFileName ) const
61{
62 if( !PLUGIN::CanReadBoard( aFileName ) )
63 return false;
64
65 return checkFileHeader( aFileName );
66}
67
68
69bool ALTIUM_DESIGNER_PLUGIN::CanReadFootprintLib( const wxString& aFileName ) const
70{
71 if( !PLUGIN::CanReadFootprintLib( aFileName ) )
72 return false;
73
74 return checkFileHeader( aFileName );
75}
76
77
78BOARD* ALTIUM_DESIGNER_PLUGIN::LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
79 const STRING_UTF8_MAP* aProperties, PROJECT* aProject,
80 PROGRESS_REPORTER* aProgressReporter )
81{
82 m_props = aProperties;
83
84 m_board = aAppendToMe ? aAppendToMe : new BOARD();
85
86 // Give the filename to the board if it's new
87 if( !aAppendToMe )
88 m_board->SetFileName( aFileName );
89
90 // clang-format off
91 const std::map<ALTIUM_PCB_DIR, std::string> mapping = {
92 { ALTIUM_PCB_DIR::FILE_HEADER, "FileHeader" },
93 { ALTIUM_PCB_DIR::ARCS6, "Arcs6" },
94 { ALTIUM_PCB_DIR::BOARD6, "Board6" },
95 { ALTIUM_PCB_DIR::BOARDREGIONS, "BoardRegions" },
96 { ALTIUM_PCB_DIR::CLASSES6, "Classes6" },
97 { ALTIUM_PCB_DIR::COMPONENTS6, "Components6" },
98 { ALTIUM_PCB_DIR::COMPONENTBODIES6, "ComponentBodies6" },
99 { ALTIUM_PCB_DIR::DIMENSIONS6, "Dimensions6" },
100 { ALTIUM_PCB_DIR::EXTENDPRIMITIVEINFORMATION, "ExtendedPrimitiveInformation" },
101 { ALTIUM_PCB_DIR::FILLS6, "Fills6" },
102 { ALTIUM_PCB_DIR::MODELS, "Models" },
103 { ALTIUM_PCB_DIR::NETS6, "Nets6" },
104 { ALTIUM_PCB_DIR::PADS6, "Pads6" },
105 { ALTIUM_PCB_DIR::POLYGONS6, "Polygons6" },
106 { ALTIUM_PCB_DIR::REGIONS6, "Regions6" },
107 { ALTIUM_PCB_DIR::RULES6, "Rules6" },
108 { ALTIUM_PCB_DIR::SHAPEBASEDREGIONS6, "ShapeBasedRegions6" },
109 { ALTIUM_PCB_DIR::TEXTS6, "Texts6" },
110 { ALTIUM_PCB_DIR::TRACKS6, "Tracks6" },
111 { ALTIUM_PCB_DIR::VIAS6, "Vias6" },
112 { ALTIUM_PCB_DIR::WIDESTRINGS6, "WideStrings6" }
113 };
114 // clang-format on
115
116 ALTIUM_COMPOUND_FILE altiumPcbFile( aFileName );
117
118 try
119 {
120 // Parse File
121 ALTIUM_PCB pcb( m_board, aProgressReporter );
122 pcb.Parse( altiumPcbFile, mapping );
123 }
124 catch( CFB::CFBException& exception )
125 {
126 THROW_IO_ERROR( exception.what() );
127 }
128
129 return m_board;
130}
131
132long long ALTIUM_DESIGNER_PLUGIN::GetLibraryTimestamp( const wxString& aLibraryPath ) const
133{
134 // File hasn't been loaded yet.
135 if( aLibraryPath.IsEmpty() )
136 {
137 return 0;
138 }
139
140 wxFileName fn( aLibraryPath );
141
142 if( fn.IsFileReadable() )
143 {
144 return fn.GetModificationTime().GetValue().GetValue();
145 }
146 else
147 {
148 return 0;
149 }
150}
151
152void ALTIUM_DESIGNER_PLUGIN::FootprintEnumerate( wxArrayString& aFootprintNames,
153 const wxString& aLibraryPath, bool aBestEfforts,
154 const STRING_UTF8_MAP* aProperties )
155{
156 ALTIUM_COMPOUND_FILE* altiumLibFile = nullptr;
157 auto it = m_fplibFiles.find( aLibraryPath );
158
159 if( it == m_fplibFiles.end() )
160 {
161 auto new_it = m_fplibFiles.emplace( aLibraryPath, std::make_unique<ALTIUM_COMPOUND_FILE>( aLibraryPath ) );
162 altiumLibFile = new_it.first->second.get();
163 }
164 else
165 {
166 altiumLibFile = it->second.get();
167 }
168
169 try
170 {
171 // Map code-page-dependent names to unicode names
172 std::map<wxString, wxString> patternMap = altiumLibFile->ListLibFootprints();
173
174 const std::vector<std::string> streamName = { "Library", "Data" };
175 const CFB::COMPOUND_FILE_ENTRY* libraryData = altiumLibFile->FindStream( streamName );
176
177 if( libraryData == nullptr )
178 {
180 wxString::Format( _( "File not found: '%s'." ), FormatPath( streamName ) ) );
181 }
182
183 ALTIUM_PARSER parser( *altiumLibFile, libraryData );
184
185 std::map<wxString, wxString> properties = parser.ReadProperties();
186
187 uint32_t numberOfFootprints = parser.Read<uint32_t>();
188 aFootprintNames.Alloc( numberOfFootprints );
189
190 for( size_t i = 0; i < numberOfFootprints; i++ )
191 {
193
194 wxScopedCharBuffer charBuffer = parser.ReadCharBuffer();
195 wxString fpPattern( charBuffer, wxConvISO8859_1 );
196
197 auto it = patternMap.find( fpPattern );
198 if( it != patternMap.end() )
199 {
200 aFootprintNames.Add( it->second ); // Proper unicode name
201 }
202 else
203 {
204 THROW_IO_ERROR( wxString::Format( "Component name not found: '%s'", fpPattern ) );
205 }
206
207 parser.SkipSubrecord();
208 }
209
210 if( parser.HasParsingError() )
211 {
212 THROW_IO_ERROR( wxString::Format( "%s stream was not parsed correctly",
213 FormatPath( streamName ) ) );
214 }
215
216 if( parser.GetRemainingBytes() != 0 )
217 {
219 wxString::Format( "%s stream is not fully parsed", FormatPath( streamName ) ) );
220 }
221 }
222 catch( CFB::CFBException& exception )
223 {
224 THROW_IO_ERROR( exception.what() );
225 }
226}
227
229 const wxString& aFootprintName, bool aKeepUUID,
230 const STRING_UTF8_MAP* aProperties )
231{
232 ALTIUM_COMPOUND_FILE* altiumLibFile = nullptr;
233 auto it = m_fplibFiles.find( aLibraryPath );
234
235 if( it == m_fplibFiles.end() )
236 {
237 auto new_it = m_fplibFiles.emplace( aLibraryPath, std::make_unique<ALTIUM_COMPOUND_FILE>( aLibraryPath ) );
238 altiumLibFile = new_it.first->second.get();
239 }
240 else
241 {
242 altiumLibFile = it->second.get();
243 }
244
245 try
246 {
247 // Parse File
248 ALTIUM_PCB pcb( m_board, nullptr );
249 return pcb.ParseFootprint( *altiumLibFile, aFootprintName );
250 }
251 catch( CFB::CFBException& exception )
252 {
253 THROW_IO_ERROR( exception.what() );
254 }
255}
std::string FormatPath(const std::vector< std::string > &aVectorPath)
Helper for debug logging (vector -> string)
std::map< wxString, wxString > ListLibFootprints()
const CFB::COMPOUND_FILE_ENTRY * FindStream(const std::vector< std::string > &aStreamPath) const
std::map< wxString, std::unique_ptr< ALTIUM_COMPOUND_FILE > > m_fplibFiles
FOOTPRINT * FootprintLoad(const wxString &aLibraryPath, const wxString &aFootprintName, bool aKeepUUID=false, const STRING_UTF8_MAP *aProperties=nullptr) override
Load a footprint having aFootprintName from the aLibraryPath containing a library format that this PL...
static bool checkFileHeader(const wxString &aFileName)
bool CanReadBoard(const wxString &aFileName) const override
Checks if this PLUGIN can read the specified board file.
bool CanReadFootprintLib(const wxString &aFileName) const override
Checks if this PLUGIN can read footprint library from specified file or directory.
BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const STRING_UTF8_MAP *aProperties, PROJECT *aProject=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr) override
Load information from some input file format that this PLUGIN implementation knows about into either ...
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, bool aBestEfforts, const STRING_UTF8_MAP *aProperties=nullptr) override
Return a list of footprint names contained within the library at aLibraryPath.
const STRING_UTF8_MAP * m_props
long long GetLibraryTimestamp(const wxString &aLibraryPath) const override
Generate a timestamp representing all the files in the library (including the library directory).
wxScopedCharBuffer ReadCharBuffer()
size_t GetRemainingBytes() const
bool HasParsingError()
std::map< wxString, wxString > ReadProperties(std::function< std::map< wxString, wxString >(const std::string &)> handleBinaryData=[](const std::string &) { return std::map< wxString, wxString >();})
size_t ReadAndSetSubrecordLength()
void SkipSubrecord()
void Parse(const ALTIUM_COMPOUND_FILE &aAltiumPcbFile, const std::map< ALTIUM_PCB_DIR, std::string > &aFileMapping)
Definition: altium_pcb.cpp:298
FOOTPRINT * ParseFootprint(ALTIUM_COMPOUND_FILE &altiumLibFile, const wxString &aFootprintName)
Definition: altium_pcb.cpp:607
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:271
void SetFileName(const wxString &aFileName)
Definition: board.h:306
virtual bool CanReadFootprintLib(const wxString &aFileName) const
Checks if this PLUGIN can read footprint library from specified file or directory.
Definition: plugin.cpp:96
virtual bool CanReadBoard(const wxString &aFileName) const
Checks if this PLUGIN can read the specified board file.
Definition: plugin.cpp:64
static bool fileStartsWithBinaryHeader(const wxString &aFilePath, const std::vector< uint8_t > &aHeader)
Definition: plugin.cpp:322
A progress reporter interface for use in multi-threaded environments.
Container for project specific data.
Definition: project.h:62
A name/value tuple with unique names and optional values.
#define _(s)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38