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