KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_io_kicad_legacy_lib_cache.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <magic_enum.hpp>
21#include <wx/log.h>
22#include <wx/tokenzr.h>
23
24#include <common.h>
25#include <kiplatform/io.h>
26#include <lib_symbol.h>
27#include <sch_shape.h>
28#include <sch_pin.h>
29#include <sch_text.h>
30#include <macros.h>
31#include <richio.h>
32#include <string_utils.h>
33#include <template_fieldnames.h>
34#include <trace_helpers.h>
36
39
40
41#define LIB_VERSION_MAJOR 2
42#define LIB_VERSION_MINOR 4
43
44#define LIB_VERSION( major, minor ) ( major * 100 + minor )
45
47#define LIBFILE_IDENT "EESchema-LIBRARY Version"
48
50#define DOCFILE_IDENT "EESchema-DOCLIB Version 2.0"
51
58#define USE_OLD_DOC_FILE_FORMAT( major, minor ) \
59 ( LIB_VERSION( major, minor ) <= LIB_VERSION( 2, 4 ) )
60
61
62const int fill_tab[3] = { 'N', 'F', 'f' };
63
64
65SCH_IO_KICAD_LEGACY_LIB_CACHE::SCH_IO_KICAD_LEGACY_LIB_CACHE( const wxString& aFullPathAndFileName ) :
66 SCH_IO_LIB_CACHE( aFullPathAndFileName )
67{
68 m_versionMajor = -1;
69 m_versionMinor = -1;
70}
71
72
74{
75 if( !m_libFileName.FileExists() )
76 {
77 THROW_IO_ERROR( wxString::Format( _( "Library file '%s' not found." ),
78 m_libFileName.GetFullPath() ) );
79 }
80
81 wxCHECK_RET( m_libFileName.IsAbsolute(),
82 wxString::Format( "Cannot use relative file paths in legacy plugin to "
83 "open library '%s'.", m_libFileName.GetFullPath() ) );
84
85 wxLogTrace( traceSchLegacyPlugin, "Loading legacy symbol file '%s'",
86 m_libFileName.GetFullPath() );
87
88 FILE_LINE_READER reader( m_libFileName.GetFullPath() );
89
90 if( !reader.ReadLine() )
91 THROW_IO_ERROR( _( "Unexpected end of file." ) );
92
93 const char* line = reader.Line();
94
95 if( !strCompare( "EESchema-LIBRARY Version", line, &line ) )
96 {
97 // Old .sym files (which are libraries with only one symbol, used to store and reuse shapes)
98 // EESchema-LIB Version x.x SYMBOL. They are valid files.
99 if( !strCompare( "EESchema-LIB Version", line, &line ) )
100 SCH_PARSE_ERROR( "file is not a valid symbol or symbol library file", reader, line );
101 }
102
103 m_versionMajor = parseInt( reader, line, &line );
104
105 if( *line == '/' )
106 {
107 // Some old libraries use a version syntax like
108 // EESchema-LIBRARY Version 2/10/2006-18:49:15
109 // use 2.3 version numer to read the file
110 m_versionMajor = 2;
111 m_versionMinor = 3;
112 }
113 else
114 {
115 if( *line != '.' )
116 SCH_PARSE_ERROR( "invalid file version formatting in header", reader, line );
117
118 line++;
119
120 m_versionMinor = parseInt( reader, line, &line );
121 }
122
124 SCH_PARSE_ERROR( "invalid file version in header", reader, line );
125
126 // Check if this is a symbol library which is the same as a symbol library but without
127 // any alias, documentation, footprint filters, etc.
128 if( strCompare( "SYMBOL", line, &line ) )
129 {
130 // Symbol files add date and time stamp info to the header.
132
134 }
135 else
136 {
138 }
139
140 while( reader.ReadLine() )
141 {
142 line = reader.Line();
143
144 if( *line == '#' || isspace( *line ) ) // Skip comments and blank lines.
145 continue;
146
147 // Headers where only supported in older library file formats.
148 if( m_libType == SCH_LIB_TYPE::LT_EESCHEMA && strCompare( "$HEADER", line ) )
149 loadHeader( reader );
150
151 if( strCompare( "DEF", line ) )
152 {
153 // Read one DEF/ENDDEF symbol entry from library:
155
156 m_symbols[ symbol->GetName() ] = symbol;
157 }
158 }
159
161
162 // Remember the file modification time of library file when the
163 // cache snapshot was made, so that in a networked environment we will
164 // reload the cache as needed.
166
168 loadDocs();
169}
170
171
173{
174 const char* line;
175 wxString text;
176 wxString aliasName;
177 wxFileName fn = m_libFileName;
178 LIB_SYMBOL* symbol = nullptr;;
179
181
182 // Not all libraries will have a document file.
183 if( !fn.FileExists() )
184 return;
185
186 if( !fn.IsFileReadable() )
187 {
188 THROW_IO_ERROR( wxString::Format( _( "Insufficient permissions to read library '%s'." ),
189 fn.GetFullPath() ) );
190 }
191
192 FILE_LINE_READER reader( fn.GetFullPath() );
193
194 line = reader.ReadLine();
195
196 if( !line )
197 THROW_IO_ERROR( _( "symbol document library file is empty" ) );
198
199 if( !strCompare( DOCFILE_IDENT, line, &line ) )
200 SCH_PARSE_ERROR( "invalid document library file version formatting in header", reader, line );
201
202 while( reader.ReadLine() )
203 {
204 line = reader.Line();
205
206 if( *line == '#' ) // Comment line.
207 continue;
208
209 if( !strCompare( "$CMP", line, &line ) != 0 )
210 SCH_PARSE_ERROR( "$CMP command expected", reader, line );
211
212 aliasName = wxString::FromUTF8( line );
213 aliasName.Trim();
214
215 LIB_SYMBOL_MAP::iterator it = m_symbols.find( aliasName );
216
217 if( it == m_symbols.end() )
218 {
219 wxLogWarning( "Symbol '%s' not found in library:\n\n"
220 "'%s'\n\nat line %d offset %d",
221 aliasName,
222 fn.GetFullPath(),
223 reader.LineNumber(),
224 (int) (line - reader.Line() ) );
225 }
226 else
227 {
228 symbol = it->second;
229 }
230
231 // Read the current alias associated doc.
232 // if the alias does not exist, just skip the description
233 // (Can happen if a .dcm is not synchronized with the corresponding .lib file)
234 while( reader.ReadLine() )
235 {
236 line = reader.Line();
237
238 if( !line )
239 SCH_PARSE_ERROR( "unexpected end of file", reader, line );
240
241 if( strCompare( "$ENDCMP", line, &line ) )
242 break;
243
244 text = From_UTF8( line + 2 );
245 // Remove spaces at eol, and eol chars:
246 text = text.Trim();
247
248 switch( line[0] )
249 {
250 case 'D':
251 if( symbol )
252 symbol->SetDescription( text );
253 break;
254
255 case 'K':
256 if( symbol )
257 symbol->SetKeyWords( text );
258 break;
259
260 case 'F':
261 if( symbol )
263 break;
264
265 case 0:
266 case '\n':
267 case '\r':
268 case '#':
269 // Empty line or commment
270 break;
271
272 default:
273 SCH_PARSE_ERROR( "expected token in symbol definition", reader, line );
274 }
275 }
276 }
277}
278
279
281{
282 const char* line = aReader.Line();
283
284 wxASSERT( strCompare( "$HEADER", line, &line ) );
285
286 while( aReader.ReadLine() )
287 {
288 line = (char*) aReader;
289
290 // The time stamp saved in old library files is not used or saved in the latest
291 // library file version.
292 if( strCompare( "TimeStamp", line, &line ) )
293 continue;
294 else if( strCompare( "$ENDHEADER", line, &line ) )
295 return;
296 }
297
298 SCH_PARSE_ERROR( "$ENDHEADER not found", aReader, line );
299}
300
301
303 int aMinorVersion, LIB_SYMBOL_MAP* aMap )
304{
305 const char* line = aReader.Line();
306
307 while( *line == '#' )
308 aReader.ReadLine();
309
310 if( !strCompare( "DEF", line, &line ) )
311 SCH_PARSE_ERROR( "invalid symbol definition", aReader, line );
312
313 long num;
314 size_t pos = 4; // "DEF" plus the first space.
315 wxString utf8Line = wxString::FromUTF8( line );
316 wxStringTokenizer tokens( utf8Line, " \t\r\n" );
317
318 if( tokens.CountTokens() < 8 )
319 SCH_PARSE_ERROR( "invalid symbol definition", aReader, line );
320
321 // Read DEF line:
322 std::unique_ptr<LIB_SYMBOL> symbol = std::make_unique<LIB_SYMBOL>( wxEmptyString );
323
324 wxString name, prefix, tmp;
325
326 name = tokens.GetNextToken();
327
328 // This fixes a dubious decision to escape LIB_ID characters. Escaped LIB_IDs broke rescue
329 // library look up. Legacy LIB_IDs should not be escaped.
330 if( name != UnescapeString( name ) )
332
333 pos += name.size() + 1;
334
335 prefix = tokens.GetNextToken();
336 pos += prefix.size() + 1;
337
338 tmp = tokens.GetNextToken();
339 pos += tmp.size() + 1; // NumOfPins, unused.
340
341 tmp = tokens.GetNextToken(); // Pin name offset.
342
343 if( !tmp.ToLong( &num ) )
344 {
345 THROW_PARSE_ERROR( "invalid pin offset", aReader.GetSource(), aReader.Line(),
346 aReader.LineNumber(), pos );
347 }
348
349 pos += tmp.size() + 1;
350 symbol->SetPinNameOffset( schIUScale.MilsToIU( (int)num ) );
351
352 tmp = tokens.GetNextToken(); // Show pin numbers.
353
354 if( !( tmp == "Y" || tmp == "N") )
355 {
356 THROW_PARSE_ERROR( "expected Y or N", aReader.GetSource(), aReader.Line(),
357 aReader.LineNumber(), pos );
358 }
359
360 pos += tmp.size() + 1;
361 symbol->SetShowPinNumbers( ( tmp == "N" ) ? false : true );
362
363 tmp = tokens.GetNextToken(); // Show pin names.
364
365 if( !( tmp == "Y" || tmp == "N") )
366 {
367 THROW_PARSE_ERROR( "expected Y or N", aReader.GetSource(), aReader.Line(),
368 aReader.LineNumber(), pos );
369 }
370
371 pos += tmp.size() + 1;
372 symbol->SetShowPinNames( ( tmp == "N" ) ? false : true );
373
374 tmp = tokens.GetNextToken(); // Number of units.
375
376 if( !tmp.ToLong( &num ) )
377 THROW_PARSE_ERROR( "invalid unit count", aReader.GetSource(), aReader.Line(), aReader.LineNumber(), pos );
378
379 pos += tmp.size() + 1;
380 symbol->SetUnitCount( (int)num, true );
381
382 // Ensure m_unitCount is >= 1. Could be read as 0 in old libraries.
383 if( symbol->GetUnitCount() < 1 )
384 symbol->SetUnitCount( 1, true );
385
386 // Copy symbol name and prefix.
387
388 // The root alias is added to the alias list by SetName() which is called by SetText().
389 if( name.IsEmpty() )
390 {
391 symbol->SetName( "~" );
392 }
393 else if( name[0] != '~' )
394 {
395 symbol->SetName( name );
396 }
397 else
398 {
399 symbol->SetName( name.Right( name.Length() - 1 ) );
400 symbol->GetValueField().SetVisible( false );
401 }
402
403 // Don't set the library alias, this is determined by the symbol library table.
404 symbol->SetLibId( LIB_ID( wxEmptyString, symbol->GetName() ) );
405
406 SCH_FIELD& reference = symbol->GetReferenceField();
407
408 if( prefix == "~" )
409 {
410 reference.Empty();
411 reference.SetVisible( false );
412 }
413 else
414 {
415 reference.SetText( prefix );
416 }
417
418 // In version 2.2 and earlier, this parameter was a '0' which was just a place holder.
419 // The was no concept of interchangeable multiple unit symbols.
420 if( LIB_VERSION( aMajorVersion, aMinorVersion ) > 0
421 && LIB_VERSION( aMajorVersion, aMinorVersion ) <= LIB_VERSION( 2, 2 ) )
422 {
423 // Nothing needs to be set since the default setting for symbols with multiple
424 // units were never interchangeable. Just parse the 0 an move on.
425 tmp = tokens.GetNextToken();
426 pos += tmp.size() + 1;
427 }
428 else
429 {
430 tmp = tokens.GetNextToken();
431
432 if( tmp == "L" )
433 symbol->LockUnits( true );
434 else if( tmp == "F" || tmp == "0" )
435 symbol->LockUnits( false );
436 else
437 THROW_PARSE_ERROR( "expected L, F, or 0", aReader.GetSource(), aReader.Line(),
438 aReader.LineNumber(), pos );
439
440 pos += tmp.size() + 1;
441 }
442
443 // There is the optional power symbol flag.
444 if( tokens.HasMoreTokens() )
445 {
446 tmp = tokens.GetNextToken();
447
448 if( tmp == "P" )
449 symbol->SetGlobalPower();
450 else if( tmp == "N" )
451 symbol->SetNormal();
452 else
453 THROW_PARSE_ERROR( "expected P or N", aReader.GetSource(), aReader.Line(),
454 aReader.LineNumber(), pos );
455 }
456
457 line = aReader.ReadLine();
458
459 // Read lines until "ENDDEF" is found.
460 while( line )
461 {
462 if( *line == '#' ) // Comment
463 ;
464 else if( strCompare( "Ti", line, &line ) ) // Modification date is ignored.
465 continue;
466 else if( strCompare( "ALIAS", line, &line ) ) // Aliases
467 loadAliases( symbol, aReader, aMap );
468 else if( *line == 'F' ) // Fields
469 loadField( symbol, aReader );
470 else if( strCompare( "DRAW", line, &line ) ) // Drawing objects.
471 loadDrawEntries( symbol, aReader, aMajorVersion, aMinorVersion );
472 else if( strCompare( "$FPLIST", line, &line ) ) // Footprint filter list
473 loadFootprintFilters( symbol, aReader );
474 else if( strCompare( "ENDDEF", line, &line ) ) // End of symbol description
475 {
476 symbol->SetHasDeMorganBodyStyles( symbol->HasLegacyAlternateBodyStyle() );
477 return symbol.release();
478 }
479
480 line = aReader.ReadLine();
481 }
482
483 SCH_PARSE_ERROR( "missing ENDDEF", aReader, line );
484}
485
486
487void SCH_IO_KICAD_LEGACY_LIB_CACHE::loadAliases( std::unique_ptr<LIB_SYMBOL>& aSymbol,
488 LINE_READER& aReader,
489 LIB_SYMBOL_MAP* aMap )
490{
491 wxString newAliasName;
492 const char* line = aReader.Line();
493
494 wxCHECK_RET( strCompare( "ALIAS", line, &line ), "Invalid ALIAS section" );
495
496 wxString utf8Line = wxString::FromUTF8( line );
497 wxStringTokenizer tokens( utf8Line, " \t\r\n" );
498
499 // Parse the ALIAS list.
500 while( tokens.HasMoreTokens() )
501 {
502 newAliasName = tokens.GetNextToken();
503
504 if( aMap )
505 {
506 LIB_SYMBOL* newSymbol = new LIB_SYMBOL( newAliasName );
507
508 // Inherit the parent mandatory field attributes.
509 for( FIELD_T fieldId : MANDATORY_FIELDS )
510 {
511 SCH_FIELD* field = newSymbol->GetField( fieldId );
512 SCH_FIELD* parentField = aSymbol->GetField( fieldId );
513
514 *field = *parentField;
515
516 if( fieldId == FIELD_T::VALUE )
517 field->SetText( newAliasName );
518
519 field->SetParent( newSymbol );
520 }
521
522 newSymbol->SetParent( aSymbol.get() );
523 newSymbol->SetHasDeMorganBodyStyles( newSymbol->HasLegacyAlternateBodyStyle() );
524
525 // This will prevent duplicate aliases.
526 (*aMap)[ newSymbol->GetName() ] = newSymbol;
527 }
528 }
529}
530
531
532void SCH_IO_KICAD_LEGACY_LIB_CACHE::loadField( std::unique_ptr<LIB_SYMBOL>& aSymbol,
533 LINE_READER& aReader )
534{
535 const char* line = aReader.Line();
536
537 wxCHECK_RET( *line == 'F', "Invalid field line" );
538
539 wxString text;
540 int legacy_field_id;
541
542 if( sscanf( line + 1, "%d", &legacy_field_id ) != 1 || legacy_field_id < 0 )
543 SCH_PARSE_ERROR( "invalid field ID", aReader, line + 1 );
544
546 SCH_FIELD* field;
547
548 // Map fixed legacy IDs
549 switch( legacy_field_id )
550 {
551 case 0: id = FIELD_T::REFERENCE; break;
552 case 1: id = FIELD_T::VALUE; break;
553 case 2: id = FIELD_T::FOOTPRINT; break;
554 case 3: id = FIELD_T::DATASHEET; break;
555 }
556
557 if( id != FIELD_T::USER )
558 {
559 field = aSymbol->GetField( id );
560 }
561 else
562 {
563 field = new SCH_FIELD( aSymbol.get(), id );
564 aSymbol->AddDrawItem( field, false );
565 }
566
567 // Skip to the first double quote.
568 while( *line != '"' && *line != 0 )
569 line++;
570
571 if( *line == 0 )
572 SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, line );
573
574 parseQuotedString( text, aReader, line, &line, true );
575
576 // The value field needs to be "special" escaped. The other fields are
577 // escaped normally and don't need special handling
578 if( id == FIELD_T::VALUE )
580
581 // Doctor the *.lib file field which has a "~" in blank fields. New saves will
582 // not save like this.
583 if( text.size() == 1 && text[0] == '~' )
584 field->SetText( wxEmptyString );
585 else
587
588 VECTOR2I pos;
589
590 pos.x = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
591 pos.y = -schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
592 field->SetPosition( pos );
593
594 VECTOR2I textSize;
595
596 textSize.x = textSize.y = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
597 field->SetTextSize( textSize );
598
599 char textOrient = parseChar( aReader, line, &line );
600
601 if( textOrient == 'H' )
603 else if( textOrient == 'V' )
605 else
606 SCH_PARSE_ERROR( "invalid field text orientation parameter", aReader, line );
607
608 char textVisible = parseChar( aReader, line, &line );
609
610 if( textVisible == 'V' )
611 field->SetVisible( true );
612 else if ( textVisible == 'I' )
613 field->SetVisible( false );
614 else
615 SCH_PARSE_ERROR( "invalid field text visibility parameter", aReader, line );
616
617 // It may be technically correct to use the library version to determine if the field text
618 // attributes are present. If anyone knows if that is valid and what version that would be,
619 // please change this to test the library version rather than an EOL or the quoted string
620 // of the field name.
621 if( *line != 0 && *line != '"' )
622 {
623 char textHJustify = parseChar( aReader, line, &line );
624
625 if( textHJustify == 'C' )
627 else if( textHJustify == 'L' )
629 else if( textHJustify == 'R' )
631 else
632 SCH_PARSE_ERROR( "invalid field text horizontal justification", aReader, line );
633
634 wxString attributes;
635
636 parseUnquotedString( attributes, aReader, line, &line );
637
638 size_t attrSize = attributes.size();
639
640 if( !(attrSize == 3 || attrSize == 1 ) )
641 SCH_PARSE_ERROR( "invalid field text attributes size", aReader, line );
642
643 switch( (wxChar) attributes[0] )
644 {
645 case 'C': field->SetVertJustify( GR_TEXT_V_ALIGN_CENTER ); break;
646 case 'B': field->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM ); break;
647 case 'T': field->SetVertJustify( GR_TEXT_V_ALIGN_TOP ); break;
648 default: SCH_PARSE_ERROR( "invalid field text vertical justification", aReader, line );
649 }
650
651 if( attrSize == 3 )
652 {
653 wxChar attr_1 = attributes[1];
654 wxChar attr_2 = attributes[2];
655
656 if( attr_1 == 'I' ) // Italic
657 field->SetItalicFlag( true );
658 else if( attr_1 != 'N' ) // No italics is default, check for error.
659 SCH_PARSE_ERROR( "invalid field text italic parameter", aReader, line );
660
661 if ( attr_2 == 'B' ) // Bold
662 field->SetBoldFlag( true );
663 else if( attr_2 != 'N' ) // No bold is default, check for error.
664 SCH_PARSE_ERROR( "invalid field text bold parameter", aReader, line );
665 }
666 }
667
668 // Fields in RAM must always have names.
669 if( field->IsMandatory() )
670 {
671 // Fields in RAM must always have names, because we are trying to get
672 // less dependent on field ids and more dependent on names.
673 // Plus assumptions are made in the field editors.
674 field->SetName( GetCanonicalFieldName( field->GetId() ) );
675
676 // Ensure the VALUE field = the symbol name (can be not the case
677 // with malformed libraries: edited by hand, or converted from other tools)
678 if( id == FIELD_T::VALUE )
679 field->SetText( aSymbol->GetName() );
680 }
681 else
682 {
683 wxString fieldName = wxEmptyString;
684 parseQuotedString( fieldName, aReader, line, &line, true ); // Optional.
685
686 if( fieldName.IsEmpty() )
687 return;
688
689 wxString candidateFieldName = fieldName;
690 int suffix = 0;
691
692 //Deduplicate field name
693 while( aSymbol->GetField( candidateFieldName ) != nullptr )
694 candidateFieldName = wxString::Format( "%s_%d", fieldName, ++suffix );
695
696 field->SetName( candidateFieldName );
697 }
698}
699
700
701void SCH_IO_KICAD_LEGACY_LIB_CACHE::loadDrawEntries( std::unique_ptr<LIB_SYMBOL>& aSymbol,
702 LINE_READER& aReader,
703 int aMajorVersion,
704 int aMinorVersion )
705{
706 const char* line = aReader.Line();
707
708 wxCHECK_RET( strCompare( "DRAW", line, &line ), "Invalid DRAW section" );
709
710 line = aReader.ReadLine();
711
712 while( line )
713 {
714 if( strCompare( "ENDDRAW", line, &line ) )
715 {
716 aSymbol->GetDrawItems().sort();
717 return;
718 }
719
720 switch( line[0] )
721 {
722 case 'A': // Arc
723 aSymbol->AddDrawItem( loadArc( aReader ), false );
724 break;
725
726 case 'C': // Circle
727 aSymbol->AddDrawItem( loadCircle( aReader ), false );
728 break;
729
730 case 'T': // Text
731 aSymbol->AddDrawItem( loadText( aReader, aMajorVersion, aMinorVersion ), false );
732 break;
733
734 case 'S': // Square
735 aSymbol->AddDrawItem( loadRect( aReader ), false );
736 break;
737
738 case 'X': // Pin Description
739 aSymbol->AddDrawItem( loadPin( aSymbol, aReader ), false );
740 break;
741
742 case 'P': // Polyline
743 aSymbol->AddDrawItem( loadPolyLine( aReader ), false );
744 break;
745
746 case 'B': // Bezier Curves
747 aSymbol->AddDrawItem( loadBezier( aReader ), false );
748 break;
749
750 case '#': // Comment
751 case '\n': // Empty line
752 case '\r':
753 case 0:
754 break;
755
756 default:
757 SCH_PARSE_ERROR( "undefined DRAW entry", aReader, line );
758 }
759
760 line = aReader.ReadLine();
761 }
762
763 SCH_PARSE_ERROR( "File ended prematurely loading symbol draw element.", aReader, line );
764}
765
766
768 const char** aOutput )
769{
770 switch ( parseChar( aReader, aLine, aOutput ) )
771 {
772 case 'F': return FILL_T::FILLED_SHAPE;
773 case 'f': return FILL_T::FILLED_WITH_BG_BODYCOLOR;
774 case 'N': return FILL_T::NO_FILL;
775 default: break;
776 }
777
778 SCH_PARSE_ERROR( "invalid fill type, expected f, F, or N", aReader, aLine );
779}
780
781
786static bool MapAnglesV6( int* aAngle1, int* aAngle2 )
787{
788 auto DECIDEG2RAD = []( double deg ) -> double
789 {
790 return deg * M_PI / 1800.0;
791 };
792
793 int angle, delta;
794 double x, y;
795 bool swap = false;
796
797 delta = *aAngle2 - *aAngle1;
798
799 if( delta >= 1800 )
800 {
801 *aAngle1 -= 1;
802 *aAngle2 += 1;
803 }
804
805 x = cos( DECIDEG2RAD( *aAngle1 ) );
806 y = -sin( DECIDEG2RAD( *aAngle1 ) );
807 *aAngle1 = KiROUND( RAD2DECIDEG( atan2( y, x ) ) );
808
809 x = cos( DECIDEG2RAD( *aAngle2 ) );
810 y = -sin( DECIDEG2RAD( *aAngle2 ) );
811 *aAngle2 = KiROUND( RAD2DECIDEG( atan2( y, x ) ) );
812
813 NORMALIZE_ANGLE_POS( *aAngle1 );
814 NORMALIZE_ANGLE_POS( *aAngle2 );
815
816 if( *aAngle2 < *aAngle1 )
817 *aAngle2 += 3600;
818
819 if( *aAngle2 - *aAngle1 > 1800 ) // Need to swap the two angles
820 {
821 angle = ( *aAngle1 );
822 *aAngle1 = ( *aAngle2 );
823 *aAngle2 = angle;
824
825 NORMALIZE_ANGLE_POS( *aAngle1 );
826 NORMALIZE_ANGLE_POS( *aAngle2 );
827
828 if( *aAngle2 < *aAngle1 )
829 *aAngle2 += 3600;
830
831 swap = true;
832 }
833
834 if( delta >= 1800 )
835 {
836 *aAngle1 += 1;
837 *aAngle2 -= 1;
838 }
839
840 return swap;
841}
842
843
845{
846 const char* line = aReader.Line();
847
848 wxCHECK_MSG( strCompare( "A", line, &line ), nullptr, "Invalid arc definition" );
849
851
853
854 center.x = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
855 center.y = -schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
856
857 arc->SetPosition( center );
858
859 int radius = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
860 int angle1 = parseInt( aReader, line, &line );
861 int angle2 = parseInt( aReader, line, &line );
862
863 NORMALIZE_ANGLE_POS( angle1 );
864 NORMALIZE_ANGLE_POS( angle2 );
865
866 arc->SetUnit( parseInt( aReader, line, &line ) );
867 arc->SetBodyStyle( parseInt( aReader, line, &line ) );
868
869 STROKE_PARAMS stroke( schIUScale.MilsToIU( parseInt( aReader, line, &line ) ),
871
872 arc->SetStroke( stroke );
873
874 // Old libraries (version <= 2.2) do not have always this FILL MODE param when fill mode
875 // is no fill (default mode).
876 if( *line != 0 )
877 arc->SetFillMode( parseFillMode( aReader, line, &line ) );
878
879 // Actual Coordinates of arc ends are read from file
880 if( *line != 0 )
881 {
882 VECTOR2I arcStart, arcEnd;
883
884 arcStart.x = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
885 arcStart.y = -schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
886 arcEnd.x = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
887 arcEnd.y = -schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
888
889 arc->SetStart( arcStart );
890 arc->SetEnd( arcEnd );
891 }
892 else
893 {
894 // Actual Coordinates of arc ends are not read from file
895 // (old library), calculate them
896 VECTOR2I arcStart( radius, 0 );
897 VECTOR2I arcEnd( radius, 0 );
898
900 arcStart += arc->GetCenter();
901 arc->SetStart( arcStart );
903 arcEnd += arc->GetCenter();
904 arc->SetEnd( arcEnd );
905 }
906
914 if( MapAnglesV6( &angle1, &angle2 ) )
915 {
916 VECTOR2I temp = arc->GetEnd();
917 arc->SetEnd( arc->GetStart() );
918 arc->SetStart( temp );
919 }
920
921 // Re-run SetArcGeometry so the internal representation matches what the s-expression
922 // loader produces. Without this, the arc center stored internally after a legacy load
923 // differs from the center recalculated by SetArcGeometry during s-expression load,
924 // causing false ERC "symbol mismatch" warnings after save and reopen.
925 arc->SetArcGeometry( arc->GetStart(), arc->GetArcMid(), arc->GetEnd() );
926
927 return arc;
928}
929
930
932{
933 const char* line = aReader.Line();
934
935 wxCHECK_MSG( strCompare( "C", line, &line ), nullptr, "Invalid circle definition" );
936
938
940
941 center.x = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
942 center.y = -schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
943
944 int radius = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
945
946 circle->SetStart( center );
947 circle->SetEnd( VECTOR2I( center.x + radius, center.y ) );
948 circle->SetUnit( parseInt( aReader, line, &line ) );
949 circle->SetBodyStyle( parseInt( aReader, line, &line ) );
950
951 STROKE_PARAMS stroke( schIUScale.MilsToIU( parseInt( aReader, line, &line ) ),
953
954 circle->SetStroke( stroke );
955
956 if( *line != 0 )
957 circle->SetFillMode( parseFillMode( aReader, line, &line ) );
958
959 return circle;
960}
961
962
964 int aMajorVersion, int aMinorVersion )
965{
966 const char* line = aReader.Line();
967
968 wxCHECK_MSG( strCompare( "T", line, &line ), nullptr, "Invalid SCH_TEXT definition" );
969
970 double angleInTenths;
972 VECTOR2I size;
973 wxString str;
974 bool visible;
975 int unit;
976 int bodyStyle;
977
978 angleInTenths = parseInt( aReader, line, &line );
979
980 center.x = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
981 center.y = -schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
982 size.x = size.y = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
983 visible = !parseInt( aReader, line, &line );
984 unit = parseInt( aReader, line, &line );
985 bodyStyle = parseInt( aReader, line, &line );
986
987 // If quoted string loading fails, load as not quoted string.
988 if( *line == '"' )
989 {
990 parseQuotedString( str, aReader, line, &line );
991
992 str = ConvertToNewOverbarNotation( str );
993 }
994 else
995 {
996 parseUnquotedString( str, aReader, line, &line );
997
998 // In old libs, "spaces" are replaced by '~' in unquoted strings:
999 str.Replace( "~", " " );
1000 }
1001
1002 if( !str.IsEmpty() )
1003 {
1004 // convert two apostrophes back to double quote
1005 str.Replace( "''", "\"" );
1006 }
1007
1008 SCH_ITEM* sch_item = nullptr;
1009 EDA_TEXT* eda_text = nullptr;
1010
1011 if( !visible )
1012 {
1013 SCH_FIELD* field = new SCH_FIELD( nullptr, FIELD_T::USER );
1014 sch_item = field;
1015 eda_text = field;
1016 }
1017 else
1018 {
1019 SCH_TEXT* sch_text = new SCH_TEXT( center, str, LAYER_DEVICE );
1020 sch_item = sch_text;
1021 eda_text = sch_text;
1022 }
1023
1024 eda_text->SetTextAngle( EDA_ANGLE( angleInTenths, TENTHS_OF_A_DEGREE_T ) );
1025 eda_text->SetTextSize( size );
1026 eda_text->SetTextPos( center );
1027 eda_text->SetVisible( visible );
1028 sch_item->SetUnit( unit );
1029 sch_item->SetBodyStyle( bodyStyle );
1030
1031 // Here things are murky and not well defined. At some point it appears the format
1032 // was changed to add text properties. However rather than add the token to the end of
1033 // the text definition, it was added after the string and no mention if the file
1034 // verion was bumped or not so this code make break on very old symbol libraries.
1035 //
1036 // Update: apparently even in the latest version this can be different so added a test
1037 // for end of line before checking for the text properties.
1038 if( LIB_VERSION( aMajorVersion, aMinorVersion ) > 0
1039 && LIB_VERSION( aMajorVersion, aMinorVersion ) > LIB_VERSION( 2, 0 )
1040 && !is_eol( *line ) )
1041 {
1042 if( strCompare( "Italic", line, &line ) )
1043 eda_text->SetItalicFlag( true );
1044 else if( !strCompare( "Normal", line, &line ) )
1045 SCH_PARSE_ERROR( "invalid eda_text stype, expected 'Normal' or 'Italic'", aReader, line );
1046
1047 if( parseInt( aReader, line, &line ) > 0 )
1048 eda_text->SetBoldFlag( true );
1049
1050 // Some old libaries version > 2.0 do not have these options for eda_text justification:
1051 if( !is_eol( *line ) )
1052 {
1053 switch( parseChar( aReader, line, &line ) )
1054 {
1055 case 'L': eda_text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); break;
1056 case 'C': eda_text->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER ); break;
1057 case 'R': eda_text->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT ); break;
1058 default: SCH_PARSE_ERROR( "invalid horizontal eda_text justication; expected L, C, or R",
1059 aReader, line );
1060 }
1061
1062 switch( parseChar( aReader, line, &line ) )
1063 {
1064 case 'T': eda_text->SetVertJustify( GR_TEXT_V_ALIGN_TOP ); break;
1065 case 'C': eda_text->SetVertJustify( GR_TEXT_V_ALIGN_CENTER ); break;
1066 case 'B': eda_text->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM ); break;
1067 default: SCH_PARSE_ERROR( "invalid vertical eda_text justication; expected T, C, or B",
1068 aReader, line );
1069 }
1070 }
1071 }
1072
1073 return sch_item;
1074}
1075
1076
1078{
1079 const char* line = aReader.Line();
1080
1081 wxCHECK_MSG( strCompare( "S", line, &line ), nullptr, "Invalid rectangle definition" );
1082
1084
1085 VECTOR2I pos;
1086
1087 pos.x = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
1088 pos.y = -schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
1089 rectangle->SetPosition( pos );
1090
1091 VECTOR2I end;
1092
1093 end.x = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
1094 end.y = -schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
1095 rectangle->SetEnd( end );
1096
1097 rectangle->SetUnit( parseInt( aReader, line, &line ) );
1098 rectangle->SetBodyStyle( parseInt( aReader, line, &line ) );
1099
1100 STROKE_PARAMS stroke( schIUScale.MilsToIU( parseInt( aReader, line, &line ) ),
1102
1103 rectangle->SetStroke( stroke );
1104
1105
1106 if( *line != 0 )
1107 rectangle->SetFillMode( parseFillMode( aReader, line, &line ) );
1108
1109 return rectangle;
1110}
1111
1112
1113SCH_PIN* SCH_IO_KICAD_LEGACY_LIB_CACHE::loadPin( std::unique_ptr<LIB_SYMBOL>& aSymbol,
1114 LINE_READER& aReader )
1115{
1116 const char* line = aReader.Line();
1117
1118 wxCHECK_MSG( strCompare( "X", line, &line ), nullptr, "Invalid SCH_PIN definition" );
1119
1120 wxString name;
1121 wxString number;
1122
1123 size_t pos = 2; // "X" plus ' ' space character.
1124 wxString tmp;
1125 wxString utf8Line = wxString::FromUTF8( line );
1126 wxStringTokenizer tokens( utf8Line, " \t\r\n" );
1127
1128 if( tokens.CountTokens() < 11 )
1129 SCH_PARSE_ERROR( "invalid pin definition", aReader, line );
1130
1131 tmp = tokens.GetNextToken();
1132 name = tmp;
1133 pos += tmp.size() + 1;
1134
1135 tmp = tokens.GetNextToken();
1136 number = tmp ;
1137 pos += tmp.size() + 1;
1138
1139 long num;
1140 VECTOR2I position;
1141
1142 tmp = tokens.GetNextToken();
1143
1144 if( !tmp.ToLong( &num ) )
1145 {
1146 THROW_PARSE_ERROR( "invalid pin X coordinate", aReader.GetSource(), aReader.Line(),
1147 aReader.LineNumber(), pos );
1148 }
1149
1150 pos += tmp.size() + 1;
1151 position.x = schIUScale.MilsToIU( (int) num );
1152
1153 tmp = tokens.GetNextToken();
1154
1155 if( !tmp.ToLong( &num ) )
1156 {
1157 THROW_PARSE_ERROR( "invalid pin Y coordinate", aReader.GetSource(), aReader.Line(),
1158 aReader.LineNumber(), pos );
1159 }
1160
1161 pos += tmp.size() + 1;
1162 position.y = -schIUScale.MilsToIU( (int) num );
1163
1164 tmp = tokens.GetNextToken();
1165
1166 if( !tmp.ToLong( &num ) )
1167 {
1168 THROW_PARSE_ERROR( "invalid pin length", aReader.GetSource(), aReader.Line(),
1169 aReader.LineNumber(), pos );
1170 }
1171
1172 pos += tmp.size() + 1;
1173 int length = schIUScale.MilsToIU( (int) num );
1174
1175
1176 tmp = tokens.GetNextToken();
1177
1178 if( tmp.size() > 1 )
1179 {
1180 THROW_PARSE_ERROR( "invalid pin orientation", aReader.GetSource(), aReader.Line(),
1181 aReader.LineNumber(), pos );
1182 }
1183
1184 pos += tmp.size() + 1;
1185
1186 PIN_ORIENTATION orientation;
1187
1188 switch( static_cast<char>( tmp[0] ) )
1189 {
1190 case 'U': orientation = PIN_ORIENTATION::PIN_UP; break;
1191 case 'D': orientation = PIN_ORIENTATION::PIN_DOWN; break;
1192 case 'L': orientation = PIN_ORIENTATION::PIN_LEFT; break;
1193 case 'R': /* fall-through */
1194 default: orientation = PIN_ORIENTATION::PIN_RIGHT; break;
1195 }
1196
1197 tmp = tokens.GetNextToken();
1198
1199 if( !tmp.ToLong( &num ) )
1200 {
1201 THROW_PARSE_ERROR( "invalid pin number text size", aReader.GetSource(), aReader.Line(),
1202 aReader.LineNumber(), pos );
1203 }
1204
1205 pos += tmp.size() + 1;
1206 int numberTextSize = schIUScale.MilsToIU( (int) num );
1207
1208 tmp = tokens.GetNextToken();
1209
1210 if( !tmp.ToLong( &num ) )
1211 {
1212 THROW_PARSE_ERROR( "invalid pin name text size", aReader.GetSource(), aReader.Line(),
1213 aReader.LineNumber(), pos );
1214 }
1215
1216 pos += tmp.size() + 1;
1217 int nameTextSize = schIUScale.MilsToIU( (int) num );
1218
1219 tmp = tokens.GetNextToken();
1220
1221 if( !tmp.ToLong( &num ) )
1222 {
1223 THROW_PARSE_ERROR( "invalid pin unit", aReader.GetSource(), aReader.Line(),
1224 aReader.LineNumber(), pos );
1225 }
1226
1227 pos += tmp.size() + 1;
1228 int unit = (int) num;
1229
1230 tmp = tokens.GetNextToken();
1231
1232 if( !tmp.ToLong( &num ) )
1233 {
1234 THROW_PARSE_ERROR( "invalid pin body style", aReader.GetSource(), aReader.Line(),
1235 aReader.LineNumber(), pos );
1236 }
1237
1238 pos += tmp.size() + 1;
1239 int bodyStyle = (int) num;
1240
1241 tmp = tokens.GetNextToken();
1242
1243 if( tmp.size() != 1 )
1244 {
1245 THROW_PARSE_ERROR( "invalid pin type", aReader.GetSource(), aReader.Line(),
1246 aReader.LineNumber(), pos );
1247 }
1248
1249 pos += tmp.size() + 1;
1250 char type = tmp[0];
1251 ELECTRICAL_PINTYPE pinType;
1252
1253 switch( type )
1254 {
1255 case 'I': pinType = ELECTRICAL_PINTYPE::PT_INPUT; break;
1256 case 'O': pinType = ELECTRICAL_PINTYPE::PT_OUTPUT; break;
1257 case 'B': pinType = ELECTRICAL_PINTYPE::PT_BIDI; break;
1258 case 'T': pinType = ELECTRICAL_PINTYPE::PT_TRISTATE; break;
1259 case 'P': pinType = ELECTRICAL_PINTYPE::PT_PASSIVE; break;
1260 case 'U': pinType = ELECTRICAL_PINTYPE::PT_UNSPECIFIED; break;
1261 case 'W': pinType = ELECTRICAL_PINTYPE::PT_POWER_IN; break;
1262 case 'w': pinType = ELECTRICAL_PINTYPE::PT_POWER_OUT; break;
1263 case 'C': pinType = ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR; break;
1264 case 'E': pinType = ELECTRICAL_PINTYPE::PT_OPENEMITTER; break;
1265 case 'N': pinType = ELECTRICAL_PINTYPE::PT_NC; break;
1266 default:
1267 THROW_PARSE_ERROR( "unknown pin type", aReader.GetSource(), aReader.Line(),
1268 aReader.LineNumber(), pos );
1269 }
1270
1271 SCH_PIN* pin = new SCH_PIN( aSymbol.get(),
1274 orientation,
1275 pinType,
1276 length,
1277 nameTextSize,
1278 numberTextSize,
1279 bodyStyle,
1280 position,
1281 unit );
1282
1283 // Optional
1284 if( tokens.HasMoreTokens() ) /* Special Symbol defined */
1285 {
1286 tmp = tokens.GetNextToken();
1287
1288 enum
1289 {
1290 INVERTED = 1 << 0,
1291 CLOCK = 1 << 1,
1292 LOWLEVEL_IN = 1 << 2,
1293 LOWLEVEL_OUT = 1 << 3,
1294 FALLING_EDGE = 1 << 4,
1295 NONLOGIC = 1 << 5
1296 };
1297
1298 int flags = 0;
1299
1300 for( int j = (int) tmp.size(); j > 0; )
1301 {
1302 switch( tmp[--j].GetValue() )
1303 {
1304 case '~': break;
1305 case 'N': pin->SetVisible( false ); break;
1306 case 'I': flags |= INVERTED; break;
1307 case 'C': flags |= CLOCK; break;
1308 case 'L': flags |= LOWLEVEL_IN; break;
1309 case 'V': flags |= LOWLEVEL_OUT; break;
1310 case 'F': flags |= FALLING_EDGE; break;
1311 case 'X': flags |= NONLOGIC; break;
1312 default: THROW_PARSE_ERROR( "invalid pin attribut", aReader.GetSource(),
1313 aReader.Line(), aReader.LineNumber(), pos );
1314 }
1315
1316 pos += 1;
1317 }
1318
1319 switch( flags )
1320 {
1321 case 0: pin->SetShape( GRAPHIC_PINSHAPE::LINE ); break;
1322 case INVERTED: pin->SetShape( GRAPHIC_PINSHAPE::INVERTED ); break;
1323 case CLOCK: pin->SetShape( GRAPHIC_PINSHAPE::CLOCK ); break;
1324 case INVERTED | CLOCK: pin->SetShape( GRAPHIC_PINSHAPE::INVERTED_CLOCK ); break;
1325 case LOWLEVEL_IN: pin->SetShape( GRAPHIC_PINSHAPE::INPUT_LOW ); break;
1326 case LOWLEVEL_IN | CLOCK: pin->SetShape( GRAPHIC_PINSHAPE::CLOCK_LOW ); break;
1327 case LOWLEVEL_OUT: pin->SetShape( GRAPHIC_PINSHAPE::OUTPUT_LOW ); break;
1328 case FALLING_EDGE: pin->SetShape( GRAPHIC_PINSHAPE::FALLING_EDGE_CLOCK ); break;
1329 case NONLOGIC: pin->SetShape( GRAPHIC_PINSHAPE::NONLOGIC ); break;
1330 default: SCH_PARSE_ERROR( "pin attributes do not define a valid pin shape", aReader, line );
1331 }
1332 }
1333
1334 return pin;
1335}
1336
1337
1339{
1340 const char* line = aReader.Line();
1341
1342 wxCHECK_MSG( strCompare( "P", line, &line ), nullptr, "Invalid poly definition" );
1343
1344 SCH_SHAPE* polyLine = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
1345
1346 int points = parseInt( aReader, line, &line );
1347 polyLine->SetUnit( parseInt( aReader, line, &line ) );
1348 polyLine->SetBodyStyle( parseInt( aReader, line, &line ) );
1349
1350 STROKE_PARAMS stroke( schIUScale.MilsToIU( parseInt( aReader, line, &line ) ), LINE_STYLE::SOLID );
1351
1352 polyLine->SetStroke( stroke );
1353
1354 VECTOR2I pt;
1355
1356 for( int i = 0; i < points; i++ )
1357 {
1358 pt.x = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
1359 pt.y = -schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
1360 polyLine->AddPoint( pt );
1361 }
1362
1363 if( *line != 0 )
1364 polyLine->SetFillMode( parseFillMode( aReader, line, &line ) );
1365
1366 return polyLine;
1367}
1368
1369
1371{
1372 const char* line = aReader.Line();
1373
1374 wxCHECK_MSG( strCompare( "B", line, &line ), nullptr, "Invalid Bezier definition" );
1375
1376 int points = parseInt( aReader, line, &line );
1377
1378 wxCHECK_MSG( points == 4, NULL, "Invalid Bezier curve definition" );
1379
1381
1382 bezier->SetUnit( parseInt( aReader, line, &line ) );
1383 bezier->SetBodyStyle( parseInt( aReader, line, &line ) );
1384
1385 STROKE_PARAMS stroke ( schIUScale.MilsToIU( parseInt( aReader, line, &line ) ), LINE_STYLE::SOLID );
1386
1387 bezier->SetStroke( stroke );
1388
1389 VECTOR2I pt;
1390
1391 pt.x = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
1392 pt.y = -schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
1393 bezier->SetStart( pt );
1394
1395 pt.x = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
1396 pt.y = -schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
1397 bezier->SetBezierC1( pt );
1398
1399 pt.x = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
1400 pt.y = -schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
1401 bezier->SetBezierC2( pt );
1402
1403 pt.x = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
1404 pt.y = -schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
1405 bezier->SetEnd( pt );
1406
1408
1409 if( *line != 0 )
1410 bezier->SetFillMode( parseFillMode( aReader, line, &line ) );
1411
1412 return bezier;
1413}
1414
1415
1416void SCH_IO_KICAD_LEGACY_LIB_CACHE::loadFootprintFilters( std::unique_ptr<LIB_SYMBOL>& aSymbol,
1417 LINE_READER& aReader )
1418{
1419 const char* line = aReader.Line();
1420
1421 wxCHECK_RET( strCompare( "$FPLIST", line, &line ), "Invalid footprint filter list" );
1422
1423 line = aReader.ReadLine();
1424
1425 wxArrayString footprintFilters;
1426
1427 while( line )
1428 {
1429 if( strCompare( "$ENDFPLIST", line, &line ) )
1430 {
1431 aSymbol->SetFPFilters( footprintFilters );
1432 return;
1433 }
1434
1435 wxString footprint;
1436
1437 parseUnquotedString( footprint, aReader, line, &line );
1438 footprintFilters.Add( footprint );
1439 line = aReader.ReadLine();
1440 }
1441
1442 SCH_PARSE_ERROR( "File ended prematurely while loading footprint filters.", aReader, line );
1443}
1444
1445
1446void SCH_IO_KICAD_LEGACY_LIB_CACHE::Save( const std::optional<bool>& aOpt )
1447{
1448 wxCHECK( aOpt, /* void */ );
1449
1450 bool doSaveDocFile = *aOpt;
1451
1452 if( !m_isModified )
1453 return;
1454
1455 // Write through symlinks, don't replace them
1456 wxFileName fn = GetRealFile();
1457
1458 auto formatter = std::make_unique<FILE_OUTPUTFORMATTER>( fn.GetFullPath() );
1459 formatter->Print( 0, "%s %d.%d\n", LIBFILE_IDENT, LIB_VERSION_MAJOR, LIB_VERSION_MINOR );
1460 formatter->Print( 0, "#encoding utf-8\n");
1461
1462 for( LIB_SYMBOL_MAP::iterator it = m_symbols.begin(); it != m_symbols.end(); it++ )
1463 {
1464 if( !it->second->IsRoot() )
1465 continue;
1466
1467 SaveSymbol( it->second, *formatter.get(), &m_symbols );
1468 }
1469
1470 formatter->Print( 0, "#\n#End Library\n" );
1471 formatter->Finish();
1472 formatter.reset();
1473
1474 m_fileModTime = KIPLATFORM::IO::TimestampDir( fn.GetPath(), fn.GetFullName() );
1475 m_isModified = false;
1476
1477 if( doSaveDocFile )
1478 saveDocFile();
1479}
1480
1481
1483 LIB_SYMBOL_MAP* aMap )
1484{
1485 /*
1486 * NB:
1487 * Some of the rescue code still uses the legacy format as an intermediary, so we have
1488 * to keep this code.
1489 */
1490
1491 wxCHECK_RET( aSymbol && aSymbol->IsRoot(), "Invalid LIB_SYMBOL pointer." );
1492
1493 // LIB_ALIAS objects are deprecated but we still need to gather up the derived symbols
1494 // and save their names for the old file format.
1495 wxArrayString aliasNames;
1496
1497 if( aMap )
1498 {
1499 for( auto& entry : *aMap )
1500 {
1501 LIB_SYMBOL* symbol = entry.second;
1502
1503 if( symbol->IsDerived() && symbol->GetParent().lock() == aSymbol->SharedPtr() )
1504 aliasNames.Add( symbol->GetName() );
1505 }
1506 }
1507
1508 SCH_FIELD& value = aSymbol->GetValueField();
1509
1510 // First line: it s a comment (symbol name for readers)
1511 aFormatter.Print( 0, "#\n# %s\n#\n", TO_UTF8( value.GetText() ) );
1512
1513 // Save data
1514 aFormatter.Print( 0, "DEF" );
1515 aFormatter.Print( 0, " %s", TO_UTF8( value.GetText() ) );
1516
1517 SCH_FIELD& reference = aSymbol->GetReferenceField();
1518
1519 if( !reference.GetText().IsEmpty() )
1520 aFormatter.Print( 0, " %s", TO_UTF8( reference.GetText() ) );
1521 else
1522 aFormatter.Print( 0, " ~" );
1523
1524 aFormatter.Print( 0, " %d %d %c %c %d %c %c\n",
1525 0, schIUScale.IUToMils( aSymbol->GetPinNameOffset() ),
1526 aSymbol->GetShowPinNumbers() ? 'Y' : 'N',
1527 aSymbol->GetShowPinNames() ? 'Y' : 'N',
1528 aSymbol->GetUnitCount(), aSymbol->UnitsLocked() ? 'L' : 'F',
1529 aSymbol->IsGlobalPower() ? 'P' : 'N' );
1530
1531 timestamp_t dateModified = aSymbol->GetLastModDate();
1532
1533 if( dateModified != 0 )
1534 {
1535 int sec = dateModified & 63;
1536 int min = ( dateModified >> 6 ) & 63;
1537 int hour = ( dateModified >> 12 ) & 31;
1538 int day = ( dateModified >> 17 ) & 31;
1539 int mon = ( dateModified >> 22 ) & 15;
1540 int year = ( dateModified >> 26 ) + 1990;
1541
1542 aFormatter.Print( 0, "Ti %d/%d/%d %d:%d:%d\n", year, mon, day, hour, min, sec );
1543 }
1544
1545 std::vector<SCH_FIELD*> orderedFields;
1546 aSymbol->GetFields( orderedFields );
1547
1548 // NB: FieldIDs in legacy libraries must be consecutive, and include user fields
1549 int legacy_field_id = 0;
1550
1551 for( SCH_FIELD* field : orderedFields )
1552 saveField( field, legacy_field_id++, aFormatter );
1553
1554 // Save the alias list: a line starting by "ALIAS".
1555 if( !aliasNames.IsEmpty() )
1556 {
1557 aFormatter.Print( 0, "ALIAS" );
1558
1559 for( unsigned i = 0; i < aliasNames.GetCount(); i++ )
1560 aFormatter.Print( 0, " %s", TO_UTF8( aliasNames[i] ) );
1561
1562 aFormatter.Print( 0, "\n" );
1563 }
1564
1565 wxArrayString footprints = aSymbol->GetFPFilters();
1566
1567 // Write the footprint filter list
1568 if( footprints.GetCount() != 0 )
1569 {
1570 aFormatter.Print( 0, "$FPLIST\n" );
1571
1572 for( unsigned i = 0; i < footprints.GetCount(); i++ )
1573 aFormatter.Print( 0, " %s\n", TO_UTF8( footprints[i] ) );
1574
1575 aFormatter.Print( 0, "$ENDFPLIST\n" );
1576 }
1577
1578 // Save graphics items (including pins)
1579 if( !aSymbol->GetDrawItems().empty() )
1580 {
1581 // Sort the draw items in order to editing a file editing by hand.
1582 aSymbol->GetDrawItems().sort();
1583
1584 aFormatter.Print( 0, "DRAW\n" );
1585
1586 for( SCH_ITEM& item : aSymbol->GetDrawItems() )
1587 {
1588 switch( item.Type() )
1589 {
1590 case SCH_PIN_T:
1591 savePin( static_cast<SCH_PIN*>( &item ), aFormatter );
1592
1593 break;
1594 case SCH_TEXT_T:
1595 saveText( static_cast<SCH_TEXT*>( &item ), aFormatter );
1596 break;
1597
1598 case SCH_SHAPE_T:
1599 {
1600 SCH_SHAPE& shape = static_cast<SCH_SHAPE&>( item );
1601
1602 switch( shape.GetShape() )
1603 {
1604 case SHAPE_T::ARC: saveArc( &shape, aFormatter ); break;
1605 case SHAPE_T::BEZIER: saveBezier( &shape, aFormatter ); break;
1606 case SHAPE_T::CIRCLE: saveCircle( &shape, aFormatter ); break;
1607 case SHAPE_T::POLY: savePolyLine( &shape, aFormatter ); break;
1608 case SHAPE_T::RECTANGLE: saveRectangle( &shape, aFormatter ); break;
1609 default: break;
1610 }
1611
1612 break;
1613 }
1614
1615 default:
1616 break;
1617 }
1618 }
1619
1620 aFormatter.Print( 0, "ENDDRAW\n" );
1621 }
1622
1623 aFormatter.Print( 0, "ENDDEF\n" );
1624}
1625
1626
1628{
1629 wxCHECK_RET( aArc && aArc->GetShape() == SHAPE_T::ARC, "Invalid ARC object." );
1630
1631 EDA_ANGLE startAngle, endAngle;
1632
1633 aArc->CalcArcAngles( endAngle, startAngle );
1634 startAngle.Normalize180();
1635 endAngle.Normalize180();
1636
1637 aFormatter.Print( 0, "A %d %d %d %d %d %d %d %d %c %d %d %d %d\n",
1638 schIUScale.IUToMils( aArc->GetPosition().x ),
1639 schIUScale.IUToMils( -aArc->GetPosition().y ),
1640 schIUScale.IUToMils( aArc->GetRadius() ),
1641 startAngle.AsTenthsOfADegree(),
1642 endAngle.AsTenthsOfADegree(),
1643 aArc->GetUnit(),
1644 aArc->GetBodyStyle(),
1645 schIUScale.IUToMils( aArc->GetWidth() ),
1646 fill_tab[ static_cast<int>( aArc->GetFillMode() ) - 1 ],
1647 schIUScale.IUToMils( aArc->GetStart().x ),
1648 schIUScale.IUToMils( -aArc->GetStart().y ),
1649 schIUScale.IUToMils( aArc->GetEnd().x ),
1650 schIUScale.IUToMils( -aArc->GetEnd().y ) );
1651}
1652
1653
1655{
1656 wxCHECK_RET( aBezier && aBezier->GetShape() == SHAPE_T::BEZIER, "Invalid BEZIER object." );
1657
1658 aFormatter.Print( 0, "B 4 %d %d %d",
1659 aBezier->GetUnit(),
1660 aBezier->GetBodyStyle(),
1661 schIUScale.IUToMils( aBezier->GetWidth() ) );
1662
1663 aFormatter.Print( 0, " %d %d %d %d %d %d %d %d",
1664 schIUScale.IUToMils( aBezier->GetStart().x ),
1665 schIUScale.IUToMils( -aBezier->GetStart().y ),
1666 schIUScale.IUToMils( aBezier->GetBezierC1().x ),
1667 schIUScale.IUToMils( -aBezier->GetBezierC1().y ),
1668 schIUScale.IUToMils( aBezier->GetBezierC2().x ),
1669 schIUScale.IUToMils( -aBezier->GetBezierC2().y ),
1670 schIUScale.IUToMils( aBezier->GetEnd().x ),
1671 schIUScale.IUToMils( -aBezier->GetEnd().y ) );
1672
1673 aFormatter.Print( 0, " %c\n", fill_tab[ static_cast<int>( aBezier->GetFillMode() ) - 1 ] );
1674}
1675
1676
1678{
1679 wxCHECK_RET( aCircle && aCircle->GetShape() == SHAPE_T::CIRCLE, "Invalid CIRCLE object." );
1680
1681 aFormatter.Print( 0, "C %d %d %d %d %d %d %c\n",
1682 schIUScale.IUToMils( aCircle->GetPosition().x ),
1683 schIUScale.IUToMils( -aCircle->GetPosition().y ),
1684 schIUScale.IUToMils( aCircle->GetRadius() ),
1685 aCircle->GetUnit(),
1686 aCircle->GetBodyStyle(),
1687 schIUScale.IUToMils( aCircle->GetWidth() ),
1688 fill_tab[ static_cast<int>( aCircle->GetFillMode() ) - 1 ] );
1689}
1690
1691
1692void SCH_IO_KICAD_LEGACY_LIB_CACHE::saveField( const SCH_FIELD* aField, int aLegacyFieldIdx,
1693 OUTPUTFORMATTER& aFormatter )
1694{
1695 wxCHECK_RET( aField && aField->Type() == SCH_FIELD_T, "Invalid SCH_FIELD object." );
1696
1697 int hjustify, vjustify;
1698 wxString text = aField->GetText();
1699
1700 hjustify = 'C';
1701
1702 if( aField->GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT )
1703 hjustify = 'L';
1704 else if( aField->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
1705 hjustify = 'R';
1706
1707 vjustify = 'C';
1708
1709 if( aField->GetVertJustify() == GR_TEXT_V_ALIGN_BOTTOM )
1710 vjustify = 'B';
1711 else if( aField->GetVertJustify() == GR_TEXT_V_ALIGN_TOP )
1712 vjustify = 'T';
1713
1714 aFormatter.Print( 0, "F%d %s %d %d %d %c %c %c %c%c%c",
1715 aLegacyFieldIdx,
1716 EscapedUTF8( text ).c_str(), // wraps in quotes
1717 schIUScale.IUToMils( aField->GetTextPos().x ),
1718 schIUScale.IUToMils( -aField->GetTextPos().y ),
1719 schIUScale.IUToMils( aField->GetTextWidth() ),
1720 aField->GetTextAngle().IsHorizontal() ? 'H' : 'V',
1721 aField->IsVisible() ? 'V' : 'I',
1722 hjustify, vjustify,
1723 aField->IsItalic() ? 'I' : 'N',
1724 aField->IsBold() ? 'B' : 'N' );
1725
1726 // Translated names were stored in legacy files, so it's important not to save the
1727 // default names as they weren't yet canonical.
1728 if( !aField->IsMandatory()
1729 && !aField->GetName().IsEmpty()
1730 && aField->GetName() != GetUserFieldName( aLegacyFieldIdx, !DO_TRANSLATE ) )
1731 {
1732 aFormatter.Print( 0, " %s", EscapedUTF8( aField->GetName() ).c_str() );
1733 }
1734
1735 aFormatter.Print( 0, "\n" );
1736}
1737
1738
1740{
1741 wxCHECK_RET( aPin && aPin->Type() == SCH_PIN_T, "Invalid SCH_PIN object." );
1742
1743 int Etype;
1744
1745 switch( aPin->GetType() )
1746 {
1747 default:
1748 case ELECTRICAL_PINTYPE::PT_INPUT: Etype = 'I'; break;
1749 case ELECTRICAL_PINTYPE::PT_OUTPUT: Etype = 'O'; break;
1750 case ELECTRICAL_PINTYPE::PT_BIDI: Etype = 'B'; break;
1751 case ELECTRICAL_PINTYPE::PT_TRISTATE: Etype = 'T'; break;
1752 case ELECTRICAL_PINTYPE::PT_PASSIVE: Etype = 'P'; break;
1753 case ELECTRICAL_PINTYPE::PT_UNSPECIFIED: Etype = 'U'; break;
1754 case ELECTRICAL_PINTYPE::PT_POWER_IN: Etype = 'W'; break;
1755 case ELECTRICAL_PINTYPE::PT_POWER_OUT: Etype = 'w'; break;
1756 case ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR: Etype = 'C'; break;
1757 case ELECTRICAL_PINTYPE::PT_OPENEMITTER: Etype = 'E'; break;
1758 case ELECTRICAL_PINTYPE::PT_NC: Etype = 'N'; break;
1759 }
1760
1761 if( !aPin->GetName().IsEmpty() )
1762 aFormatter.Print( 0, "X %s", TO_UTF8( aPin->GetName() ) );
1763 else
1764 aFormatter.Print( 0, "X ~" );
1765
1766 int pin_orient = 'L'; // Printed as a char in lib file
1767
1768 switch( aPin->GetOrientation() )
1769 {
1770 case PIN_ORIENTATION::PIN_RIGHT: pin_orient = 'R'; break;
1771 case PIN_ORIENTATION::PIN_LEFT: pin_orient = 'L'; break;
1772 case PIN_ORIENTATION::PIN_UP: pin_orient = 'U'; break;
1773 case PIN_ORIENTATION::PIN_DOWN: pin_orient = 'D'; break;
1774 case PIN_ORIENTATION::INHERIT: pin_orient = 'L'; break; // Should not happens
1775 }
1776
1777 aFormatter.Print( 0, " %s %d %d %d %c %d %d %d %d %c",
1778 aPin->GetNumber().IsEmpty() ? "~" : TO_UTF8( aPin->GetNumber() ),
1779 schIUScale.IUToMils( aPin->GetPosition().x ),
1780 schIUScale.IUToMils( -aPin->GetPosition().y ),
1781 schIUScale.IUToMils( (int) aPin->GetLength() ),
1782 pin_orient,
1783 schIUScale.IUToMils( aPin->GetNumberTextSize() ),
1784 schIUScale.IUToMils( aPin->GetNameTextSize() ),
1785 aPin->GetUnit(),
1786 aPin->GetBodyStyle(),
1787 Etype );
1788
1789 if( aPin->GetShape() != GRAPHIC_PINSHAPE::LINE || !aPin->IsVisible() )
1790 aFormatter.Print( 0, " " );
1791
1792 if( !aPin->IsVisible() )
1793 aFormatter.Print( 0, "N" );
1794
1795 switch( aPin->GetShape() )
1796 {
1797 case GRAPHIC_PINSHAPE::LINE: break;
1798 case GRAPHIC_PINSHAPE::INVERTED: aFormatter.Print( 0, "I" ); break;
1799 case GRAPHIC_PINSHAPE::CLOCK: aFormatter.Print( 0, "C" ); break;
1800 case GRAPHIC_PINSHAPE::INVERTED_CLOCK: aFormatter.Print( 0, "IC" ); break;
1801 case GRAPHIC_PINSHAPE::INPUT_LOW: aFormatter.Print( 0, "L" ); break;
1802 case GRAPHIC_PINSHAPE::CLOCK_LOW: aFormatter.Print( 0, "CL" ); break;
1803 case GRAPHIC_PINSHAPE::OUTPUT_LOW: aFormatter.Print( 0, "V" ); break;
1804 case GRAPHIC_PINSHAPE::FALLING_EDGE_CLOCK: aFormatter.Print( 0, "F" ); break;
1805 case GRAPHIC_PINSHAPE::NONLOGIC: aFormatter.Print( 0, "X" ); break;
1806 default: wxFAIL_MSG( "Invalid pin shape" );
1807 }
1808
1809 aFormatter.Print( 0, "\n" );
1810
1811 const_cast<SCH_PIN*>( aPin )->ClearFlags( IS_CHANGED );
1812}
1813
1814
1816 OUTPUTFORMATTER& aFormatter )
1817{
1818 wxCHECK_RET( aPolyLine && aPolyLine->GetShape() == SHAPE_T::POLY, "Invalid POLY object." );
1819
1820 aFormatter.Print( 0, "P %d %d %d %d",
1821 (int) aPolyLine->GetPolyShape().Outline( 0 ).GetPointCount(),
1822 aPolyLine->GetUnit(),
1823 aPolyLine->GetBodyStyle(),
1824 schIUScale.IUToMils( aPolyLine->GetWidth() ) );
1825
1826 for( const VECTOR2I& pt : aPolyLine->GetPolyShape().Outline( 0 ).CPoints() )
1827 aFormatter.Print( 0, " %d %d", schIUScale.IUToMils( pt.x ), -schIUScale.IUToMils( pt.y ) );
1828
1829 aFormatter.Print( 0, " %c\n", fill_tab[ static_cast<int>( aPolyLine->GetFillMode() ) - 1 ] );
1830}
1831
1832
1834 OUTPUTFORMATTER& aFormatter )
1835{
1836 wxCHECK_RET( aRectangle && aRectangle->GetShape() == SHAPE_T::RECTANGLE,
1837 "Invalid RECT object." );
1838
1839 aFormatter.Print( 0, "S %d %d %d %d %d %d %d %c\n",
1840 schIUScale.IUToMils( aRectangle->GetPosition().x ),
1841 schIUScale.IUToMils( -aRectangle->GetPosition().y ),
1842 schIUScale.IUToMils( aRectangle->GetEnd().x ),
1843 schIUScale.IUToMils( -aRectangle->GetEnd().y ),
1844 aRectangle->GetUnit(),
1845 aRectangle->GetBodyStyle(),
1846 schIUScale.IUToMils( aRectangle->GetWidth() ),
1847 fill_tab[ static_cast<int>( aRectangle->GetFillMode() ) - 1 ] );
1848}
1849
1850
1852{
1853 wxCHECK_RET( aText && aText->Type() == SCH_TEXT_T, "Invalid SCH_TEXT object." );
1854
1855 wxString text = aText->GetText();
1856
1857 if( text.Contains( wxT( " " ) ) || text.Contains( wxT( "~" ) ) || text.Contains( wxT( "\"" ) ) )
1858 {
1859 // convert double quote to similar-looking two apostrophes
1860 text.Replace( wxT( "\"" ), wxT( "''" ) );
1861 text = wxT( "\"" ) + text + wxT( "\"" );
1862 }
1863
1864 aFormatter.Print( 0, "T %d %d %d %d %d %d %d %s",
1866 schIUScale.IUToMils( aText->GetTextPos().x ),
1867 schIUScale.IUToMils( -aText->GetTextPos().y ),
1868 schIUScale.IUToMils( aText->GetTextWidth() ),
1869 !aText->IsVisible(),
1870 aText->GetUnit(),
1871 aText->GetBodyStyle(),
1872 TO_UTF8( text ) );
1873
1874 aFormatter.Print( 0, " %s %d", aText->IsItalic() ? "Italic" : "Normal", aText->IsBold() );
1875
1876 char hjustify = 'C';
1877
1878 if( aText->GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT )
1879 hjustify = 'L';
1880 else if( aText->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
1881 hjustify = 'R';
1882
1883 char vjustify = 'C';
1884
1885 if( aText->GetVertJustify() == GR_TEXT_V_ALIGN_BOTTOM )
1886 vjustify = 'B';
1887 else if( aText->GetVertJustify() == GR_TEXT_V_ALIGN_TOP )
1888 vjustify = 'T';
1889
1890 aFormatter.Print( 0, " %c %c\n", hjustify, vjustify );
1891}
1892
1893
1895{
1896 /*
1897 * NB:
1898 * Some of the rescue code still uses the legacy format as an intermediary, so we have
1899 * to keep this code.
1900 */
1901
1902 wxFileName fileName = m_libFileName;
1903
1905 FILE_OUTPUTFORMATTER formatter( fileName.GetFullPath() );
1906
1907 formatter.Print( 0, "%s\n", DOCFILE_IDENT );
1908
1909 for( LIB_SYMBOL_MAP::iterator it = m_symbols.begin(); it != m_symbols.end(); ++it )
1910 {
1911 wxString description = it->second->GetDescription();
1912 wxString keyWords = it->second->GetKeyWords();
1913 wxString docFileName = it->second->GetDatasheetField().GetText();
1914
1915 if( description.IsEmpty() && keyWords.IsEmpty() && docFileName.IsEmpty() )
1916 continue;
1917
1918 formatter.Print( 0, "#\n$CMP %s\n", TO_UTF8( it->second->GetName() ) );
1919
1920 if( !description.IsEmpty() )
1921 formatter.Print( 0, "D %s\n", TO_UTF8( description ) );
1922
1923 if( !keyWords.IsEmpty() )
1924 formatter.Print( 0, "K %s\n", TO_UTF8( keyWords ) );
1925
1926 if( !docFileName.IsEmpty() )
1927 formatter.Print( 0, "F %s\n", TO_UTF8( docFileName ) );
1928
1929 formatter.Print( 0, "$ENDCMP\n" );
1930 }
1931
1932 formatter.Print( 0, "#\n#End Doc Library\n" );
1933 formatter.Finish();
1934}
1935
1936
1937void SCH_IO_KICAD_LEGACY_LIB_CACHE::DeleteSymbol( const wxString& aSymbolName )
1938{
1939 LIB_SYMBOL_MAP::iterator it = m_symbols.find( aSymbolName );
1940
1941 if( it == m_symbols.end() )
1942 THROW_IO_ERROR( wxString::Format( _( "library %s does not contain a symbol named %s" ),
1943 m_libFileName.GetFullName(), aSymbolName ) );
1944
1945 LIB_SYMBOL* symbol = it->second;
1946
1947 if( symbol->IsRoot() )
1948 {
1949 LIB_SYMBOL* rootSymbol = symbol;
1950
1951 // Remove the root symbol and all its children.
1952 m_symbols.erase( it );
1953
1954 LIB_SYMBOL_MAP::iterator it1 = m_symbols.begin();
1955
1956 while( it1 != m_symbols.end() )
1957 {
1958 if( it1->second->IsDerived()
1959 && it1->second->GetParent().lock() == rootSymbol->SharedPtr() )
1960 {
1961 delete it1->second;
1962 it1 = m_symbols.erase( it1 );
1963 }
1964 else
1965 {
1966 it1++;
1967 }
1968 }
1969
1970 delete rootSymbol;
1971 }
1972 else
1973 {
1974 // Just remove the alias.
1975 m_symbols.erase( it );
1976 delete symbol;
1977 }
1978
1980 m_isModified = true;
1981}
const char * name
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:127
constexpr double ARC_LOW_DEF_MM
Definition base_units.h:131
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
int AsTenthsOfADegree() const
Definition eda_angle.h:118
bool IsHorizontal() const
Definition eda_angle.h:142
EDA_ANGLE Normalize180()
Definition eda_angle.h:268
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:112
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:93
const VECTOR2I & GetBezierC2() const
Definition eda_shape.h:279
void SetBezierC2(const VECTOR2I &aPt)
Definition eda_shape.h:278
FILL_T GetFillMode() const
Definition eda_shape.h:162
SHAPE_POLY_SET & GetPolyShape()
void CalcArcAngles(EDA_ANGLE &aStartAngle, EDA_ANGLE &aEndAngle) const
Calc arc start and end angles such that aStartAngle < aEndAngle.
int GetRadius() const
SHAPE_T GetShape() const
Definition eda_shape.h:189
void RebuildBezierToSegmentsPointsList(int aMaxError)
Rebuild the m_bezierPoints vertex list that approximate the Bezier curve by a list of segments.
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:236
void SetStart(const VECTOR2I &aStart)
Definition eda_shape.h:198
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:194
void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:240
void SetBezierC1(const VECTOR2I &aPt)
Definition eda_shape.h:275
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Set the three controlling points for an arc.
const VECTOR2I & GetBezierC1() const
Definition eda_shape.h:276
virtual int GetWidth() const
Definition eda_shape.h:177
void SetFillMode(FILL_T aFill)
VECTOR2I GetArcMid() const
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:93
const VECTOR2I & GetTextPos() const
Definition eda_text.h:298
bool IsItalic() const
Definition eda_text.h:194
const EDA_ANGLE & GetTextAngle() const
Definition eda_text.h:172
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition eda_text.cpp:536
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:114
virtual bool IsVisible() const
Definition eda_text.h:212
void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:580
int GetTextWidth() const
Definition eda_text.h:289
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:416
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:225
void SetBoldFlag(bool aBold)
Set only the bold flag, without changing the font.
Definition eda_text.cpp:377
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:385
void Empty()
Definition eda_text.cpp:620
void SetItalicFlag(bool aItalic)
Set only the italic flag, without changing the font.
Definition eda_text.cpp:326
bool IsBold() const
Definition eda_text.h:209
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition eda_text.h:228
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:298
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:408
A LINE_READER that reads from an open file.
Definition richio.h:158
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition richio.cpp:212
Used for text file output.
Definition richio.h:474
bool Finish() override
Flushes the temp file to disk and atomically renames it over the final target path.
Definition richio.cpp:646
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
Define a library symbol object.
Definition lib_symbol.h:83
std::weak_ptr< LIB_SYMBOL > & GetParent()
Definition lib_symbol.h:114
void GetFields(std::vector< SCH_FIELD * > &aList, bool aVisibleOnly=false) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
bool UnitsLocked() const
Check whether symbol units are interchangeable.
Definition lib_symbol.h:287
bool IsRoot() const override
For symbols derived from other symbols, IsRoot() indicates no derivation.
Definition lib_symbol.h:199
bool IsDerived() const
Definition lib_symbol.h:200
timestamp_t GetLastModDate() const
Definition lib_symbol.h:207
SCH_FIELD * GetField(const wxString &aFieldName)
Find a field within this symbol matching aFieldName; return nullptr if not found.
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:713
void SetParent(LIB_SYMBOL *aParent=nullptr)
wxString GetName() const override
Definition lib_symbol.h:145
void SetDescription(const wxString &aDescription)
Gets the Description field text value *‍/.
void SetKeyWords(const wxString &aKeyWords)
SCH_FIELD & GetValueField()
Return reference to the value field.
Definition lib_symbol.h:333
wxArrayString GetFPFilters() const
Definition lib_symbol.h:211
bool HasLegacyAlternateBodyStyle() const
Before V10 we didn't store the number of body styles in a symbol – we just looked through all its dra...
std::shared_ptr< LIB_SYMBOL > SharedPtr() const
http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/sp_techniques.html#weak_without_shared.
Definition lib_symbol.h:92
void SetHasDeMorganBodyStyles(bool aFlag)
Definition lib_symbol.h:786
bool IsGlobalPower() const override
int GetUnitCount() const override
SCH_FIELD & GetReferenceField()
Return reference to the reference designator field.
Definition lib_symbol.h:337
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
Definition richio.h:66
virtual char * ReadLine()=0
Read a line of text into the buffer and increments the line number counter.
virtual const wxString & GetSource() const
Returns the name of the source of the lines in an abstract sense.
Definition richio.h:94
virtual unsigned LineNumber() const
Return the line number of the last line read from this LINE_READER.
Definition richio.h:120
char * Line() const
Return a pointer to the last line that was read in.
Definition richio.h:102
bool empty(int aType=UNDEFINED_TYPE) const
An interface used to output 8 bit text in a convenient way.
Definition richio.h:295
int PRINTF_FUNC_N Print(int nestLevel, const char *fmt,...)
Format and write text to the output stream.
Definition richio.cpp:426
bool IsMandatory() const
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:132
FIELD_T GetId() const
Definition sch_field.h:136
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
void SetPosition(const VECTOR2I &aPosition) override
void SetName(const wxString &aName)
void SetText(const wxString &aText) override
SCH_IO_KICAD_LEGACY_LIB_CACHE(const wxString &aLibraryPath)
static void loadDrawEntries(std::unique_ptr< LIB_SYMBOL > &aSymbol, LINE_READER &aReader, int aMajorVersion, int aMinorVersion)
void loadHeader(FILE_LINE_READER &aReader)
static SCH_SHAPE * loadBezier(LINE_READER &aReader)
static void saveField(const SCH_FIELD *aField, int aLegacyFieldIdx, OUTPUTFORMATTER &aFormatter)
static void saveArc(SCH_SHAPE *aArc, OUTPUTFORMATTER &aFormatter)
static void saveCircle(SCH_SHAPE *aCircle, OUTPUTFORMATTER &aFormatter)
static SCH_SHAPE * loadArc(LINE_READER &aReader)
static void loadField(std::unique_ptr< LIB_SYMBOL > &aSymbol, LINE_READER &aReader)
static LIB_SYMBOL * LoadPart(LINE_READER &aReader, int aMajorVersion, int aMinorVersion, LIB_SYMBOL_MAP *aMap=nullptr)
static void savePolyLine(SCH_SHAPE *aPolyLine, OUTPUTFORMATTER &aFormatter)
static SCH_SHAPE * loadPolyLine(LINE_READER &aReader)
static void saveBezier(SCH_SHAPE *aBezier, OUTPUTFORMATTER &aFormatter)
static SCH_SHAPE * loadCircle(LINE_READER &aReader)
static SCH_ITEM * loadText(LINE_READER &aReader, int aMajorVersion, int aMinorVersion)
void Save(const std::optional< bool > &aOpt) override
Save the entire library to file m_libFileName;.
static SCH_SHAPE * loadRect(LINE_READER &aReader)
static void loadAliases(std::unique_ptr< LIB_SYMBOL > &aSymbol, LINE_READER &aReader, LIB_SYMBOL_MAP *aMap=nullptr)
static void loadFootprintFilters(std::unique_ptr< LIB_SYMBOL > &aSymbol, LINE_READER &aReader)
void DeleteSymbol(const wxString &aName) override
static void savePin(const SCH_PIN *aPin, OUTPUTFORMATTER &aFormatter)
static SCH_PIN * loadPin(std::unique_ptr< LIB_SYMBOL > &aSymbol, LINE_READER &aReader)
static FILL_T parseFillMode(LINE_READER &aReader, const char *aLine, const char **aOutput)
static void saveRectangle(SCH_SHAPE *aRectangle, OUTPUTFORMATTER &aFormatter)
static void SaveSymbol(LIB_SYMBOL *aSymbol, OUTPUTFORMATTER &aFormatter, LIB_SYMBOL_MAP *aMap=nullptr)
static void saveText(const SCH_TEXT *aText, OUTPUTFORMATTER &aFormatter)
SCH_LIB_TYPE m_libType
LIB_SYMBOL_MAP m_symbols
wxFileName GetRealFile() const
long long GetLibModificationTime()
SCH_IO_LIB_CACHE(const wxString &aLibraryPath)
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:166
virtual void SetBodyStyle(int aBodyStyle)
Definition sch_item.h:245
int GetBodyStyle() const
Definition sch_item.h:246
int GetUnit() const
Definition sch_item.h:237
virtual void SetUnit(int aUnit)
Definition sch_item.h:236
int GetNumberTextSize() const
Definition sch_pin.cpp:765
int GetLength() const
Definition sch_pin.cpp:379
bool IsVisible() const
Definition sch_pin.cpp:471
const wxString & GetName() const
Definition sch_pin.cpp:485
PIN_ORIENTATION GetOrientation() const
Definition sch_pin.cpp:344
VECTOR2I GetPosition() const override
Definition sch_pin.cpp:336
int GetNameTextSize() const
Definition sch_pin.cpp:739
const wxString & GetNumber() const
Definition sch_pin.h:127
GRAPHIC_PINSHAPE GetShape() const
Definition sch_pin.cpp:358
ELECTRICAL_PINTYPE GetType() const
Definition sch_pin.cpp:393
void SetPosition(const VECTOR2I &aPos) override
Definition sch_shape.h:89
void SetStroke(const STROKE_PARAMS &aStroke) override
VECTOR2I GetCenter() const
Definition sch_shape.h:96
void AddPoint(const VECTOR2I &aPosition)
VECTOR2I GetPosition() const override
Definition sch_shape.h:88
virtual size_t GetPointCount() const override
const std::vector< VECTOR2I > & CPoints() const
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
Simple container to manage line stroke parameters.
int GetPinNameOffset() const
Definition symbol.h:163
virtual bool GetShowPinNames() const
Definition symbol.h:169
virtual bool GetShowPinNumbers() const
Definition symbol.h:175
The common library.
#define _(s)
@ TENTHS_OF_A_DEGREE_T
Definition eda_angle.h:30
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:408
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:407
#define IS_CHANGED
Item was edited, and modified.
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:51
FILL_T
Definition eda_shape.h:63
@ NO_FILL
Definition eda_shape.h:64
@ FILLED_WITH_BG_BODYCOLOR
Definition eda_shape.h:66
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:65
static const std::string LegacySymbolDocumentFileExtension
const wxChar *const traceSchLegacyPlugin
Flag to enable legacy schematic plugin debug output.
std::chrono::steady_clock CLOCK
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
uint32_t timestamp_t
timestamp_t is our type to represent unique IDs for all kinds of elements; historically simply the ti...
Definition kiid.h:45
@ LAYER_DEVICE
Definition layer_ids.h:468
This file contains miscellaneous commonly used macros and functions.
long long TimestampDir(const wxString &aDirPath, const wxString &aFilespec)
Computes a hash of modification times and sizes for files matching a pattern.
Definition unix/io.cpp:123
ELECTRICAL_PINTYPE
The symbol library pin object electrical types used in ERC tests.
Definition pin_type.h:36
@ PT_INPUT
usual pin input: must be connected
Definition pin_type.h:37
@ PT_NC
not connected (must be left open)
Definition pin_type.h:50
@ PT_OUTPUT
usual output
Definition pin_type.h:38
@ PT_TRISTATE
tri state bus pin
Definition pin_type.h:40
@ PT_BIDI
input or output (like port for a microprocessor)
Definition pin_type.h:39
@ PT_OPENEMITTER
pin type open emitter
Definition pin_type.h:49
@ PT_POWER_OUT
output of a regulator: intended to be connected to power input pins
Definition pin_type.h:47
@ PT_OPENCOLLECTOR
pin type open collector
Definition pin_type.h:48
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
Definition pin_type.h:46
@ PT_UNSPECIFIED
unknown electrical properties: creates always a warning when connected
Definition pin_type.h:45
@ PT_PASSIVE
pin for passive symbols: must be connected, and can be connected to any pin.
Definition pin_type.h:43
PIN_ORIENTATION
The symbol library pin object orientations.
Definition pin_type.h:105
@ PIN_UP
The pin extends upwards from the connection point: Probably on the bottom side of the symbol.
Definition pin_type.h:127
@ PIN_RIGHT
The pin extends rightwards from the connection point.
Definition pin_type.h:111
@ PIN_LEFT
The pin extends leftwards from the connection point: Probably on the right side of the symbol.
Definition pin_type.h:118
@ PIN_DOWN
The pin extends downwards from the connection: Probably on the top side of the symbol.
Definition pin_type.h:135
int parseInt(LINE_READER &aReader, const char *aLine, const char **aOutput)
Parse an ASCII integer string with possible leading whitespace into an integer and updates the pointe...
bool strCompare(const char *aString, const char *aLine, const char **aOutput)
Compare aString to the string starting at aLine and advances the character point to the end of String...
void parseQuotedString(wxString &aString, LINE_READER &aReader, const char *aCurrentToken, const char **aNextToken, bool aCanBeEmpty)
Parse an quoted ASCII utf8 and updates the pointer at aOutput if it is not NULL.
void parseUnquotedString(wxString &aString, LINE_READER &aReader, const char *aCurrentToken, const char **aNextToken, bool aCanBeEmpty)
Parse an unquoted utf8 string and updates the pointer at aOutput if it is not NULL.
bool is_eol(char c)
char parseChar(LINE_READER &aReader, const char *aCurrentToken, const char **aNextToken)
Parse a single ASCII character and updates the pointer at aOutput if it is not NULL.
#define SCH_PARSE_ERROR(text, reader, pos)
static bool MapAnglesV6(int *aAngle1, int *aAngle2)
This function based on version 6.0 is required for reading legacy arcs.
#define LIB_VERSION_MINOR
Legacy symbol library minor version.
const int fill_tab[3]
#define LIBFILE_IDENT
Legacy symbol library (.lib) file header.
#define USE_OLD_DOC_FILE_FORMAT(major, minor)
Library versions 2.4 and lower use the old separate library (.lib) and document (....
#define LIB_VERSION(major, minor)
#define DOCFILE_IDENT
Legacy symbol library document (.dcm) file header.
#define LIB_VERSION_MAJOR
Legacy symbol library major version.
wxString ConvertToNewOverbarNotation(const wxString &aOldStr)
Convert the old ~...~ overbar notation to the new ~{...} one.
wxString UnescapeString(const wxString &aSource)
wxString From_UTF8(const char *cstring)
std::string EscapedUTF8(const wxString &aString)
Return an 8 bit UTF8 string given aString in Unicode form.
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
@ CTX_QUOTED_STR
std::map< wxString, LIB_SYMBOL *, LibSymbolMapSort > LIB_SYMBOL_MAP
wxString GetUserFieldName(int aFieldNdx, bool aTranslateForHI)
#define DO_TRANSLATE
#define MANDATORY_FIELDS
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ USER
The field ID hasn't been set yet; field is invalid.
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ DATASHEET
name of datasheet
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
wxString GetCanonicalFieldName(FIELD_T aFieldType)
KIBIS_PIN * pin
VECTOR2I center
int radius
VECTOR2I end
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
int delta
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
#define M_PI
wxLogTrace helper definitions.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:229
void NORMALIZE_ANGLE_POS(T &Angle)
Definition trigo.h:187
double RAD2DECIDEG(double rad)
Definition trigo.h:170
@ SCH_FIELD_T
Definition typeinfo.h:151
@ SCH_SHAPE_T
Definition typeinfo.h:150
@ SCH_TEXT_T
Definition typeinfo.h:152
@ SCH_PIN_T
Definition typeinfo.h:154
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
Definition of file extensions used in Kicad.