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