KiCad PCB EDA Suite
Loading...
Searching...
No Matches
easypc_classes_styles.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 <algorithm>
23#include <climits>
24
25#include <ki_exception.h>
26#include <wx/translation.h>
27
29
30
31namespace EASYPC
32{
33
34namespace
35{
36
37 // Legacy spacing keys in stream order (below 15000)
38 constexpr int32_t LEGACY_SPACING_KEYS[] = { 0x40004, 0x40002, 0x100004, 0x200004, 0x40001, 0x20002, 0x100002,
39 0x200002, 0x20001, 0x100010, 0x200010, 0x100001, 0x200020, 0x200001,
40 0x80004, 0x80002, 0x80008, 0x100008, 0x200008, 0x80001 };
41
42 // Legitimate parent chains are a few objects long; this keeps a crafted cycle off the stack
43 constexpr size_t MAX_PARENT_WALK = 1024;
44
45 // Classes whose fields no importer reads
46 constexpr FIELD_ROW ATTRIBUTE_ARRAY[] = { { 0, INT_MAX, "o" } };
47 constexpr FIELD_ROW BARCODE_FONT[] = { { 0, INT_MAX, "i s i" } };
48 constexpr FIELD_ROW HATCH_STYLE[] = { { 0, INT_MAX, "s b i f" } };
49 constexpr FIELD_ROW NOTE_CATEGORY[] = { { 0, INT_MAX, "s i2 13 i2" } };
50
51 // A layer after the net: the colour sets, flags and draw order of each version
52 constexpr FIELD_ROW OLD_LAYER_TAIL[] = { { 0x7d3, INT_MAX, "i" }, { 5000, INT_MAX, "b" },
53 { 7000, 0x2711, "b" }, { 8000, 0x2711, "i" },
54 { 0x2712, INT_MAX, "b2 i" }, { 9000, INT_MAX, "i" },
55 { 0x2716, INT_MAX, "i" }, { 9000, INT_MAX, "i" },
56 { 13000, INT_MAX, "i2" }, { 14000, INT_MAX, "b" } };
57
58
59 void checkItemFormat( const ARCHIVE& aAr, int aFormat )
60 {
61 if( aFormat > NEWEST_ITEM_FORMAT )
62 {
64 wxString::Format( _( "Easy-PC item format %d at offset %zu is too new." ), aFormat, aAr.Pos() ) );
65 }
66 }
67
68} // namespace
69
70
71// ---- bases -------------------------------------------------------------------------------------------------------
72
74{
75 Parent = co_await aAr.Object();
76
77 if( ItemFormat( aAr ) > 0x839 )
78 {
79 while( OBJECT* item = co_await aAr.Object() )
80 Items.push_back( item );
81
82 co_return;
83 }
84
85 // Older lists are counted
86 for( uint32_t i = aAr.Count(); i > 0; --i )
87 Items.push_back( co_await aAr.Object() );
88}
89
90
92{
93 if( !Parent )
94 return aAr.OrphanFormat();
95
96 return dynamic_cast<const SOURCE_DESIGN_ITEM*>( Parent ) ? Parent->ItemFormat( aAr ) : aAr.CurrentReadFormat();
97}
98
99
101{
102 Parent = co_await aAr.Object();
103}
104
105
107{
108 return Parent ? aAr.CurrentReadFormat() : aAr.OrphanFormat();
109}
110
111
113{
114 Parent = co_await aAr.Object();
115
116 // Taken after the parent is known because ItemFormat walks it
117 int v = ItemFormat( aAr );
118
119 Attributes = co_await aAr.Object();
120
121 // The group, and from 29000 the group list
122 co_await SkipFields( aAr, v > 28999 ? "o2" : v > 0x835 ? "o" : "" );
123}
124
125
127{
128 if( !Parent )
129 return aAr.OrphanFormat();
130
131 if( !dynamic_cast<const SOURCE_DESIGN_ITEM*>( Parent ) && !dynamic_cast<const SOURCE_COMMON_SHAPE*>( Parent )
132 && !dynamic_cast<const SOURCE_COMMON_SEGMENT*>( Parent ) )
133 {
134 return aAr.CurrentReadFormat();
135 }
136
137 // Parent tags are file data, so a crafted file can make the chain cyclic
138 size_t& depth = aAr.ParentWalkDepth();
139
140 if( depth > MAX_PARENT_WALK )
142 wxString::Format( _( "Easy-PC %s at offset %zu has a cyclic parent chain." ), ClassName, Offset ) );
143
144 struct UNWIND
145 {
146 size_t& Depth;
147 ~UNWIND() { --Depth; }
148 } unwind{ ++depth };
149
150 return Parent->ItemFormat( aAr );
151}
152
153
155{
156 aFormat = aAr.ObjectSchema() < 2 ? 0 : aAr.I32();
157 checkItemFormat( aAr, aFormat );
158 aAr.SetReadFormat( aFormat );
159}
160
161
162void SOURCE_DESIGN_ITEM::LoadOldFormat( ARCHIVE& aAr, int& aFormat ) const
163{
164 if( ItemFormat( aAr ) != 0 )
165 return;
166
167 aFormat = aAr.I32();
168 checkItemFormat( aAr, aFormat );
169 aAr.SetReadFormat( aFormat );
170}
171
172
173// ---- attributes and styles ---------------------------------------------------------------------------------------
174
176{
177 static constexpr FIELD_ROW ROWS[] = { { 8001, INT_MAX, "s" }, { 0x2ee4, INT_MAX, "i" } };
178
179 co_await SOURCE_DESIGN_ITEM::Load( aAr );
180 Name = aAr.ReadString();
181 co_await SkipRows( aAr, ItemFormat( aAr ), ROWS );
182}
183
184
186{
187 co_await SOURCE_DESIGN_ITEM::Load( aAr );
188
190 Value = aAr.ReadString();
191 Displayed = aAr.InBool();
192}
193
194
196{
197 co_await SOURCE_DESIGN_ITEM::Load( aAr );
198
199 Name = aAr.ReadString();
200 Width = aAr.I32();
201
202 if( ItemFormat( aAr ) > 10999 )
203 {
204 aAr.Skip( 12 ); // dash and gap lengths
205 }
206}
207
208
210{
211 co_await SOURCE_DESIGN_ITEM::Load( aAr );
212 aAr.Skip( 0x9c ); // a Win32 ENUMLOGFONTA
213}
214
215
217{
218 co_await SOURCE_DESIGN_ITEM::Load( aAr );
219
220 const int v = ItemFormat( aAr );
221
222 Name = aAr.ReadString();
223 Height = aAr.I32();
224 LineWidth = aAr.I32();
225
226 if( v > 4999 )
227 {
228 aAr.InBool(); // underlined
229 Font = co_await aAr.Object();
230
231 if( v < 0x32c9 )
232 co_return;
233
234 aAr.Skip( 4 * size_t( aAr.Count() ) ); // barcode parameters
235 }
236
237 if( v > 21999 )
238 {
240 CharWidthPercent = aAr.I32();
241 Proportional = aAr.Bool();
242 }
243
244 if( v > 29999 )
245 aAr.SkipString();
246}
247
248
250{
251 co_await SOURCE_DESIGN_ITEM::Load( aAr );
252
253 Name = aAr.ReadString();
254 Width = aAr.I32();
255}
256
257
259{
260 co_await SOURCE_DESIGN_ITEM::Load( aAr );
261
262 const int v = ItemFormat( aAr );
263
264 Name = aAr.ReadString();
265 Size = aAr.I32();
266 Shape = static_cast<PAD_SHAPE>( aAr.I32() );
267 Drill = aAr.I32();
268 Length = aAr.I32();
269 Exceptions = co_await aAr.Object();
270
271 if( v > 8999 )
272 {
273 Plated = aAr.InBool();
274 Dimension3 = aAr.I32();
275 }
276
277 // Schematic pad styles below 11004 lose their drill in memory
278 if( v < 0x2afc && aAr.Kind() == DOC_KIND::SCHEMATIC )
279 Drill = 0;
280
281 if( v > 12000 )
282 {
283 DrillShape = static_cast<PAD_SHAPE>( aAr.I32() );
284 DrillLength = aAr.I32();
285 DrillCornerRadius = aAr.I32();
286
287 // No known file turns a slot, and an unturned slot would be drilled across its intended axis
288 if( aAr.Bool() && DrillShape != PAD_SHAPE::ROUND )
289 THROW_IO_ERROR( wxString::Format( _( "Unsupported Easy-PC turned slot in pad style '%s'." ), Name ) );
290 }
291
292 if( v > 17999 )
293 aAr.Skip( 4 );
294
295 if( v > 23999 )
296 aAr.Skip( 4 ); // thermal spoke width
297}
298
299
301{
302 co_await SOURCE_DESIGN_ITEM::Load( aAr );
303
304 Layer = co_await aAr.Object();
305 Shape = static_cast<PAD_SHAPE>( aAr.I32() );
306 Size = aAr.I32();
307 Length = aAr.I32();
308
309 const int v = ItemFormat( aAr );
310
311 if( v > 10000 )
312 Dimension3 = aAr.I32();
313
314 if( v > 17999 )
315 aAr.Skip( 4 );
316
317 if( v > 23999 )
318 aAr.Skip( 4 );
319}
320
321
322// ---- layers ------------------------------------------------------------------------------------------------------
323
325{
326 static constexpr FIELD_ROW ROWS[] = { { 13000, INT_MAX, "b" },
327 { 21000, INT_MAX, "b i" },
328 { 0x6d63, INT_MAX, "13" } };
329
330 co_await SOURCE_DESIGN_ITEM::Load( aAr );
331
332 Name = aAr.ReadString();
333 Usage = aAr.I32();
335 ViasEnabled = aAr.InBool();
338
339 const int v = ItemFormat( aAr );
340
341 if( v > 8999 )
342 {
343 Oversize = aAr.I32();
344 OversizeType = static_cast<LAYER_OVERSIZE_TYPE>( aAr.I32() );
345 }
346
347 SurfacePadsEnabled = v < 0x2ee6 ? AllLayerPadsEnabled : aAr.Bool();
348 co_await SkipRows( aAr, v, ROWS );
349}
350
351
353{
354 co_await SOURCE_DESIGN_ITEM::Load( aAr );
355
356 const int v = ItemFormat( aAr );
357
358 Name = aAr.ReadString();
359 Side = static_cast<LAYER_SIDE>( aAr.I32() );
360
361 if( v < 3000 )
362 TypeName = aAr.ReadString();
363 else
364 Type = co_await aAr.ObjectAs<SOURCE_LAYER_TYPE>();
365
366 Usage = aAr.I32();
367 Displayed = aAr.InBool();
368
369 if( v > 17999 )
370 {
371 // A colour map with a plain int32 count, then the bias
372 aAr.Skip( 8 * size_t( aAr.U32() ) + 4 );
373 Net = co_await aAr.Object();
374 co_await SkipFields( aAr, "b3 i b" );
375 Terminals = co_await aAr.Object();
376 }
377 else
378 {
379 aAr.Skip( 40 ); // nine colours and the bias
380 Net = co_await aAr.Object();
381 co_await SkipRows( aAr, v, OLD_LAYER_TAIL );
382
383 if( v > 0x3a99 )
384 Terminals = co_await aAr.Object();
385 }
386
387 if( TypeName.IsEmpty() )
388 co_return;
389
390 // A type name: a design types the layer by its usage, a library item makes a usage 4 type
391 ConvertedType = std::make_unique<SOURCE_LAYER_TYPE>();
392 ConvertedType->Name = TypeName;
394 Type = ConvertedType.get();
395
396 if( TypeName.CmpNoCase( wxS( "Silk Screen" ) ) == 0 )
397 {
398 Type->SurfacePadInstancesEnabled = false;
399 Type->AllLayerPadInstancesEnabled = false;
400 Type->ViasEnabled = false;
401 Type->AllLayerPadsEnabled = false;
402 Type->SurfacePadsEnabled = false;
403 }
404}
405
406
408{
409 co_await SOURCE_LAYER::Load( aAr );
410
411 TopLayer = co_await aAr.ObjectAs<SOURCE_LAYER>();
412 BottomLayer = co_await aAr.ObjectAs<SOURCE_LAYER>();
413}
414
415
417{
418 co_await SOURCE_DESIGN_LIST::Load( aAr );
419
420 aAr.Skip( 4 ); // next colour
421
422 // The loader moves the first bottom layer set to the end
423 auto it = std::find_if( Items.begin(), Items.end(),
424 []( const OBJECT* aItem )
425 {
426 const SOURCE_LAYER* layer = dynamic_cast<const SOURCE_LAYER*>( aItem );
427 return layer && layer->Side == LAYER_SIDE::BOTTOM
428 && ( layer->EffectiveUsage() & LAYER_USAGE_SET );
429 } );
430
431 if( it != Items.end() )
432 std::rotate( it, it + 1, Items.end() );
433}
434
435
436// ---- net classes and spacings ------------------------------------------------------------------------------------
437
439{
440 co_await SOURCE_DESIGN_ITEM::Load( aAr );
441
442 Name = aAr.ReadString();
443 Type = aAr.I32();
444 TrackStyle1 = co_await aAr.ObjectAs<SOURCE_TRACK_STYLE>();
445 TrackStyle2 = co_await aAr.ObjectAs<SOURCE_TRACK_STYLE>();
446 ViaStyle = co_await aAr.ObjectAs<SOURCE_PAD_STYLE>();
447
448 const int v = ItemFormat( aAr );
449
450 if( v > 0x32c9 )
451 {
452 aAr.Skip( 14 ); // track length difference and min/max limits with their switches
453 }
454
455 // The thermal rules, own colour and connection display
456 if( v > 17999 )
457 {
458 co_await SkipFields( aAr, THERMAL_RULE_SET );
459 aAr.Skip( 9 );
460 }
461
462 if( v > 24999 )
463 {
464 TentedVias = aAr.I32();
465 aAr.Skip( 1 ); // diff pair switch
466 DiffPairGap = aAr.I32();
467 aAr.Skip( 5 ); // skew
468 }
469
470 if( v > 26999 )
471 {
472 aAr.Skip( 10 ); // via count and stub length limits with their switches
473 }
474}
475
476
478{
479 co_await SOURCE_DESIGN_ITEM::Load( aAr );
480
481 const int v = ItemFormat( aAr );
482
483 if( v < 0x3a98 )
484 {
485 Bidirectional = true;
486
487 for( int32_t key : LEGACY_SPACING_KEYS )
488 Values[key] = aAr.I32();
489
490 if( v > 0x1f42 )
491 Values[0x400040] = aAr.I32();
492
493 co_return;
494 }
495
496 Bidirectional = aAr.Bool();
497
498 // A counted map of key to clearance
499 for( uint32_t i = aAr.Count(); i > 0; --i )
500 {
501 int32_t key = aAr.I32();
502 Values[key] = aAr.I32();
503 }
504}
505
506
508{
509 // A design's spacings start at 0.254 mm
510 for( int32_t key : LEGACY_SPACING_KEYS )
511 Values[key] = 2540;
512
513 Values[0x400040] = 0;
514}
515
516
518{
519 co_await SOURCE_SPACINGS::Load( aAr );
520
521 // No known file holds a class spacing, so the list must be a null tag
522 if( ItemFormat( aAr ) > 15000 )
523 co_await aAr.Object();
524}
525
526
528{
529 Register<SOURCE_DESIGN_ITEM>( aReg, { "CDesignItem" } );
530 Register<SOURCE_ATTRIBUTE_NAME>( aReg, { "CAttributeName" } );
531 Register<SOURCE_ATTRIBUTE>( aReg, { "CAttribute" } );
532 Register<SOURCE_LINE_STYLE>( aReg, { "CLineStyle" } );
533 Register<SOURCE_TYPE_FONT>( aReg, { "CTypeFont" } );
534 Register<SOURCE_TEXT_STYLE>( aReg, { "CTextStyle" } );
535 Register<SOURCE_TRACK_STYLE>( aReg, { "CTrackStyle" } );
536 Register<SOURCE_PAD_STYLE>( aReg, { "CPadStyle" } );
537 Register<SOURCE_PAD_STYLE_EXCEPTION>( aReg, { "CPadStyleException" } );
538 Register<SOURCE_LAYER_TYPE>( aReg, { "CLayerType" } );
539 Register<SOURCE_LAYER>( aReg, { "CLayer" } );
540 Register<SOURCE_LAYER_SPAN>( aReg, { "CLayerSpan" } );
541 Register<SOURCE_LAYER_ARRAY>( aReg, { "CLayerArray" } );
542 Register<SOURCE_NET_CLASS>( aReg, { "CNetClass" } );
543 Register<SOURCE_SPACINGS>( aReg, { "CSpacings" } );
544 Register<SOURCE_DESIGN_SPACINGS>( aReg, { "CDesignSpacings" } );
545 RegisterSkipped<SOURCE_DESIGN_LIST>( aReg, "CAttributeArray", ATTRIBUTE_ARRAY );
546 RegisterSkipped<SOURCE_DESIGN_ITEM>( aReg, "CBarcodeFont", BARCODE_FONT );
547 RegisterSkipped<SOURCE_DESIGN_ITEM>( aReg, "CHatchStyle", HATCH_STYLE );
548 RegisterSkipped<SOURCE_DESIGN_ITEM>( aReg, "CNoteCategory", NOTE_CATEGORY );
550 { "CDesignList", "CAttributeNameArray", "CLineStyleArray", "CTextStyleArray",
551 "CTrackStyleArray", "CHatchStyleList", "CPadStyleArray", "CPadStyleExceptionList",
552 "CLayerTypeList", "CLayerSpanArray", "CNetClassArray", "CNoteCategoryList" } );
553}
554
555} // namespace EASYPC
One archive load stream; it owns every object it creates.
void Skip(size_t aLen)
DOC_KIND Kind() const
size_t & ParentWalkDepth() const
Bounds ItemFormat parent walks, which recurse through file-supplied parent tags.
int CurrentReadFormat() const
bool IsDesign() const
wxString ReadString()
ANSI (windows-1252) or the 0xFF 0xFFFE UTF-16 form.
TYPED_AWAITER< T > ObjectAs()
void SetReadFormat(int aFormat)
uint16_t ObjectSchema() const
bool InBool()
one or four bytes, depending on the active format
int OrphanFormat() const
A null parent tag is the document: the header version in a design, else the current read format.
uint32_t Count()
a 16-bit count, 0xFFFF escaping to 32 bits
OBJECT_AWAITER Object()
A loader coroutine. Awaiting one queues it on its archive's frame stack instead of nesting the call.
Shapes, vertices and the free-standing drawn items.
Design items, attributes, styles, layers, net classes and spacings.
#define _(s)
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
std::map< std::string, std::function< std::unique_ptr< OBJECT >()>, std::less<> > REGISTRY
LOAD_TASK SkipRows(ARCHIVE &aAr, int aVersion, std::span< const FIELD_ROW > aRows)
SkipFields for every row aVersion falls in, in order.
constexpr int NEWEST_ITEM_FORMAT
The newest item format a file can carry (30001)
LOAD_TASK SkipFields(ARCHIVE &aAr, std::string_view aOps)
Read and drop a run of fields described by aOps, each letter optionally followed by a repeat count: b...
constexpr char THERMAL_RULE_SET[]
A thermal rule set as SkipFields ops: owner, four thermal rules (owner and an int array),...
LAYER_OVERSIZE_TYPE
How a layer type grows pads.
void RegisterSkipped(REGISTRY &aReg, const char *aName, std::span< const FIELD_ROW > aRows)
PAD_SHAPE
Pad style shape, also the drill and exception shape.
void Register(REGISTRY &aReg, std::initializer_list< const char * > aNames)
Register the class names whose objects load as a T.
void RegisterStyleClasses(REGISTRY &aReg)
A run of fields present from version since to until inclusive.
Root of every deserialized object.
size_t Offset
stream offset of the tag or of an embedded member's first field
const char * ClassName
registered class name
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
SOURCE_ATTRIBUTE_NAME * AttributeName
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
int ItemFormat(const ARCHIVE &aAr) const override
The version this object gates on; the base is the archive's current read format.
The base of nearly every class.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
int ItemFormat(const ARCHIVE &aAr) const override
The version this object gates on; the base is the archive's current read format.
OBJECT * Attributes
attribute array
void LoadOldFormat(ARCHIVE &aAr, int &aFormat) const
An older item format, stored only while the format is still 0.
OBJECT * Parent
null is the document in a design, nothing in a library item
static void LoadFormatted(ARCHIVE &aAr, int &aFormat)
An item format, stored only from object schema 2, which governs what follows.
std::vector< OBJECT * > Items
int ItemFormat(const ARCHIVE &aAr) const override
The version this object gates on; the base is the archive's current read format.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
Layer type names determine silk, mask and paste roles.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
std::unique_ptr< SOURCE_LAYER_TYPE > ConvertedType
The type made from type_name.
OBJECT * Net
net of a power plane
SOURCE_LAYER_TYPE * Type
null for the layer sets
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
wxString TypeName
below v3000 the type is stored by name
OBJECT * Terminals
copper terminal array
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
SOURCE_TRACK_STYLE * TrackStyle1
the narrower of the two is the minimum width
SOURCE_TRACK_STYLE * TrackStyle2
int32_t Type
0 signal, 1 power
int32_t TentedVias
0 none, 1 all, 2 per via
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
OBJECT * Exceptions
pad style exception list
int32_t Length
Y extent for shapes that have one.
std::map< int32_t, int32_t > Values
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
OBJECT * Font
type or barcode font, or null for the stroke font
int32_t Height
the accessor is GetWidth but it is the text height
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.
LOAD_TASK Load(ARCHIVE &aAr) override
Read this object's fields.