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