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