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