KiCad PCB EDA Suite
Loading...
Searching...
No Matches
altium_project_variants.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
21
22#include <boost/uuid/name_generator_sha1.hpp>
23#include <boost/uuid/string_generator.hpp>
24#include <boost/uuid/uuid_io.hpp>
25
26#include <wx/fileconf.h>
27#include <wx/filename.h>
28#include <wx/log.h>
29
30
36static wxString absoluteProjectPath( const wxString& aPrjPcbPath )
37{
38 wxFileName fn( aPrjPcbPath );
39 fn.MakeAbsolute();
40
41 return fn.GetFullPath();
42}
43
44
45KIID AltiumUniqueIdToKiid( const wxString& aUniqueId )
46{
47 // Fixed namespace so a given id always maps to the same KIID. Must never change or
48 // previously stamped footprint paths would stop matching.
49 static const boost::uuids::uuid s_namespace =
50 boost::uuids::string_generator()( "6f9619ff-8b86-d011-b42d-00cf4fc964ff" );
51
52 boost::uuids::name_generator_sha1 generator( s_namespace );
53 boost::uuids::uuid uuid = generator( aUniqueId.utf8_string() );
54
55 return KIID( wxString::FromUTF8( boost::uuids::to_string( uuid ) ) );
56}
57
58
60{
62
63 // AlternatePart is the last named field on the line; everything after it belongs to the
64 // alternate part definition rather than to the component itself
65 bool inAlternatePart = false;
66
67 // UniqueId targets are backslash-delimited paths, so wxSplit's default '\' escape would
68 // merge the field that follows one ending in a separator
69 for( const wxString& token : wxSplit( aValue, '|', '\0' ) )
70 {
71 int eqPos = token.Find( '=' );
72
73 if( eqPos == wxNOT_FOUND )
74 continue;
75
76 wxString key = token.Left( eqPos ).Trim().Trim( false );
77 wxString val = token.Mid( eqPos + 1 ).Trim().Trim( false );
78
79 if( key.CmpNoCase( wxS( "AlternatePart" ) ) == 0 )
80 {
81 inAlternatePart = true;
82
83 // Typically empty for Kind=1 and a library reference for Kind=0
84 if( !val.empty() )
85 entry.alternateFields[wxS( "LibReference" )] = val;
86 }
87 else if( inAlternatePart )
88 {
89 if( !val.empty() )
90 entry.alternateFields[key] = val;
91 }
92 else if( key.CmpNoCase( wxS( "Designator" ) ) == 0 )
93 {
94 entry.designator = val;
95 }
96 else if( key.CmpNoCase( wxS( "UniqueId" ) ) == 0 )
97 {
98 // The target is a backslash-delimited path; only the final segment is the
99 // component's own unique id, which is what symbol and footprint records store.
100 int sep = val.Find( '\\', true );
101
102 if( sep != wxNOT_FOUND )
103 entry.uniqueId = val.Mid( sep + 1 );
104 else
105 entry.uniqueId = val;
106 }
107 else if( key.CmpNoCase( wxS( "Kind" ) ) == 0 )
108 {
109 long k = 0;
110 val.ToLong( &k );
111 entry.kind = static_cast<int>( k );
112 }
113 }
114
115 return entry;
116}
117
118
119std::map<wxString, wxString> ParseAltiumProjectParameters( const wxString& aPrjPcbPath )
120{
121 std::map<wxString, wxString> parameters;
122
123 wxFileConfig config( wxEmptyString, wxEmptyString, wxEmptyString, absoluteProjectPath( aPrjPcbPath ),
124 wxCONFIG_USE_NO_ESCAPE_CHARACTERS );
125
126 wxString groupname;
127 long groupid;
128
129 for( bool more = config.GetFirstGroup( groupname, groupid ); more;
130 more = config.GetNextGroup( groupname, groupid ) )
131 {
132 if( !groupname.StartsWith( wxS( "Parameter" ) ) )
133 continue;
134
135 // Only numbered [ParameterN] sections hold the project parameters; reject look-alikes
136 // such as [ParameterEngine] by requiring a trailing integer.
137 wxString numStr = groupname.Mid( 9 );
138 long num;
139
140 if( !numStr.ToLong( &num ) )
141 continue;
142
143 wxString name = config.Read( groupname + wxS( "/Name" ), wxEmptyString );
144
145 if( name.empty() )
146 continue;
147
148 wxString value = config.Read( groupname + wxS( "/Value" ), wxEmptyString );
149
150 // KiCad variable references are matched case-insensitively by resolving to upper case,
151 // which is what AltiumPcbSpecialStringsToKiCadStrings emits, so key on the upper-cased
152 // name to keep ${PCB_REVISION} and friends resolvable.
153 name.UpperCase();
154
155 parameters[name] = value;
156 }
157
158 return parameters;
159}
160
161
162std::vector<ALTIUM_PROJECT_VARIANT> ParseAltiumProjectVariants( const wxString& aPrjPcbPath )
163{
164 std::vector<ALTIUM_PROJECT_VARIANT> variants;
165
166 wxFileConfig config( wxEmptyString, wxEmptyString, wxEmptyString, absoluteProjectPath( aPrjPcbPath ),
167 wxCONFIG_USE_NO_ESCAPE_CHARACTERS );
168
169 wxString groupname;
170 long groupid;
171
172 for( bool more = config.GetFirstGroup( groupname, groupid ); more;
173 more = config.GetNextGroup( groupname, groupid ) )
174 {
175 if( !groupname.StartsWith( wxS( "ProjectVariant" ) ) )
176 continue;
177
178 wxString numStr = groupname.Mid( 14 );
179 long num;
180
181 if( !numStr.ToLong( &num ) )
182 continue;
183
185
186 pv.description = config.Read( groupname + wxS( "/Description" ), wxEmptyString );
187 pv.name = pv.description;
188
189 if( pv.name.empty() )
190 pv.name = groupname;
191
192 long variationCount = 0;
193 config.Read( groupname + wxS( "/VariationCount" ), &variationCount, 0 );
194
195 for( long vi = 1; vi <= variationCount; ++vi )
196 {
197 wxString key = wxString::Format( wxS( "%s/Variation%ld" ), groupname, vi );
198 wxString value = config.Read( key, wxEmptyString );
199
200 if( value.empty() )
201 continue;
202
204
205 if( !entry.designator.empty() )
206 pv.variations.push_back( std::move( entry ) );
207 }
208
209 if( !pv.variations.empty() )
210 variants.push_back( std::move( pv ) );
211 }
212
213 return variants;
214}
const char * name
std::vector< ALTIUM_PROJECT_VARIANT > ParseAltiumProjectVariants(const wxString &aPrjPcbPath)
Parse all [ProjectVariantN] sections from an Altium .PrjPcb project file.
static wxString absoluteProjectPath(const wxString &aPrjPcbPath)
wxFileConfig resolves a relative local filename against the user's home directory rather than the wor...
std::map< wxString, wxString > ParseAltiumProjectParameters(const wxString &aPrjPcbPath)
Parse all [ParameterN] sections from an Altium .PrjPcb project file.
ALTIUM_VARIANT_ENTRY ParseVariationString(const wxString &aValue)
Parse a single pipe-delimited Altium "Variation" string into its component entry.
KIID AltiumUniqueIdToKiid(const wxString &aUniqueId)
Derive a stable KIID from an Altium component unique id.
Definition kiid.h:46
A project-level assembly variant parsed from an Altium .PrjPcb file.
std::vector< ALTIUM_VARIANT_ENTRY > variations
A single component variation within an Altium project variant.
int kind
wxString uniqueId
wxString designator
std::map< wxString, wxString > alternateFields