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