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