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