KiCad PCB EDA Suite
Loading...
Searching...
No Matches
altium_parser_pcb.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) 2020 Thomas Pointhuber <[email protected]>
5 * Copyright The 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
25#include <map>
26#include <unordered_map>
27
28#include <ki_exception.h>
29#include <math/util.h>
30
31#include <wx/log.h>
32#include <wx/translation.h>
33
34#include "altium_parser_pcb.h"
37
38
46static const wxChar* traceAltiumImport = wxT( "KICAD_ALTIUM_IMPORT" );
47
48
49/*
50 * Returns an Altium layer id from V6 and V7 file format data, compatible with the rest of the parser.
51 */
53{
55 return aV7Layer;
56
57 return aV6Layer;
58}
59
60
61/*
62 * Returns V7 layer ids for Mechanical 17 and above. Otherwise, V6 layer ids.
63 */
64ALTIUM_LAYER altium_layer_from_name( const wxString& aName )
65{
66 if( aName.IsEmpty() )
68
69 static const std::unordered_map<std::string, ALTIUM_LAYER> hash_map = {
70 { "TOP", ALTIUM_LAYER::TOP_LAYER },
71 { "MID1", ALTIUM_LAYER::MID_LAYER_1 },
72 { "MID2", ALTIUM_LAYER::MID_LAYER_2 },
73 { "MID3", ALTIUM_LAYER::MID_LAYER_3 },
74 { "MID4", ALTIUM_LAYER::MID_LAYER_4 },
75 { "MID5", ALTIUM_LAYER::MID_LAYER_5 },
76 { "MID6", ALTIUM_LAYER::MID_LAYER_6 },
77 { "MID7", ALTIUM_LAYER::MID_LAYER_7 },
78 { "MID8", ALTIUM_LAYER::MID_LAYER_8 },
79 { "MID9", ALTIUM_LAYER::MID_LAYER_9 },
80 { "MID10", ALTIUM_LAYER::MID_LAYER_10 },
81 { "MID11", ALTIUM_LAYER::MID_LAYER_11 },
82 { "MID12", ALTIUM_LAYER::MID_LAYER_12 },
83 { "MID13", ALTIUM_LAYER::MID_LAYER_13 },
84 { "MID14", ALTIUM_LAYER::MID_LAYER_14 },
85 { "MID15", ALTIUM_LAYER::MID_LAYER_15 },
86 { "MID16", ALTIUM_LAYER::MID_LAYER_16 },
87 { "MID17", ALTIUM_LAYER::MID_LAYER_17 },
88 { "MID18", ALTIUM_LAYER::MID_LAYER_18 },
89 { "MID19", ALTIUM_LAYER::MID_LAYER_19 },
90 { "MID20", ALTIUM_LAYER::MID_LAYER_20 },
91 { "MID21", ALTIUM_LAYER::MID_LAYER_21 },
92 { "MID22", ALTIUM_LAYER::MID_LAYER_22 },
93 { "MID23", ALTIUM_LAYER::MID_LAYER_23 },
94 { "MID24", ALTIUM_LAYER::MID_LAYER_24 },
95 { "MID25", ALTIUM_LAYER::MID_LAYER_25 },
96 { "MID26", ALTIUM_LAYER::MID_LAYER_26 },
97 { "MID27", ALTIUM_LAYER::MID_LAYER_27 },
98 { "MID28", ALTIUM_LAYER::MID_LAYER_28 },
99 { "MID29", ALTIUM_LAYER::MID_LAYER_29 },
100 { "MID30", ALTIUM_LAYER::MID_LAYER_30 },
101 { "BOTTOM", ALTIUM_LAYER::BOTTOM_LAYER },
102
103 { "TOPOVERLAY", ALTIUM_LAYER::TOP_OVERLAY },
104 { "BOTTOMOVERLAY", ALTIUM_LAYER::BOTTOM_OVERLAY },
105 { "TOPPASTE", ALTIUM_LAYER::TOP_PASTE },
106 { "BOTTOMPASTE", ALTIUM_LAYER::BOTTOM_PASTE },
107 { "TOPSOLDER", ALTIUM_LAYER::TOP_SOLDER },
108 { "BOTTOMSOLDER", ALTIUM_LAYER::BOTTOM_SOLDER },
109
110 { "PLANE1", ALTIUM_LAYER::INTERNAL_PLANE_1 },
111 { "PLANE2", ALTIUM_LAYER::INTERNAL_PLANE_2 },
112 { "PLANE3", ALTIUM_LAYER::INTERNAL_PLANE_3 },
113 { "PLANE4", ALTIUM_LAYER::INTERNAL_PLANE_4 },
114 { "PLANE5", ALTIUM_LAYER::INTERNAL_PLANE_5 },
115 { "PLANE6", ALTIUM_LAYER::INTERNAL_PLANE_6 },
116 { "PLANE7", ALTIUM_LAYER::INTERNAL_PLANE_7 },
117 { "PLANE8", ALTIUM_LAYER::INTERNAL_PLANE_8 },
118 { "PLANE9", ALTIUM_LAYER::INTERNAL_PLANE_9 },
119 { "PLANE10", ALTIUM_LAYER::INTERNAL_PLANE_10 },
120 { "PLANE11", ALTIUM_LAYER::INTERNAL_PLANE_11 },
121 { "PLANE12", ALTIUM_LAYER::INTERNAL_PLANE_12 },
122 { "PLANE13", ALTIUM_LAYER::INTERNAL_PLANE_13 },
123 { "PLANE14", ALTIUM_LAYER::INTERNAL_PLANE_14 },
124 { "PLANE15", ALTIUM_LAYER::INTERNAL_PLANE_15 },
125 { "PLANE16", ALTIUM_LAYER::INTERNAL_PLANE_16 },
126
127 { "DRILLGUIDE", ALTIUM_LAYER::DRILL_GUIDE },
128 { "KEEPOUT", ALTIUM_LAYER::KEEP_OUT_LAYER },
129
130 { "MECHANICAL1", ALTIUM_LAYER::MECHANICAL_1 },
131 { "MECHANICAL2", ALTIUM_LAYER::MECHANICAL_2 },
132 { "MECHANICAL3", ALTIUM_LAYER::MECHANICAL_3 },
133 { "MECHANICAL4", ALTIUM_LAYER::MECHANICAL_4 },
134 { "MECHANICAL5", ALTIUM_LAYER::MECHANICAL_5 },
135 { "MECHANICAL6", ALTIUM_LAYER::MECHANICAL_6 },
136 { "MECHANICAL7", ALTIUM_LAYER::MECHANICAL_7 },
137 { "MECHANICAL8", ALTIUM_LAYER::MECHANICAL_8 },
138 { "MECHANICAL9", ALTIUM_LAYER::MECHANICAL_9 },
139 { "MECHANICAL10", ALTIUM_LAYER::MECHANICAL_10 },
140 { "MECHANICAL11", ALTIUM_LAYER::MECHANICAL_11 },
141 { "MECHANICAL12", ALTIUM_LAYER::MECHANICAL_12 },
142 { "MECHANICAL13", ALTIUM_LAYER::MECHANICAL_13 },
143 { "MECHANICAL14", ALTIUM_LAYER::MECHANICAL_14 },
144 { "MECHANICAL15", ALTIUM_LAYER::MECHANICAL_15 },
145 { "MECHANICAL16", ALTIUM_LAYER::MECHANICAL_16 },
146
147 { "DRILLDRAWING", ALTIUM_LAYER::DRILL_DRAWING },
148 { "MULTILAYER", ALTIUM_LAYER::MULTI_LAYER },
149
150 // FIXME: the following mapping is just a guess
151 { "CONNECTIONS", ALTIUM_LAYER::CONNECTIONS },
152 { "BACKGROUND", ALTIUM_LAYER::BACKGROUND },
153 { "DRCERRORMARKERS", ALTIUM_LAYER::DRC_ERROR_MARKERS },
154 { "SELECTIONS", ALTIUM_LAYER::SELECTIONS },
155 { "VISIBLEGRID1", ALTIUM_LAYER::VISIBLE_GRID_1 },
156 { "VISIBLEGRID2", ALTIUM_LAYER::VISIBLE_GRID_2 },
157 { "PADHOLES", ALTIUM_LAYER::PAD_HOLES },
158 { "VIAHOLES", ALTIUM_LAYER::VIA_HOLES },
159 };
160
161 auto it = hash_map.find( std::string( aName.c_str() ) );
162
163 if( it != hash_map.end() )
164 return it->second;
165
166 // Try V7 format mechanical layers
167 const wxString mechanicalStr( "MECHANICAL" );
168
169 if( aName.StartsWith( mechanicalStr ) )
170 {
171 unsigned long val = 0;
172
173 if( aName.Mid( mechanicalStr.length() ).ToULong( &val ) )
174 return static_cast<ALTIUM_LAYER>( static_cast<int>( ALTIUM_LAYER::V7_MECHANICAL_BASE ) + val );
175 }
176
177 wxLogError( _( "Unknown mapping of the Altium layer '%s'." ), aName );
179}
180
181
183{
184 static const std::unordered_map<std::string, ALTIUM_MECHKIND> hash_map = {
185 { "AssemblyTop", ALTIUM_MECHKIND::ASSEMBLY_TOP },
186 { "AssemblyBottom", ALTIUM_MECHKIND::ASSEMBLY_BOT },
187
188 { "AssemblyNotes", ALTIUM_MECHKIND::ASSEMBLY_NOTES },
189 { "Board", ALTIUM_MECHKIND::BOARD },
190
191 { "CoatingTop", ALTIUM_MECHKIND::COATING_TOP },
192 { "CoatingBottom", ALTIUM_MECHKIND::COATING_BOT },
193
194 { "ComponentCenterTop", ALTIUM_MECHKIND::COMPONENT_CENTER_TOP },
195 { "ComponentCenterBottom", ALTIUM_MECHKIND::COMPONENT_CENTER_BOT },
196
197 { "ComponentOutlineTop", ALTIUM_MECHKIND::COMPONENT_OUTLINE_TOP },
198 { "ComponentOutlineBottom", ALTIUM_MECHKIND::COMPONENT_OUTLINE_BOT },
199
200 { "CourtyardTop", ALTIUM_MECHKIND::COURTYARD_TOP },
201 { "CourtyardBottom", ALTIUM_MECHKIND::COURTYARD_BOT },
202
203 { "DesignatorTop", ALTIUM_MECHKIND::DESIGNATOR_TOP },
204 { "DesignatorBottom", ALTIUM_MECHKIND::DESIGNATOR_BOT },
205
206 { "Dimensions", ALTIUM_MECHKIND::DIMENSIONS },
207 { "DimensionsTop", ALTIUM_MECHKIND::DIMENSIONS_TOP },
208 { "DimensionsBottom", ALTIUM_MECHKIND::DIMENSIONS_BOT },
209
210 { "FabNotes", ALTIUM_MECHKIND::FAB_NOTES },
211
212 { "GluePointsTop", ALTIUM_MECHKIND::GLUE_POINTS_TOP },
213 { "GluePointsBottom", ALTIUM_MECHKIND::GLUE_POINTS_BOT },
214
215 { "GoldPlatingTop", ALTIUM_MECHKIND::GOLD_PLATING_TOP },
216 { "GoldPlatingBottom", ALTIUM_MECHKIND::GOLD_PLATING_BOT },
217
218 { "ValueTop", ALTIUM_MECHKIND::VALUE_TOP },
219 { "ValueBottom", ALTIUM_MECHKIND::VALUE_BOT },
220
221 { "VCut", ALTIUM_MECHKIND::V_CUT },
222
223 { "3DBodyTop", ALTIUM_MECHKIND::BODY_3D_TOP },
224 { "3DBodyBottom", ALTIUM_MECHKIND::BODY_3D_BOT },
225
226 { "RouteToolPath", ALTIUM_MECHKIND::ROUTE_TOOL_PATH },
227 { "Sheet", ALTIUM_MECHKIND::SHEET },
228 { "BoardShape", ALTIUM_MECHKIND::BOARD_SHAPE },
229 };
230
231 auto it = hash_map.find( std::string( aName.c_str() ) );
232
233 if( it != hash_map.end() )
234 {
235 return it->second;
236 }
237 else
238 {
239 wxLogError( _( "Unknown mapping of the Altium layer kind '%s'." ), aName );
241 }
242}
243
244
245void altium_parse_polygons( std::map<wxString, wxString>& aProps,
246 std::vector<ALTIUM_VERTICE>& aVertices )
247{
248 for( size_t i = 0; i < std::numeric_limits<size_t>::max(); i++ )
249 {
250 const wxString si = std::to_string( i );
251
252 const wxString vxi = wxT( "VX" ) + si;
253 const wxString vyi = wxT( "VY" ) + si;
254
255 if( aProps.find( vxi ) == aProps.end() || aProps.find( vyi ) == aProps.end() )
256 break; // it doesn't seem like we know beforehand how many vertices are inside a polygon
257
258 const bool isRound = ALTIUM_PROPS_UTILS::ReadInt( aProps, wxT( "KIND" ) + si, 0 ) != 0;
259 const int32_t radius = ALTIUM_PROPS_UTILS::ReadKicadUnit( aProps, wxT( "R" ) + si, wxT( "0mil" ) );
260 const double sa = ALTIUM_PROPS_UTILS::ReadDouble( aProps, wxT( "SA" ) + si, 0. );
261 const double ea = ALTIUM_PROPS_UTILS::ReadDouble( aProps, wxT( "EA" ) + si, 0. );
262 const VECTOR2I vp = VECTOR2I( ALTIUM_PROPS_UTILS::ReadKicadUnit( aProps, vxi, wxT( "0mil" ) ),
263 -ALTIUM_PROPS_UTILS::ReadKicadUnit( aProps, vyi, wxT( "0mil" ) ) );
264 const VECTOR2I cp = VECTOR2I( ALTIUM_PROPS_UTILS::ReadKicadUnit( aProps, wxT( "CX" ) + si, wxT( "0mil" ) ),
265 -ALTIUM_PROPS_UTILS::ReadKicadUnit( aProps, wxT( "CY" ) + si, wxT( "0mil" ) ) );
266
267 aVertices.emplace_back( isRound, radius, sa, ea, vp, cp );
268 }
269}
270
271
272static ALTIUM_MODE ReadAltiumModeFromProperties( const std::map<wxString, wxString>& aProps,
273 wxString aKey )
274{
275 wxString mode = ALTIUM_PROPS_UTILS::ReadString( aProps, aKey, wxT( "" ) );
276
277 if( mode == wxT( "None" ) )
278 return ALTIUM_MODE::NONE;
279 else if( mode == wxT( "Rule" ) )
280 return ALTIUM_MODE::RULE;
281 else if( mode == wxT( "Manual" ) )
282 return ALTIUM_MODE::MANUAL;
283
284 wxLogError( _( "Unknown Mode string: '%s'." ), mode );
286}
287
288
289static ALTIUM_RECORD ReadAltiumRecordFromProperties( const std::map<wxString, wxString>& aProps,
290 wxString aKey )
291{
292 wxString record = ALTIUM_PROPS_UTILS::ReadString( aProps, aKey, wxT( "" ) );
293
294 if( record == wxT( "Arc" ) )
295 return ALTIUM_RECORD::ARC;
296 else if( record == wxT( "Pad" ) )
297 return ALTIUM_RECORD::PAD;
298 else if( record == wxT( "Via" ) )
299 return ALTIUM_RECORD::VIA;
300 else if( record == wxT( "Track" ) )
302 else if( record == wxT( "Text" ) )
303 return ALTIUM_RECORD::TEXT;
304 else if( record == wxT( "Fill" ) )
305 return ALTIUM_RECORD::FILL;
306 else if( record == wxT( "Region" ) ) // correct?
308 else if( record == wxT( "Model" ) )
310
311 wxLogError( _( "Unknown Record name string: '%s'." ), record );
313}
314
315
318 const std::map<wxString, wxString>& aProps, wxString aKey )
319{
320 wxString parsedType = ALTIUM_PROPS_UTILS::ReadString( aProps, aKey, wxT( "" ) );
321
322 if( parsedType == wxT( "Mask" ) )
324
325 wxLogError( _( "Unknown Extended Primitive Information type: '%s'." ), parsedType );
327}
328
329
338static void ExpectSubrecordLengthAtLeast( const std::string& aStreamType,
339 const std::string& aSubrecordName, size_t aExpectedLength,
340 size_t aActualLength )
341{
342 if( aActualLength < aExpectedLength )
343 {
344 THROW_IO_ERROR( wxString::Format( "%s stream %s has length %d, "
345 "which is unexpected (expected at least %d)",
346 aStreamType, aSubrecordName, aActualLength,
347 aExpectedLength ) );
348 }
349}
350
351
353{
354 const std::map<wxString, wxString> props = aReader.ReadProperties();
355
356 if( props.empty() )
357 THROW_IO_ERROR( wxT( "ExtendedPrimitiveInformation stream has no properties!" ) );
358
359 primitiveIndex = ALTIUM_PROPS_UTILS::ReadInt( props, wxT( "PRIMITIVEINDEX" ), -1 );
360 primitiveObjectId = ReadAltiumRecordFromProperties( props, wxT( "PRIMITIVEOBJECTID" ) );
362
363 pastemaskexpansionmode = ReadAltiumModeFromProperties( props, wxT( "PASTEMASKEXPANSIONMODE" ) );
365 props, wxT( "PASTEMASKEXPANSION_MANUAL" ), wxT( "0mil" ) );
367 ReadAltiumModeFromProperties( props, wxT( "SOLDERMASKEXPANSIONMODE" ) );
369 props, wxT( "SOLDERMASKEXPANSION_MANUAL" ), wxT( "0mil" ) );
370}
371
372
373ABOARD6_LAYER_STACKUP::ABOARD6_LAYER_STACKUP( const std::map<wxString, wxString>& aProps, const wxString& aPrefix,
374 uint32_t aLayerIdFallback )
375{
376 // LAYERID is specific to V7 format
377 layerId = ALTIUM_PROPS_UTILS::ReadInt( aProps, aPrefix + wxT( "LAYERID" ), aLayerIdFallback );
378
379 name = ALTIUM_PROPS_UTILS::ReadString( aProps, aPrefix + wxT( "NAME" ), wxT( "" ) );
380 nextId = ALTIUM_PROPS_UTILS::ReadInt( aProps, aPrefix + wxT( "NEXT" ), 0 );
381 prevId = ALTIUM_PROPS_UTILS::ReadInt( aProps, aPrefix + wxT( "PREV" ), 0 );
382 copperthick = ALTIUM_PROPS_UTILS::ReadKicadUnit( aProps, aPrefix + wxT( "COPTHICK" ), wxT( "1.4mil" ) );
383
384 dielectricconst = ALTIUM_PROPS_UTILS::ReadDouble( aProps, aPrefix + wxT( "DIELCONST" ), 0. );
385 dielectricthick = ALTIUM_PROPS_UTILS::ReadKicadUnit( aProps, aPrefix + wxT( "DIELHEIGHT" ), wxT( "60mil" ) );
386 dielectricmaterial = ALTIUM_PROPS_UTILS::ReadString( aProps, aPrefix + wxT( "DIELMATERIAL" ), wxT( "FR-4" ) );
387
388 // TODO: In some component libraries MECHENABLED may be FALSE but the layers show up as used.
389 // (we should check if any objects exists on these layers?)
390 wxString mechEnabled = ALTIUM_PROPS_UTILS::ReadString( aProps, aPrefix + wxT( "MECHENABLED" ), wxT( "" ) );
391
392 mechenabled = !mechEnabled.Contains( wxS( "FALSE" ) );
393
394 if( mechenabled )
395 {
396 wxString mechKind = ALTIUM_PROPS_UTILS::ReadString( aProps, aPrefix + wxT( "MECHKIND" ), wxT( "" ) );
397
398 if( !mechKind.IsEmpty() )
400 }
401}
402
403
404static std::vector<ABOARD6_LAYER_STACKUP> ReadAltiumStackupFromProperties( const std::map<wxString, wxString>& aProps )
405{
406 std::vector<ABOARD6_LAYER_STACKUP> stackup;
407
408 for( size_t i = 1; i < std::numeric_limits<size_t>::max(); i++ )
409 {
410 const wxString layeri = wxString( wxT( "LAYER" ) ) << std::to_string( i );
411 const wxString layername = layeri + wxT( "NAME" );
412
413 auto layernameit = aProps.find( layername );
414
415 if( layernameit == aProps.end() )
416 break;
417
418 ABOARD6_LAYER_STACKUP l( aProps, layeri, i );
419 stackup.push_back( l );
420 }
421
422 // V7 format layers
423 for( size_t i = 0; i < std::numeric_limits<size_t>::max(); i++ )
424 {
425 const wxString layeri = wxString( wxT( "LAYERV7_" ) ) << std::to_string( i );
426 const wxString layername = layeri + wxT( "NAME" );
427
428 auto layernameit = aProps.find( layername );
429
430 if( layernameit == aProps.end() )
431 break;
432
433 ABOARD6_LAYER_STACKUP l( aProps, layeri, 0 );
434 stackup.push_back( l );
435 }
436
437 return stackup;
438}
439
440
442{
443 std::map<wxString, wxString> props = aReader.ReadProperties();
444
445 if( props.empty() )
446 THROW_IO_ERROR( wxT( "Library stream has no properties!" ) );
447
448 layercount = ALTIUM_PROPS_UTILS::ReadInt( props, wxT( "LAYERSETSCOUNT" ), 1 ) + 1;
449
451
453 {
454 wxString originalName = l.name;
455
456 // Ensure that layer names are unique in KiCad
457 for( int ii = 2; !layerNames.insert( l.name ).second; ii++ )
458 l.name = wxString::Format( wxT( "%s %d" ), originalName, ii );
459 }
460
461 if( aReader.HasParsingError() )
462 THROW_IO_ERROR( wxT( "Library stream was not parsed correctly!" ) );
463}
464
465
467{
468 std::map<wxString, wxString> props = aReader.ReadProperties();
469
470 if( props.empty() )
471 THROW_IO_ERROR( wxT( "Board6 stream has no properties!" ) );
472
473 sheetpos = VECTOR2I( ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "SHEETX" ), wxT( "0mil" ) ),
474 -ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "SHEETY" ), wxT( "0mil" ) ) );
475 sheetsize = wxSize( ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "SHEETWIDTH" ), wxT( "0mil" ) ),
476 ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "SHEETHEIGHT" ), wxT( "0mil" ) ) );
477
478 layercount = ALTIUM_PROPS_UTILS::ReadInt( props, wxT( "LAYERSETSCOUNT" ), 1 ) + 1;
479
481
483 {
484 wxString originalName = l.name;
485
486 // Ensure that layer names are unique in KiCad
487 for( int ii = 2; !layerNames.insert( l.name ).second; ii++ )
488 l.name = wxString::Format( wxT( "%s %d" ), originalName, ii );
489 }
490
492
493 if( aReader.HasParsingError() )
494 THROW_IO_ERROR( wxT( "Board6 stream was not parsed correctly!" ) );
495}
496
498{
499 std::map<wxString, wxString> properties = aReader.ReadProperties();
500
501 if( properties.empty() )
502 THROW_IO_ERROR( wxT( "Classes6 stream has no properties!" ) );
503
504 name = ALTIUM_PROPS_UTILS::ReadString( properties, wxT( "NAME" ), wxT( "" ) );
505 uniqueid = ALTIUM_PROPS_UTILS::ReadString( properties, wxT( "UNIQUEID" ), wxT( "" ) );
506 kind = static_cast<ALTIUM_CLASS_KIND>( ALTIUM_PROPS_UTILS::ReadInt( properties, wxT( "KIND" ), -1 ) );
507
508 for( size_t i = 0; i < std::numeric_limits<size_t>::max(); i++ )
509 {
510 auto mit = properties.find( wxT( "M" ) + wxString( std::to_string( i ) ) );
511
512 if( mit == properties.end() )
513 break; // it doesn't seem like we know beforehand how many components are in the netclass
514
515 names.push_back( mit->second );
516 }
517
518 if( aReader.HasParsingError() )
519 THROW_IO_ERROR( wxT( "Classes6 stream was not parsed correctly" ) );
520}
521
523{
524 std::map<wxString, wxString> props = aReader.ReadProperties();
525
526 if( props.empty() )
527 THROW_IO_ERROR( wxT( "Components6 stream has no props" ) );
528
529 layer = altium_layer_from_name( ALTIUM_PROPS_UTILS::ReadString( props, wxT( "LAYER" ), wxT( "" ) ) );
530 position = VECTOR2I( ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "X" ), wxT( "0mil" ) ),
531 -ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "Y" ), wxT( "0mil" ) ) );
532 rotation = ALTIUM_PROPS_UTILS::ReadDouble( props, wxT( "ROTATION" ), 0. );
533 locked = ALTIUM_PROPS_UTILS::ReadBool( props, wxT( "LOCKED" ), false );
534 nameon = ALTIUM_PROPS_UTILS::ReadBool( props, wxT( "NAMEON" ), true );
535 commenton = ALTIUM_PROPS_UTILS::ReadBool( props, wxT( "COMMENTON" ), false );
536 sourcedesignator = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "SOURCEDESIGNATOR" ), wxT( "" ) );
537
538 sourceUniqueID = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "SOURCEUNIQUEID" ), wxT( "" ) );
539
540 // Remove leading backslash from sourceUniqueID to match schematic component unique IDs
541 if( sourceUniqueID.starts_with( wxT( "\\" ) ) )
543
544 sourceHierachicalPath = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "SOURCEHIERARCHICALPATH" ), wxT( "" ) );
546 ALTIUM_PROPS_UTILS::ReadUnicodeString( props, wxT( "SOURCEFOOTPRINTLIBRARY" ), wxT( "" ) );
547 pattern = ALTIUM_PROPS_UTILS::ReadUnicodeString( props, wxT( "PATTERN" ), wxT( "" ) );
548
549 sourcecomponentlibrary = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "SOURCECOMPONENTLIBRARY" ), wxT( "" ) );
550 sourcelibreference = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "SOURCELIBREFERENCE" ), wxT( "" ) );
551
553 ALTIUM_PROPS_UTILS::ReadInt( props, wxT( "NAMEAUTOPOSITION" ), 0 ) );
555 ALTIUM_PROPS_UTILS::ReadInt( props, wxT( "COMMENTAUTOPOSITION" ), 0 ) );
556
557 if( aReader.HasParsingError() )
558 THROW_IO_ERROR( wxT( "Components6 stream was not parsed correctly" ) );
559}
560
562{
563 aReader.Skip( 2 );
564
565 std::map<wxString, wxString> props = aReader.ReadProperties();
566
567 if( props.empty() )
568 THROW_IO_ERROR( wxT( "Dimensions6 stream has no props" ) );
569
570 layer_v6 = altium_layer_from_name( ALTIUM_PROPS_UTILS::ReadString( props, wxT( "LAYER" ), wxT( "" ) ) );
571 layer_v7 = altium_layer_from_name( ALTIUM_PROPS_UTILS::ReadString( props, wxT( "LAYER_V7" ), wxT( "" ) ) );
572 kind = static_cast<ALTIUM_DIMENSION_KIND>( ALTIUM_PROPS_UTILS::ReadInt( props, wxT( "DIMENSIONKIND" ), 0 ) );
573
574 textformat = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "TEXTFORMAT" ), wxT( "" ) );
575 textprefix = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "TEXTPREFIX" ), wxT( "" ) );
576 textsuffix = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "TEXTSUFFIX" ), wxT( "" ) );
577
578 height = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "HEIGHT" ), wxT( "0mil" ) );
579 angle = ALTIUM_PROPS_UTILS::ReadDouble( props, wxT( "ANGLE" ), 0. );
580
581 linewidth = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "LINEWIDTH" ), wxT( "10mil" ) );
582 textheight = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "TEXTHEIGHT" ), wxT( "10mil" ) );
583 textlinewidth = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "TEXTLINEWIDTH" ), wxT( "6mil" ) );
584 textprecision = ALTIUM_PROPS_UTILS::ReadInt( props, wxT( "TEXTPRECISION" ), 2 );
585 textbold = ALTIUM_PROPS_UTILS::ReadBool( props, wxT( "TEXTLINEWIDTH" ), false );
586 textitalic = ALTIUM_PROPS_UTILS::ReadBool( props, wxT( "ITALIC" ), false );
587 textgap = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "TEXTGAP" ), wxT( "10mil" ) );
588
589 arrowsize = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "ARROWSIZE" ), wxT( "60mil" ) );
590
591 wxString text_position_raw = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "TEXTPOSITION" ), wxT( "" ) );
592
593 xy1 = VECTOR2I( ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "X1" ), wxT( "0mil" ) ),
594 -ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "Y1" ), wxT( "0mil" ) ) );
595
596 int refcount = ALTIUM_PROPS_UTILS::ReadInt( props, wxT( "REFERENCES_COUNT" ), 0 );
597
598 for( int i = 0; i < refcount; i++ )
599 {
600 const std::string refi = "REFERENCE" + std::to_string( i ) + "POINT";
601 const wxString ref( refi );
602 referencePoint.emplace_back( ALTIUM_PROPS_UTILS::ReadKicadUnit( props, ref + wxT( "X" ), wxT( "0mil" ) ),
603 -ALTIUM_PROPS_UTILS::ReadKicadUnit( props, ref + wxT( "Y" ), wxT( "0mil" ) ) );
604 }
605
606 for( size_t i = 1; i < std::numeric_limits<size_t>::max(); i++ )
607 {
608 const std::string texti = "TEXT" + std::to_string( i );
609 const std::string textix = texti + "X";
610 const std::string textiy = texti + "Y";
611
612 if( props.find( textix ) == props.end() || props.find( textiy ) == props.end() )
613 break; // it doesn't seem like we know beforehand how many vertices are inside a polygon
614
615 textPoint.emplace_back( ALTIUM_PROPS_UTILS::ReadKicadUnit( props, textix, wxT( "0mil" ) ),
616 -ALTIUM_PROPS_UTILS::ReadKicadUnit( props, textiy, wxT( "0mil" ) ) );
617 }
618
619 wxString dimensionunit = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "TEXTDIMENSIONUNIT" ), wxT( "Millimeters" ) );
620
621 if( dimensionunit == wxT( "Inches" ) ) textunit = ALTIUM_UNIT::INCH;
622 else if( dimensionunit == wxT( "Mils" ) ) textunit = ALTIUM_UNIT::MILS;
623 else if( dimensionunit == wxT( "Millimeters" ) ) textunit = ALTIUM_UNIT::MM;
624 else if( dimensionunit == wxT( "Centimeters" ) ) textunit = ALTIUM_UNIT::CM;
626
628
629 if( aReader.HasParsingError() )
630 THROW_IO_ERROR( wxT( "Dimensions6 stream was not parsed correctly" ) );
631}
632
634{
635 std::map<wxString, wxString> properties = aReader.ReadProperties();
636
637 if( properties.empty() )
638 THROW_IO_ERROR( wxT( "Model stream has no properties!" ) );
639
640 name = ALTIUM_PROPS_UTILS::ReadString( properties, wxT( "NAME" ), wxT( "" ) );
641 id = ALTIUM_PROPS_UTILS::ReadString( properties, wxT( "ID" ), wxT( "" ) );
642 isEmbedded = ALTIUM_PROPS_UTILS::ReadBool( properties, wxT( "EMBED" ), false );
643
644 rotation.x = ALTIUM_PROPS_UTILS::ReadDouble( properties, wxT( "ROTX" ), 0. );
645 rotation.y = ALTIUM_PROPS_UTILS::ReadDouble( properties, wxT( "ROTY" ), 0. );
646 rotation.z = ALTIUM_PROPS_UTILS::ReadDouble( properties, wxT( "ROTZ" ), 0. );
647
648 z_offset = ALTIUM_PROPS_UTILS::ReadDouble( properties, wxT( "DZ" ), 0. );
649 checksum = ALTIUM_PROPS_UTILS::ReadInt( properties, wxT( "CHECKSUM" ), 0 );
650
651 if( aReader.HasParsingError() )
652 THROW_IO_ERROR( wxT( "Model stream was not parsed correctly" ) );
653}
654
656{
657 std::map<wxString, wxString> properties = aReader.ReadProperties();
658
659 if( properties.empty() )
660 THROW_IO_ERROR( wxT( "Nets6 stream has no properties" ) );
661
662 name = ALTIUM_PROPS_UTILS::ReadString( properties, wxT( "NAME" ), wxT( "" ) );
663
664 if( aReader.HasParsingError() )
665 THROW_IO_ERROR( wxT( "Nets6 stream was not parsed correctly" ) );
666}
667
669{
670 std::map<wxString, wxString> properties = aReader.ReadProperties();
671
672 if( properties.empty() )
673 THROW_IO_ERROR( wxT( "Polygons6 stream has no properties" ) );
674
675 layer_v6 = altium_layer_from_name( ALTIUM_PROPS_UTILS::ReadString( properties, wxT( "LAYER" ), wxT( "" ) ) );
676 layer_v7 = altium_layer_from_name( ALTIUM_PROPS_UTILS::ReadString( properties, wxT( "LAYER_V7" ), wxT( "" ) ) );
677 net = ALTIUM_PROPS_UTILS::ReadInt( properties, wxT( "NET" ), ALTIUM_NET_UNCONNECTED );
678 locked = ALTIUM_PROPS_UTILS::ReadBool( properties, wxT( "LOCKED" ), false );
679
680 // TODO: kind
681
682 gridsize = ALTIUM_PROPS_UTILS::ReadKicadUnit( properties, wxT( "GRIDSIZE" ), wxT( "0mil" ) );
683 trackwidth = ALTIUM_PROPS_UTILS::ReadKicadUnit( properties, wxT( "TRACKWIDTH" ), wxT( "0mil" ) );
684 minprimlength = ALTIUM_PROPS_UTILS::ReadKicadUnit( properties, wxT( "MINPRIMLENGTH" ), wxT( "0mil" ) );
685 useoctagons = ALTIUM_PROPS_UTILS::ReadBool( properties, wxT( "USEOCTAGONS" ), false );
686
687 pourindex = ALTIUM_PROPS_UTILS::ReadInt( properties, wxT( "POURINDEX" ), 0 );
688
689 wxString hatchstyleraw = ALTIUM_PROPS_UTILS::ReadString( properties, wxT( "HATCHSTYLE" ), wxT( "" ) );
690
691 if( hatchstyleraw == wxT( "Solid" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::SOLID;
692 else if( hatchstyleraw == wxT( "45Degree" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::DEGREE_45;
693 else if( hatchstyleraw == wxT( "90Degree" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::DEGREE_90;
694 else if( hatchstyleraw == wxT( "Horizontal" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::HORIZONTAL;
695 else if( hatchstyleraw == wxT( "Vertical" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::VERTICAL;
696 else if( hatchstyleraw == wxT( "None" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::NONE;
698
699 altium_parse_polygons( properties, vertices );
700
702
703 if( aReader.HasParsingError() )
704 THROW_IO_ERROR( wxT( "Polygons6 stream was not parsed correctly" ) );
705}
706
708{
709 aReader.Skip( 2 );
710
711 std::map<wxString, wxString> props = aReader.ReadProperties();
712
713 if( props.empty() )
714 THROW_IO_ERROR( wxT( "Rules6 stream has no props" ) );
715
716 name = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "NAME" ), wxT( "" ) );
717 priority = ALTIUM_PROPS_UTILS::ReadInt( props, wxT( "PRIORITY" ), 1 );
718
719 scope1expr = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "SCOPE1EXPRESSION" ), wxT( "" ) );
720 scope2expr = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "SCOPE2EXPRESSION" ), wxT( "" ) );
721
722 wxString rulekind = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "RULEKIND" ), wxT( "" ) );
723 if( rulekind == wxT( "Clearance" ) )
724 {
726 clearanceGap = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "GAP" ), wxT( "10mil" ) );
727 }
728 else if( rulekind == wxT( "DiffPairsRouting" ) )
729 {
731 }
732 else if( rulekind == wxT( "Height" ) )
733 {
735 }
736 else if( rulekind == wxT( "HoleSize" ) )
737 {
739 minLimit = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "MINLIMIT" ), wxT( "1mil" ) );
740 maxLimit = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "MAXLIMIT" ), wxT( "150mil" ) );
741 }
742 else if( rulekind == wxT( "HoleToHoleClearance" ) )
743 {
745 clearanceGap = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "GAP" ), wxT( "10mil" ) );
746 }
747 else if( rulekind == wxT( "RoutingVias" ) )
748 {
750 width = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "WIDTH" ), wxT( "20mil" ) );
751 minWidth = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "MINWIDTH" ), wxT( "20mil" ) );
752 maxWidth = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "MAXWIDTH" ), wxT( "50mil" ) );
753 holeWidth = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "HOLEWIDTH" ), wxT( "10mil" ) );
754 minHoleWidth = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "MINHOLEWIDTH" ), wxT( "10mil" ) );
755 maxHoleWidth = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "MAXHOLEWIDTH" ), wxT( "28mil" ) );
756 }
757 else if( rulekind == wxT( "Width" ) )
758 {
760 minLimit = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "MINLIMIT" ), wxT( "6mil" ) );
761 maxLimit = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "MAXLIMIT" ), wxT( "40mil" ) );
762 preferredWidth = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "PREFERREDWIDTH" ), wxT( "6mil" ) );
763}
764 else if( rulekind == wxT( "PasteMaskExpansion" ) )
765 {
767 pastemaskExpansion = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "EXPANSION" ), wxT( "0" ) );
768 }
769 else if( rulekind == wxT( "SolderMaskExpansion" ) )
770 {
772 soldermaskExpansion = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "EXPANSION" ), wxT( "4mil" ) );
773 }
774 else if( rulekind == wxT( "PlaneClearance" ) )
775 {
777 planeclearanceClearance = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "CLEARANCE" ), wxT( "10mil" ) );
778 }
779 else if( rulekind == wxT( "PolygonConnect" ) )
780 {
782 polygonconnectAirgapwidth = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "AIRGAPWIDTH" ), wxT( "10mil" ) );
783 polygonconnectReliefconductorwidth = ALTIUM_PROPS_UTILS::ReadKicadUnit( props, wxT( "RELIEFCONDUCTORWIDTH" ), wxT( "10mil" ) );
784 polygonconnectReliefentries = ALTIUM_PROPS_UTILS::ReadInt( props, wxT( "RELIEFENTRIES" ), 4 );
785
786 wxString style = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "CONNECTSTYLE" ), wxT( "" ) );
787
788 if( style == wxT( "Direct" ) ) polygonconnectStyle = ALTIUM_CONNECT_STYLE::DIRECT;
789 else if( style == wxT( "Relief" ) ) polygonconnectStyle = ALTIUM_CONNECT_STYLE::RELIEF;
790 else if( style == wxT( "NoConnect" ) ) polygonconnectStyle = ALTIUM_CONNECT_STYLE::NONE;
792 }
793 else
794 {
796 }
797
798 if( aReader.HasParsingError() )
799 THROW_IO_ERROR( wxT( "Rules6 stream was not parsed correctly" ) );
800}
801
803{
804 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
805 if( recordtype != ALTIUM_RECORD::ARC )
806 {
807 THROW_IO_ERROR( wxT( "Arcs6 stream has invalid recordtype" ) );
808 }
809
810 // Subrecord 1
812
813 layer_v6 = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
814
815 uint8_t flags1 = aReader.Read<uint8_t>();
816 is_locked = ( flags1 & 0x04 ) == 0;
817 is_polygonoutline = ( flags1 & 0x02 ) != 0;
818
819 uint8_t flags2 = aReader.Read<uint8_t>();
820 is_keepout = flags2 == 2;
821
822 net = aReader.Read<uint16_t>();
823 polygon = aReader.Read<uint16_t>();
824 component = aReader.Read<uint16_t>();
825 aReader.Skip( 4 );
826 center = aReader.ReadVector2IPos();
827 radius = aReader.ReadKicadUnit();
828 startangle = aReader.Read<double>();
829 endangle = aReader.Read<double>();
830 width = aReader.ReadKicadUnit();
831 subpolyindex = aReader.Read<uint16_t>();
832
833 int remaining = aReader.GetRemainingSubrecordBytes();
834
835 if( remaining >= 9 )
836 {
837 aReader.Skip( 5 );
838 layer_v7 = static_cast<ALTIUM_LAYER>( aReader.Read<uint32_t>() );
839 }
840
841 if( remaining >= 10 )
842 keepoutrestrictions = aReader.Read<uint8_t>();
843 else
844 keepoutrestrictions = is_keepout ? 0x1F : 0;
845
847
848 aReader.SkipSubrecord();
849
850 if( aReader.HasParsingError() )
851 {
852 THROW_IO_ERROR( wxT( "Arcs6 stream was not parsed correctly" ) );
853 }
854}
855
857{
858 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
859
860 if( recordtype != ALTIUM_RECORD::MODEL )
861 THROW_IO_ERROR( wxT( "ComponentsBodies6 stream has invalid recordtype" ) );
862
864
865 aReader.Skip( 7 );
866 component = aReader.Read<uint16_t>();
867 aReader.Skip( 9 );
868
869 std::map<wxString, wxString> properties = aReader.ReadProperties();
870
871 if( properties.empty() )
872 THROW_IO_ERROR( wxT( "ComponentsBodies6 stream has no properties" ) );
873
874 modelName = ALTIUM_PROPS_UTILS::ReadString( properties, wxT( "MODEL.NAME" ), wxT( "" ) );
875 modelId = ALTIUM_PROPS_UTILS::ReadString( properties, wxT( "MODELID" ), wxT( "" ) );
876 modelIsEmbedded = ALTIUM_PROPS_UTILS::ReadBool( properties, wxT( "MODEL.EMBED" ), false );
877
878 modelPosition.x = ALTIUM_PROPS_UTILS::ReadKicadUnit( properties, wxT( "MODEL.2D.X" ), wxT( "0mil" ) );
879 modelPosition.y = -ALTIUM_PROPS_UTILS::ReadKicadUnit( properties, wxT( "MODEL.2D.Y" ), wxT( "0mil" ) );
880 modelPosition.z = ALTIUM_PROPS_UTILS::ReadKicadUnit( properties, wxT( "MODEL.3D.DZ" ), wxT( "0mil" ) );
881
882 modelRotation.x = ALTIUM_PROPS_UTILS::ReadDouble( properties, wxT( "MODEL.3D.ROTX" ), 0. );
883 modelRotation.y = ALTIUM_PROPS_UTILS::ReadDouble( properties, wxT( "MODEL.3D.ROTY" ), 0. );
884 modelRotation.z = ALTIUM_PROPS_UTILS::ReadDouble( properties, wxT( "MODEL.3D.ROTZ" ), 0. );
885
886 rotation = ALTIUM_PROPS_UTILS::ReadDouble( properties, wxT( "MODEL.2D.ROTATION" ), 0. );
887
888 body_opacity_3d = ALTIUM_PROPS_UTILS::ReadDouble( properties, wxT( "BODYOPACITY3D" ), 1. );
889 body_projection = ALTIUM_PROPS_UTILS::ReadInt( properties, wxT( "BODYPROJECTION" ), 0 );
890
891 aReader.SkipSubrecord();
892
893 if( aReader.HasParsingError() )
894 THROW_IO_ERROR( wxT( "Components6 stream was not parsed correctly" ) );
895}
896
898{
899 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
900
901 if( recordtype != ALTIUM_RECORD::PAD )
902 THROW_IO_ERROR( wxT( "Pads6 stream has invalid recordtype" ) );
903
904 // Subrecord 1
905 size_t subrecord1 = aReader.ReadAndSetSubrecordLength();
906
907 if( subrecord1 == 0 )
908 THROW_IO_ERROR( wxT( "Pads6 stream has no subrecord1 data" ) );
909
910 name = aReader.ReadWxString();
911
912 if( aReader.GetRemainingSubrecordBytes() != 0 )
913 THROW_IO_ERROR( wxT( "Pads6 stream has invalid subrecord1 length" ) );
914
915 aReader.SkipSubrecord();
916
917 // Subrecord 2
919 aReader.SkipSubrecord();
920
921 // Subrecord 3
923 aReader.SkipSubrecord();
924
925 // Subrecord 4
927 aReader.SkipSubrecord();
928
929 // Subrecord 5
930 size_t subrecord5 = aReader.ReadAndSetSubrecordLength();
931
932 ExpectSubrecordLengthAtLeast( "Pads6", "subrecord5", 110, subrecord5 );
933
934 layer_v6 = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
937
938 uint8_t flags1 = aReader.Read<uint8_t>();
939 is_test_fab_top = ( flags1 & 0x80 ) != 0;
940 is_tent_bottom = ( flags1 & 0x40 ) != 0;
941 is_tent_top = ( flags1 & 0x20 ) != 0;
942 is_locked = ( flags1 & 0x04 ) == 0;
943
944 uint8_t flags2 = aReader.Read<uint8_t>();
945 is_test_fab_bottom = ( flags2 & 0x01 ) != 0;
946
947 net = aReader.Read<uint16_t>();
948 aReader.Skip( 2 );
949 component = aReader.Read<uint16_t>();
950 aReader.Skip( 4 ); // to 13
951
952 position = aReader.ReadVector2IPos();
953 topsize = aReader.ReadVector2ISize();
954 midsize = aReader.ReadVector2ISize();
955 botsize = aReader.ReadVector2ISize();
956 holesize = aReader.ReadKicadUnit(); // to 49
957
958 topshape = static_cast<ALTIUM_PAD_SHAPE>( aReader.Read<uint8_t>() );
959 midshape = static_cast<ALTIUM_PAD_SHAPE>( aReader.Read<uint8_t>() );
960 botshape = static_cast<ALTIUM_PAD_SHAPE>( aReader.Read<uint8_t>() );
961
962 direction = aReader.Read<double>();
963 plated = aReader.Read<uint8_t>() != 0;
964 aReader.Skip( 1 );
965 padmode = static_cast<ALTIUM_PAD_MODE>( aReader.Read<uint8_t>() );
966 aReader.Skip( 23 );
969 aReader.Skip( 7 );
970 pastemaskexpansionmode = static_cast<ALTIUM_MODE>( aReader.Read<uint8_t>() );
971 soldermaskexpansionmode = static_cast<ALTIUM_MODE>( aReader.Read<uint8_t>() );
972 aReader.Skip( 3 ); // to 106
973
976
977 if( subrecord5 == 110 )
978 {
979 // Don't know exactly what this is, but it's always been 0 in the files with 110-byte subrecord5.
980 // e.g. https://gitlab.com/kicad/code/kicad/-/issues/16514
981 const uint32_t unknown = aReader.ReadKicadUnit(); // to 110
982
983 if( unknown != 0 )
984 {
985 THROW_IO_ERROR( wxString::Format( "Pads6 stream subrecord5 + 106 has value %d, which is unexpected",
986 unknown ) );
987 }
988 holerotation = 0;
989 }
990 else
991 {
992 // More than 110, need at least 114
993 ExpectSubrecordLengthAtLeast( "Pads6", "subrecord5", 114, subrecord5 );
994 holerotation = aReader.Read<double>(); // to 114
995 }
996
997 if( subrecord5 >= 120 )
998 {
999 tolayer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
1000 aReader.Skip( 2 );
1001 fromlayer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
1002 //aReader.skip( 2 );
1003 }
1004 else if( subrecord5 == 171 )
1005 {
1006 }
1007
1008 if( subrecord5 >= 202 )
1009 {
1010 aReader.Skip( 40 );
1011 pad_to_die_length = aReader.ReadKicadUnit();
1012 aReader.Skip( 32 );
1013 pad_to_die_delay = KiROUND( aReader.Read<double>() * 1e18 );
1014 }
1015
1016 aReader.SkipSubrecord();
1017
1018 // Subrecord 6
1019 size_t subrecord6 = aReader.ReadAndSetSubrecordLength();
1020 // Known lengths: 596, 628, 651
1021 // 596 is the number of bytes read in this code-block
1022 if( subrecord6 >= 596 )
1023 {
1024 sizeAndShape = std::make_unique<APAD6_SIZE_AND_SHAPE>();
1025
1026 for( wxSize& size : sizeAndShape->inner_size )
1027 size.x = aReader.ReadKicadUnitX();
1028
1029 for( wxSize& size : sizeAndShape->inner_size )
1030 size.y = aReader.ReadKicadUnitY();
1031
1032 for( ALTIUM_PAD_SHAPE& shape : sizeAndShape->inner_shape )
1033 shape = static_cast<ALTIUM_PAD_SHAPE>( aReader.Read<uint8_t>() );
1034
1035 aReader.Skip( 1 );
1036
1037 sizeAndShape->holeshape = static_cast<ALTIUM_PAD_HOLE_SHAPE>( aReader.Read<uint8_t>() );
1038 sizeAndShape->slotsize = aReader.ReadKicadUnit();
1039 sizeAndShape->slotrotation = aReader.Read<double>();
1040
1041 for( VECTOR2I& pt : sizeAndShape->holeoffset )
1042 pt.x = aReader.ReadKicadUnitX();
1043
1044 for( VECTOR2I& pt : sizeAndShape->holeoffset )
1045 pt.y = aReader.ReadKicadUnitY();
1046
1047 aReader.Skip( 1 );
1048
1049 for( ALTIUM_PAD_SHAPE_ALT& shape : sizeAndShape->alt_shape )
1050 shape = static_cast<ALTIUM_PAD_SHAPE_ALT>( aReader.Read<uint8_t>() );
1051
1052 for( uint8_t& radius : sizeAndShape->cornerradius )
1053 radius = aReader.Read<uint8_t>();
1054 }
1055 else if( subrecord6 != 0 )
1056 {
1057 wxLogError( _( "Pads6 stream has unexpected length for subrecord 6: %d." ), subrecord6 );
1058 }
1059
1061
1062 aReader.SkipSubrecord();
1063
1064 if( aReader.HasParsingError() )
1065 THROW_IO_ERROR( wxT( "Pads6 stream was not parsed correctly" ) );
1066}
1067
1069{
1070 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
1071
1072 if( recordtype != ALTIUM_RECORD::VIA )
1073 THROW_IO_ERROR( wxT( "Vias6 stream has invalid recordtype" ) );
1074
1075 // Subrecord 1
1076 size_t subrecord1 = aReader.ReadAndSetSubrecordLength();
1077
1078 aReader.Skip( 1 );
1079 uint8_t flags1 = aReader.Read<uint8_t>();
1080 is_test_fab_top = ( flags1 & 0x80 ) != 0;
1081 is_tent_bottom = ( flags1 & 0x40 ) != 0;
1082 is_tent_top = ( flags1 & 0x20 ) != 0;
1083 is_locked = ( flags1 & 0x04 ) == 0;
1084
1085 uint8_t flags2 = aReader.Read<uint8_t>();
1086 is_test_fab_bottom = ( flags2 & 0x01 ) != 0;
1087
1088 net = aReader.Read<uint16_t>();
1089 aReader.Skip( 8 );
1090 position = aReader.ReadVector2IPos();
1091 diameter = aReader.ReadKicadUnit();
1092 holesize = aReader.ReadKicadUnit();
1093
1094 layer_start = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
1095 layer_end = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
1096
1097 if( subrecord1 <= 74 )
1098 {
1100 }
1101 else
1102 {
1103 uint8_t temp_byte = aReader.Read<uint8_t>(); // Unknown.
1104
1106 thermal_relief_conductorcount = aReader.Read<uint8_t>();
1107 aReader.Skip( 1 ); // Unknown.
1108
1110
1111 aReader.ReadKicadUnit(); // Unknown. 20mil?
1112 aReader.ReadKicadUnit(); // Unknown. 20mil?
1113
1114 aReader.Skip( 4 );
1116 aReader.Skip( 8 );
1117
1118 temp_byte = aReader.Read<uint8_t>();
1119 soldermask_expansion_manual = temp_byte & 0x02;
1120
1121 aReader.Skip( 7 );
1122
1123 viamode = static_cast<ALTIUM_PAD_MODE>( aReader.Read<uint8_t>() );
1124
1125 for( int ii = 0; ii < 32; ++ii )
1126 {
1127 diameter_by_layer[ii] = aReader.ReadKicadUnit();
1128 }
1129 }
1130
1131 if( subrecord1 >= 246 )
1132 {
1133 aReader.Skip( 38 );
1134 soldermask_expansion_linked = aReader.Read<uint8_t>() & 0x01;
1136 }
1137
1138 if( subrecord1 >= 307 )
1139 {
1140 aReader.Skip( 45 );
1141
1142 pos_tolerance = aReader.ReadKicadUnit();
1143 neg_tolerance = aReader.ReadKicadUnit();
1144 }
1145
1146 aReader.SkipSubrecord();
1147
1148 if( aReader.HasParsingError() )
1149 THROW_IO_ERROR( wxT( "Vias6 stream was not parsed correctly" ) );
1150}
1151
1153{
1154 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
1155
1156 if( recordtype != ALTIUM_RECORD::TRACK )
1157 THROW_IO_ERROR( wxT( "Tracks6 stream has invalid recordtype" ) );
1158
1159 // Subrecord 1
1160 aReader.ReadAndSetSubrecordLength();
1161
1162 layer_v6 = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
1163
1164 uint8_t flags1 = aReader.Read<uint8_t>();
1165 is_locked = ( flags1 & 0x04 ) == 0;
1166 is_polygonoutline = ( flags1 & 0x02 ) != 0;
1167
1168 uint8_t flags2 = aReader.Read<uint8_t>();
1169 is_keepout = flags2 == 2;
1170
1171 net = aReader.Read<uint16_t>();
1172 polygon = aReader.Read<uint16_t>();
1173 component = aReader.Read<uint16_t>();
1174 aReader.Skip( 4 );
1175 start = aReader.ReadVector2IPos();
1176 end = aReader.ReadVector2IPos();
1177 width = aReader.ReadKicadUnit();
1178 subpolyindex = aReader.Read<uint16_t>();
1179 aReader.Skip( 1 );
1180
1181 int remaining = aReader.GetRemainingSubrecordBytes();
1182
1183 if( remaining >= 9 )
1184 {
1185 aReader.Skip( 5 );
1186 layer_v7 = static_cast<ALTIUM_LAYER>( aReader.Read<uint32_t>() );
1187 }
1188
1189 if( remaining >= 10 )
1190 keepoutrestrictions = aReader.Read<uint8_t>();
1191 else
1192 keepoutrestrictions = is_keepout ? 0x1F : 0;
1193
1195
1196 aReader.SkipSubrecord();
1197
1198 if( aReader.HasParsingError() )
1199 THROW_IO_ERROR( wxT( "Tracks6 stream was not parsed correctly" ) );
1200}
1201
1202ATEXT6::ATEXT6( ALTIUM_BINARY_PARSER& aReader, std::map<uint32_t, wxString>& aStringTable )
1203{
1204 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
1205
1206 if( recordtype != ALTIUM_RECORD::TEXT )
1207 THROW_IO_ERROR( wxT( "Texts6 stream has invalid recordtype" ) );
1208
1209 // Subrecord 1 - Properties
1210 size_t subrecord1 = aReader.ReadAndSetSubrecordLength();
1211
1212 layer_v6 = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
1213 aReader.Skip( 6 );
1214 component = aReader.Read<uint16_t>();
1215 aReader.Skip( 4 );
1216 position = aReader.ReadVector2IPos();
1217 height = aReader.ReadKicadUnit();
1218 strokefonttype = static_cast<STROKE_FONT_TYPE>( aReader.Read<uint16_t>() );
1219 // TODO: The Serif font type doesn't match well with KiCad, we should replace it with a better match
1220
1221 rotation = aReader.Read<double>();
1222 isMirrored = aReader.Read<uint8_t>() != 0;
1223 strokewidth = aReader.ReadKicadUnit();
1224
1225 if( subrecord1 < 123 )
1226 {
1228 aReader.SkipSubrecord();
1229 return;
1230 }
1231
1232 isComment = aReader.Read<uint8_t>() != 0;
1233 isDesignator = aReader.Read<uint8_t>() != 0;
1234 aReader.Skip( 1 );
1235 fonttype = static_cast<ALTIUM_TEXT_TYPE>( aReader.Read<uint8_t>() );
1236 isBold = aReader.Read<uint8_t>() != 0;
1237 isItalic = aReader.Read<uint8_t>() != 0;
1238
1239 char fontData[64] = { 0 };
1240 aReader.ReadBytes( fontData, sizeof( fontData ) );
1241 fontname = wxString( fontData, wxMBConvUTF16LE(), sizeof( fontData ) ).BeforeFirst( '\0' );
1242
1243 char tmpbyte = aReader.Read<uint8_t>();
1244 isInverted = !!tmpbyte;
1245 margin_border_width = aReader.ReadKicadUnit(); // "Margin Border"
1246 widestring_index = aReader.Read<uint32_t>();
1247 aReader.Skip( 4 );
1248
1249 // An inverted rect in Altium is like a text box with the text inverted.
1250 isInvertedRect = aReader.Read<uint8_t>() != 0;
1251
1254 textbox_rect_justification = static_cast<ALTIUM_TEXT_POSITION>( aReader.Read<uint8_t>() );
1255 text_offset_width = aReader.ReadKicadUnit(); // "Text Offset"
1256
1257 int remaining = aReader.GetRemainingSubrecordBytes();
1258
1259 if( remaining >= 93 )
1260 {
1261 VECTOR2I unk_vec = aReader.ReadVector2ISize();
1262 wxLogTrace( traceAltiumImport, " Unk vec: %d, %d\n", unk_vec.x, unk_vec.y );
1263
1264 barcode_margin = aReader.ReadVector2ISize();
1265
1266 int32_t unk32 = aReader.ReadKicadUnit();
1267 wxLogTrace( traceAltiumImport, " Unk32: %d\n", unk32 );
1268
1269 barcode_type = static_cast<ALTIUM_BARCODE_TYPE>( aReader.Read<uint8_t>() );
1270 uint8_t unk8 = aReader.Read<uint8_t>();
1271 wxLogTrace( traceAltiumImport, " Unk8: %u\n", unk8 );
1272
1273 barcode_inverted = aReader.Read<uint8_t>() != 0;
1274 fonttype = static_cast<ALTIUM_TEXT_TYPE>( aReader.Read<uint8_t>() );
1275
1276 aReader.ReadBytes( fontData, sizeof( fontData ) );
1277 barcode_fontname = wxString( fontData, wxMBConvUTF16LE(), sizeof( fontData ) ).BeforeFirst( '\0' );
1278
1279 aReader.Read<uint8_t>();
1280 wxLogTrace( traceAltiumImport, " Unk8_2: %u\n", unk8 );
1281
1282 layer_v7 = static_cast<ALTIUM_LAYER>( aReader.Read<uint32_t>() );
1283 }
1284
1285 if( remaining >= 103 )
1286 {
1287 // "Frame" text type flag
1288 isFrame = aReader.Read<uint8_t>() != 0;
1289
1290 // Use "Offset" border value instead of "Margin"
1291 isOffsetBorder = aReader.Read<uint8_t>() != 0;
1292
1293 for( size_t ii = 0; ii < 8; ++ii )
1294 {
1295 uint8_t temp = aReader.Peek<uint8_t>();
1296 uint32_t temp32 = ii < 3 ? ALTIUM_PROPS_UTILS::ConvertToKicadUnit( aReader.Peek<uint32_t>() ) : 0;
1297 wxLogTrace( traceAltiumImport, "3ATEXT6 %zu:\t Byte:%u, Kicad:%u\n", ii, temp, temp32 );
1298 aReader.Skip( 1 );
1299 }
1300 }
1301 else
1302 {
1304 isOffsetBorder = false;
1305 }
1306
1307 if( remaining >= 115 )
1308 {
1309 // textbox_rect_justification will be wrong (5) when this flag is unset,
1310 // in that case, we should always use the left bottom justification.
1311 isJustificationValid = aReader.Read<uint8_t>() != 0;
1312 }
1313 else
1314 {
1315 isJustificationValid = false;
1316 }
1317
1318 aReader.SkipSubrecord();
1319
1320 // Subrecord 2 - Legacy 8bit string, max 255 chars, unknown codepage
1321 aReader.ReadAndSetSubrecordLength();
1322
1323 auto entry = aStringTable.find( widestring_index );
1324
1325 if( entry != aStringTable.end() )
1326 text = entry->second;
1327 else
1328 text = aReader.ReadWxString();
1329
1330 // Normalize Windows line endings
1331 text.Replace( wxT( "\r\n" ), wxT( "\n" ) );
1332
1333 aReader.SkipSubrecord();
1334
1335 // Altium only supports inverting truetype fonts
1337 {
1338 isInverted = false;
1339 isInvertedRect = false;
1340 }
1341
1343
1344 if( aReader.HasParsingError() )
1345 THROW_IO_ERROR( wxT( "Texts6 stream was not parsed correctly" ) );
1346}
1347
1349{
1350 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
1351
1352 if( recordtype != ALTIUM_RECORD::FILL )
1353 THROW_IO_ERROR( wxT( "Fills6 stream has invalid recordtype" ) );
1354
1355 // Subrecord 1
1356 aReader.ReadAndSetSubrecordLength();
1357
1358 layer_v6 = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
1359
1360 uint8_t flags1 = aReader.Read<uint8_t>();
1361 is_locked = ( flags1 & 0x04 ) == 0;
1362
1363 uint8_t flags2 = aReader.Read<uint8_t>();
1364 is_keepout = flags2 == 2;
1365
1366 net = aReader.Read<uint16_t>();
1367 aReader.Skip( 2 );
1368 component = aReader.Read<uint16_t>();
1369 aReader.Skip( 4 );
1370 pos1 = aReader.ReadVector2IPos();
1371 pos2 = aReader.ReadVector2IPos();
1372 rotation = aReader.Read<double>();
1373
1374 int remaining = aReader.GetRemainingSubrecordBytes();
1375
1376 if( remaining >= 9 )
1377 {
1378 aReader.Skip( 5 );
1379 layer_v7 = static_cast<ALTIUM_LAYER>( aReader.Read<uint32_t>() );
1380 }
1381
1382 if( remaining >= 10 )
1383 keepoutrestrictions = aReader.Read<uint8_t>();
1384 else
1385 keepoutrestrictions = is_keepout ? 0x1F : 0;
1386
1388
1389 aReader.SkipSubrecord();
1390
1391 if( aReader.HasParsingError() )
1392 THROW_IO_ERROR( wxT( "Fills6 stream was not parsed correctly" ) );
1393}
1394
1395AREGION6::AREGION6( ALTIUM_BINARY_PARSER& aReader, bool aExtendedVertices )
1396{
1397 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
1398
1399 if( recordtype != ALTIUM_RECORD::REGION )
1400 THROW_IO_ERROR( wxT( "Regions6 stream has invalid recordtype" ) );
1401
1402 // Subrecord 1
1403 aReader.ReadAndSetSubrecordLength();
1404
1405 layer_v6 = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
1406
1407 uint8_t flags1 = aReader.Read<uint8_t>();
1408 is_locked = ( flags1 & 0x04 ) == 0;
1409 is_teardrop = ( flags1 & 0x10 ) != 0;
1410
1411 uint8_t flags2 = aReader.Read<uint8_t>();
1412 is_keepout = flags2 == 2;
1413
1414 net = aReader.Read<uint16_t>();
1415 polygon = aReader.Read<uint16_t>();
1416 component = aReader.Read<uint16_t>();
1417 aReader.Skip( 5 );
1418 holecount = aReader.Read<uint16_t>();
1419 aReader.Skip( 2 );
1420
1421 std::map<wxString, wxString> properties = aReader.ReadProperties();
1422
1423 if( properties.empty() )
1424 THROW_IO_ERROR( wxT( "Regions6 stream has empty properties" ) );
1425
1426 layer_v7 = altium_layer_from_name( ALTIUM_PROPS_UTILS::ReadString( properties, wxT( "V7_LAYER" ), "" ) );
1427
1428 int pkind = ALTIUM_PROPS_UTILS::ReadInt( properties, wxT( "KIND" ), 0 );
1429 bool is_cutout = ALTIUM_PROPS_UTILS::ReadBool( properties, wxT( "ISBOARDCUTOUT" ), false );
1430
1431 is_shapebased = ALTIUM_PROPS_UTILS::ReadBool( properties, wxT( "ISSHAPEBASED" ), false );
1432 keepoutrestrictions = static_cast<uint8_t>(
1433 ALTIUM_PROPS_UTILS::ReadInt( properties, wxT( "KEEPOUTRESTRIC" ), 0x1F ) );
1434
1435 // TODO: this can differ from the other subpolyindex?!
1436 // Note: "the other subpolyindex" is "polygon"
1437 subpolyindex = static_cast<uint16_t>(
1438 ALTIUM_PROPS_UTILS::ReadInt( properties, "SUBPOLYINDEX", ALTIUM_POLYGON_NONE ) );
1439
1440 switch( pkind )
1441 {
1442 case 0:
1443 if( is_cutout )
1444 {
1446 }
1447 else
1448 {
1450 }
1451
1452 break;
1453
1454 case 1:
1456 break;
1457
1458 case 2:
1460 break;
1461
1462 case 3:
1463 kind = ALTIUM_REGION_KIND::UNKNOWN_3; // TODO: what kind is this?
1464 break;
1465
1466 case 4:
1468 break;
1469
1470 default:
1472 break;
1473 }
1474
1475 uint32_t num_outline_vertices = aReader.Read<uint32_t>();
1476
1477 if( aExtendedVertices )
1478 num_outline_vertices++; // Has a closing vertex
1479
1480 for( uint32_t i = 0; i < num_outline_vertices; i++ )
1481 {
1482 if( aExtendedVertices )
1483 {
1484 bool isRound = aReader.Read<uint8_t>() != 0;
1485 VECTOR2I position = aReader.ReadVector2IPos();
1486 VECTOR2I center = aReader.ReadVector2IPos();
1487 int32_t radius = aReader.ReadKicadUnit();
1488 double angle1 = aReader.Read<double>();
1489 double angle2 = aReader.Read<double>();
1490 outline.emplace_back( isRound, radius, angle1, angle2, position, center );
1491 }
1492 else
1493 {
1494 // For some regions the coordinates are stored as double and not as int32_t
1495 int32_t x = ALTIUM_PROPS_UTILS::ConvertToKicadUnit( aReader.Read<double>() );
1496 int32_t y = ALTIUM_PROPS_UTILS::ConvertToKicadUnit( -aReader.Read<double>() );
1497 outline.emplace_back( VECTOR2I( x, y ) );
1498 }
1499 }
1500
1501 holes.resize( holecount );
1502 for( uint16_t k = 0; k < holecount; k++ )
1503 {
1504 uint32_t num_hole_vertices = aReader.Read<uint32_t>();
1505 holes.at( k ).reserve( num_hole_vertices );
1506
1507 for( uint32_t i = 0; i < num_hole_vertices; i++ )
1508 {
1509 int32_t x = ALTIUM_PROPS_UTILS::ConvertToKicadUnit( aReader.Read<double>() );
1510 int32_t y = ALTIUM_PROPS_UTILS::ConvertToKicadUnit( -aReader.Read<double>() );
1511 holes.at( k ).emplace_back( VECTOR2I( x, y ) );
1512 }
1513 }
1514
1516
1517 aReader.SkipSubrecord();
1518
1519 if( aReader.HasParsingError() )
1520 THROW_IO_ERROR( wxT( "Regions6 stream was not parsed correctly" ) );
1521}
void altium_parse_polygons(std::map< wxString, wxString > &aProps, std::vector< ALTIUM_VERTICE > &aVertices)
ALTIUM_MECHKIND altium_mechkind_from_name(const wxString &aName)
static void ExpectSubrecordLengthAtLeast(const std::string &aStreamType, const std::string &aSubrecordName, size_t aExpectedLength, size_t aActualLength)
Throw an IO_ERROR if the actual length is less than the expected length.
ALTIUM_LAYER altium_layer_from_name(const wxString &aName)
static AEXTENDED_PRIMITIVE_INFORMATION_TYPE ReadAltiumExtendedPrimitiveInformationTypeFromProperties(const std::map< wxString, wxString > &aProps, wxString aKey)
ALTIUM_LAYER altium_versioned_layer(ALTIUM_LAYER aV6Layer, ALTIUM_LAYER aV7Layer)
static ALTIUM_MODE ReadAltiumModeFromProperties(const std::map< wxString, wxString > &aProps, wxString aKey)
static std::vector< ABOARD6_LAYER_STACKUP > ReadAltiumStackupFromProperties(const std::map< wxString, wxString > &aProps)
static ALTIUM_RECORD ReadAltiumRecordFromProperties(const std::map< wxString, wxString > &aProps, wxString aKey)
ALTIUM_PAD_SHAPE_ALT
ALTIUM_TEXT_POSITION
ALTIUM_MECHKIND
ALTIUM_PAD_MODE
ALTIUM_TEXT_TYPE
ALTIUM_PAD_SHAPE
ALTIUM_BARCODE_TYPE
ALTIUM_DIMENSION_KIND
ALTIUM_PAD_HOLE_SHAPE
const uint16_t ALTIUM_NET_UNCONNECTED
ALTIUM_CLASS_KIND
const uint16_t ALTIUM_POLYGON_NONE
AEXTENDED_PRIMITIVE_INFORMATION_TYPE
ALTIUM_RECORD
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
void Skip(size_t aLength)
size_t GetRemainingSubrecordBytes() const
std::map< wxString, wxString > ReadProperties(std::function< std::map< wxString, wxString >(const std::string &)> handleBinaryData=[](const std::string &) { return std::map< wxString, wxString >();})
int ReadBytes(char *aOut, size_t aSize)
static int ReadInt(const std::map< wxString, wxString > &aProps, const wxString &aKey, int aDefault)
static int32_t ReadKicadUnit(const std::map< wxString, wxString > &aProps, const wxString &aKey, const wxString &aDefault)
static bool ReadBool(const std::map< wxString, wxString > &aProps, const wxString &aKey, bool aDefault)
static wxString ReadUnicodeString(const std::map< wxString, wxString > &aProps, const wxString &aKey, const wxString &aDefault)
static wxString ReadString(const std::map< wxString, wxString > &aProps, const wxString &aKey, const wxString &aDefault)
static double ReadDouble(const std::map< wxString, wxString > &aProps, const wxString &aKey, double aDefault)
static int32_t ConvertToKicadUnit(const double aValue)
#define _(s)
static const wxChar * traceAltiumImport
Flag to enable Altium importer logging.
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
double startangle
uint16_t component
uint32_t width
ALTIUM_LAYER layer
AARC6(ALTIUM_BINARY_PARSER &aReader)
uint8_t keepoutrestrictions
uint16_t polygon
VECTOR2I center
uint32_t radius
uint16_t net
ALTIUM_LAYER layer_v6
ALTIUM_LAYER layer_v7
bool is_polygonoutline
double endangle
uint16_t subpolyindex
ABOARD6_LAYER_STACKUP(const std::map< wxString, wxString > &aProps, const wxString &aPrefix, uint32_t aLayerIdFallback)
VECTOR2I sheetpos
std::set< wxString > layerNames
ABOARD6(ALTIUM_BINARY_PARSER &aReader)
std::vector< ABOARD6_LAYER_STACKUP > stackup
std::vector< ALTIUM_VERTICE > board_vertices
wxString uniqueid
std::vector< wxString > names
ALTIUM_CLASS_KIND kind
wxString name
ACLASS6(ALTIUM_BINARY_PARSER &aReader)
wxString sourceHierachicalPath
ALTIUM_TEXT_POSITION commentautoposition
ALTIUM_TEXT_POSITION nameautoposition
ACOMPONENT6(ALTIUM_BINARY_PARSER &aReader)
wxString sourcefootprintlibrary
ALTIUM_LAYER layer
wxString sourcelibreference
wxString sourcedesignator
wxString sourceUniqueID
wxString sourcecomponentlibrary
ACOMPONENTBODY6(ALTIUM_BINARY_PARSER &aReader)
ALTIUM_UNIT textunit
uint32_t textlinewidth
ALTIUM_LAYER layer
ALTIUM_LAYER layer_v6
std::vector< VECTOR2I > textPoint
ALTIUM_DIMENSION_KIND kind
ALTIUM_LAYER layer_v7
ADIMENSION6(ALTIUM_BINARY_PARSER &aReader)
std::vector< VECTOR2I > referencePoint
AEXTENDED_PRIMITIVE_INFORMATION_TYPE type
AEXTENDED_PRIMITIVE_INFORMATION(ALTIUM_BINARY_PARSER &aReader)
VECTOR2I pos2
ALTIUM_LAYER layer
uint16_t net
VECTOR2I pos1
double rotation
uint8_t keepoutrestrictions
AFILL6(ALTIUM_BINARY_PARSER &aReader)
ALTIUM_LAYER layer_v6
uint16_t component
ALTIUM_LAYER layer_v7
std::set< wxString > layerNames
std::vector< ABOARD6_LAYER_STACKUP > stackup
ALIBRARY(ALTIUM_BINARY_PARSER &aReader)
double z_offset
int32_t checksum
wxString name
VECTOR3D rotation
AMODEL(ALTIUM_BINARY_PARSER &aReader)
ANET6(ALTIUM_BINARY_PARSER &aReader)
wxString name
double holerotation
int32_t soldermaskexpansionmanual
uint16_t net
ALTIUM_LAYER layer
APAD6(ALTIUM_BINARY_PARSER &aReader)
std::unique_ptr< APAD6_SIZE_AND_SHAPE > sizeAndShape
ALTIUM_LAYER layer_v7
ALTIUM_LAYER tolayer
ALTIUM_PAD_SHAPE topshape
ALTIUM_LAYER layer_v6
ALTIUM_PAD_MODE padmode
ALTIUM_MODE pastemaskexpansionmode
uint32_t holesize
double direction
ALTIUM_MODE soldermaskexpansionmode
wxString name
bool is_test_fab_bottom
int32_t pad_to_die_delay
bool is_tent_bottom
VECTOR2I botsize
ALTIUM_PAD_SHAPE botshape
uint16_t component
VECTOR2I midsize
ALTIUM_PAD_SHAPE midshape
int32_t pastemaskexpansionmanual
ALTIUM_LAYER fromlayer
VECTOR2I position
VECTOR2I topsize
bool is_test_fab_top
int32_t pad_to_die_length
ALTIUM_LAYER layer_v6
int32_t minprimlength
std::vector< ALTIUM_VERTICE > vertices
APOLYGON6(ALTIUM_BINARY_PARSER &aReader)
ALTIUM_LAYER layer_v7
ALTIUM_POLYGON_HATCHSTYLE hatchstyle
ALTIUM_LAYER layer
uint8_t keepoutrestrictions
ALTIUM_LAYER layer
AREGION6(ALTIUM_BINARY_PARSER &aReader, bool aExtendedVertices)
ALTIUM_LAYER layer_v7
uint16_t holecount
ALTIUM_LAYER layer_v6
std::vector< ALTIUM_VERTICE > outline
uint16_t subpolyindex
std::vector< std::vector< ALTIUM_VERTICE > > holes
uint16_t component
uint16_t polygon
ALTIUM_REGION_KIND kind
ALTIUM_RULE_KIND kind
ALTIUM_CONNECT_STYLE polygonconnectStyle
wxString scope1expr
wxString name
int planeclearanceClearance
int32_t polygonconnectReliefconductorwidth
int pastemaskExpansion
wxString scope2expr
int soldermaskExpansion
ARULE6(ALTIUM_BINARY_PARSER &aReader)
int32_t polygonconnectAirgapwidth
int polygonconnectReliefentries
uint32_t text_offset_width
VECTOR2I barcode_margin
uint32_t textbox_rect_height
uint16_t component
ALTIUM_LAYER layer_v6
ALTIUM_TEXT_POSITION textbox_rect_justification
bool isInvertedRect
wxString text
uint32_t widestring_index
uint32_t textbox_rect_width
double rotation
uint32_t margin_border_width
uint32_t height
wxString fontname
bool isJustificationValid
ALTIUM_BARCODE_TYPE barcode_type
ALTIUM_LAYER layer
VECTOR2I position
ALTIUM_LAYER layer_v7
ALTIUM_TEXT_TYPE fonttype
STROKE_FONT_TYPE strokefonttype
wxString barcode_fontname
bool isOffsetBorder
ATEXT6(ALTIUM_BINARY_PARSER &aReader, std::map< uint32_t, wxString > &aStringTable)
bool barcode_inverted
uint32_t strokewidth
ALTIUM_LAYER layer_v6
ATRACK6(ALTIUM_BINARY_PARSER &aReader)
uint32_t width
bool is_polygonoutline
ALTIUM_LAYER layer_v7
uint16_t polygon
uint16_t subpolyindex
uint8_t keepoutrestrictions
VECTOR2I start
ALTIUM_LAYER layer
uint16_t component
bool soldermask_expansion_linked
uint32_t thermal_relief_conductorcount
uint32_t diameter
uint32_t neg_tolerance
uint16_t net
VECTOR2I position
int32_t thermal_relief_airgap
bool is_test_fab_top
int32_t soldermask_expansion_front
uint32_t pos_tolerance
bool is_tent_bottom
bool is_test_fab_bottom
bool soldermask_expansion_manual
ALTIUM_PAD_MODE viamode
AVIA6(ALTIUM_BINARY_PARSER &aReader)
uint32_t thermal_relief_conductorwidth
int32_t soldermask_expansion_back
uint32_t diameter_by_layer[32]
ALTIUM_LAYER layer_start
ALTIUM_LAYER layer_end
uint32_t holesize
VECTOR2I center
int radius
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695