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