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