KiCad PCB EDA Suite
sch_legacy_plugin.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2016 CERN
5  * Copyright (C) 2016-2017 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * @author Wayne Stambaugh <stambaughw@gmail.com>
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 along
20  * with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <ctype.h>
24 #include <algorithm>
25 
26 #include <wx/mstream.h>
27 #include <wx/filename.h>
28 #include <wx/tokenzr.h>
29 
30 #include <drawtxt.h>
31 #include <kiway.h>
32 #include <kicad_string.h>
33 #include <richio.h>
34 #include <core/typeinfo.h>
35 #include <properties.h>
36 
37 #include <general.h>
38 #include <lib_field.h>
39 #include <sch_bus_entry.h>
40 #include <sch_marker.h>
41 #include <sch_junction.h>
42 #include <sch_line.h>
43 #include <sch_no_connect.h>
44 #include <sch_component.h>
45 #include <sch_text.h>
46 #include <sch_sheet.h>
47 #include <sch_bitmap.h>
48 #include <sch_legacy_plugin.h>
49 #include <template_fieldnames.h>
50 #include <class_sch_screen.h>
51 #include <class_libentry.h>
52 #include <class_library.h>
53 #include <lib_arc.h>
54 #include <lib_bezier.h>
55 #include <lib_circle.h>
56 #include <lib_pin.h>
57 #include <lib_polyline.h>
58 #include <lib_rectangle.h>
59 #include <lib_text.h>
60 #include <eeschema_id.h> // for MAX_UNIT_COUNT_PER_PACKAGE definition
61 #include <symbol_lib_table.h> // for PropPowerSymsOnly definintion.
62 
63 
64 // Must be the first line of part library document (.dcm) files.
65 #define DOCFILE_IDENT "EESchema-DOCLIB Version 2.0"
66 
67 #define SCH_PARSE_ERROR( text, reader, pos ) \
68  THROW_PARSE_ERROR( text, reader.GetSource(), reader.Line(), \
69  reader.LineNumber(), pos - reader.Line() )
70 
71 
72 // Token delimiters.
73 const char* delims = " \t\r\n";
74 
75 // Tokens to read/save graphic lines style
76 #define T_STYLE "style"
77 #define T_COLOR "rgb" // cannot be modifed (used by wxWidgets)
78 #define T_COLORA "rgba" // cannot be modifed (used by wxWidgets)
79 #define T_WIDTH "width"
80 
86 const wxChar traceSchLegacyPlugin[] = wxT( "KICAD_TRACE_SCH_LEGACY_PLUGIN" );
87 
88 
89 static bool is_eol( char c )
90 {
91  // The default file eol character used internally by KiCad.
92  // |
93  // | Possible eol if someone edited the file by hand on certain platforms.
94  // | |
95  // | | May have gone past eol with strtok().
96  // | | |
97  if( c == '\n' || c == '\r' || c == 0 )
98  return true;
99 
100  return false;
101 }
102 
103 
115 static bool strCompare( const char* aString, const char* aLine, const char** aOutput = NULL )
116 {
117  size_t len = strlen( aString );
118  bool retv = ( strncasecmp( aLine, aString, len ) == 0 ) &&
119  ( isspace( aLine[ len ] ) || aLine[ len ] == 0 );
120 
121  if( retv && aOutput )
122  {
123  const char* tmp = aLine;
124 
125  // Move past the end of the token.
126  tmp += len;
127 
128  // Move to the beginning of the next token.
129  while( *tmp && isspace( *tmp ) )
130  tmp++;
131 
132  *aOutput = tmp;
133  }
134 
135  return retv;
136 }
137 
138 
154 static int parseInt( FILE_LINE_READER& aReader, const char* aLine, const char** aOutput = NULL )
155 {
156  if( !*aLine )
157  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aLine );
158 
159  // Clear errno before calling strtol() in case some other crt call set it.
160  errno = 0;
161 
162  long retv = strtol( aLine, (char**) aOutput, 10 );
163 
164  // Make sure no error occurred when calling strtol().
165  if( errno == ERANGE )
166  SCH_PARSE_ERROR( "invalid integer value", aReader, aLine );
167 
168  // strtol does not strip off whitespace before the next token.
169  if( aOutput )
170  {
171  const char* next = *aOutput;
172 
173  while( *next && isspace( *next ) )
174  next++;
175 
176  *aOutput = next;
177  }
178 
179  return (int) retv;
180 }
181 
182 
198 static unsigned long parseHex( FILE_LINE_READER& aReader, const char* aLine,
199  const char** aOutput = NULL )
200 {
201  if( !*aLine )
202  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aLine );
203 
204  unsigned long retv;
205 
206  // Clear errno before calling strtoul() in case some other crt call set it.
207  errno = 0;
208  retv = strtoul( aLine, (char**) aOutput, 16 );
209 
210  // Make sure no error occurred when calling strtoul().
211  if( errno == ERANGE )
212  SCH_PARSE_ERROR( "invalid hexadecimal number", aReader, aLine );
213 
214  // Strip off whitespace before the next token.
215  if( aOutput )
216  {
217  // const char* next = aLine + strlen( token );
218 
219  const char* next = *aOutput;
220 
221  while( *next && isspace( *next ) )
222  next++;
223 
224  *aOutput = next;
225  }
226 
227  return retv;
228 }
229 
230 
246 static double parseDouble( FILE_LINE_READER& aReader, const char* aLine,
247  const char** aOutput = NULL )
248 {
249  if( !*aLine )
250  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aLine );
251 
252  // Clear errno before calling strtod() in case some other crt call set it.
253  errno = 0;
254 
255  double retv = strtod( aLine, (char**) aOutput );
256 
257  // Make sure no error occurred when calling strtod().
258  if( errno == ERANGE )
259  SCH_PARSE_ERROR( "invalid floating point number", aReader, aLine );
260 
261  // strtod does not strip off whitespace before the next token.
262  if( aOutput )
263  {
264  const char* next = *aOutput;
265 
266  while( *next && isspace( *next ) )
267  next++;
268 
269  *aOutput = next;
270  }
271 
272  return retv;
273 }
274 
275 
289 static char parseChar( FILE_LINE_READER& aReader, const char* aCurrentToken,
290  const char** aNextToken = NULL )
291 {
292  while( *aCurrentToken && isspace( *aCurrentToken ) )
293  aCurrentToken++;
294 
295  if( !*aCurrentToken )
296  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
297 
298  if( !isspace( *( aCurrentToken + 1 ) ) )
299  SCH_PARSE_ERROR( "expected single character token", aReader, aCurrentToken );
300 
301  if( aNextToken )
302  {
303  const char* next = aCurrentToken + 2;
304 
305  while( *next && isspace( *next ) )
306  next++;
307 
308  *aNextToken = next;
309  }
310 
311  return *aCurrentToken;
312 }
313 
314 
331 static void parseUnquotedString( wxString& aString, FILE_LINE_READER& aReader,
332  const char* aCurrentToken, const char** aNextToken = NULL,
333  bool aCanBeEmpty = false )
334 {
335  if( !*aCurrentToken )
336  {
337  if( aCanBeEmpty )
338  return;
339  else
340  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
341  }
342 
343  const char* tmp = aCurrentToken;
344 
345  while( *tmp && isspace( *tmp ) )
346  tmp++;
347 
348  if( !*tmp )
349  {
350  if( aCanBeEmpty )
351  return;
352  else
353  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
354  }
355 
356  std::string utf8;
357 
358  while( *tmp && !isspace( *tmp ) )
359  utf8 += *tmp++;
360 
361  aString = FROM_UTF8( utf8.c_str() );
362 
363  if( aString.IsEmpty() && !aCanBeEmpty )
364  SCH_PARSE_ERROR( _( "expected unquoted string" ), aReader, aCurrentToken );
365 
366  if( aNextToken )
367  {
368  const char* next = tmp;
369 
370  while( *next && isspace( *next ) )
371  next++;
372 
373  *aNextToken = next;
374  }
375 }
376 
377 
395 static void parseQuotedString( wxString& aString, FILE_LINE_READER& aReader,
396  const char* aCurrentToken, const char** aNextToken = NULL,
397  bool aCanBeEmpty = false )
398 {
399  if( !*aCurrentToken )
400  {
401  if( aCanBeEmpty )
402  return;
403  else
404  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
405  }
406 
407  const char* tmp = aCurrentToken;
408 
409  while( *tmp && isspace( *tmp ) )
410  tmp++;
411 
412  if( !*tmp )
413  {
414  if( aCanBeEmpty )
415  return;
416  else
417  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
418  }
419 
420  // Verify opening quote.
421  if( *tmp != '"' )
422  SCH_PARSE_ERROR( "expecting opening quote", aReader, aCurrentToken );
423 
424  tmp++;
425 
426  std::string utf8; // utf8 without escapes and quotes.
427 
428  // Fetch everything up to closing quote.
429  while( *tmp )
430  {
431  if( *tmp == '\\' )
432  {
433  tmp++;
434 
435  if( !*tmp )
436  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken );
437 
438  // Do not copy the escape byte if it is followed by \ or "
439  if( *tmp != '"' && *tmp != '\\' )
440  utf8 += '\\';
441 
442  utf8 += *tmp;
443  }
444  else if( *tmp == '"' ) // Closing double quote.
445  {
446  break;
447  }
448  else
449  {
450  utf8 += *tmp;
451  }
452 
453  tmp++;
454  }
455 
456  aString = FROM_UTF8( utf8.c_str() );
457 
458  if( aString.IsEmpty() && !aCanBeEmpty )
459  SCH_PARSE_ERROR( "expected quoted string", aReader, aCurrentToken );
460 
461  if( *tmp && *tmp != '"' )
462  SCH_PARSE_ERROR( "no closing quote for string found", aReader, tmp );
463 
464  // Move past the closing quote.
465  tmp++;
466 
467  if( aNextToken )
468  {
469  const char* next = tmp;
470 
471  while( *next && *next == ' ' )
472  next++;
473 
474  *aNextToken = next;
475  }
476 }
477 
478 
486 {
487  static int m_modHash; // Keep track of the modification status of the library.
488 
489  wxFileName m_libFileName; // Absolute path and file name is required here.
490  wxDateTime m_fileModTime;
491  LIB_ALIAS_MAP m_aliases; // Map of names of LIB_ALIAS pointers.
496  int m_libType; // Is this cache a component or symbol library.
497 
498  LIB_PART* loadPart( FILE_LINE_READER& aReader );
499  void loadHeader( FILE_LINE_READER& aReader );
500  void loadAliases( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
501  void loadField( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
502  void loadDrawEntries( std::unique_ptr< LIB_PART >& aPart,
503  FILE_LINE_READER& aReader );
504  void loadFootprintFilters( std::unique_ptr< LIB_PART >& aPart,
505  FILE_LINE_READER& aReader );
506  void loadDocs();
507  LIB_ARC* loadArc( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
508  LIB_CIRCLE* loadCircle( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
509  LIB_TEXT* loadText( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
510  LIB_RECTANGLE* loadRectangle( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
511  LIB_PIN* loadPin( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
512  LIB_POLYLINE* loadPolyLine( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
513  LIB_BEZIER* loadBezier( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
514 
515  FILL_T parseFillMode( FILE_LINE_READER& aReader, const char* aLine,
516  const char** aOutput );
517  bool checkForDuplicates( wxString& aAliasName );
518  LIB_ALIAS* removeAlias( LIB_ALIAS* aAlias );
519 
520  void saveDocFile();
521 
523 
524 public:
525  SCH_LEGACY_PLUGIN_CACHE( const wxString& aLibraryPath );
527 
528  int GetModifyHash() const { return m_modHash; }
529 
530  // Most all functions in this class throw IO_ERROR exceptions. There are no
531  // error codes nor user interface calls from here, nor in any SCH_PLUGIN objects.
532  // Catch these exceptions higher up please.
533 
535  void Save( bool aSaveDocFile = true );
536 
537  void Load();
538 
539  void AddSymbol( const LIB_PART* aPart );
540 
541  void DeleteAlias( const wxString& aAliasName );
542 
543  void DeleteSymbol( const wxString& aAliasName );
544 
545  wxDateTime GetLibModificationTime();
546 
547  bool IsFile( const wxString& aFullPathAndFileName ) const;
548 
549  bool IsFileChanged() const;
550 
551  void SetModified( bool aModified = true ) { m_isModified = aModified; }
552 
553  wxString GetLogicalName() const { return m_libFileName.GetName(); }
554 
555  void SetFileName( const wxString& aFileName ) { m_libFileName = aFileName; }
556 
557  wxString GetFileName() const { return m_libFileName.GetFullPath(); }
558 };
559 
560 
562 {
563  init( NULL );
564 }
565 
566 
568 {
569  delete m_cache;
570 }
571 
572 
573 void SCH_LEGACY_PLUGIN::init( KIWAY* aKiway, const PROPERTIES* aProperties )
574 {
575  m_version = 0;
576  m_rootSheet = NULL;
577  m_props = aProperties;
578  m_kiway = aKiway;
579  m_cache = NULL;
580  m_out = NULL;
581 }
582 
583 
584 SCH_SHEET* SCH_LEGACY_PLUGIN::Load( const wxString& aFileName, KIWAY* aKiway,
585  SCH_SHEET* aAppendToMe, const PROPERTIES* aProperties )
586 {
587  wxASSERT( !aFileName || aKiway != NULL );
588 
589  LOCALE_IO toggle; // toggles on, then off, the C locale.
590  SCH_SHEET* sheet;
591 
592  wxFileName fn = aFileName;
593 
594  // Unfortunately child sheet file names the legacy schematic file format are not fully
595  // qualified and are always appended to the project path. The aFileName attribute must
596  // always be an absolute path so the project path can be used for load child sheet files.
597  wxASSERT( fn.IsAbsolute() );
598 
599  m_path = fn.GetPath();
600 
601  init( aKiway, aProperties );
602 
603  if( aAppendToMe == NULL )
604  {
605  // Clean up any allocated memory if an exception occurs loading the schematic.
606  std::unique_ptr< SCH_SHEET > newSheet( new SCH_SHEET );
607  newSheet->SetFileName( aFileName );
608  m_rootSheet = newSheet.get();
609  loadHierarchy( newSheet.get() );
610 
611  // If we got here, the schematic loaded successfully.
612  sheet = newSheet.release();
613  }
614  else
615  {
616  m_rootSheet = aAppendToMe->GetRootSheet();
617  wxASSERT( m_rootSheet != NULL );
618  sheet = aAppendToMe;
619  loadHierarchy( sheet );
620  }
621 
622  return sheet;
623 }
624 
625 
626 // Everything below this comment is recursive. Modify with care.
627 
629 {
630  SCH_SCREEN* screen = NULL;
631 
632  if( !aSheet->GetScreen() )
633  {
634  // SCH_SCREEN objects store the full path and file name where the SCH_SHEET object only
635  // stores the file name and extension. Add the project path to the file name and
636  // extension to compare when calling SCH_SHEET::SearchHierarchy().
637  wxFileName fileName = aSheet->GetFileName();
638 
639  if( !fileName.IsAbsolute() )
640  fileName.MakeAbsolute( m_path );
641 
642  m_rootSheet->SearchHierarchy( fileName.GetFullPath(), &screen );
643 
644  if( screen )
645  {
646  aSheet->SetScreen( screen );
647 
648  // Do not need to load the sub-sheets - this has already been done.
649  }
650  else
651  {
652  aSheet->SetScreen( new SCH_SCREEN( m_kiway ) );
653  aSheet->GetScreen()->SetFileName( fileName.GetFullPath() );
654  loadFile( fileName.GetFullPath(), aSheet->GetScreen() );
655 
656  EDA_ITEM* item = aSheet->GetScreen()->GetDrawItems();
657 
658  while( item )
659  {
660  if( item->Type() == SCH_SHEET_T )
661  {
662  SCH_SHEET* sheet = (SCH_SHEET*) item;
663 
664  // Set the parent to aSheet. This effectively creates a method to find
665  // the root sheet from any sheet so a pointer to the root sheet does not
666  // need to be stored globally. Note: this is not the same as a hierarchy.
667  // Complex hierarchies can have multiple copies of a sheet. This only
668  // provides a simple tree to find the root sheet.
669  sheet->SetParent( aSheet );
670 
671  // Recursion starts here.
672  loadHierarchy( sheet );
673  }
674 
675  item = item->Next();
676  }
677  }
678  }
679 }
680 
681 
682 void SCH_LEGACY_PLUGIN::loadFile( const wxString& aFileName, SCH_SCREEN* aScreen )
683 {
684  FILE_LINE_READER reader( aFileName );
685 
686  loadHeader( reader, aScreen );
687 
688  while( reader.ReadLine() )
689  {
690  char* line = reader.Line();
691 
692  while( *line && *line == ' ' )
693  line++;
694 
695  // Either an object will be loaded properly or the file load will fail and raise
696  // an exception.
697  if( strCompare( "$Descr", line ) )
698  loadPageSettings( reader, aScreen );
699  else if( strCompare( "$Comp", line ) )
700  aScreen->Append( loadComponent( reader ) );
701  else if( strCompare( "$Sheet", line ) )
702  aScreen->Append( loadSheet( reader ) );
703  else if( strCompare( "$Bitmap", line ) )
704  aScreen->Append( loadBitmap( reader ) );
705  else if( strCompare( "Connection", line ) )
706  aScreen->Append( loadJunction( reader ) );
707  else if( strCompare( "NoConn", line ) )
708  aScreen->Append( loadNoConnect( reader ) );
709  else if( strCompare( "Wire", line ) )
710  aScreen->Append( loadWire( reader ) );
711  else if( strCompare( "Entry", line ) )
712  aScreen->Append( loadBusEntry( reader ) );
713  else if( strCompare( "Text", line ) )
714  aScreen->Append( loadText( reader ) );
715  else if( strCompare( "$EndSCHEMATC", line ) )
716  return;
717  }
718 
719  // Unfortunately schematic files prior to version 2 are not terminated with $EndSCHEMATC
720  // so checking for it's existance will fail so just exit here and take our chances. :(
721  if( m_version > 1 )
722  THROW_IO_ERROR( "'$EndSCHEMATC' not found" );
723 }
724 
725 
727 {
728  const char* line = aReader.ReadLine();
729 
730  if( !strCompare( "Eeschema Schematic File Version", line, &line ) )
731  {
732  m_error.Printf( _( "'%s' does not appear to be an Eeschema file" ),
733  GetChars( aScreen->GetFileName() ) );
735  }
736 
737  // get the file version here.
738  m_version = parseInt( aReader, line, &line );
739 
740  // The next lines are the lib list section, and are mainly comments, like:
741  // LIBS:power
742  // the lib list is not used, but is in schematic file just in case.
743  // It is usually not empty, but we accept empty list.
744  // If empty, there is a legacy section, not used
745  // EELAYER i j
746  // and the last line is
747  // EELAYER END
748  // Skip all lines until the end of header "EELAYER END" is found
749  while( aReader.ReadLine() )
750  {
751  line = aReader.Line();
752 
753  while( *line == ' ' )
754  line++;
755 
756  if( strCompare( "EELAYER END", line ) )
757  return;
758  }
759 
760  THROW_IO_ERROR( _( "Missing 'EELAYER END'" ) );
761 }
762 
763 
765 {
766  wxASSERT( aScreen != NULL );
767 
768  wxString buf;
769  const char* line = aReader.Line();
770 
771  PAGE_INFO pageInfo;
772  TITLE_BLOCK tb;
773 
774  wxCHECK_RET( strCompare( "$Descr", line, &line ), "Invalid sheet description" );
775 
776  parseUnquotedString( buf, aReader, line, &line );
777 
778  if( !pageInfo.SetType( buf ) )
779  SCH_PARSE_ERROR( "invalid page size", aReader, line );
780 
781  int pagew = parseInt( aReader, line, &line );
782  int pageh = parseInt( aReader, line, &line );
783 
784  if( buf == PAGE_INFO::Custom )
785  {
786  pageInfo.SetWidthMils( pagew );
787  pageInfo.SetHeightMils( pageh );
788  }
789  else
790  {
791  wxString orientation;
792 
793  // Non custom size, set portrait if its present. Can be empty string which defaults
794  // to landscape.
795  parseUnquotedString( orientation, aReader, line, &line, true );
796 
797  if( orientation == "portrait" )
798  pageInfo.SetPortrait( true );
799  }
800 
801  aScreen->SetPageSettings( pageInfo );
802 
803  while( line != NULL )
804  {
805  buf.clear();
806 
807  if( !aReader.ReadLine() )
808  SCH_PARSE_ERROR( _( "unexpected end of file" ), aReader, line );
809 
810  line = aReader.Line();
811 
812  if( strCompare( "Sheet", line, &line ) )
813  {
814  aScreen->m_ScreenNumber = parseInt( aReader, line, &line );
815  aScreen->m_NumberOfScreens = parseInt( aReader, line, &line );
816  }
817  else if( strCompare( "Title", line, &line ) )
818  {
819  parseQuotedString( buf, aReader, line, &line, true );
820  tb.SetTitle( buf );
821  }
822  else if( strCompare( "Date", line, &line ) )
823  {
824  parseQuotedString( buf, aReader, line, &line, true );
825  tb.SetDate( buf );
826  }
827  else if( strCompare( "Rev", line, &line ) )
828  {
829  parseQuotedString( buf, aReader, line, &line, true );
830  tb.SetRevision( buf );
831  }
832  else if( strCompare( "Comp", line, &line ) )
833  {
834  parseQuotedString( buf, aReader, line, &line, true );
835  tb.SetCompany( buf );
836  }
837  else if( strCompare( "Comment1", line, &line ) )
838  {
839  parseQuotedString( buf, aReader, line, &line, true );
840  tb.SetComment1( buf );
841  }
842  else if( strCompare( "Comment2", line, &line ) )
843  {
844  parseQuotedString( buf, aReader, line, &line, true );
845  tb.SetComment2( buf );
846  }
847  else if( strCompare( "Comment3", line, &line ) )
848  {
849  parseQuotedString( buf, aReader, line, &line, true );
850  tb.SetComment3( buf );
851  }
852  else if( strCompare( "Comment4", line, &line ) )
853  {
854  parseQuotedString( buf, aReader, line, &line, true );
855  tb.SetComment4( buf );
856  }
857  else if( strCompare( "$EndDescr", line ) )
858  {
859  aScreen->SetTitleBlock( tb );
860  return;
861  }
862  }
863 
864  SCH_PARSE_ERROR( "missing 'EndDescr'", aReader, line );
865 }
866 
867 
869 {
870  std::unique_ptr< SCH_SHEET > sheet( new SCH_SHEET() );
871 
872  sheet->SetTimeStamp( GetNewTimeStamp() );
873 
874  const char* line = aReader.ReadLine();
875 
876  while( line != NULL )
877  {
878  if( strCompare( "S", line, &line ) ) // Sheet dimensions.
879  {
880  wxPoint position;
881 
882  position.x = parseInt( aReader, line, &line );
883  position.y = parseInt( aReader, line, &line );
884  sheet->SetPosition( position );
885 
886  wxSize size;
887 
888  size.SetWidth( parseInt( aReader, line, &line ) );
889  size.SetHeight( parseInt( aReader, line, &line ) );
890  sheet->SetSize( size );
891  }
892  else if( strCompare( "U", line, &line ) ) // Sheet time stamp.
893  {
894  sheet->SetTimeStamp( parseHex( aReader, line ) );
895  }
896  else if( *line == 'F' ) // Sheet field.
897  {
898  line++;
899 
900  wxString text;
901  int size;
902  int fieldId = parseInt( aReader, line, &line );
903 
904  if( fieldId == 0 || fieldId == 1 ) // Sheet name and file name.
905  {
906  parseQuotedString( text, aReader, line, &line );
907  size = parseInt( aReader, line, &line );
908 
909  if( fieldId == 0 )
910  {
911  sheet->SetName( text );
912  sheet->SetSheetNameSize( size );
913  }
914  else
915  {
916  sheet->SetFileName( text );
917  sheet->SetFileNameSize( size );
918  }
919  }
920  else // Sheet pin.
921  {
922  std::unique_ptr< SCH_SHEET_PIN > sheetPin( new SCH_SHEET_PIN( sheet.get() ) );
923 
924  sheetPin->SetNumber( fieldId );
925 
926  // Can be empty fields.
927  parseQuotedString( text, aReader, line, &line, true );
928 
929  sheetPin->SetText( text );
930 
931  if( line == NULL )
932  THROW_IO_ERROR( _( "unexpected end of line" ) );
933 
934  switch( parseChar( aReader, line, &line ) )
935  {
936  case 'I':
937  sheetPin->SetShape( NET_INPUT );
938  break;
939 
940  case 'O':
941  sheetPin->SetShape( NET_OUTPUT );
942  break;
943 
944  case 'B':
945  sheetPin->SetShape( NET_BIDI );
946  break;
947 
948  case 'T':
949  sheetPin->SetShape( NET_TRISTATE );
950  break;
951 
952  case 'U':
953  sheetPin->SetShape( NET_UNSPECIFIED );
954  break;
955  default:
956  SCH_PARSE_ERROR( "invalid sheet pin type", aReader, line );
957  }
958 
959  switch( parseChar( aReader, line, &line ) )
960  {
961  case 'R': /* pin on right side */
962  sheetPin->SetEdge( SCH_SHEET_PIN::SHEET_RIGHT_SIDE );
963  break;
964 
965  case 'T': /* pin on top side */
966  sheetPin->SetEdge( SCH_SHEET_PIN::SHEET_TOP_SIDE );
967  break;
968 
969  case 'B': /* pin on bottom side */
970  sheetPin->SetEdge( SCH_SHEET_PIN::SHEET_BOTTOM_SIDE );
971  break;
972 
973  case 'L': /* pin on left side */
974  sheetPin->SetEdge( SCH_SHEET_PIN::SHEET_LEFT_SIDE );
975  break;
976  default:
977  SCH_PARSE_ERROR( "invalid sheet pin side", aReader, line );
978  }
979 
980  wxPoint position;
981 
982  position.x = parseInt( aReader, line, &line );
983  position.y = parseInt( aReader, line, &line );
984  sheetPin->SetPosition( position );
985 
986  size = parseInt( aReader, line, &line );
987 
988  sheetPin->SetTextSize( wxSize( size, size ) );
989 
990  sheet->AddPin( sheetPin.release() );
991  }
992  }
993  else if( strCompare( "$EndSheet", line ) )
994  return sheet.release();
995 
996  line = aReader.ReadLine();
997  }
998 
999  SCH_PARSE_ERROR( "missing '$EndSheet`", aReader, line );
1000 
1001  return NULL; // Prevents compiler warning. Should never get here.
1002 }
1003 
1004 
1006 {
1007  std::unique_ptr< SCH_BITMAP > bitmap( new SCH_BITMAP );
1008 
1009  const char* line = aReader.Line();
1010 
1011  wxCHECK( strCompare( "$Bitmap", line, &line ), NULL );
1012 
1013  line = aReader.ReadLine();
1014 
1015  while( line != NULL )
1016  {
1017  if( strCompare( "Pos", line, &line ) )
1018  {
1019  wxPoint position;
1020 
1021  position.x = parseInt( aReader, line, &line );
1022  position.y = parseInt( aReader, line, &line );
1023  bitmap->SetPosition( position );
1024  }
1025  else if( strCompare( "Scale", line, &line ) )
1026  {
1028  bitmap->GetImage()->SetScale( parseDouble( aReader, line, &line ) );
1029  }
1030  else if( strCompare( "Data", line, &line ) )
1031  {
1032  wxMemoryOutputStream stream;
1033 
1034  while( line )
1035  {
1036  if( !aReader.ReadLine() )
1037  SCH_PARSE_ERROR( _( "Unexpected end of file" ), aReader, line );
1038 
1039  line = aReader.Line();
1040 
1041  if( strCompare( "EndData", line ) )
1042  {
1043  // all the PNG date is read.
1044  // We expect here m_image and m_bitmap are void
1045  wxImage* image = new wxImage();
1046  wxMemoryInputStream istream( stream );
1047  image->LoadFile( istream, wxBITMAP_TYPE_PNG );
1048  bitmap->GetImage()->SetImage( image );
1049  bitmap->GetImage()->SetBitmap( new wxBitmap( *image ) );
1050  break;
1051  }
1052 
1053  // Read PNG data, stored in hexadecimal,
1054  // each byte = 2 hexadecimal digits and a space between 2 bytes
1055  // and put it in memory stream buffer
1056  int len = strlen( line );
1057 
1058  for( ; len > 0 && !isspace( *line ); len -= 3, line += 3 )
1059  {
1060  int value = 0;
1061 
1062  if( sscanf( line, "%X", &value ) == 1 )
1063  stream.PutC( (char) value );
1064  else
1065  THROW_IO_ERROR( "invalid PNG data" );
1066  }
1067  }
1068 
1069  if( line == NULL )
1070  THROW_IO_ERROR( _( "unexpected end of file" ) );
1071  }
1072  else if( strCompare( "$EndBitmap", line ) )
1073  return bitmap.release();
1074 
1075  line = aReader.ReadLine();
1076  }
1077 
1078  THROW_IO_ERROR( _( "unexpected end of file" ) );
1079 }
1080 
1081 
1083 {
1084  std::unique_ptr< SCH_JUNCTION > junction( new SCH_JUNCTION );
1085 
1086  const char* line = aReader.Line();
1087 
1088  wxCHECK( strCompare( "Connection", line, &line ), NULL );
1089 
1090  wxString name;
1091 
1092  parseUnquotedString( name, aReader, line, &line );
1093 
1094  wxPoint position;
1095 
1096  position.x = parseInt( aReader, line, &line );
1097  position.y = parseInt( aReader, line, &line );
1098  junction->SetPosition( position );
1099 
1100  return junction.release();
1101 }
1102 
1103 
1105 {
1106  std::unique_ptr< SCH_NO_CONNECT > no_connect( new SCH_NO_CONNECT );
1107 
1108  const char* line = aReader.Line();
1109 
1110  wxCHECK( strCompare( "NoConn", line, &line ), NULL );
1111 
1112  wxString name;
1113 
1114  parseUnquotedString( name, aReader, line, &line );
1115 
1116  wxPoint position;
1117 
1118  position.x = parseInt( aReader, line, &line );
1119  position.y = parseInt( aReader, line, &line );
1120  no_connect->SetPosition( position );
1121 
1122  return no_connect.release();
1123 }
1124 
1125 
1127 {
1128  std::unique_ptr< SCH_LINE > wire( new SCH_LINE );
1129 
1130  const char* line = aReader.Line();
1131 
1132  wxCHECK( strCompare( "Wire", line, &line ), NULL );
1133 
1134  if( strCompare( "Wire", line, &line ) )
1135  wire->SetLayer( LAYER_WIRE );
1136  else if( strCompare( "Bus", line, &line ) )
1137  wire->SetLayer( LAYER_BUS );
1138  else if( strCompare( "Notes", line, &line ) )
1139  wire->SetLayer( LAYER_NOTES );
1140  else
1141  SCH_PARSE_ERROR( "invalid line type", aReader, line );
1142 
1143  if( !strCompare( "Line", line, &line ) )
1144  SCH_PARSE_ERROR( "invalid wire definition", aReader, line );
1145 
1146  // Since Sept 15, 2017, a line style is alloved (width, style, color)
1147  // Only non default values are stored
1148  while( !is_eol( *line ) )
1149  {
1150  wxString buf;
1151 
1152  parseUnquotedString( buf, aReader, line, &line );
1153 
1154  if( buf == ")" )
1155  continue;
1156 
1157  else if( buf == T_WIDTH )
1158  {
1159  int size = parseInt( aReader, line, &line );
1160  wire->SetLineWidth( size );
1161  }
1162  else if( buf == T_STYLE )
1163  {
1164  parseUnquotedString( buf, aReader, line, &line );
1165  int style = SCH_LINE::GetLineStyleInternalId( buf );
1166  wire->SetLineStyle( style );
1167  }
1168  else // should be the color parameter.
1169  {
1170  // The color param is something like rgb(150, 40, 191)
1171  // and because there is no space between ( and 150
1172  // the first param is inside buf.
1173  // So break keyword and the first param into 2 separate strings.
1174  wxString prm, keyword;
1175  keyword = buf.BeforeLast( '(', &prm );
1176 
1177  if( ( keyword == T_COLOR ) || ( keyword == T_COLORA ) )
1178  {
1179  long color[4] = { 0 };
1180 
1181  int ii = 0;
1182 
1183  if( !prm.IsEmpty() )
1184  {
1185  prm.ToLong( &color[ii] );
1186  ii++;
1187  }
1188 
1189  int prm_count = ( keyword == T_COLORA ) ? 4 : 3;
1190  // fix opacity to 1.0 or 255, when not exists in file
1191  color[3] = 255;
1192 
1193  for(; ii < prm_count && !is_eol( *line ); ii++ )
1194  color[ii] = parseInt( aReader, line, &line );
1195 
1196  wire->SetLineColor( color[0]/255.0, color[1]/255.0, color[2]/255.0,color[3]/255.0 );
1197  }
1198  }
1199  }
1200 
1201  // Read the segment en points coordinates:
1202  line = aReader.ReadLine();
1203 
1204  wxPoint begin, end;
1205 
1206  begin.x = parseInt( aReader, line, &line );
1207  begin.y = parseInt( aReader, line, &line );
1208  end.x = parseInt( aReader, line, &line );
1209  end.y = parseInt( aReader, line, &line );
1210 
1211  wire->SetStartPoint( begin );
1212  wire->SetEndPoint( end );
1213 
1214  return wire.release();
1215 }
1216 
1217 
1219 {
1220  const char* line = aReader.Line();
1221 
1222  wxCHECK( strCompare( "Entry", line, &line ), NULL );
1223 
1224  std::unique_ptr< SCH_BUS_ENTRY_BASE > busEntry;
1225 
1226  if( strCompare( "Wire", line, &line ) )
1227  {
1228  busEntry.reset( new SCH_BUS_WIRE_ENTRY );
1229 
1230  if( !strCompare( "Line", line, &line ) )
1231  SCH_PARSE_ERROR( "invalid bus entry definition expected 'Line'", aReader, line );
1232  }
1233  else if( strCompare( "Bus", line, &line ) )
1234  {
1235  busEntry.reset( new SCH_BUS_BUS_ENTRY );
1236 
1237  if( !strCompare( "Bus", line, &line ) )
1238  SCH_PARSE_ERROR( "invalid bus entry definition expected 'Bus'", aReader, line );
1239  }
1240  else
1241  SCH_PARSE_ERROR( "invalid bus entry type", aReader, line );
1242 
1243  line = aReader.ReadLine();
1244 
1245  wxPoint pos;
1246  wxSize size;
1247 
1248  pos.x = parseInt( aReader, line, &line );
1249  pos.y = parseInt( aReader, line, &line );
1250  size.x = parseInt( aReader, line, &line );
1251  size.y = parseInt( aReader, line, &line );
1252 
1253  size.x -= pos.x;
1254  size.y -= pos.y;
1255 
1256  busEntry->SetPosition( pos );
1257  busEntry->SetSize( size );
1258 
1259  return busEntry.release();
1260 }
1261 
1262 
1264 {
1265  const char* line = aReader.Line();
1266 
1267  wxCHECK( strCompare( "Text", line, &line ), NULL );
1268 
1269  std::unique_ptr< SCH_TEXT> text;
1270 
1271  if( strCompare( "Notes", line, &line ) )
1272  text.reset( new SCH_TEXT );
1273  else if( strCompare( "Label", line, &line ) )
1274  text.reset( new SCH_LABEL );
1275  else if( strCompare( "HLabel", line, &line ) )
1276  text.reset( new SCH_HIERLABEL );
1277  else if( strCompare( "GLabel", line, &line ) )
1278  {
1279  // Prior to version 2, the SCH_GLOBALLABEL object did not exist.
1280  if( m_version == 1 )
1281  text.reset( new SCH_HIERLABEL );
1282  else
1283  text.reset( new SCH_GLOBALLABEL );
1284  }
1285  else
1286  SCH_PARSE_ERROR( "unknown Text type", aReader, line );
1287 
1288  // Parse the parameters common to all text objects.
1289  wxPoint position;
1290 
1291  position.x = parseInt( aReader, line, &line );
1292  position.y = parseInt( aReader, line, &line );
1293  text->SetPosition( position );
1294  text->SetLabelSpinStyle( parseInt( aReader, line, &line ) );
1295 
1296  int size = parseInt( aReader, line, &line );
1297 
1298  text->SetTextSize( wxSize( size, size ) );
1299 
1300  // Parse the global and hierarchical label type.
1301  if( text->Type() == SCH_HIERARCHICAL_LABEL_T || text->Type() == SCH_GLOBAL_LABEL_T )
1302  {
1303  if( strCompare( SheetLabelType[NET_INPUT], line, &line ) )
1304  text->SetShape( NET_INPUT );
1305  else if( strCompare( SheetLabelType[NET_OUTPUT], line, &line ) )
1306  text->SetShape( NET_OUTPUT );
1307  else if( strCompare( SheetLabelType[NET_BIDI], line, &line ) )
1308  text->SetShape( NET_BIDI );
1309  else if( strCompare( SheetLabelType[NET_TRISTATE], line, &line ) )
1310  text->SetShape( NET_TRISTATE );
1311  else if( strCompare( SheetLabelType[NET_UNSPECIFIED], line, &line ) )
1312  text->SetShape( NET_UNSPECIFIED );
1313  else
1314  SCH_PARSE_ERROR( "invalid label type", aReader, line );
1315  }
1316 
1317  int thickness = 0;
1318 
1319  // The following tokens do not exist in version 1 schematic files.
1320  if( m_version > 1 )
1321  {
1322  if( strCompare( "Italic", line, &line ) )
1323  text->SetItalic( true );
1324  else if( !strCompare( "~", line, &line ) )
1325  SCH_PARSE_ERROR( _( "expected 'Italics' or '~'" ), aReader, line );
1326 
1327  // The thickness token does not exist in older versions of the schematic file format
1328  // so calling parseInt will be made only if the EOL is not reached.
1329  if( *line >= ' ' )
1330  thickness = parseInt( aReader, line, &line );
1331  }
1332 
1333  text->SetBold( thickness != 0 );
1334  text->SetThickness( thickness != 0 ? GetPenSizeForBold( size ) : 0 );
1335 
1336  // Read the text string for the text.
1337  char* tmp = aReader.ReadLine();
1338 
1339  tmp = strtok( tmp, "\r\n" );
1340  wxString val = FROM_UTF8( tmp );
1341 
1342  for( ; ; )
1343  {
1344  int i = val.find( wxT( "\\n" ) );
1345 
1346  if( i == wxNOT_FOUND )
1347  break;
1348 
1349  val.erase( i, 2 );
1350  val.insert( i, wxT( "\n" ) );
1351  }
1352 
1353  text->SetText( val );
1354 
1355  return text.release();
1356 }
1357 
1358 
1360 {
1361  const char* line = aReader.Line();
1362 
1363  wxCHECK( strCompare( "$Comp", line, &line ), NULL );
1364 
1365  std::unique_ptr< SCH_COMPONENT > component( new SCH_COMPONENT() );
1366 
1367  line = aReader.ReadLine();
1368 
1369  while( line != NULL )
1370  {
1371  if( strCompare( "L", line, &line ) )
1372  {
1373  wxString libName;
1374 
1375  parseUnquotedString( libName, aReader, line, &line );
1376  libName.Replace( "~", " " );
1377 
1378  LIB_ID libId;
1379 
1380  // Prior to schematic version 4, library IDs did not have a library nickname so
1381  // parsing the symbol name with LIB_ID::Parse() would break symbol library links
1382  // that contained '/' and ':' characters.
1383  if( m_version > 3 )
1384  libId.Parse( libName );
1385  else
1386  libId.SetLibItemName( libName, false );
1387 
1388  component->SetLibId( libId );
1389 
1390  wxString refDesignator;
1391 
1392  parseUnquotedString( refDesignator, aReader, line, &line );
1393  refDesignator.Replace( "~", " " );
1394 
1395  wxString prefix = refDesignator;
1396 
1397  while( prefix.Length() )
1398  {
1399  if( ( prefix.Last() < '0' || prefix.Last() > '9') && prefix.Last() != '?' )
1400  break;
1401 
1402  prefix.RemoveLast();
1403  }
1404 
1405  // Avoid a prefix containing trailing/leading spaces
1406  prefix.Trim( true );
1407  prefix.Trim( false );
1408 
1409  if( prefix.IsEmpty() )
1410  component->SetPrefix( wxString( "U" ) );
1411  else
1412  component->SetPrefix( prefix );
1413  }
1414  else if( strCompare( "U", line, &line ) )
1415  {
1416  // This fixes a potentially buggy files caused by unit being set to zero which
1417  // causes netlist issues. See https://bugs.launchpad.net/kicad/+bug/1677282.
1418  int unit = parseInt( aReader, line, &line );
1419 
1420  if( unit == 0 )
1421  {
1422  unit = 1;
1423 
1424  // Set the file as modified so the user can be warned.
1425  if( m_rootSheet && m_rootSheet->GetScreen() )
1427  }
1428 
1429  component->SetUnit( unit );
1430  component->SetConvert( parseInt( aReader, line, &line ) );
1431  component->SetTimeStamp( parseHex( aReader, line, &line ) );
1432  }
1433  else if( strCompare( "P", line, &line ) )
1434  {
1435  wxPoint pos;
1436 
1437  pos.x = parseInt( aReader, line, &line );
1438  pos.y = parseInt( aReader, line, &line );
1439  component->SetPosition( pos );
1440  }
1441  else if( strCompare( "AR", line, &line ) )
1442  {
1443  const char* strCompare = "Path=";
1444  int len = strlen( strCompare );
1445 
1446  if( strncasecmp( strCompare, line, len ) != 0 )
1447  SCH_PARSE_ERROR( "missing 'Path=' token", aReader, line );
1448 
1449  line += len;
1450  wxString path, reference, unit;
1451 
1452  parseQuotedString( path, aReader, line, &line );
1453 
1454  strCompare = "Ref=";
1455  len = strlen( strCompare );
1456 
1457  if( strncasecmp( strCompare, line, len ) != 0 )
1458  SCH_PARSE_ERROR( "missing 'Ref=' token", aReader, line );
1459 
1460  line+= len;
1461  parseQuotedString( reference, aReader, line, &line );
1462 
1463  strCompare = "Part=";
1464  len = strlen( strCompare );
1465 
1466  if( strncasecmp( strCompare, line, len ) != 0 )
1467  SCH_PARSE_ERROR( "missing 'Part=' token", aReader, line );
1468 
1469  line+= len;
1470  parseQuotedString( unit, aReader, line, &line );
1471 
1472  long tmp;
1473 
1474  if( !unit.ToLong( &tmp, 10 ) )
1475  SCH_PARSE_ERROR( "expected integer value", aReader, line );
1476 
1477  if( tmp < 0 || tmp > MAX_UNIT_COUNT_PER_PACKAGE )
1478  SCH_PARSE_ERROR( "unit value out of range", aReader, line );
1479 
1480  component->AddHierarchicalReference( path, reference, (int)tmp );
1481  component->GetField( REFERENCE )->SetText( reference );
1482 
1483  }
1484  else if( strCompare( "F", line, &line ) )
1485  {
1486  int index = parseInt( aReader, line, &line );
1487 
1488  wxString text, name;
1489 
1490  parseQuotedString( text, aReader, line, &line, true );
1491 
1492  char orientation = parseChar( aReader, line, &line );
1493  wxPoint pos;
1494  pos.x = parseInt( aReader, line, &line );
1495  pos.y = parseInt( aReader, line, &line );
1496  int size = parseInt( aReader, line, &line );
1497  int attributes = parseHex( aReader, line, &line );
1498 
1499  if( index >= component->GetFieldCount() )
1500  {
1501  // The first MANDATOR_FIELDS _must_ be constructed within
1502  // the SCH_COMPONENT constructor. This assert is simply here
1503  // to guard against a change in that constructor.
1504  wxASSERT( component->GetFieldCount() >= MANDATORY_FIELDS );
1505 
1506  // Ignore the _supplied_ fieldNdx. It is not important anymore
1507  // if within the user defined fields region (i.e. >= MANDATORY_FIELDS).
1508  // We freely renumber the index to fit the next available field slot.
1509  index = component->GetFieldCount(); // new has this index after insertion
1510 
1511  SCH_FIELD field( wxPoint( 0, 0 ), -1, component.get(), name );
1512  component->AddField( field );
1513  }
1514 
1515  // Prior to version 2 of the schematic file format, none of the following existed.
1516  if( m_version > 1 )
1517  {
1518  wxString textAttrs;
1519  char hjustify = parseChar( aReader, line, &line );
1520 
1521  parseUnquotedString( textAttrs, aReader, line, &line );
1522 
1523  // The name of the field is optional.
1524  parseQuotedString( name, aReader, line, &line, true );
1525 
1526  if( hjustify == 'L' )
1527  component->GetField( index )->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
1528  else if( hjustify == 'R' )
1529  component->GetField( index )->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
1530  else if( hjustify != 'C' )
1531  SCH_PARSE_ERROR( "component field text horizontal justification must be "
1532  "L, R, or C", aReader, line );
1533 
1534  // We are guaranteed to have a least one character here for older file formats
1535  // otherwise an exception would have been raised..
1536  if( textAttrs[0] == 'T' )
1537  component->GetField( index )->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
1538  else if( textAttrs[0] == 'B' )
1539  component->GetField( index )->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
1540  else if( textAttrs[0] != 'C' )
1541  SCH_PARSE_ERROR( "component field text vertical justification must be "
1542  "B, T, or C", aReader, line );
1543 
1544  // Newer file formats include the bold and italics text attribute.
1545  if( textAttrs.Length() > 1 )
1546  {
1547  if( textAttrs.Length() != 3 )
1548  SCH_PARSE_ERROR( _( "component field text attributes must be 3 characters wide" ),
1549  aReader, line );
1550 
1551  if( textAttrs[1] == 'I' )
1552  component->GetField( index )->SetItalic( true );
1553  else if( textAttrs[1] != 'N' )
1554  SCH_PARSE_ERROR( "component field text italics indicator must be I or N",
1555  aReader, line );
1556 
1557  if( textAttrs[2] == 'B' )
1558  component->GetField( index )->SetBold( true );
1559  else if( textAttrs[2] != 'N' )
1560  SCH_PARSE_ERROR( "component field text bold indicator must be B or N",
1561  aReader, line );
1562  }
1563  }
1564 
1565  component->GetField( index )->SetText( text );
1566  component->GetField( index )->SetTextPos( pos );
1567  component->GetField( index )->SetVisible( !attributes );
1568  component->GetField( index )->SetTextSize( wxSize( size, size ) );
1569 
1570  if( orientation == 'H' )
1571  component->GetField( index )->SetTextAngle( TEXT_ANGLE_HORIZ );
1572  else if( orientation == 'V' )
1573  component->GetField( index )->SetTextAngle( TEXT_ANGLE_VERT );
1574  else
1575  SCH_PARSE_ERROR( "component field orientation must be H or V",
1576  aReader, line );
1577 
1578  if( name.IsEmpty() )
1580 
1581  component->GetField( index )->SetName( name );
1582  }
1583  else if( strCompare( "$EndComp", line ) )
1584  {
1585  // Ensure all flags (some are set by previous initializations) are reset:
1586  component->ClearFlags();
1587  return component.release();
1588  }
1589  else
1590  {
1591  // There are two lines that begin with a tab or spaces that includes a line with the
1592  // redundant position information and the transform matrix settings.
1593 
1594  // Parse the redundant position information just the same to check for formatting
1595  // errors.
1596  parseInt( aReader, line, &line ); // Always 1.
1597  parseInt( aReader, line, &line ); // The X coordinate.
1598  parseInt( aReader, line, &line ); // The Y coordinate.
1599 
1600  line = aReader.ReadLine();
1601 
1602  TRANSFORM transform;
1603 
1604  transform.x1 = parseInt( aReader, line, &line );
1605 
1606  if( transform.x1 < -1 || transform.x1 > 1 )
1607  SCH_PARSE_ERROR( "invalid component X1 transform value", aReader, line );
1608 
1609  transform.y1 = parseInt( aReader, line, &line );
1610 
1611  if( transform.y1 < -1 || transform.y1 > 1 )
1612  SCH_PARSE_ERROR( "invalid component Y1 transform value", aReader, line );
1613 
1614  transform.x2 = parseInt( aReader, line, &line );
1615 
1616  if( transform.x2 < -1 || transform.x2 > 1 )
1617  SCH_PARSE_ERROR( "invalid component X2 transform value", aReader, line );
1618 
1619  transform.y2 = parseInt( aReader, line, &line );
1620 
1621  if( transform.y2 < -1 || transform.y2 > 1 )
1622  SCH_PARSE_ERROR( "invalid component Y2 transform value", aReader, line );
1623 
1624  component->SetTransform( transform );
1625  }
1626 
1627  line = aReader.ReadLine();
1628  }
1629 
1630  SCH_PARSE_ERROR( "invalid component line", aReader, line );
1631 
1632  return NULL; // Prevents compiler warning. Should never get here.
1633 }
1634 
1635 
1636 void SCH_LEGACY_PLUGIN::Save( const wxString& aFileName, SCH_SCREEN* aScreen, KIWAY* aKiway,
1637  const PROPERTIES* aProperties )
1638 {
1639  wxCHECK_RET( aScreen != NULL, "NULL SCH_SCREEN object." );
1640  wxCHECK_RET( !aFileName.IsEmpty(), "No schematic file name defined." );
1641 
1642  init( aKiway, aProperties );
1643 
1644  wxFileName fn = aFileName;
1645 
1646  // File names should be absolute. Don't assume everything relative to the project path
1647  // works properly.
1648  wxASSERT( fn.IsAbsolute() );
1649 
1650  FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
1651 
1652  m_out = &formatter; // no ownership
1653 
1654  Format( aScreen );
1655 }
1656 
1657 
1659 {
1660  wxCHECK_RET( aScreen != NULL, "NULL SCH_SCREEN* object." );
1661  wxCHECK_RET( m_kiway != NULL, "NULL KIWAY* object." );
1662 
1663  // Write the header
1664  m_out->Print( 0, "%s %s %d\n", "EESchema", SCHEMATIC_HEAD_STRING, EESCHEMA_VERSION );
1665 
1666  // Write the project libraries.
1667  for( const PART_LIB& lib : *m_kiway->Prj().SchLibs() )
1668  m_out->Print( 0, "LIBS:%s\n", TO_UTF8( lib.GetName() ) );
1669 
1670  // This section is not used, but written for file compatibility
1671  m_out->Print( 0, "EELAYER %d %d\n", SCH_LAYER_ID_COUNT, 0 );
1672  m_out->Print( 0, "EELAYER END\n" );
1673 
1674  /* Write page info, ScreenNumber and NumberOfScreen; not very meaningful for
1675  * SheetNumber and Sheet Count in a complex hierarchy, but useful in
1676  * simple hierarchy and flat hierarchy. Used also to search the root
1677  * sheet ( ScreenNumber = 1 ) within the files
1678  */
1679  const TITLE_BLOCK& tb = aScreen->GetTitleBlock();
1680  const PAGE_INFO& page = aScreen->GetPageSettings();
1681 
1682  m_out->Print( 0, "$Descr %s %d %d%s\n", TO_UTF8( page.GetType() ),
1683  page.GetWidthMils(),
1684  page.GetHeightMils(),
1685  !page.IsCustom() && page.IsPortrait() ? " portrait" : "" );
1686  m_out->Print( 0, "encoding utf-8\n" );
1687  m_out->Print( 0, "Sheet %d %d\n", aScreen->m_ScreenNumber, aScreen->m_NumberOfScreens );
1688  m_out->Print( 0, "Title %s\n", EscapedUTF8( tb.GetTitle() ).c_str() );
1689  m_out->Print( 0, "Date %s\n", EscapedUTF8( tb.GetDate() ).c_str() );
1690  m_out->Print( 0, "Rev %s\n", EscapedUTF8( tb.GetRevision() ).c_str() );
1691  m_out->Print( 0, "Comp %s\n", EscapedUTF8( tb.GetCompany() ).c_str() );
1692  m_out->Print( 0, "Comment1 %s\n", EscapedUTF8( tb.GetComment1() ).c_str() );
1693  m_out->Print( 0, "Comment2 %s\n", EscapedUTF8( tb.GetComment2() ).c_str() );
1694  m_out->Print( 0, "Comment3 %s\n", EscapedUTF8( tb.GetComment3() ).c_str() );
1695  m_out->Print( 0, "Comment4 %s\n", EscapedUTF8( tb.GetComment4() ).c_str() );
1696  m_out->Print( 0, "$EndDescr\n" );
1697 
1698  for( SCH_ITEM* item = aScreen->GetDrawItems(); item; item = item->Next() )
1699  {
1700  switch( item->Type() )
1701  {
1702  case SCH_COMPONENT_T:
1703  saveComponent( dynamic_cast< SCH_COMPONENT* >( item ) );
1704  break;
1705  case SCH_BITMAP_T:
1706  saveBitmap( dynamic_cast< SCH_BITMAP* >( item ) );
1707  break;
1708  case SCH_SHEET_T:
1709  saveSheet( dynamic_cast< SCH_SHEET* >( item ) );
1710  break;
1711  case SCH_JUNCTION_T:
1712  saveJunction( dynamic_cast< SCH_JUNCTION* >( item ) );
1713  break;
1714  case SCH_NO_CONNECT_T:
1715  saveNoConnect( dynamic_cast< SCH_NO_CONNECT* >( item ) );
1716  break;
1717  case SCH_BUS_WIRE_ENTRY_T:
1718  case SCH_BUS_BUS_ENTRY_T:
1719  saveBusEntry( dynamic_cast< SCH_BUS_ENTRY_BASE* >( item ) );
1720  break;
1721  case SCH_LINE_T:
1722  saveLine( dynamic_cast< SCH_LINE* >( item ) );
1723  break;
1724  case SCH_TEXT_T:
1725  case SCH_LABEL_T:
1726  case SCH_GLOBAL_LABEL_T:
1728  saveText( dynamic_cast< SCH_TEXT* >( item ) );
1729  break;
1730  default:
1731  wxASSERT( "Unexpected schematic object type in SCH_LEGACY_PLUGIN::Format()" );
1732  }
1733  }
1734 
1735  m_out->Print( 0, "$EndSCHEMATC\n" );
1736 }
1737 
1738 
1740 {
1741  std::string name1;
1742  std::string name2;
1743  wxArrayString reference_fields;
1744 
1745  static wxString delimiters( wxT( " " ) );
1746 
1747  // This is redundant with the AR entries below, but it makes the files backwards-compatible.
1748  if( aComponent->GetPathsAndReferences().GetCount() > 0 )
1749  {
1750  reference_fields = wxStringTokenize( aComponent->GetPathsAndReferences()[0], delimiters );
1751  name1 = toUTFTildaText( reference_fields[1] );
1752  }
1753  else
1754  {
1755  if( aComponent->GetField( REFERENCE )->GetText().IsEmpty() )
1756  name1 = toUTFTildaText( aComponent->GetPrefix() );
1757  else
1758  name1 = toUTFTildaText( aComponent->GetField( REFERENCE )->GetText() );
1759  }
1760 
1761  wxString part_name = aComponent->GetLibId().Format();
1762 
1763  if( part_name.size() )
1764  {
1765  name2 = toUTFTildaText( part_name );
1766  }
1767  else
1768  {
1769  name2 = "_NONAME_";
1770  }
1771 
1772  m_out->Print( 0, "$Comp\n" );
1773  m_out->Print( 0, "L %s %s\n", name2.c_str(), name1.c_str() );
1774 
1775  // Generate unit number, convert and time stamp
1776  m_out->Print( 0, "U %d %d %8.8lX\n", aComponent->GetUnit(), aComponent->GetConvert(),
1777  (unsigned long)aComponent->GetTimeStamp() );
1778 
1779  // Save the position
1780  m_out->Print( 0, "P %d %d\n", aComponent->GetPosition().x, aComponent->GetPosition().y );
1781 
1782  /* If this is a complex hierarchy; save hierarchical references.
1783  * but for simple hierarchies it is not necessary.
1784  * the reference inf is already saved
1785  * this is useful for old Eeschema version compatibility
1786  */
1787  if( aComponent->GetPathsAndReferences().GetCount() > 1 )
1788  {
1789  for( unsigned int ii = 0; ii < aComponent->GetPathsAndReferences().GetCount(); ii++ )
1790  {
1791  /*format:
1792  * AR Path="/140/2" Ref="C99" Part="1"
1793  * where 140 is the uid of the containing sheet
1794  * and 2 is the timestamp of this component.
1795  * (timestamps are actually 8 hex chars)
1796  * Ref is the conventional component reference for this 'path'
1797  * Part is the conventional component part selection for this 'path'
1798  */
1799  reference_fields = wxStringTokenize( aComponent->GetPathsAndReferences()[ii],
1800  delimiters );
1801 
1802  m_out->Print( 0, "AR Path=\"%s\" Ref=\"%s\" Part=\"%s\" \n",
1803  TO_UTF8( reference_fields[0] ),
1804  TO_UTF8( reference_fields[1] ),
1805  TO_UTF8( reference_fields[2] ) );
1806  }
1807  }
1808 
1809  // update the ugly field index, which I would like to see go away someday soon.
1810  for( int i = 0; i < aComponent->GetFieldCount(); ++i )
1811  aComponent->GetField( i )->SetId( i );
1812 
1813  // Fixed fields:
1814  // Save mandatory fields even if they are blank,
1815  // because the visibility, size and orientation are set from libary editor.
1816  for( unsigned i = 0; i < MANDATORY_FIELDS; ++i )
1817  saveField( aComponent->GetField( i ) );
1818 
1819  // User defined fields:
1820  // The *policy* about which user defined fields are part of a symbol is now
1821  // only in the dialog editors. No policy should be enforced here, simply
1822  // save all the user defined fields, they are present because a dialog editor
1823  // thought they should be. If you disagree, go fix the dialog editors.
1824  for( int i = MANDATORY_FIELDS; i < aComponent->GetFieldCount(); ++i )
1825  saveField( aComponent->GetField( i ) );
1826 
1827  // Unit number, position, box ( old standard )
1828  m_out->Print( 0, "\t%-4d %-4d %-4d\n", aComponent->GetUnit(), aComponent->GetPosition().x,
1829  aComponent->GetPosition().y );
1830 
1831  TRANSFORM transform = aComponent->GetTransform();
1832 
1833  m_out->Print( 0, "\t%-4d %-4d %-4d %-4d\n",
1834  transform.x1, transform.y1, transform.x2, transform.y2 );
1835  m_out->Print( 0, "$EndComp\n" );
1836 }
1837 
1838 
1840 {
1841  char hjustify = 'C';
1842 
1843  if( aField->GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
1844  hjustify = 'L';
1845  else if( aField->GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT )
1846  hjustify = 'R';
1847 
1848  char vjustify = 'C';
1849 
1850  if( aField->GetVertJustify() == GR_TEXT_VJUSTIFY_BOTTOM )
1851  vjustify = 'B';
1852  else if( aField->GetVertJustify() == GR_TEXT_VJUSTIFY_TOP )
1853  vjustify = 'T';
1854 
1855  m_out->Print( 0, "F %d %s %c %-3d %-3d %-3d %4.4X %c %c%c%c",
1856  aField->GetId(),
1857  EscapedUTF8( aField->GetText() ).c_str(), // wraps in quotes too
1858  aField->GetTextAngle() == TEXT_ANGLE_HORIZ ? 'H' : 'V',
1859  aField->GetLibPosition().x, aField->GetLibPosition().y,
1860  aField->GetTextWidth(),
1861  !aField->IsVisible(),
1862  hjustify, vjustify,
1863  aField->IsItalic() ? 'I' : 'N',
1864  aField->IsBold() ? 'B' : 'N' );
1865 
1866  // Save field name, if the name is user definable
1867  if( aField->GetId() >= FIELD1 )
1868  {
1869  m_out->Print( 0, " %s", EscapedUTF8( aField->GetName() ).c_str() );
1870  }
1871 
1872  m_out->Print( 0, "\n" );
1873 }
1874 
1875 
1877 {
1878  wxCHECK_RET( aBitmap != NULL, "SCH_BITMAP* is NULL" );
1879 
1880  wxImage* image = aBitmap->GetImage()->GetImageData();
1881 
1882  wxCHECK_RET( image != NULL, "wxImage* is NULL" );
1883 
1884  m_out->Print( 0, "$Bitmap\n" );
1885  m_out->Print( 0, "Pos %-4d %-4d\n", aBitmap->GetPosition().x, aBitmap->GetPosition().y );
1886  m_out->Print( 0, "Scale %f\n", aBitmap->GetImage()->GetScale() );
1887  m_out->Print( 0, "Data\n" );
1888 
1889  wxMemoryOutputStream stream;
1890 
1891  image->SaveFile( stream, wxBITMAP_TYPE_PNG );
1892 
1893  // Write binary data in hexadecimal form (ASCII)
1894  wxStreamBuffer* buffer = stream.GetOutputStreamBuffer();
1895  char* begin = (char*) buffer->GetBufferStart();
1896 
1897  for( int ii = 0; begin < buffer->GetBufferEnd(); begin++, ii++ )
1898  {
1899  if( ii >= 32 )
1900  {
1901  ii = 0;
1902 
1903  m_out->Print( 0, "\n" );
1904  }
1905 
1906  m_out->Print( 0, "%2.2X ", *begin & 0xFF );
1907  }
1908 
1909  m_out->Print( 0, "\nEndData\n" );
1910  m_out->Print( 0, "$EndBitmap\n" );
1911 }
1912 
1913 
1915 {
1916  wxCHECK_RET( aSheet != NULL, "SCH_SHEET* is NULL" );
1917 
1918  m_out->Print( 0, "$Sheet\n" );
1919  m_out->Print( 0, "S %-4d %-4d %-4d %-4d\n",
1920  aSheet->GetPosition().x, aSheet->GetPosition().y,
1921  aSheet->GetSize().x, aSheet->GetSize().y );
1922 
1923  m_out->Print( 0, "U %8.8lX\n", (unsigned long) aSheet->GetTimeStamp() );
1924 
1925  if( !aSheet->GetName().IsEmpty() )
1926  m_out->Print( 0, "F0 %s %d\n", EscapedUTF8( aSheet->GetName() ).c_str(),
1927  aSheet->GetSheetNameSize() );
1928 
1929  if( !aSheet->GetFileName().IsEmpty() )
1930  m_out->Print( 0, "F1 %s %d\n", EscapedUTF8( aSheet->GetFileName() ).c_str(),
1931  aSheet->GetFileNameSize() );
1932 
1933  for( const SCH_SHEET_PIN& pin : aSheet->GetPins() )
1934  {
1935  int type, side;
1936 
1937  if( pin.GetText().IsEmpty() )
1938  break;
1939 
1940  switch( pin.GetEdge() )
1941  {
1942  default:
1944  side = 'L';
1945  break;
1946 
1948  side = 'R';
1949  break;
1950 
1952  side = 'T';
1953  break;
1954 
1956  side = 'B';
1957  break;
1958  }
1959 
1960  switch( pin.GetShape() )
1961  {
1962  case NET_INPUT:
1963  type = 'I'; break;
1964 
1965  case NET_OUTPUT:
1966  type = 'O'; break;
1967 
1968  case NET_BIDI:
1969  type = 'B'; break;
1970 
1971  case NET_TRISTATE:
1972  type = 'T'; break;
1973 
1974  default:
1975  case NET_UNSPECIFIED:
1976  type = 'U'; break;
1977  }
1978 
1979  m_out->Print( 0, "F%d %s %c %c %-3d %-3d %-3d\n", pin.GetNumber(),
1980  EscapedUTF8( pin.GetText() ).c_str(), // supplies wrapping quotes
1981  type, side, pin.GetPosition().x, pin.GetPosition().y,
1982  pin.GetTextWidth() );
1983  }
1984 
1985  m_out->Print( 0, "$EndSheet\n" );
1986 }
1987 
1988 
1990 {
1991  wxCHECK_RET( aJunction != NULL, "SCH_JUNCTION* is NULL" );
1992 
1993  m_out->Print( 0, "Connection ~ %-4d %-4d\n",
1994  aJunction->GetPosition().x, aJunction->GetPosition().y );
1995 }
1996 
1997 
1999 {
2000  wxCHECK_RET( aNoConnect != NULL, "SCH_NOCONNECT* is NULL" );
2001 
2002  m_out->Print( 0, "NoConn ~ %-4d %-4d\n", aNoConnect->GetPosition().x,
2003  aNoConnect->GetPosition().y );
2004 }
2005 
2006 
2008 {
2009  wxCHECK_RET( aBusEntry != NULL, "SCH_BUS_ENTRY_BASE* is NULL" );
2010 
2011  if( aBusEntry->GetLayer() == LAYER_WIRE )
2012  m_out->Print( 0, "Entry Wire Line\n\t%-4d %-4d %-4d %-4d\n",
2013  aBusEntry->GetPosition().x, aBusEntry->GetPosition().y,
2014  aBusEntry->m_End().x, aBusEntry->m_End().y );
2015  else
2016  m_out->Print( 0, "Entry Bus Bus\n\t%-4d %-4d %-4d %-4d\n",
2017  aBusEntry->GetPosition().x, aBusEntry->GetPosition().y,
2018  aBusEntry->m_End().x, aBusEntry->m_End().y );
2019 }
2020 
2021 
2023 {
2024  wxCHECK_RET( aLine != NULL, "SCH_LINE* is NULL" );
2025 
2026  const char* layer = "Notes";
2027  const char* width = "Line";
2028 
2029  if( aLine->GetLayer() == LAYER_WIRE )
2030  layer = "Wire";
2031  else if( aLine->GetLayer() == LAYER_BUS )
2032  layer = "Bus";
2033 
2034  m_out->Print( 0, "Wire %s %s", layer, width );
2035 
2036  // Write line style (width, type, color) only for non default values
2037  if( aLine->GetLayer() == LAYER_NOTES )
2038  {
2039  if( aLine->GetPenSize() != aLine->GetDefaultWidth() )
2040  m_out->Print( 0, " %s %d", T_WIDTH, aLine->GetLineSize() );
2041 
2042  if( aLine->GetLineStyle() != aLine->GetDefaultStyle() )
2043  m_out->Print( 0, " %s %s", T_STYLE, SCH_LINE::GetLineStyleName( aLine->GetLineStyle() ) );
2044 
2045  if( aLine->GetLineColor() != aLine->GetDefaultColor() )
2046  m_out->Print( 0, " %s",
2047  TO_UTF8( aLine->GetLineColor().ToColour().GetAsString( wxC2S_CSS_SYNTAX ) ) );
2048  }
2049 
2050  m_out->Print( 0, "\n" );
2051 
2052  m_out->Print( 0, "\t%-4d %-4d %-4d %-4d",
2053  aLine->GetStartPoint().x, aLine->GetStartPoint().y,
2054  aLine->GetEndPoint().x, aLine->GetEndPoint().y );
2055 
2056  m_out->Print( 0, "\n");
2057 }
2058 
2059 
2061 {
2062  wxCHECK_RET( aText != NULL, "SCH_TEXT* is NULL" );
2063 
2064  const char* italics = "~";
2065  const char* textType = "Notes";
2066 
2067  if( aText->IsItalic() )
2068  italics = "Italic";
2069 
2070  wxString text = aText->GetText();
2071 
2072  SCH_LAYER_ID layer = aText->GetLayer();
2073 
2074  if( layer == LAYER_NOTES || layer == LAYER_LOCLABEL )
2075  {
2076  if( layer == LAYER_NOTES )
2077  {
2078  // For compatibility reasons, the text must be saved in only one text line
2079  // so replace all EOLs with \\n
2080  text.Replace( wxT( "\n" ), wxT( "\\n" ) );
2081 
2082  // Here we should have no CR or LF character in line
2083  // This is not always the case if a multiline text was copied (using a copy/paste
2084  // function) from a text that uses E.O.L characters that differs from the current
2085  // EOL format. This is mainly the case under Linux using LF symbol when copying
2086  // a text from Windows (using CRLF symbol) so we must just remove the extra CR left
2087  // (or LF left under MacOSX)
2088  for( unsigned ii = 0; ii < text.Len(); )
2089  {
2090  if( text[ii] == 0x0A || text[ii] == 0x0D )
2091  text.erase( ii, 1 );
2092  else
2093  ii++;
2094  }
2095  }
2096  else
2097  {
2098  textType = "Label";
2099  }
2100 
2101  m_out->Print( 0, "Text %s %-4d %-4d %-4d %-4d %s %d\n%s\n", textType,
2102  aText->GetPosition().x, aText->GetPosition().y,
2103  aText->GetLabelSpinStyle(),
2104  aText->GetTextWidth(),
2105  italics, aText->GetThickness(), TO_UTF8( text ) );
2106  }
2107  else if( layer == LAYER_GLOBLABEL || layer == LAYER_HIERLABEL )
2108  {
2109  textType = ( layer == LAYER_GLOBLABEL ) ? "GLabel" : "HLabel";
2110 
2111  m_out->Print( 0, "Text %s %-4d %-4d %-4d %-4d %s %s %d\n%s\n", textType,
2112  aText->GetPosition().x, aText->GetPosition().y,
2113  aText->GetLabelSpinStyle(),
2114  aText->GetTextWidth(),
2115  SheetLabelType[aText->GetShape()],
2116  italics,
2117  aText->GetThickness(), TO_UTF8( text ) );
2118  }
2119 }
2120 
2121 
2122 int SCH_LEGACY_PLUGIN_CACHE::m_modHash = 1; // starts at 1 and goes up
2123 
2124 
2125 SCH_LEGACY_PLUGIN_CACHE::SCH_LEGACY_PLUGIN_CACHE( const wxString& aFullPathAndFileName ) :
2126  m_libFileName( aFullPathAndFileName ),
2127  m_isWritable( true ),
2128  m_isModified( false )
2129 {
2130  m_versionMajor = -1;
2131  m_versionMinor = -1;
2133 }
2134 
2135 
2137 {
2138  // When the cache is destroyed, all of the alias objects on the heap should be deleted.
2139  for( LIB_ALIAS_MAP::iterator it = m_aliases.begin(); it != m_aliases.end(); ++it )
2140  {
2141  wxLogTrace( traceSchLegacyPlugin, wxT( "Removing alias %s from library %s." ),
2142  GetChars( it->second->GetName() ), GetChars( GetLogicalName() ) );
2143  LIB_PART* part = it->second->GetPart();
2144  LIB_ALIAS* alias = it->second;
2145  delete alias;
2146 
2147  // When the last alias of a part is destroyed, the part is no longer required and it
2148  // too is destroyed.
2149  if( part && part->GetAliasCount() == 0 )
2150  delete part;
2151  }
2152 
2153  m_aliases.clear();
2154 }
2155 
2156 
2158 {
2159  // update the writable flag while we have a wxFileName, in a network this
2160  // is possibly quite dynamic anyway.
2161  m_isWritable = m_libFileName.IsFileWritable();
2162 
2163  return m_libFileName.GetModificationTime();
2164 }
2165 
2166 
2167 bool SCH_LEGACY_PLUGIN_CACHE::IsFile( const wxString& aFullPathAndFileName ) const
2168 {
2169  return m_libFileName == aFullPathAndFileName;
2170 }
2171 
2172 
2174 {
2175  if( m_fileModTime.IsValid() && m_libFileName.IsOk() && m_libFileName.FileExists() )
2176  return m_libFileName.GetModificationTime() != m_fileModTime;
2177 
2178  return false;
2179 }
2180 
2181 
2183 {
2184  wxCHECK_MSG( aAlias != NULL, NULL, "NULL pointer cannot be removed from library." );
2185 
2186  LIB_ALIAS_MAP::iterator it = m_aliases.find( aAlias->GetName() );
2187 
2188  if( it == m_aliases.end() )
2189  return NULL;
2190 
2191  // If the entry pointer doesn't match the name it is mapped to in the library, we
2192  // have done something terribly wrong.
2193  wxCHECK_MSG( *it->second == aAlias, NULL,
2194  "Pointer mismatch while attempting to remove alias entry <" + aAlias->GetName() +
2195  "> from library cache <" + m_libFileName.GetName() + ">." );
2196 
2197  LIB_ALIAS* alias = aAlias;
2198  LIB_PART* part = alias->GetPart();
2199 
2200  alias = part->RemoveAlias( alias );
2201 
2202  if( !alias )
2203  {
2204  delete part;
2205 
2206  if( m_aliases.size() > 1 )
2207  {
2208  LIB_ALIAS_MAP::iterator next = it;
2209  next++;
2210 
2211  if( next == m_aliases.end() )
2212  next = m_aliases.begin();
2213 
2214  alias = next->second;
2215  }
2216  }
2217 
2218  m_aliases.erase( it );
2219  m_isModified = true;
2220  ++m_modHash;
2221  return alias;
2222 }
2223 
2224 
2226 {
2227  // aPart is cloned in PART_LIB::AddPart(). The cache takes ownership of aPart.
2228  wxArrayString aliasNames = aPart->GetAliasNames();
2229 
2230  for( size_t i = 0; i < aliasNames.size(); i++ )
2231  {
2232  LIB_ALIAS_MAP::iterator it = m_aliases.find( aliasNames[i] );
2233 
2234  if( it != m_aliases.end() )
2235  removeAlias( it->second );
2236 
2237  LIB_ALIAS* alias = const_cast< LIB_PART* >( aPart )->GetAlias( aliasNames[i] );
2238 
2239  wxASSERT_MSG( alias != NULL, "No alias <" + aliasNames[i] + "> found in symbol <" +
2240  aPart->GetName() +">." );
2241 
2242  m_aliases[ aliasNames[i] ] = alias;
2243  }
2244 
2245  m_isModified = true;
2246  ++m_modHash;
2247 }
2248 
2249 
2251 {
2252  wxCHECK_RET( m_libFileName.IsAbsolute(),
2253  wxString::Format( "Cannot use relative file paths in legacy plugin to "
2254  "open library '%s'.", m_libFileName.GetFullPath() ) );
2255 
2256  wxLogTrace( traceSchLegacyPlugin, "Loading legacy symbol file '%s'",
2257  m_libFileName.GetFullPath() );
2258 
2259  FILE_LINE_READER reader( m_libFileName.GetFullPath() );
2260 
2261  if( !reader.ReadLine() )
2262  THROW_IO_ERROR( _( "unexpected end of file" ) );
2263 
2264  const char* line = reader.Line();
2265 
2266  if( !strCompare( "EESchema-LIBRARY Version", line, &line ) )
2267  {
2268  // Old .sym files (which are libraries with only one symbol, used to store and reuse shapes)
2269  // EESchema-LIB Version x.x SYMBOL. They are valid files.
2270  if( !strCompare( "EESchema-LIB Version", line, &line ) )
2271  SCH_PARSE_ERROR( "file is not a valid component or symbol library file", reader, line );
2272  }
2273 
2274  m_versionMajor = parseInt( reader, line, &line );
2275 
2276  if( *line != '.' )
2277  SCH_PARSE_ERROR( "invalid file version formatting in header", reader, line );
2278 
2279  line++;
2280 
2281  m_versionMinor = parseInt( reader, line, &line );
2282 
2283  if( m_versionMajor < 1 || m_versionMinor < 0 || m_versionMinor > 99 )
2284  SCH_PARSE_ERROR( "invalid file version in header", reader, line );
2285 
2286  // Check if this is a symbol library which is the same as a component library but without
2287  // any alias, documentation, footprint filters, etc.
2288  if( strCompare( "SYMBOL", line, &line ) )
2289  {
2290  // Symbol files add date and time stamp info to the header.
2292 
2294  }
2295  else
2296  {
2298  }
2299 
2300  while( reader.ReadLine() )
2301  {
2302  line = reader.Line();
2303 
2304  if( *line == '#' || isspace( *line ) ) // Skip comments and blank lines.
2305  continue;
2306 
2307  // Headers where only supported in older library file formats.
2308  if( m_libType == LIBRARY_TYPE_EESCHEMA && strCompare( "$HEADER", line ) )
2309  loadHeader( reader );
2310 
2311  if( strCompare( "DEF", line ) )
2312  {
2313  // Read one DEF/ENDDEF part entry from library:
2314  loadPart( reader );
2315 
2316  }
2317  }
2318 
2319  ++m_modHash;
2320 
2321  // Remember the file modification time of library file when the
2322  // cache snapshot was made, so that in a networked environment we will
2323  // reload the cache as needed.
2325 
2327  loadDocs();
2328 }
2329 
2330 
2332 {
2333  const char* line;
2334  wxString text;
2335  wxString aliasName;
2336  wxFileName fn = m_libFileName;
2337  LIB_ALIAS* alias = NULL;;
2338 
2339  fn.SetExt( DOC_EXT );
2340 
2341  // Not all libraries will have a document file.
2342  if( !fn.FileExists() )
2343  return;
2344 
2345  if( !fn.IsFileReadable() )
2346  THROW_IO_ERROR( wxString::Format( _( "user does not have permission to read library "
2347  "document file '%s'" ), fn.GetFullPath() ) );
2348 
2349  FILE_LINE_READER reader( fn.GetFullPath() );
2350 
2351  line = reader.ReadLine();
2352 
2353  if( !line )
2354  THROW_IO_ERROR( _( "symbol document library file is empty" ) );
2355 
2356  if( !strCompare( DOCFILE_IDENT, line, &line ) )
2357  SCH_PARSE_ERROR( "invalid document library file version formatting in header",
2358  reader, line );
2359 
2360  while( reader.ReadLine() )
2361  {
2362  line = reader.Line();
2363 
2364  if( *line == '#' ) // Comment line.
2365  continue;
2366 
2367  if( !strCompare( "$CMP", line, &line ) != 0 )
2368  SCH_PARSE_ERROR( "$CMP command expected", reader, line );
2369 
2370  parseUnquotedString( aliasName, reader, line, &line ); // Alias name.
2371 
2372  LIB_ALIAS_MAP::iterator it = m_aliases.find( aliasName );
2373 
2374  if( it == m_aliases.end() )
2375  wxLogWarning( "Alias '%s' not found in library:\n\n"
2376  "'%s'\n\nat line %d offset %d", aliasName, fn.GetFullPath(),
2377  reader.LineNumber(), (int) (line - reader.Line() ) );
2378  else
2379  alias = it->second;
2380 
2381  // Read the curent alias associated doc.
2382  // if the alias does not exist, just skip the description
2383  // (Can happen if a .dcm is not synchronized with the corresponding .lib file)
2384  while( reader.ReadLine() )
2385  {
2386  line = reader.Line();
2387 
2388  if( !line )
2389  SCH_PARSE_ERROR( "unexpected end of file", reader, line );
2390 
2391  if( strCompare( "$ENDCMP", line, &line ) )
2392  break;
2393 
2394  text = FROM_UTF8( line + 2 );
2395  text = text.Trim();
2396 
2397  switch( line[0] )
2398  {
2399  case 'D':
2400  if( alias )
2401  alias->SetDescription( text );
2402  break;
2403 
2404  case 'K':
2405  if( alias )
2406  alias->SetKeyWords( text );
2407  break;
2408 
2409  case 'F':
2410  if( alias )
2411  alias->SetDocFileName( text );
2412  break;
2413 
2414  case '#':
2415  break;
2416 
2417  default:
2418  SCH_PARSE_ERROR( "expected token in symbol definition", reader, line );
2419  }
2420  }
2421  }
2422 }
2423 
2424 
2426 {
2427  const char* line = aReader.Line();
2428 
2429  wxASSERT( strCompare( "$HEADER", line, &line ) );
2430 
2431  while( aReader.ReadLine() )
2432  {
2433  line = (char*) aReader;
2434 
2435  // The time stamp saved in old library files is not used or saved in the latest
2436  // library file version.
2437  if( strCompare( "TimeStamp", line, &line ) )
2438  continue;
2439  else if( strCompare( "$ENDHEADER", line, &line ) )
2440  return;
2441  }
2442 
2443  SCH_PARSE_ERROR( "$ENDHEADER not found", aReader, line );
2444 }
2445 
2446 
2448 {
2449  const char* line = aReader.Line();
2450 
2451  wxCHECK( strCompare( "DEF", line, &line ), NULL );
2452 
2453  // Read DEF line:
2454  char yes_no = 0;
2455 
2456  std::unique_ptr< LIB_PART > part( new LIB_PART( wxEmptyString ) );
2457 
2458  wxString name, prefix;
2459 
2460  parseUnquotedString( name, aReader, line, &line ); // Part name.
2461  parseUnquotedString( prefix, aReader, line, &line ); // Prefix name
2462  parseInt( aReader, line, &line ); // NumOfPins, unused.
2463  part->SetPinNameOffset( parseInt( aReader, line, &line ) ); // Pin name offset.
2464  yes_no = parseChar( aReader, line, &line ); // Show pin numbers.
2465 
2466  if( !( yes_no == 'Y' || yes_no == 'N') )
2467  SCH_PARSE_ERROR( "expected Y or N", aReader, line );
2468 
2469  part->SetShowPinNumbers( ( yes_no == 'N' ) ? false : true );
2470 
2471  yes_no = parseChar( aReader, line, &line ); // Show pin numbers.
2472 
2473  if( !( yes_no == 'Y' || yes_no == 'N') )
2474  SCH_PARSE_ERROR( "expected Y or N", aReader, line );
2475 
2476  part->SetShowPinNames( ( yes_no == 'N' ) ? false : true ); // Show pin names.
2477 
2478  part->SetUnitCount( parseInt( aReader, line, &line ) ); // Number of units.
2479 
2480  // Ensure m_unitCount is >= 1. Could be read as 0 in old libraries.
2481  if( part->GetUnitCount() < 1 )
2482  part->SetUnitCount( 1 );
2483 
2484  // Copy part name and prefix.
2485 
2486  // The root alias is added to the alias list by SetName() which is called by SetText().
2487  if( name.IsEmpty() )
2488  {
2489  part->SetName( "~" );
2490  }
2491  else if( name[0] != '~' )
2492  {
2493  part->SetName( name );
2494  }
2495  else
2496  {
2497  part->SetName( name.Right( name.Length() - 1 ) );
2498  part->GetValueField().SetVisible( false );
2499  }
2500 
2501  // There are some code paths in SetText() that do not set the root alias to the
2502  // alias list so add it here if it didn't get added by SetText().
2503  if( !part->HasAlias( part->GetName() ) )
2504  part->AddAlias( part->GetName() );
2505 
2506  LIB_FIELD& reference = part->GetReferenceField();
2507 
2508  if( prefix == "~" )
2509  {
2510  reference.Empty();
2511  reference.SetVisible( false );
2512  }
2513  else
2514  {
2515  reference.SetText( prefix );
2516  }
2517 
2518  // In version 2.2 and earlier, this parameter was a '0' which was just a place holder.
2519  // The was no concept of interchangeable multiple unit symbols.
2521  {
2522  // Nothing needs to be set since the default setting for symbols with multiple
2523  // units were never interchangeable. Just parse the 0 an move on.
2524  parseInt( aReader, line, &line );
2525  }
2526  else
2527  {
2528  char locked = parseChar( aReader, line, &line );
2529 
2530  if( locked == 'L' )
2531  part->LockUnits( true );
2532  else if( locked == 'F' || locked == '0' )
2533  part->LockUnits( false );
2534  else
2535  SCH_PARSE_ERROR( "expected L, F, or 0", aReader, line );
2536  }
2537 
2538 
2539  // There is the optional power component flag.
2540  if( *line )
2541  {
2542  char power = parseChar( aReader, line, &line );
2543 
2544  if( power == 'P' )
2545  part->SetPower();
2546  else if( power == 'N' )
2547  part->SetNormal();
2548  else
2549  SCH_PARSE_ERROR( "expected P or N", aReader, line );
2550  }
2551 
2552  line = aReader.ReadLine();
2553 
2554  // Read lines until "ENDDEF" is found.
2555  while( line )
2556  {
2557  if( *line == '#' ) // Comment
2558  ;
2559  else if( strCompare( "Ti", line, &line ) ) // Modification date is ignored.
2560  continue;
2561  else if( strCompare( "ALIAS", line, &line ) ) // Aliases
2562  loadAliases( part, aReader );
2563  else if( *line == 'F' ) // Fields
2564  loadField( part, aReader );
2565  else if( strCompare( "DRAW", line, &line ) ) // Drawing objects.
2566  loadDrawEntries( part, aReader );
2567  else if( strCompare( "$FPLIST", line, &line ) ) // Footprint filter list
2568  loadFootprintFilters( part, aReader );
2569  else if( strCompare( "ENDDEF", line, &line ) ) // End of part description
2570  {
2571  // Now all is good, Add the root alias to the cache alias list.
2572  m_aliases[ part->GetName() ] = part->GetAlias( part->GetName() );
2573 
2574  // Add aliases when exist
2575  for( size_t ii = 0; ii < part->GetAliasCount(); ++ii )
2576  m_aliases[ part->GetAlias( ii )->GetName() ] = part->GetAlias( ii );
2577 
2578  return part.release();
2579  }
2580 
2581  line = aReader.ReadLine();
2582  }
2583 
2584  SCH_PARSE_ERROR( "missing ENDDEF", aReader, line );
2585 }
2586 
2587 
2589 {
2590  wxCHECK_MSG( !aAliasName.IsEmpty(), false, "alias name cannot be empty" );
2591 
2592  // The alias name is not a duplicate so don't change it.
2593  if( m_aliases.find( aAliasName ) == m_aliases.end() )
2594  return false;
2595 
2596  int dupCounter = 1;
2597  wxString newAlias = aAliasName;
2598 
2599  // If the alias is already loaded, the library is broken. It may have been possible in
2600  // the past that this could happen so we assign a new alias name to prevent any conflicts
2601  // rather than throw an exception.
2602  while( m_aliases.find( newAlias ) != m_aliases.end() )
2603  {
2604  newAlias = aAliasName << dupCounter;
2605  dupCounter++;
2606  }
2607 
2608  aAliasName = newAlias;
2609 
2610  return true;
2611 }
2612 
2613 
2614 void SCH_LEGACY_PLUGIN_CACHE::loadAliases( std::unique_ptr< LIB_PART >& aPart,
2615  FILE_LINE_READER& aReader )
2616 {
2617  wxString newAlias;
2618  const char* line = aReader.Line();
2619 
2620  wxCHECK_RET( strCompare( "ALIAS", line, &line ), "Invalid ALIAS section" );
2621 
2622  // Parse the ALIAS list.
2623  wxString alias;
2624  parseUnquotedString( alias, aReader, line, &line );
2625 
2626  while( !alias.IsEmpty() )
2627  {
2628  newAlias = alias;
2629  checkForDuplicates( newAlias );
2630  aPart->AddAlias( newAlias );
2631  alias.clear();
2632  parseUnquotedString( alias, aReader, line, &line, true );
2633  }
2634 }
2635 
2636 
2637 void SCH_LEGACY_PLUGIN_CACHE::loadField( std::unique_ptr< LIB_PART >& aPart,
2638  FILE_LINE_READER& aReader )
2639 {
2640  const char* line = aReader.Line();
2641 
2642  wxCHECK_RET( *line == 'F', "Invalid field line" );
2643 
2644  int id;
2645 
2646  if( sscanf( line + 1, "%d", &id ) != 1 || id < 0 )
2647  SCH_PARSE_ERROR( "invalid field ID", aReader, line + 1 );
2648 
2649  std::unique_ptr< LIB_FIELD > field( new LIB_FIELD( aPart.get(), id ) );
2650 
2651  // Skip to the first double quote.
2652  while( *line != '"' && *line != 0 )
2653  line++;
2654 
2655  if( *line == 0 )
2656  SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, line );
2657 
2658  wxString text;
2659  parseQuotedString( text, aReader, line, &line, true );
2660 
2661  // Doctor the *.lib file field which has a "~" in blank fields. New saves will
2662  // not save like this.
2663  if( text.size() == 1 && text[0] == '~' )
2664  text.clear();
2665 
2666  field->m_Text = text;
2667 
2668  wxPoint pos;
2669 
2670  pos.x = parseInt( aReader, line, &line );
2671  pos.y = parseInt( aReader, line, &line );
2672  field->SetPosition( pos );
2673 
2674  wxSize textSize;
2675 
2676  textSize.x = textSize.y = parseInt( aReader, line, &line );
2677  field->SetTextSize( textSize );
2678 
2679  char textOrient = parseChar( aReader, line, &line );
2680 
2681  if( textOrient == 'H' )
2682  field->SetTextAngle( TEXT_ANGLE_HORIZ );
2683  else if( textOrient == 'V' )
2684  field->SetTextAngle( TEXT_ANGLE_VERT );
2685  else
2686  SCH_PARSE_ERROR( "invalid field text orientation parameter", aReader, line );
2687 
2688  char textVisible = parseChar( aReader, line, &line );
2689 
2690  if( textVisible == 'V' )
2691  field->SetVisible( true );
2692  else if ( textVisible == 'I' )
2693  field->SetVisible( false );
2694  else
2695  SCH_PARSE_ERROR( "invalid field text visibility parameter", aReader, line );
2696 
2697  // It may be technically correct to use the library version to determine if the field text
2698  // attributes are present. If anyone knows if that is valid and what version that would be,
2699  // please change this to test the library version rather than an EOL or the quoted string
2700  // of the field name.
2701  if( *line != 0 && *line != '"' )
2702  {
2703  char textHJustify = parseChar( aReader, line, &line );
2704 
2705  if( textHJustify == 'C' )
2706  field->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER );
2707  else if( textHJustify == 'L' )
2708  field->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
2709  else if( textHJustify == 'R' )
2710  field->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
2711  else
2712  SCH_PARSE_ERROR( "invalid field text horizontal justification parameter",
2713  aReader, line );
2714 
2715  wxString attributes;
2716 
2717  parseUnquotedString( attributes, aReader, line, &line );
2718 
2719  if( !(attributes.size() == 3 || attributes.size() == 1 ) )
2720  SCH_PARSE_ERROR( "invalid field text attributes size",
2721  aReader, line );
2722 
2723  if( attributes[0] == 'C' )
2724  field->SetVertJustify( GR_TEXT_VJUSTIFY_CENTER );
2725  else if( attributes[0] == 'B' )
2726  field->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
2727  else if( attributes[0] == 'T' )
2728  field->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
2729  else
2730  SCH_PARSE_ERROR( "invalid field text vertical justification parameter",
2731  aReader, line );
2732 
2733  if( attributes.size() == 3 )
2734  {
2735  if( attributes[1] == 'I' ) // Italic
2736  field->SetItalic( true );
2737  else if( attributes[1] != 'N' ) // No italics is default, check for error.
2738  SCH_PARSE_ERROR( "invalid field text italic parameter", aReader, line );
2739 
2740  if ( attributes[2] == 'B' ) // Bold
2741  field->SetBold( true );
2742  else if( attributes[2] != 'N' ) // No bold is default, check for error.
2743  SCH_PARSE_ERROR( "invalid field text bold parameter", aReader, line );
2744  }
2745  }
2746 
2747  // Fields in RAM must always have names.
2748  if( (unsigned) id < MANDATORY_FIELDS )
2749  {
2750  // Fields in RAM must always have names, because we are trying to get
2751  // less dependent on field ids and more dependent on names.
2752  // Plus assumptions are made in the field editors.
2753  field->m_name = TEMPLATE_FIELDNAME::GetDefaultFieldName( id );
2754 
2755  LIB_FIELD* fixedField = aPart->GetField( field->GetId() );
2756 
2757  // this will fire only if somebody broke a constructor or editor.
2758  // MANDATORY_FIELDS are always present in ram resident components, no
2759  // exceptions, and they always have their names set, even fixed fields.
2760  wxASSERT( fixedField );
2761 
2762  *fixedField = *field;
2763 
2764  // Ensure the VALUE field = the part name (can be not the case
2765  // with malformed libraries: edited by hand, or converted from other tools)
2766  if( fixedField->GetId() == VALUE )
2767  fixedField->m_Text = aPart->GetName();
2768  }
2769  else
2770  {
2771  wxString name;
2772 
2773  parseQuotedString( name, aReader, line, &line, true ); // Optional.
2774 
2775  if( !name.IsEmpty() )
2776  field->m_name = name;
2777 
2778  aPart->AddDrawItem( field.release() ); // LIB_FIELD* is now owned by the LIB_PART.
2779  }
2780 }
2781 
2782 
2783 void SCH_LEGACY_PLUGIN_CACHE::loadDrawEntries( std::unique_ptr< LIB_PART >& aPart,
2784  FILE_LINE_READER& aReader )
2785 {
2786  const char* line = aReader.Line();
2787 
2788  wxCHECK_RET( strCompare( "DRAW", line, &line ), "Invalid DRAW section" );
2789 
2790  line = aReader.ReadLine();
2791 
2792  while( line )
2793  {
2794  if( strCompare( "ENDDRAW", line, &line ) )
2795  return;
2796 
2797  switch( line[0] )
2798  {
2799  case 'A': // Arc
2800  aPart->AddDrawItem( loadArc( aPart, aReader ) );
2801  break;
2802 
2803  case 'C': // Circle
2804  aPart->AddDrawItem( loadCircle( aPart, aReader ) );
2805  break;
2806 
2807  case 'T': // Text
2808  aPart->AddDrawItem( loadText( aPart, aReader ) );
2809  break;
2810 
2811  case 'S': // Square
2812  aPart->AddDrawItem( loadRectangle( aPart, aReader ) );
2813  break;
2814 
2815  case 'X': // Pin Description
2816  aPart->AddDrawItem( loadPin( aPart, aReader ) );
2817  break;
2818 
2819  case 'P': // Polyline
2820  aPart->AddDrawItem( loadPolyLine( aPart, aReader ) );
2821  break;
2822 
2823  case 'B': // Bezier Curves
2824  aPart->AddDrawItem( loadBezier( aPart, aReader ) );
2825  break;
2826 
2827  case '#': // Comment
2828  case '\n': // Empty line
2829  case '\r':
2830  case 0:
2831  break;
2832 
2833  default:
2834  SCH_PARSE_ERROR( "undefined DRAW entry", aReader, line );
2835  }
2836 
2837  line = aReader.ReadLine();
2838  }
2839 
2840  SCH_PARSE_ERROR( "file ended prematurely loading component draw element", aReader, line );
2841 }
2842 
2843 
2845  const char** aOutput )
2846 {
2847  FILL_T mode;
2848 
2849  switch( parseChar( aReader, aLine, aOutput ) )
2850  {
2851  case 'F':
2852  mode = FILLED_SHAPE;
2853  break;
2854 
2855  case 'f':
2856  mode = FILLED_WITH_BG_BODYCOLOR;
2857  break;
2858 
2859  case 'N':
2860  mode = NO_FILL;
2861  break;
2862 
2863  default:
2864  SCH_PARSE_ERROR( "invalid fill type, expected f, F, or N", aReader, aLine );
2865  }
2866 
2867  return mode;
2868 }
2869 
2870 
2871 LIB_ARC* SCH_LEGACY_PLUGIN_CACHE::loadArc( std::unique_ptr< LIB_PART >& aPart,
2872  FILE_LINE_READER& aReader )
2873 {
2874  const char* line = aReader.Line();
2875 
2876  wxCHECK_MSG( strCompare( "A", line, &line ), NULL, "Invalid LIB_ARC definition" );
2877 
2878  std::unique_ptr< LIB_ARC > arc( new LIB_ARC( aPart.get() ) );
2879 
2880  wxPoint center;
2881 
2882  center.x = parseInt( aReader, line, &line );
2883  center.y = parseInt( aReader, line, &line );
2884 
2885  arc->SetPosition( center );
2886  arc->SetRadius( parseInt( aReader, line, &line ) );
2887 
2888  int angle1 = parseInt( aReader, line, &line );
2889  int angle2 = parseInt( aReader, line, &line );
2890 
2891  NORMALIZE_ANGLE_POS( angle1 );
2892  NORMALIZE_ANGLE_POS( angle2 );
2893  arc->SetFirstRadiusAngle( angle1 );
2894  arc->SetSecondRadiusAngle( angle2 );
2895 
2896  arc->SetUnit( parseInt( aReader, line, &line ) );
2897  arc->SetConvert( parseInt( aReader, line, &line ) );
2898  arc->SetWidth( parseInt( aReader, line, &line ) );
2899 
2900  // Old libraries (version <= 2.2) do not have always this FILL MODE param
2901  // when fill mode is no fill (default mode).
2902  if( *line != 0 )
2903  arc->SetFillMode( parseFillMode( aReader, line, &line ) );
2904 
2905  // Actual Coordinates of arc ends are read from file
2906  if( *line != 0 )
2907  {
2908  wxPoint arcStart, arcEnd;
2909 
2910  arcStart.x = parseInt( aReader, line, &line );
2911  arcStart.y = parseInt( aReader, line, &line );
2912  arcEnd.x = parseInt( aReader, line, &line );
2913  arcEnd.y = parseInt( aReader, line, &line );
2914 
2915  arc->SetStart( arcStart );
2916  arc->SetEnd( arcEnd );
2917  }
2918  else
2919  {
2920  // Actual Coordinates of arc ends are not read from file
2921  // (old library), calculate them
2922  wxPoint arcStart( arc->GetRadius(), 0 );
2923  wxPoint arcEnd( arc->GetRadius(), 0 );
2924 
2925  RotatePoint( &arcStart.x, &arcStart.y, -angle1 );
2926  arcStart += arc->GetPosition();
2927  arc->SetStart( arcStart );
2928  RotatePoint( &arcEnd.x, &arcEnd.y, -angle2 );
2929  arcEnd += arc->GetPosition();
2930  arc->SetEnd( arcEnd );
2931  }
2932 
2933  return arc.release();
2934 }
2935 
2936 
2937 LIB_CIRCLE* SCH_LEGACY_PLUGIN_CACHE::loadCircle( std::unique_ptr< LIB_PART >& aPart,
2938  FILE_LINE_READER& aReader )
2939 {
2940  const char* line = aReader.Line();
2941 
2942  wxCHECK_MSG( strCompare( "C", line, &line ), NULL, "Invalid LIB_CIRCLE definition" );
2943 
2944  std::unique_ptr< LIB_CIRCLE > circle( new LIB_CIRCLE( aPart.get() ) );
2945 
2946  wxPoint center;
2947 
2948  center.x = parseInt( aReader, line, &line );
2949  center.y = parseInt( aReader, line, &line );
2950 
2951  circle->SetPosition( center );
2952  circle->SetRadius( parseInt( aReader, line, &line ) );
2953  circle->SetUnit( parseInt( aReader, line, &line ) );
2954  circle->SetConvert( parseInt( aReader, line, &line ) );
2955  circle->SetWidth( parseInt( aReader, line, &line ) );
2956 
2957  if( *line != 0 )
2958  circle->SetFillMode( parseFillMode( aReader, line, &line ) );
2959 
2960  return circle.release();
2961 }
2962 
2963 
2964 LIB_TEXT* SCH_LEGACY_PLUGIN_CACHE::loadText( std::unique_ptr< LIB_PART >& aPart,
2965  FILE_LINE_READER& aReader )
2966 {
2967  const char* line = aReader.Line();
2968 
2969  wxCHECK_MSG( strCompare( "T", line, &line ), NULL, "Invalid LIB_TEXT definition" );
2970 
2971  std::unique_ptr< LIB_TEXT > text( new LIB_TEXT( aPart.get() ) );
2972 
2973  text->SetTextAngle( (double) parseInt( aReader, line, &line ) );
2974 
2975  wxPoint center;
2976 
2977  center.x = parseInt( aReader, line, &line );
2978  center.y = parseInt( aReader, line, &line );
2979  text->SetPosition( center );
2980 
2981  wxSize size;
2982 
2983  size.x = size.y = parseInt( aReader, line, &line );
2984  text->SetTextSize( size );
2985  text->SetVisible( !parseInt( aReader, line, &line ) );
2986  text->SetUnit( parseInt( aReader, line, &line ) );
2987  text->SetConvert( parseInt( aReader, line, &line ) );
2988 
2989  wxString str;
2990 
2991  // If quoted string loading fails, load as not quoted string.
2992  if( *line == '"' )
2993  parseQuotedString( str, aReader, line, &line );
2994  else
2995  parseUnquotedString( str, aReader, line, &line );
2996 
2997  if( !str.IsEmpty() )
2998  {
2999  // convert two apostrophes back to double quote
3000  str.Replace( "''", "\"" );
3001  str.Replace( wxT( "~" ), wxT( " " ) );
3002  }
3003 
3004  text->SetText( str );
3005 
3006  // Here things are murky and not well defined. At some point it appears the format
3007  // was changed to add text properties. However rather than add the token to the end of
3008  // the text definition, it was added after the string and no mention if the file
3009  // verion was bumped or not so this code make break on very old component libraries.
3010  //
3011  // Update: apparently even in the latest version this can be different so added a test
3012  // for end of line before checking for the text properties.
3013  if( LIB_VERSION( m_versionMajor, m_versionMinor ) > LIB_VERSION( 2, 0 ) && !is_eol( *line ) )
3014  {
3015  if( strCompare( "Italic", line, &line ) )
3016  text->SetItalic( true );
3017  else if( !strCompare( "Normal", line, &line ) )
3018  SCH_PARSE_ERROR( "invalid text stype, expected 'Normal' or 'Italic'",
3019  aReader, line );
3020 
3021  if( parseInt( aReader, line, &line ) > 0 )
3022  text->SetBold( true );
3023 
3024  // Some old libaries version > 2.0 do not have these options for text justification:
3025  if( !is_eol( *line ) )
3026  {
3027  switch( parseChar( aReader, line, &line ) )
3028  {
3029  case 'L':
3030  text->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
3031  break;
3032 
3033  case 'C':
3034  text->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER );
3035  break;
3036 
3037  case 'R':
3038  text->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
3039  break;
3040 
3041  default:
3042  SCH_PARSE_ERROR( "invalid horizontal text justication parameter, expected L, C, or R",
3043  aReader, line );
3044  }
3045 
3046  switch( parseChar( aReader, line, &line ) )
3047  {
3048  case 'T':
3049  text->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
3050  break;
3051 
3052  case 'C':
3053  text->SetVertJustify( GR_TEXT_VJUSTIFY_CENTER );
3054  break;
3055 
3056  case 'B':
3057  text->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
3058  break;
3059 
3060  default:
3061  SCH_PARSE_ERROR( "invalid vertical text justication parameter, expected T, C, or B",
3062  aReader, line );
3063  }
3064  }
3065  }
3066 
3067  return text.release();
3068 }
3069 
3070 
3071 LIB_RECTANGLE* SCH_LEGACY_PLUGIN_CACHE::loadRectangle( std::unique_ptr< LIB_PART >& aPart,
3072  FILE_LINE_READER& aReader )
3073 {
3074  const char* line = aReader.Line();
3075 
3076  wxCHECK_MSG( strCompare( "S", line, &line ), NULL, "Invalid LIB_RECTANGLE definition" );
3077 
3078  std::unique_ptr< LIB_RECTANGLE > rectangle( new LIB_RECTANGLE( aPart.get() ) );
3079 
3080  wxPoint pos;
3081 
3082  pos.x = parseInt( aReader, line, &line );
3083  pos.y = parseInt( aReader, line, &line );
3084  rectangle->SetPosition( pos );
3085 
3086  wxPoint end;
3087 
3088  end.x = parseInt( aReader, line, &line );
3089  end.y = parseInt( aReader, line, &line );
3090  rectangle->SetEnd( end );
3091 
3092  rectangle->SetUnit( parseInt( aReader, line, &line ) );
3093  rectangle->SetConvert( parseInt( aReader, line, &line ) );
3094  rectangle->SetWidth( parseInt( aReader, line, &line ) );
3095 
3096  if( *line != 0 )
3097  rectangle->SetFillMode( parseFillMode( aReader, line, &line ) );
3098 
3099  return rectangle.release();
3100 }
3101 
3102 
3103 LIB_PIN* SCH_LEGACY_PLUGIN_CACHE::loadPin( std::unique_ptr< LIB_PART >& aPart,
3104  FILE_LINE_READER& aReader )
3105 {
3106  const char* line = aReader.Line();
3107 
3108  wxCHECK_MSG( strCompare( "X", line, &line ), NULL, "Invalid LIB_PIN definition" );
3109 
3110  std::unique_ptr< LIB_PIN > pin( new LIB_PIN( aPart.get() ) );
3111 
3112  wxString name, number;
3113 
3114  parseUnquotedString( name, aReader, line, &line );
3115  parseUnquotedString( number, aReader, line, &line );
3116 
3117  pin->SetName( name, false );
3118  pin->SetNumber( number );
3119 
3120  wxPoint pos;
3121 
3122  pos.x = parseInt( aReader, line, &line );
3123  pos.y = parseInt( aReader, line, &line );
3124  pin->SetPosition( pos );
3125  pin->SetLength( parseInt( aReader, line, &line ), false );
3126  pin->SetOrientation( parseChar( aReader, line, &line ), false );
3127  pin->SetNumberTextSize( parseInt( aReader, line, &line ), false );
3128  pin->SetNameTextSize( parseInt( aReader, line, &line ), false );
3129  pin->SetUnit( parseInt( aReader, line, &line ) );
3130  pin->SetConvert( parseInt( aReader, line, &line ) );
3131 
3132  char type = parseChar( aReader, line, &line );
3133 
3134  wxString attributes;
3135 
3136  // Optional
3137  parseUnquotedString( attributes, aReader, line, &line, true );
3138 
3139  switch( type )
3140  {
3141  case 'I':
3142  pin->SetType( PIN_INPUT, false );
3143  break;
3144 
3145  case 'O':
3146  pin->SetType( PIN_OUTPUT, false );
3147  break;
3148 
3149  case 'B':
3150  pin->SetType( PIN_BIDI, false );
3151  break;
3152 
3153  case 'T':
3154  pin->SetType( PIN_TRISTATE, false );
3155  break;
3156 
3157  case 'P':
3158  pin->SetType( PIN_PASSIVE, false );
3159  break;
3160 
3161  case 'U':
3162  pin->SetType( PIN_UNSPECIFIED, false );
3163  break;
3164 
3165  case 'W':
3166  pin->SetType( PIN_POWER_IN, false );
3167  break;
3168 
3169  case 'w':
3170  pin->SetType( PIN_POWER_OUT, false );
3171  break;
3172 
3173  case 'C':
3174  pin->SetType( PIN_OPENCOLLECTOR, false );
3175  break;
3176 
3177  case 'E':
3178  pin->SetType( PIN_OPENEMITTER, false );
3179  break;
3180 
3181  case 'N':
3182  pin->SetType( PIN_NC, false );
3183  break;
3184 
3185  default:
3186  SCH_PARSE_ERROR( "unknown pin type", aReader, line );
3187  }
3188 
3189  if( !attributes.IsEmpty() ) /* Special Symbol defined */
3190  {
3191  enum
3192  {
3193  INVERTED = 1 << 0,
3194  CLOCK = 1 << 1,
3195  LOWLEVEL_IN = 1 << 2,
3196  LOWLEVEL_OUT = 1 << 3,
3197  FALLING_EDGE = 1 << 4,
3198  NONLOGIC = 1 << 5
3199  };
3200 
3201  int flags = 0;
3202 
3203  for( int j = attributes.size(); j > 0; )
3204  {
3205  switch( attributes[--j].GetValue() )
3206  {
3207  case '~':
3208  break;
3209 
3210  case 'N':
3211  pin->SetVisible( false );
3212  break;
3213 
3214  case 'I':
3215  flags |= INVERTED;
3216  break;
3217 
3218  case 'C':
3219  flags |= CLOCK;
3220  break;
3221 
3222  case 'L':
3223  flags |= LOWLEVEL_IN;
3224  break;
3225 
3226  case 'V':
3227  flags |= LOWLEVEL_OUT;
3228  break;
3229 
3230  case 'F':
3231  flags |= FALLING_EDGE;
3232  break;
3233 
3234  case 'X':
3235  flags |= NONLOGIC;
3236  break;
3237 
3238  default:
3239  SCH_PARSE_ERROR( "unknown pin attribute", aReader, line );
3240  }
3241  }
3242 
3243  switch( flags )
3244  {
3245  case 0:
3246  pin->SetShape( PINSHAPE_LINE );
3247  break;
3248 
3249  case INVERTED:
3250  pin->SetShape( PINSHAPE_INVERTED );
3251  break;
3252 
3253  case CLOCK:
3254  pin->SetShape( PINSHAPE_CLOCK );
3255  break;
3256 
3257  case INVERTED | CLOCK:
3258  pin->SetShape( PINSHAPE_INVERTED_CLOCK );
3259  break;
3260 
3261  case LOWLEVEL_IN:
3262  pin->SetShape( PINSHAPE_INPUT_LOW );
3263  break;
3264 
3265  case LOWLEVEL_IN | CLOCK:
3266  pin->SetShape( PINSHAPE_CLOCK_LOW );
3267  break;
3268 
3269  case LOWLEVEL_OUT:
3270  pin->SetShape( PINSHAPE_OUTPUT_LOW );
3271  break;
3272 
3273  case FALLING_EDGE:
3274  pin->SetShape( PINSHAPE_FALLING_EDGE_CLOCK );
3275  break;
3276 
3277  case NONLOGIC:
3278  pin->SetShape( PINSHAPE_NONLOGIC );
3279  break;
3280 
3281  default:
3282  SCH_PARSE_ERROR( "pin attributes do not define a valid pin shape", aReader, line );
3283  }
3284  }
3285 
3286  return pin.release();
3287 }
3288 
3289 
3290 LIB_POLYLINE* SCH_LEGACY_PLUGIN_CACHE::loadPolyLine( std::unique_ptr< LIB_PART >& aPart,
3291  FILE_LINE_READER& aReader )
3292 {
3293  const char* line = aReader.Line();
3294 
3295  wxCHECK_MSG( strCompare( "P", line, &line ), NULL, "Invalid LIB_POLYLINE definition" );
3296 
3297  std::unique_ptr< LIB_POLYLINE > polyLine( new LIB_POLYLINE( aPart.get() ) );
3298 
3299  int points = parseInt( aReader, line, &line );
3300  polyLine->SetUnit( parseInt( aReader, line, &line ) );
3301  polyLine->SetConvert( parseInt( aReader, line, &line ) );
3302  polyLine->SetWidth( parseInt( aReader, line, &line ) );
3303 
3304  wxPoint pt;
3305 
3306  for( int i = 0; i < points; i++ )
3307  {
3308  pt.x = parseInt( aReader, line, &line );
3309  pt.y = parseInt( aReader, line, &line );
3310  polyLine->AddPoint( pt );
3311  }
3312 
3313  if( *line != 0 )
3314  polyLine->SetFillMode( parseFillMode( aReader, line, &line ) );
3315 
3316  return polyLine.release();
3317 }
3318 
3319 
3320 LIB_BEZIER* SCH_LEGACY_PLUGIN_CACHE::loadBezier( std::unique_ptr< LIB_PART >& aPart,
3321  FILE_LINE_READER& aReader )
3322 {
3323  const char* line = aReader.Line();
3324 
3325  wxCHECK_MSG( strCompare( "B", line, &line ), NULL, "Invalid LIB_BEZIER definition" );
3326 
3327  std::unique_ptr< LIB_BEZIER > bezier( new LIB_BEZIER( aPart.get() ) );
3328 
3329  int points = parseInt( aReader, line, &line );
3330  bezier->SetUnit( parseInt( aReader, line, &line ) );
3331  bezier->SetConvert( parseInt( aReader, line, &line ) );
3332  bezier->SetWidth( parseInt( aReader, line, &line ) );
3333 
3334  wxPoint pt;
3335 
3336  for( int i = 0; i < points; i++ )
3337  {
3338  pt.x = parseInt( aReader, line, &line );
3339  pt.y = parseInt( aReader, line, &line );
3340  bezier->AddPoint( pt );
3341  }
3342 
3343  if( *line != 0 )
3344  bezier->SetFillMode( parseFillMode( aReader, line, &line ) );
3345 
3346  return bezier.release();
3347 }
3348 
3349 
3350 void SCH_LEGACY_PLUGIN_CACHE::loadFootprintFilters( std::unique_ptr< LIB_PART >& aPart,
3351  FILE_LINE_READER& aReader )
3352 {
3353  const char* line = aReader.Line();
3354 
3355  wxCHECK_RET( strCompare( "$FPLIST", line, &line ), "Invalid footprint filter list" );
3356 
3357  line = aReader.ReadLine();
3358 
3359  while( line )
3360  {
3361  if( strCompare( "$ENDFPLIST", line, &line ) )
3362  return;
3363 
3364  wxString footprint;
3365 
3366  parseUnquotedString( footprint, aReader, line, &line );
3367  aPart->GetFootPrints().Add( footprint );
3368  line = aReader.ReadLine();
3369  }
3370 
3371  SCH_PARSE_ERROR( "file ended prematurely while loading footprint filters", aReader, line );
3372 }
3373 
3374 
3375 void SCH_LEGACY_PLUGIN_CACHE::Save( bool aSaveDocFile )
3376 {
3377  if( !m_isModified )
3378  return;
3379 
3380  std::unique_ptr< FILE_OUTPUTFORMATTER > formatter( new FILE_OUTPUTFORMATTER( m_libFileName.GetFullPath() ) );
3381  formatter->Print( 0, "%s %d.%d\n", LIBFILE_IDENT, LIB_VERSION_MAJOR, LIB_VERSION_MINOR );
3382  formatter->Print( 0, "#encoding utf-8\n");
3383 
3384  for( LIB_ALIAS_MAP::iterator it = m_aliases.begin(); it != m_aliases.end(); it++ )
3385  {
3386  if( !it->second->IsRoot() )
3387  continue;
3388 
3389  it->second->GetPart()->Save( *formatter.get() );
3390  }
3391 
3392  formatter->Print( 0, "#\n#End Library\n" );
3393  formatter.reset();
3394 
3395  m_fileModTime = m_libFileName.GetModificationTime();
3396  m_isModified = false;
3397 
3398  if( aSaveDocFile )
3399  saveDocFile();
3400 }
3401 
3402 
3404 {
3405  wxFileName docFileName = m_libFileName;
3406 
3407  docFileName.SetExt( DOC_EXT );
3408  FILE_OUTPUTFORMATTER formatter( docFileName.GetFullPath() );
3409 
3410  formatter.Print( 0, "%s\n", DOCFILE_IDENT );
3411 
3412  for( LIB_ALIAS_MAP::iterator it = m_aliases.begin(); it != m_aliases.end(); it++ )
3413  {
3414  it->second->SaveDoc( formatter );
3415  }
3416 
3417  formatter.Print( 0, "#\n#End Doc Library\n" );
3418 }
3419 
3420 
3421 void SCH_LEGACY_PLUGIN_CACHE::DeleteAlias( const wxString& aAliasName )
3422 {
3423  LIB_ALIAS_MAP::iterator it = m_aliases.find( aAliasName );
3424 
3425  if( it == m_aliases.end() )
3426  THROW_IO_ERROR( wxString::Format( _( "library %s does not contain an alias %s" ),
3427  m_libFileName.GetFullName(), aAliasName ) );
3428 
3429  LIB_ALIAS* alias = it->second;
3430  LIB_PART* part = alias->GetPart();
3431 
3432  alias = part->RemoveAlias( alias );
3433 
3434  if( !alias )
3435  {
3436  delete part;
3437 
3438  if( m_aliases.size() > 1 )
3439  {
3440  LIB_ALIAS_MAP::iterator next = it;
3441  next++;
3442 
3443  if( next == m_aliases.end() )
3444  next = m_aliases.begin();
3445 
3446  alias = next->second;
3447  }
3448  }
3449 
3450  m_aliases.erase( it );
3451  ++m_modHash;
3452  m_isModified = true;
3453 }
3454 
3455 
3456 void SCH_LEGACY_PLUGIN_CACHE::DeleteSymbol( const wxString& aAliasName )
3457 {
3458  LIB_ALIAS_MAP::iterator it = m_aliases.find( aAliasName );
3459 
3460  if( it == m_aliases.end() )
3461  THROW_IO_ERROR( wxString::Format( _( "library %s does not contain an alias %s" ),
3462  m_libFileName.GetFullName(), aAliasName ) );
3463 
3464  LIB_ALIAS* alias = it->second;
3465  LIB_PART* part = alias->GetPart();
3466 
3467  wxArrayString aliasNames = part->GetAliasNames();
3468 
3469  // Deleting all of the aliases deletes the symbol from the library.
3470  for( size_t i = 0; i < aliasNames.Count(); i++ )
3471  DeleteAlias( aliasNames[i] );
3472 }
3473 
3474 
3475 void SCH_LEGACY_PLUGIN::cacheLib( const wxString& aLibraryFileName )
3476 {
3477  if( !m_cache || !m_cache->IsFile( aLibraryFileName ) || m_cache->IsFileChanged() )
3478  {
3479  // a spectacular episode in memory management:
3480  delete m_cache;
3481  m_cache = new SCH_LEGACY_PLUGIN_CACHE( aLibraryFileName );
3482 
3483  // Because m_cache is rebuilt, increment PART_LIBS::s_modify_generation
3484  // to modify the hash value that indicate component to symbol links
3485  // must be updated.
3487 
3488  if( !isBuffering( m_props ) )
3489  m_cache->Load();
3490  }
3491 }
3492 
3493 
3495 {
3496  std::string propName( SCH_LEGACY_PLUGIN::PropNoDocFile );
3497 
3498  if( aProperties && aProperties->find( propName ) != aProperties->end() )
3499  return false;
3500 
3501  return true;
3502 }
3503 
3504 
3505 bool SCH_LEGACY_PLUGIN::isBuffering( const PROPERTIES* aProperties )
3506 {
3507  return ( aProperties && aProperties->Exists( SCH_LEGACY_PLUGIN::PropBuffering ) );
3508 }
3509 
3510 
3512 {
3513  if( m_cache )
3514  return m_cache->GetModifyHash();
3515 
3516  // If the cache hasn't been loaded, it hasn't been modified.
3517  return 0;
3518 }
3519 
3520 
3521 size_t SCH_LEGACY_PLUGIN::GetSymbolLibCount( const wxString& aLibraryPath,
3522  const PROPERTIES* aProperties )
3523 {
3524  LOCALE_IO toggle;
3525 
3526  m_props = aProperties;
3527 
3528  cacheLib( aLibraryPath );
3529 
3530  return m_cache->m_aliases.size();
3531 }
3532 
3533 
3534 void SCH_LEGACY_PLUGIN::EnumerateSymbolLib( wxArrayString& aAliasNameList,
3535  const wxString& aLibraryPath,
3536  const PROPERTIES* aProperties )
3537 {
3538  LOCALE_IO toggle; // toggles on, then off, the C locale.
3539 
3540  m_props = aProperties;
3541 
3542  bool powerSymbolsOnly = ( aProperties &&
3543  aProperties->find( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) != aProperties->end() );
3544  cacheLib( aLibraryPath );
3545 
3546  const LIB_ALIAS_MAP& aliases = m_cache->m_aliases;
3547 
3548  for( LIB_ALIAS_MAP::const_iterator it = aliases.begin(); it != aliases.end(); ++it )
3549  {
3550  if( !powerSymbolsOnly || it->second->GetPart()->IsPower() )
3551  aAliasNameList.Add( it->first );
3552  }
3553 }
3554 
3555 
3556 void SCH_LEGACY_PLUGIN::EnumerateSymbolLib( std::vector<LIB_ALIAS*>& aAliasList,
3557  const wxString& aLibraryPath,
3558  const PROPERTIES* aProperties )
3559 {
3560  LOCALE_IO toggle; // toggles on, then off, the C locale.
3561 
3562  m_props = aProperties;
3563 
3564  bool powerSymbolsOnly = ( aProperties &&
3565  aProperties->find( SYMBOL_LIB_TABLE::PropPowerSymsOnly ) != aProperties->end() );
3566  cacheLib( aLibraryPath );
3567 
3568  const LIB_ALIAS_MAP& aliases = m_cache->m_aliases;
3569 
3570  for( LIB_ALIAS_MAP::const_iterator it = aliases.begin(); it != aliases.end(); ++it )
3571  {
3572  if( !powerSymbolsOnly || it->second->GetPart()->IsPower() )
3573  aAliasList.push_back( it->second );
3574  }
3575 }
3576 
3577 
3578 LIB_ALIAS* SCH_LEGACY_PLUGIN::LoadSymbol( const wxString& aLibraryPath, const wxString& aAliasName,
3579  const PROPERTIES* aProperties )
3580 {
3581  LOCALE_IO toggle; // toggles on, then off, the C locale.
3582 
3583  m_props = aProperties;
3584 
3585  cacheLib( aLibraryPath );
3586 
3587  LIB_ALIAS_MAP::const_iterator it = m_cache->m_aliases.find( aAliasName );
3588 
3589  if( it == m_cache->m_aliases.end() )
3590  return NULL;
3591 
3592  return it->second;
3593 }
3594 
3595 
3596 void SCH_LEGACY_PLUGIN::SaveSymbol( const wxString& aLibraryPath, const LIB_PART* aSymbol,
3597  const PROPERTIES* aProperties )
3598 {
3599  m_props = aProperties;
3600 
3601  cacheLib( aLibraryPath );
3602 
3603  m_cache->AddSymbol( aSymbol );
3604 
3605  if( !isBuffering( aProperties ) )
3606  m_cache->Save( writeDocFile( aProperties ) );
3607 }
3608 
3609 
3610 void SCH_LEGACY_PLUGIN::DeleteAlias( const wxString& aLibraryPath, const wxString& aAliasName,
3611  const PROPERTIES* aProperties )
3612 {
3613  m_props = aProperties;
3614 
3615  cacheLib( aLibraryPath );
3616 
3617  m_cache->DeleteAlias( aAliasName );
3618 
3619  if( !isBuffering( aProperties ) )
3620  m_cache->Save( writeDocFile( aProperties ) );
3621 }
3622 
3623 
3624 void SCH_LEGACY_PLUGIN::DeleteSymbol( const wxString& aLibraryPath, const wxString& aAliasName,
3625  const PROPERTIES* aProperties )
3626 {
3627  m_props = aProperties;
3628 
3629  cacheLib( aLibraryPath );
3630 
3631  m_cache->DeleteSymbol( aAliasName );
3632 
3633  if( !isBuffering( aProperties ) )
3634  m_cache->Save( writeDocFile( aProperties ) );
3635 }
3636 
3637 
3638 void SCH_LEGACY_PLUGIN::CreateSymbolLib( const wxString& aLibraryPath,
3639  const PROPERTIES* aProperties )
3640 {
3641  if( wxFileExists( aLibraryPath ) )
3642  {
3644  _( "symbol library '%s' already exists, cannot create a new library" ),
3645  aLibraryPath.GetData() ) );
3646  }
3647 
3648  LOCALE_IO toggle;
3649 
3650  m_props = aProperties;
3651 
3652  delete m_cache;
3653  m_cache = new SCH_LEGACY_PLUGIN_CACHE( aLibraryPath );
3654  m_cache->SetModified();
3655  m_cache->Save( writeDocFile( aProperties ) );
3656  m_cache->Load(); // update m_writable and m_mod_time
3657 }
3658 
3659 
3660 bool SCH_LEGACY_PLUGIN::DeleteSymbolLib( const wxString& aLibraryPath,
3661  const PROPERTIES* aProperties )
3662 {
3663  wxFileName fn = aLibraryPath;
3664 
3665  if( !fn.FileExists() )
3666  return false;
3667 
3668  // Some of the more elaborate wxRemoveFile() crap puts up its own wxLog dialog
3669  // we don't want that. we want bare metal portability with no UI here.
3670  if( wxRemove( aLibraryPath ) )
3671  {
3672  THROW_IO_ERROR( wxString::Format( _( "library '%s' cannot be deleted" ),
3673  aLibraryPath.GetData() ) );
3674  }
3675 
3676  if( m_cache && m_cache->IsFile( aLibraryPath ) )
3677  {
3678  delete m_cache;
3679  m_cache = 0;
3680  }
3681 
3682  return true;
3683 }
3684 
3685 
3686 void SCH_LEGACY_PLUGIN::SaveLibrary( const wxString& aLibraryPath, const PROPERTIES* aProperties )
3687 {
3688  if( !m_cache )
3689  m_cache = new SCH_LEGACY_PLUGIN_CACHE( aLibraryPath );
3690 
3691  wxString oldFileName = m_cache->GetFileName();
3692 
3693  if( !m_cache->IsFile( aLibraryPath ) )
3694  {
3695  m_cache->SetFileName( aLibraryPath );
3696  }
3697 
3698  // This is a forced save.
3699  m_cache->SetModified();
3700  m_cache->Save( writeDocFile( aProperties ) );
3701  m_cache->SetFileName( oldFileName );
3702 }
3703 
3704 
3705 bool SCH_LEGACY_PLUGIN::CheckHeader( const wxString& aFileName )
3706 {
3707  // Open file and check first line
3708  wxTextFile tempFile;
3709 
3710  tempFile.Open( aFileName );
3711  wxString firstline;
3712  // read the first line
3713  firstline = tempFile.GetFirstLine();
3714  tempFile.Close();
3715 
3716  return firstline.StartsWith( "EESchema" );
3717 }
3718 
3719 
3720 bool SCH_LEGACY_PLUGIN::IsSymbolLibWritable( const wxString& aLibraryPath )
3721 {
3722  return wxFileName::IsFileWritable( aLibraryPath );
3723 }
3724 
3725 
3726 const char* SCH_LEGACY_PLUGIN::PropBuffering = "buffering";
3727 const char* SCH_LEGACY_PLUGIN::PropNoDocFile = "no_doc_file";
void SetComment1(const wxString &aComment)
Definition of the SCH_SHEET class for Eeschema.
Class for a bus to bus entry.
CITER next(CITER it)
Definition: ptree.cpp:130
FILE_OUTPUTFORMATTER * m_out
The output formatter for saving SCH_SCREEN objects.
PINSHEETLABEL_SHAPE GetShape() const
Definition: sch_text.h:118
#define TEXT_ANGLE_HORIZ
Frequent text rotations, used with {Set,Get}TextAngle(), in 0.1 degrees for now, hoping to migrate to...
Definition: common.h:90
Class SCH_FIELD instances are attached to a component and provide a place for the component's value...
Definition: sch_field.h:56
SCH_BITMAP * loadBitmap(FILE_LINE_READER &aReader)
LIB_PIN * loadPin(std::unique_ptr< LIB_PART > &aPart, FILE_LINE_READER &aReader)
Part library alias object definition.
char * ReadLine() override
Function ReadLine reads a line of text into the buffer and increments the line number counter...
Definition: richio.cpp:194
wxString GetName(bool aUseDefaultName=true) const
Function GetName returns the field name.
Definition: sch_field.cpp:425
bool SearchHierarchy(const wxString &aFilename, SCH_SCREEN **aScreen)
Search the existing hierarchy for an instance of screen loaded from aFileName.
Definition: sch_sheet.cpp:562
wxString m_Text
Definition: eda_text.h:346
TRANSFORM & GetTransform() const
SCH_SHEET_PINS & GetPins()
Definition: sch_sheet.h:334
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
int y2
Definition: transform.h:51
bool IsItalic() const
Definition: eda_text.h:170
Class LOCALE_IO is a class that can be instantiated within a scope in which you are expecting excepti...
Definition: common.h:165
const wxString & GetCompany() const
wxString m_error
For throwing exceptions.
static int s_modify_generation
helper for GetModifyHash()
static int parseInt(FILE_LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Function parseInt.
LIB_BEZIER * loadBezier(std::unique_ptr< LIB_PART > &aPart, FILE_LINE_READER &aReader)
#define LIBFILE_IDENT
Definition: class_library.h:59
wxPoint GetPosition() const override
Function GetPosition.
void SetRevision(const wxString &aRevision)
Class LIB_TEXT defines a component library graphical text item.
Definition: lib_text.h:45
void saveLine(SCH_LINE *aLine)
COLOR4D GetLineColor() const
Definition: sch_line.cpp:234
int GetId() const
Definition: sch_field.h:87
SCH_LEGACY_PLUGIN_CACHE * m_cache
LIB_CIRCLE * loadCircle(std::unique_ptr< LIB_PART > &aPart, FILE_LINE_READER &aReader)
static char parseChar(FILE_LINE_READER &aReader, const char *aCurrentToken, const char **aNextToken=NULL)
Function parseChar.
The first 4 are mandatory, and must be instantiated in SCH_COMPONENT and LIB_PART constructors...
Class LIB_FIELD is used in symbol libraries.
Definition: lib_field.h:60
int GetTextWidth() const
Definition: eda_text.h:218
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:103
const wxString & GetFileName() const
wxString GetPrefix() const
void SaveLibrary(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
wxImage * GetImageData()
size_t GetSymbolLibCount(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
int GetLabelSpinStyle() const
Definition: sch_text.h:116
void SetVisible(bool aVisible)
Definition: eda_text.h:175
time_t GetNewTimeStamp()
Definition: common.cpp:166
int x2
Definition: transform.h:50
wxPoint GetLibPosition() const
Definition: sch_field.h:187
SCH_SHEET * m_rootSheet
The root sheet of the schematic being loaded..
SCH_SHEET * GetRootSheet()
Return the root sheet of this SCH_SHEET object.
Definition: sch_sheet.cpp:135
void Format(SCH_SCREEN *aScreen)
void saveText(SCH_TEXT *aText)
#define LIB_VERSION_MINOR
Definition: class_library.h:56
const wxString & GetComment4() const
void SetDate(const wxString &aDate)
Function SetDate sets the date field, and defaults to the current time and date.
SCH_LEGACY_PLUGIN_CACHE(const wxString &aLibraryPath)
bool Exists(const std::string &aProperty) const
Definition: properties.h:44
void SetPageSettings(const PAGE_INFO &aPageSettings)
#define LIB_VERSION(major, minor)
Definition: class_library.h:61
void SaveSymbol(const wxString &aLibraryPath, const LIB_PART *aSymbol, const PROPERTIES *aProperties=NULL) override
Write aSymbol to an existing library located at aLibraryPath.
wxPoint GetEndPoint() const
Definition: sch_line.h:80
const wxString & GetDate() const
int x1
Definition: transform.h:48
static const wxString GetDefaultFieldName(int aFieldNdx)
Function GetDefaultFieldName returns a default symbol field name for field aFieldNdx for all componen...
int Parse(const UTF8 &aId)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:122
SCH_LAYER_ID GetLayer() const
Function GetLayer returns the layer this item is on.
#define MAX_UNIT_COUNT_PER_PACKAGE
The maximum number of units per package.
Definition: eeschema_id.h:48
static const wxChar Custom[]
"User" defined page type
wxPoint m_End() const
void DeleteSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const PROPERTIES *aProperties=NULL) override
Delete the entire LIB_PART associated with aAliasName from the library aLibraryPath.
void Save(const wxString &aFileName, SCH_SCREEN *aScreen, KIWAY *aKiway, const PROPERTIES *aProperties=NULL) override
Write aSchematic to a storage file in a format that this SCH_PLUGIN implementation knows about...
#define SCH_LAYER_ID_COUNT
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
void saveNoConnect(SCH_NO_CONNECT *aNoConnect)
const char * SheetLabelType[]
Definition: sch_text.cpp:57
void NORMALIZE_ANGLE_POS(T &Angle)
Definition: trigo.h:241
wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_bitmap.h:133
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
size_t GetAliasCount() const
Class PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
void loadHeader(FILE_LINE_READER &aReader)
static dpoint_t bezier(double t, dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3)
Definition: trace.cpp:259
SCH_SCREEN * GetScreen()
Definition: sch_sheet.h:279
Class TITLE_BLOCK holds the information shown in the lower right corner of a plot, printout, or editing view.
const wxChar traceSchLegacyPlugin[]
Flag to enable legacy schematic plugin debug output.
void SetDocFileName(const wxString &aDocFileName)
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:190
#define T_WIDTH
SCH_ITEM * Next() const
#define TEXT_ANGLE_VERT
Definition: common.h:91
Field Reference of part, i.e. "IC21".
void saveSheet(SCH_SHEET *aSheet)
LIB_ARC * loadArc(std::unique_ptr< LIB_PART > &aPart, FILE_LINE_READER &aReader)
bool IsBold() const
Definition: eda_text.h:173
double GetTextAngle() const
Definition: eda_text.h:164
void SetComment4(const wxString &aComment)
void loadAliases(std::unique_ptr< LIB_PART > &aPart, FILE_LINE_READER &aReader)
void loadPageSettings(FILE_LINE_READER &aReader, SCH_SCREEN *aScreen)
int GetThickness() const
Function GetThickness returns pen width.
Definition: eda_text.h:154
Class SCH_LEGACY_PLUGIN_CACHE is a cache assistant for the part library portion of the SCH_PLUGIN API...
std::map< wxString, LIB_ALIAS *, AliasMapSort > LIB_ALIAS_MAP
Alias map used by part library object.
void saveField(SCH_FIELD *aField)
#define T_STYLE
wxPoint GetStartPoint() const
Definition: sch_line.h:76
Base class for a bus or wire entry.
Definition: sch_bus_entry.h:41
void saveJunction(SCH_JUNCTION *aJunction)
#define LIB_VERSION_MAJOR
Definition: class_library.h:55
void CreateSymbolLib(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Create a new empty symbol library at aLibraryPath.
int m_version
Version of file being loaded.
void loadFile(const wxString &aFileName, SCH_SCREEN *aScreen)
#define SCHEMATIC_HEAD_STRING
Definition: general.h:41
static double parseDouble(FILE_LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Function parseDouble.
wxString m_path
Root project path for loading child sheets.
#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
int GetConvert() const
int y1
Definition: transform.h:49
int GetSheetNameSize() const
Definition: sch_sheet.h:271
const wxString & GetTitle() const
std::string EscapedUTF8(const wxString &aString)
Function EscapedUTF8 returns an 8 bit UTF8 string given aString in unicode form.
Definition: string.cpp:137
COLOR4D GetDefaultColor() const
Definition: sch_line.cpp:204
#define EESCHEMA_VERSION
Definition: general.h:40
SCH_SHEET * loadSheet(FILE_LINE_READER &aReader)
bool IsPortrait() const
Class FILE_LINE_READER is a LINE_READER that reads from an open file.
Definition: richio.h:180
Class for tranforming drawing coordinates for a wxDC device context.
Definition: transform.h:45
#define DOCFILE_IDENT
bool isBuffering(const PROPERTIES *aProperties)
SCH_FIELD * GetField(int aFieldNdx) const
Returns a field in this symbol.
BITMAP_BASE * GetImage()
Definition: sch_bitmap.h:65
void DeleteAlias(const wxString &aAliasName)
void loadHierarchy(SCH_SHEET *aSheet)
void SetText(const wxString &aText) override
Sets the field text to aText.
Definition: lib_field.cpp:675
wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_junction.h:88
void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:227
int GetId() const
Definition: lib_field.h:136
static void parseUnquotedString(wxString &aString, FILE_LINE_READER &aReader, const char *aCurrentToken, const char **aNextToken=NULL, bool aCanBeEmpty=false)
Function parseUnquotedString.
Definitions for the Eeschema program SCH_SCREEN class.
const wxString & GetName() const
const wxString & GetRevision() const
Class PAGE_INFO describes the page size and margins of a paper page on which to eventually print or p...
char * Line() const
Function Line returns a pointer to the last line that was read in.
Definition: richio.h:139
Class LIB_ITEM definition.
const wxString & GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:130
LIB_TEXT * loadText(std::unique_ptr< LIB_PART > &aPart, FILE_LINE_READER &aReader)
VTBL_ENTRY PROJECT & Prj() const
Function Prj returns the PROJECT associated with this KIWAY.
Definition: kiway.cpp:144
SCH_TEXT * loadText(FILE_LINE_READER &aReader)
const wxArrayString & GetPathsAndReferences() const
bool DeleteSymbolLib(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Delete an existing symbol library and returns true if successful, or if library does not exist return...
static bool is_eol(char c)
LIB_POLYLINE * loadPolyLine(std::unique_ptr< LIB_PART > &aPart, FILE_LINE_READER &aReader)
std::string toUTFTildaText(const wxString &txt)
Function toUTFTildaText convert a wxString to UTF8 and replace any control characters with a ~...
void Empty()
Definition: eda_text.h:231
Class LIB_PART defines a library part object.
void SetCompany(const wxString &aCompany)
#define DOC_EXT
Definition: class_library.h:50
static unsigned long parseHex(FILE_LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Function parseHex.
Class KIWAY is a minimalistic software bus for communications between various DLLs/DSOs (DSOs) within...
Definition: kiway.h:257
void init(KIWAY *aKiway, const PROPERTIES *aProperties=NULL)
initialize PLUGIN like a constructor would.
int GetFileNameSize() const
Definition: sch_sheet.h:275
#define T_COLOR
void saveBitmap(SCH_BITMAP *aBitmap)
const wxString & GetComment3() const
bool SetType(const wxString &aStandardPageDescriptionName, bool IsPortrait=false)
Function SetType sets the name of the page type and also the sizes and margins commonly associated wi...
SCH_LAYER_ID
Eeschema drawing layers.
static const char * PropNoDocFile
const char* PropBuffering
SCH_JUNCTION * loadJunction(FILE_LINE_READER &aReader)
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet.h:61
#define USE_OLD_DOC_FILE_FORMAT(major, minor)
Definition: class_library.h:75
void loadField(std::unique_ptr< LIB_PART > &aPart, FILE_LINE_READER &aReader)
wxString GetFileName() const
int GetUnit() const
void SetModified(bool aModified=true)
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_sheet.h:540
void SetTitle(const wxString &aTitle)
FILL_T parseFillMode(FILE_LINE_READER &aReader, const char *aLine, const char **aOutput)
void loadDrawEntries(std::unique_ptr< LIB_PART > &aPart, FILE_LINE_READER &aReader)
int GetWidthMils() const
LIB_ALIAS * removeAlias(LIB_ALIAS *aAlias)
static int GetLineStyleInternalId(const wxString &aStyleName)
Definition: sch_line.cpp:131
void SetPortrait(bool isPortrait)
Function SetPortrait will rotate the paper page 90 degrees.
int GetLineStyle() const
Definition: sch_line.cpp:260
wxString GetFileName(void) const
Return the filename corresponding to this sheet.
Definition: sch_sheet.cpp:645
void SetDescription(const wxString &aDescription)
double GetScale() const
Object to handle a bitmap image that can be inserted in a schematic.
Definition: sch_bitmap.h:42
void SetHeightMils(int aHeightInMils)
void saveComponent(SCH_COMPONENT *aComponent)
const TITLE_BLOCK & GetTitleBlock() const
int SetLibItemName(const UTF8 &aLibItemName, bool aTestForRev=true)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition: lib_id.cpp:232
const wxString & GetComment2() const
const char * delims
time_t GetTimeStamp() const
Definition: base_struct.h:218
bool CheckHeader(const wxString &aFileName) override
Function CheckHeader returns true if the first line in aFileName begins with the expected header...
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:209
virtual wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_text.h:192
LIB_PART * GetPart() const
Function GetPart gets the shared LIB_PART.
void SetFileName(const wxString &aFileName)
bool checkForDuplicates(wxString &aAliasName)
EDA_TEXT_VJUSTIFY_T GetVertJustify() const
Definition: eda_text.h:191
int GetDefaultWidth() const
Definition: sch_line.cpp:269
SCH_ITEM * GetDrawItems() const
Definition the SCH_COMPONENT class for Eeschema.
bool IsCustom() const
Function IsCustom returns true if the type is Custom.
int GetPenSizeForBold(int aTextSize)
Function GetPensizeForBold.
Definition: drawtxt.cpp:49
void SetComment2(const wxString &aComment)
const wxString & GetComment1() const
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
int GetLineSize() const
Definition: sch_line.h:110
#define SCH_PARSE_ERROR(text, reader, pos)
void RemoveAlias(const wxString &aName)
const wxString & GetName() const
Segment description base class to describe items which have 2 end points (track, wire, draw line ...)
Definition: sch_line.h:41
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
static void parseQuotedString(wxString &aString, FILE_LINE_READER &aReader, const char *aCurrentToken, const char **aNextToken=NULL, bool aCanBeEmpty=false)
Function parseQuotedString.
int GetFieldCount() const
Return the number of fields in this symbol.
static const char * GetLineStyleName(int aStyle)
Definition: sch_line.cpp:103
void Append(SCH_ITEM *aItem)
void loadHeader(FILE_LINE_READER &aReader, SCH_SCREEN *aScreen)
bool IsVisible() const
Definition: eda_text.h:176
void SetKeyWords(const wxString &aKeyWords)
void EnumerateSymbolLib(wxArrayString &aAliasNameList, const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Populate a list of LIB_PART alias names contained within the library aLibraryPath.
wxArrayString GetAliasNames(bool aIncludeRoot=true) const
LIB_RECTANGLE * loadRectangle(std::unique_ptr< LIB_PART > &aPart, FILE_LINE_READER &aReader)
void SetWidthMils(int aWidthInMils)
SCH_BUS_ENTRY_BASE * loadBusEntry(FILE_LINE_READER &aReader)
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:69
wxPoint GetPosition() const override
Function GetPosition.
const LIB_ID & GetLibId() const
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:165
static const char * PropBuffering
const char* PropBuffering
void cacheLib(const wxString &aLibraryFileName)
LIB_PART * loadPart(FILE_LINE_READER &aReader)
static bool strCompare(const char *aString, const char *aLine, const char **aOutput=NULL)
Function strCompare.
UTF8 Format() const
Definition: lib_id.cpp:263
const char * name
Class FILE_OUTPUTFORMATTER may be used for text file output.
Definition: richio.h:492
SCH_COMPONENT * loadComponent(FILE_LINE_READER &aReader)
void DeleteAlias(const wxString &aLibraryPath, const wxString &aAliasName, const PROPERTIES *aProperties=NULL) override
Delete aAliasName from the library at aLibraryPath.
int GetModifyHash() const override
Return the modification hash from the library cache.
FILL_T
Enum FILL_T is the set of fill types used in plotting or drawing enclosed areas.
Definition: base_struct.h:70
int GetDefaultStyle() const
Definition: sch_line.cpp:242
Class for a wire to bus entry.
This file is part of the common libary.
const PAGE_INFO & GetPageSettings() const
SCH_LINE * loadWire(FILE_LINE_READER &aReader)
wxString GetLogicalName() const
int GetPenSize() const override
Function GetPenSize virtual pure.
Definition: sch_line.cpp:287
LIB_ALIAS * LoadSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const PROPERTIES *aProperties=NULL) override
Load a LIB_ALIAS object having aAliasName from the aLibraryPath containing a library format that this...
void SetComment3(const wxString &aComment)
const wxString & GetType() const
SCH_NO_CONNECT * loadNoConnect(FILE_LINE_READER &aReader)
void SetFileName(const wxString &aFileName)
KIWAY * m_kiway
Required for path to legacy component libraries.
Definition for part library class.
void SetId(int aId)
Definition: sch_field.h:89
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Function Print formats and writes text to the output stream.
Definition: richio.cpp:404
#define T_COLORA
wxString GetName() const
Definition: sch_sheet.h:267
#define VALUE
bool IsSymbolLibWritable(const wxString &aLibraryPath) override
Return true if the library at aLibraryPath is writable.
Class PART_LIB is used to load, save, search, and otherwise manipulate part library files...
bool IsFile(const wxString &aFullPathAndFileName) const
void Save(bool aSaveDocFile=true)
Save the entire library to file m_libFileName;.
Class SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container clas...
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
Implementation of the label properties dialog.
void saveBusEntry(SCH_BUS_ENTRY_BASE *aBusEntry)
void DeleteSymbol(const wxString &aAliasName)
static const char * PropPowerSymsOnly
wxSize GetSize()
Definition: sch_sheet.h:281
int GetHeightMils() const
void AddSymbol(const LIB_PART *aPart)
bool writeDocFile(const PROPERTIES *aProperties)
SCH_SHEET * Load(const wxString &aFileName, KIWAY *aKiway, SCH_SHEET *aAppendToMe=NULL, const PROPERTIES *aProperties=NULL) override
Load information from some input file format that this SCH_PLUGIN implementation knows about...
const PROPERTIES * m_props
Passed via Save() or Load(), no ownership, may be NULL.
Class LIB_BEZIER defines bezier curve graphic body item.
Definition: lib_bezier.h:39
void loadFootprintFilters(std::unique_ptr< LIB_PART > &aPart, FILE_LINE_READER &aReader)
wxPoint GetPosition() const override
Function GetPosition.