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  // ignore
658  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->GraphicalItemsList().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->PadsList().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->GraphicalItemsList().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 endContour = false;
2479  int holeIndex = -1; // -1 is the main outline; holeIndex >= 0 = hole index
2480  char buf[1024];
2481  char* line;
2482  char* saveptr;
2483 
2484  while( ( line = READLINE( m_reader ) ) != NULL )
2485  {
2486  const char* data;
2487 
2488  if( TESTLINE( "ZCorner" ) ) // new corner of the zone outlines found
2489  {
2490  // e.g. "ZCorner 25650 49500 0"
2491  BIU x = biuParse( line + SZ( "ZCorner" ), &data );
2492  BIU y = biuParse( data, &data );
2493 
2494  if( endContour )
2495  {
2496  // the previous corner was the last corner of a contour.
2497  // so this corner is the first of a new hole
2498  endContour = false;
2499  zc->NewHole();
2500  holeIndex++;
2501  }
2502 
2503  zc->AppendCorner( wxPoint( x, y ), holeIndex );
2504 
2505  // Is this corner the end of current contour?
2506  // the next corner (if any) will be stored in a new contour (a hole)
2507  // intParse( data )returns 0 = usual corner, 1 = last corner of the current contour:
2508  endContour = intParse( data );
2509  }
2510 
2511  else if( TESTLINE( "ZInfo" ) ) // general info found
2512  {
2513  // e.g. 'ZInfo 479194B1 310 "COMMON"'
2514  time_t timestamp = hexParse( line + SZ( "ZInfo" ), &data );
2515  int netcode = intParse( data, &data );
2516 
2517  if( ReadDelimitedText( buf, data, sizeof(buf) ) > (int) sizeof(buf) )
2518  {
2519  THROW_IO_ERROR( "ZInfo netname too long" );
2520  }
2521 
2522  zc->SetTimeStamp( timestamp );
2523  // Init the net code only, not the netname, to be sure
2524  // the zone net name is the name read in file.
2525  // (When mismatch, the user will be prompted in DRC, to fix the actual name)
2526  zc->BOARD_CONNECTED_ITEM::SetNetCode( getNetCode( netcode ) );
2527  }
2528 
2529  else if( TESTLINE( "ZLayer" ) ) // layer found
2530  {
2531  LAYER_NUM layer_num = layerParse( line + SZ( "ZLayer" ) );
2532  zc->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2533  }
2534 
2535  else if( TESTLINE( "ZAux" ) ) // aux info found
2536  {
2537  // e.g. "ZAux 7 E"
2538  int ignore = intParse( line + SZ( "ZAux" ), &data );
2539  char* hopt = strtok_r( (char*) data, delims, &saveptr );
2540 
2541  if( !hopt )
2542  {
2543  m_error.Printf( wxT( "Bad ZAux for CZONE_CONTAINER '%s'" ), zc->GetNetname().GetData() );
2545  }
2546 
2547  switch( *hopt ) // upper case required
2548  {
2549  case 'N': outline_hatch = ZONE_CONTAINER::NO_HATCH; break;
2550  case 'E': outline_hatch = ZONE_CONTAINER::DIAGONAL_EDGE; break;
2551  case 'F': outline_hatch = ZONE_CONTAINER::DIAGONAL_FULL; break;
2552 
2553  default:
2554  m_error.Printf( wxT( "Bad ZAux for CZONE_CONTAINER '%s'" ), zc->GetNetname().GetData() );
2556  }
2557 
2558  (void) ignore;
2559 
2560  // Set hatch mode later, after reading corner outline data
2561  }
2562 
2563  else if( TESTLINE( "ZSmoothing" ) )
2564  {
2565  // e.g. "ZSmoothing 0 0"
2566  int smoothing = intParse( line + SZ( "ZSmoothing" ), &data );
2567  BIU cornerRadius = biuParse( data );
2568 
2569  if( smoothing >= ZONE_SETTINGS::SMOOTHING_LAST || smoothing < 0 )
2570  {
2571  m_error.Printf( wxT( "Bad ZSmoothing for CZONE_CONTAINER '%s'" ), zc->GetNetname().GetData() );
2573  }
2574 
2575  zc->SetCornerSmoothingType( smoothing );
2576  zc->SetCornerRadius( cornerRadius );
2577  }
2578 
2579  else if( TESTLINE( "ZKeepout" ) )
2580  {
2581  zc->SetIsKeepout( true );
2582  // e.g. "ZKeepout tracks N vias N pads Y"
2583  data = strtok_r( line + SZ( "ZKeepout" ), delims, &saveptr );
2584 
2585  while( data )
2586  {
2587  if( !strcmp( data, "tracks" ) )
2588  {
2589  data = strtok_r( NULL, delims, &saveptr );
2590  zc->SetDoNotAllowTracks( data && *data == 'N' );
2591  }
2592  else if( !strcmp( data, "vias" ) )
2593  {
2594  data = strtok_r( NULL, delims, &saveptr );
2595  zc->SetDoNotAllowVias( data && *data == 'N' );
2596  }
2597  else if( !strcmp( data, "copperpour" ) )
2598  {
2599  data = strtok_r( NULL, delims, &saveptr );
2600  zc->SetDoNotAllowCopperPour( data && *data == 'N' );
2601  }
2602 
2603  data = strtok_r( NULL, delims, &saveptr );
2604  }
2605  }
2606 
2607  else if( TESTLINE( "ZOptions" ) )
2608  {
2609  // e.g. "ZOptions 0 32 F 200 200"
2610  int fillmode = intParse( line + SZ( "ZOptions" ), &data );
2611  int arcsegcount = intParse( data, &data );
2612  char fillstate = data[1]; // here e.g. " F"
2613  BIU thermalReliefGap = biuParse( data += 2 , &data ); // +=2 for " F"
2614  BIU thermalReliefCopperBridge = biuParse( data );
2615 
2616  zc->SetFillMode( fillmode ? 1 : 0 );
2617 
2618  // @todo ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF: don't really want pcbnew.h
2619  // in here, after all, its a PLUGIN and global data is evil.
2620  // put in accessor
2621  if( arcsegcount >= 32 )
2622  arcsegcount = 32;
2623 
2624  zc->SetArcSegmentCount( arcsegcount );
2625  zc->SetIsFilled( fillstate == 'S' );
2626  zc->SetThermalReliefGap( thermalReliefGap );
2627  zc->SetThermalReliefCopperBridge( thermalReliefCopperBridge );
2628  }
2629 
2630  else if( TESTLINE( "ZClearance" ) ) // Clearance and pad options info found
2631  {
2632  // e.g. "ZClearance 40 I"
2633  BIU clearance = biuParse( line + SZ( "ZClearance" ), &data );
2634  char* padoption = strtok_r( (char*) data, delims, &saveptr ); // data: " I"
2635 
2636  ZoneConnection popt;
2637  switch( *padoption )
2638  {
2639  case 'I': popt = PAD_ZONE_CONN_FULL; break;
2640  case 'T': popt = PAD_ZONE_CONN_THERMAL; break;
2641  case 'H': popt = PAD_ZONE_CONN_THT_THERMAL; break;
2642  case 'X': popt = PAD_ZONE_CONN_NONE; break;
2643 
2644  default:
2645  m_error.Printf( wxT( "Bad ZClearance padoption for CZONE_CONTAINER '%s'" ),
2646  zc->GetNetname().GetData() );
2648  }
2649 
2650  zc->SetZoneClearance( clearance );
2651  zc->SetPadConnection( popt );
2652  }
2653 
2654  else if( TESTLINE( "ZMinThickness" ) )
2655  {
2656  BIU thickness = biuParse( line + SZ( "ZMinThickness" ) );
2657  zc->SetMinThickness( thickness );
2658  }
2659 
2660  else if( TESTLINE( "ZPriority" ) )
2661  {
2662  int priority = intParse( line + SZ( "ZPriority" ) );
2663  zc->SetPriority( priority );
2664  }
2665 
2666  else if( TESTLINE( "$POLYSCORNERS" ) )
2667  {
2668  // Read the PolysList (polygons that are the solid areas in the filled zone)
2669  SHAPE_POLY_SET polysList;
2670 
2671  bool makeNewOutline = true;
2672 
2673  while( ( line = READLINE( m_reader ) ) != NULL )
2674  {
2675  if( TESTLINE( "$endPOLYSCORNERS" ) )
2676  break;
2677 
2678  // e.g. "39610 43440 0 0"
2679  BIU x = biuParse( line, &data );
2680  BIU y = biuParse( data, &data );
2681 
2682  if( makeNewOutline )
2683  polysList.NewOutline();
2684 
2685  polysList.Append( x, y );
2686 
2687  bool end_contour = intParse( data, &data ); // end_countour was a bool when file saved, so '0' or '1' here
2688  intParse( data ); // skip corner utility flag
2689 
2690  makeNewOutline = end_contour;
2691  }
2692 
2693  zc->AddFilledPolysList( polysList );
2694  }
2695 
2696  else if( TESTLINE( "$FILLSEGMENTS" ) )
2697  {
2698  while( ( line = READLINE( m_reader ) ) != NULL )
2699  {
2700  if( TESTLINE( "$endFILLSEGMENTS" ) )
2701  break;
2702 
2703  // e.g. ""%d %d %d %d\n"
2704  BIU sx = biuParse( line, &data );
2705  BIU sy = biuParse( data, &data );
2706  BIU ex = biuParse( data, &data );
2707  BIU ey = biuParse( data );
2708 
2709  zc->FillSegments().push_back( SEGMENT( wxPoint( sx, sy ), wxPoint( ex, ey ) ) );
2710  }
2711  }
2712 
2713  else if( TESTLINE( "$endCZONE_OUTLINE" ) )
2714  {
2715  // Ensure keepout does not have a net
2716  // (which have no sense for a keepout zone)
2717  if( zc->GetIsKeepout() )
2718  zc->SetNetCode( NETINFO_LIST::UNCONNECTED );
2719 
2720  // should always occur, but who knows, a zone without two corners
2721  // is no zone at all, it's a spot?
2722 
2723  if( zc->GetNumCorners() > 2 )
2724  {
2725  if( !zc->IsOnCopperLayer() )
2726  {
2727  zc->SetFillMode( 0 );
2728  zc->SetNetCode( NETINFO_LIST::UNCONNECTED );
2729  }
2730 
2731  // Hatch here, after outlines corners are read
2732  // Set hatch here, after outlines corners are read
2733  zc->SetHatch( outline_hatch, Mils2iu( ZONE_CONTAINER::GetDefaultHatchPitchMils() ),
2734  true );
2735 
2736  m_board->Add( zc.release() );
2737  }
2738 
2739  return; // preferred exit
2740  }
2741  }
2742 
2743  THROW_IO_ERROR( "Missing '$endCZONE_OUTLINE'" );
2744 }
2745 
2746 
2748 {
2749  unique_ptr<DIMENSION> dim( new DIMENSION( m_board ) );
2750 
2751  char* line;
2752  char* saveptr;
2753 
2754  while( ( line = READLINE( m_reader ) ) != NULL )
2755  {
2756  const char* data;
2757 
2758  if( TESTLINE( "$endCOTATION" ) )
2759  {
2760  m_board->Add( dim.release(), ADD_APPEND );
2761  return; // preferred exit
2762  }
2763 
2764  else if( TESTLINE( "Va" ) )
2765  {
2766  BIU value = biuParse( line + SZ( "Va" ) );
2767  dim->SetValue( value );
2768  }
2769 
2770  else if( TESTLINE( "Ge" ) )
2771  {
2772  LAYER_NUM layer_num;
2773  unsigned long timestamp;
2774  int shape;
2775  int ilayer;
2776 
2777  sscanf( line + SZ( "Ge" ), " %d %d %lX", &shape, &ilayer, &timestamp );
2778 
2779  if( ilayer < FIRST_NON_COPPER_LAYER )
2780  layer_num = FIRST_NON_COPPER_LAYER;
2781  else if( ilayer > LAST_NON_COPPER_LAYER )
2782  layer_num = LAST_NON_COPPER_LAYER;
2783  else
2784  layer_num = ilayer;
2785 
2786  dim->SetLayer( leg_layer2new( m_cu_count, layer_num ) );
2787  dim->SetTimeStamp( (time_t) timestamp );
2788  dim->SetShape( shape );
2789  }
2790 
2791  else if( TESTLINE( "Te" ) )
2792  {
2793  char buf[2048];
2794 
2795  ReadDelimitedText( buf, line + SZ( "Te" ), sizeof(buf) );
2796  dim->SetText( FROM_UTF8( buf ) );
2797  }
2798 
2799  else if( TESTLINE( "Po" ) )
2800  {
2801  // sscanf( Line + 2, " %d %d %d %d %d %d %d", &m_Text->m_Pos.x, &m_Text->m_Pos.y,
2802  // &m_Text->m_Size.x, &m_Text->m_Size.y, &thickness, &orientation, &normal_display );
2803 
2804  BIU pos_x = biuParse( line + SZ( "Po" ), &data );
2805  BIU pos_y = biuParse( data, &data );
2806  BIU width = biuParse( data, &data );
2807  BIU height = biuParse( data, &data );
2808  BIU thickn = biuParse( data, &data );
2809  double orient = degParse( data, &data );
2810  char* mirror = strtok_r( (char*) data, delims, &saveptr );
2811 
2812  // This sets both DIMENSION's position and internal m_Text's.
2813  // @todo: But why do we even know about internal m_Text?
2814  dim->SetPosition( wxPoint( pos_x, pos_y ) );
2815  dim->SetTextSize( wxSize( width, height ) );
2816 
2817  dim->Text().SetMirrored( mirror && *mirror == '0' );
2818  dim->Text().SetThickness( thickn );
2819  dim->Text().SetTextAngle( orient );
2820  }
2821 
2822  else if( TESTLINE( "Sb" ) )
2823  {
2824  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_crossBarOx, &m_crossBarOy, &m_crossBarFx, &m_crossBarFy, &m_Width );
2825 
2826  int ignore = biuParse( line + SZ( "Sb" ), &data );
2827  BIU crossBarOx = biuParse( data, &data );
2828  BIU crossBarOy = biuParse( data, &data );
2829  BIU crossBarFx = biuParse( data, &data );
2830  BIU crossBarFy = biuParse( data, &data );
2831  BIU width = biuParse( data );
2832 
2833  dim->m_crossBarO.x = crossBarOx;
2834  dim->m_crossBarO.y = crossBarOy;
2835  dim->m_crossBarF.x = crossBarFx;
2836  dim->m_crossBarF.y = crossBarFy;
2837  dim->SetWidth( width );
2838  (void) ignore;
2839  }
2840 
2841  else if( TESTLINE( "Sd" ) )
2842  {
2843  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_featureLineDOx, &m_featureLineDOy, &m_featureLineDFx, &m_featureLineDFy, &Dummy );
2844 
2845  int ignore = intParse( line + SZ( "Sd" ), &data );
2846  BIU featureLineDOx = biuParse( data, &data );
2847  BIU featureLineDOy = biuParse( data, &data );
2848  BIU featureLineDFx = biuParse( data, &data );
2849  BIU featureLineDFy = biuParse( data );
2850 
2851  dim->m_featureLineDO.x = featureLineDOx;
2852  dim->m_featureLineDO.y = featureLineDOy;
2853  dim->m_featureLineDF.x = featureLineDFx;
2854  dim->m_featureLineDF.y = featureLineDFy;
2855  (void) ignore;
2856  }
2857 
2858  else if( TESTLINE( "Sg" ) )
2859  {
2860  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_featureLineGOx, &m_featureLineGOy, &m_featureLineGFx, &m_featureLineGFy, &Dummy );
2861 
2862  int ignore = intParse( line + SZ( "Sg" ), &data );
2863  BIU featureLineGOx = biuParse( data, &data );
2864  BIU featureLineGOy = biuParse( data, &data );
2865  BIU featureLineGFx = biuParse( data, &data );
2866  BIU featureLineGFy = biuParse( data );
2867 
2868  dim->m_featureLineGO.x = featureLineGOx;
2869  dim->m_featureLineGO.y = featureLineGOy;
2870  dim->m_featureLineGF.x = featureLineGFx;
2871  dim->m_featureLineGF.y = featureLineGFy;
2872  (void) ignore;
2873  }
2874 
2875  else if( TESTLINE( "S1" ) )
2876  {
2877  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_arrowD1Ox, &m_arrowD1Oy, &m_arrowD1Fx, &m_arrowD1Fy, &Dummy );
2878 
2879  int ignore = intParse( line + SZ( "S1" ), &data );
2880  biuParse( data, &data ); // skipping excessive data
2881  biuParse( data, &data ); // skipping excessive data
2882  BIU arrowD1Fx = biuParse( data, &data );
2883  BIU arrowD1Fy = biuParse( data );
2884 
2885  dim->m_arrowD1F.x = arrowD1Fx;
2886  dim->m_arrowD1F.y = arrowD1Fy;
2887  (void) ignore;
2888  }
2889 
2890  else if( TESTLINE( "S2" ) )
2891  {
2892  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_arrowD2Ox, &m_arrowD2Oy, &m_arrowD2Fx, &m_arrowD2Fy, &Dummy );
2893 
2894  int ignore = intParse( line + SZ( "S2" ), &data );
2895  biuParse( data, &data ); // skipping excessive data
2896  biuParse( data, &data ); // skipping excessive data
2897  BIU arrowD2Fx = biuParse( data, &data );
2898  BIU arrowD2Fy = biuParse( data, &data );
2899 
2900  dim->m_arrowD2F.x = arrowD2Fx;
2901  dim->m_arrowD2F.y = arrowD2Fy;
2902  (void) ignore;
2903  }
2904 
2905  else if( TESTLINE( "S3" ) )
2906  {
2907  // sscanf( Line + 2, " %d %d %d %d %d %d\n", &Dummy, &m_arrowG1Ox, &m_arrowG1Oy, &m_arrowG1Fx, &m_arrowG1Fy, &Dummy );
2908  int ignore = intParse( line + SZ( "S3" ), &data );
2909  biuParse( data, &data ); // skipping excessive data
2910  biuParse( data, &data ); // skipping excessive data
2911  BIU arrowG1Fx = biuParse( data, &data );
2912  BIU arrowG1Fy = biuParse( data, &data );
2913 
2914  dim->m_arrowG1F.x = arrowG1Fx;
2915  dim->m_arrowG1F.y = arrowG1Fy;
2916  (void) ignore;
2917  }
2918 
2919  else if( TESTLINE( "S4" ) )
2920  {
2921  // sscanf( Line + 2, " %d %d %d %d %d %d", &Dummy, &m_arrowG2Ox, &m_arrowG2Oy, &m_arrowG2Fx, &m_arrowG2Fy, &Dummy );
2922  int ignore = intParse( line + SZ( "S4" ), &data );
2923  biuParse( data, &data ); // skipping excessive data
2924  biuParse( data, &data ); // skipping excessive data
2925  BIU arrowG2Fx = biuParse( data, &data );
2926  BIU arrowG2Fy = biuParse( data, &data );
2927 
2928  dim->m_arrowG2F.x = arrowG2Fx;
2929  dim->m_arrowG2F.y = arrowG2Fy;
2930  (void) ignore;
2931  }
2932  }
2933 
2934  THROW_IO_ERROR( "Missing '$endCOTATION'" );
2935 }
2936 
2937 
2939 {
2940  char* line;
2941 
2942  while( ( line = READLINE( m_reader ) ) != NULL )
2943  {
2944  const char* data;
2945 
2946  if( TESTLINE( "$EndPCB_TARGET" ) || TESTLINE( "$EndMIREPCB" ) )
2947  {
2948  return; // preferred exit
2949  }
2950 
2951  else if( TESTLINE( "Po" ) )
2952  {
2953  // 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 );
2954 
2955  int shape = intParse( line + SZ( "Po" ), &data );
2956 
2957  LAYER_NUM layer_num = layerParse( data, &data );
2958 
2959  BIU pos_x = biuParse( data, &data );
2960  BIU pos_y = biuParse( data, &data );
2961  BIU size = biuParse( data, &data );
2962  BIU width = biuParse( data, &data );
2963  time_t timestamp = hexParse( data );
2964 
2965  if( layer_num < FIRST_NON_COPPER_LAYER )
2966  layer_num = FIRST_NON_COPPER_LAYER;
2967 
2968  else if( layer_num > LAST_NON_COPPER_LAYER )
2969  layer_num = LAST_NON_COPPER_LAYER;
2970 
2971  PCB_TARGET* t = new PCB_TARGET( m_board, shape, leg_layer2new( m_cu_count, layer_num ),
2972  wxPoint( pos_x, pos_y ), size, width );
2973  m_board->Add( t, ADD_APPEND );
2974 
2975  t->SetTimeStamp( timestamp );
2976  }
2977  }
2978 
2979  THROW_IO_ERROR( "Missing '$EndDIMENSION'" );
2980 }
2981 
2982 
2983 BIU LEGACY_PLUGIN::biuParse( const char* aValue, const char** nptrptr )
2984 {
2985  char* nptr;
2986 
2987  errno = 0;
2988 
2989  double fval = strtod( aValue, &nptr );
2990 
2991  if( errno )
2992  {
2993  m_error.Printf( _( "invalid float number in file: '%s'\nline: %d, offset: %d" ),
2994  m_reader->GetSource().GetData(),
2995  m_reader->LineNumber(), aValue - m_reader->Line() + 1 );
2996 
2998  }
2999 
3000  if( aValue == nptr )
3001  {
3002  m_error.Printf( _( "missing float number in file: '%s'\nline: %d, offset: %d" ),
3003  m_reader->GetSource().GetData(),
3004  m_reader->LineNumber(), aValue - m_reader->Line() + 1 );
3005 
3007  }
3008 
3009  if( nptrptr )
3010  *nptrptr = nptr;
3011 
3012  fval *= diskToBiu;
3013 
3014  // fval is up into the whole number realm here, and should be bounded
3015  // within INT_MIN to INT_MAX since BIU's are nanometers.
3016  return KiROUND( fval );
3017 }
3018 
3019 
3020 double LEGACY_PLUGIN::degParse( const char* aValue, const char** nptrptr )
3021 {
3022  char* nptr;
3023 
3024  errno = 0;
3025 
3026  double fval = strtod( aValue, &nptr );
3027 
3028  if( errno )
3029  {
3030  m_error.Printf( _( "invalid float number in file: '%s'\nline: %d, offset: %d" ),
3031  m_reader->GetSource().GetData(), m_reader->LineNumber(), aValue - m_reader->Line() + 1 );
3032 
3034  }
3035 
3036  if( aValue == nptr )
3037  {
3038  m_error.Printf( _( "missing float number in file: '%s'\nline: %d, offset: %d" ),
3039  m_reader->GetSource().GetData(), m_reader->LineNumber(), aValue - m_reader->Line() + 1 );
3040 
3042  }
3043 
3044  if( nptrptr )
3045  *nptrptr = nptr;
3046 
3047  return fval;
3048 }
3049 
3050 
3051 void LEGACY_PLUGIN::init( const PROPERTIES* aProperties )
3052 {
3054  m_cu_count = 16;
3055  m_board = NULL;
3056  m_props = aProperties;
3057 
3058  // conversion factor for saving RAM BIUs to KICAD legacy file format.
3059  biuToDisk = 1.0/IU_PER_MM; // BIUs are nanometers & file is mm
3060 
3061  // Conversion factor for loading KICAD legacy file format into BIUs in RAM
3062  // Start by assuming the *.brd file is in deci-mils.
3063  // If we see "Units mm" in the $GENERAL section, set diskToBiu to 1000000.0
3064  // then, during the file loading process, to start a conversion from
3065  // mm to nanometers. The deci-mil legacy files have no such "Units" marker
3066  // so we must assume the file is in deci-mils until told otherwise.
3067 
3068  diskToBiu = IU_PER_MILS / 10; // BIUs are nanometers
3069 }
3070 
3071 
3072 void LEGACY_PLUGIN::SaveModule3D( const MODULE* me ) const
3073 {
3074  std::list<S3D_INFO>::const_iterator sM = me->Models().begin();
3075  std::list<S3D_INFO>::const_iterator eM = me->Models().end();
3076 
3077  while( sM != eM )
3078  {
3079  if( sM->m_Filename.empty() )
3080  {
3081  ++sM;
3082  continue;
3083  }
3084 
3085  fprintf( m_fp, "$SHAPE3D\n" );
3086 
3087  fprintf( m_fp, "Na %s\n", EscapedUTF8( sM->m_Filename ).c_str() );
3088 
3089  fprintf(m_fp,
3090 #if defined(DEBUG)
3091  // use old formats for testing, just to verify compatibility
3092  // using "diff", then switch to more concise form for release builds.
3093  "Sc %lf %lf %lf\n",
3094 #else
3095  "Sc %.10g %.10g %.10g\n",
3096 #endif
3097  sM->m_Scale.x,
3098  sM->m_Scale.y,
3099  sM->m_Scale.z );
3100 
3101  fprintf(m_fp,
3102 #if defined(DEBUG)
3103  "Of %lf %lf %lf\n",
3104 #else
3105  "Of %.10g %.10g %.10g\n",
3106 #endif
3107  sM->m_Offset.x,
3108  sM->m_Offset.y,
3109  sM->m_Offset.z );
3110 
3111  fprintf(m_fp,
3112 #if defined(DEBUG)
3113  "Ro %lf %lf %lf\n",
3114 #else
3115  "Ro %.10g %.10g %.10g\n",
3116 #endif
3117  sM->m_Rotation.x,
3118  sM->m_Rotation.y,
3119  sM->m_Rotation.z );
3120 
3121  fprintf( m_fp, "$EndSHAPE3D\n" );
3122 
3123  ++sM;
3124  }
3125 
3126  return;
3127 }
3128 
3129 
3130 //-----<FOOTPRINT LIBRARY FUNCTIONS>--------------------------------------------
3131 
3132 /*
3133 
3134  The legacy file format is being obsoleted and this code will have a short
3135  lifetime, so it only needs to be good enough for a short duration of time.
3136  Caching all the MODULEs is a bit memory intensive, but it is a considerably
3137  faster way of fulfilling the API contract. Otherwise, without the cache, you
3138  would have to re-read the file when searching for any MODULE, and this would
3139  be very problematic filling a FOOTPRINT_LIST via this PLUGIN API. If memory
3140  becomes a concern, consider the cache lifetime policy, which determines the
3141  time that a LP_CACHE is in RAM. Note PLUGIN lifetime also plays a role in
3142  cache lifetime.
3143 
3144 */
3145 
3146 
3147 #include <boost/ptr_container/ptr_map.hpp>
3148 #include <wx/filename.h>
3149 
3150 typedef boost::ptr_map< std::string, MODULE > MODULE_MAP;
3151 typedef MODULE_MAP::iterator MODULE_ITER;
3152 typedef MODULE_MAP::const_iterator MODULE_CITER;
3153 
3154 
3161 struct LP_CACHE
3162 {
3163  LEGACY_PLUGIN* m_owner; // my owner, I need its LEGACY_PLUGIN::loadMODULE()
3164  wxString m_lib_path;
3165  wxDateTime m_mod_time;
3166  MODULE_MAP m_modules; // map or tuple of footprint_name vs. MODULE*
3168 
3169  LP_CACHE( LEGACY_PLUGIN* aOwner, const wxString& aLibraryPath );
3170 
3171  // Most all functions in this class throw IO_ERROR exceptions. There are no
3172  // error codes nor user interface calls from here, nor in any PLUGIN.
3173  // Catch these exceptions higher up please.
3174 
3176  void Save();
3177 
3178  void SaveHeader( FILE* aFile );
3179 
3180  void SaveIndex( FILE* aFile );
3181 
3182  void SaveModules( FILE* aFile );
3183 
3184  void SaveEndOfFile( FILE* aFile )
3185  {
3186  fprintf( aFile, "$EndLIBRARY\n" );
3187  }
3188 
3189  void Load();
3190 
3191  void ReadAndVerifyHeader( LINE_READER* aReader );
3192 
3193  void SkipIndex( LINE_READER* aReader );
3194 
3195  void LoadModules( LINE_READER* aReader );
3196 
3197  wxDateTime GetLibModificationTime();
3198 };
3199 
3200 
3201 LP_CACHE::LP_CACHE( LEGACY_PLUGIN* aOwner, const wxString& aLibraryPath ) :
3202  m_owner( aOwner ),
3203  m_lib_path( aLibraryPath ),
3204  m_writable( true )
3205 {
3206 }
3207 
3208 
3210 {
3211  wxFileName fn( m_lib_path );
3212 
3213  // update the writable flag while we have a wxFileName, in a network this
3214  // is possibly quite dynamic anyway.
3215  m_writable = fn.IsFileWritable();
3216 
3217  return fn.GetModificationTime();
3218 }
3219 
3220 
3222 {
3223  FILE_LINE_READER reader( m_lib_path );
3224 
3225  ReadAndVerifyHeader( &reader );
3226  SkipIndex( &reader );
3227  LoadModules( &reader );
3228 
3229  // Remember the file modification time of library file when the
3230  // cache snapshot was made, so that in a networked environment we will
3231  // reload the cache as needed.
3233 }
3234 
3235 
3237 {
3238  char* line = aReader->ReadLine();
3239  char* saveptr;
3240 
3241  if( !line )
3242  goto L_bad_library;
3243 
3244  if( !TESTLINE( "PCBNEW-LibModule-V1" ) )
3245  goto L_bad_library;
3246 
3247  while( ( line = aReader->ReadLine() ) != NULL )
3248  {
3249  if( TESTLINE( "Units" ) )
3250  {
3251  const char* units = strtok_r( line + SZ( "Units" ), delims, &saveptr );
3252 
3253  if( !strcmp( units, "mm" ) )
3254  {
3255  m_owner->diskToBiu = IU_PER_MM;
3256  }
3257 
3258  }
3259  else if( TESTLINE( "$INDEX" ) )
3260  return;
3261  }
3262 
3263 L_bad_library:
3264  THROW_IO_ERROR( wxString::Format( _( "File '%s' is empty or is not a legacy library" ),
3265  m_lib_path.GetData() ) );
3266 }
3267 
3268 
3270 {
3271  // Some broken INDEX sections have more than one section, due to prior bugs.
3272  // So we must read the next line after $EndINDEX tag,
3273  // to see if this is not a new $INDEX tag.
3274  bool exit = false;
3275  char* line = aReader->Line();
3276 
3277  do
3278  {
3279  if( TESTLINE( "$INDEX" ) )
3280  {
3281  exit = false;
3282 
3283  while( ( line = aReader->ReadLine() ) != NULL )
3284  {
3285  if( TESTLINE( "$EndINDEX" ) )
3286  {
3287  exit = true;
3288  break;
3289  }
3290  }
3291  }
3292  else if( exit )
3293  break;
3294  } while( ( line = aReader->ReadLine() ) != NULL );
3295 }
3296 
3297 
3299 {
3300  m_owner->SetReader( aReader );
3301 
3302  char* line = aReader->Line();
3303 
3304  do
3305  {
3306  // test first for the $MODULE, even before reading because of INDEX bug.
3307  if( TESTLINE( "$MODULE" ) )
3308  {
3309  unique_ptr<MODULE> module( new MODULE( m_owner->m_board ) );
3310 
3311  std::string footprintName = StrPurge( line + SZ( "$MODULE" ) );
3312 
3313  // The footprint names in legacy libraries can contain the '/' and ':'
3314  // characters which will cause the LIB_ID parser to choke.
3315  ReplaceIllegalFileNameChars( &footprintName );
3316 
3317  // set the footprint name first thing, so exceptions can use name.
3318  module->SetFPID( LIB_ID( footprintName ) );
3319 
3320  m_owner->loadMODULE( module.get() );
3321 
3322  MODULE* m = module.release(); // exceptions after this are not expected.
3323 
3324  // Not sure why this is asserting on debug builds. The debugger shows the
3325  // strings are the same. If it's not really needed maybe it can be removed.
3326 // wxASSERT( footprintName == m->GetFPID().GetLibItemName() );
3327 
3328  /*
3329 
3330  There was a bug in old legacy library management code
3331  (pre-LEGACY_PLUGIN) which was introducing duplicate footprint names
3332  in legacy libraries without notification. To best recover from such
3333  bad libraries, and use them to their fullest, there are a few
3334  strategies that could be used. (Note: footprints must have unique
3335  names to be accepted into this cache.) The strategy used here is to
3336  append a differentiating version counter to the end of the name as:
3337  _v2, _v3, etc.
3338 
3339  */
3340 
3341  MODULE_CITER it = m_modules.find( footprintName );
3342 
3343  if( it == m_modules.end() ) // footprintName is not present in cache yet.
3344  {
3345  std::pair<MODULE_ITER, bool> r = m_modules.insert( footprintName, m );
3346 
3347  wxASSERT_MSG( r.second, wxT( "error doing cache insert using guaranteed unique name" ) );
3348  (void) r;
3349  }
3350 
3351  // Bad library has a duplicate of this footprintName, generate a
3352  // unique footprint name and load it anyway.
3353  else
3354  {
3355  bool nameOK = false;
3356  int version = 2;
3357  char buf[48];
3358 
3359  while( !nameOK )
3360  {
3361  std::string newName = footprintName;
3362 
3363  newName += "_v";
3364  sprintf( buf, "%d", version++ );
3365  newName += buf;
3366 
3367  it = m_modules.find( newName );
3368 
3369  if( it == m_modules.end() )
3370  {
3371  nameOK = true;
3372 
3373  m->SetFPID( LIB_ID( newName ) );
3374  std::pair<MODULE_ITER, bool> r = m_modules.insert( newName, m );
3375 
3376  wxASSERT_MSG( r.second, wxT( "error doing cache insert using guaranteed unique name" ) );
3377  (void) r;
3378  }
3379  }
3380  }
3381  }
3382 
3383  } while( ( line = aReader->ReadLine() ) != NULL );
3384 }
3385 
3386 
3387 void LEGACY_PLUGIN::cacheLib( const wxString& aLibraryPath )
3388 {
3389  if( !m_cache || m_cache->m_lib_path != aLibraryPath ||
3390  // somebody else on a network touched the library:
3392  {
3393  // a spectacular episode in memory management:
3394  delete m_cache;
3395  m_cache = new LP_CACHE( this, aLibraryPath );
3396  m_cache->Load();
3397  }
3398 }
3399 
3400 
3401 void LEGACY_PLUGIN::FootprintEnumerate( wxArrayString& aFootprintNames,
3402  const wxString& aLibraryPath,
3403  const PROPERTIES* aProperties )
3404 {
3405  LOCALE_IO toggle; // toggles on, then off, the C locale.
3406 
3407  init( aProperties );
3408 
3409  cacheLib( aLibraryPath );
3410 
3411  const MODULE_MAP& mods = m_cache->m_modules;
3412 
3413  for( MODULE_CITER it = mods.begin(); it != mods.end(); ++it )
3414  {
3415  aFootprintNames.Add( FROM_UTF8( it->first.c_str() ) );
3416  }
3417 }
3418 
3419 
3420 MODULE* LEGACY_PLUGIN::FootprintLoad( const wxString& aLibraryPath,
3421  const wxString& aFootprintName, const PROPERTIES* aProperties )
3422 {
3423  LOCALE_IO toggle; // toggles on, then off, the C locale.
3424 
3425  init( aProperties );
3426 
3427  cacheLib( aLibraryPath );
3428 
3429  const MODULE_MAP& mods = m_cache->m_modules;
3430 
3431  MODULE_CITER it = mods.find( TO_UTF8( aFootprintName ) );
3432 
3433  if( it == mods.end() )
3434  {
3435  /*
3436  THROW_IO_ERROR( wxString::Format( _( "No '%s' footprint in library '%s'" ),
3437  aFootprintName.GetData(), aLibraryPath.GetData() ) );
3438  */
3439 
3440  return NULL;
3441  }
3442 
3443  // copy constructor to clone the already loaded MODULE
3444  return new MODULE( *it->second );
3445 }
3446 
3447 
3448 bool LEGACY_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
3449 {
3450  wxFileName fn = aLibraryPath;
3451 
3452  if( !fn.FileExists() )
3453  return false;
3454 
3455  // Some of the more elaborate wxRemoveFile() crap puts up its own wxLog dialog
3456  // we don't want that. we want bare metal portability with no UI here.
3457  if( wxRemove( aLibraryPath ) )
3458  {
3460  _( "library '%s' cannot be deleted" ),
3461  aLibraryPath.GetData() ) );
3462  }
3463 
3464  if( m_cache && m_cache->m_lib_path == aLibraryPath )
3465  {
3466  delete m_cache;
3467  m_cache = 0;
3468  }
3469 
3470  return true;
3471 }
3472 
3473 
3474 bool LEGACY_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath )
3475 {
3476 #if 0 // no support for 32 Cu layers in legacy format
3477  return false;
3478 #else
3479  LOCALE_IO toggle;
3480 
3481  init( NULL );
3482 
3483  cacheLib( aLibraryPath );
3484 
3485  return m_cache->m_writable;
3486 #endif
3487 }
3488 
3489 
3491  m_cu_count( 16 ), // for FootprintLoad()
3492  m_board( 0 ),
3493  m_props( 0 ),
3494  m_reader( 0 ),
3495  m_fp( 0 ),
3496  m_cache( 0 ),
3497  m_mapping( new NETINFO_MAPPING() )
3498 {
3499  init( NULL );
3500 }
3501 
3502 
3504 {
3505  delete m_cache;
3506  delete m_mapping;
3507 }
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:534
int m_SolderMaskMargin
Solder mask margin.
void SetFileFormatVersionAtLoad(int aVersion)
Definition: class_board.h:276
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:558
#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:463
void SaveModules(FILE *aFile)
void SetThermalGap(int aGap)
Definition: class_module.h:194
EDA_TEXT_HJUSTIFY_T
Definition: eda_text.h:47
const ZONE_SETTINGS & GetZoneSettings() const
Definition: class_board.h:557
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:440
void SetLocalClearance(int aClearance)
Definition: class_module.h:180
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:531
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:555
#define LAYER_N_BACK
unsigned long timeStamp(wxXmlNode *aTree)
Make a unique time stamp.
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:155
LEGACY_PLUGIN * m_owner
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: class_board.h:549
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:188
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:150
#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:282
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:186
int m_loading_format_version
which BOARD_FORMAT_VERSION am I Load()ing?
#define ECO2_N
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:164
#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:439
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:160
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:462
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:71
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
Adds an item to the container.
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:191
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:533
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 FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Return a list of footprint names contained within the library at aLibraryPath.
void SetDesignSettings(const BOARD_DESIGN_SETTINGS &aDesignSettings)
Function SetDesignSettings.
Definition: class_board.h:543
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:255
LEGACY_PLUGIN::BIU BIU
HATCH_STYLE
Zone hatch styles.
Definition: class_zone.h:85
void SetFileName(const wxString &aFileName)
Definition: class_board.h:232
void SetPosition(const wxPoint &aPos) override
void SetPlotOptions(const PCB_PLOT_PARAMS &aOptions)
Definition: class_board.h:552
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:177
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:468
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.
Definition: class_netinfo.h:69
void SetLocalSolderPasteMargin(int aMargin)
Definition: class_module.h:183
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:246
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:169
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:447
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:171
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.
DLIST< BOARD_ITEM > & GraphicalItemsList()
Definition: class_module.h:137
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 > & PadsList()
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
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:165
#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:174
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:198
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:168