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