KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_io_kicad_legacy.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) 2007-2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
5 * Copyright (C) 2019 Jean-Pierre Charras, [email protected]
6 * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26/*
27 This implements loading and saving a BOARD, behind the PLUGIN interface.
28
29 The definitions:
30
31 *) a Board Internal Unit (BIU) is a unit of length that is used only internally
32 to PCBNEW, and is nanometers when this work is done, but deci-mils until done.
33
34 The philosophies:
35
36 *) BIUs should be typed as such to distinguish them from ints. This is mostly
37 for human readability, and having the type nearby in the source supports this readability.
38 *) Do not assume that BIUs will always be int, doing a sscanf() into a BIU
39 does not make sense in case the size of the BIU changes.
40 *) variables are put onto the stack in an automatic, even when it might look
41 more efficient to do otherwise. This is so we can seem them with a debugger.
42 *) Global variables should not be touched from within a PLUGIN, since it will eventually
43 be in a DLL/DSO. This includes window information too. The PLUGIN API knows
44 nothing of wxFrame or globals and all error reporting must be done by throwing
45 an exception.
46 *) No wxWindowing calls are made in here, since the UI resides higher up than in here,
47 and is going to process a bucket of detailed information thrown from down here
48 in the form of an exception if an error happens.
49 *) Much of what we do in this source file is for human readability, not performance.
50 Simply avoiding strtok() more often than the old code washes out performance losses.
51 Remember strncmp() will bail as soon as a mismatch happens, not going all the way
52 to end of string unless a full match.
53 *) angles are in the process of migrating to doubles, and 'int' if used, is
54 only shortterm, and along with this a change, and transition from from
55 "tenths of degrees" to simply "degrees" in the double (which has no problem
56 representing any portion of a degree).
57*/
58
59
60#include <cerrno>
61#include <cmath>
62#include <cstdio>
63#include <cstring>
64#include <pcb_io/kicad_legacy/pcb_io_kicad_legacy.h> // implement this here
65#include <wx/ffile.h>
66#include <wx/log.h>
67#include <wx/string.h>
68#include <wx/filename.h>
69#include <wx/wfstream.h>
70#include <wx/txtstrm.h>
71#include <boost/ptr_container/ptr_map.hpp>
72
73#include <string_utils.h>
74#include <locale_io.h>
75#include <macros.h>
76#include <string_utf8_map.h>
77#include <filter_reader.h>
78#include <zones.h>
79
80#include <board.h>
82#include <footprint.h>
83#include <core/ignore.h>
84#include <pad.h>
85#include <pcb_track.h>
86#include <pcb_text.h>
87#include <zone.h>
88#include <pcb_dimension.h>
89#include <pcb_shape.h>
90#include <pcb_target.h>
91#include <pcb_plot_params.h>
93#include <trigo.h>
94#include <confirm.h>
95#include <math/util.h> // for KiROUND
96#include <progress_reporter.h>
97
99
100
101typedef unsigned LEG_MASK;
102
103#define FIRST_LAYER 0
104#define FIRST_COPPER_LAYER 0
105#define LAYER_N_BACK 0
106#define LAYER_N_2 1
107#define LAYER_N_3 2
108#define LAYER_N_4 3
109#define LAYER_N_5 4
110#define LAYER_N_6 5
111#define LAYER_N_7 6
112#define LAYER_N_8 7
113#define LAYER_N_9 8
114#define LAYER_N_10 9
115#define LAYER_N_11 10
116#define LAYER_N_12 11
117#define LAYER_N_13 12
118#define LAYER_N_14 13
119#define LAYER_N_15 14
120#define LAYER_N_FRONT 15
121#define LAST_COPPER_LAYER LAYER_N_FRONT
122
123#define FIRST_NON_COPPER_LAYER 16
124#define ADHESIVE_N_BACK 16
125#define ADHESIVE_N_FRONT 17
126#define SOLDERPASTE_N_BACK 18
127#define SOLDERPASTE_N_FRONT 19
128#define SILKSCREEN_N_BACK 20
129#define SILKSCREEN_N_FRONT 21
130#define SOLDERMASK_N_BACK 22
131#define SOLDERMASK_N_FRONT 23
132#define DRAW_N 24
133#define COMMENT_N 25
134#define ECO1_N 26
135#define ECO2_N 27
136#define EDGE_N 28
137#define LAST_NON_COPPER_LAYER 28
138
139// Masks to identify a layer by a bit map
140typedef unsigned LAYER_MSK;
141#define LAYER_BACK (1 << LAYER_N_BACK)
142#define LAYER_2 (1 << LAYER_N_2)
143#define LAYER_3 (1 << LAYER_N_3)
144#define LAYER_4 (1 << LAYER_N_4)
145#define LAYER_5 (1 << LAYER_N_5)
146#define LAYER_6 (1 << LAYER_N_6)
147#define LAYER_7 (1 << LAYER_N_7)
148#define LAYER_8 (1 << LAYER_N_8)
149#define LAYER_9 (1 << LAYER_N_9)
150#define LAYER_10 (1 << LAYER_N_10)
151#define LAYER_11 (1 << LAYER_N_11)
152#define LAYER_12 (1 << LAYER_N_12)
153#define LAYER_13 (1 << LAYER_N_13)
154#define LAYER_14 (1 << LAYER_N_14)
155#define LAYER_15 (1 << LAYER_N_15)
156#define LAYER_FRONT (1 << LAYER_N_FRONT)
157#define ADHESIVE_LAYER_BACK (1 << ADHESIVE_N_BACK)
158#define ADHESIVE_LAYER_FRONT (1 << ADHESIVE_N_FRONT)
159#define SOLDERPASTE_LAYER_BACK (1 << SOLDERPASTE_N_BACK)
160#define SOLDERPASTE_LAYER_FRONT (1 << SOLDERPASTE_N_FRONT)
161#define SILKSCREEN_LAYER_BACK (1 << SILKSCREEN_N_BACK)
162#define SILKSCREEN_LAYER_FRONT (1 << SILKSCREEN_N_FRONT)
163#define SOLDERMASK_LAYER_BACK (1 << SOLDERMASK_N_BACK)
164#define SOLDERMASK_LAYER_FRONT (1 << SOLDERMASK_N_FRONT)
165#define DRAW_LAYER (1 << DRAW_N)
166#define COMMENT_LAYER (1 << COMMENT_N)
167#define ECO1_LAYER (1 << ECO1_N)
168#define ECO2_LAYER (1 << ECO2_N)
169#define EDGE_LAYER (1 << EDGE_N)
170
171// Helpful global layer masks:
172// ALL_AUX_LAYERS layers are technical layers, ALL_NO_CU_LAYERS has user
173// and edge layers too!
174#define ALL_NO_CU_LAYERS 0x1FFF0000
175#define ALL_CU_LAYERS 0x0000FFFF
176#define FRONT_TECH_LAYERS (SILKSCREEN_LAYER_FRONT | SOLDERMASK_LAYER_FRONT \
177 | ADHESIVE_LAYER_FRONT | SOLDERPASTE_LAYER_FRONT)
178#define BACK_TECH_LAYERS (SILKSCREEN_LAYER_BACK | SOLDERMASK_LAYER_BACK \
179 | ADHESIVE_LAYER_BACK | SOLDERPASTE_LAYER_BACK)
180#define ALL_TECH_LAYERS (FRONT_TECH_LAYERS | BACK_TECH_LAYERS)
181#define BACK_LAYERS (LAYER_BACK | BACK_TECH_LAYERS)
182#define FRONT_LAYERS (LAYER_FRONT | FRONT_TECH_LAYERS)
183
184#define ALL_USER_LAYERS (DRAW_LAYER | COMMENT_LAYER | ECO1_LAYER | ECO2_LAYER )
185
186#define NO_LAYERS 0x00000000
187
188#define PCB_LEGACY_TEXT_is_REFERENCE 0
189#define PCB_LEGACY_TEXT_is_VALUE 1
190#define PCB_LEGACY_TEXT_is_DIVERS 2 // French for "other"
191
192// Old internal units definition (UI = decimil)
193#define PCB_LEGACY_INTERNAL_UNIT 10000
194
196#define SZ( x ) (sizeof(x)-1)
197
198
199static const char delims[] = " \t\r\n";
200
201
202static bool inline isSpace( int c ) { return strchr( delims, c ) != nullptr; }
203
204#define MASK(x) (1<<(x))
205
206
208{
209 const unsigned PROGRESS_DELTA = 250;
210
212 {
213 unsigned curLine = m_reader->LineNumber();
214
215 if( curLine > m_lastProgressLine + PROGRESS_DELTA )
216 {
217 m_progressReporter->SetCurrentProgress( ( (double) curLine )
218 / std::max( 1U, m_lineCount ) );
219
221 THROW_IO_ERROR( _( "Open cancelled by user." ) );
222
223 m_lastProgressLine = curLine;
224 }
225 }
226}
227
228
229//-----<BOARD Load Functions>---------------------------------------------------
230
232#define TESTLINE( x ) ( !strncasecmp( line, x, SZ( x ) ) && isSpace( line[SZ( x )] ) )
233
235#define TESTSUBSTR( x ) ( !strncasecmp( line, x, SZ( x ) ) )
236
237
238#if 1
239#define READLINE( rdr ) rdr->ReadLine()
240
241#else
245static inline char* ReadLine( LINE_READER* rdr, const char* caller )
246{
247 char* ret = rdr->ReadLine();
248
249 const char* line = rdr->Line();
250
251#if 0 // trap
252 if( !strcmp( "loadSETUP", caller ) && !strcmp( "$EndSETUP\n", line ) )
253 {
254 int breakhere = 1;
255 }
256#endif
257
258 return ret;
259}
260#define READLINE( rdr ) ReadLine( rdr, __FUNCTION__ )
261#endif
262
263
264static GR_TEXT_H_ALIGN_T horizJustify( const char* horizontal )
265{
266 if( !strcmp( "L", horizontal ) )
268
269 if( !strcmp( "R", horizontal ) )
271
273}
274
275static GR_TEXT_V_ALIGN_T vertJustify( const char* vertical )
276{
277 if( !strcmp( "T", vertical ) )
278 return GR_TEXT_V_ALIGN_TOP;
279
280 if( !strcmp( "B", vertical ) )
282
284}
285
286
289{
290 int count = 0;
291
292 while( aMask )
293 {
294 if( aMask & 1 )
295 ++count;
296
297 aMask >>= 1;
298 }
299
300 return count;
301}
302
303
304// return true if aLegacyLayerNum is a valid copper layer legacy id, therefore
305// top, bottom or inner activated layer
306inline bool is_leg_copperlayer_valid( int aCu_Count, int aLegacyLayerNum )
307{
308 return aLegacyLayerNum == LAYER_N_FRONT || aLegacyLayerNum < aCu_Count;
309}
310
311
313{
314 int newid;
315 unsigned old = aLayerNum;
316
317 // this is a speed critical function, be careful.
318
319 if( unsigned( old ) <= unsigned( LAYER_N_FRONT ) )
320 {
321 // In .brd files, the layers are numbered from back to front
322 // (the opposite of the .kicad_pcb files)
323 if( old == LAYER_N_FRONT )
324 {
325 newid = F_Cu;
326 }
327 else if( old == LAYER_N_BACK )
328 {
329 newid = B_Cu;
330 }
331 else
332 {
333 newid = cu_count - 1 - old;
334 wxASSERT( newid >= 0 );
335
336 // This is of course incorrect, but at least it avoid crashing pcbnew:
337 if( newid < 0 )
338 newid = 0;
339 }
340 }
341 else
342 {
343 switch( old )
344 {
345 case ADHESIVE_N_BACK: newid = B_Adhes; break;
346 case ADHESIVE_N_FRONT: newid = F_Adhes; break;
347 case SOLDERPASTE_N_BACK: newid = B_Paste; break;
348 case SOLDERPASTE_N_FRONT: newid = F_Paste; break;
349 case SILKSCREEN_N_BACK: newid = B_SilkS; break;
350 case SILKSCREEN_N_FRONT: newid = F_SilkS; break;
351 case SOLDERMASK_N_BACK: newid = B_Mask; break;
352 case SOLDERMASK_N_FRONT: newid = F_Mask; break;
353 case DRAW_N: newid = Dwgs_User; break;
354 case COMMENT_N: newid = Cmts_User; break;
355 case ECO1_N: newid = Eco1_User; break;
356 case ECO2_N: newid = Eco2_User; break;
357 case EDGE_N: newid = Edge_Cuts; break;
358 default:
359 // Remap all illegal non copper layers to comment layer
360 newid = Cmts_User;
361 }
362 }
363
364 return PCB_LAYER_ID( newid );
365}
366
367
368LSET PCB_IO_KICAD_LEGACY::leg_mask2new( int cu_count, unsigned aMask )
369{
370 LSET ret;
371
372 if( ( aMask & ALL_CU_LAYERS ) == ALL_CU_LAYERS )
373 {
374 ret = LSET::AllCuMask();
375
376 aMask &= ~ALL_CU_LAYERS;
377 }
378
379 for( int i=0; aMask; ++i, aMask >>= 1 )
380 {
381 if( aMask & 1 )
382 ret.set( leg_layer2new( cu_count, i ) );
383 }
384
385 return ret;
386}
387
388
395static inline int intParse( const char* next, const char** out = nullptr )
396{
397 // please just compile this and be quiet, hide casting ugliness:
398 return (int) strtol( next, (char**) out, 10 );
399}
400
401
408static inline long hexParse( const char* next, const char** out = nullptr )
409{
410 // please just compile this and be quiet, hide casting ugliness:
411 return strtol( next, (char**) out, 16 );
412}
413
414
415bool PCB_IO_KICAD_LEGACY::CanReadBoard( const wxString& aFileName ) const
416{
417 if( !PCB_IO::CanReadBoard( aFileName ) )
418 return false;
419
420 try
421 {
422 FILE_LINE_READER tempReader( aFileName );
423 getVersion( &tempReader );
424 }
425 catch( const IO_ERROR& )
426 {
427 return false;
428 }
429
430 return true;
431}
432
433
434bool PCB_IO_KICAD_LEGACY::CanReadFootprint( const wxString& aFileName ) const
435{
436 if( !PCB_IO::CanReadFootprint( aFileName ) )
437 return false;
438
439 try
440 {
441 FILE_LINE_READER freader( aFileName );
442 WHITESPACE_FILTER_READER reader( freader );
443
444 reader.ReadLine();
445 char* line = reader.Line();
446
447 if( !line )
448 return false;
449
450 if( !strncasecmp( line, FOOTPRINT_LIBRARY_HEADER, FOOTPRINT_LIBRARY_HEADER_CNT ) )
451 {
452 while( reader.ReadLine() )
453 {
454 if( !strncasecmp( line, "$MODULE", strlen( "$MODULE" ) ) )
455 {
456 return true;
457 }
458 }
459 }
460 }
461 catch( const IO_ERROR& )
462 {
463 return false;
464 }
465
466 return false;
467}
468
469
470BOARD* PCB_IO_KICAD_LEGACY::LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
471 const STRING_UTF8_MAP* aProperties, PROJECT* aProject )
472{
473 LOCALE_IO toggle; // toggles on, then off, the C locale.
474
475 init( aProperties );
476
477 std::unique_ptr<BOARD> boardDeleter;
478
479 if( aAppendToMe )
480 {
481 m_board = aAppendToMe;
482 }
483 else
484 {
485 boardDeleter = std::make_unique<BOARD>();
486 m_board = boardDeleter.get();
487 }
488
489 // Give the filename to the board if it's new
490 if( !aAppendToMe )
491 m_board->SetFileName( aFileName );
492
493 FILE_LINE_READER reader( aFileName );
494
495 m_reader = &reader;
496
499
501 {
502 m_lineCount = 0;
503
504 m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aFileName ) );
505
507 THROW_IO_ERROR( _( "Open cancelled by user." ) );
508
509 while( reader.ReadLine() )
510 m_lineCount++;
511
512 reader.Rewind();
513 }
514
515 loadAllSections( bool( aAppendToMe ) );
516
517 ignore_unused( boardDeleter.release() ); // give it up so we dont delete it on exit
518 m_progressReporter = nullptr;
519 return m_board;
520}
521
522
524{
525 // $GENERAL section is first
526
527 // $SHEETDESCR section is next
528
529 // $SETUP section is next
530
531 // Then follows $EQUIPOT and all the rest
532 char* line;
533
534 while( ( line = READLINE( m_reader ) ) != nullptr )
535 {
536 checkpoint();
537
538 // put the more frequent ones at the top, but realize TRACKs are loaded as a group
539
540 if( TESTLINE( "$MODULE" ) )
541 {
542 std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( m_board );
543
544 LIB_ID fpid;
545 std::string fpName = StrPurge( line + SZ( "$MODULE" ) );
546
547 // The footprint names in legacy libraries can contain the '/' and ':'
548 // characters which will cause the FPID parser to choke.
550
551 if( !fpName.empty() )
552 fpid.Parse( fpName, true );
553
554 footprint->SetFPID( fpid );
555
556 loadFOOTPRINT( footprint.get());
557 m_board->Add( footprint.release(), ADD_MODE::APPEND );
558 }
559 else if( TESTLINE( "$DRAWSEGMENT" ) )
560 {
561 loadPCB_LINE();
562 }
563 else if( TESTLINE( "$EQUIPOT" ) )
564 {
566 }
567 else if( TESTLINE( "$TEXTPCB" ) )
568 {
569 loadPCB_TEXT();
570 }
571 else if( TESTLINE( "$TRACK" ) )
572 {
574 }
575 else if( TESTLINE( "$NCLASS" ) )
576 {
577 loadNETCLASS();
578 }
579 else if( TESTLINE( "$CZONE_OUTLINE" ) )
580 {
582 }
583 else if( TESTLINE( "$COTATION" ) )
584 {
586 }
587 else if( TESTLINE( "$PCB_TARGET" ) || TESTLINE( "$MIREPCB" ) )
588 {
590 }
591 else if( TESTLINE( "$ZONE" ) )
592 {
593 // No longer supported; discard segment fills
595 }
596 else if( TESTLINE( "$GENERAL" ) )
597 {
598 loadGENERAL();
599 }
600 else if( TESTLINE( "$SHEETDESCR" ) )
601 {
602 loadSHEET();
603 }
604 else if( TESTLINE( "$SETUP" ) )
605 {
606 if( !doAppend )
607 {
608 loadSETUP();
609 }
610 else
611 {
612 while( ( line = READLINE( m_reader ) ) != nullptr )
613 {
614 // gobble until $EndSetup
615 if( TESTLINE( "$EndSETUP" ) )
616 break;
617 }
618 }
619 }
620 else if( TESTLINE( "$EndBOARD" ) )
621 {
622 return; // preferred exit
623 }
624 }
625
626 THROW_IO_ERROR( wxT( "Missing '$EndBOARD'" ) );
627}
628
629
631{
632 // Read first line and TEST if it is a PCB file format header like this:
633 // "PCBNEW-BOARD Version 1 ...."
634
635 aReader->ReadLine();
636
637 char* line = aReader->Line();
638
639 if( !TESTLINE( "PCBNEW-BOARD" ) )
640 {
641 THROW_IO_ERROR( wxT( "Unknown file type" ) );
642 }
643
644 int ver = 1; // if sccanf fails
645 sscanf( line, "PCBNEW-BOARD Version %d", &ver );
646
647 // Some legacy files have a version number = 7, similar to version 2
648 // So use in this case ver = 2
649 if( ver == 7 )
650 ver = 2;
651
652#if !defined( DEBUG )
653 if( ver > LEGACY_BOARD_FILE_VERSION )
654 {
655 THROW_IO_ERROR( wxString::Format( _( "File '%s' has an unrecognized version: %d." ),
656 aReader->GetSource().GetData(), ver ) );
657 }
658#endif
659
660 return ver;
661}
662
663
665{
666 char* line;
667 char* saveptr;
668 bool saw_LayerCount = false;
669
670 while( ( line = READLINE( m_reader ) ) != nullptr )
671 {
672 const char* data;
673
674 if( TESTLINE( "Units" ) )
675 {
676 // what are the engineering units of the lengths in the BOARD?
677 data = strtok_r( line + SZ("Units"), delims, &saveptr );
678
679 if( !strcmp( data, "mm" ) )
680 {
682 }
683 }
684 else if( TESTLINE( "LayerCount" ) )
685 {
686 int tmp = intParse( line + SZ( "LayerCount" ) );
687
689
690 // This has to be set early so that leg_layer2new() works OK, and
691 // that means before parsing "EnabledLayers" and "VisibleLayers".
692 m_cu_count = tmp;
693
694 saw_LayerCount = true;
695 }
696 else if( TESTLINE( "EnabledLayers" ) )
697 {
698 if( !saw_LayerCount )
699 THROW_IO_ERROR( wxT( "Missing '$GENERAL's LayerCount" ) );
700
701 LEG_MASK enabledLayers = hexParse( line + SZ( "EnabledLayers" ) );
702 LSET new_mask = leg_mask2new( m_cu_count, enabledLayers );
703
704 m_board->SetEnabledLayers( new_mask );
705
706 // layer visibility equals layer usage, unless overridden later via "VisibleLayers"
707 // Must call SetEnabledLayers() before calling SetVisibleLayers().
708 m_board->SetVisibleLayers( new_mask );
709
710 // Ensure copper layers count is not modified:
712 }
713 else if( TESTLINE( "VisibleLayers" ) )
714 {
715 // Keep all enabled layers visible.
716 // the old visibility control does not make sense in current Pcbnew version
717 // However, this code works.
718 #if 0
719 if( !saw_LayerCount )
720 THROW_IO_ERROR( wxT( "Missing '$GENERAL's LayerCount" ) );
721
722 LEG_MASK visibleLayers = hexParse( line + SZ( "VisibleLayers" ) );
723
724 LSET new_mask = leg_mask2new( m_cu_count, visibleLayers );
725
726 m_board->SetVisibleLayers( new_mask );
727 #endif
728 }
729 else if( TESTLINE( "Ly" ) ) // Old format for Layer count
730 {
731 if( !saw_LayerCount )
732 {
733 LEG_MASK layer_mask = hexParse( line + SZ( "Ly" ) );
734
737
738 saw_LayerCount = true;
739 }
740 }
741 else if( TESTLINE( "BoardThickness" ) )
742 {
743 BIU thickn = biuParse( line + SZ( "BoardThickness" ) );
745 }
746 else if( TESTLINE( "NoConn" ) )
747 {
748 // ignore
749 intParse( line + SZ( "NoConn" ) );
750 }
751 else if( TESTLINE( "Di" ) )
752 {
753 biuParse( line + SZ( "Di" ), &data );
754 biuParse( data, &data );
755 biuParse( data, &data );
756 biuParse( data );
757 }
758 else if( TESTLINE( "Nnets" ) )
759 {
760 m_netCodes.resize( intParse( line + SZ( "Nnets" ) ) );
761 }
762 else if( TESTLINE( "Nn" ) ) // id "Nnets" for old .brd files
763 {
764 m_netCodes.resize( intParse( line + SZ( "Nn" ) ) );
765 }
766 else if( TESTLINE( "$EndGENERAL" ) )
767 {
768 return; // preferred exit
769 }
770 }
771
772 THROW_IO_ERROR( wxT( "Missing '$EndGENERAL'" ) );
773}
774
775
777{
778 char buf[260];
779 TITLE_BLOCK tb;
780 char* line;
781 char* data;
782
783 while( ( line = READLINE( m_reader ) ) != nullptr )
784 {
785 if( TESTLINE( "Sheet" ) )
786 {
787 // e.g. "Sheet A3 16535 11700"
788 // width and height are in 1/1000th of an inch, always
789 PAGE_INFO page;
790 char* sname = strtok_r( line + SZ( "Sheet" ), delims, &data );
791
792 if( sname )
793 {
794 wxString wname = From_UTF8( sname );
795
796 if( !page.SetType( wname ) )
797 {
798 m_error.Printf( _( "Unknown sheet type '%s' on line: %d." ),
799 wname.GetData(),
800 m_reader->LineNumber() );
802 }
803
804 char* width = strtok_r( nullptr, delims, &data );
805 char* height = strtok_r( nullptr, delims, &data );
806 char* orient = strtok_r( nullptr, delims, &data );
807
808 // only parse the width and height if page size is custom ("User")
809 if( wname == PAGE_INFO::Custom )
810 {
811 if( width && height )
812 {
813 // legacy disk file describes paper in mils
814 // (1/1000th of an inch)
815 int w = intParse( width );
816 int h = intParse( height );
817
818 page.SetWidthMils( w );
819 page.SetHeightMils( h );
820 }
821 }
822
823 if( orient && !strcmp( orient, "portrait" ) )
824 {
825 page.SetPortrait( true );
826 }
827
828 m_board->SetPageSettings( page );
829 }
830 }
831 else if( TESTLINE( "Title" ) )
832 {
833 ReadDelimitedText( buf, line, sizeof(buf) );
834 tb.SetTitle( From_UTF8( buf ) );
835 }
836 else if( TESTLINE( "Date" ) )
837 {
838 ReadDelimitedText( buf, line, sizeof(buf) );
839 tb.SetDate( From_UTF8( buf ) );
840 }
841 else if( TESTLINE( "Rev" ) )
842 {
843 ReadDelimitedText( buf, line, sizeof(buf) );
844 tb.SetRevision( From_UTF8( buf ) );
845 }
846 else if( TESTLINE( "Comp" ) )
847 {
848 ReadDelimitedText( buf, line, sizeof(buf) );
849 tb.SetCompany( From_UTF8( buf ) );
850 }
851 else if( TESTLINE( "Comment1" ) )
852 {
853 ReadDelimitedText( buf, line, sizeof(buf) );
854 tb.SetComment( 0, From_UTF8( buf ) );
855 }
856 else if( TESTLINE( "Comment2" ) )
857 {
858 ReadDelimitedText( buf, line, sizeof(buf) );
859 tb.SetComment( 1, From_UTF8( buf ) );
860 }
861 else if( TESTLINE( "Comment3" ) )
862 {
863 ReadDelimitedText( buf, line, sizeof(buf) );
864 tb.SetComment( 2, From_UTF8( buf ) );
865 }
866 else if( TESTLINE( "Comment4" ) )
867 {
868 ReadDelimitedText( buf, line, sizeof(buf) );
869 tb.SetComment( 3, From_UTF8( buf ) );
870 }
871 else if( TESTLINE( "Comment5" ) )
872 {
873 ReadDelimitedText( buf, line, sizeof(buf) );
874 tb.SetComment( 4, From_UTF8( buf ) );
875 }
876 else if( TESTLINE( "Comment6" ) )
877 {
878 ReadDelimitedText( buf, line, sizeof(buf) );
879 tb.SetComment( 5, From_UTF8( buf ) );
880 }
881 else if( TESTLINE( "Comment7" ) )
882 {
883 ReadDelimitedText( buf, line, sizeof(buf) );
884 tb.SetComment( 6, From_UTF8( buf ) );
885 }
886 else if( TESTLINE( "Comment8" ) )
887 {
888 ReadDelimitedText( buf, line, sizeof(buf) );
889 tb.SetComment( 7, From_UTF8( buf ) );
890 }
891 else if( TESTLINE( "Comment9" ) )
892 {
893 ReadDelimitedText( buf, line, sizeof(buf) );
894 tb.SetComment( 8, From_UTF8( buf ) );
895 }
896 else if( TESTLINE( "$EndSHEETDESCR" ) )
897 {
898 m_board->SetTitleBlock( tb );
899 return; // preferred exit
900 }
901 }
902
903 THROW_IO_ERROR( wxT( "Missing '$EndSHEETDESCR'" ) );
904}
905
906
908{
910 ZONE_SETTINGS zoneSettings = bds.GetDefaultZoneSettings();
911 std::shared_ptr<NETCLASS> defaultNetclass = bds.m_NetSettings->m_DefaultNetClass;
912 char* line;
913 char* saveptr;
914
917
918 while( ( line = READLINE( m_reader ) ) != nullptr )
919 {
920 const char* data;
921
922 if( TESTLINE( "PcbPlotParams" ) )
923 {
924 PCB_PLOT_PARAMS plot_opts;
925
926 PCB_PLOT_PARAMS_PARSER parser( line + SZ( "PcbPlotParams" ), m_reader->GetSource() );
927
928 plot_opts.Parse( &parser );
929
930 m_board->SetPlotOptions( plot_opts );
931
932 if( plot_opts.GetLegacyPlotViaOnMaskLayer().has_value() )
933 {
934 bool tent = *plot_opts.GetLegacyPlotViaOnMaskLayer();
937 }
938 }
939
940 else if( TESTLINE( "AuxiliaryAxisOrg" ) )
941 {
942 BIU gx = biuParse( line + SZ( "AuxiliaryAxisOrg" ), &data );
943 BIU gy = biuParse( data );
944
945 bds.SetAuxOrigin( VECTOR2I( gx, gy ) );
946 }
947 else if( TESTSUBSTR( "Layer[" ) )
948 {
949 // eg: "Layer[n] <a_Layer_name_with_no_spaces> <LAYER_T>"
950
951 int layer_num = intParse( line + SZ( "Layer[" ), &data );
952 PCB_LAYER_ID layer_id = leg_layer2new( m_cu_count, layer_num );
953
954 data = strtok_r( (char*) data+1, delims, &saveptr ); // +1 for ']'
955
956 if( data )
957 {
958 wxString layerName = From_UTF8( data );
959 m_board->SetLayerName( layer_id, layerName );
960
961 data = strtok_r( nullptr, delims, &saveptr );
962
963 if( data ) // optional in old board files
964 {
965 LAYER_T type = LAYER::ParseType( data );
966 m_board->SetLayerType( layer_id, type );
967 }
968 }
969 }
970 else if( TESTLINE( "TrackWidth" ) )
971 {
972 BIU tmp = biuParse( line + SZ( "TrackWidth" ) );
973 defaultNetclass->SetTrackWidth( tmp );
974 }
975 else if( TESTLINE( "TrackWidthList" ) )
976 {
977 BIU tmp = biuParse( line + SZ( "TrackWidthList" ) );
978 bds.m_TrackWidthList.push_back( tmp );
979 }
980 else if( TESTLINE( "TrackClearence" ) )
981 {
982 BIU tmp = biuParse( line + SZ( "TrackClearence" ) );
983 defaultNetclass->SetClearance( tmp );
984 }
985 else if( TESTLINE( "TrackMinWidth" ) )
986 {
987 BIU tmp = biuParse( line + SZ( "TrackMinWidth" ) );
988 bds.m_TrackMinWidth = tmp;
989 }
990 else if( TESTLINE( "ZoneClearence" ) )
991 {
992 BIU tmp = biuParse( line + SZ( "ZoneClearence" ) );
993 zoneSettings.m_ZoneClearance = tmp;
994 }
995 else if( TESTLINE( "Zone_45_Only" ) ) // No longer used
996 {
997 /* bool tmp = (bool) */ intParse( line + SZ( "Zone_45_Only" ) );
998 }
999 else if( TESTLINE( "DrawSegmWidth" ) )
1000 {
1001 BIU tmp = biuParse( line + SZ( "DrawSegmWidth" ) );
1003 }
1004 else if( TESTLINE( "EdgeSegmWidth" ) )
1005 {
1006 BIU tmp = biuParse( line + SZ( "EdgeSegmWidth" ) );
1008 }
1009 else if( TESTLINE( "ViaMinSize" ) )
1010 {
1011 BIU tmp = biuParse( line + SZ( "ViaMinSize" ) );
1012 bds.m_ViasMinSize = tmp;
1013 }
1014 else if( TESTLINE( "MicroViaMinSize" ) )
1015 {
1016 BIU tmp = biuParse( line + SZ( "MicroViaMinSize" ) );
1017 bds.m_MicroViasMinSize = tmp;
1018 }
1019 else if( TESTLINE( "ViaSizeList" ) )
1020 {
1021 // e.g. "ViaSizeList DIAMETER [DRILL]"
1022
1023 BIU drill = 0;
1024 BIU diameter = biuParse( line + SZ( "ViaSizeList" ), &data );
1025
1026 data = strtok_r( (char*) data, delims, (char**) &data );
1027 if( data ) // DRILL may not be present ?
1028 drill = biuParse( data );
1029
1030 bds.m_ViasDimensionsList.emplace_back( diameter, drill );
1031 }
1032 else if( TESTLINE( "ViaSize" ) )
1033 {
1034 BIU tmp = biuParse( line + SZ( "ViaSize" ) );
1035 defaultNetclass->SetViaDiameter( tmp );
1036 }
1037 else if( TESTLINE( "ViaDrill" ) )
1038 {
1039 BIU tmp = biuParse( line + SZ( "ViaDrill" ) );
1040 defaultNetclass->SetViaDrill( tmp );
1041 }
1042 else if( TESTLINE( "ViaMinDrill" ) )
1043 {
1044 BIU tmp = biuParse( line + SZ( "ViaMinDrill" ) );
1045 bds.m_MinThroughDrill = tmp;
1046 }
1047 else if( TESTLINE( "MicroViaSize" ) )
1048 {
1049 BIU tmp = biuParse( line + SZ( "MicroViaSize" ) );
1050 defaultNetclass->SetuViaDiameter( tmp );
1051 }
1052 else if( TESTLINE( "MicroViaDrill" ) )
1053 {
1054 BIU tmp = biuParse( line + SZ( "MicroViaDrill" ) );
1055 defaultNetclass->SetuViaDrill( tmp );
1056 }
1057 else if( TESTLINE( "MicroViaMinDrill" ) )
1058 {
1059 BIU tmp = biuParse( line + SZ( "MicroViaMinDrill" ) );
1060 bds.m_MicroViasMinDrill = tmp;
1061 }
1062 else if( TESTLINE( "MicroViasAllowed" ) )
1063 {
1064 intParse( line + SZ( "MicroViasAllowed" ) );
1065 }
1066 else if( TESTLINE( "TextPcbWidth" ) )
1067 {
1068 BIU tmp = biuParse( line + SZ( "TextPcbWidth" ) );
1070 }
1071 else if( TESTLINE( "TextPcbSize" ) )
1072 {
1073 BIU x = biuParse( line + SZ( "TextPcbSize" ), &data );
1074 BIU y = biuParse( data );
1075
1076 bds.m_TextSize[ LAYER_CLASS_COPPER ] = VECTOR2I( x, y );
1077 }
1078 else if( TESTLINE( "EdgeModWidth" ) )
1079 {
1080 BIU tmp = biuParse( line + SZ( "EdgeModWidth" ) );
1081 bds.m_LineThickness[ LAYER_CLASS_SILK ] = tmp;
1083 }
1084 else if( TESTLINE( "TextModWidth" ) )
1085 {
1086 BIU tmp = biuParse( line + SZ( "TextModWidth" ) );
1087 bds.m_TextThickness[ LAYER_CLASS_SILK ] = tmp;
1089 }
1090 else if( TESTLINE( "TextModSize" ) )
1091 {
1092 BIU x = biuParse( line + SZ( "TextModSize" ), &data );
1093 BIU y = biuParse( data );
1094
1095 bds.m_TextSize[LAYER_CLASS_SILK] = VECTOR2I( x, y );
1096 bds.m_TextSize[LAYER_CLASS_OTHERS] = VECTOR2I( x, y );
1097 }
1098 else if( TESTLINE( "PadSize" ) )
1099 {
1100 BIU x = biuParse( line + SZ( "PadSize" ), &data );
1101 BIU y = biuParse( data );
1102
1103 bds.m_Pad_Master->SetSize( VECTOR2I( x, y ) );
1104 }
1105 else if( TESTLINE( "PadDrill" ) )
1106 {
1107 BIU tmp = biuParse( line + SZ( "PadDrill" ) );
1108 bds.m_Pad_Master->SetDrillSize( VECTOR2I( tmp, tmp ) );
1109 }
1110 else if( TESTLINE( "Pad2MaskClearance" ) )
1111 {
1112 BIU tmp = biuParse( line + SZ( "Pad2MaskClearance" ) );
1113 bds.m_SolderMaskExpansion = tmp;
1114 }
1115 else if( TESTLINE( "SolderMaskMinWidth" ) )
1116 {
1117 BIU tmp = biuParse( line + SZ( "SolderMaskMinWidth" ) );
1118 bds.m_SolderMaskMinWidth = tmp;
1119 }
1120 else if( TESTLINE( "Pad2PasteClearance" ) )
1121 {
1122 BIU tmp = biuParse( line + SZ( "Pad2PasteClearance" ) );
1123 bds.m_SolderPasteMargin = tmp;
1124 }
1125 else if( TESTLINE( "Pad2PasteClearanceRatio" ) )
1126 {
1127 double ratio = atof( line + SZ( "Pad2PasteClearanceRatio" ) );
1128 bds.m_SolderPasteMarginRatio = ratio;
1129 }
1130
1131 else if( TESTLINE( "GridOrigin" ) )
1132 {
1133 BIU x = biuParse( line + SZ( "GridOrigin" ), &data );
1134 BIU y = biuParse( data );
1135
1136 bds.SetGridOrigin( VECTOR2I( x, y ) );
1137 }
1138 else if( TESTLINE( "VisibleElements" ) )
1139 {
1140 // Keep all elements visible.
1141 // the old visibility control does not make sense in current Pcbnew version,
1142 // and this code does not work.
1143#if 0
1144 int visibleElements = hexParse( line + SZ( "VisibleElements" ) );
1145
1146 // Does not work: each old item should be tested one by one to set
1147 // visibility of new item list
1148 GAL_SET visibles;
1149
1150 for( size_t i = 0; i < visibles.size(); i++ )
1151 visibles.set( i, visibleElements & ( 1u << i ) );
1152
1153 m_board->SetVisibleElements( visibles );
1154#endif
1155 }
1156 else if( TESTLINE( "$EndSETUP" ) )
1157 {
1158 bds.SetDefaultZoneSettings( zoneSettings );
1159
1160 // Very old *.brd file does not have NETCLASSes
1161 // "TrackWidth", "ViaSize", "ViaDrill", "ViaMinSize", and "TrackClearence" were
1162 // defined in SETUP; these values are put into the default NETCLASS until later board
1163 // load code should override them. *.brd files which have been saved with knowledge
1164 // of NETCLASSes will override these defaults, very old boards (before 2009) will not
1165 // and use the setup values.
1166 // However these values should be the same as default NETCLASS.
1167
1168 return; // preferred exit
1169 }
1170 }
1171
1172 /*
1173 * Ensure tracks and vias sizes lists are ok:
1174 * Sort lists by by increasing value and remove duplicates
1175 * (the first value is not tested, because it is the netclass value)
1176 */
1177 BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
1178 sort( designSettings.m_ViasDimensionsList.begin() + 1,
1179 designSettings.m_ViasDimensionsList.end() );
1180 sort( designSettings.m_TrackWidthList.begin() + 1, designSettings.m_TrackWidthList.end() );
1181
1182 for( unsigned ii = 1; ii < designSettings.m_ViasDimensionsList.size() - 1; ii++ )
1183 {
1184 if( designSettings.m_ViasDimensionsList[ii] == designSettings.m_ViasDimensionsList[ii + 1] )
1185 {
1186 designSettings.m_ViasDimensionsList.erase( designSettings.m_ViasDimensionsList.begin() + ii );
1187 ii--;
1188 }
1189 }
1190
1191 for( unsigned ii = 1; ii < designSettings.m_TrackWidthList.size() - 1; ii++ )
1192 {
1193 if( designSettings.m_TrackWidthList[ii] == designSettings.m_TrackWidthList[ii + 1] )
1194 {
1195 designSettings.m_TrackWidthList.erase( designSettings.m_TrackWidthList.begin() + ii );
1196 ii--;
1197 }
1198 }
1199}
1200
1201
1203{
1204 char* line;
1205
1206 while( ( line = READLINE( m_reader ) ) != nullptr )
1207 {
1208 const char* data;
1209
1210 // most frequently encountered ones at the top
1211
1212 if( TESTSUBSTR( "D" ) && strchr( "SCAP", line[1] ) ) // read a drawing item, e.g. "DS"
1213 {
1214 loadFP_SHAPE( aFootprint );
1215 }
1216 else if( TESTLINE( "$PAD" ) )
1217 {
1218 loadPAD( aFootprint );
1219 }
1220 else if( TESTSUBSTR( "T" ) ) // Read a footprint text description (ref, value, or drawing)
1221 {
1222 // e.g. "T1 6940 -16220 350 300 900 60 M I 20 N "CFCARD"\r\n"
1223 int tnum = intParse( line + SZ( "T" ) );
1224
1225 PCB_TEXT* text = nullptr;
1226
1227 switch( tnum )
1228 {
1230 text = &aFootprint->Reference();
1231 break;
1232
1234 text = &aFootprint->Value();
1235 break;
1236
1237 // All other fields greater than 1.
1238 default:
1239 text = new PCB_TEXT( aFootprint );
1240 aFootprint->Add( text );
1241 }
1242
1244 }
1245 else if( TESTLINE( "Po" ) )
1246 {
1247 // e.g. "Po 19120 39260 900 0 4E823D06 68183921-93a5-49ac-91b0-49d05a0e1647 ~~\r\n"
1248 BIU pos_x = biuParse( line + SZ( "Po" ), &data );
1249 BIU pos_y = biuParse( data, &data );
1250 int orient = intParse( data, &data );
1251 int layer_num = intParse( data, &data );
1252 PCB_LAYER_ID layer_id = leg_layer2new( m_cu_count, layer_num );
1253
1254 [[maybe_unused]] long edittime = hexParse( data, &data );
1255
1256 char* uuid = strtok_r( (char*) data, delims, (char**) &data );
1257
1258 data = strtok_r( (char*) data+1, delims, (char**) &data );
1259
1260 // data is now a two character long string
1261 // Note: some old files do not have this field
1262 if( data && data[0] == 'F' )
1263 aFootprint->SetLocked( true );
1264
1265 if( data && data[1] == 'P' )
1266 aFootprint->SetIsPlaced( true );
1267
1268 aFootprint->SetPosition( VECTOR2I( pos_x, pos_y ) );
1269 aFootprint->SetLayer( layer_id );
1270 aFootprint->SetOrientation( EDA_ANGLE( orient, TENTHS_OF_A_DEGREE_T ) );
1271 const_cast<KIID&>( aFootprint->m_Uuid ) = KIID( uuid );
1272 }
1273 else if( TESTLINE( "Sc" ) ) // timestamp
1274 {
1275 char* uuid = strtok_r( (char*) line + SZ( "Sc" ), delims, (char**) &data );
1276 const_cast<KIID&>( aFootprint->m_Uuid ) = KIID( uuid );
1277 }
1278 else if( TESTLINE( "Op" ) ) // (Op)tions for auto placement (no longer supported)
1279 {
1280 hexParse( line + SZ( "Op" ), &data );
1281 hexParse( data );
1282 }
1283 else if( TESTLINE( "At" ) ) // (At)tributes of footprint
1284 {
1285 int attrs = 0;
1286
1287 data = line + SZ( "At" );
1288
1289 if( strstr( data, "SMD" ) )
1290 attrs |= FP_SMD;
1291 else if( strstr( data, "VIRTUAL" ) )
1293 else
1295
1296 aFootprint->SetAttributes( attrs );
1297 }
1298 else if( TESTLINE( "AR" ) ) // Alternate Reference
1299 {
1300 // e.g. "AR /68183921-93a5-49ac-e164-49d05a0e1647/93a549d0-49d0-e164-91b0-49d05a0e1647"
1301 data = strtok_r( line + SZ( "AR" ), delims, (char**) &data );
1302
1303 if( data )
1304 aFootprint->SetPath( KIID_PATH( From_UTF8( data ) ) );
1305 }
1306 else if( TESTLINE( "$SHAPE3D" ) )
1307 {
1308 load3D( aFootprint );
1309 }
1310 else if( TESTLINE( "Cd" ) )
1311 {
1312 // e.g. "Cd Double rangee de contacts 2 x 4 pins\r\n"
1313 aFootprint->SetLibDescription( From_UTF8( StrPurge( line + SZ( "Cd" ) ) ) );
1314 }
1315 else if( TESTLINE( "Kw" ) ) // Key words
1316 {
1317 aFootprint->SetKeywords( From_UTF8( StrPurge( line + SZ( "Kw" ) ) ) );
1318 }
1319 else if( TESTLINE( ".SolderPasteRatio" ) )
1320 {
1321 double tmp = atof( line + SZ( ".SolderPasteRatio" ) );
1322
1323 // Due to a bug in dialog editor in Footprint Editor, fixed in BZR version 3565
1324 // this parameter can be broken.
1325 // It should be >= -50% (no solder paste) and <= 0% (full area of the pad)
1326
1327 if( tmp < -0.50 )
1328 tmp = -0.50;
1329
1330 if( tmp > 0.0 )
1331 tmp = 0.0;
1332
1333 aFootprint->SetLocalSolderPasteMarginRatio( tmp );
1334 }
1335 else if( TESTLINE( ".SolderPaste" ) )
1336 {
1337 BIU tmp = biuParse( line + SZ( ".SolderPaste" ) );
1338 aFootprint->SetLocalSolderPasteMargin( tmp );
1339 }
1340 else if( TESTLINE( ".SolderMask" ) )
1341 {
1342 BIU tmp = biuParse( line + SZ( ".SolderMask" ) );
1343 aFootprint->SetLocalSolderMaskMargin( tmp );
1344 }
1345 else if( TESTLINE( ".LocalClearance" ) )
1346 {
1347 BIU tmp = biuParse( line + SZ( ".LocalClearance" ) );
1348 aFootprint->SetLocalClearance( tmp );
1349 }
1350 else if( TESTLINE( ".ZoneConnection" ) )
1351 {
1352 int tmp = intParse( line + SZ( ".ZoneConnection" ) );
1353 aFootprint->SetLocalZoneConnection((ZONE_CONNECTION) tmp );
1354 }
1355 else if( TESTLINE( ".ThermalWidth" ) )
1356 {
1357 BIU tmp = biuParse( line + SZ( ".ThermalWidth" ) );
1358 ignore_unused( tmp );
1359 }
1360 else if( TESTLINE( ".ThermalGap" ) )
1361 {
1362 BIU tmp = biuParse( line + SZ( ".ThermalGap" ) );
1363 ignore_unused( tmp );
1364 }
1365 else if( TESTLINE( "$EndMODULE" ) )
1366 {
1367 return; // preferred exit
1368 }
1369 }
1370
1371 wxString msg = wxString::Format( _( "Missing '$EndMODULE' for MODULE '%s'." ),
1372 aFootprint->GetFPID().GetLibItemName().wx_str() );
1373 THROW_IO_ERROR( msg );
1374}
1375
1376
1378{
1379 std::unique_ptr<PAD> pad = std::make_unique<PAD>( aFootprint );
1380 char* line;
1381 char* saveptr;
1382
1383 while( ( line = READLINE( m_reader ) ) != nullptr )
1384 {
1385 const char* data;
1386
1387 if( TESTLINE( "Sh" ) ) // (Sh)ape and padname
1388 {
1389 // e.g. "Sh "A2" C 520 520 0 0 900"
1390 // or "Sh "1" R 157 1378 0 0 900"
1391
1392 // mypadnumber is LATIN1/CRYLIC for BOARD_FORMAT_VERSION 1, but for
1393 // BOARD_FORMAT_VERSION 2, it is UTF8 from disk.
1394 // Moving forward padnumbers will be in UTF8 on disk, as are all KiCad strings on disk.
1395 char mypadnumber[50];
1396
1397 data = line + SZ( "Sh" ) + 1; // +1 skips trailing whitespace
1398
1399 // +1 trailing whitespace.
1400 data = data + ReadDelimitedText( mypadnumber, data, sizeof( mypadnumber ) ) + 1;
1401
1402 while( isSpace( *data ) )
1403 ++data;
1404
1405 unsigned char padchar = (unsigned char) *data++;
1406 int padshape;
1407
1408 BIU size_x = biuParse( data, &data );
1409 BIU size_y = biuParse( data, &data );
1410 BIU delta_x = biuParse( data, &data );
1411 BIU delta_y = biuParse( data, &data );
1412 EDA_ANGLE orient = degParse( data );
1413
1414 switch( padchar )
1415 {
1416 case 'C': padshape = static_cast<int>( PAD_SHAPE::CIRCLE ); break;
1417 case 'R': padshape = static_cast<int>( PAD_SHAPE::RECTANGLE ); break;
1418 case 'O': padshape = static_cast<int>( PAD_SHAPE::OVAL ); break;
1419 case 'T': padshape = static_cast<int>( PAD_SHAPE::TRAPEZOID ); break;
1420 default:
1421 m_error.Printf( _( "Unknown padshape '%c=0x%02x' on line: %d of footprint: '%s'." ),
1422 padchar, padchar, m_reader->LineNumber(),
1423 aFootprint->GetFPID().GetLibItemName().wx_str() );
1425 }
1426
1427 // go through a wxString to establish a universal character set properly
1428 wxString padNumber;
1429
1430 if( m_loading_format_version == 1 )
1431 {
1432 // add 8 bit bytes, file format 1 was KiCad font type byte,
1433 // simply promote those 8 bit bytes up into UNICODE. (subset of LATIN1)
1434 const unsigned char* cp = (unsigned char*) mypadnumber;
1435
1436 while( *cp )
1437 padNumber += *cp++; // unsigned, ls 8 bits only
1438 }
1439 else
1440 {
1441 // version 2, which is UTF8.
1442 padNumber = From_UTF8( mypadnumber );
1443 }
1444
1445 // chances are both were ASCII, but why take chances?
1446
1447 pad->SetNumber( padNumber );
1448 pad->SetShape( static_cast<PAD_SHAPE>( padshape ) );
1449 pad->SetSize( VECTOR2I( size_x, size_y ) );
1450 pad->SetDelta( VECTOR2I( delta_x, delta_y ) );
1451 pad->SetOrientation( orient );
1452 }
1453 else if( TESTLINE( "Dr" ) ) // (Dr)ill
1454 {
1455 // e.g. "Dr 350 0 0" or "Dr 0 0 0 O 0 0"
1456 BIU drill_x = biuParse( line + SZ( "Dr" ), &data );
1457 BIU drill_y = drill_x;
1458 BIU offs_x = biuParse( data, &data );
1459 BIU offs_y = biuParse( data, &data );
1460
1461 PAD_DRILL_SHAPE drShape = PAD_DRILL_SHAPE::CIRCLE;
1462
1463 data = strtok_r( (char*) data, delims, &saveptr );
1464
1465 if( data ) // optional shape
1466 {
1467 if( data[0] == 'O' )
1468 {
1469 drShape = PAD_DRILL_SHAPE::OBLONG;
1470
1471 data = strtok_r( nullptr, delims, &saveptr );
1472 drill_x = biuParse( data );
1473
1474 data = strtok_r( nullptr, delims, &saveptr );
1475 drill_y = biuParse( data );
1476 }
1477 }
1478
1479 pad->SetDrillShape( drShape );
1480 pad->SetOffset( VECTOR2I( offs_x, offs_y ) );
1481 pad->SetDrillSize( VECTOR2I( drill_x, drill_y ) );
1482 }
1483 else if( TESTLINE( "At" ) ) // (At)tribute
1484 {
1485 // e.g. "At SMD N 00888000"
1486 // sscanf( PtLine, "%s %s %X", BufLine, BufCar, &m_layerMask );
1487
1488 PAD_ATTRIB attribute;
1489
1490 data = strtok_r( line + SZ( "At" ), delims, &saveptr );
1491
1492 if( !strcmp( data, "SMD" ) )
1493 attribute = PAD_ATTRIB::SMD;
1494 else if( !strcmp( data, "CONN" ) )
1495 attribute = PAD_ATTRIB::CONN;
1496 else if( !strcmp( data, "HOLE" ) )
1497 attribute = PAD_ATTRIB::NPTH;
1498 else
1499 attribute = PAD_ATTRIB::PTH;
1500
1501 strtok_r( nullptr, delims, &saveptr ); // skip unused prm
1502 data = strtok_r( nullptr, delims, &saveptr );
1503
1504 LEG_MASK layer_mask = hexParse( data );
1505
1506 pad->SetLayerSet( leg_mask2new( m_cu_count, layer_mask ) );
1507 pad->SetAttribute( attribute );
1508 }
1509 else if( TESTLINE( "Ne" ) ) // (Ne)tname
1510 {
1511 // e.g. "Ne 461 "V5.0"
1512
1513 char buf[1024]; // can be fairly long
1514 int netcode = intParse( line + SZ( "Ne" ), &data );
1515
1516 // Store the new code mapping
1517 pad->SetNetCode( getNetCode( netcode ) );
1518
1519 // read Netname
1520 ReadDelimitedText( buf, data, sizeof(buf) );
1521
1522 if( m_board )
1523 {
1524 wxASSERT( m_board->FindNet( getNetCode( netcode ) )->GetNetname()
1526 }
1527 }
1528 else if( TESTLINE( "Po" ) ) // (Po)sition
1529 {
1530 // e.g. "Po 500 -500"
1531 VECTOR2I pos;
1532
1533 pos.x = biuParse( line + SZ( "Po" ), &data );
1534 pos.y = biuParse( data );
1535
1536 pad->SetFPRelativePosition( pos );
1537 }
1538 else if( TESTLINE( "Le" ) )
1539 {
1540 BIU tmp = biuParse( line + SZ( "Le" ) );
1541 pad->SetPadToDieLength( tmp );
1542 }
1543 else if( TESTLINE( ".SolderMask" ) )
1544 {
1545 BIU tmp = biuParse( line + SZ( ".SolderMask" ) );
1546 pad->SetLocalSolderMaskMargin( tmp );
1547 }
1548 else if( TESTLINE( ".SolderPasteRatio" ) )
1549 {
1550 double tmp = atof( line + SZ( ".SolderPasteRatio" ) );
1551 pad->SetLocalSolderPasteMarginRatio( tmp );
1552 }
1553 else if( TESTLINE( ".SolderPaste" ) )
1554 {
1555 BIU tmp = biuParse( line + SZ( ".SolderPaste" ) );
1556 pad->SetLocalSolderPasteMargin( tmp );
1557 }
1558 else if( TESTLINE( ".LocalClearance" ) )
1559 {
1560 BIU tmp = biuParse( line + SZ( ".LocalClearance" ) );
1561 pad->SetLocalClearance( tmp );
1562 }
1563 else if( TESTLINE( ".ZoneConnection" ) )
1564 {
1565 int tmp = intParse( line + SZ( ".ZoneConnection" ) );
1566 pad->SetLocalZoneConnection( (ZONE_CONNECTION) tmp );
1567 }
1568 else if( TESTLINE( ".ThermalWidth" ) )
1569 {
1570 BIU tmp = biuParse( line + SZ( ".ThermalWidth" ) );
1571 pad->SetThermalSpokeWidth( tmp );
1572 }
1573 else if( TESTLINE( ".ThermalGap" ) )
1574 {
1575 BIU tmp = biuParse( line + SZ( ".ThermalGap" ) );
1576 pad->SetThermalGap( tmp );
1577 }
1578 else if( TESTLINE( "$EndPAD" ) )
1579 {
1580 if( pad->GetSizeX() > 0 && pad->GetSizeY() > 0 )
1581 {
1582 aFootprint->Add( pad.release() );
1583 }
1584 else
1585 {
1586 wxLogError( _( "Invalid zero-sized pad ignored in\nfile: %s" ),
1587 m_reader->GetSource() );
1588 }
1589
1590 return; // preferred exit
1591 }
1592 }
1593
1594 THROW_IO_ERROR( wxT( "Missing '$EndPAD'" ) );
1595}
1596
1597
1599{
1600 SHAPE_T shape;
1601 char* line = m_reader->Line(); // obtain current (old) line
1602
1603 switch( line[1] )
1604 {
1605 case 'S': shape = SHAPE_T::SEGMENT; break;
1606 case 'C': shape = SHAPE_T::CIRCLE; break;
1607 case 'A': shape = SHAPE_T::ARC; break;
1608 case 'P': shape = SHAPE_T::POLY; break;
1609 default:
1610 m_error.Printf( _( "Unknown PCB_SHAPE type:'%c=0x%02x' on line %d of footprint '%s'." ),
1611 (unsigned char) line[1], (unsigned char) line[1], m_reader->LineNumber(),
1612 aFootprint->GetFPID().GetLibItemName().wx_str() );
1614 }
1615
1616 std::unique_ptr<PCB_SHAPE> dwg = std::make_unique<PCB_SHAPE>( aFootprint, shape ); // a drawing
1617
1618 const char* data;
1619
1620 // common to all cases, and we have to check their values uniformly at end
1621 BIU width = 1;
1622 int layer = FIRST_NON_COPPER_LAYER;
1623
1624 switch( shape )
1625 {
1626 case SHAPE_T::ARC:
1627 {
1628 BIU center0_x = biuParse( line + SZ( "DA" ), &data );
1629 BIU center0_y = biuParse( data, &data );
1630 BIU start0_x = biuParse( data, &data );
1631 BIU start0_y = biuParse( data, &data );
1632 EDA_ANGLE angle = degParse( data, &data );
1633
1634 width = biuParse( data, &data );
1635 layer = intParse( data );
1636
1637 dwg->SetCenter( VECTOR2I( center0_x, center0_y ) );
1638 dwg->SetStart( VECTOR2I( start0_x, start0_y ) );
1639 dwg->SetArcAngleAndEnd( angle, true );
1640 break;
1641 }
1642
1643 case SHAPE_T::SEGMENT:
1644 case SHAPE_T::CIRCLE:
1645 {
1646 // e.g. "DS -7874 -10630 7874 -10630 50 20\r\n"
1647 BIU start0_x = biuParse( line + SZ( "DS" ), &data );
1648 BIU start0_y = biuParse( data, &data );
1649 BIU end0_x = biuParse( data, &data );
1650 BIU end0_y = biuParse( data, &data );
1651
1652 width = biuParse( data, &data );
1653 layer = intParse( data );
1654
1655 dwg->SetStart( VECTOR2I( start0_x, start0_y ) );
1656 dwg->SetEnd( VECTOR2I( end0_x, end0_y ) );
1657 break;
1658 }
1659
1660 case SHAPE_T::POLY:
1661 {
1662 // e.g. "DP %d %d %d %d %d %d %d\n"
1663 BIU start0_x = biuParse( line + SZ( "DP" ), &data );
1664 BIU start0_y = biuParse( data, &data );
1665 BIU end0_x = biuParse( data, &data );
1666 BIU end0_y = biuParse( data, &data );
1667 int ptCount = intParse( data, &data );
1668
1669 width = biuParse( data, &data );
1670 layer = intParse( data );
1671
1672 dwg->SetStart( VECTOR2I( start0_x, start0_y ) );
1673 dwg->SetEnd( VECTOR2I( end0_x, end0_y ) );
1674
1675 std::vector<VECTOR2I> pts;
1676 pts.reserve( ptCount );
1677
1678 for( int ii = 0; ii < ptCount; ++ii )
1679 {
1680 if( ( line = READLINE( m_reader ) ) == nullptr )
1681 {
1682 THROW_IO_ERROR( wxT( "S_POLGON point count mismatch." ) );
1683 }
1684
1685 // e.g. "Dl 23 44\n"
1686
1687 if( !TESTLINE( "Dl" ) )
1688 {
1689 THROW_IO_ERROR( wxT( "Missing Dl point def" ) );
1690 }
1691
1692 BIU x = biuParse( line + SZ( "Dl" ), &data );
1693 BIU y = biuParse( data );
1694
1695 pts.emplace_back( x, y );
1696 }
1697
1698 dwg->SetPolyPoints( pts );
1699 break;
1700 }
1701
1702 default:
1703 // first switch code above prevents us from getting here.
1704 break;
1705 }
1706
1707 // Check for a reasonable layer:
1708 // layer must be >= FIRST_NON_COPPER_LAYER, but because microwave footprints can use the
1709 // copper layers, layer < FIRST_NON_COPPER_LAYER is allowed.
1710 if( layer < FIRST_LAYER || layer > LAST_NON_COPPER_LAYER )
1711 layer = SILKSCREEN_N_FRONT;
1712
1713 dwg->SetStroke( STROKE_PARAMS( width, LINE_STYLE::SOLID ) );
1714 dwg->SetLayer( leg_layer2new( m_cu_count, layer ) );
1715
1716 dwg->Rotate( { 0, 0 }, aFootprint->GetOrientation() );
1717 dwg->Move( aFootprint->GetPosition() );
1718 aFootprint->Add( dwg.release() );
1719}
1720
1721
1723{
1724 const char* data;
1725 const char* txt_end;
1726 const char* line = m_reader->Line(); // current (old) line
1727
1728 // e.g. "T1 6940 -16220 350 300 900 60 M I 20 N "CFCARD"\r\n"
1729 // or T1 0 500 600 400 900 80 M V 20 N"74LS245"
1730 // ouch, the last example has no space between N and "74LS245" !
1731 // that is an older version.
1732
1733 int type = intParse( line+1, &data );
1734 BIU pos0_x = biuParse( data, &data );
1735 BIU pos0_y = biuParse( data, &data );
1736 BIU size0_y = biuParse( data, &data );
1737 BIU size0_x = biuParse( data, &data );
1738 EDA_ANGLE orient = degParse( data, &data );
1739 BIU thickn = biuParse( data, &data );
1740
1741 // read the quoted text before the first call to strtok() which introduces
1742 // NULs into the string and chops it into multiple C strings, something
1743 // ReadDelimitedText() cannot traverse.
1744
1745 // convert the "quoted, escaped, UTF8, text" to a wxString, find it by skipping
1746 // as far forward as needed until the first double quote.
1747 txt_end = data + ReadDelimitedText( &m_field, data );
1748 m_field.Replace( wxT( "%V" ), wxT( "${VALUE}" ) );
1749 m_field.Replace( wxT( "%R" ), wxT( "${REFERENCE}" ) );
1751 aText->SetText( m_field );
1752
1753 // after switching to strtok, there's no easy coming back because of the
1754 // embedded nul(s?) placed to the right of the current field.
1755 // (that's the reason why strtok was deprecated...)
1756 char* mirror = strtok_r( (char*) data, delims, (char**) &data );
1757 char* hide = strtok_r( nullptr, delims, (char**) &data );
1758 char* tmp = strtok_r( nullptr, delims, (char**) &data );
1759
1760 int layer_num = tmp ? intParse( tmp ) : SILKSCREEN_N_FRONT;
1761
1762 char* italic = strtok_r( nullptr, delims, (char**) &data );
1763
1764 char* hjust = strtok_r( (char*) txt_end, delims, (char**) &data );
1765 char* vjust = strtok_r( nullptr, delims, (char**) &data );
1766
1769
1770 aText->SetFPRelativePosition( VECTOR2I( pos0_x, pos0_y ) );
1771 aText->SetTextSize( VECTOR2I( size0_x, size0_y ) );
1772
1773 aText->SetTextAngle( orient );
1774
1775 aText->SetTextThickness( thickn < 1 ? 0 : thickn );
1776
1777 aText->SetMirrored( mirror && *mirror == 'M' );
1778
1779 aText->SetVisible( !(hide && *hide == 'I') );
1780
1781 aText->SetItalic( italic && *italic == 'I' );
1782
1783 if( hjust )
1784 aText->SetHorizJustify( horizJustify( hjust ) );
1785
1786 if( vjust )
1787 aText->SetVertJustify( vertJustify( vjust ) );
1788
1789 // A protection against mal formed (or edited by hand) files:
1790 if( layer_num < FIRST_LAYER )
1791 layer_num = FIRST_LAYER;
1792 else if( layer_num > LAST_NON_COPPER_LAYER )
1793 layer_num = LAST_NON_COPPER_LAYER;
1794 else if( layer_num == LAYER_N_BACK )
1795 layer_num = SILKSCREEN_N_BACK;
1796 else if( layer_num == LAYER_N_FRONT )
1797 layer_num = SILKSCREEN_N_FRONT;
1798 else if( layer_num < LAYER_N_FRONT ) // this case is a internal layer
1799 layer_num = SILKSCREEN_N_FRONT;
1800
1801 aText->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
1802}
1803
1804
1806{
1807 FP_3DMODEL t3D;
1808
1809 char* line;
1810
1811 while( ( line = READLINE( m_reader ) ) != nullptr )
1812 {
1813 if( TESTLINE( "Na" ) ) // Shape File Name
1814 {
1815 char buf[512];
1816 ReadDelimitedText( buf, line + SZ( "Na" ), sizeof(buf) );
1817 t3D.m_Filename = buf;
1818 }
1819 else if( TESTLINE( "Sc" ) ) // Scale
1820 {
1821 sscanf( line + SZ( "Sc" ), "%lf %lf %lf\n", &t3D.m_Scale.x, &t3D.m_Scale.y,
1822 &t3D.m_Scale.z );
1823 }
1824 else if( TESTLINE( "Of" ) ) // Offset
1825 {
1826 sscanf( line + SZ( "Of" ), "%lf %lf %lf\n", &t3D.m_Offset.x, &t3D.m_Offset.y,
1827 &t3D.m_Offset.z );
1828 }
1829 else if( TESTLINE( "Ro" ) ) // Rotation
1830 {
1831 sscanf( line + SZ( "Ro" ), "%lf %lf %lf\n", &t3D.m_Rotation.x, &t3D.m_Rotation.y,
1832 &t3D.m_Rotation.z );
1833 }
1834 else if( TESTLINE( "$EndSHAPE3D" ) )
1835 {
1836 aFootprint->Models().push_back( t3D );
1837 return; // preferred exit
1838 }
1839 }
1840
1841 THROW_IO_ERROR( wxT( "Missing '$EndSHAPE3D'" ) );
1842}
1843
1844
1846{
1847 /* example:
1848 $DRAWSEGMENT
1849 Po 0 57500 -1000 57500 0 150
1850 De 24 0 900 0 0
1851 $EndDRAWSEGMENT
1852 */
1853
1854 std::unique_ptr<PCB_SHAPE> dseg = std::make_unique<PCB_SHAPE>( m_board );
1855
1856 char* line;
1857 char* saveptr;
1858
1859 while( ( line = READLINE( m_reader ) ) != nullptr )
1860 {
1861 const char* data;
1862
1863 if( TESTLINE( "Po" ) )
1864 {
1865 int shape = intParse( line + SZ( "Po" ), &data );
1866 BIU start_x = biuParse( data, &data );
1867 BIU start_y = biuParse( data, &data );
1868 BIU end_x = biuParse( data, &data );
1869 BIU end_y = biuParse( data, &data );
1870 BIU width = biuParse( data );
1871
1872 if( width < 0 )
1873 width = 0;
1874
1875 dseg->SetShape( static_cast<SHAPE_T>( shape ) );
1876 dseg->SetFilled( false );
1877 dseg->SetStroke( STROKE_PARAMS( width, LINE_STYLE::SOLID ) );
1878
1879 if( dseg->GetShape() == SHAPE_T::ARC )
1880 {
1881 dseg->SetCenter( VECTOR2I( start_x, start_y ) );
1882 dseg->SetStart( VECTOR2I( end_x, end_y ) );
1883 }
1884 else
1885 {
1886 dseg->SetStart( VECTOR2I( start_x, start_y ) );
1887 dseg->SetEnd( VECTOR2I( end_x, end_y ) );
1888 }
1889 }
1890 else if( TESTLINE( "De" ) )
1891 {
1892 BIU x = 0;
1893 BIU y;
1894
1895 data = strtok_r( line + SZ( "De" ), delims, &saveptr );
1896
1897 for( int i = 0; data; ++i, data = strtok_r( nullptr, delims, &saveptr ) )
1898 {
1899 switch( i )
1900 {
1901 case 0:
1902 int layer;
1903 layer = intParse( data );
1904
1905 if( layer < FIRST_NON_COPPER_LAYER )
1906 layer = FIRST_NON_COPPER_LAYER;
1907
1908 else if( layer > LAST_NON_COPPER_LAYER )
1909 layer = LAST_NON_COPPER_LAYER;
1910
1911 dseg->SetLayer( leg_layer2new( m_cu_count, layer ) );
1912 break;
1913 case 1:
1914 ignore_unused( intParse( data ) );
1915 break;
1916 case 2:
1917 {
1918 EDA_ANGLE angle = degParse( data );
1919
1920 if( dseg->GetShape() == SHAPE_T::ARC )
1921 dseg->SetArcAngleAndEnd( angle );
1922
1923 break;
1924 }
1925 case 3:
1926 const_cast<KIID&>( dseg->m_Uuid ) = KIID( data );
1927 break;
1928 case 4:
1929 {
1930 // Ignore state data
1931 hexParse( data );
1932 break;
1933 }
1934 // Bezier Control Points
1935 case 5:
1936 x = biuParse( data );
1937 break;
1938 case 6:
1939 y = biuParse( data );
1940 dseg->SetBezierC1( VECTOR2I( x, y ) );
1941 break;
1942 case 7:
1943 x = biuParse( data );
1944 break;
1945 case 8:
1946 y = biuParse( data );
1947 dseg->SetBezierC2( VECTOR2I( x, y ) );
1948 break;
1949
1950 default:
1951 break;
1952 }
1953 }
1954 }
1955 else if( TESTLINE( "$EndDRAWSEGMENT" ) )
1956 {
1957 m_board->Add( dseg.release(), ADD_MODE::APPEND );
1958 return; // preferred exit
1959 }
1960 }
1961
1962 THROW_IO_ERROR( wxT( "Missing '$EndDRAWSEGMENT'" ) );
1963}
1964
1966{
1967 /* a net description is something like
1968 * $EQUIPOT
1969 * Na 5 "/BIT1"
1970 * St ~
1971 * $EndEQUIPOT
1972 */
1973
1974 char buf[1024];
1975
1976 NETINFO_ITEM* net = nullptr;
1977 char* line;
1978 int netCode = 0;
1979
1980 while( ( line = READLINE( m_reader ) ) != nullptr )
1981 {
1982 const char* data;
1983
1984 if( TESTLINE( "Na" ) )
1985 {
1986 // e.g. "Na 58 "/cpu.sch/PAD7"\r\n"
1987
1988 netCode = intParse( line + SZ( "Na" ), &data );
1989
1990 ReadDelimitedText( buf, data, sizeof(buf) );
1991
1992 if( net == nullptr )
1993 {
1995 netCode );
1996 }
1997 else
1998 {
1999 THROW_IO_ERROR( wxT( "Two net definitions in '$EQUIPOT' block" ) );
2000 }
2001 }
2002 else if( TESTLINE( "$EndEQUIPOT" ) )
2003 {
2004 // net 0 should be already in list, so store this net
2005 // if it is not the net 0, or if the net 0 does not exists.
2006 if( net && ( net->GetNetCode() > 0 || m_board->FindNet( 0 ) == nullptr ) )
2007 {
2008 m_board->Add( net );
2009
2010 // Be sure we have room to store the net in m_netCodes
2011 if( (int)m_netCodes.size() <= netCode )
2012 m_netCodes.resize( netCode+1 );
2013
2014 m_netCodes[netCode] = net->GetNetCode();
2015 net = nullptr;
2016 }
2017 else
2018 {
2019 delete net;
2020 net = nullptr; // Avoid double deletion.
2021 }
2022
2023 return; // preferred exit
2024 }
2025 }
2026
2027 // If we are here, there is an error.
2028 delete net;
2029 THROW_IO_ERROR( wxT( "Missing '$EndEQUIPOT'" ) );
2030}
2031
2032
2034{
2035 /* examples:
2036 For a single line text:
2037 ----------------------
2038 $TEXTPCB
2039 Te "Text example"
2040 Po 66750 53450 600 800 150 0
2041 De 24 1 0 Italic
2042 $EndTEXTPCB
2043
2044 For a multi line text:
2045 ---------------------
2046 $TEXTPCB
2047 Te "Text example"
2048 Nl "Line 2"
2049 Po 66750 53450 600 800 150 0
2050 De 24 1 0 Italic
2051 $EndTEXTPCB
2052 Nl "line nn" is a line added to the current text
2053 */
2054
2055 char text[1024];
2056
2057 // maybe someday a constructor that takes all this data in one call?
2058 PCB_TEXT* pcbtxt = new PCB_TEXT( m_board );
2059 m_board->Add( pcbtxt, ADD_MODE::APPEND );
2060
2061 char* line;
2062
2063 while( ( line = READLINE( m_reader ) ) != nullptr )
2064 {
2065 const char* data;
2066
2067 if( TESTLINE( "Te" ) ) // Text line (or first line for multi line texts)
2068 {
2069 ReadDelimitedText( text, line + SZ( "Te" ), sizeof(text) );
2071 }
2072 else if( TESTLINE( "nl" ) ) // next line of the current text
2073 {
2074 ReadDelimitedText( text, line + SZ( "nl" ), sizeof(text) );
2075 pcbtxt->SetText( pcbtxt->GetText() + wxChar( '\n' ) + From_UTF8( text ) );
2076 }
2077 else if( TESTLINE( "Po" ) )
2078 {
2079 VECTOR2I size;
2080 BIU pos_x = biuParse( line + SZ( "Po" ), &data );
2081 BIU pos_y = biuParse( data, &data );
2082
2083 size.x = biuParse( data, &data );
2084 size.y = biuParse( data, &data );
2085
2086 BIU thickn = biuParse( data, &data );
2087 EDA_ANGLE angle = degParse( data );
2088
2089 pcbtxt->SetTextSize( size );
2090 pcbtxt->SetTextThickness( thickn );
2091 pcbtxt->SetTextAngle( angle );
2092
2093 pcbtxt->SetTextPos( VECTOR2I( pos_x, pos_y ) );
2094 }
2095 else if( TESTLINE( "De" ) )
2096 {
2097 // e.g. "De 21 1 68183921-93a5-49ac-91b0-49d05a0e1647 Normal C\r\n"
2098 int layer_num = intParse( line + SZ( "De" ), &data );
2099 int notMirrored = intParse( data, &data );
2100 char* uuid = strtok_r( (char*) data, delims, (char**) &data );
2101 char* style = strtok_r( nullptr, delims, (char**) &data );
2102 char* hJustify = strtok_r( nullptr, delims, (char**) &data );
2103 char* vJustify = strtok_r( nullptr, delims, (char**) &data );
2104
2105 pcbtxt->SetMirrored( !notMirrored );
2106 const_cast<KIID&>( pcbtxt->m_Uuid ) = KIID( uuid );
2107 pcbtxt->SetItalic( !strcmp( style, "Italic" ) );
2108
2109 if( hJustify )
2110 {
2111 pcbtxt->SetHorizJustify( horizJustify( hJustify ) );
2112 }
2113 else
2114 {
2115 // boom, somebody changed a constructor, I was relying on this:
2116 wxASSERT( pcbtxt->GetHorizJustify() == GR_TEXT_H_ALIGN_CENTER );
2117 }
2118
2119 if( vJustify )
2120 pcbtxt->SetVertJustify( vertJustify( vJustify ) );
2121
2122 if( layer_num < FIRST_COPPER_LAYER )
2123 layer_num = FIRST_COPPER_LAYER;
2124 else if( layer_num > LAST_NON_COPPER_LAYER )
2125 layer_num = LAST_NON_COPPER_LAYER;
2126
2127 if( layer_num >= FIRST_NON_COPPER_LAYER ||
2128 is_leg_copperlayer_valid( m_cu_count, layer_num ) )
2129 pcbtxt->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2130 else // not perfect, but putting this text on front layer is a workaround
2131 pcbtxt->SetLayer( F_Cu );
2132 }
2133 else if( TESTLINE( "$EndTEXTPCB" ) )
2134 {
2135 return; // preferred exit
2136 }
2137 }
2138
2139 THROW_IO_ERROR( wxT( "Missing '$EndTEXTPCB'" ) );
2140}
2141
2142
2144{
2145 char* line;
2146
2147 while( ( line = READLINE( m_reader ) ) != nullptr )
2148 {
2149 checkpoint();
2150
2151 // read two lines per loop iteration, each loop is one TRACK or VIA
2152 // example first line:
2153 // e.g. "Po 0 23994 28800 24400 28800 150 -1" for a track
2154 // e.g. "Po 3 21086 17586 21086 17586 180 -1" for a via (uses sames start and end)
2155 const char* data;
2156
2157 if( line[0] == '$' ) // $EndTRACK
2158 return; // preferred exit
2159
2160 assert( TESTLINE( "Po" ) );
2161
2162 VIATYPE viatype = static_cast<VIATYPE>( intParse( line + SZ( "Po" ), &data ) );
2163 BIU start_x = biuParse( data, &data );
2164 BIU start_y = biuParse( data, &data );
2165 BIU end_x = biuParse( data, &data );
2166 BIU end_y = biuParse( data, &data );
2167 BIU width = biuParse( data, &data );
2168
2169 // optional 7th drill parameter (must be optional in an old format?)
2170 data = strtok_r( (char*) data, delims, (char**) &data );
2171
2172 BIU drill = data ? biuParse( data ) : -1; // SetDefault() if < 0
2173
2174 // Read the 2nd line to determine the exact type, one of:
2175 // PCB_TRACE_T, PCB_VIA_T, or PCB_SEGZONE_T. The type field in 2nd line
2176 // differentiates between PCB_TRACE_T and PCB_VIA_T. With virtual
2177 // functions in use, it is critical to instantiate the PCB_VIA_T
2178 // exactly.
2179 READLINE( m_reader );
2180
2181 line = m_reader->Line();
2182
2183 // example second line:
2184 // "De 0 0 463 0 800000\r\n"
2185
2186#if 1
2187 assert( TESTLINE( "De" ) );
2188#else
2189 if( !TESTLINE( "De" ) )
2190 {
2191 // mandatory 2nd line is missing
2192 THROW_IO_ERROR( wxT( "Missing 2nd line of a TRACK def" ) );
2193 }
2194#endif
2195
2196 int makeType;
2197
2198 // parse the 2nd line to determine the type of object
2199 // e.g. "De 15 1 7 68183921-93a5-49ac-91b0-49d05a0e1647 0" for a via
2200 int layer_num = intParse( line + SZ( "De" ), &data );
2201 int type = intParse( data, &data );
2202 int net_code = intParse( data, &data );
2203 char* uuid = strtok_r( (char*) data, delims, (char**) &data );
2204
2205 // Discard flags data
2206 intParse( data, (const char**) &data );
2207
2208 if( aStructType == PCB_TRACE_T )
2209 {
2210 makeType = ( type == 1 ) ? PCB_VIA_T : PCB_TRACE_T;
2211 }
2212 else if (aStructType == NOT_USED )
2213 {
2214 continue;
2215 }
2216 else
2217 {
2218 wxFAIL_MSG( wxT( "Segment type unknown" ) );
2219 continue;
2220 }
2221
2222 PCB_TRACK* newTrack;
2223
2224 switch( makeType )
2225 {
2226 default:
2227 case PCB_TRACE_T: newTrack = new PCB_TRACK( m_board ); break;
2228 case PCB_VIA_T: newTrack = new PCB_VIA( m_board ); break;
2229 }
2230
2231 const_cast<KIID&>( newTrack->m_Uuid ) = KIID( uuid );
2232 newTrack->SetPosition( VECTOR2I( start_x, start_y ) );
2233 newTrack->SetEnd( VECTOR2I( end_x, end_y ) );
2234
2235 newTrack->SetWidth( width );
2236
2237 if( makeType == PCB_VIA_T ) // Ensure layers are OK when possible:
2238 {
2239 PCB_VIA *via = static_cast<PCB_VIA*>( newTrack );
2240 via->SetViaType( viatype );
2241
2242 if( drill < 0 )
2243 via->SetDrillDefault();
2244 else
2245 via->SetDrill( drill );
2246
2247 if( via->GetViaType() == VIATYPE::THROUGH )
2248 {
2249 via->SetLayerPair( F_Cu, B_Cu );
2250 }
2251 else
2252 {
2253 PCB_LAYER_ID back = leg_layer2new( m_cu_count, (layer_num >> 4) & 0xf );
2254 PCB_LAYER_ID front = leg_layer2new( m_cu_count, layer_num & 0xf );
2255
2256 if( is_leg_copperlayer_valid( m_cu_count, back ) &&
2258 {
2259 via->SetLayerPair( front, back );
2260 }
2261 else
2262 {
2263 delete via;
2264 newTrack = nullptr;
2265 }
2266 }
2267 }
2268 else
2269 {
2270 // A few legacy boards can have tracks on non existent layers, because
2271 // reducing the number of layers does not remove tracks on removed layers
2272 // If happens, skip them
2273 if( is_leg_copperlayer_valid( m_cu_count, layer_num ) )
2274 {
2275 newTrack->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2276 }
2277 else
2278 {
2279 delete newTrack;
2280 newTrack = nullptr;
2281 }
2282 }
2283
2284 if( newTrack )
2285 {
2286 newTrack->SetNetCode( getNetCode( net_code ) );
2287
2288 m_board->Add( newTrack );
2289 }
2290 }
2291
2292 THROW_IO_ERROR( wxT( "Missing '$EndTRACK'" ) );
2293}
2294
2295
2297{
2298 char buf[1024];
2299 wxString netname;
2300 char* line;
2301
2302 // create an empty NETCLASS without a name, but do not add it to the BOARD
2303 // yet since that would bypass duplicate netclass name checking within the BOARD.
2304 // store it temporarily in an unique_ptr until successfully inserted into the BOARD
2305 // just before returning.
2306 std::shared_ptr<NETCLASS> nc = std::make_shared<NETCLASS>( wxEmptyString );
2307
2308 while( ( line = READLINE( m_reader ) ) != nullptr )
2309 {
2310 if( TESTLINE( "AddNet" ) ) // most frequent type of line
2311 {
2312 // e.g. "AddNet "V3.3D"\n"
2313 ReadDelimitedText( buf, line + SZ( "AddNet" ), sizeof(buf) );
2314 netname = ConvertToNewOverbarNotation( From_UTF8( buf ) );
2315
2316 m_board->GetDesignSettings().m_NetSettings->m_NetClassPatternAssignments.push_back(
2317 {
2318 std::make_unique<EDA_COMBINED_MATCHER>( netname, CTX_NETCLASS ),
2319 nc->GetName()
2320 } );
2321 }
2322 else if( TESTLINE( "Clearance" ) )
2323 {
2324 BIU tmp = biuParse( line + SZ( "Clearance" ) );
2325 nc->SetClearance( tmp );
2326 }
2327 else if( TESTLINE( "TrackWidth" ) )
2328 {
2329 BIU tmp = biuParse( line + SZ( "TrackWidth" ) );
2330 nc->SetTrackWidth( tmp );
2331 }
2332 else if( TESTLINE( "ViaDia" ) )
2333 {
2334 BIU tmp = biuParse( line + SZ( "ViaDia" ) );
2335 nc->SetViaDiameter( tmp );
2336 }
2337 else if( TESTLINE( "ViaDrill" ) )
2338 {
2339 BIU tmp = biuParse( line + SZ( "ViaDrill" ) );
2340 nc->SetViaDrill( tmp );
2341 }
2342 else if( TESTLINE( "uViaDia" ) )
2343 {
2344 BIU tmp = biuParse( line + SZ( "uViaDia" ) );
2345 nc->SetuViaDiameter( tmp );
2346 }
2347 else if( TESTLINE( "uViaDrill" ) )
2348 {
2349 BIU tmp = biuParse( line + SZ( "uViaDrill" ) );
2350 nc->SetuViaDrill( tmp );
2351 }
2352 else if( TESTLINE( "Name" ) )
2353 {
2354 ReadDelimitedText( buf, line + SZ( "Name" ), sizeof(buf) );
2355 nc->SetName( From_UTF8( buf ) );
2356 }
2357 else if( TESTLINE( "Desc" ) )
2358 {
2359 ReadDelimitedText( buf, line + SZ( "Desc" ), sizeof(buf) );
2360 nc->SetDescription( From_UTF8( buf ) );
2361 }
2362 else if( TESTLINE( "$EndNCLASS" ) )
2363 {
2364 if( m_board->GetDesignSettings().m_NetSettings->m_NetClasses.count( nc->GetName() ) )
2365 {
2366 // Must have been a name conflict, this is a bad board file.
2367 // User may have done a hand edit to the file.
2368
2369 // unique_ptr will delete nc on this code path
2370
2371 m_error.Printf( _( "Duplicate NETCLASS name '%s'." ), nc->GetName() );
2373 }
2374 else
2375 {
2376 m_board->GetDesignSettings().m_NetSettings->m_NetClasses[ nc->GetName() ] = nc;
2377 }
2378
2379 return; // preferred exit
2380 }
2381 }
2382
2383 THROW_IO_ERROR( wxT( "Missing '$EndNCLASS'" ) );
2384}
2385
2386
2388{
2389 std::unique_ptr<ZONE> zc = std::make_unique<ZONE>( m_board );
2390
2391 ZONE_BORDER_DISPLAY_STYLE outline_hatch = ZONE_BORDER_DISPLAY_STYLE::NO_HATCH;
2392 bool endContour = false;
2393 int holeIndex = -1; // -1 is the main outline; holeIndex >= 0 = hole index
2394 char buf[1024];
2395 char* line;
2396
2397 while( ( line = READLINE( m_reader ) ) != nullptr )
2398 {
2399 const char* data;
2400
2401 if( TESTLINE( "ZCorner" ) ) // new corner of the zone outlines found
2402 {
2403 // e.g. "ZCorner 25650 49500 0"
2404 BIU x = biuParse( line + SZ( "ZCorner" ), &data );
2405 BIU y = biuParse( data, &data );
2406
2407 if( endContour )
2408 {
2409 // the previous corner was the last corner of a contour.
2410 // so this corner is the first of a new hole
2411 endContour = false;
2412 zc->NewHole();
2413 holeIndex++;
2414 }
2415
2416 zc->AppendCorner( VECTOR2I( x, y ), holeIndex );
2417
2418 // Is this corner the end of current contour?
2419 // the next corner (if any) will be stored in a new contour (a hole)
2420 // intParse( data )returns 0 = usual corner, 1 = last corner of the current contour:
2421 endContour = intParse( data );
2422 }
2423 else if( TESTLINE( "ZInfo" ) ) // general info found
2424 {
2425 // e.g. 'ZInfo 68183921-93a5-49ac-91b0-49d05a0e1647 310 "COMMON"'
2426 char* uuid = strtok_r( (char*) line + SZ( "ZInfo" ), delims, (char**) &data );
2427 int netcode = intParse( data, &data );
2428
2429 if( ReadDelimitedText( buf, data, sizeof(buf) ) > (int) sizeof(buf) )
2430 THROW_IO_ERROR( wxT( "ZInfo netname too long" ) );
2431
2432 const_cast<KIID&>( zc->m_Uuid ) = KIID( uuid );
2433
2434 // Init the net code only, not the netname, to be sure
2435 // the zone net name is the name read in file.
2436 // (When mismatch, the user will be prompted in DRC, to fix the actual name)
2437 zc->BOARD_CONNECTED_ITEM::SetNetCode( getNetCode( netcode ) );
2438 }
2439 else if( TESTLINE( "ZLayer" ) ) // layer found
2440 {
2441 int layer_num = intParse( line + SZ( "ZLayer" ) );
2442 zc->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2443 }
2444 else if( TESTLINE( "ZAux" ) ) // aux info found
2445 {
2446 // e.g. "ZAux 7 E"
2447 ignore_unused( intParse( line + SZ( "ZAux" ), &data ) );
2448 char* hopt = strtok_r( (char*) data, delims, (char**) &data );
2449
2450 if( !hopt )
2451 {
2452 m_error.Printf( _( "Bad ZAux for CZONE_CONTAINER \"%s\"" ),
2453 zc->GetNetname().GetData() );
2455 }
2456
2457 switch( *hopt ) // upper case required
2458 {
2459 case 'N': outline_hatch = ZONE_BORDER_DISPLAY_STYLE::NO_HATCH; break;
2460 case 'E': outline_hatch = ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE; break;
2461 case 'F': outline_hatch = ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_FULL; break;
2462 default:
2463 m_error.Printf( _( "Bad ZAux for CZONE_CONTAINER \"%s\"" ),
2464 zc->GetNetname().GetData() );
2466 }
2467
2468 // Set hatch mode later, after reading corner outline data
2469 }
2470 else if( TESTLINE( "ZSmoothing" ) )
2471 {
2472 // e.g. "ZSmoothing 0 0"
2473 int smoothing = intParse( line + SZ( "ZSmoothing" ), &data );
2474 BIU cornerRadius = biuParse( data );
2475
2476 if( smoothing >= ZONE_SETTINGS::SMOOTHING_LAST || smoothing < 0 )
2477 {
2478 m_error.Printf( _( "Bad ZSmoothing for CZONE_CONTAINER \"%s\"" ),
2479 zc->GetNetname().GetData() );
2481 }
2482
2483 zc->SetCornerSmoothingType( smoothing );
2484 zc->SetCornerRadius( cornerRadius );
2485 }
2486 else if( TESTLINE( "ZKeepout" ) )
2487 {
2488 char* token;
2489 zc->SetIsRuleArea( true );
2490 zc->SetDoNotAllowPads( false ); // Not supported in legacy
2491 zc->SetDoNotAllowFootprints( false ); // Not supported in legacy
2492
2493 // e.g. "ZKeepout tracks N vias N pads Y"
2494 token = strtok_r( line + SZ( "ZKeepout" ), delims, (char**) &data );
2495
2496 while( token )
2497 {
2498 if( !strcmp( token, "tracks" ) )
2499 {
2500 token = strtok_r( nullptr, delims, (char**) &data );
2501 zc->SetDoNotAllowTracks( token && *token == 'N' );
2502 }
2503 else if( !strcmp( token, "vias" ) )
2504 {
2505 token = strtok_r( nullptr, delims, (char**) &data );
2506 zc->SetDoNotAllowVias( token && *token == 'N' );
2507 }
2508 else if( !strcmp( token, "copperpour" ) )
2509 {
2510 token = strtok_r( nullptr, delims, (char**) &data );
2511 zc->SetDoNotAllowCopperPour( token && *token == 'N' );
2512 }
2513
2514 token = strtok_r( nullptr, delims, (char**) &data );
2515 }
2516 }
2517 else if( TESTLINE( "ZOptions" ) )
2518 {
2519 // e.g. "ZOptions 0 32 F 200 200"
2520 int fillmode = intParse( line + SZ( "ZOptions" ), &data );
2521 ignore_unused( intParse( data, &data ) );
2522 char fillstate = data[1]; // here e.g. " F"
2523 BIU thermalReliefGap = biuParse( data += 2 , &data ); // +=2 for " F"
2524 BIU thermalReliefCopperBridge = biuParse( data );
2525
2526 if( fillmode)
2527 {
2529 {
2530 wxLogWarning( _( "The legacy segment zone fill mode is no longer supported.\n"
2531 "Zone fills will be converted on a best-effort basis." ) );
2532
2534 }
2535 }
2536
2537 zc->SetFillMode( ZONE_FILL_MODE::POLYGONS );
2538 zc->SetIsFilled( fillstate == 'S' );
2539 zc->SetThermalReliefGap( thermalReliefGap );
2540 zc->SetThermalReliefSpokeWidth( thermalReliefCopperBridge );
2541 }
2542 else if( TESTLINE( "ZClearance" ) ) // Clearance and pad options info found
2543 {
2544 // e.g. "ZClearance 40 I"
2545 BIU clearance = biuParse( line + SZ( "ZClearance" ), &data );
2546 char* padoption = strtok_r( (char*) data, delims, (char**) &data ); // data: " I"
2547
2548 ZONE_CONNECTION popt;
2549 switch( *padoption )
2550 {
2551 case 'I': popt = ZONE_CONNECTION::FULL; break;
2552 case 'T': popt = ZONE_CONNECTION::THERMAL; break;
2553 case 'H': popt = ZONE_CONNECTION::THT_THERMAL; break;
2554 case 'X': popt = ZONE_CONNECTION::NONE; break;
2555 default:
2556 m_error.Printf( _( "Bad ZClearance padoption for CZONE_CONTAINER \"%s\"" ),
2557 zc->GetNetname().GetData() );
2559 }
2560
2561 zc->SetLocalClearance( clearance );
2562 zc->SetPadConnection( popt );
2563 }
2564 else if( TESTLINE( "ZMinThickness" ) )
2565 {
2566 BIU thickness = biuParse( line + SZ( "ZMinThickness" ) );
2567 zc->SetMinThickness( thickness );
2568 }
2569 else if( TESTLINE( "ZPriority" ) )
2570 {
2571 int priority = intParse( line + SZ( "ZPriority" ) );
2572 zc->SetAssignedPriority( priority );
2573 }
2574 else if( TESTLINE( "$POLYSCORNERS" ) )
2575 {
2576 // Read the PolysList (polygons that are the solid areas in the filled zone)
2577 SHAPE_POLY_SET polysList;
2578
2579 bool makeNewOutline = true;
2580
2581 while( ( line = READLINE( m_reader ) ) != nullptr )
2582 {
2583 if( TESTLINE( "$endPOLYSCORNERS" ) )
2584 break;
2585
2586 // e.g. "39610 43440 0 0"
2587 BIU x = biuParse( line, &data );
2588 BIU y = biuParse( data, &data );
2589
2590 if( makeNewOutline )
2591 polysList.NewOutline();
2592
2593 polysList.Append( x, y );
2594
2595 // end_countour was a bool when file saved, so '0' or '1' here
2596 bool end_contour = intParse( data, &data );
2597 intParse( data ); // skip corner utility flag
2598
2599 makeNewOutline = end_contour;
2600 }
2601
2602 zc->SetFilledPolysList( zc->GetFirstLayer(), polysList );
2603 }
2604 else if( TESTLINE( "$FILLSEGMENTS" ) )
2605 {
2606 while( ( line = READLINE( m_reader ) ) != nullptr )
2607 {
2608 if( TESTLINE( "$endFILLSEGMENTS" ) )
2609 break;
2610
2611 // e.g. ""%d %d %d %d\n"
2612 ignore_unused( biuParse( line, &data ) );
2613 ignore_unused( biuParse( data, &data ) );
2614 ignore_unused( biuParse( data, &data ) );
2615 ignore_unused( biuParse( data ) );
2616 }
2617 }
2618 else if( TESTLINE( "$endCZONE_OUTLINE" ) )
2619 {
2620 // Ensure keepout does not have a net
2621 // (which have no sense for a keepout zone)
2622 if( zc->GetIsRuleArea() )
2623 zc->SetNetCode( NETINFO_LIST::UNCONNECTED );
2624
2625 if( zc->GetMinThickness() > 0 )
2626 {
2627 // Inflate the fill polygon
2628 PCB_LAYER_ID layer = zc->GetFirstLayer();
2629 SHAPE_POLY_SET inflatedFill = SHAPE_POLY_SET( *zc->GetFilledPolysList( layer ) );
2630
2631 inflatedFill.InflateWithLinkedHoles( zc->GetMinThickness() / 2,
2632 CORNER_STRATEGY::ROUND_ALL_CORNERS,
2633 ARC_HIGH_DEF / 2,
2635
2636 zc->SetFilledPolysList( layer, inflatedFill );
2637 }
2638
2639 // should always occur, but who knows, a zone without two corners
2640 // is no zone at all, it's a spot?
2641
2642 if( zc->GetNumCorners() > 2 )
2643 {
2644 if( !zc->IsOnCopperLayer() )
2645 {
2646 zc->SetFillMode( ZONE_FILL_MODE::POLYGONS );
2647 zc->SetNetCode( NETINFO_LIST::UNCONNECTED );
2648 }
2649
2650 // HatchBorder here, after outlines corners are read
2651 // Set hatch here, after outlines corners are read
2652 zc->SetBorderDisplayStyle( outline_hatch, ZONE::GetDefaultHatchPitch(), true );
2653
2654 m_board->Add( zc.release() );
2655 }
2656
2657 return; // preferred exit
2658 }
2659 }
2660
2661 THROW_IO_ERROR( wxT( "Missing '$endCZONE_OUTLINE'" ) );
2662}
2663
2664
2666{
2667 std::unique_ptr<PCB_DIM_ALIGNED> dim = std::make_unique<PCB_DIM_ALIGNED>( m_board,
2669 VECTOR2I crossBarO;
2670 VECTOR2I crossBarF;
2671
2672 char* line;
2673
2674 while( ( line = READLINE( m_reader ) ) != nullptr )
2675 {
2676 const char* data;
2677
2678 if( TESTLINE( "$endCOTATION" ) )
2679 {
2680 dim->UpdateHeight( crossBarF, crossBarO );
2681
2682 m_board->Add( dim.release(), ADD_MODE::APPEND );
2683 return; // preferred exit
2684 }
2685 else if( TESTLINE( "Va" ) )
2686 {
2687 BIU value = biuParse( line + SZ( "Va" ) );
2688
2689 // unused; dimension value is calculated from coordinates
2690 ( void )value;
2691 }
2692 else if( TESTLINE( "Ge" ) )
2693 {
2694 // e.g. "Ge 1 21 68183921-93a5-49ac-91b0-49d05a0e1647\r\n"
2695 int shape = intParse( line + SZ( "De" ), (const char**) &data );
2696 int layer_num = intParse( data, &data );
2697 char* uuid = strtok_r( (char*) data, delims, (char**) &data );
2698
2699 dim->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2700 const_cast<KIID&>( dim->m_Uuid ) = KIID( uuid );
2701
2702 // not used
2703 ( void )shape;
2704 }
2705 else if( TESTLINE( "Te" ) )
2706 {
2707 char buf[2048];
2708
2709 ReadDelimitedText( buf, line + SZ( "Te" ), sizeof(buf) );
2710 dim->SetOverrideText( From_UTF8( buf ) );
2711 dim->SetOverrideTextEnabled( true );
2712 dim->SetUnitsFormat( DIM_UNITS_FORMAT::NO_SUFFIX );
2713 dim->SetAutoUnits();
2714 }
2715 else if( TESTLINE( "Po" ) )
2716 {
2717 BIU pos_x = biuParse( line + SZ( "Po" ), &data );
2718 BIU pos_y = biuParse( data, &data );
2719 BIU width = biuParse( data, &data );
2720 BIU height = biuParse( data, &data );
2721 BIU thickn = biuParse( data, &data );
2722 EDA_ANGLE orient = degParse( data, &data );
2723 char* mirror = strtok_r( (char*) data, delims, (char**) &data );
2724
2725 dim->SetTextPos( VECTOR2I( pos_x, pos_y ) );
2726 dim->SetTextSize( VECTOR2I( width, height ) );
2727 dim->SetMirrored( mirror && *mirror == '0' );
2728 dim->SetTextThickness( thickn );
2729 dim->SetTextAngle( orient );
2730 }
2731 else if( TESTLINE( "Sb" ) )
2732 {
2733 ignore_unused( biuParse( line + SZ( "Sb" ), &data ) );
2734 BIU crossBarOx = biuParse( data, &data );
2735 BIU crossBarOy = biuParse( data, &data );
2736 BIU crossBarFx = biuParse( data, &data );
2737 BIU crossBarFy = biuParse( data, &data );
2738 BIU width = biuParse( data );
2739
2740 dim->SetLineThickness( width );
2741 crossBarO = VECTOR2I( crossBarOx, crossBarOy );
2742 crossBarF = VECTOR2I( crossBarFx, crossBarFy );
2743 }
2744 else if( TESTLINE( "Sd" ) )
2745 {
2746 ignore_unused( intParse( line + SZ( "Sd" ), &data ) );
2747 BIU featureLineDOx = biuParse( data, &data );
2748 BIU featureLineDOy = biuParse( data, &data );
2749
2750 ignore_unused( biuParse( data, &data ) );
2751 ignore_unused( biuParse( data ) );
2752
2753 dim->SetStart( VECTOR2I( featureLineDOx, featureLineDOy ) );
2754 }
2755 else if( TESTLINE( "Sg" ) )
2756 {
2757 ignore_unused( intParse( line + SZ( "Sg" ), &data ) );
2758 BIU featureLineGOx = biuParse( data, &data );
2759 BIU featureLineGOy = biuParse( data, &data );
2760
2761 ignore_unused( biuParse( data, &data ) );
2762 ignore_unused( biuParse( data ) );
2763
2764 dim->SetEnd( VECTOR2I( featureLineGOx, featureLineGOy ) );
2765 }
2766 else if( TESTLINE( "S1" ) ) // Arrow: no longer imported
2767 {
2768 ignore_unused( intParse( line + SZ( "S1" ), &data ) );
2769 biuParse( data, &data ); // skipping excessive data
2770 biuParse( data, &data ); // skipping excessive data
2771 biuParse( data, &data );
2772 biuParse( data );
2773 }
2774 else if( TESTLINE( "S2" ) ) // Arrow: no longer imported
2775 {
2776 ignore_unused( intParse( line + SZ( "S2" ), &data ) );
2777 biuParse( data, &data ); // skipping excessive data
2778 biuParse( data, &data ); // skipping excessive data
2779 biuParse( data, &data );
2780 biuParse( data, &data );
2781 }
2782 else if( TESTLINE( "S3" ) ) // Arrow: no longer imported
2783 {
2784 ignore_unused( intParse( line + SZ( "S3" ), &data ) );
2785 biuParse( data, &data ); // skipping excessive data
2786 biuParse( data, &data ); // skipping excessive data
2787 biuParse( data, &data );
2788 biuParse( data, &data );
2789 }
2790 else if( TESTLINE( "S4" ) ) // Arrow: no longer imported
2791 {
2792 ignore_unused( intParse( line + SZ( "S4" ), &data ) );
2793 biuParse( data, &data ); // skipping excessive data
2794 biuParse( data, &data ); // skipping excessive data
2795 biuParse( data, &data );
2796 biuParse( data, &data );
2797 }
2798 }
2799
2800 THROW_IO_ERROR( wxT( "Missing '$endCOTATION'" ) );
2801}
2802
2803
2805{
2806 char* line;
2807
2808 while( ( line = READLINE( m_reader ) ) != nullptr )
2809 {
2810 const char* data;
2811
2812 if( TESTLINE( "$EndPCB_TARGET" ) || TESTLINE( "$EndMIREPCB" ) )
2813 {
2814 return; // preferred exit
2815 }
2816 else if( TESTLINE( "Po" ) )
2817 {
2818 int shape = intParse( line + SZ( "Po" ), &data );
2819 int layer_num = intParse( data, &data );
2820 BIU pos_x = biuParse( data, &data );
2821 BIU pos_y = biuParse( data, &data );
2822 BIU size = biuParse( data, &data );
2823 BIU width = biuParse( data, &data );
2824 char* uuid = strtok_r( (char*) data, delims, (char**) &data );
2825
2826 if( layer_num < FIRST_NON_COPPER_LAYER )
2827 layer_num = FIRST_NON_COPPER_LAYER;
2828 else if( layer_num > LAST_NON_COPPER_LAYER )
2829 layer_num = LAST_NON_COPPER_LAYER;
2830
2831 PCB_TARGET* t = new PCB_TARGET( m_board, shape, leg_layer2new( m_cu_count, layer_num ),
2832 VECTOR2I( pos_x, pos_y ), size, width );
2833 m_board->Add( t, ADD_MODE::APPEND );
2834
2835 const_cast<KIID&>( t->m_Uuid ) = KIID( uuid );
2836 }
2837 }
2838
2839 THROW_IO_ERROR( wxT( "Missing '$EndDIMENSION'" ) );
2840}
2841
2842
2843BIU PCB_IO_KICAD_LEGACY::biuParse( const char* aValue, const char** nptrptr )
2844{
2845 char* nptr;
2846
2847 errno = 0;
2848
2849 double fval = strtod( aValue, &nptr );
2850
2851 if( errno )
2852 {
2853 m_error.Printf( _( "Invalid floating point number in file: '%s'\nline: %d, offset: %d" ),
2854 m_reader->GetSource().GetData(),
2856 aValue - m_reader->Line() + 1 );
2857
2859 }
2860
2861 if( aValue == nptr )
2862 {
2863 m_error.Printf( _( "Missing floating point number in file: '%s'\nline: %d, offset: %d" ),
2864 m_reader->GetSource().GetData(),
2866 aValue - m_reader->Line() + 1 );
2867
2869 }
2870
2871 if( nptrptr )
2872 *nptrptr = nptr;
2873
2874 fval *= diskToBiu;
2875
2876 // fval is up into the whole number realm here, and should be bounded
2877 // within INT_MIN to INT_MAX since BIU's are nanometers.
2878 return KiROUND( fval );
2879}
2880
2881
2882EDA_ANGLE PCB_IO_KICAD_LEGACY::degParse( const char* aValue, const char** nptrptr )
2883{
2884 char* nptr;
2885
2886 errno = 0;
2887
2888 double fval = strtod( aValue, &nptr );
2889
2890 if( errno )
2891 {
2892 m_error.Printf( _( "Invalid floating point number in file: '%s'\nline: %d, offset: %d" ),
2893 m_reader->GetSource().GetData(),
2895 aValue - m_reader->Line() + 1 );
2896
2898 }
2899
2900 if( aValue == nptr )
2901 {
2902 m_error.Printf( _( "Missing floating point number in file: '%s'\nline: %d, offset: %d" ),
2903 m_reader->GetSource().GetData(),
2905 aValue - m_reader->Line() + 1 );
2906
2908 }
2909
2910 if( nptrptr )
2911 *nptrptr = nptr;
2912
2913 return EDA_ANGLE( fval, TENTHS_OF_A_DEGREE_T );
2914}
2915
2916
2918{
2920 m_cu_count = 16;
2921 m_board = nullptr;
2923 m_props = aProperties;
2924
2925 // conversion factor for saving RAM BIUs to KICAD legacy file format.
2926 biuToDisk = 1.0 / pcbIUScale.IU_PER_MM; // BIUs are nanometers & file is mm
2927
2928 // Conversion factor for loading KICAD legacy file format into BIUs in RAM
2929 // Start by assuming the *.brd file is in deci-mils.
2930 // If we see "Units mm" in the $GENERAL section, set diskToBiu to 1000000.0
2931 // then, during the file loading process, to start a conversion from
2932 // mm to nanometers. The deci-mil legacy files have no such "Units" marker
2933 // so we must assume the file is in deci-mils until told otherwise.
2934
2935 diskToBiu = pcbIUScale.IU_PER_MILS / 10; // BIUs are nanometers
2936}
2937
2938
2939//-----<FOOTPRINT LIBRARY FUNCTIONS>--------------------------------------------
2940
2941/*
2942
2943 The legacy file format is being obsoleted and this code will have a short
2944 lifetime, so it only needs to be good enough for a short duration of time.
2945 Caching all the MODULEs is a bit memory intensive, but it is a considerably
2946 faster way of fulfilling the API contract. Otherwise, without the cache, you
2947 would have to re-read the file when searching for any FOOTPRINT, and this would
2948 be very problematic filling a FOOTPRINT_LIST via this PLUGIN API. If memory
2949 becomes a concern, consider the cache lifetime policy, which determines the
2950 time that a LP_CACHE is in RAM. Note PLUGIN lifetime also plays a role in
2951 cache lifetime.
2952
2953*/
2954
2955
2956typedef boost::ptr_map< std::string, FOOTPRINT > FOOTPRINT_MAP;
2957
2958
2964{
2965 LP_CACHE( PCB_IO_KICAD_LEGACY* aOwner, const wxString& aLibraryPath );
2966
2967 // Most all functions in this class throw IO_ERROR exceptions. There are no
2968 // error codes nor user interface calls from here, nor in any PLUGIN.
2969 // Catch these exceptions higher up please.
2970
2971 void Load();
2972
2973 void ReadAndVerifyHeader( LINE_READER* aReader );
2974
2975 void SkipIndex( LINE_READER* aReader );
2976
2977 void LoadModules( LINE_READER* aReader );
2978
2979 bool IsModified();
2980 static long long GetTimestamp( const wxString& aLibPath );
2981
2982 PCB_IO_KICAD_LEGACY* m_owner; // my owner, I need its PCB_IO_KICAD_LEGACY::loadFOOTPRINT()
2983 wxString m_lib_path;
2984 FOOTPRINT_MAP m_footprints; // map or tuple of footprint_name vs. FOOTPRINT*
2986
2987 bool m_cache_dirty; // Stored separately because it's expensive to check
2988 // m_cache_timestamp against all the files.
2989 long long m_cache_timestamp; // A hash of the timestamps for all the footprint
2990 // files.
2991};
2992
2993
2994LP_CACHE::LP_CACHE( PCB_IO_KICAD_LEGACY* aOwner, const wxString& aLibraryPath ) :
2995 m_owner( aOwner ),
2996 m_lib_path( aLibraryPath ),
2997 m_writable( true ),
2998 m_cache_dirty( true ),
2999 m_cache_timestamp( 0 )
3000{
3001}
3002
3003
3005{
3007
3008 return m_cache_dirty;
3009}
3010
3011
3012long long LP_CACHE::GetTimestamp( const wxString& aLibPath )
3013{
3014 return wxFileName( aLibPath ).GetModificationTime().GetValue().GetValue();
3015}
3016
3017
3019{
3020 m_cache_dirty = false;
3021
3022 FILE_LINE_READER reader( m_lib_path );
3023
3024 ReadAndVerifyHeader( &reader );
3025 SkipIndex( &reader );
3026 LoadModules( &reader );
3027
3028 // Remember the file modification time of library file when the
3029 // cache snapshot was made, so that in a networked environment we will
3030 // reload the cache as needed.
3032}
3033
3034
3036{
3037 char* line = aReader->ReadLine();
3038 char* data;
3039
3040 if( !line )
3041 THROW_IO_ERROR( wxString::Format( _( "File '%s' is empty." ), m_lib_path ) );
3042
3043 if( !TESTLINE( "PCBNEW-LibModule-V1" ) )
3044 THROW_IO_ERROR( wxString::Format( _( "File '%s' is not a legacy library." ), m_lib_path ) );
3045
3046 while( ( line = aReader->ReadLine() ) != nullptr )
3047 {
3048 if( TESTLINE( "Units" ) )
3049 {
3050 const char* units = strtok_r( line + SZ( "Units" ), delims, &data );
3051
3052 if( !strcmp( units, "mm" ) )
3054
3055 }
3056 else if( TESTLINE( "$INDEX" ) )
3057 {
3058 return;
3059 }
3060 }
3061}
3062
3063
3065{
3066 // Some broken INDEX sections have more than one section, due to prior bugs.
3067 // So we must read the next line after $EndINDEX tag,
3068 // to see if this is not a new $INDEX tag.
3069 bool exit = false;
3070 char* line = aReader->Line();
3071
3072 do
3073 {
3074 if( TESTLINE( "$INDEX" ) )
3075 {
3076 exit = false;
3077
3078 while( ( line = aReader->ReadLine() ) != nullptr )
3079 {
3080 if( TESTLINE( "$EndINDEX" ) )
3081 {
3082 exit = true;
3083 break;
3084 }
3085 }
3086 }
3087 else if( exit )
3088 {
3089 break;
3090 }
3091 } while( ( line = aReader->ReadLine() ) != nullptr );
3092}
3093
3094
3096{
3097 m_owner->SetReader( aReader );
3098
3099 char* line = aReader->Line();
3100
3101 do
3102 {
3103 // test first for the $MODULE, even before reading because of INDEX bug.
3104 if( TESTLINE( "$MODULE" ) )
3105 {
3106 std::unique_ptr<FOOTPRINT> fp_ptr = std::make_unique<FOOTPRINT>( m_owner->m_board );
3107
3108 std::string footprintName = StrPurge( line + SZ( "$MODULE" ) );
3109
3110 // The footprint names in legacy libraries can contain the '/' and ':'
3111 // characters which will cause the LIB_ID parser to choke.
3112 ReplaceIllegalFileNameChars( &footprintName );
3113
3114 // set the footprint name first thing, so exceptions can use name.
3115 fp_ptr->SetFPID( LIB_ID( wxEmptyString, footprintName ) );
3116
3117 m_owner->loadFOOTPRINT( fp_ptr.get());
3118
3119 FOOTPRINT* fp = fp_ptr.release(); // exceptions after this are not expected.
3120
3121 // Not sure why this is asserting on debug builds. The debugger shows the
3122 // strings are the same. If it's not really needed maybe it can be removed.
3123
3124 /*
3125
3126 There was a bug in old legacy library management code
3127 (pre-PCB_IO_KICAD_LEGACY) which was introducing duplicate footprint names
3128 in legacy libraries without notification. To best recover from such
3129 bad libraries, and use them to their fullest, there are a few
3130 strategies that could be used. (Note: footprints must have unique
3131 names to be accepted into this cache.) The strategy used here is to
3132 append a differentiating version counter to the end of the name as:
3133 _v2, _v3, etc.
3134
3135 */
3136
3137 FOOTPRINT_MAP::const_iterator it = m_footprints.find( footprintName );
3138
3139 if( it == m_footprints.end() ) // footprintName is not present in cache yet.
3140 {
3141 if( !m_footprints.insert( footprintName, fp ).second )
3142 {
3143 wxFAIL_MSG( wxT( "error doing cache insert using guaranteed unique name" ) );
3144 }
3145 }
3146 else
3147 {
3148 // Bad library has a duplicate of this footprintName, generate a
3149 // unique footprint name and load it anyway.
3150 bool nameOK = false;
3151 int version = 2;
3152 char buf[48];
3153
3154 while( !nameOK )
3155 {
3156 std::string newName = footprintName;
3157
3158 newName += "_v";
3159 snprintf( buf, sizeof(buf), "%d", version++ );
3160 newName += buf;
3161
3162 it = m_footprints.find( newName );
3163
3164 if( it == m_footprints.end() )
3165 {
3166 nameOK = true;
3167
3168 fp->SetFPID( LIB_ID( wxEmptyString, newName ) );
3169
3170 if( !m_footprints.insert( newName, fp ).second )
3171 {
3172 wxFAIL_MSG( wxT( "error doing cache insert using guaranteed unique "
3173 "name" ) );
3174 }
3175 }
3176 }
3177 }
3178 }
3179
3180 } while( ( line = aReader->ReadLine() ) != nullptr );
3181}
3182
3183
3184long long PCB_IO_KICAD_LEGACY::GetLibraryTimestamp( const wxString& aLibraryPath ) const
3185{
3186 return LP_CACHE::GetTimestamp( aLibraryPath );
3187}
3188
3189
3190void PCB_IO_KICAD_LEGACY::cacheLib( const wxString& aLibraryPath )
3191{
3192 if( !m_cache || m_cache->m_lib_path != aLibraryPath || m_cache->IsModified() )
3193 {
3194 // a spectacular episode in memory management:
3195 delete m_cache;
3196 m_cache = new LP_CACHE( this, aLibraryPath );
3197 m_cache->Load();
3198 }
3199}
3200
3201
3202void PCB_IO_KICAD_LEGACY::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibPath,
3203 bool aBestEfforts, const STRING_UTF8_MAP* aProperties )
3204{
3205 LOCALE_IO toggle; // toggles on, then off, the C locale.
3206 wxString errorMsg;
3207
3208 init( aProperties );
3209
3210 try
3211 {
3212 cacheLib( aLibPath );
3213 }
3214 catch( const IO_ERROR& ioe )
3215 {
3216 errorMsg = ioe.What();
3217 }
3218
3219 // Some of the files may have been parsed correctly so we want to add the valid files to
3220 // the library.
3221
3222 for( const auto& footprint : m_cache->m_footprints )
3223 aFootprintNames.Add( From_UTF8( footprint.first.c_str() ) );
3224
3225 if( !errorMsg.IsEmpty() && !aBestEfforts )
3226 THROW_IO_ERROR( errorMsg );
3227}
3228
3229
3230FOOTPRINT* PCB_IO_KICAD_LEGACY::FootprintLoad( const wxString& aLibraryPath,
3231 const wxString& aFootprintName, bool aKeepUUID,
3232 const STRING_UTF8_MAP* aProperties )
3233{
3234 LOCALE_IO toggle; // toggles on, then off, the C locale.
3235
3236 init( aProperties );
3237
3238 cacheLib( aLibraryPath );
3239
3240 const FOOTPRINT_MAP& footprints = m_cache->m_footprints;
3241 FOOTPRINT_MAP::const_iterator it = footprints.find( TO_UTF8( aFootprintName ) );
3242
3243 if( it == footprints.end() )
3244 {
3245 return nullptr;
3246 }
3247
3248 // Return copy of already loaded FOOTPRINT
3249 FOOTPRINT* copy = (FOOTPRINT*) it->second->Duplicate();
3250 copy->SetParent( nullptr );
3251 return copy;
3252}
3253
3254
3255bool PCB_IO_KICAD_LEGACY::DeleteLibrary( const wxString& aLibraryPath,
3256 const STRING_UTF8_MAP* aProperties )
3257{
3258 wxFileName fn = aLibraryPath;
3259
3260 if( !fn.FileExists() )
3261 return false;
3262
3263 // Some of the more elaborate wxRemoveFile() crap puts up its own wxLog dialog
3264 // we don't want that. we want bare metal portability with no UI here.
3265 if( wxRemove( aLibraryPath ) )
3266 {
3267 THROW_IO_ERROR( wxString::Format( _( "Footprint library '%s' cannot be deleted." ),
3268 aLibraryPath.GetData() ) );
3269 }
3270
3271 if( m_cache && m_cache->m_lib_path == aLibraryPath )
3272 {
3273 delete m_cache;
3274 m_cache = nullptr;
3275 }
3276
3277 return true;
3278}
3279
3280
3281bool PCB_IO_KICAD_LEGACY::IsLibraryWritable( const wxString& aLibraryPath )
3282{
3283#if 0 // no support for 32 Cu layers in legacy format
3284 return false;
3285#else
3286 LOCALE_IO toggle;
3287
3288 init( nullptr );
3289
3290 cacheLib( aLibraryPath );
3291
3292 return m_cache->m_writable;
3293#endif
3294}
3295
3296
3298 m_cu_count( 16 ), // for FootprintLoad()
3299 m_progressReporter( nullptr ),
3300 m_lastProgressLine( 0 ),
3301 m_lineCount( 0 ),
3302 m_reader( nullptr ),
3303 m_fp( nullptr ),
3304 m_cache( nullptr )
3305{
3306 init( nullptr );
3307}
3308
3309
3311{
3312 delete m_cache;
3313}
constexpr int ARC_HIGH_DEF
Definition: base_units.h:120
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
LAYER_T
The allowed types of layers, same as Specctra DSN spec.
Definition: board.h:152
@ LAYER_CLASS_OTHERS
@ LAYER_CLASS_SILK
@ LAYER_CLASS_COPPER
@ LAYER_CLASS_EDGES
BASE_SET & set(size_t pos=std::numeric_limits< size_t >::max(), bool value=true)
Definition: base_set.h:62
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
Container for design settings for a BOARD object.
std::shared_ptr< NET_SETTINGS > m_NetSettings
void SetGridOrigin(const VECTOR2I &aOrigin)
std::unique_ptr< PAD > m_Pad_Master
void SetAuxOrigin(const VECTOR2I &aOrigin)
void SetDefaultZoneSettings(const ZONE_SETTINGS &aSettings)
int m_TextThickness[LAYER_CLASS_COUNT]
std::vector< int > m_TrackWidthList
int m_LineThickness[LAYER_CLASS_COUNT]
void SetBoardThickness(int aThickness)
ZONE_SETTINGS & GetDefaultZoneSettings()
VECTOR2I m_TextSize[LAYER_CLASS_COUNT]
std::vector< VIA_DIMENSION > m_ViasDimensionsList
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:276
void SetFPRelativePosition(const VECTOR2I &aPos)
Definition: board_item.cpp:309
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:289
void SetPlotOptions(const PCB_PLOT_PARAMS &aOptions)
Definition: board.h:686
bool m_LegacyDesignSettingsLoaded
True if the legacy board design settings were loaded from a file.
Definition: board.h:372
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:983
void SetFileName(const wxString &aFileName)
Definition: board.h:324
void SetEnabledLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:778
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1901
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
Definition: board.cpp:591
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: board.h:683
void SetVisibleLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings changes the bit-mask of vis...
Definition: board.cpp:790
bool m_LegacyNetclassesLoaded
True if netclasses were loaded from the file.
Definition: board.h:376
void SetCopperLayerCount(int aCount)
Definition: board.cpp:740
bool SetLayerType(PCB_LAYER_ID aLayer, LAYER_T aLayerType)
Change the type of the layer given by aLayer.
Definition: board.cpp:625
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:875
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition: board.h:690
void SetVisibleElements(const GAL_SET &aMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:797
void SetFileFormatVersionAtLoad(int aVersion)
Definition: board.h:392
const KIID m_Uuid
Definition: eda_item.h:489
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:373
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:94
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:418
void SetMirrored(bool isMirrored)
Definition: eda_text.cpp:251
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition: eda_text.cpp:275
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:160
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:244
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.cpp:196
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:182
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:204
void SetItalic(bool aItalic)
Definition: eda_text.cpp:212
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:267
A LINE_READER that reads from an open file.
Definition: richio.h:185
void Rewind()
Rewind the file and resets the line number back to zero.
Definition: richio.h:234
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition: richio.cpp:244
void SetPosition(const VECTOR2I &aPos) override
Definition: footprint.cpp:2348
void SetFPID(const LIB_ID &aFPID)
Definition: footprint.h:248
void SetLocked(bool isLocked) override
Set the #MODULE_is_LOCKED bit in the m_ModuleStatus.
Definition: footprint.h:420
EDA_ANGLE GetOrientation() const
Definition: footprint.h:226
void SetIsPlaced(bool isPlaced)
Definition: footprint.h:434
void SetOrientation(const EDA_ANGLE &aNewAngle)
Definition: footprint.cpp:2420
void SetLocalSolderPasteMarginRatio(std::optional< double > aRatio)
Definition: footprint.h:284
void SetPath(const KIID_PATH &aPath)
Definition: footprint.h:263
void SetKeywords(const wxString &aKeywords)
Definition: footprint.h:260
void SetAttributes(int aAttributes)
Definition: footprint.h:290
PCB_FIELD & Value()
read/write accessors:
Definition: footprint.h:637
void SetLocalZoneConnection(ZONE_CONNECTION aType)
Definition: footprint.h:286
const LIB_ID & GetFPID() const
Definition: footprint.h:247
PCB_FIELD & Reference()
Definition: footprint.h:638
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: footprint.cpp:983
std::vector< FP_3DMODEL > & Models()
Definition: footprint.h:219
void SetLibDescription(const wxString &aDesc)
Definition: footprint.h:257
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition: footprint.h:278
void SetLocalClearance(std::optional< int > aClearance)
Definition: footprint.h:275
void SetLocalSolderPasteMargin(std::optional< int > aMargin)
Definition: footprint.h:281
VECTOR2I GetPosition() const override
Definition: footprint.h:223
VECTOR3D m_Offset
3D model offset (mm)
Definition: footprint.h:100
VECTOR3D m_Rotation
3D model rotation (degrees)
Definition: footprint.h:99
VECTOR3D m_Scale
3D model scaling factor (dimensionless)
Definition: footprint.h:98
wxString m_Filename
The 3D shape filename in 3D library.
Definition: footprint.h:102
Helper for storing and iterating over GAL_LAYER_IDs.
Definition: layer_ids.h:308
GAL_SET & set()
Definition: layer_ids.h:324
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:77
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
Definition: kiid.h:49
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:51
const UTF8 & GetLibItemName() const
Definition: lib_id.h:102
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
Definition: richio.h:93
virtual char * ReadLine()=0
Read a line of text into the buffer and increments the line number counter.
virtual const wxString & GetSource() const
Returns the name of the source of the lines in an abstract sense.
Definition: richio.h:121
virtual unsigned LineNumber() const
Return the line number of the last line read from this LINE_READER.
Definition: richio.h:147
char * Line() const
Return a pointer to the last line that was read in.
Definition: richio.h:129
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:49
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:35
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:732
Handle the data for a net.
Definition: netinfo.h:56
int GetNetCode() const
Definition: netinfo.h:108
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition: netinfo.h:381
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:59
void SetPortrait(bool aIsPortrait)
Rotate the paper page 90 degrees.
Definition: page_info.cpp:189
static const wxChar Custom[]
"User" defined page type
Definition: page_info.h:82
void SetHeightMils(double aHeightInMils)
Definition: page_info.cpp:261
void SetWidthMils(double aWidthInMils)
Definition: page_info.cpp:247
bool SetType(const wxString &aStandardPageDescriptionName, bool aIsPortrait=false)
Set the name of the page type and also the sizes and margins commonly associated with that type name.
Definition: page_info.cpp:122
A #PLUGIN derivation which could possibly be put into a DLL/DSO.
wxString m_error
for throwing exceptions
EDA_ANGLE degParse(const char *aValue, const char **nptrptr=nullptr)
Parse an ASCII decimal floating point value which is certainly an angle in tenths of a degree.
void loadMODULE_TEXT(PCB_TEXT *aText)
bool CanReadFootprint(const wxString &aFileName) const override
Checks if this PCB_IO can read a footprint from specified file or directory.
PROGRESS_REPORTER * m_progressReporter
may be NULL, no ownership
BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const STRING_UTF8_MAP *aProperties=nullptr, PROJECT *aProject=nullptr) override
Load information from some input file format that this PCB_IO implementation knows about into either ...
void loadFP_SHAPE(FOOTPRINT *aFootprint)
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 PC...
std::vector< int > m_netCodes
net codes mapping for boards being loaded
long long GetLibraryTimestamp(const wxString &aLibraryPath) const override
Generate a timestamp representing all the files in the library (including the library directory).
void loadAllSections(bool doAppend)
unsigned m_lineCount
for progress reporting
void cacheLib(const wxString &aLibraryPath)
we only cache one footprint library for now, this determines which one.
void loadPAD(FOOTPRINT *aFootprint)
double biuToDisk
convert from BIUs to disk engineering units with this scale factor
static LSET leg_mask2new(int cu_count, unsigned aMask)
void loadTrackList(int aStructType)
Read a list of segments (Tracks and Vias, or Segzones)
LINE_READER * m_reader
no ownership here.
void SetReader(LINE_READER *aReader)
double diskToBiu
convert from disk engineering units to BIUs
BIU biuParse(const char *aValue, const char **nptrptr=nullptr)
Parse an ASCII decimal floating point value and scales it into a BIU according to the current value o...
wxString m_field
reused to stuff FOOTPRINT fields.
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.
void checkpoint()
Converts net code using the mapping table if available, otherwise returns unchanged net code.
bool DeleteLibrary(const wxString &aLibraryPath, const STRING_UTF8_MAP *aProperties=nullptr) override
Delete an existing library and returns true, or if library does not exist returns false,...
void init(const STRING_UTF8_MAP *aProperties)
initialize PLUGIN like a constructor would, and futz with fresh BOARD if needed.
void loadFOOTPRINT(FOOTPRINT *aFootprint)
static int getVersion(LINE_READER *aReader)
void load3D(FOOTPRINT *aFootprint)
bool CanReadBoard(const wxString &aFileName) const override
Checks if this PCB_IO can read the specified board file.
int getNetCode(int aNetCode)
bool IsLibraryWritable(const wxString &aLibraryPath) override
Return true if the library at aLibraryPath is writable.
int m_loading_format_version
which BOARD_FORMAT_VERSION am I Load()ing?
static PCB_LAYER_ID leg_layer2new(int cu_count, int aLayerNum)
A base class that BOARD loading and saving plugins should derive from.
Definition: pcb_io.h:72
BOARD * m_board
The board BOARD being worked on, no ownership here.
Definition: pcb_io.h:343
virtual bool CanReadFootprint(const wxString &aFileName) const
Checks if this PCB_IO can read a footprint from specified file or directory.
Definition: pcb_io.cpp:59
const STRING_UTF8_MAP * m_props
Properties passed via Save() or Load(), no ownership, may be NULL.
Definition: pcb_io.h:346
virtual bool CanReadBoard(const wxString &aFileName) const
Checks if this PCB_IO can read the specified board file.
Definition: pcb_io.cpp:43
The parser for PCB_PLOT_PARAMS.
Parameters and options when plotting/printing a board.
std::optional< bool > GetLegacyPlotViaOnMaskLayer() const
void Parse(PCB_PLOT_PARAMS_PARSER *aParser)
void SetEnd(const VECTOR2I &aEnd)
Definition: pcb_track.h:118
void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_track.h:111
virtual void SetWidth(int aWidth)
Definition: pcb_track.h:115
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void Report(const wxString &aMessage)=0
Display aMessage in the progress bar dialog.
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).
Container for project specific data.
Definition: project.h:62
Represent a set of closed polygons.
void InflateWithLinkedHoles(int aFactor, CORNER_STRATEGY aCornerStrategy, int aMaxError, POLYGON_MODE aFastMode)
Perform outline inflation/deflation, using round corners.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
int NewOutline()
Creates a new empty polygon in the set and returns its index.
A name/value tuple with unique names and optional values.
Simple container to manage line stroke parameters.
Definition: stroke_params.h:81
Hold the information shown in the lower right corner of a plot, printout, or editing view.
Definition: title_block.h:41
void SetRevision(const wxString &aRevision)
Definition: title_block.h:81
void SetComment(int aIdx, const wxString &aComment)
Definition: title_block.h:101
void SetTitle(const wxString &aTitle)
Definition: title_block.h:58
void SetCompany(const wxString &aCompany)
Definition: title_block.h:91
void SetDate(const wxString &aDate)
Set the date field, and defaults to the current time and date.
Definition: title_block.h:71
wxString wx_str() const
Definition: utf8.cpp:45
T y
Definition: vector3.h:63
T z
Definition: vector3.h:64
T x
Definition: vector3.h:62
Read lines of text from another LINE_READER but only returns non-comment lines and non-blank lines wi...
Definition: filter_reader.h:69
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
ZONE_SETTINGS handles zones parameters.
Definition: zone_settings.h:72
static int GetDefaultHatchPitch()
Definition: zone.cpp:1054
This file is part of the common library.
#define FIRST_COPPER_LAYER
static bool isSpace(char cc)
Test for whitespace.
Definition: dsnlexer.cpp:437
#define _(s)
@ TENTHS_OF_A_DEGREE_T
Definition: eda_angle.h:30
@ CTX_NETCLASS
SHAPE_T
Definition: eda_shape.h:42
@ FP_SMD
Definition: footprint.h:75
@ FP_EXCLUDE_FROM_POS_FILES
Definition: footprint.h:76
@ FP_EXCLUDE_FROM_BOM
Definition: footprint.h:77
@ FP_THROUGH_HOLE
Definition: footprint.h:74
void ignore_unused(const T &)
Definition: ignore.h:24
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Adhes
Definition: layer_ids.h:97
@ Edge_Cuts
Definition: layer_ids.h:113
@ Dwgs_User
Definition: layer_ids.h:109
@ F_Paste
Definition: layer_ids.h:101
@ Cmts_User
Definition: layer_ids.h:110
@ F_Adhes
Definition: layer_ids.h:98
@ B_Mask
Definition: layer_ids.h:106
@ B_Cu
Definition: layer_ids.h:95
@ Eco1_User
Definition: layer_ids.h:111
@ F_Mask
Definition: layer_ids.h:107
@ B_Paste
Definition: layer_ids.h:100
@ F_SilkS
Definition: layer_ids.h:104
@ Eco2_User
Definition: layer_ids.h:112
@ B_SilkS
Definition: layer_ids.h:103
@ F_Cu
Definition: layer_ids.h:64
This file contains miscellaneous commonly used macros and functions.
PAD_DRILL_SHAPE
The set of pad drill shapes, used with PAD::{Set,Get}DrillShape()
Definition: padstack.h:63
PAD_ATTRIB
The set of pad shapes, used with PAD::{Set,Get}Attribute().
Definition: padstack.h:74
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
Definition: padstack.h:46
std::map< wxString, FOOTPRINT * > FOOTPRINT_MAP
Definition: pcb_io_eagle.h:46
static GR_TEXT_V_ALIGN_T vertJustify(const char *vertical)
static int intParse(const char *next, const char **out=nullptr)
Parse an ASCII integer string with possible leading whitespace into an integer and updates the pointe...
#define SILKSCREEN_N_BACK
#define ECO2_N
#define DRAW_N
#define PCB_LEGACY_TEXT_is_DIVERS
#define ADHESIVE_N_FRONT
#define SZ(x)
Get the length of a string constant, at compile time.
static const char delims[]
#define TESTSUBSTR(x)
C sub-string compare test for a specific length of characters.
#define ECO1_N
#define LAST_NON_COPPER_LAYER
PCB_IO_KICAD_LEGACY::BIU BIU
unsigned LEG_MASK
#define SOLDERMASK_N_FRONT
#define SOLDERMASK_N_BACK
#define EDGE_N
bool is_leg_copperlayer_valid(int aCu_Count, int aLegacyLayerNum)
#define SOLDERPASTE_N_BACK
int layerMaskCountSet(LEG_MASK aMask)
Count the number of set layers in the mask.
static long hexParse(const char *next, const char **out=nullptr)
Parse an ASCII hex integer string with possible leading whitespace into a long integer and updates th...
#define SOLDERPASTE_N_FRONT
#define READLINE(rdr)
#define COMMENT_N
#define PCB_LEGACY_TEXT_is_REFERENCE
unsigned LAYER_MSK
#define LAYER_N_FRONT
#define ADHESIVE_N_BACK
static GR_TEXT_H_ALIGN_T horizJustify(const char *horizontal)
#define SILKSCREEN_N_FRONT
#define TESTLINE(x)
C string compare test for a specific length of characters.
#define ALL_CU_LAYERS
boost::ptr_map< std::string, FOOTPRINT > FOOTPRINT_MAP
#define FIRST_NON_COPPER_LAYER
#define FIRST_LAYER
#define LAYER_N_BACK
#define PCB_LEGACY_TEXT_is_VALUE
static bool isSpace(int c)
#define FOOTPRINT_LIBRARY_HEADER_CNT
#define FOOTPRINT_LIBRARY_HEADER
VIATYPE
Definition: pcb_track.h:66
CITER next(CITER it)
Definition: ptree.cpp:126
const char * delims
wxString ConvertToNewOverbarNotation(const wxString &aOldStr)
Convert the old ~...~ overbar notation to the new ~{...} one.
wxString From_UTF8(const char *cstring)
int ReadDelimitedText(wxString *aDest, const char *aSource)
Copy bytes from aSource delimited string segment to aDest wxString.
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Checks aName for illegal file name characters.
char * StrPurge(char *text)
Remove leading and training spaces, tabs and end of line chars in text.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: string_utils.h:391
const double IU_PER_MM
Definition: base_units.h:76
const double IU_PER_MILS
Definition: base_units.h:77
static LAYER_T ParseType(const char *aType)
Convert a string to a LAYER_T.
Definition: board.cpp:654
The footprint portion of the PLUGIN API, and only for the PCB_IO_KICAD_LEGACY, so therefore is privat...
PCB_IO_KICAD_LEGACY * m_owner
void ReadAndVerifyHeader(LINE_READER *aReader)
long long m_cache_timestamp
void LoadModules(LINE_READER *aReader)
FOOTPRINT_MAP m_footprints
static long long GetTimestamp(const wxString &aLibPath)
LP_CACHE(PCB_IO_KICAD_LEGACY *aOwner, const wxString &aLibraryPath)
void SkipIndex(LINE_READER *aReader)
GR_TEXT_H_ALIGN_T
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
GR_TEXT_V_ALIGN_T
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ NOT_USED
the 3d code uses this value
Definition: typeinfo.h:79
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:101
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
constexpr ret_type KiROUND(fp_type v, bool aQuiet=false)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:100
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:676
ZONE_BORDER_DISPLAY_STYLE
Zone border styles.
Definition: zone_settings.h:50
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:47