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 if( plot_opts.GetLegacyPlotViaOnMaskLayer().has_value() )
931 {
932 bool tent = *plot_opts.GetLegacyPlotViaOnMaskLayer();
935 }
936 }
937
938 else if( TESTLINE( "AuxiliaryAxisOrg" ) )
939 {
940 BIU gx = biuParse( line + SZ( "AuxiliaryAxisOrg" ), &data );
941 BIU gy = biuParse( data );
942
943 bds.SetAuxOrigin( VECTOR2I( gx, gy ) );
944 }
945 else if( TESTSUBSTR( "Layer[" ) )
946 {
947 // eg: "Layer[n] <a_Layer_name_with_no_spaces> <LAYER_T>"
948
949 int layer_num = intParse( line + SZ( "Layer[" ), &data );
950 PCB_LAYER_ID layer_id = leg_layer2new( m_cu_count, layer_num );
951
952 data = strtok_r( (char*) data+1, delims, &saveptr ); // +1 for ']'
953
954 if( data )
955 {
956 wxString layerName = From_UTF8( data );
957 m_board->SetLayerName( layer_id, layerName );
958
959 data = strtok_r( nullptr, delims, &saveptr );
960
961 if( data ) // optional in old board files
962 {
963 LAYER_T type = LAYER::ParseType( data );
964 m_board->SetLayerType( layer_id, type );
965 }
966 }
967 }
968 else if( TESTLINE( "TrackWidth" ) )
969 {
970 BIU tmp = biuParse( line + SZ( "TrackWidth" ) );
971 defaultNetclass->SetTrackWidth( tmp );
972 }
973 else if( TESTLINE( "TrackWidthList" ) )
974 {
975 BIU tmp = biuParse( line + SZ( "TrackWidthList" ) );
976 bds.m_TrackWidthList.push_back( tmp );
977 }
978 else if( TESTLINE( "TrackClearence" ) )
979 {
980 BIU tmp = biuParse( line + SZ( "TrackClearence" ) );
981 defaultNetclass->SetClearance( tmp );
982 }
983 else if( TESTLINE( "TrackMinWidth" ) )
984 {
985 BIU tmp = biuParse( line + SZ( "TrackMinWidth" ) );
986 bds.m_TrackMinWidth = tmp;
987 }
988 else if( TESTLINE( "ZoneClearence" ) )
989 {
990 BIU tmp = biuParse( line + SZ( "ZoneClearence" ) );
991 zoneSettings.m_ZoneClearance = tmp;
992 }
993 else if( TESTLINE( "Zone_45_Only" ) ) // No longer used
994 {
995 /* bool tmp = (bool) */ intParse( line + SZ( "Zone_45_Only" ) );
996 }
997 else if( TESTLINE( "DrawSegmWidth" ) )
998 {
999 BIU tmp = biuParse( line + SZ( "DrawSegmWidth" ) );
1001 }
1002 else if( TESTLINE( "EdgeSegmWidth" ) )
1003 {
1004 BIU tmp = biuParse( line + SZ( "EdgeSegmWidth" ) );
1006 }
1007 else if( TESTLINE( "ViaMinSize" ) )
1008 {
1009 BIU tmp = biuParse( line + SZ( "ViaMinSize" ) );
1010 bds.m_ViasMinSize = tmp;
1011 }
1012 else if( TESTLINE( "MicroViaMinSize" ) )
1013 {
1014 BIU tmp = biuParse( line + SZ( "MicroViaMinSize" ) );
1015 bds.m_MicroViasMinSize = tmp;
1016 }
1017 else if( TESTLINE( "ViaSizeList" ) )
1018 {
1019 // e.g. "ViaSizeList DIAMETER [DRILL]"
1020
1021 BIU drill = 0;
1022 BIU diameter = biuParse( line + SZ( "ViaSizeList" ), &data );
1023
1024 data = strtok_r( (char*) data, delims, (char**) &data );
1025 if( data ) // DRILL may not be present ?
1026 drill = biuParse( data );
1027
1028 bds.m_ViasDimensionsList.emplace_back( diameter, drill );
1029 }
1030 else if( TESTLINE( "ViaSize" ) )
1031 {
1032 BIU tmp = biuParse( line + SZ( "ViaSize" ) );
1033 defaultNetclass->SetViaDiameter( tmp );
1034 }
1035 else if( TESTLINE( "ViaDrill" ) )
1036 {
1037 BIU tmp = biuParse( line + SZ( "ViaDrill" ) );
1038 defaultNetclass->SetViaDrill( tmp );
1039 }
1040 else if( TESTLINE( "ViaMinDrill" ) )
1041 {
1042 BIU tmp = biuParse( line + SZ( "ViaMinDrill" ) );
1043 bds.m_MinThroughDrill = tmp;
1044 }
1045 else if( TESTLINE( "MicroViaSize" ) )
1046 {
1047 BIU tmp = biuParse( line + SZ( "MicroViaSize" ) );
1048 defaultNetclass->SetuViaDiameter( tmp );
1049 }
1050 else if( TESTLINE( "MicroViaDrill" ) )
1051 {
1052 BIU tmp = biuParse( line + SZ( "MicroViaDrill" ) );
1053 defaultNetclass->SetuViaDrill( tmp );
1054 }
1055 else if( TESTLINE( "MicroViaMinDrill" ) )
1056 {
1057 BIU tmp = biuParse( line + SZ( "MicroViaMinDrill" ) );
1058 bds.m_MicroViasMinDrill = tmp;
1059 }
1060 else if( TESTLINE( "MicroViasAllowed" ) )
1061 {
1062 intParse( line + SZ( "MicroViasAllowed" ) );
1063 }
1064 else if( TESTLINE( "TextPcbWidth" ) )
1065 {
1066 BIU tmp = biuParse( line + SZ( "TextPcbWidth" ) );
1068 }
1069 else if( TESTLINE( "TextPcbSize" ) )
1070 {
1071 BIU x = biuParse( line + SZ( "TextPcbSize" ), &data );
1072 BIU y = biuParse( data );
1073
1074 bds.m_TextSize[ LAYER_CLASS_COPPER ] = VECTOR2I( x, y );
1075 }
1076 else if( TESTLINE( "EdgeModWidth" ) )
1077 {
1078 BIU tmp = biuParse( line + SZ( "EdgeModWidth" ) );
1079 bds.m_LineThickness[ LAYER_CLASS_SILK ] = tmp;
1081 }
1082 else if( TESTLINE( "TextModWidth" ) )
1083 {
1084 BIU tmp = biuParse( line + SZ( "TextModWidth" ) );
1085 bds.m_TextThickness[ LAYER_CLASS_SILK ] = tmp;
1087 }
1088 else if( TESTLINE( "TextModSize" ) )
1089 {
1090 BIU x = biuParse( line + SZ( "TextModSize" ), &data );
1091 BIU y = biuParse( data );
1092
1093 bds.m_TextSize[LAYER_CLASS_SILK] = VECTOR2I( x, y );
1094 bds.m_TextSize[LAYER_CLASS_OTHERS] = VECTOR2I( x, y );
1095 }
1096 else if( TESTLINE( "PadSize" ) )
1097 {
1098 BIU x = biuParse( line + SZ( "PadSize" ), &data );
1099 BIU y = biuParse( data );
1100
1101 bds.m_Pad_Master->SetSize( VECTOR2I( x, y ) );
1102 }
1103 else if( TESTLINE( "PadDrill" ) )
1104 {
1105 BIU tmp = biuParse( line + SZ( "PadDrill" ) );
1106 bds.m_Pad_Master->SetDrillSize( VECTOR2I( tmp, tmp ) );
1107 }
1108 else if( TESTLINE( "Pad2MaskClearance" ) )
1109 {
1110 BIU tmp = biuParse( line + SZ( "Pad2MaskClearance" ) );
1111 bds.m_SolderMaskExpansion = tmp;
1112 }
1113 else if( TESTLINE( "SolderMaskMinWidth" ) )
1114 {
1115 BIU tmp = biuParse( line + SZ( "SolderMaskMinWidth" ) );
1116 bds.m_SolderMaskMinWidth = tmp;
1117 }
1118 else if( TESTLINE( "Pad2PasteClearance" ) )
1119 {
1120 BIU tmp = biuParse( line + SZ( "Pad2PasteClearance" ) );
1121 bds.m_SolderPasteMargin = tmp;
1122 }
1123 else if( TESTLINE( "Pad2PasteClearanceRatio" ) )
1124 {
1125 double ratio = atof( line + SZ( "Pad2PasteClearanceRatio" ) );
1126 bds.m_SolderPasteMarginRatio = ratio;
1127 }
1128
1129 else if( TESTLINE( "GridOrigin" ) )
1130 {
1131 BIU x = biuParse( line + SZ( "GridOrigin" ), &data );
1132 BIU y = biuParse( data );
1133
1134 bds.SetGridOrigin( VECTOR2I( x, y ) );
1135 }
1136 else if( TESTLINE( "VisibleElements" ) )
1137 {
1138 // Keep all elements visible.
1139 // the old visibility control does not make sense in current Pcbnew version,
1140 // and this code does not work.
1141#if 0
1142 int visibleElements = hexParse( line + SZ( "VisibleElements" ) );
1143
1144 // Does not work: each old item should be tested one by one to set
1145 // visibility of new item list
1146 GAL_SET visibles;
1147
1148 for( size_t i = 0; i < visibles.size(); i++ )
1149 visibles.set( i, visibleElements & ( 1u << i ) );
1150
1151 m_board->SetVisibleElements( visibles );
1152#endif
1153 }
1154 else if( TESTLINE( "$EndSETUP" ) )
1155 {
1156 bds.SetDefaultZoneSettings( zoneSettings );
1157
1158 // Very old *.brd file does not have NETCLASSes
1159 // "TrackWidth", "ViaSize", "ViaDrill", "ViaMinSize", and "TrackClearence" were
1160 // defined in SETUP; these values are put into the default NETCLASS until later board
1161 // load code should override them. *.brd files which have been saved with knowledge
1162 // of NETCLASSes will override these defaults, very old boards (before 2009) will not
1163 // and use the setup values.
1164 // However these values should be the same as default NETCLASS.
1165
1166 return; // preferred exit
1167 }
1168 }
1169
1170 /*
1171 * Ensure tracks and vias sizes lists are ok:
1172 * Sort lists by by increasing value and remove duplicates
1173 * (the first value is not tested, because it is the netclass value)
1174 */
1175 BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
1176 sort( designSettings.m_ViasDimensionsList.begin() + 1,
1177 designSettings.m_ViasDimensionsList.end() );
1178 sort( designSettings.m_TrackWidthList.begin() + 1, designSettings.m_TrackWidthList.end() );
1179
1180 for( unsigned ii = 1; ii < designSettings.m_ViasDimensionsList.size() - 1; ii++ )
1181 {
1182 if( designSettings.m_ViasDimensionsList[ii] == designSettings.m_ViasDimensionsList[ii + 1] )
1183 {
1184 designSettings.m_ViasDimensionsList.erase( designSettings.m_ViasDimensionsList.begin() + ii );
1185 ii--;
1186 }
1187 }
1188
1189 for( unsigned ii = 1; ii < designSettings.m_TrackWidthList.size() - 1; ii++ )
1190 {
1191 if( designSettings.m_TrackWidthList[ii] == designSettings.m_TrackWidthList[ii + 1] )
1192 {
1193 designSettings.m_TrackWidthList.erase( designSettings.m_TrackWidthList.begin() + ii );
1194 ii--;
1195 }
1196 }
1197}
1198
1199
1201{
1202 char* line;
1203
1204 while( ( line = READLINE( m_reader ) ) != nullptr )
1205 {
1206 const char* data;
1207
1208 // most frequently encountered ones at the top
1209
1210 if( TESTSUBSTR( "D" ) && strchr( "SCAP", line[1] ) ) // read a drawing item, e.g. "DS"
1211 {
1212 loadFP_SHAPE( aFootprint );
1213 }
1214 else if( TESTLINE( "$PAD" ) )
1215 {
1216 loadPAD( aFootprint );
1217 }
1218 else if( TESTSUBSTR( "T" ) ) // Read a footprint text description (ref, value, or drawing)
1219 {
1220 // e.g. "T1 6940 -16220 350 300 900 60 M I 20 N "CFCARD"\r\n"
1221 int tnum = intParse( line + SZ( "T" ) );
1222
1223 PCB_TEXT* text = nullptr;
1224
1225 switch( tnum )
1226 {
1228 text = &aFootprint->Reference();
1229 break;
1230
1232 text = &aFootprint->Value();
1233 break;
1234
1235 // All other fields greater than 1.
1236 default:
1237 text = new PCB_TEXT( aFootprint );
1238 aFootprint->Add( text );
1239 }
1240
1242 }
1243 else if( TESTLINE( "Po" ) )
1244 {
1245 // e.g. "Po 19120 39260 900 0 4E823D06 68183921-93a5-49ac-91b0-49d05a0e1647 ~~\r\n"
1246 BIU pos_x = biuParse( line + SZ( "Po" ), &data );
1247 BIU pos_y = biuParse( data, &data );
1248 int orient = intParse( data, &data );
1249 int layer_num = intParse( data, &data );
1250 PCB_LAYER_ID layer_id = leg_layer2new( m_cu_count, layer_num );
1251
1252 [[maybe_unused]] long edittime = hexParse( data, &data );
1253
1254 char* uuid = strtok_r( (char*) data, delims, (char**) &data );
1255
1256 data = strtok_r( (char*) data+1, delims, (char**) &data );
1257
1258 // data is now a two character long string
1259 // Note: some old files do not have this field
1260 if( data && data[0] == 'F' )
1261 aFootprint->SetLocked( true );
1262
1263 if( data && data[1] == 'P' )
1264 aFootprint->SetIsPlaced( true );
1265
1266 aFootprint->SetPosition( VECTOR2I( pos_x, pos_y ) );
1267 aFootprint->SetLayer( layer_id );
1268 aFootprint->SetOrientation( EDA_ANGLE( orient, TENTHS_OF_A_DEGREE_T ) );
1269 const_cast<KIID&>( aFootprint->m_Uuid ) = KIID( uuid );
1270 }
1271 else if( TESTLINE( "Sc" ) ) // timestamp
1272 {
1273 char* uuid = strtok_r( (char*) line + SZ( "Sc" ), delims, (char**) &data );
1274 const_cast<KIID&>( aFootprint->m_Uuid ) = KIID( uuid );
1275 }
1276 else if( TESTLINE( "Op" ) ) // (Op)tions for auto placement (no longer supported)
1277 {
1278 hexParse( line + SZ( "Op" ), &data );
1279 hexParse( data );
1280 }
1281 else if( TESTLINE( "At" ) ) // (At)tributes of footprint
1282 {
1283 int attrs = 0;
1284
1285 data = line + SZ( "At" );
1286
1287 if( strstr( data, "SMD" ) )
1288 attrs |= FP_SMD;
1289 else if( strstr( data, "VIRTUAL" ) )
1291 else
1293
1294 aFootprint->SetAttributes( attrs );
1295 }
1296 else if( TESTLINE( "AR" ) ) // Alternate Reference
1297 {
1298 // e.g. "AR /68183921-93a5-49ac-e164-49d05a0e1647/93a549d0-49d0-e164-91b0-49d05a0e1647"
1299 data = strtok_r( line + SZ( "AR" ), delims, (char**) &data );
1300
1301 if( data )
1302 aFootprint->SetPath( KIID_PATH( From_UTF8( data ) ) );
1303 }
1304 else if( TESTLINE( "$SHAPE3D" ) )
1305 {
1306 load3D( aFootprint );
1307 }
1308 else if( TESTLINE( "Cd" ) )
1309 {
1310 // e.g. "Cd Double rangee de contacts 2 x 4 pins\r\n"
1311 aFootprint->SetLibDescription( From_UTF8( StrPurge( line + SZ( "Cd" ) ) ) );
1312 }
1313 else if( TESTLINE( "Kw" ) ) // Key words
1314 {
1315 aFootprint->SetKeywords( From_UTF8( StrPurge( line + SZ( "Kw" ) ) ) );
1316 }
1317 else if( TESTLINE( ".SolderPasteRatio" ) )
1318 {
1319 double tmp = atof( line + SZ( ".SolderPasteRatio" ) );
1320
1321 // Due to a bug in dialog editor in Footprint Editor, fixed in BZR version 3565
1322 // this parameter can be broken.
1323 // It should be >= -50% (no solder paste) and <= 0% (full area of the pad)
1324
1325 if( tmp < -0.50 )
1326 tmp = -0.50;
1327
1328 if( tmp > 0.0 )
1329 tmp = 0.0;
1330
1331 aFootprint->SetLocalSolderPasteMarginRatio( tmp );
1332 }
1333 else if( TESTLINE( ".SolderPaste" ) )
1334 {
1335 BIU tmp = biuParse( line + SZ( ".SolderPaste" ) );
1336 aFootprint->SetLocalSolderPasteMargin( tmp );
1337 }
1338 else if( TESTLINE( ".SolderMask" ) )
1339 {
1340 BIU tmp = biuParse( line + SZ( ".SolderMask" ) );
1341 aFootprint->SetLocalSolderMaskMargin( tmp );
1342 }
1343 else if( TESTLINE( ".LocalClearance" ) )
1344 {
1345 BIU tmp = biuParse( line + SZ( ".LocalClearance" ) );
1346 aFootprint->SetLocalClearance( tmp );
1347 }
1348 else if( TESTLINE( ".ZoneConnection" ) )
1349 {
1350 int tmp = intParse( line + SZ( ".ZoneConnection" ) );
1351 aFootprint->SetLocalZoneConnection((ZONE_CONNECTION) tmp );
1352 }
1353 else if( TESTLINE( ".ThermalWidth" ) )
1354 {
1355 BIU tmp = biuParse( line + SZ( ".ThermalWidth" ) );
1356 ignore_unused( tmp );
1357 }
1358 else if( TESTLINE( ".ThermalGap" ) )
1359 {
1360 BIU tmp = biuParse( line + SZ( ".ThermalGap" ) );
1361 ignore_unused( tmp );
1362 }
1363 else if( TESTLINE( "$EndMODULE" ) )
1364 {
1365 return; // preferred exit
1366 }
1367 }
1368
1369 wxString msg = wxString::Format( _( "Missing '$EndMODULE' for MODULE '%s'." ),
1370 aFootprint->GetFPID().GetLibItemName().wx_str() );
1371 THROW_IO_ERROR( msg );
1372}
1373
1374
1376{
1377 std::unique_ptr<PAD> pad = std::make_unique<PAD>( aFootprint );
1378 char* line;
1379 char* saveptr;
1380
1381 while( ( line = READLINE( m_reader ) ) != nullptr )
1382 {
1383 const char* data;
1384
1385 if( TESTLINE( "Sh" ) ) // (Sh)ape and padname
1386 {
1387 // e.g. "Sh "A2" C 520 520 0 0 900"
1388 // or "Sh "1" R 157 1378 0 0 900"
1389
1390 // mypadnumber is LATIN1/CRYLIC for BOARD_FORMAT_VERSION 1, but for
1391 // BOARD_FORMAT_VERSION 2, it is UTF8 from disk.
1392 // Moving forward padnumbers will be in UTF8 on disk, as are all KiCad strings on disk.
1393 char mypadnumber[50];
1394
1395 data = line + SZ( "Sh" ) + 1; // +1 skips trailing whitespace
1396
1397 // +1 trailing whitespace.
1398 data = data + ReadDelimitedText( mypadnumber, data, sizeof( mypadnumber ) ) + 1;
1399
1400 while( isSpace( *data ) )
1401 ++data;
1402
1403 unsigned char padchar = (unsigned char) *data++;
1404 int padshape;
1405
1406 BIU size_x = biuParse( data, &data );
1407 BIU size_y = biuParse( data, &data );
1408 BIU delta_x = biuParse( data, &data );
1409 BIU delta_y = biuParse( data, &data );
1410 EDA_ANGLE orient = degParse( data );
1411
1412 switch( padchar )
1413 {
1414 case 'C': padshape = static_cast<int>( PAD_SHAPE::CIRCLE ); break;
1415 case 'R': padshape = static_cast<int>( PAD_SHAPE::RECTANGLE ); break;
1416 case 'O': padshape = static_cast<int>( PAD_SHAPE::OVAL ); break;
1417 case 'T': padshape = static_cast<int>( PAD_SHAPE::TRAPEZOID ); break;
1418 default:
1419 m_error.Printf( _( "Unknown padshape '%c=0x%02x' on line: %d of footprint: '%s'." ),
1420 padchar, padchar, m_reader->LineNumber(),
1421 aFootprint->GetFPID().GetLibItemName().wx_str() );
1423 }
1424
1425 // go through a wxString to establish a universal character set properly
1426 wxString padNumber;
1427
1428 if( m_loading_format_version == 1 )
1429 {
1430 // add 8 bit bytes, file format 1 was KiCad font type byte,
1431 // simply promote those 8 bit bytes up into UNICODE. (subset of LATIN1)
1432 const unsigned char* cp = (unsigned char*) mypadnumber;
1433
1434 while( *cp )
1435 padNumber += *cp++; // unsigned, ls 8 bits only
1436 }
1437 else
1438 {
1439 // version 2, which is UTF8.
1440 padNumber = From_UTF8( mypadnumber );
1441 }
1442
1443 // chances are both were ASCII, but why take chances?
1444
1445 pad->SetNumber( padNumber );
1446 pad->SetShape( static_cast<PAD_SHAPE>( padshape ) );
1447 pad->SetSize( VECTOR2I( size_x, size_y ) );
1448 pad->SetDelta( VECTOR2I( delta_x, delta_y ) );
1449 pad->SetOrientation( orient );
1450 }
1451 else if( TESTLINE( "Dr" ) ) // (Dr)ill
1452 {
1453 // e.g. "Dr 350 0 0" or "Dr 0 0 0 O 0 0"
1454 BIU drill_x = biuParse( line + SZ( "Dr" ), &data );
1455 BIU drill_y = drill_x;
1456 BIU offs_x = biuParse( data, &data );
1457 BIU offs_y = biuParse( data, &data );
1458
1459 PAD_DRILL_SHAPE drShape = PAD_DRILL_SHAPE::CIRCLE;
1460
1461 data = strtok_r( (char*) data, delims, &saveptr );
1462
1463 if( data ) // optional shape
1464 {
1465 if( data[0] == 'O' )
1466 {
1467 drShape = PAD_DRILL_SHAPE::OBLONG;
1468
1469 data = strtok_r( nullptr, delims, &saveptr );
1470 drill_x = biuParse( data );
1471
1472 data = strtok_r( nullptr, delims, &saveptr );
1473 drill_y = biuParse( data );
1474 }
1475 }
1476
1477 pad->SetDrillShape( drShape );
1478 pad->SetOffset( VECTOR2I( offs_x, offs_y ) );
1479 pad->SetDrillSize( VECTOR2I( drill_x, drill_y ) );
1480 }
1481 else if( TESTLINE( "At" ) ) // (At)tribute
1482 {
1483 // e.g. "At SMD N 00888000"
1484 // sscanf( PtLine, "%s %s %X", BufLine, BufCar, &m_layerMask );
1485
1486 PAD_ATTRIB attribute;
1487
1488 data = strtok_r( line + SZ( "At" ), delims, &saveptr );
1489
1490 if( !strcmp( data, "SMD" ) )
1491 attribute = PAD_ATTRIB::SMD;
1492 else if( !strcmp( data, "CONN" ) )
1493 attribute = PAD_ATTRIB::CONN;
1494 else if( !strcmp( data, "HOLE" ) )
1495 attribute = PAD_ATTRIB::NPTH;
1496 else
1497 attribute = PAD_ATTRIB::PTH;
1498
1499 strtok_r( nullptr, delims, &saveptr ); // skip unused prm
1500 data = strtok_r( nullptr, delims, &saveptr );
1501
1502 LEG_MASK layer_mask = hexParse( data );
1503
1504 pad->SetLayerSet( leg_mask2new( m_cu_count, layer_mask ) );
1505 pad->SetAttribute( attribute );
1506 }
1507 else if( TESTLINE( "Ne" ) ) // (Ne)tname
1508 {
1509 // e.g. "Ne 461 "V5.0"
1510
1511 char buf[1024]; // can be fairly long
1512 int netcode = intParse( line + SZ( "Ne" ), &data );
1513
1514 // Store the new code mapping
1515 pad->SetNetCode( getNetCode( netcode ) );
1516
1517 // read Netname
1518 ReadDelimitedText( buf, data, sizeof(buf) );
1519
1520 if( m_board )
1521 {
1522 wxASSERT( m_board->FindNet( getNetCode( netcode ) )->GetNetname()
1524 }
1525 }
1526 else if( TESTLINE( "Po" ) ) // (Po)sition
1527 {
1528 // e.g. "Po 500 -500"
1529 VECTOR2I pos;
1530
1531 pos.x = biuParse( line + SZ( "Po" ), &data );
1532 pos.y = biuParse( data );
1533
1534 pad->SetFPRelativePosition( pos );
1535 }
1536 else if( TESTLINE( "Le" ) )
1537 {
1538 BIU tmp = biuParse( line + SZ( "Le" ) );
1539 pad->SetPadToDieLength( tmp );
1540 }
1541 else if( TESTLINE( ".SolderMask" ) )
1542 {
1543 BIU tmp = biuParse( line + SZ( ".SolderMask" ) );
1544 pad->SetLocalSolderMaskMargin( tmp );
1545 }
1546 else if( TESTLINE( ".SolderPasteRatio" ) )
1547 {
1548 double tmp = atof( line + SZ( ".SolderPasteRatio" ) );
1549 pad->SetLocalSolderPasteMarginRatio( tmp );
1550 }
1551 else if( TESTLINE( ".SolderPaste" ) )
1552 {
1553 BIU tmp = biuParse( line + SZ( ".SolderPaste" ) );
1554 pad->SetLocalSolderPasteMargin( tmp );
1555 }
1556 else if( TESTLINE( ".LocalClearance" ) )
1557 {
1558 BIU tmp = biuParse( line + SZ( ".LocalClearance" ) );
1559 pad->SetLocalClearance( tmp );
1560 }
1561 else if( TESTLINE( ".ZoneConnection" ) )
1562 {
1563 int tmp = intParse( line + SZ( ".ZoneConnection" ) );
1564 pad->SetLocalZoneConnection( (ZONE_CONNECTION) tmp );
1565 }
1566 else if( TESTLINE( ".ThermalWidth" ) )
1567 {
1568 BIU tmp = biuParse( line + SZ( ".ThermalWidth" ) );
1569 pad->SetThermalSpokeWidth( tmp );
1570 }
1571 else if( TESTLINE( ".ThermalGap" ) )
1572 {
1573 BIU tmp = biuParse( line + SZ( ".ThermalGap" ) );
1574 pad->SetThermalGap( tmp );
1575 }
1576 else if( TESTLINE( "$EndPAD" ) )
1577 {
1578 if( pad->GetSizeX() > 0 && pad->GetSizeY() > 0 )
1579 {
1580 aFootprint->Add( pad.release() );
1581 }
1582 else
1583 {
1584 wxLogError( _( "Invalid zero-sized pad ignored in\nfile: %s" ),
1585 m_reader->GetSource() );
1586 }
1587
1588 return; // preferred exit
1589 }
1590 }
1591
1592 THROW_IO_ERROR( wxT( "Missing '$EndPAD'" ) );
1593}
1594
1595
1597{
1598 SHAPE_T shape;
1599 char* line = m_reader->Line(); // obtain current (old) line
1600
1601 switch( line[1] )
1602 {
1603 case 'S': shape = SHAPE_T::SEGMENT; break;
1604 case 'C': shape = SHAPE_T::CIRCLE; break;
1605 case 'A': shape = SHAPE_T::ARC; break;
1606 case 'P': shape = SHAPE_T::POLY; break;
1607 default:
1608 m_error.Printf( _( "Unknown PCB_SHAPE type:'%c=0x%02x' on line %d of footprint '%s'." ),
1609 (unsigned char) line[1], (unsigned char) line[1], m_reader->LineNumber(),
1610 aFootprint->GetFPID().GetLibItemName().wx_str() );
1612 }
1613
1614 std::unique_ptr<PCB_SHAPE> dwg = std::make_unique<PCB_SHAPE>( aFootprint, shape ); // a drawing
1615
1616 const char* data;
1617
1618 // common to all cases, and we have to check their values uniformly at end
1619 BIU width = 1;
1620 int layer = FIRST_NON_COPPER_LAYER;
1621
1622 switch( shape )
1623 {
1624 case SHAPE_T::ARC:
1625 {
1626 BIU center0_x = biuParse( line + SZ( "DA" ), &data );
1627 BIU center0_y = biuParse( data, &data );
1628 BIU start0_x = biuParse( data, &data );
1629 BIU start0_y = biuParse( data, &data );
1630 EDA_ANGLE angle = degParse( data, &data );
1631
1632 width = biuParse( data, &data );
1633 layer = intParse( data );
1634
1635 dwg->SetCenter( VECTOR2I( center0_x, center0_y ) );
1636 dwg->SetStart( VECTOR2I( start0_x, start0_y ) );
1637 dwg->SetArcAngleAndEnd( angle, true );
1638 break;
1639 }
1640
1641 case SHAPE_T::SEGMENT:
1642 case SHAPE_T::CIRCLE:
1643 {
1644 // e.g. "DS -7874 -10630 7874 -10630 50 20\r\n"
1645 BIU start0_x = biuParse( line + SZ( "DS" ), &data );
1646 BIU start0_y = biuParse( data, &data );
1647 BIU end0_x = biuParse( data, &data );
1648 BIU end0_y = biuParse( data, &data );
1649
1650 width = biuParse( data, &data );
1651 layer = intParse( data );
1652
1653 dwg->SetStart( VECTOR2I( start0_x, start0_y ) );
1654 dwg->SetEnd( VECTOR2I( end0_x, end0_y ) );
1655 break;
1656 }
1657
1658 case SHAPE_T::POLY:
1659 {
1660 // e.g. "DP %d %d %d %d %d %d %d\n"
1661 BIU start0_x = biuParse( line + SZ( "DP" ), &data );
1662 BIU start0_y = biuParse( data, &data );
1663 BIU end0_x = biuParse( data, &data );
1664 BIU end0_y = biuParse( data, &data );
1665 int ptCount = intParse( data, &data );
1666
1667 width = biuParse( data, &data );
1668 layer = intParse( data );
1669
1670 dwg->SetStart( VECTOR2I( start0_x, start0_y ) );
1671 dwg->SetEnd( VECTOR2I( end0_x, end0_y ) );
1672
1673 std::vector<VECTOR2I> pts;
1674 pts.reserve( ptCount );
1675
1676 for( int ii = 0; ii < ptCount; ++ii )
1677 {
1678 if( ( line = READLINE( m_reader ) ) == nullptr )
1679 {
1680 THROW_IO_ERROR( wxT( "S_POLGON point count mismatch." ) );
1681 }
1682
1683 // e.g. "Dl 23 44\n"
1684
1685 if( !TESTLINE( "Dl" ) )
1686 {
1687 THROW_IO_ERROR( wxT( "Missing Dl point def" ) );
1688 }
1689
1690 BIU x = biuParse( line + SZ( "Dl" ), &data );
1691 BIU y = biuParse( data );
1692
1693 pts.emplace_back( x, y );
1694 }
1695
1696 dwg->SetPolyPoints( pts );
1697 break;
1698 }
1699
1700 default:
1701 // first switch code above prevents us from getting here.
1702 break;
1703 }
1704
1705 // Check for a reasonable layer:
1706 // layer must be >= FIRST_NON_COPPER_LAYER, but because microwave footprints can use the
1707 // copper layers, layer < FIRST_NON_COPPER_LAYER is allowed.
1708 if( layer < FIRST_LAYER || layer > LAST_NON_COPPER_LAYER )
1709 layer = SILKSCREEN_N_FRONT;
1710
1711 dwg->SetStroke( STROKE_PARAMS( width, LINE_STYLE::SOLID ) );
1712 dwg->SetLayer( leg_layer2new( m_cu_count, layer ) );
1713
1714 dwg->Rotate( { 0, 0 }, aFootprint->GetOrientation() );
1715 dwg->Move( aFootprint->GetPosition() );
1716 aFootprint->Add( dwg.release() );
1717}
1718
1719
1721{
1722 const char* data;
1723 const char* txt_end;
1724 const char* line = m_reader->Line(); // current (old) line
1725
1726 // e.g. "T1 6940 -16220 350 300 900 60 M I 20 N "CFCARD"\r\n"
1727 // or T1 0 500 600 400 900 80 M V 20 N"74LS245"
1728 // ouch, the last example has no space between N and "74LS245" !
1729 // that is an older version.
1730
1731 int type = intParse( line+1, &data );
1732 BIU pos0_x = biuParse( data, &data );
1733 BIU pos0_y = biuParse( data, &data );
1734 BIU size0_y = biuParse( data, &data );
1735 BIU size0_x = biuParse( data, &data );
1736 EDA_ANGLE orient = degParse( data, &data );
1737 BIU thickn = biuParse( data, &data );
1738
1739 // read the quoted text before the first call to strtok() which introduces
1740 // NULs into the string and chops it into multiple C strings, something
1741 // ReadDelimitedText() cannot traverse.
1742
1743 // convert the "quoted, escaped, UTF8, text" to a wxString, find it by skipping
1744 // as far forward as needed until the first double quote.
1745 txt_end = data + ReadDelimitedText( &m_field, data );
1746 m_field.Replace( wxT( "%V" ), wxT( "${VALUE}" ) );
1747 m_field.Replace( wxT( "%R" ), wxT( "${REFERENCE}" ) );
1749 aText->SetText( m_field );
1750
1751 // after switching to strtok, there's no easy coming back because of the
1752 // embedded nul(s?) placed to the right of the current field.
1753 // (that's the reason why strtok was deprecated...)
1754 char* mirror = strtok_r( (char*) data, delims, (char**) &data );
1755 char* hide = strtok_r( nullptr, delims, (char**) &data );
1756 char* tmp = strtok_r( nullptr, delims, (char**) &data );
1757
1758 int layer_num = tmp ? intParse( tmp ) : SILKSCREEN_N_FRONT;
1759
1760 char* italic = strtok_r( nullptr, delims, (char**) &data );
1761
1762 char* hjust = strtok_r( (char*) txt_end, delims, (char**) &data );
1763 char* vjust = strtok_r( nullptr, delims, (char**) &data );
1764
1767
1768 aText->SetFPRelativePosition( VECTOR2I( pos0_x, pos0_y ) );
1769 aText->SetTextSize( VECTOR2I( size0_x, size0_y ) );
1770
1771 aText->SetTextAngle( orient );
1772
1773 aText->SetTextThickness( thickn < 1 ? 0 : thickn );
1774
1775 aText->SetMirrored( mirror && *mirror == 'M' );
1776
1777 aText->SetVisible( !(hide && *hide == 'I') );
1778
1779 aText->SetItalic( italic && *italic == 'I' );
1780
1781 if( hjust )
1782 aText->SetHorizJustify( horizJustify( hjust ) );
1783
1784 if( vjust )
1785 aText->SetVertJustify( vertJustify( vjust ) );
1786
1787 // A protection against mal formed (or edited by hand) files:
1788 if( layer_num < FIRST_LAYER )
1789 layer_num = FIRST_LAYER;
1790 else if( layer_num > LAST_NON_COPPER_LAYER )
1791 layer_num = LAST_NON_COPPER_LAYER;
1792 else if( layer_num == LAYER_N_BACK )
1793 layer_num = SILKSCREEN_N_BACK;
1794 else if( layer_num == LAYER_N_FRONT )
1795 layer_num = SILKSCREEN_N_FRONT;
1796 else if( layer_num < LAYER_N_FRONT ) // this case is a internal layer
1797 layer_num = SILKSCREEN_N_FRONT;
1798
1799 aText->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
1800}
1801
1802
1804{
1805 FP_3DMODEL t3D;
1806
1807 char* line;
1808
1809 while( ( line = READLINE( m_reader ) ) != nullptr )
1810 {
1811 if( TESTLINE( "Na" ) ) // Shape File Name
1812 {
1813 char buf[512];
1814 ReadDelimitedText( buf, line + SZ( "Na" ), sizeof(buf) );
1815 t3D.m_Filename = buf;
1816 }
1817 else if( TESTLINE( "Sc" ) ) // Scale
1818 {
1819 sscanf( line + SZ( "Sc" ), "%lf %lf %lf\n", &t3D.m_Scale.x, &t3D.m_Scale.y,
1820 &t3D.m_Scale.z );
1821 }
1822 else if( TESTLINE( "Of" ) ) // Offset
1823 {
1824 sscanf( line + SZ( "Of" ), "%lf %lf %lf\n", &t3D.m_Offset.x, &t3D.m_Offset.y,
1825 &t3D.m_Offset.z );
1826 }
1827 else if( TESTLINE( "Ro" ) ) // Rotation
1828 {
1829 sscanf( line + SZ( "Ro" ), "%lf %lf %lf\n", &t3D.m_Rotation.x, &t3D.m_Rotation.y,
1830 &t3D.m_Rotation.z );
1831 }
1832 else if( TESTLINE( "$EndSHAPE3D" ) )
1833 {
1834 aFootprint->Models().push_back( t3D );
1835 return; // preferred exit
1836 }
1837 }
1838
1839 THROW_IO_ERROR( wxT( "Missing '$EndSHAPE3D'" ) );
1840}
1841
1842
1844{
1845 /* example:
1846 $DRAWSEGMENT
1847 Po 0 57500 -1000 57500 0 150
1848 De 24 0 900 0 0
1849 $EndDRAWSEGMENT
1850 */
1851
1852 std::unique_ptr<PCB_SHAPE> dseg = std::make_unique<PCB_SHAPE>( m_board );
1853
1854 char* line;
1855 char* saveptr;
1856
1857 while( ( line = READLINE( m_reader ) ) != nullptr )
1858 {
1859 const char* data;
1860
1861 if( TESTLINE( "Po" ) )
1862 {
1863 int shape = intParse( line + SZ( "Po" ), &data );
1864 BIU start_x = biuParse( data, &data );
1865 BIU start_y = biuParse( data, &data );
1866 BIU end_x = biuParse( data, &data );
1867 BIU end_y = biuParse( data, &data );
1868 BIU width = biuParse( data );
1869
1870 if( width < 0 )
1871 width = 0;
1872
1873 dseg->SetShape( static_cast<SHAPE_T>( shape ) );
1874 dseg->SetFilled( false );
1875 dseg->SetStroke( STROKE_PARAMS( width, LINE_STYLE::SOLID ) );
1876
1877 if( dseg->GetShape() == SHAPE_T::ARC )
1878 {
1879 dseg->SetCenter( VECTOR2I( start_x, start_y ) );
1880 dseg->SetStart( VECTOR2I( end_x, end_y ) );
1881 }
1882 else
1883 {
1884 dseg->SetStart( VECTOR2I( start_x, start_y ) );
1885 dseg->SetEnd( VECTOR2I( end_x, end_y ) );
1886 }
1887 }
1888 else if( TESTLINE( "De" ) )
1889 {
1890 BIU x = 0;
1891 BIU y;
1892
1893 data = strtok_r( line + SZ( "De" ), delims, &saveptr );
1894
1895 for( int i = 0; data; ++i, data = strtok_r( nullptr, delims, &saveptr ) )
1896 {
1897 switch( i )
1898 {
1899 case 0:
1900 int layer;
1901 layer = intParse( data );
1902
1903 if( layer < FIRST_NON_COPPER_LAYER )
1904 layer = FIRST_NON_COPPER_LAYER;
1905
1906 else if( layer > LAST_NON_COPPER_LAYER )
1907 layer = LAST_NON_COPPER_LAYER;
1908
1909 dseg->SetLayer( leg_layer2new( m_cu_count, layer ) );
1910 break;
1911 case 1:
1912 ignore_unused( intParse( data ) );
1913 break;
1914 case 2:
1915 {
1916 EDA_ANGLE angle = degParse( data );
1917
1918 if( dseg->GetShape() == SHAPE_T::ARC )
1919 dseg->SetArcAngleAndEnd( angle );
1920
1921 break;
1922 }
1923 case 3:
1924 const_cast<KIID&>( dseg->m_Uuid ) = KIID( data );
1925 break;
1926 case 4:
1927 {
1928 // Ignore state data
1929 hexParse( data );
1930 break;
1931 }
1932 // Bezier Control Points
1933 case 5:
1934 x = biuParse( data );
1935 break;
1936 case 6:
1937 y = biuParse( data );
1938 dseg->SetBezierC1( VECTOR2I( x, y ) );
1939 break;
1940 case 7:
1941 x = biuParse( data );
1942 break;
1943 case 8:
1944 y = biuParse( data );
1945 dseg->SetBezierC2( VECTOR2I( x, y ) );
1946 break;
1947
1948 default:
1949 break;
1950 }
1951 }
1952 }
1953 else if( TESTLINE( "$EndDRAWSEGMENT" ) )
1954 {
1955 m_board->Add( dseg.release(), ADD_MODE::APPEND );
1956 return; // preferred exit
1957 }
1958 }
1959
1960 THROW_IO_ERROR( wxT( "Missing '$EndDRAWSEGMENT'" ) );
1961}
1962
1964{
1965 /* a net description is something like
1966 * $EQUIPOT
1967 * Na 5 "/BIT1"
1968 * St ~
1969 * $EndEQUIPOT
1970 */
1971
1972 char buf[1024];
1973
1974 NETINFO_ITEM* net = nullptr;
1975 char* line;
1976 int netCode = 0;
1977
1978 while( ( line = READLINE( m_reader ) ) != nullptr )
1979 {
1980 const char* data;
1981
1982 if( TESTLINE( "Na" ) )
1983 {
1984 // e.g. "Na 58 "/cpu.sch/PAD7"\r\n"
1985
1986 netCode = intParse( line + SZ( "Na" ), &data );
1987
1988 ReadDelimitedText( buf, data, sizeof(buf) );
1989
1990 if( net == nullptr )
1991 {
1993 netCode );
1994 }
1995 else
1996 {
1997 THROW_IO_ERROR( wxT( "Two net definitions in '$EQUIPOT' block" ) );
1998 }
1999 }
2000 else if( TESTLINE( "$EndEQUIPOT" ) )
2001 {
2002 // net 0 should be already in list, so store this net
2003 // if it is not the net 0, or if the net 0 does not exists.
2004 if( net && ( net->GetNetCode() > 0 || m_board->FindNet( 0 ) == nullptr ) )
2005 {
2006 m_board->Add( net );
2007
2008 // Be sure we have room to store the net in m_netCodes
2009 if( (int)m_netCodes.size() <= netCode )
2010 m_netCodes.resize( netCode+1 );
2011
2012 m_netCodes[netCode] = net->GetNetCode();
2013 net = nullptr;
2014 }
2015 else
2016 {
2017 delete net;
2018 net = nullptr; // Avoid double deletion.
2019 }
2020
2021 return; // preferred exit
2022 }
2023 }
2024
2025 // If we are here, there is an error.
2026 delete net;
2027 THROW_IO_ERROR( wxT( "Missing '$EndEQUIPOT'" ) );
2028}
2029
2030
2032{
2033 /* examples:
2034 For a single line text:
2035 ----------------------
2036 $TEXTPCB
2037 Te "Text example"
2038 Po 66750 53450 600 800 150 0
2039 De 24 1 0 Italic
2040 $EndTEXTPCB
2041
2042 For a multi line text:
2043 ---------------------
2044 $TEXTPCB
2045 Te "Text example"
2046 Nl "Line 2"
2047 Po 66750 53450 600 800 150 0
2048 De 24 1 0 Italic
2049 $EndTEXTPCB
2050 Nl "line nn" is a line added to the current text
2051 */
2052
2053 char text[1024];
2054
2055 // maybe someday a constructor that takes all this data in one call?
2056 PCB_TEXT* pcbtxt = new PCB_TEXT( m_board );
2057 m_board->Add( pcbtxt, ADD_MODE::APPEND );
2058
2059 char* line;
2060
2061 while( ( line = READLINE( m_reader ) ) != nullptr )
2062 {
2063 const char* data;
2064
2065 if( TESTLINE( "Te" ) ) // Text line (or first line for multi line texts)
2066 {
2067 ReadDelimitedText( text, line + SZ( "Te" ), sizeof(text) );
2069 }
2070 else if( TESTLINE( "nl" ) ) // next line of the current text
2071 {
2072 ReadDelimitedText( text, line + SZ( "nl" ), sizeof(text) );
2073 pcbtxt->SetText( pcbtxt->GetText() + wxChar( '\n' ) + From_UTF8( text ) );
2074 }
2075 else if( TESTLINE( "Po" ) )
2076 {
2077 VECTOR2I size;
2078 BIU pos_x = biuParse( line + SZ( "Po" ), &data );
2079 BIU pos_y = biuParse( data, &data );
2080
2081 size.x = biuParse( data, &data );
2082 size.y = biuParse( data, &data );
2083
2084 BIU thickn = biuParse( data, &data );
2085 EDA_ANGLE angle = degParse( data );
2086
2087 pcbtxt->SetTextSize( size );
2088 pcbtxt->SetTextThickness( thickn );
2089 pcbtxt->SetTextAngle( angle );
2090
2091 pcbtxt->SetTextPos( VECTOR2I( pos_x, pos_y ) );
2092 }
2093 else if( TESTLINE( "De" ) )
2094 {
2095 // e.g. "De 21 1 68183921-93a5-49ac-91b0-49d05a0e1647 Normal C\r\n"
2096 int layer_num = intParse( line + SZ( "De" ), &data );
2097 int notMirrored = intParse( data, &data );
2098 char* uuid = strtok_r( (char*) data, delims, (char**) &data );
2099 char* style = strtok_r( nullptr, delims, (char**) &data );
2100 char* hJustify = strtok_r( nullptr, delims, (char**) &data );
2101 char* vJustify = strtok_r( nullptr, delims, (char**) &data );
2102
2103 pcbtxt->SetMirrored( !notMirrored );
2104 const_cast<KIID&>( pcbtxt->m_Uuid ) = KIID( uuid );
2105 pcbtxt->SetItalic( !strcmp( style, "Italic" ) );
2106
2107 if( hJustify )
2108 {
2109 pcbtxt->SetHorizJustify( horizJustify( hJustify ) );
2110 }
2111 else
2112 {
2113 // boom, somebody changed a constructor, I was relying on this:
2114 wxASSERT( pcbtxt->GetHorizJustify() == GR_TEXT_H_ALIGN_CENTER );
2115 }
2116
2117 if( vJustify )
2118 pcbtxt->SetVertJustify( vertJustify( vJustify ) );
2119
2120 if( layer_num < FIRST_COPPER_LAYER )
2121 layer_num = FIRST_COPPER_LAYER;
2122 else if( layer_num > LAST_NON_COPPER_LAYER )
2123 layer_num = LAST_NON_COPPER_LAYER;
2124
2125 if( layer_num >= FIRST_NON_COPPER_LAYER ||
2126 is_leg_copperlayer_valid( m_cu_count, layer_num ) )
2127 pcbtxt->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2128 else // not perfect, but putting this text on front layer is a workaround
2129 pcbtxt->SetLayer( F_Cu );
2130 }
2131 else if( TESTLINE( "$EndTEXTPCB" ) )
2132 {
2133 return; // preferred exit
2134 }
2135 }
2136
2137 THROW_IO_ERROR( wxT( "Missing '$EndTEXTPCB'" ) );
2138}
2139
2140
2142{
2143 char* line;
2144
2145 while( ( line = READLINE( m_reader ) ) != nullptr )
2146 {
2147 checkpoint();
2148
2149 // read two lines per loop iteration, each loop is one TRACK or VIA
2150 // example first line:
2151 // e.g. "Po 0 23994 28800 24400 28800 150 -1" for a track
2152 // e.g. "Po 3 21086 17586 21086 17586 180 -1" for a via (uses sames start and end)
2153 const char* data;
2154
2155 if( line[0] == '$' ) // $EndTRACK
2156 return; // preferred exit
2157
2158 assert( TESTLINE( "Po" ) );
2159
2160 VIATYPE viatype = static_cast<VIATYPE>( intParse( line + SZ( "Po" ), &data ) );
2161 BIU start_x = biuParse( data, &data );
2162 BIU start_y = biuParse( data, &data );
2163 BIU end_x = biuParse( data, &data );
2164 BIU end_y = biuParse( data, &data );
2165 BIU width = biuParse( data, &data );
2166
2167 // optional 7th drill parameter (must be optional in an old format?)
2168 data = strtok_r( (char*) data, delims, (char**) &data );
2169
2170 BIU drill = data ? biuParse( data ) : -1; // SetDefault() if < 0
2171
2172 // Read the 2nd line to determine the exact type, one of:
2173 // PCB_TRACE_T, PCB_VIA_T, or PCB_SEGZONE_T. The type field in 2nd line
2174 // differentiates between PCB_TRACE_T and PCB_VIA_T. With virtual
2175 // functions in use, it is critical to instantiate the PCB_VIA_T
2176 // exactly.
2177 READLINE( m_reader );
2178
2179 line = m_reader->Line();
2180
2181 // example second line:
2182 // "De 0 0 463 0 800000\r\n"
2183
2184#if 1
2185 assert( TESTLINE( "De" ) );
2186#else
2187 if( !TESTLINE( "De" ) )
2188 {
2189 // mandatory 2nd line is missing
2190 THROW_IO_ERROR( wxT( "Missing 2nd line of a TRACK def" ) );
2191 }
2192#endif
2193
2194 int makeType;
2195
2196 // parse the 2nd line to determine the type of object
2197 // e.g. "De 15 1 7 68183921-93a5-49ac-91b0-49d05a0e1647 0" for a via
2198 int layer_num = intParse( line + SZ( "De" ), &data );
2199 int type = intParse( data, &data );
2200 int net_code = intParse( data, &data );
2201 char* uuid = strtok_r( (char*) data, delims, (char**) &data );
2202
2203 // Discard flags data
2204 intParse( data, (const char**) &data );
2205
2206 if( aStructType == PCB_TRACE_T )
2207 {
2208 makeType = ( type == 1 ) ? PCB_VIA_T : PCB_TRACE_T;
2209 }
2210 else if (aStructType == NOT_USED )
2211 {
2212 continue;
2213 }
2214 else
2215 {
2216 wxFAIL_MSG( wxT( "Segment type unknown" ) );
2217 continue;
2218 }
2219
2220 PCB_TRACK* newTrack;
2221
2222 switch( makeType )
2223 {
2224 default:
2225 case PCB_TRACE_T: newTrack = new PCB_TRACK( m_board ); break;
2226 case PCB_VIA_T: newTrack = new PCB_VIA( m_board ); break;
2227 }
2228
2229 const_cast<KIID&>( newTrack->m_Uuid ) = KIID( uuid );
2230 newTrack->SetPosition( VECTOR2I( start_x, start_y ) );
2231 newTrack->SetEnd( VECTOR2I( end_x, end_y ) );
2232
2233 newTrack->SetWidth( width );
2234
2235 if( makeType == PCB_VIA_T ) // Ensure layers are OK when possible:
2236 {
2237 PCB_VIA *via = static_cast<PCB_VIA*>( newTrack );
2238 via->SetViaType( viatype );
2239
2240 if( drill < 0 )
2241 via->SetDrillDefault();
2242 else
2243 via->SetDrill( drill );
2244
2245 if( via->GetViaType() == VIATYPE::THROUGH )
2246 {
2247 via->SetLayerPair( F_Cu, B_Cu );
2248 }
2249 else
2250 {
2251 PCB_LAYER_ID back = leg_layer2new( m_cu_count, (layer_num >> 4) & 0xf );
2252 PCB_LAYER_ID front = leg_layer2new( m_cu_count, layer_num & 0xf );
2253
2254 if( is_leg_copperlayer_valid( m_cu_count, back ) &&
2256 {
2257 via->SetLayerPair( front, back );
2258 }
2259 else
2260 {
2261 delete via;
2262 newTrack = nullptr;
2263 }
2264 }
2265 }
2266 else
2267 {
2268 // A few legacy boards can have tracks on non existent layers, because
2269 // reducing the number of layers does not remove tracks on removed layers
2270 // If happens, skip them
2271 if( is_leg_copperlayer_valid( m_cu_count, layer_num ) )
2272 {
2273 newTrack->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2274 }
2275 else
2276 {
2277 delete newTrack;
2278 newTrack = nullptr;
2279 }
2280 }
2281
2282 if( newTrack )
2283 {
2284 newTrack->SetNetCode( getNetCode( net_code ) );
2285
2286 m_board->Add( newTrack );
2287 }
2288 }
2289
2290 THROW_IO_ERROR( wxT( "Missing '$EndTRACK'" ) );
2291}
2292
2293
2295{
2296 char buf[1024];
2297 wxString netname;
2298 char* line;
2299
2300 // create an empty NETCLASS without a name, but do not add it to the BOARD
2301 // yet since that would bypass duplicate netclass name checking within the BOARD.
2302 // store it temporarily in an unique_ptr until successfully inserted into the BOARD
2303 // just before returning.
2304 std::shared_ptr<NETCLASS> nc = std::make_shared<NETCLASS>( wxEmptyString );
2305
2306 while( ( line = READLINE( m_reader ) ) != nullptr )
2307 {
2308 if( TESTLINE( "AddNet" ) ) // most frequent type of line
2309 {
2310 // e.g. "AddNet "V3.3D"\n"
2311 ReadDelimitedText( buf, line + SZ( "AddNet" ), sizeof(buf) );
2312 netname = ConvertToNewOverbarNotation( From_UTF8( buf ) );
2313
2314 m_board->GetDesignSettings().m_NetSettings->m_NetClassPatternAssignments.push_back(
2315 {
2316 std::make_unique<EDA_COMBINED_MATCHER>( netname, CTX_NETCLASS ),
2317 nc->GetName()
2318 } );
2319 }
2320 else if( TESTLINE( "Clearance" ) )
2321 {
2322 BIU tmp = biuParse( line + SZ( "Clearance" ) );
2323 nc->SetClearance( tmp );
2324 }
2325 else if( TESTLINE( "TrackWidth" ) )
2326 {
2327 BIU tmp = biuParse( line + SZ( "TrackWidth" ) );
2328 nc->SetTrackWidth( tmp );
2329 }
2330 else if( TESTLINE( "ViaDia" ) )
2331 {
2332 BIU tmp = biuParse( line + SZ( "ViaDia" ) );
2333 nc->SetViaDiameter( tmp );
2334 }
2335 else if( TESTLINE( "ViaDrill" ) )
2336 {
2337 BIU tmp = biuParse( line + SZ( "ViaDrill" ) );
2338 nc->SetViaDrill( tmp );
2339 }
2340 else if( TESTLINE( "uViaDia" ) )
2341 {
2342 BIU tmp = biuParse( line + SZ( "uViaDia" ) );
2343 nc->SetuViaDiameter( tmp );
2344 }
2345 else if( TESTLINE( "uViaDrill" ) )
2346 {
2347 BIU tmp = biuParse( line + SZ( "uViaDrill" ) );
2348 nc->SetuViaDrill( tmp );
2349 }
2350 else if( TESTLINE( "Name" ) )
2351 {
2352 ReadDelimitedText( buf, line + SZ( "Name" ), sizeof(buf) );
2353 nc->SetName( From_UTF8( buf ) );
2354 }
2355 else if( TESTLINE( "Desc" ) )
2356 {
2357 ReadDelimitedText( buf, line + SZ( "Desc" ), sizeof(buf) );
2358 nc->SetDescription( From_UTF8( buf ) );
2359 }
2360 else if( TESTLINE( "$EndNCLASS" ) )
2361 {
2362 if( m_board->GetDesignSettings().m_NetSettings->m_NetClasses.count( nc->GetName() ) )
2363 {
2364 // Must have been a name conflict, this is a bad board file.
2365 // User may have done a hand edit to the file.
2366
2367 // unique_ptr will delete nc on this code path
2368
2369 m_error.Printf( _( "Duplicate NETCLASS name '%s'." ), nc->GetName() );
2371 }
2372 else
2373 {
2374 m_board->GetDesignSettings().m_NetSettings->m_NetClasses[ nc->GetName() ] = nc;
2375 }
2376
2377 return; // preferred exit
2378 }
2379 }
2380
2381 THROW_IO_ERROR( wxT( "Missing '$EndNCLASS'" ) );
2382}
2383
2384
2386{
2387 std::unique_ptr<ZONE> zc = std::make_unique<ZONE>( m_board );
2388
2389 ZONE_BORDER_DISPLAY_STYLE outline_hatch = ZONE_BORDER_DISPLAY_STYLE::NO_HATCH;
2390 bool endContour = false;
2391 int holeIndex = -1; // -1 is the main outline; holeIndex >= 0 = hole index
2392 char buf[1024];
2393 char* line;
2394
2395 while( ( line = READLINE( m_reader ) ) != nullptr )
2396 {
2397 const char* data;
2398
2399 if( TESTLINE( "ZCorner" ) ) // new corner of the zone outlines found
2400 {
2401 // e.g. "ZCorner 25650 49500 0"
2402 BIU x = biuParse( line + SZ( "ZCorner" ), &data );
2403 BIU y = biuParse( data, &data );
2404
2405 if( endContour )
2406 {
2407 // the previous corner was the last corner of a contour.
2408 // so this corner is the first of a new hole
2409 endContour = false;
2410 zc->NewHole();
2411 holeIndex++;
2412 }
2413
2414 zc->AppendCorner( VECTOR2I( x, y ), holeIndex );
2415
2416 // Is this corner the end of current contour?
2417 // the next corner (if any) will be stored in a new contour (a hole)
2418 // intParse( data )returns 0 = usual corner, 1 = last corner of the current contour:
2419 endContour = intParse( data );
2420 }
2421 else if( TESTLINE( "ZInfo" ) ) // general info found
2422 {
2423 // e.g. 'ZInfo 68183921-93a5-49ac-91b0-49d05a0e1647 310 "COMMON"'
2424 char* uuid = strtok_r( (char*) line + SZ( "ZInfo" ), delims, (char**) &data );
2425 int netcode = intParse( data, &data );
2426
2427 if( ReadDelimitedText( buf, data, sizeof(buf) ) > (int) sizeof(buf) )
2428 THROW_IO_ERROR( wxT( "ZInfo netname too long" ) );
2429
2430 const_cast<KIID&>( zc->m_Uuid ) = KIID( uuid );
2431
2432 // Init the net code only, not the netname, to be sure
2433 // the zone net name is the name read in file.
2434 // (When mismatch, the user will be prompted in DRC, to fix the actual name)
2435 zc->BOARD_CONNECTED_ITEM::SetNetCode( getNetCode( netcode ) );
2436 }
2437 else if( TESTLINE( "ZLayer" ) ) // layer found
2438 {
2439 int layer_num = intParse( line + SZ( "ZLayer" ) );
2440 zc->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2441 }
2442 else if( TESTLINE( "ZAux" ) ) // aux info found
2443 {
2444 // e.g. "ZAux 7 E"
2445 ignore_unused( intParse( line + SZ( "ZAux" ), &data ) );
2446 char* hopt = strtok_r( (char*) data, delims, (char**) &data );
2447
2448 if( !hopt )
2449 {
2450 m_error.Printf( _( "Bad ZAux for CZONE_CONTAINER \"%s\"" ),
2451 zc->GetNetname().GetData() );
2453 }
2454
2455 switch( *hopt ) // upper case required
2456 {
2457 case 'N': outline_hatch = ZONE_BORDER_DISPLAY_STYLE::NO_HATCH; break;
2458 case 'E': outline_hatch = ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE; break;
2459 case 'F': outline_hatch = ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_FULL; break;
2460 default:
2461 m_error.Printf( _( "Bad ZAux for CZONE_CONTAINER \"%s\"" ),
2462 zc->GetNetname().GetData() );
2464 }
2465
2466 // Set hatch mode later, after reading corner outline data
2467 }
2468 else if( TESTLINE( "ZSmoothing" ) )
2469 {
2470 // e.g. "ZSmoothing 0 0"
2471 int smoothing = intParse( line + SZ( "ZSmoothing" ), &data );
2472 BIU cornerRadius = biuParse( data );
2473
2474 if( smoothing >= ZONE_SETTINGS::SMOOTHING_LAST || smoothing < 0 )
2475 {
2476 m_error.Printf( _( "Bad ZSmoothing for CZONE_CONTAINER \"%s\"" ),
2477 zc->GetNetname().GetData() );
2479 }
2480
2481 zc->SetCornerSmoothingType( smoothing );
2482 zc->SetCornerRadius( cornerRadius );
2483 }
2484 else if( TESTLINE( "ZKeepout" ) )
2485 {
2486 char* token;
2487 zc->SetIsRuleArea( true );
2488 zc->SetDoNotAllowPads( false ); // Not supported in legacy
2489 zc->SetDoNotAllowFootprints( false ); // Not supported in legacy
2490
2491 // e.g. "ZKeepout tracks N vias N pads Y"
2492 token = strtok_r( line + SZ( "ZKeepout" ), delims, (char**) &data );
2493
2494 while( token )
2495 {
2496 if( !strcmp( token, "tracks" ) )
2497 {
2498 token = strtok_r( nullptr, delims, (char**) &data );
2499 zc->SetDoNotAllowTracks( token && *token == 'N' );
2500 }
2501 else if( !strcmp( token, "vias" ) )
2502 {
2503 token = strtok_r( nullptr, delims, (char**) &data );
2504 zc->SetDoNotAllowVias( token && *token == 'N' );
2505 }
2506 else if( !strcmp( token, "copperpour" ) )
2507 {
2508 token = strtok_r( nullptr, delims, (char**) &data );
2509 zc->SetDoNotAllowCopperPour( token && *token == 'N' );
2510 }
2511
2512 token = strtok_r( nullptr, delims, (char**) &data );
2513 }
2514 }
2515 else if( TESTLINE( "ZOptions" ) )
2516 {
2517 // e.g. "ZOptions 0 32 F 200 200"
2518 int fillmode = intParse( line + SZ( "ZOptions" ), &data );
2519 ignore_unused( intParse( data, &data ) );
2520 char fillstate = data[1]; // here e.g. " F"
2521 BIU thermalReliefGap = biuParse( data += 2 , &data ); // +=2 for " F"
2522 BIU thermalReliefCopperBridge = biuParse( data );
2523
2524 if( fillmode)
2525 {
2527 {
2528 wxLogWarning( _( "The legacy segment zone fill mode is no longer supported.\n"
2529 "Zone fills will be converted on a best-effort basis." ) );
2530
2532 }
2533 }
2534
2535 zc->SetFillMode( ZONE_FILL_MODE::POLYGONS );
2536 zc->SetIsFilled( fillstate == 'S' );
2537 zc->SetThermalReliefGap( thermalReliefGap );
2538 zc->SetThermalReliefSpokeWidth( thermalReliefCopperBridge );
2539 }
2540 else if( TESTLINE( "ZClearance" ) ) // Clearance and pad options info found
2541 {
2542 // e.g. "ZClearance 40 I"
2543 BIU clearance = biuParse( line + SZ( "ZClearance" ), &data );
2544 char* padoption = strtok_r( (char*) data, delims, (char**) &data ); // data: " I"
2545
2546 ZONE_CONNECTION popt;
2547 switch( *padoption )
2548 {
2549 case 'I': popt = ZONE_CONNECTION::FULL; break;
2550 case 'T': popt = ZONE_CONNECTION::THERMAL; break;
2551 case 'H': popt = ZONE_CONNECTION::THT_THERMAL; break;
2552 case 'X': popt = ZONE_CONNECTION::NONE; break;
2553 default:
2554 m_error.Printf( _( "Bad ZClearance padoption for CZONE_CONTAINER \"%s\"" ),
2555 zc->GetNetname().GetData() );
2557 }
2558
2559 zc->SetLocalClearance( clearance );
2560 zc->SetPadConnection( popt );
2561 }
2562 else if( TESTLINE( "ZMinThickness" ) )
2563 {
2564 BIU thickness = biuParse( line + SZ( "ZMinThickness" ) );
2565 zc->SetMinThickness( thickness );
2566 }
2567 else if( TESTLINE( "ZPriority" ) )
2568 {
2569 int priority = intParse( line + SZ( "ZPriority" ) );
2570 zc->SetAssignedPriority( priority );
2571 }
2572 else if( TESTLINE( "$POLYSCORNERS" ) )
2573 {
2574 // Read the PolysList (polygons that are the solid areas in the filled zone)
2575 SHAPE_POLY_SET polysList;
2576
2577 bool makeNewOutline = true;
2578
2579 while( ( line = READLINE( m_reader ) ) != nullptr )
2580 {
2581 if( TESTLINE( "$endPOLYSCORNERS" ) )
2582 break;
2583
2584 // e.g. "39610 43440 0 0"
2585 BIU x = biuParse( line, &data );
2586 BIU y = biuParse( data, &data );
2587
2588 if( makeNewOutline )
2589 polysList.NewOutline();
2590
2591 polysList.Append( x, y );
2592
2593 // end_countour was a bool when file saved, so '0' or '1' here
2594 bool end_contour = intParse( data, &data );
2595 intParse( data ); // skip corner utility flag
2596
2597 makeNewOutline = end_contour;
2598 }
2599
2600 zc->SetFilledPolysList( zc->GetFirstLayer(), polysList );
2601 }
2602 else if( TESTLINE( "$FILLSEGMENTS" ) )
2603 {
2604 while( ( line = READLINE( m_reader ) ) != nullptr )
2605 {
2606 if( TESTLINE( "$endFILLSEGMENTS" ) )
2607 break;
2608
2609 // e.g. ""%d %d %d %d\n"
2610 ignore_unused( biuParse( line, &data ) );
2611 ignore_unused( biuParse( data, &data ) );
2612 ignore_unused( biuParse( data, &data ) );
2613 ignore_unused( biuParse( data ) );
2614 }
2615 }
2616 else if( TESTLINE( "$endCZONE_OUTLINE" ) )
2617 {
2618 // Ensure keepout does not have a net
2619 // (which have no sense for a keepout zone)
2620 if( zc->GetIsRuleArea() )
2621 zc->SetNetCode( NETINFO_LIST::UNCONNECTED );
2622
2623 if( zc->GetMinThickness() > 0 )
2624 {
2625 // Inflate the fill polygon
2626 PCB_LAYER_ID layer = zc->GetFirstLayer();
2627 SHAPE_POLY_SET inflatedFill = SHAPE_POLY_SET( *zc->GetFilledPolysList( layer ) );
2628
2629 inflatedFill.InflateWithLinkedHoles( zc->GetMinThickness() / 2,
2630 CORNER_STRATEGY::ROUND_ALL_CORNERS,
2631 ARC_HIGH_DEF / 2,
2633
2634 zc->SetFilledPolysList( layer, inflatedFill );
2635 }
2636
2637 // should always occur, but who knows, a zone without two corners
2638 // is no zone at all, it's a spot?
2639
2640 if( zc->GetNumCorners() > 2 )
2641 {
2642 if( !zc->IsOnCopperLayer() )
2643 {
2644 zc->SetFillMode( ZONE_FILL_MODE::POLYGONS );
2645 zc->SetNetCode( NETINFO_LIST::UNCONNECTED );
2646 }
2647
2648 // HatchBorder here, after outlines corners are read
2649 // Set hatch here, after outlines corners are read
2650 zc->SetBorderDisplayStyle( outline_hatch, ZONE::GetDefaultHatchPitch(), true );
2651
2652 m_board->Add( zc.release() );
2653 }
2654
2655 return; // preferred exit
2656 }
2657 }
2658
2659 THROW_IO_ERROR( wxT( "Missing '$endCZONE_OUTLINE'" ) );
2660}
2661
2662
2664{
2665 std::unique_ptr<PCB_DIM_ALIGNED> dim = std::make_unique<PCB_DIM_ALIGNED>( m_board,
2667 VECTOR2I crossBarO;
2668 VECTOR2I crossBarF;
2669
2670 char* line;
2671
2672 while( ( line = READLINE( m_reader ) ) != nullptr )
2673 {
2674 const char* data;
2675
2676 if( TESTLINE( "$endCOTATION" ) )
2677 {
2678 dim->UpdateHeight( crossBarF, crossBarO );
2679
2680 m_board->Add( dim.release(), ADD_MODE::APPEND );
2681 return; // preferred exit
2682 }
2683 else if( TESTLINE( "Va" ) )
2684 {
2685 BIU value = biuParse( line + SZ( "Va" ) );
2686
2687 // unused; dimension value is calculated from coordinates
2688 ( void )value;
2689 }
2690 else if( TESTLINE( "Ge" ) )
2691 {
2692 // e.g. "Ge 1 21 68183921-93a5-49ac-91b0-49d05a0e1647\r\n"
2693 int shape = intParse( line + SZ( "De" ), (const char**) &data );
2694 int layer_num = intParse( data, &data );
2695 char* uuid = strtok_r( (char*) data, delims, (char**) &data );
2696
2697 dim->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2698 const_cast<KIID&>( dim->m_Uuid ) = KIID( uuid );
2699
2700 // not used
2701 ( void )shape;
2702 }
2703 else if( TESTLINE( "Te" ) )
2704 {
2705 char buf[2048];
2706
2707 ReadDelimitedText( buf, line + SZ( "Te" ), sizeof(buf) );
2708 dim->SetOverrideText( From_UTF8( buf ) );
2709 dim->SetOverrideTextEnabled( true );
2710 dim->SetUnitsFormat( DIM_UNITS_FORMAT::NO_SUFFIX );
2711 dim->SetAutoUnits();
2712 }
2713 else if( TESTLINE( "Po" ) )
2714 {
2715 BIU pos_x = biuParse( line + SZ( "Po" ), &data );
2716 BIU pos_y = biuParse( data, &data );
2717 BIU width = biuParse( data, &data );
2718 BIU height = biuParse( data, &data );
2719 BIU thickn = biuParse( data, &data );
2720 EDA_ANGLE orient = degParse( data, &data );
2721 char* mirror = strtok_r( (char*) data, delims, (char**) &data );
2722
2723 dim->SetTextPos( VECTOR2I( pos_x, pos_y ) );
2724 dim->SetTextSize( VECTOR2I( width, height ) );
2725 dim->SetMirrored( mirror && *mirror == '0' );
2726 dim->SetTextThickness( thickn );
2727 dim->SetTextAngle( orient );
2728 }
2729 else if( TESTLINE( "Sb" ) )
2730 {
2731 ignore_unused( biuParse( line + SZ( "Sb" ), &data ) );
2732 BIU crossBarOx = biuParse( data, &data );
2733 BIU crossBarOy = biuParse( data, &data );
2734 BIU crossBarFx = biuParse( data, &data );
2735 BIU crossBarFy = biuParse( data, &data );
2736 BIU width = biuParse( data );
2737
2738 dim->SetLineThickness( width );
2739 crossBarO = VECTOR2I( crossBarOx, crossBarOy );
2740 crossBarF = VECTOR2I( crossBarFx, crossBarFy );
2741 }
2742 else if( TESTLINE( "Sd" ) )
2743 {
2744 ignore_unused( intParse( line + SZ( "Sd" ), &data ) );
2745 BIU featureLineDOx = biuParse( data, &data );
2746 BIU featureLineDOy = biuParse( data, &data );
2747
2748 ignore_unused( biuParse( data, &data ) );
2749 ignore_unused( biuParse( data ) );
2750
2751 dim->SetStart( VECTOR2I( featureLineDOx, featureLineDOy ) );
2752 }
2753 else if( TESTLINE( "Sg" ) )
2754 {
2755 ignore_unused( intParse( line + SZ( "Sg" ), &data ) );
2756 BIU featureLineGOx = biuParse( data, &data );
2757 BIU featureLineGOy = biuParse( data, &data );
2758
2759 ignore_unused( biuParse( data, &data ) );
2760 ignore_unused( biuParse( data ) );
2761
2762 dim->SetEnd( VECTOR2I( featureLineGOx, featureLineGOy ) );
2763 }
2764 else if( TESTLINE( "S1" ) ) // Arrow: no longer imported
2765 {
2766 ignore_unused( intParse( line + SZ( "S1" ), &data ) );
2767 biuParse( data, &data ); // skipping excessive data
2768 biuParse( data, &data ); // skipping excessive data
2769 biuParse( data, &data );
2770 biuParse( data );
2771 }
2772 else if( TESTLINE( "S2" ) ) // Arrow: no longer imported
2773 {
2774 ignore_unused( intParse( line + SZ( "S2" ), &data ) );
2775 biuParse( data, &data ); // skipping excessive data
2776 biuParse( data, &data ); // skipping excessive data
2777 biuParse( data, &data );
2778 biuParse( data, &data );
2779 }
2780 else if( TESTLINE( "S3" ) ) // Arrow: no longer imported
2781 {
2782 ignore_unused( intParse( line + SZ( "S3" ), &data ) );
2783 biuParse( data, &data ); // skipping excessive data
2784 biuParse( data, &data ); // skipping excessive data
2785 biuParse( data, &data );
2786 biuParse( data, &data );
2787 }
2788 else if( TESTLINE( "S4" ) ) // Arrow: no longer imported
2789 {
2790 ignore_unused( intParse( line + SZ( "S4" ), &data ) );
2791 biuParse( data, &data ); // skipping excessive data
2792 biuParse( data, &data ); // skipping excessive data
2793 biuParse( data, &data );
2794 biuParse( data, &data );
2795 }
2796 }
2797
2798 THROW_IO_ERROR( wxT( "Missing '$endCOTATION'" ) );
2799}
2800
2801
2803{
2804 char* line;
2805
2806 while( ( line = READLINE( m_reader ) ) != nullptr )
2807 {
2808 const char* data;
2809
2810 if( TESTLINE( "$EndPCB_TARGET" ) || TESTLINE( "$EndMIREPCB" ) )
2811 {
2812 return; // preferred exit
2813 }
2814 else if( TESTLINE( "Po" ) )
2815 {
2816 int shape = intParse( line + SZ( "Po" ), &data );
2817 int layer_num = intParse( data, &data );
2818 BIU pos_x = biuParse( data, &data );
2819 BIU pos_y = biuParse( data, &data );
2820 BIU size = biuParse( data, &data );
2821 BIU width = biuParse( data, &data );
2822 char* uuid = strtok_r( (char*) data, delims, (char**) &data );
2823
2824 if( layer_num < FIRST_NON_COPPER_LAYER )
2825 layer_num = FIRST_NON_COPPER_LAYER;
2826 else if( layer_num > LAST_NON_COPPER_LAYER )
2827 layer_num = LAST_NON_COPPER_LAYER;
2828
2829 PCB_TARGET* t = new PCB_TARGET( m_board, shape, leg_layer2new( m_cu_count, layer_num ),
2830 VECTOR2I( pos_x, pos_y ), size, width );
2831 m_board->Add( t, ADD_MODE::APPEND );
2832
2833 const_cast<KIID&>( t->m_Uuid ) = KIID( uuid );
2834 }
2835 }
2836
2837 THROW_IO_ERROR( wxT( "Missing '$EndDIMENSION'" ) );
2838}
2839
2840
2841BIU PCB_IO_KICAD_LEGACY::biuParse( const char* aValue, const char** nptrptr )
2842{
2843 char* nptr;
2844
2845 errno = 0;
2846
2847 double fval = strtod( aValue, &nptr );
2848
2849 if( errno )
2850 {
2851 m_error.Printf( _( "Invalid floating point number in file: '%s'\nline: %d, offset: %d" ),
2852 m_reader->GetSource().GetData(),
2854 aValue - m_reader->Line() + 1 );
2855
2857 }
2858
2859 if( aValue == nptr )
2860 {
2861 m_error.Printf( _( "Missing floating point number in file: '%s'\nline: %d, offset: %d" ),
2862 m_reader->GetSource().GetData(),
2864 aValue - m_reader->Line() + 1 );
2865
2867 }
2868
2869 if( nptrptr )
2870 *nptrptr = nptr;
2871
2872 fval *= diskToBiu;
2873
2874 // fval is up into the whole number realm here, and should be bounded
2875 // within INT_MIN to INT_MAX since BIU's are nanometers.
2876 return KiROUND( fval );
2877}
2878
2879
2880EDA_ANGLE PCB_IO_KICAD_LEGACY::degParse( const char* aValue, const char** nptrptr )
2881{
2882 char* nptr;
2883
2884 errno = 0;
2885
2886 double fval = strtod( aValue, &nptr );
2887
2888 if( errno )
2889 {
2890 m_error.Printf( _( "Invalid floating point number in file: '%s'\nline: %d, offset: %d" ),
2891 m_reader->GetSource().GetData(),
2893 aValue - m_reader->Line() + 1 );
2894
2896 }
2897
2898 if( aValue == nptr )
2899 {
2900 m_error.Printf( _( "Missing floating point number in file: '%s'\nline: %d, offset: %d" ),
2901 m_reader->GetSource().GetData(),
2903 aValue - m_reader->Line() + 1 );
2904
2906 }
2907
2908 if( nptrptr )
2909 *nptrptr = nptr;
2910
2911 return EDA_ANGLE( fval, TENTHS_OF_A_DEGREE_T );
2912}
2913
2914
2916{
2918 m_cu_count = 16;
2919 m_board = nullptr;
2921 m_props = aProperties;
2922
2923 // conversion factor for saving RAM BIUs to KICAD legacy file format.
2924 biuToDisk = 1.0 / pcbIUScale.IU_PER_MM; // BIUs are nanometers & file is mm
2925
2926 // Conversion factor for loading KICAD legacy file format into BIUs in RAM
2927 // Start by assuming the *.brd file is in deci-mils.
2928 // If we see "Units mm" in the $GENERAL section, set diskToBiu to 1000000.0
2929 // then, during the file loading process, to start a conversion from
2930 // mm to nanometers. The deci-mil legacy files have no such "Units" marker
2931 // so we must assume the file is in deci-mils until told otherwise.
2932
2933 diskToBiu = pcbIUScale.IU_PER_MILS / 10; // BIUs are nanometers
2934}
2935
2936
2937//-----<FOOTPRINT LIBRARY FUNCTIONS>--------------------------------------------
2938
2939/*
2940
2941 The legacy file format is being obsoleted and this code will have a short
2942 lifetime, so it only needs to be good enough for a short duration of time.
2943 Caching all the MODULEs is a bit memory intensive, but it is a considerably
2944 faster way of fulfilling the API contract. Otherwise, without the cache, you
2945 would have to re-read the file when searching for any FOOTPRINT, and this would
2946 be very problematic filling a FOOTPRINT_LIST via this PLUGIN API. If memory
2947 becomes a concern, consider the cache lifetime policy, which determines the
2948 time that a LP_CACHE is in RAM. Note PLUGIN lifetime also plays a role in
2949 cache lifetime.
2950
2951*/
2952
2953
2954typedef boost::ptr_map< std::string, FOOTPRINT > FOOTPRINT_MAP;
2955
2956
2962{
2963 LP_CACHE( PCB_IO_KICAD_LEGACY* aOwner, const wxString& aLibraryPath );
2964
2965 // Most all functions in this class throw IO_ERROR exceptions. There are no
2966 // error codes nor user interface calls from here, nor in any PLUGIN.
2967 // Catch these exceptions higher up please.
2968
2969 void Load();
2970
2971 void ReadAndVerifyHeader( LINE_READER* aReader );
2972
2973 void SkipIndex( LINE_READER* aReader );
2974
2975 void LoadModules( LINE_READER* aReader );
2976
2977 bool IsModified();
2978 static long long GetTimestamp( const wxString& aLibPath );
2979
2980 PCB_IO_KICAD_LEGACY* m_owner; // my owner, I need its PCB_IO_KICAD_LEGACY::loadFOOTPRINT()
2981 wxString m_lib_path;
2982 FOOTPRINT_MAP m_footprints; // map or tuple of footprint_name vs. FOOTPRINT*
2984
2985 bool m_cache_dirty; // Stored separately because it's expensive to check
2986 // m_cache_timestamp against all the files.
2987 long long m_cache_timestamp; // A hash of the timestamps for all the footprint
2988 // files.
2989};
2990
2991
2992LP_CACHE::LP_CACHE( PCB_IO_KICAD_LEGACY* aOwner, const wxString& aLibraryPath ) :
2993 m_owner( aOwner ),
2994 m_lib_path( aLibraryPath ),
2995 m_writable( true ),
2996 m_cache_dirty( true ),
2997 m_cache_timestamp( 0 )
2998{
2999}
3000
3001
3003{
3005
3006 return m_cache_dirty;
3007}
3008
3009
3010long long LP_CACHE::GetTimestamp( const wxString& aLibPath )
3011{
3012 return wxFileName( aLibPath ).GetModificationTime().GetValue().GetValue();
3013}
3014
3015
3017{
3018 m_cache_dirty = false;
3019
3020 FILE_LINE_READER reader( m_lib_path );
3021
3022 ReadAndVerifyHeader( &reader );
3023 SkipIndex( &reader );
3024 LoadModules( &reader );
3025
3026 // Remember the file modification time of library file when the
3027 // cache snapshot was made, so that in a networked environment we will
3028 // reload the cache as needed.
3030}
3031
3032
3034{
3035 char* line = aReader->ReadLine();
3036 char* data;
3037
3038 if( !line )
3039 THROW_IO_ERROR( wxString::Format( _( "File '%s' is empty." ), m_lib_path ) );
3040
3041 if( !TESTLINE( "PCBNEW-LibModule-V1" ) )
3042 THROW_IO_ERROR( wxString::Format( _( "File '%s' is not a legacy library." ), m_lib_path ) );
3043
3044 while( ( line = aReader->ReadLine() ) != nullptr )
3045 {
3046 if( TESTLINE( "Units" ) )
3047 {
3048 const char* units = strtok_r( line + SZ( "Units" ), delims, &data );
3049
3050 if( !strcmp( units, "mm" ) )
3052
3053 }
3054 else if( TESTLINE( "$INDEX" ) )
3055 {
3056 return;
3057 }
3058 }
3059}
3060
3061
3063{
3064 // Some broken INDEX sections have more than one section, due to prior bugs.
3065 // So we must read the next line after $EndINDEX tag,
3066 // to see if this is not a new $INDEX tag.
3067 bool exit = false;
3068 char* line = aReader->Line();
3069
3070 do
3071 {
3072 if( TESTLINE( "$INDEX" ) )
3073 {
3074 exit = false;
3075
3076 while( ( line = aReader->ReadLine() ) != nullptr )
3077 {
3078 if( TESTLINE( "$EndINDEX" ) )
3079 {
3080 exit = true;
3081 break;
3082 }
3083 }
3084 }
3085 else if( exit )
3086 {
3087 break;
3088 }
3089 } while( ( line = aReader->ReadLine() ) != nullptr );
3090}
3091
3092
3094{
3095 m_owner->SetReader( aReader );
3096
3097 char* line = aReader->Line();
3098
3099 do
3100 {
3101 // test first for the $MODULE, even before reading because of INDEX bug.
3102 if( TESTLINE( "$MODULE" ) )
3103 {
3104 std::unique_ptr<FOOTPRINT> fp_ptr = std::make_unique<FOOTPRINT>( m_owner->m_board );
3105
3106 std::string footprintName = StrPurge( line + SZ( "$MODULE" ) );
3107
3108 // The footprint names in legacy libraries can contain the '/' and ':'
3109 // characters which will cause the LIB_ID parser to choke.
3110 ReplaceIllegalFileNameChars( &footprintName );
3111
3112 // set the footprint name first thing, so exceptions can use name.
3113 fp_ptr->SetFPID( LIB_ID( wxEmptyString, footprintName ) );
3114
3115 m_owner->loadFOOTPRINT( fp_ptr.get());
3116
3117 FOOTPRINT* fp = fp_ptr.release(); // exceptions after this are not expected.
3118
3119 // Not sure why this is asserting on debug builds. The debugger shows the
3120 // strings are the same. If it's not really needed maybe it can be removed.
3121
3122 /*
3123
3124 There was a bug in old legacy library management code
3125 (pre-PCB_IO_KICAD_LEGACY) which was introducing duplicate footprint names
3126 in legacy libraries without notification. To best recover from such
3127 bad libraries, and use them to their fullest, there are a few
3128 strategies that could be used. (Note: footprints must have unique
3129 names to be accepted into this cache.) The strategy used here is to
3130 append a differentiating version counter to the end of the name as:
3131 _v2, _v3, etc.
3132
3133 */
3134
3135 FOOTPRINT_MAP::const_iterator it = m_footprints.find( footprintName );
3136
3137 if( it == m_footprints.end() ) // footprintName is not present in cache yet.
3138 {
3139 if( !m_footprints.insert( footprintName, fp ).second )
3140 {
3141 wxFAIL_MSG( wxT( "error doing cache insert using guaranteed unique name" ) );
3142 }
3143 }
3144 else
3145 {
3146 // Bad library has a duplicate of this footprintName, generate a
3147 // unique footprint name and load it anyway.
3148 bool nameOK = false;
3149 int version = 2;
3150 char buf[48];
3151
3152 while( !nameOK )
3153 {
3154 std::string newName = footprintName;
3155
3156 newName += "_v";
3157 snprintf( buf, sizeof(buf), "%d", version++ );
3158 newName += buf;
3159
3160 it = m_footprints.find( newName );
3161
3162 if( it == m_footprints.end() )
3163 {
3164 nameOK = true;
3165
3166 fp->SetFPID( LIB_ID( wxEmptyString, newName ) );
3167
3168 if( !m_footprints.insert( newName, fp ).second )
3169 {
3170 wxFAIL_MSG( wxT( "error doing cache insert using guaranteed unique "
3171 "name" ) );
3172 }
3173 }
3174 }
3175 }
3176 }
3177
3178 } while( ( line = aReader->ReadLine() ) != nullptr );
3179}
3180
3181
3182long long PCB_IO_KICAD_LEGACY::GetLibraryTimestamp( const wxString& aLibraryPath ) const
3183{
3184 return LP_CACHE::GetTimestamp( aLibraryPath );
3185}
3186
3187
3188void PCB_IO_KICAD_LEGACY::cacheLib( const wxString& aLibraryPath )
3189{
3190 if( !m_cache || m_cache->m_lib_path != aLibraryPath || m_cache->IsModified() )
3191 {
3192 // a spectacular episode in memory management:
3193 delete m_cache;
3194 m_cache = new LP_CACHE( this, aLibraryPath );
3195 m_cache->Load();
3196 }
3197}
3198
3199
3200void PCB_IO_KICAD_LEGACY::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibPath,
3201 bool aBestEfforts, const STRING_UTF8_MAP* aProperties )
3202{
3203 LOCALE_IO toggle; // toggles on, then off, the C locale.
3204 wxString errorMsg;
3205
3206 init( aProperties );
3207
3208 try
3209 {
3210 cacheLib( aLibPath );
3211 }
3212 catch( const IO_ERROR& ioe )
3213 {
3214 errorMsg = ioe.What();
3215 }
3216
3217 // Some of the files may have been parsed correctly so we want to add the valid files to
3218 // the library.
3219
3220 for( const auto& footprint : m_cache->m_footprints )
3221 aFootprintNames.Add( From_UTF8( footprint.first.c_str() ) );
3222
3223 if( !errorMsg.IsEmpty() && !aBestEfforts )
3224 THROW_IO_ERROR( errorMsg );
3225}
3226
3227
3228FOOTPRINT* PCB_IO_KICAD_LEGACY::FootprintLoad( const wxString& aLibraryPath,
3229 const wxString& aFootprintName, bool aKeepUUID,
3230 const STRING_UTF8_MAP* aProperties )
3231{
3232 LOCALE_IO toggle; // toggles on, then off, the C locale.
3233
3234 init( aProperties );
3235
3236 cacheLib( aLibraryPath );
3237
3238 const FOOTPRINT_MAP& footprints = m_cache->m_footprints;
3239 FOOTPRINT_MAP::const_iterator it = footprints.find( TO_UTF8( aFootprintName ) );
3240
3241 if( it == footprints.end() )
3242 {
3243 return nullptr;
3244 }
3245
3246 // Return copy of already loaded FOOTPRINT
3247 FOOTPRINT* copy = (FOOTPRINT*) it->second->Duplicate();
3248 copy->SetParent( nullptr );
3249 return copy;
3250}
3251
3252
3253bool PCB_IO_KICAD_LEGACY::DeleteLibrary( const wxString& aLibraryPath,
3254 const STRING_UTF8_MAP* aProperties )
3255{
3256 wxFileName fn = aLibraryPath;
3257
3258 if( !fn.FileExists() )
3259 return false;
3260
3261 // Some of the more elaborate wxRemoveFile() crap puts up its own wxLog dialog
3262 // we don't want that. we want bare metal portability with no UI here.
3263 if( wxRemove( aLibraryPath ) )
3264 {
3265 THROW_IO_ERROR( wxString::Format( _( "Footprint library '%s' cannot be deleted." ),
3266 aLibraryPath.GetData() ) );
3267 }
3268
3269 if( m_cache && m_cache->m_lib_path == aLibraryPath )
3270 {
3271 delete m_cache;
3272 m_cache = nullptr;
3273 }
3274
3275 return true;
3276}
3277
3278
3279bool PCB_IO_KICAD_LEGACY::IsLibraryWritable( const wxString& aLibraryPath )
3280{
3281#if 0 // no support for 32 Cu layers in legacy format
3282 return false;
3283#else
3284 LOCALE_IO toggle;
3285
3286 init( nullptr );
3287
3288 cacheLib( aLibraryPath );
3289
3290 return m_cache->m_writable;
3291#endif
3292}
3293
3294
3296 m_cu_count( 16 ), // for FootprintLoad()
3297 m_progressReporter( nullptr ),
3298 m_lastProgressLine( 0 ),
3299 m_lineCount( 0 ),
3300 m_reader( nullptr ),
3301 m_fp( nullptr ),
3302 m_cache( nullptr )
3303{
3304 init( nullptr );
3305}
3306
3307
3309{
3310 delete m_cache;
3311}
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:151
@ 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:276
void SetFPRelativePosition(const VECTOR2I &aPos)
Definition: board_item.cpp:307
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:288
void SetPlotOptions(const PCB_PLOT_PARAMS &aOptions)
Definition: board.h:678
bool m_LegacyDesignSettingsLoaded
True if the legacy board design settings were loaded from a file.
Definition: board.h:371
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:960
void SetFileName(const wxString &aFileName)
Definition: board.h:323
void SetEnabledLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:775
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1878
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
Definition: board.cpp:589
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: board.h:675
void SetVisibleLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings changes the bit-mask of vis...
Definition: board.cpp:787
bool m_LegacyNetclassesLoaded
True if netclasses were loaded from the file.
Definition: board.h:375
void SetCopperLayerCount(int aCount)
Definition: board.cpp:737
bool SetLayerType(PCB_LAYER_ID aLayer, LAYER_T aLayerType)
Change the type of the layer given by aLayer.
Definition: board.cpp:622
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:872
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition: board.h:682
void SetVisibleElements(const GAL_SET &aMask)
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:794
void SetFileFormatVersionAtLoad(int aVersion)
Definition: board.h:391
const KIID m_Uuid
Definition: eda_item.h:486
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:373
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:94
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:418
void SetMirrored(bool isMirrored)
Definition: eda_text.cpp:251
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition: eda_text.cpp:275
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:160
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:244
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.cpp:196
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:182
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:204
void SetItalic(bool aItalic)
Definition: eda_text.cpp:212
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:267
A LINE_READER that reads from an open file.
Definition: richio.h:185
void Rewind()
Rewind the file and resets the line number back to zero.
Definition: richio.h:234
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition: richio.cpp:244
void SetPosition(const VECTOR2I &aPos) override
Definition: footprint.cpp:2334
void SetFPID(const LIB_ID &aFPID)
Definition: footprint.h:237
void SetLocked(bool isLocked) override
Set the #MODULE_is_LOCKED bit in the m_ModuleStatus.
Definition: footprint.h:409
EDA_ANGLE GetOrientation() const
Definition: footprint.h:215
void SetIsPlaced(bool isPlaced)
Definition: footprint.h:423
void SetOrientation(const EDA_ANGLE &aNewAngle)
Definition: footprint.cpp:2406
void SetLocalSolderPasteMarginRatio(std::optional< double > aRatio)
Definition: footprint.h:273
void SetPath(const KIID_PATH &aPath)
Definition: footprint.h:252
void SetKeywords(const wxString &aKeywords)
Definition: footprint.h:249
void SetAttributes(int aAttributes)
Definition: footprint.h:279
PCB_FIELD & Value()
read/write accessors:
Definition: footprint.h:626
void SetLocalZoneConnection(ZONE_CONNECTION aType)
Definition: footprint.h:275
const LIB_ID & GetFPID() const
Definition: footprint.h:236
PCB_FIELD & Reference()
Definition: footprint.h:627
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: footprint.cpp:969
std::vector< FP_3DMODEL > & Models()
Definition: footprint.h:208
void SetLibDescription(const wxString &aDesc)
Definition: footprint.h:246
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition: footprint.h:267
void SetLocalClearance(std::optional< int > aClearance)
Definition: footprint.h:264
void SetLocalSolderPasteMargin(std::optional< int > aMargin)
Definition: footprint.h:270
VECTOR2I GetPosition() const override
Definition: footprint.h:212
VECTOR3D m_Offset
3D model offset (mm)
Definition: footprint.h:99
VECTOR3D m_Rotation
3D model rotation (degrees)
Definition: footprint.h:98
VECTOR3D m_Scale
3D model scaling factor (dimensionless)
Definition: footprint.h:97
wxString m_Filename
The 3D shape filename in 3D library.
Definition: footprint.h:101
Helper for storing and iterating over GAL_LAYER_IDs.
Definition: layer_ids.h:308
GAL_SET & set()
Definition: layer_ids.h:324
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:77
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
Definition: kiid.h:49
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:51
const UTF8 & GetLibItemName() const
Definition: lib_id.h:102
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
Definition: richio.h:93
virtual char * ReadLine()=0
Read a line of text into the buffer and increments the line number counter.
virtual const wxString & GetSource() const
Returns the name of the source of the lines in an abstract sense.
Definition: richio.h:121
virtual unsigned LineNumber() const
Return the line number of the last line read from this LINE_READER.
Definition: richio.h:147
char * Line() const
Return a pointer to the last line that was read in.
Definition: richio.h:129
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:49
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:737
Handle the data for a net.
Definition: netinfo.h:56
int GetNetCode() const
Definition: netinfo.h:108
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition: netinfo.h:381
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:59
void SetPortrait(bool aIsPortrait)
Rotate the paper page 90 degrees.
Definition: page_info.cpp:189
static const wxChar Custom[]
"User" defined page type
Definition: page_info.h:82
void SetHeightMils(double aHeightInMils)
Definition: page_info.cpp:261
void SetWidthMils(double aWidthInMils)
Definition: page_info.cpp:247
bool SetType(const wxString &aStandardPageDescriptionName, bool aIsPortrait=false)
Set the name of the page type and also the sizes and margins commonly associated with that type name.
Definition: page_info.cpp:122
A #PLUGIN derivation which could possibly be put into a DLL/DSO.
wxString m_error
for throwing exceptions
EDA_ANGLE degParse(const char *aValue, const char **nptrptr=nullptr)
Parse an ASCII decimal floating point value which is certainly an angle in tenths of a degree.
void loadMODULE_TEXT(PCB_TEXT *aText)
bool CanReadFootprint(const wxString &aFileName) const override
Checks if this PCB_IO can read a footprint from specified file or directory.
PROGRESS_REPORTER * m_progressReporter
may be NULL, no ownership
BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const STRING_UTF8_MAP *aProperties=nullptr, PROJECT *aProject=nullptr) override
Load information from some input file format that this PCB_IO implementation knows about into either ...
void loadFP_SHAPE(FOOTPRINT *aFootprint)
FOOTPRINT * FootprintLoad(const wxString &aLibraryPath, const wxString &aFootprintName, bool aKeepUUID=false, const STRING_UTF8_MAP *aProperties=nullptr) override
Load a footprint having aFootprintName from the aLibraryPath containing a library format that this PC...
std::vector< int > m_netCodes
net codes mapping for boards being loaded
long long GetLibraryTimestamp(const wxString &aLibraryPath) const override
Generate a timestamp representing all the files in the library (including the library directory).
void loadAllSections(bool doAppend)
unsigned m_lineCount
for progress reporting
void cacheLib(const wxString &aLibraryPath)
we only cache one footprint library for now, this determines which one.
void loadPAD(FOOTPRINT *aFootprint)
double biuToDisk
convert from BIUs to disk engineering units with this scale factor
static LSET leg_mask2new(int cu_count, unsigned aMask)
void loadTrackList(int aStructType)
Read a list of segments (Tracks and Vias, or Segzones)
LINE_READER * m_reader
no ownership here.
void SetReader(LINE_READER *aReader)
double diskToBiu
convert from disk engineering units to BIUs
BIU biuParse(const char *aValue, const char **nptrptr=nullptr)
Parse an ASCII decimal floating point value and scales it into a BIU according to the current value o...
wxString m_field
reused to stuff FOOTPRINT fields.
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, bool aBestEfforts, const STRING_UTF8_MAP *aProperties=nullptr) override
Return a list of footprint names contained within the library at aLibraryPath.
void checkpoint()
Converts net code using the mapping table if available, otherwise returns unchanged net code.
bool DeleteLibrary(const wxString &aLibraryPath, const STRING_UTF8_MAP *aProperties=nullptr) override
Delete an existing library and returns true, or if library does not exist returns false,...
void init(const STRING_UTF8_MAP *aProperties)
initialize PLUGIN like a constructor would, and futz with fresh BOARD if needed.
void loadFOOTPRINT(FOOTPRINT *aFootprint)
static int getVersion(LINE_READER *aReader)
void load3D(FOOTPRINT *aFootprint)
bool CanReadBoard(const wxString &aFileName) const override
Checks if this PCB_IO can read the specified board file.
int getNetCode(int aNetCode)
bool IsLibraryWritable(const wxString &aLibraryPath) override
Return true if the library at aLibraryPath is writable.
int m_loading_format_version
which BOARD_FORMAT_VERSION am I Load()ing?
static PCB_LAYER_ID leg_layer2new(int cu_count, int aLayerNum)
A base class that BOARD loading and saving plugins should derive from.
Definition: pcb_io.h:72
BOARD * m_board
The board BOARD being worked on, no ownership here.
Definition: pcb_io.h:343
virtual bool CanReadFootprint(const wxString &aFileName) const
Checks if this PCB_IO can read a footprint from specified file or directory.
Definition: pcb_io.cpp:59
const STRING_UTF8_MAP * m_props
Properties passed via Save() or Load(), no ownership, may be NULL.
Definition: pcb_io.h:346
virtual bool CanReadBoard(const wxString &aFileName) const
Checks if this PCB_IO can read the specified board file.
Definition: pcb_io.cpp:43
The parser for PCB_PLOT_PARAMS.
Parameters and options when plotting/printing a board.
std::optional< bool > GetLegacyPlotViaOnMaskLayer() const
void Parse(PCB_PLOT_PARAMS_PARSER *aParser)
void SetWidth(int aWidth)
Definition: pcb_track.h:115
void SetEnd(const VECTOR2I &aEnd)
Definition: pcb_track.h:118
void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_track.h:111
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void Report(const wxString &aMessage)=0
Display aMessage in the progress bar dialog.
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).
Container for project specific data.
Definition: project.h:62
Represent a set of closed polygons.
void InflateWithLinkedHoles(int aFactor, CORNER_STRATEGY aCornerStrategy, int aMaxError, POLYGON_MODE aFastMode)
Perform outline inflation/deflation, using round corners.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
int NewOutline()
Creates a new empty polygon in the set and returns its index.
A name/value tuple with unique names and optional values.
Simple container to manage line stroke parameters.
Definition: stroke_params.h:81
Hold the information shown in the lower right corner of a plot, printout, or editing view.
Definition: title_block.h:41
void SetRevision(const wxString &aRevision)
Definition: title_block.h:81
void SetComment(int aIdx, const wxString &aComment)
Definition: title_block.h:101
void SetTitle(const wxString &aTitle)
Definition: title_block.h:58
void SetCompany(const wxString &aCompany)
Definition: title_block.h:91
void SetDate(const wxString &aDate)
Set the date field, and defaults to the current time and date.
Definition: title_block.h:71
wxString wx_str() const
Definition: utf8.cpp:45
T y
Definition: vector3.h:63
T z
Definition: vector3.h:64
T x
Definition: vector3.h:62
Read lines of text from another LINE_READER but only returns non-comment lines and non-blank lines wi...
Definition: filter_reader.h:69
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
ZONE_SETTINGS handles zones parameters.
Definition: zone_settings.h:72
static int GetDefaultHatchPitch()
Definition: zone.cpp:1054
This file is part of the common library.
#define FIRST_COPPER_LAYER
static bool isSpace(char cc)
Test for whitespace.
Definition: dsnlexer.cpp: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:74
@ FP_EXCLUDE_FROM_POS_FILES
Definition: footprint.h:75
@ FP_EXCLUDE_FROM_BOM
Definition: footprint.h:76
@ FP_THROUGH_HOLE
Definition: footprint.h:73
void ignore_unused(const T &)
Definition: ignore.h:24
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Adhes
Definition: layer_ids.h:97
@ Edge_Cuts
Definition: layer_ids.h:113
@ Dwgs_User
Definition: layer_ids.h:109
@ F_Paste
Definition: layer_ids.h:101
@ Cmts_User
Definition: layer_ids.h:110
@ F_Adhes
Definition: layer_ids.h:98
@ B_Mask
Definition: layer_ids.h:106
@ B_Cu
Definition: layer_ids.h:95
@ Eco1_User
Definition: layer_ids.h:111
@ F_Mask
Definition: layer_ids.h:107
@ B_Paste
Definition: layer_ids.h:100
@ F_SilkS
Definition: layer_ids.h:104
@ Eco2_User
Definition: layer_ids.h:112
@ B_SilkS
Definition: layer_ids.h:103
@ F_Cu
Definition: layer_ids.h:64
This file contains miscellaneous commonly used macros and functions.
PAD_DRILL_SHAPE
The set of pad drill shapes, used with PAD::{Set,Get}DrillShape()
Definition: padstack.h:63
PAD_ATTRIB
The set of pad shapes, used with PAD::{Set,Get}Attribute().
Definition: padstack.h:74
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
Definition: padstack.h:46
std::map< wxString, FOOTPRINT * > FOOTPRINT_MAP
Definition: pcb_io_eagle.h:46
static GR_TEXT_V_ALIGN_T vertJustify(const char *vertical)
static int intParse(const char *next, const char **out=nullptr)
Parse an ASCII integer string with possible leading whitespace into an integer and updates the pointe...
#define SILKSCREEN_N_BACK
#define ECO2_N
#define DRAW_N
#define PCB_LEGACY_TEXT_is_DIVERS
#define ADHESIVE_N_FRONT
#define SZ(x)
Get the length of a string constant, at compile time.
static const char delims[]
#define TESTSUBSTR(x)
C sub-string compare test for a specific length of characters.
#define ECO1_N
#define LAST_NON_COPPER_LAYER
PCB_IO_KICAD_LEGACY::BIU BIU
unsigned LEG_MASK
#define SOLDERMASK_N_FRONT
#define SOLDERMASK_N_BACK
#define EDGE_N
bool is_leg_copperlayer_valid(int aCu_Count, int aLegacyLayerNum)
#define SOLDERPASTE_N_BACK
int layerMaskCountSet(LEG_MASK aMask)
Count the number of set layers in the mask.
static long hexParse(const char *next, const char **out=nullptr)
Parse an ASCII hex integer string with possible leading whitespace into a long integer and updates th...
#define SOLDERPASTE_N_FRONT
#define READLINE(rdr)
#define COMMENT_N
#define PCB_LEGACY_TEXT_is_REFERENCE
unsigned LAYER_MSK
#define LAYER_N_FRONT
#define ADHESIVE_N_BACK
static GR_TEXT_H_ALIGN_T horizJustify(const char *horizontal)
#define SILKSCREEN_N_FRONT
#define TESTLINE(x)
C string compare test for a specific length of characters.
#define ALL_CU_LAYERS
boost::ptr_map< std::string, FOOTPRINT > FOOTPRINT_MAP
#define FIRST_NON_COPPER_LAYER
#define FIRST_LAYER
#define LAYER_N_BACK
#define PCB_LEGACY_TEXT_is_VALUE
static bool isSpace(int c)
#define FOOTPRINT_LIBRARY_HEADER_CNT
#define FOOTPRINT_LIBRARY_HEADER
VIATYPE
Definition: pcb_track.h:66
CITER next(CITER it)
Definition: ptree.cpp:126
const char * delims
wxString ConvertToNewOverbarNotation(const wxString &aOldStr)
Convert the old ~...~ overbar notation to the new ~{...} one.
wxString From_UTF8(const char *cstring)
int ReadDelimitedText(wxString *aDest, const char *aSource)
Copy bytes from aSource delimited string segment to aDest wxString.
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Checks aName for illegal file name characters.
char * StrPurge(char *text)
Remove leading and training spaces, tabs and end of line chars in text.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: string_utils.h:391
const double IU_PER_MM
Definition: base_units.h:76
const double IU_PER_MILS
Definition: base_units.h:77
static LAYER_T ParseType(const char *aType)
Convert a string to a LAYER_T.
Definition: board.cpp:651
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:121
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:673
ZONE_BORDER_DISPLAY_STYLE
Zone border styles.
Definition: zone_settings.h:50
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:47