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