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