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