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