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