KiCad PCB EDA Suite
Loading...
Searching...
No Matches
eagle_parser.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * Copyright (C) 2017 CERN.
7 *
8 * @author Alejandro GarcĂ­a Montoro <[email protected]>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
25
26#include <core/profile.h>
27#include <io/io_base.h>
28
29#include <string_utils.h>
30#include <richio.h>
31#include <trace_helpers.h>
32#include <wx/log.h>
33#include <wx/regex.h>
34#include <wx/tokenzr.h>
35
36#include <functional>
37#include <cstdio>
38#include <array>
39
41
42
43wxString escapeName( const wxString& aNetName )
44{
45 wxString ret( aNetName );
46
47 ret.Replace( "!", "~" );
48
49 return ConvertToNewOverbarNotation( ret );
50}
51
52
53wxString interpretText( const wxString& aText )
54{
55 wxString token = aText;
56
57 if( substituteVariable( &token ) )
58 return token;
59
60 wxString text;
61 bool sectionOpen = false;
62
63 for( wxString::size_type i = 0; i < aText.size(); i++ )
64 {
65 // Interpret escaped characters
66 if( aText[ i ] == '\\' )
67 {
68 if( i + 1 != aText.size() )
69 text.Append( aText[ i + 1 ] );
70
71 i++;
72 continue;
73 }
74
75 // Escape ~ for KiCAD
76 if( aText[i] == '~' )
77 {
78 text.Append( '~' );
79 text.Append( '~' );
80 continue;
81 }
82
83 if( aText[ i ] == '!' )
84 {
85 if( sectionOpen )
86 {
87 text.Append( '~' );
88 sectionOpen = false;
89 continue;
90 }
91
92 static wxString escapeChars( wxT( " )]}'\"" ) );
93
94 if( i + 1 != aText.size() && escapeChars.Find( aText[i + 1] ) == wxNOT_FOUND )
95 {
96 sectionOpen = true;
97 text.Append( '~' );
98 }
99 else
100 {
101 text.Append( aText[ i ] );
102 }
103
104 continue;
105 }
106
107 if( aText[i] == ',' && sectionOpen )
108 {
109 text.Append( '~' );
110 sectionOpen = false;
111 }
112
113 text.Append( aText[ i ] );
114 }
115
116 return text;
117}
118
119
120bool substituteVariable( wxString* aText )
121{
122 if( aText->StartsWith( '>' ) && aText->AfterFirst( ' ' ).IsEmpty() )
123 {
124 wxString token = aText->Upper();
125
126 if ( token == wxT( ">NAME" ) ) *aText = wxT( "${REFERENCE}" );
127 else if( token == wxT( ">VALUE" ) ) *aText = wxT( "${VALUE}" );
128 else if( token == wxT( ">PART" ) ) *aText = wxT( "${REFERENCE}" );
129 else if( token == wxT( ">GATE" ) ) *aText = wxT( "${UNIT}" );
130 else if( token == wxT( ">MODULE" ) ) *aText = wxT( "${FOOTPRINT_NAME}" );
131 else if( token == wxT( ">SHEETNR" ) ) *aText = wxT( "${#}" );
132 else if( token == wxT( ">SHEETS" ) ) *aText = wxT( "${##}" );
133 else if( token == wxT( ">SHEET" ) ) *aText = wxT( "${#}/${##}" );
134 else if( token == wxT( ">SHEETNR_TOTAL" ) ) *aText = wxT( "${#}" );
135 else if( token == wxT( ">SHEETS_TOTAL" ) ) *aText = wxT( "${##}" );
136 else if( token == wxT( ">SHEET_TOTAL" ) ) *aText = wxT( "${#}/${##}" );
137 else if( token == wxT( ">SHEET_HEADLINE" ) ) *aText = wxT( "${SHEETNAME}" );
138 else if( token == wxT( ">ASSEMBLY_VARIANT" ) ) *aText = wxT( "${ASSEMBLY_VARIANT}" );
139 else if( token == wxT( ">DRAWING_NAME" ) ) *aText = wxT( "${PROJECTNAME}" );
140 else if( token == wxT( ">LAST_DATE_TIME" ) ) *aText = wxT( "${CURRENT_DATE}" );
141 else if( token == wxT( ">PLOT_DATE_TIME" ) ) *aText = wxT( "${CURRENT_DATE}" );
142 else *aText = wxString::Format( wxS( "${%s}" ), aText->Mid( 1 ).Trim() );
143
144 return true;
145 }
146
147 return false;
148}
149
150
151wxString convertDescription( wxString aDescr )
152{
153 aDescr.Replace( wxS( "\n" ), wxS( " " ) );
154 aDescr.Replace( wxS( "\r" ), wxEmptyString );
155
156 wxRegEx( wxS( "<a\\s+(?:[^>]*?\\s+)?href=\"([^\"]*)\"[^>]*>" ) )
157 .ReplaceAll( &aDescr, wxS( "\\1 " ) );
158
159 aDescr.Replace( wxS( "<p>" ), wxS( "\n\n" ) );
160 aDescr.Replace( wxS( "</p>" ), wxS( "\n\n" ) );
161
162 aDescr.Replace( wxS( "<br>" ), wxS( "\n" ) );
163 aDescr.Replace( wxS( "<ul>" ), wxS( "\n" ) );
164 aDescr.Replace( wxS( "</ul>" ), wxS( "\n\n" ) );
165 aDescr.Replace( wxS( "<li></li>" ), wxS( "\n" ) );
166 aDescr.Replace( wxS( "<li>" ), wxS( "\n \u2022 " ) ); // Bullet point
167
168 aDescr = RemoveHTMLTags( aDescr );
169
170 wxRegEx( wxS( "\n +" ) ).ReplaceAll( &aDescr, wxS( "\n" ) );
171 wxRegEx( wxS( " +\n" ) ).ReplaceAll( &aDescr, wxS( "\n" ) );
172
173 wxRegEx( wxS( "\n{3,}" ) ).ReplaceAll( &aDescr, wxS( "\n\n" ) );
174 wxRegEx( wxS( "^\n+" ) ).ReplaceAll( &aDescr, wxEmptyString );
175 wxRegEx( wxS( "\n+$" ) ).ReplaceAll( &aDescr, wxEmptyString );
176
177 return aDescr;
178}
179
180
181size_t GetNodeCount( const wxXmlNode* aNode )
182{
183 size_t cnt = 0;
184
185 PROF_TIMER timer;
186
187 std::function<size_t( const wxXmlNode* )> countNodes =
188 [&]( const wxXmlNode* node )
189 {
190 size_t count = 0;
191
192 while( node )
193 {
194 if( const wxXmlNode* child = node->GetChildren() )
195 count += countNodes( child );
196 else
197 count++;
198
199 node = node->GetNext();
200 }
201
202 return count;
203 };
204
205 cnt = countNodes( aNode );
206
207 timer.Stop();
208
209 wxLogTrace( traceEagleIo, wxS( "XML node '%s' count = %zu took %0.4f ms." ),
210 aNode->GetName(), cnt, timer.msecs() );
211
212 return cnt;
213}
214template<> template<>
216{
217 m_isAvailable = !aData.IsEmpty();
218
219 if( m_isAvailable )
220 Set( aData );
221}
222
223
224ECOORD::ECOORD( const wxString& aValue, enum ECOORD::EAGLE_UNIT aUnit )
225{
226 // This array is used to adjust the fraction part value basing on the number of digits
227 // in the fraction.
228 static std::array<int, 9> DIVIDERS = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
229
230 int integer, pre_fraction, post_fraction;
231 long long unsigned fraction;
232
233 // The following check is needed to handle correctly negative fractions where the integer
234 // part == 0.
235 bool negative = ( aValue[0] == '-' );
236
237 // %n is used to find out how many digits contains the fraction part, e.g. 0.001 contains 3
238 // digits.
239 int ret = sscanf( aValue.c_str(), "%d.%n%llu%n", &integer, &pre_fraction, &fraction,
240 &post_fraction );
241
242 if( ret == 0 )
243 throw XML_PARSER_ERROR( "Invalid coordinate" );
244
245 // process the integer part
246 value = ConvertToNm( integer, aUnit );
247
248 // process the fraction part
249 if( ret == 2 )
250 {
251 int digits = post_fraction - pre_fraction;
252
253 // adjust the number of digits if necessary as we cannot handle anything smaller than
254 // nanometers (rounding).
255 if( digits >= static_cast<int>( DIVIDERS.size() ) )
256 {
257 long long unsigned denom = pow( 10, digits - DIVIDERS.size() + 1 );
258 digits = DIVIDERS.size() - 1;
259 fraction /= denom;
260 }
261
262 int frac_value = ConvertToNm( fraction, aUnit ) / DIVIDERS[digits];
263
264 // keep the sign in mind
265 value = negative ? value - frac_value : value + frac_value;
266 }
267}
268
269
270long long int ECOORD::ConvertToNm( int aValue, enum EAGLE_UNIT aUnit )
271{
272 long long int ret;
273
274 switch( aUnit )
275 {
276 default:
277 case EU_NM: ret = aValue; break;
278 case EU_MM: ret = (long long) aValue * 1000000; break;
279 case EU_INCH: ret = (long long) aValue * 25400000; break;
280 case EU_MIL: ret = (long long) aValue * 25400; break;
281 }
282
283 if( ( ret > 0 ) != ( aValue > 0 ) )
284 wxLogTrace( traceEagleIo, wxT( "Invalid size %d: too large" ), aValue );
285
286 return ret;
287}
288
289
290EURN::EURN( const wxString& aUrn )
291{
292 Parse( aUrn );
293}
294
295
296void EURN::Parse( const wxString& aUrn )
297{
298 wxStringTokenizer tokens( aUrn, ":" );
299
300 host = tokens.GetNextToken();
301 path = tokens.GetNextToken();
302 assetType = tokens.GetNextToken();
303
304 // Split off the version if there is one.
305 wxString tmp = tokens.GetNextToken();
306
307 assetId = tmp.BeforeFirst( '/' );
308 assetVersion = tmp.AfterLast( '/' );
309}
310
311
312bool EURN::IsValid() const
313{
314 if( host != "urn" )
315 return false;
316
317 if( path.IsEmpty() )
318 return false;
319
320 static std::set<wxString> validAssetTypes =
321 {
322 "component",
323 "footprint",
324 "library",
325 "package",
326 "symbol",
327 "fs.file"
328 };
329
330 if( validAssetTypes.count( assetType ) == 0 )
331 return false;
332
333 if( assetId.IsEmpty() )
334 return false;
335
336 return true;
337}
338
339
340// Template specializations below parse wxString to the used types:
341// - wxString (preferred)
342// - string
343// - double
344// - int
345// - bool
346// - EROT
347// - ECOORD
348
349template <>
350wxString Convert<wxString>( const wxString& aValue )
351{
352 return aValue;
353}
354
355
356template <>
357std::string Convert<std::string>( const wxString& aValue )
358{
359 return std::string( aValue.ToUTF8() );
360}
361
362
363template <>
364double Convert<double>( const wxString& aValue )
365{
366 double value;
367
368 if( aValue.ToCDouble( &value ) )
369 return value;
370 else
371 throw XML_PARSER_ERROR( "Conversion to double failed. Original value: '" +
372 aValue.ToStdString() + "'." );
373}
374
375
376template <>
377int Convert<int>( const wxString& aValue )
378{
379 if( aValue.IsEmpty() )
380 throw XML_PARSER_ERROR( "Conversion to int failed. Original value is empty." );
381
382 return wxAtoi( aValue );
383}
384
385
386template <>
387bool Convert<bool>( const wxString& aValue )
388{
389 if( aValue != "yes" && aValue != "no" )
390 throw XML_PARSER_ERROR( "Conversion to bool failed. Original value, '" +
391 aValue.ToStdString() +
392 "', is neither 'yes' nor 'no'." );
393
394 return aValue == "yes";
395}
396
397
400template<>
401EROT Convert<EROT>( const wxString& aRot )
402{
403 EROT value;
404
405 value.spin = aRot.find( 'S' ) != aRot.npos;
406 value.mirror = aRot.find( 'M' ) != aRot.npos;
407
408 size_t rPos = aRot.find( 'R' );
409
410 if( rPos == wxString::npos )
411 {
412 value.degrees = 0.0;
413 return value;
414 }
415
416 // Calculate the offset after 'R', 'S', and 'M'
417 size_t offset;
418
419 for( offset = 0; offset < aRot.size(); offset++ )
420 {
421 if( wxIsdigit( aRot[offset] ) )
422 break;
423 }
424
425 wxString degreesStr = aRot.Mid( offset );
426
427 // Use locale-independent conversion
428 if( !degreesStr.ToCDouble( &value.degrees ) )
429 value.degrees = 0.0;
430
431 return value;
432}
433
434
435template<>
436ECOORD Convert<ECOORD>( const wxString& aCoord )
437{
438 // Eagle uses millimeters as the default unit
439 return ECOORD( aCoord, ECOORD::EAGLE_UNIT::EU_MM );
440}
441
442
443template<>
444EURN Convert<EURN>( const wxString& aUrn )
445{
446 return EURN( aUrn );
447}
448
449
458template<typename T>
459T parseRequiredAttribute( wxXmlNode* aNode, const wxString& aAttribute )
460{
461 wxString value;
462
463 if( aNode->GetAttribute( aAttribute, &value ) )
464 return Convert<T>( value );
465 else
466 throw XML_PARSER_ERROR( "The required attribute " + aAttribute + " is missing at "
467 "line " + wxString::Format( "%d", aNode->GetLineNumber() ) +
468 "." );
469}
470
471
480template<typename T>
481OPTIONAL_XML_ATTRIBUTE<T> parseOptionalAttribute( wxXmlNode* aNode, const wxString& aAttribute )
482{
483 return OPTIONAL_XML_ATTRIBUTE<T>( aNode->GetAttribute( aAttribute ) );
484}
485
486
487NODE_MAP MapChildren( wxXmlNode* aCurrentNode )
488{
489 // Map node_name -> node_pointer
490 NODE_MAP nodesMap;
491
492 // Loop through all children mapping them in nodesMap
493 if( aCurrentNode )
494 aCurrentNode = aCurrentNode->GetChildren();
495
496 while( aCurrentNode )
497 {
498 // Create a new pair in the map
499 // key: current node name
500 // value: current node pointer
501 nodesMap[aCurrentNode->GetName()] = aCurrentNode;
502
503 // Get next child
504 aCurrentNode = aCurrentNode->GetNext();
505 }
506
507 return nodesMap;
508}
509
510
511VECTOR2I ConvertArcCenter( const VECTOR2I& aStart, const VECTOR2I& aEnd, double aAngle )
512{
513 // Eagle give us start and end.
514 // S_ARC wants start to give the center, and end to give the start.
515 double dx = aEnd.x - aStart.x, dy = aEnd.y - aStart.y;
516 VECTOR2I mid = ( aStart + aEnd ) / 2;
517
518 double dlen = sqrt( dx*dx + dy*dy );
519
520 if( !std::isnormal( dlen ) || !std::isnormal( aAngle ) )
521 {
522 // Note that we allow the floating point output here because this message is displayed to the user and should
523 // be in their locale.
524 THROW_IO_ERRORF( _( "Invalid Arc with radius %0.2f and angle %0.2f" ), //format:allow
525 dlen, aAngle );
526 }
527
528 double dist = dlen / ( 2 * tan( DEG2RAD( aAngle ) / 2 ) );
529
531 mid.x + dist * ( dy / dlen ),
532 mid.y - dist * ( dx / dlen )
533 );
534
535 return center;
536}
537
538
539static int parseAlignment( const wxString& aAlignment )
540{
541 // (bottom-left | bottom-center | bottom-right | center-left |
542 // center | center-right | top-left | top-center | top-right)
543 if( aAlignment == "center" )
544 return ETEXT::CENTER;
545 else if( aAlignment == "center-right" )
546 return ETEXT::CENTER_RIGHT;
547 else if( aAlignment == "top-left" )
548 return ETEXT::TOP_LEFT;
549 else if( aAlignment == "top-center" )
550 return ETEXT::TOP_CENTER;
551 else if( aAlignment == "top-right" )
552 return ETEXT::TOP_RIGHT;
553 else if( aAlignment == "bottom-left" )
554 return ETEXT::BOTTOM_LEFT;
555 else if( aAlignment == "bottom-center" )
557 else if( aAlignment == "bottom-right" )
558 return ETEXT::BOTTOM_RIGHT;
559 else if( aAlignment == "center-left" )
560 return ETEXT::CENTER_LEFT;
561
562 return DEFAULT_ALIGNMENT;
563}
564
565
566void EAGLE_BASE::Report( const wxString& aMsg, SEVERITY aSeverity )
567{
568 if( !io )
569 return;
570
571 io->Report( aMsg, aSeverity );
572}
573
574
576{
577 if( !io )
578 return;
579
580 io->AdvanceProgressPhase();
581}
582
583
584EWIRE::EWIRE( wxXmlNode* aWire, IO_BASE* aIo ) :
585 EAGLE_BASE( aIo )
586{
587 /*
588 * <!ELEMENT wire EMPTY>
589 * <!ATTLIST wire
590 * x1 %Coord; #REQUIRED
591 * y1 %Coord; #REQUIRED
592 * x2 %Coord; #REQUIRED
593 * y2 %Coord; #REQUIRED
594 * width %Dimension; #REQUIRED
595 * layer %Layer; #REQUIRED
596 * extent %Extent; #IMPLIED -- only applicable for airwires --
597 * style %WireStyle; "continuous"
598 * curve %WireCurve; "0"
599 * cap %WireCap; "round" -- only applicable if 'curve' is not zero --
600 * >
601 */
602
603 x1 = parseRequiredAttribute<ECOORD>( aWire, "x1" );
604 y1 = parseRequiredAttribute<ECOORD>( aWire, "y1" );
605 x2 = parseRequiredAttribute<ECOORD>( aWire, "x2" );
606 y2 = parseRequiredAttribute<ECOORD>( aWire, "y2" );
607 width = parseRequiredAttribute<ECOORD>( aWire, "width" );
608 layer = parseRequiredAttribute<int>( aWire, "layer" );
609 curve = parseOptionalAttribute<double>( aWire, "curve" );
610
612
613 if( s == "continuous" )
615 else if( s == "longdash" )
617 else if( s == "shortdash" )
619 else if( s == "dashdot" )
621
622 s = parseOptionalAttribute<wxString>( aWire, "cap" );
623
624 if( s == "round" )
626 else if( s == "flat" )
628
630}
631
632
633ESEGMENT::ESEGMENT( wxXmlNode* aSegment, IO_BASE* aIo ) :
634 EAGLE_BASE( aIo )
635{
636 /*
637 * <!ELEMENT segment (pinref | portref | wire | junction | label | probe)*>
638 * <!-- 'pinref' and 'junction' are only valid in a <net> context -->
639 */
640 for( wxXmlNode* child = aSegment->GetChildren(); child; child = child->GetNext() )
641 {
642 if( child->GetName() == "pinref" )
643 pinRefs.emplace_back( std::make_unique<EPINREF>( child, aIo ) );
644 else if( child->GetName() == "portref" )
645 portRefs.emplace_back( std::make_unique<EPORTREF>( child, aIo ) );
646 else if( child->GetName() == "wire" )
647 wires.emplace_back( std::make_unique<EWIRE>( child, aIo ) );
648 else if( child->GetName() == "junction" )
649 junctions.emplace_back( std::make_unique<EJUNCTION>( child, aIo ) );
650 else if( child->GetName() == "label" )
651 labels.emplace_back( std::make_unique<ELABEL>( child, aIo ) );
652 else if( child->GetName() == "probe" )
653 probes.emplace_back( std::make_unique<EPROBE>( child, aIo ) );
654 }
655
657}
658
659
660EBUS::EBUS( wxXmlNode* aBus, IO_BASE* aIo ) :
661 EAGLE_BASE( aIo )
662{
663 /*
664 * <!ELEMENT bus (segment)*>
665 * <!ATTLIST bus
666 * name %String; #REQUIRED
667 * >
668 */
669 name = parseRequiredAttribute<wxString>( aBus, "name" );
670
671 for( wxXmlNode* child = aBus->GetChildren(); child; child = child->GetNext() )
672 {
673 if( child->GetName() == "segment" )
674 segments.emplace_back( std::make_unique<ESEGMENT>( child, aIo ) );
675 }
676
678}
679
680
681EJUNCTION::EJUNCTION( wxXmlNode* aJunction, IO_BASE* aIo ) :
682 EAGLE_BASE( aIo )
683{
684 /*
685 * <!ELEMENT junction EMPTY>
686 * <!ATTLIST junction
687 * x %Coord; #REQUIRED
688 * y %Coord; #REQUIRED
689 * >
690 */
691
692 x = parseRequiredAttribute<ECOORD>( aJunction, "x" );
693 y = parseRequiredAttribute<ECOORD>( aJunction, "y" );
694
696}
697
698
699ELABEL::ELABEL( wxXmlNode* aLabel, IO_BASE* aIo ) :
700 EAGLE_BASE( aIo )
701{
702 /*
703 * <!ELEMENT label EMPTY>
704 * <!ATTLIST label
705 * x %Coord; #REQUIRED
706 * y %Coord; #REQUIRED
707 * size %Dimension; #REQUIRED
708 * layer %Layer; #REQUIRED
709 * font %TextFont; "proportional"
710 * ratio %Int; "8"
711 * rot %Rotation; "R0"
712 * xref %Bool; "no"
713 * align %Align; "bottom-left"
714 * grouprefs IDREFS #IMPLIED
715 * >
716 * <!-- rot: Only 0, 90, 180 or 270 -->
717 * <!-- xref: Only in <net> context -->
718 */
719 x = parseRequiredAttribute<ECOORD>( aLabel, "x" );
720 y = parseRequiredAttribute<ECOORD>( aLabel, "y" );
721 size = parseRequiredAttribute<ECOORD>( aLabel, "size" );
722 layer = parseRequiredAttribute<int>( aLabel, "layer" );
723 font = parseOptionalAttribute<wxString>( aLabel, "font" );
724 ratio = parseOptionalAttribute<int>( aLabel, "ratio" );
725 rot = parseOptionalAttribute<EROT>( aLabel, "rot" );
726 xref = parseOptionalAttribute<wxString>( aLabel, "xref" );
727 align = parseOptionalAttribute<wxString>( aLabel, "align" );
728
730}
731
732
733ENET::ENET( wxXmlNode* aNet, IO_BASE* aIo ) :
734 EAGLE_BASE( aIo )
735{
736 /*
737 * <!ELEMENT net (segment)*>
738 * <!ATTLIST net
739 * name %String; #REQUIRED
740 * class %Class; "0"
741 * >
742 */
744 netcode = parseRequiredAttribute<int>( aNet, "class" );
745
746 for( wxXmlNode* segment = aNet->GetChildren(); segment; segment = segment->GetNext() )
747 segments.emplace_back( std::make_unique<ESEGMENT>( segment ) );
748
750}
751
752
753EVIA::EVIA( wxXmlNode* aVia, IO_BASE* aIo ) :
754 EAGLE_BASE( aIo )
755{
756 /*
757 * <!ELEMENT via EMPTY>
758 * <!ATTLIST via
759 * x %Coord; #REQUIRED
760 * y %Coord; #REQUIRED
761 * extent %Extent; #REQUIRED
762 * drill %Dimension; #REQUIRED
763 * diameter %Dimension; "0"
764 * shape %ViaShape; "round"
765 * alwaysstop %Bool; "no"
766 * >
767 */
768
769 x = parseRequiredAttribute<ECOORD>( aVia, "x" );
770 y = parseRequiredAttribute<ECOORD>( aVia, "y" );
771
772 wxString ext = parseRequiredAttribute<wxString>( aVia, "extent" );
773 sscanf( ext.c_str(), "%d-%d", &layer_front_most, &layer_back_most );
774
775 drill = parseRequiredAttribute<ECOORD>( aVia, "drill" );
776 diam = parseOptionalAttribute<ECOORD>( aVia, "diameter" );
777 shape = parseOptionalAttribute<wxString>( aVia, "shape" );
778
780}
781
782
783ECIRCLE::ECIRCLE( wxXmlNode* aCircle, IO_BASE* aIo ) :
784 EAGLE_BASE( aIo )
785{
786 /*
787 * <!ELEMENT circle EMPTY>
788 * <!ATTLIST circle
789 * x %Coord; #REQUIRED
790 * y %Coord; #REQUIRED
791 * radius %Coord; #REQUIRED
792 * width %Dimension; #REQUIRED
793 * layer %Layer; #REQUIRED
794 * >
795 */
796
797 x = parseRequiredAttribute<ECOORD>( aCircle, "x" );
798 y = parseRequiredAttribute<ECOORD>( aCircle, "y" );
799 radius = parseRequiredAttribute<ECOORD>( aCircle, "radius" );
800 width = parseRequiredAttribute<ECOORD>( aCircle, "width" );
801 layer = parseRequiredAttribute<int>( aCircle, "layer" );
802
804}
805
806
807ERECT::ERECT( wxXmlNode* aRect, IO_BASE* aIo ) :
808 EAGLE_BASE( aIo )
809{
810 /*
811 * <!ELEMENT rectangle EMPTY>
812 * <!ATTLIST rectangle
813 * x1 %Coord; #REQUIRED
814 * y1 %Coord; #REQUIRED
815 * x2 %Coord; #REQUIRED
816 * y2 %Coord; #REQUIRED
817 * layer %Layer; #REQUIRED
818 * rot %Rotation; "R0"
819 * >
820 */
821
822 x1 = parseRequiredAttribute<ECOORD>( aRect, "x1" );
823 y1 = parseRequiredAttribute<ECOORD>( aRect, "y1" );
824 x2 = parseRequiredAttribute<ECOORD>( aRect, "x2" );
825 y2 = parseRequiredAttribute<ECOORD>( aRect, "y2" );
826 layer = parseRequiredAttribute<int>( aRect, "layer" );
827 rot = parseOptionalAttribute<EROT>( aRect, "rot" );
828
830}
831
832
833EDESCRIPTION::EDESCRIPTION( wxXmlNode* aDescription, IO_BASE* aIo ) :
834 EAGLE_BASE( aIo )
835{
836 /*
837 * <!ELEMENT description (#PCDATA)>
838 * <!ATTLIST description
839 * language %String; "en"
840 * >
841 */
842
843 text = aDescription->GetNodeContent();
844 language = parseOptionalAttribute<wxString>( aDescription, "language" );
845
847}
848
849
850EATTR::EATTR( wxXmlNode* aTree, IO_BASE* aIo ) :
851 EAGLE_BASE( aIo )
852{
853 /*
854 * <!ELEMENT attribute EMPTY>
855 * <!ATTLIST attribute
856 * name %String; #REQUIRED
857 * value %String; #IMPLIED
858 * x %Coord; #IMPLIED
859 * y %Coord; #IMPLIED
860 * size %Dimension; #IMPLIED
861 * layer %Layer; #IMPLIED
862 * font %TextFont; #IMPLIED
863 * ratio %Int; #IMPLIED
864 * rot %Rotation; "R0"
865 * display %AttributeDisplay; "value" -- only in <element> or <instance> context --
866 * constant %Bool; "no" -- only in <device> context --
867 * >
868 */
869
870 name = parseRequiredAttribute<wxString>( aTree, "name" );
871 value = parseOptionalAttribute<wxString>( aTree, "value" );
872
873 x = parseOptionalAttribute<ECOORD>( aTree, "x" );
874 y = parseOptionalAttribute<ECOORD>( aTree, "y" );
875 size = parseOptionalAttribute<ECOORD>( aTree, "size" );
876
877 layer = parseOptionalAttribute<int>( aTree, "layer" );
878 ratio = parseOptionalAttribute<double>( aTree, "ratio" );
879 rot = parseOptionalAttribute<EROT>( aTree, "rot" );
880
881 opt_wxString stemp = parseOptionalAttribute<wxString>( aTree, "display" );
882
883 // (off | value | name | both)
884 if( stemp == "off" )
886 else if( stemp == "name" )
888 else if( stemp == "both" )
890 else // "value" is the default
892
893 stemp = parseOptionalAttribute<wxString>( aTree, "align" );
894
895 align = stemp ? parseAlignment( *stemp ) : DEFAULT_ALIGNMENT;
896
898}
899
900
901EPINREF::EPINREF( wxXmlNode* aPinRef, IO_BASE* aIo ) :
902 EAGLE_BASE( aIo )
903{
904 /*
905 * <!ELEMENT pinref EMPTY>
906 * <!ATTLIST pinref
907 * part %String; #REQUIRED
908 * gate %String; #REQUIRED
909 * pin %String; #REQUIRED
910 * >
911 */
912 part = parseRequiredAttribute<wxString>( aPinRef, "part" );
913 gate = parseRequiredAttribute<wxString>( aPinRef, "gate" );
914 pin = parseRequiredAttribute<wxString>( aPinRef, "pin" );
915
917}
918
919
920EPORTREF::EPORTREF( wxXmlNode* aPortRef, IO_BASE* aIo ) :
921 EAGLE_BASE( aIo )
922{
923 /*
924 * <!ELEMENT portref EMPTY>
925 * <!ATTLIST portref
926 * moduleinst %String; #REQUIRED
927 * port %String; #REQUIRED
928 * >
929 */
930 moduleinst = parseRequiredAttribute<wxString>( aPortRef, "moduleinst" );
931 port = parseRequiredAttribute<wxString>( aPortRef, "port" );
932
934}
935
936
937EPROBE::EPROBE( wxXmlNode* aProbe, IO_BASE* aIo ) :
938 EAGLE_BASE( aIo )
939{
940 /*
941 * <!ELEMENT probe EMPTY>
942 * <!ATTLIST probe
943 * x %Coord; #REQUIRED
944 * y %Coord; #REQUIRED
945 * size %Dimension; #REQUIRED
946 * layer %Layer; #REQUIRED
947 * font %TextFont; "proportional"
948 * ratio %Int; "8"
949 * rot %Rotation; "R0"
950 * xref %Bool; "no"
951 * grouprefs IDREFS #IMPLIED
952 * >
953 * <!-- rot: Only 0, 90, 180 or 270 -->
954 * <!-- xref: Only in <net> context -->
955 */
956 x = parseRequiredAttribute<ECOORD>( aProbe, "x" );
957 y = parseRequiredAttribute<ECOORD>( aProbe, "y" );
958 size = parseRequiredAttribute<double>( aProbe, "size" );
959 layer = parseRequiredAttribute<int>( aProbe, "layer" );
960 font = parseOptionalAttribute<wxString>( aProbe, "font" );
961 ratio = parseOptionalAttribute<int>( aProbe, "ratio" );
962 rot = parseOptionalAttribute<EROT>( aProbe, "rot" );
963 xref = parseOptionalAttribute<bool>( aProbe, "xref" );
964
966}
967
968
969EDIMENSION::EDIMENSION( wxXmlNode* aDimension, IO_BASE* aIo ) :
970 EAGLE_BASE( aIo )
971{
972 /*
973 * <!ELEMENT dimension EMPTY>
974 * <!ATTLIST dimension
975 * x1 %Coord; #REQUIRED
976 * y1 %Coord; #REQUIRED
977 * x2 %Coord; #REQUIRED
978 * y2 %Coord; #REQUIRED
979 * x3 %Coord; #REQUIRED
980 * y3 %Coord; #REQUIRED
981 * textsize %Coord;
982 * layer %Layer; #REQUIRED
983 * dtype %DimensionType; "parallel"
984 * >
985 */
986
987 x1 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "x1" ) );
988 y1 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "y1" ) );
989 x2 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "x2" ) );
990 y2 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "y2" ) );
991 x3 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "x3" ) );
992 y3 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "y3" ) );
993 textsize = parseOptionalAttribute<ECOORD>( aDimension, wxT( "textsize" ) );
994 layer = parseRequiredAttribute<int>( aDimension, wxT( "layer" ) );
995 dimensionType = parseOptionalAttribute<wxString>( aDimension, wxT( "dtype" ) );
996
998}
999
1000
1001ETEXT::ETEXT( wxXmlNode* aText, IO_BASE* aIo ) :
1002 EAGLE_BASE( aIo )
1003{
1004 /*
1005 <!ELEMENT text (#PCDATA)>
1006 <!ATTLIST text
1007 x %Coord; #REQUIRED
1008 y %Coord; #REQUIRED
1009 size %Dimension; #REQUIRED
1010 layer %Layer; #REQUIRED
1011 font %TextFont; "proportional"
1012 ratio %Int; "8"
1013 rot %Rotation; "R0"
1014 align %Align; "bottom-left"
1015 >
1016 */
1017
1018 text = aText->GetNodeContent();
1019 x = parseRequiredAttribute<ECOORD>( aText, "x" );
1020 y = parseRequiredAttribute<ECOORD>( aText, "y" );
1021 size = parseRequiredAttribute<ECOORD>( aText, "size" );
1022 layer = parseRequiredAttribute<int>( aText, "layer" );
1023
1024 font = parseOptionalAttribute<wxString>( aText, "font" );
1025 ratio = parseOptionalAttribute<double>( aText, "ratio" );
1026 rot = parseOptionalAttribute<EROT>( aText, "rot" );
1027
1028 opt_wxString stemp = parseOptionalAttribute<wxString>( aText, "align" );
1029
1030 align = stemp ? parseAlignment( *stemp ) : DEFAULT_ALIGNMENT;
1031
1033}
1034
1035
1037{
1038 VECTOR2I textsize;
1039
1040 if( font )
1041 {
1042 const wxString& fontName = font.CGet();
1043
1044 if( fontName == "vector" )
1045 {
1046 textsize = VECTOR2I( size.ToSchUnits(), size.ToSchUnits() );
1047 }
1048 else if( fontName == "fixed" )
1049 {
1050 textsize = VECTOR2I( size.ToSchUnits(), size.ToSchUnits() * 0.80 );
1051 }
1052 else
1053 {
1054 textsize = VECTOR2I( size.ToSchUnits(), size.ToSchUnits() );
1055 }
1056 }
1057 else
1058 {
1059 textsize = VECTOR2I( size.ToSchUnits() * 0.85, size.ToSchUnits() );
1060 }
1061
1062 return textsize;
1063}
1064
1065
1067{
1068 return ConvertEagleTextSize( font, size );
1069}
1070
1071
1072EFRAME::EFRAME( wxXmlNode* aFrameNode, IO_BASE* aIo ) :
1073 EAGLE_BASE( aIo )
1074{
1075 /*
1076 * <!ELEMENT frame EMPTY>
1077 * <!ATTLIST frame
1078 * x1 %Coord; #REQUIRED
1079 * y1 %Coord; #REQUIRED
1080 * x2 %Coord; #REQUIRED
1081 * y2 %Coord; #REQUIRED
1082 * columns %Int; #REQUIRED
1083 * rows %Int; #REQUIRED
1084 * layer %Layer; #REQUIRED
1085 * border-left %Bool; "yes"
1086 * border-top %Bool; "yes"
1087 * border-right %Bool; "yes"
1088 * border-bottom %Bool; "yes"
1089 * >
1090 */
1091 border_left = true;
1092 border_top = true;
1093 border_right = true;
1094 border_bottom = true;
1095
1096 x1 = parseRequiredAttribute<ECOORD>( aFrameNode, "x1" );
1097 y1 = parseRequiredAttribute<ECOORD>( aFrameNode, "y1" );
1098 x2 = parseRequiredAttribute<ECOORD>( aFrameNode, "x2" );
1099 y2 = parseRequiredAttribute<ECOORD>( aFrameNode, "y2" );
1100 columns = parseRequiredAttribute<int>( aFrameNode, "columns" );
1101 rows = parseRequiredAttribute<int>( aFrameNode, "rows" );
1102 layer = parseRequiredAttribute<int>( aFrameNode, "layer" );
1103 border_left = parseOptionalAttribute<bool>( aFrameNode, "border-left" );
1104 border_top = parseOptionalAttribute<bool>( aFrameNode, "border-top" );
1105 border_right = parseOptionalAttribute<bool>( aFrameNode, "border-right" );
1106 border_bottom = parseOptionalAttribute<bool>( aFrameNode, "border-bottom" );
1107
1109}
1110
1111
1112EPAD_COMMON::EPAD_COMMON( wxXmlNode* aPad, IO_BASE* aIo ) :
1113 EAGLE_BASE( aIo )
1114{
1115 // #REQUIRED says DTD, throw exception if not found
1116 name = parseRequiredAttribute<wxString>( aPad, "name" );
1117 x = parseRequiredAttribute<ECOORD>( aPad, "x" );
1118 y = parseRequiredAttribute<ECOORD>( aPad, "y" );
1119 rot = parseOptionalAttribute<EROT>( aPad, "rot" );
1120 stop = parseOptionalAttribute<bool>( aPad, "stop" );
1121 thermals = parseOptionalAttribute<bool>( aPad, "thermals" );
1122}
1123
1124
1125EPAD::EPAD( wxXmlNode* aPad, IO_BASE* aIo ) :
1126 EPAD_COMMON( aPad, aIo )
1127{
1128 /*
1129 <!ELEMENT pad EMPTY>
1130 <!ATTLIST pad
1131 name %String; #REQUIRED
1132 x %Coord; #REQUIRED
1133 y %Coord; #REQUIRED
1134 drill %Dimension; #REQUIRED
1135 diameter %Dimension; "0"
1136 shape %PadShape; "round"
1137 rot %Rotation; "R0"
1138 stop %Bool; "yes"
1139 thermals %Bool; "yes"
1140 first %Bool; "no"
1141 >
1142 */
1143
1144 // #REQUIRED says DTD, but DipTrace doesn't write it sometimes
1145 drill = parseOptionalAttribute<ECOORD>( aPad, "drill" );
1146
1147 // Optional attributes
1148 diameter = parseOptionalAttribute<ECOORD>( aPad, "diameter" );
1149
1151
1152 // (square | round | octagon | long | offset)
1153 if( s == "square" )
1155 else if( s == "round" )
1157 else if( s == "octagon" )
1159 else if( s == "long" )
1160 shape = EPAD::LONG;
1161 else if( s == "offset" )
1163
1164 first = parseOptionalAttribute<bool>( aPad, "first" );
1165
1167}
1168
1169
1170ESMD::ESMD( wxXmlNode* aSMD, IO_BASE* aIo ) :
1171 EPAD_COMMON( aSMD, aIo )
1172{
1173 /*
1174 <!ATTLIST smd
1175 name %String; #REQUIRED
1176 x %Coord; #REQUIRED
1177 y %Coord; #REQUIRED
1178 dx %Dimension; #REQUIRED
1179 dy %Dimension; #REQUIRED
1180 layer %Layer; #REQUIRED
1181 roundness %Int; "0"
1182 rot %Rotation; "R0"
1183 stop %Bool; "yes"
1184 thermals %Bool; "yes"
1185 cream %Bool; "yes"
1186 >
1187 */
1188
1189 // DTD #REQUIRED, throw exception if not found
1190 dx = parseRequiredAttribute<ECOORD>( aSMD, "dx" );
1191 dy = parseRequiredAttribute<ECOORD>( aSMD, "dy" );
1192 layer = parseRequiredAttribute<int>( aSMD, "layer" );
1193
1194 roundness = parseOptionalAttribute<int>( aSMD, "roundness" );
1195 cream = parseOptionalAttribute<bool>( aSMD, "cream" );
1196
1198}
1199
1200
1201EPIN::EPIN( wxXmlNode* aPin, IO_BASE* aIo ) :
1202 EAGLE_BASE( aIo )
1203{
1204 /*
1205 <!ELEMENT pin EMPTY>
1206 <!ATTLIST pin
1207 name %String; #REQUIRED
1208 x %Coord; #REQUIRED
1209 y %Coord; #REQUIRED
1210 visible %PinVisible; "both"
1211 length %PinLength; "long"
1212 direction %PinDirection; "io"
1213 function %PinFunction; "none"
1214 swaplevel %Int; "0"
1215 rot %Rotation; "R0"
1216 >
1217 */
1218
1219 // DTD #REQUIRED, throw exception if not found
1220 name = parseRequiredAttribute<wxString>( aPin, "name" );
1221 x = parseRequiredAttribute<ECOORD>( aPin, "x" );
1222 y = parseRequiredAttribute<ECOORD>( aPin, "y" );
1223
1224 visible = parseOptionalAttribute<wxString>( aPin, "visible" );
1225 length = parseOptionalAttribute<wxString>( aPin, "length" );
1226 direction = parseOptionalAttribute<wxString>( aPin, "direction" );
1227 function = parseOptionalAttribute<wxString>( aPin, "function" );
1228 swaplevel = parseOptionalAttribute<int>( aPin, "swaplevel" );
1229 rot = parseOptionalAttribute<EROT>( aPin, "rot" );
1230
1232}
1233
1234
1235EVERTEX::EVERTEX( wxXmlNode* aVertex, IO_BASE* aIo ) :
1236 EAGLE_BASE( aIo )
1237{
1238 /*
1239 * <!ELEMENT vertex EMPTY>
1240 * <!ATTLIST vertex
1241 * x %Coord; #REQUIRED
1242 * y %Coord; #REQUIRED
1243 * curve %WireCurve; "0" -- the curvature from this vertex to the next one --
1244 * >
1245 */
1246
1247 x = parseRequiredAttribute<ECOORD>( aVertex, "x" );
1248 y = parseRequiredAttribute<ECOORD>( aVertex, "y" );
1249 curve = parseOptionalAttribute<double>( aVertex, "curve" );
1250
1252}
1253
1254
1255EPOLYGON::EPOLYGON( wxXmlNode* aPolygon, IO_BASE* aIo ) :
1256 EAGLE_BASE( aIo )
1257{
1258 /*
1259 * <!ELEMENT polygon (vertex)*>
1260 * <!-- the vertices must define a valid polygon; if the last vertex is the same
1261 * as the first one, it is ignored -->
1262 * <!ATTLIST polygon
1263 * width %Dimension; #REQUIRED
1264 * layer %Layer; #REQUIRED
1265 * spacing %Dimension; #IMPLIED
1266 * pour %PolygonPour; "solid"
1267 * isolate %Dimension; #IMPLIED
1268 * orphans %Bool; "no"
1269 * thermals %Bool; "yes"
1270 * rank %Int; "0"
1271 * grouprefs IDREFS #IMPLIED
1272 * >
1273 * <!-- isolate: Only in <signal> or <package> context -->
1274 * <!-- orphans: Only in <signal> context -->
1275 * <!-- thermals:Only in <signal> context -->
1276 * <!-- rank: 1..6 in <signal> context, 0 or 7 in <package> context -->
1277 */
1278
1279 width = parseRequiredAttribute<ECOORD>( aPolygon, "width" );
1280 layer = parseRequiredAttribute<int>( aPolygon, "layer" );
1281
1282 spacing = parseOptionalAttribute<ECOORD>( aPolygon, "spacing" );
1283 isolate = parseOptionalAttribute<ECOORD>( aPolygon, "isolate" );
1284 opt_wxString s = parseOptionalAttribute<wxString>( aPolygon, "pour" );
1285
1286 // default pour to solid fill
1288
1289 // (solid | hatch | cutout)
1290 if( s == "hatch" )
1292 else if( s == "cutout" )
1294
1295 orphans = parseOptionalAttribute<bool>( aPolygon, "orphans" );
1296 thermals = parseOptionalAttribute<bool>( aPolygon, "thermals" );
1297 rank = parseOptionalAttribute<int>( aPolygon, "rank" );
1298
1299 for( wxXmlNode* child = aPolygon->GetChildren(); child; child = child->GetNext() )
1300 {
1301 if( child->GetName() == "vertex" )
1302 vertices.emplace_back( std::make_unique<EVERTEX>( child, aIo ) );
1303 }
1304
1306}
1307
1308
1309ESPLINE::ESPLINE( wxXmlNode* aSpline, IO_BASE* aIo ) :
1310 EAGLE_BASE( aIo )
1311{
1312 /*
1313 * <!ELEMENT spline (vertex)*>
1314 * <!-- Four simple (non-curve) vertices define the control points of a degree-3 spline
1315 * curve -->
1316 * <!ATTLIST spline
1317 * width %Dimension; #REQUIRED
1318 * >
1319 */
1320 width = parseRequiredAttribute<double>( aSpline, "width" );
1321
1322 for( wxXmlNode* child = aSpline->GetChildren(); child; child = child->GetNext() )
1323 {
1324 if( child->GetName() == "vertex" )
1325 vertices.emplace_back( std::make_unique<EVERTEX>( child, aIo ) );
1326 }
1327
1329}
1330
1331
1332EVARIANT::EVARIANT( wxXmlNode* aVariant, IO_BASE* aIo ) :
1333 EAGLE_BASE( aIo )
1334{
1335 /*
1336 * <!ELEMENT variant EMPTY>
1337 * <!ATTLIST variant
1338 * name %String; #REQUIRED
1339 * populate %Bool; "yes"
1340 * value %String; #IMPLIED
1341 * technology %String; #IMPLIED
1342 * >
1343 * <!-- technology: Only in part context -->
1344 */
1345 name = parseRequiredAttribute<wxString>( aVariant, "name" );
1346 populate = parseOptionalAttribute<bool>( aVariant, "populate" );
1347 value = parseOptionalAttribute<wxString>( aVariant, "value" );
1348 technology = parseOptionalAttribute<wxString>( aVariant, "technology" );
1349
1351}
1352
1353
1354EMODEL::EMODEL( wxXmlNode* aModel, IO_BASE* aIo ) :
1355 EAGLE_BASE( aIo )
1356{
1357 /*
1358 * <!ELEMENT model (#PCDATA)>
1359 * <!ATTLIST model
1360 * name %String; #REQUIRED
1361 * >
1362 */
1363 name = parseRequiredAttribute<wxString>( aModel, "name" );
1364 model = aModel->GetNodeContent();
1365
1367}
1368
1369
1370EPINMAP::EPINMAP( wxXmlNode* aPinMap, IO_BASE* aIo ) :
1371 EAGLE_BASE( aIo )
1372{
1373 /*
1374 * <!ELEMENT pinmap EMPTY>
1375 * <!ATTLIST pinmap
1376 * gate %String; #REQUIRED
1377 * pin %String; #REQUIRED
1378 * pinorder %String; #REQUIRED
1379 * >
1380 */
1381 gate = parseRequiredAttribute<wxString>( aPinMap, "gate" );
1382 pin = parseRequiredAttribute<wxString>( aPinMap, "pin" );
1383 pinorder = parseRequiredAttribute<wxString>( aPinMap, "pinorder" );
1384
1386}
1387
1388
1389EPINMAPPING::EPINMAPPING( wxXmlNode* aPinMapping, IO_BASE* aIo ) :
1390 EAGLE_BASE( aIo )
1391{
1392 /*
1393 * <!ELEMENT pinmapping (pinmap+)>
1394 * <!ATTLIST pinmapping
1395 * isusermap %Bool; "no"
1396 * iddevicewide %Bool; "yes"
1397 * spiceprefix %String; ""
1398 * >
1399 */
1400 isusermap = parseOptionalAttribute<bool>( aPinMapping, "isusermap" );
1401 iddevicewide = parseOptionalAttribute<bool>( aPinMapping, "iddevicewide" );
1402 spiceprefix = parseOptionalAttribute<wxString>( aPinMapping, "spiceprefix" );
1403
1404 for( wxXmlNode* child = aPinMapping->GetChildren(); child; child = child->GetNext() )
1405 {
1406 if( child->GetName() == "pinmap" )
1407 pinmaps.emplace_back( std::make_unique<EPINMAP>( child, aIo ) );
1408 }
1409
1411}
1412
1413
1414ESPICE::ESPICE( wxXmlNode* aSpice, IO_BASE* aIo ) :
1415 EAGLE_BASE( aIo )
1416{
1417 /*
1418 * <!ELEMENT spice (pinmapping, model)>
1419 */
1420 pinmapping = std::make_unique<EPINMAPPING>( aSpice );
1421
1422 if( aSpice->GetName() == "model" )
1423 model = std::make_unique<EMODEL>( aSpice );
1424
1426}
1427
1428
1429EHOLE::EHOLE( wxXmlNode* aHole, IO_BASE* aIo ) :
1430 EAGLE_BASE( aIo )
1431{
1432 /*
1433 <!ELEMENT hole EMPTY>
1434 <!ATTLIST hole
1435 x %Coord; #REQUIRED
1436 y %Coord; #REQUIRED
1437 drill %Dimension; #REQUIRED
1438 >
1439 */
1440
1441 // #REQUIRED:
1442 x = parseRequiredAttribute<ECOORD>( aHole, "x" );
1443 y = parseRequiredAttribute<ECOORD>( aHole, "y" );
1444 drill = parseRequiredAttribute<ECOORD>( aHole, "drill" );
1445
1447}
1448
1449
1450EELEMENT::EELEMENT( wxXmlNode* aElement, IO_BASE* aIo ) :
1451 EAGLE_BASE( aIo )
1452{
1453 /*
1454 <!ELEMENT element (attribute*, variant*)>
1455 <!ATTLIST element
1456 name %String; #REQUIRED
1457 library %String; #REQUIRED
1458 library_urn %Urn; ""
1459 package %String; #REQUIRED
1460 package3d_urn %Urn; ""
1461 override_package3d_urn %Urn; ""
1462 override_package_urn %Urn; ""
1463 override_locally_modified %Bool; "no"
1464 value %String; #REQUIRED
1465 x %Coord; #REQUIRED
1466 y %Coord; #REQUIRED
1467 locked %Bool; "no"
1468 populate %Bool; "yes"
1469 smashed %Bool; "no"
1470 rot %Rotation; "R0"
1471 grouprefs IDREFS #IMPLIED
1472 >
1473 */
1474
1475 // #REQUIRED
1476 name = parseRequiredAttribute<wxString>( aElement, "name" );
1477 library = parseRequiredAttribute<wxString>( aElement, "library" );
1478 value = parseRequiredAttribute<wxString>( aElement, "value" );
1479 std::string p = parseRequiredAttribute<std::string>( aElement, "package" );
1481 package = wxString::FromUTF8( p.c_str() );
1482
1483 x = parseRequiredAttribute<ECOORD>( aElement, "x" );
1484 y = parseRequiredAttribute<ECOORD>( aElement, "y" );
1485
1486 // optional
1487 library_urn = parseOptionalAttribute<EURN>( aElement, "library_urn" );
1488 locked = parseOptionalAttribute<bool>( aElement, "locked" );
1489 smashed = parseOptionalAttribute<bool>( aElement, "smashed" );
1490 rot = parseOptionalAttribute<EROT>( aElement, "rot" );
1491
1492 for( wxXmlNode* child = aElement->GetChildren(); child; child = child->GetNext() )
1493 {
1494 if( child->GetName() == "attribute" )
1495 {
1496 std::unique_ptr<EATTR> attr = std::make_unique<EATTR>( child, aIo );
1497 attributes[ attr->name ] = std::move( attr );
1498 }
1499 else if( child->GetName() == "variant" )
1500 {
1501 std::unique_ptr<EVARIANT> variant = std::make_unique<EVARIANT>( child, aIo );
1502 variants[ variant->name ] = std::move( variant );
1503 }
1504 }
1505
1507}
1508
1509
1510ELAYER::ELAYER( wxXmlNode* aLayer, IO_BASE* aIo ) :
1511 EAGLE_BASE( aIo )
1512{
1513 /*
1514 <!ELEMENT layer EMPTY>
1515 <!ATTLIST layer
1516 number %Layer; #REQUIRED
1517 name %String; #REQUIRED
1518 color %Int; #REQUIRED
1519 fill %Int; #REQUIRED
1520 visible %Bool; "yes"
1521 active %Bool; "yes"
1522 >
1523 */
1524
1525 number = parseRequiredAttribute<int>( aLayer, "number" );
1526 name = parseRequiredAttribute<wxString>( aLayer, "name" );
1527 color = parseRequiredAttribute<int>( aLayer, "color" );
1528 fill = parseRequiredAttribute<int>( aLayer, "fill" );
1529 visible = parseOptionalAttribute<bool>( aLayer, "visible" );
1530 active = parseOptionalAttribute<bool>( aLayer, "active" );
1531
1533}
1534
1535
1536EPART::EPART( wxXmlNode* aPart, IO_BASE* aIo ) :
1537 EAGLE_BASE( aIo )
1538{
1539 /*
1540 * <!ELEMENT part (attribute*, variant*)>
1541 * <!ATTLIST part
1542 * name %String; #REQUIRED
1543 * library %String; #REQUIRED
1544 * deviceset %String; #REQUIRED
1545 * device %String; #REQUIRED
1546 * technology %String; ""
1547 * value %String; #IMPLIED
1548 * >
1549 */
1550 name = parseRequiredAttribute<wxString>( aPart, "name" );
1551 library = parseRequiredAttribute<wxString>( aPart, "library" );
1552 libraryUrn = parseOptionalAttribute<EURN>( aPart, "library_urn" );
1553 deviceset = parseRequiredAttribute<wxString>( aPart, "deviceset" );
1554 device = parseRequiredAttribute<wxString>( aPart, "device" );
1555 package3d_urn = parseOptionalAttribute<wxString>( aPart, "package3d_urn" );
1556 override_package3d_urn = parseOptionalAttribute<wxString>( aPart, "override_package3d_urn" );
1557 override_package_urn = parseOptionalAttribute<wxString>( aPart, "override_package_urn" );
1558 override_locally_modified = parseOptionalAttribute<bool>( aPart, "override_locally_modified" );
1559 technology = parseOptionalAttribute<wxString>( aPart, "technology" );
1560 value = parseOptionalAttribute<wxString>( aPart, "value" );
1561
1562 for( wxXmlNode* child = aPart->GetChildren(); child; child = child->GetNext() )
1563 {
1564 if( child->GetName() == "attribute" )
1565 {
1566 std::unique_ptr<EATTR> attr = std::make_unique<EATTR>( child, aIo );
1567 attributes[ attr->name ] = std::move( attr );
1568 }
1569 else if( child->GetName() == "variant" )
1570 {
1571 std::unique_ptr<EVARIANT> variant = std::make_unique<EVARIANT>( child, aIo );
1572 variants[ variant->name ] = std::move( variant );
1573 }
1574 else if( child->GetName() == "spice" )
1575 {
1576 spice = std::make_unique<ESPICE>( child, aIo );
1577 }
1578 }
1579
1581}
1582
1583
1584EINSTANCE::EINSTANCE( wxXmlNode* aInstance, IO_BASE* aIo ) :
1585 EAGLE_BASE( aIo )
1586{
1587 /*
1588 * <!ELEMENT instance (attribute)*>
1589 * <!ATTLIST instance
1590 * part %String; #REQUIRED
1591 * gate %String; #REQUIRED
1592 * x %Coord; #REQUIRED
1593 * y %Coord; #REQUIRED
1594 * smashed %Bool; "no"
1595 * rot %Rotation; "R0"
1596 * >
1597 */
1598 part = parseRequiredAttribute<wxString>( aInstance, "part" );
1599 gate = parseRequiredAttribute<wxString>( aInstance, "gate" );
1600
1601 x = parseRequiredAttribute<ECOORD>( aInstance, "x" );
1602 y = parseRequiredAttribute<ECOORD>( aInstance, "y" );
1603
1604 // optional
1605 smashed = parseOptionalAttribute<bool>( aInstance, "smashed" );
1606 rot = parseOptionalAttribute<EROT>( aInstance, "rot" );
1607
1608 for( wxXmlNode* child = aInstance->GetChildren(); child; child = child->GetNext() )
1609 {
1610 if( child->GetName() == "attribute" )
1611 {
1612 std::unique_ptr<EATTR> attr = std::make_unique<EATTR>( child, aIo );
1613 attributes[ attr->name ] = std::move( attr );
1614 }
1615 }
1616
1618}
1619
1620
1621EGATE::EGATE( wxXmlNode* aGate, IO_BASE* aIo ) :
1622 EAGLE_BASE( aIo )
1623{
1624 /*
1625 * <!ELEMENT gate EMPTY>
1626 * <!ATTLIST gate
1627 * name %String; #REQUIRED
1628 * symbol %String; #REQUIRED
1629 * x %Coord; #REQUIRED
1630 * y %Coord; #REQUIRED
1631 * addlevel %GateAddLevel; "next"
1632 * swaplevel %Int; "0"
1633 * >
1634 */
1635
1636 name = parseRequiredAttribute<wxString>( aGate, "name" );
1637 symbol = parseRequiredAttribute<wxString>( aGate, "symbol" );
1638
1639 x = parseRequiredAttribute<ECOORD>( aGate, "x" );
1640 y = parseRequiredAttribute<ECOORD>( aGate, "y" );
1641
1642 opt_wxString stemp = parseOptionalAttribute<wxString>( aGate, "addlevel" );
1643
1644 // (off | value | name | both)
1645 if( stemp == "must" )
1647 else if( stemp == "can" )
1649 else if( stemp == "next" )
1651 else if( stemp == "request" )
1653 else if( stemp == "always" )
1655 else
1657
1658 swaplevel = parseOptionalAttribute<int>( aGate, "swaplevel" );
1659
1661}
1662
1663
1664ECONNECT::ECONNECT( wxXmlNode* aConnect, IO_BASE* aIo ) :
1665 EAGLE_BASE( aIo )
1666{
1667 /*
1668 * <!ELEMENT connect EMPTY>
1669 * <!ATTLIST connect
1670 * gate %String; #REQUIRED
1671 * pin %String; #REQUIRED
1672 * pad %String; #REQUIRED
1673 * route %ContactRoute; "all"
1674 * >
1675 */
1676 gate = parseRequiredAttribute<wxString>( aConnect, "gate" );
1677 pin = parseRequiredAttribute<wxString>( aConnect, "pin" );
1678 pad = parseRequiredAttribute<wxString>( aConnect, "pad" );
1679 contactroute = parseOptionalAttribute<wxString>( aConnect, "contactroute" );
1680
1682}
1683
1684
1685ETECHNOLOGY::ETECHNOLOGY( wxXmlNode* aTechnology, IO_BASE* aIo ) :
1686 EAGLE_BASE( aIo )
1687{
1688 /*
1689 * <!ELEMENT technology (attribute)*>
1690 * <!ATTLIST technology
1691 * name %String; #REQUIRED
1692 * >
1693 */
1694 name = parseRequiredAttribute<wxString>( aTechnology, "name" );
1695
1696 for( wxXmlNode* child = aTechnology->GetChildren(); child; child = child->GetNext() )
1697 {
1698 if( child->GetName() == "attribute" )
1699 attributes.emplace_back( std::make_unique<EATTR>( child, aIo ) );
1700 }
1701
1703}
1704
1705
1706EPACKAGE3DINST::EPACKAGE3DINST( wxXmlNode* aPackage3dInst, IO_BASE* aIo ) :
1707 EAGLE_BASE( aIo )
1708{
1709 /*
1710 * <!ELEMENT package3dinstance EMPTY>
1711 * <!ATTLIST package3dinstance
1712 * package3d_urn %Urn; #REQUIRED
1713 * >
1714 */
1715 package3d_urn = parseRequiredAttribute<wxString>( aPackage3dInst, "package3d_urn" );
1716
1718}
1719
1720
1721EDEVICE::EDEVICE( wxXmlNode* aDevice, IO_BASE* aIo ) :
1722 EAGLE_BASE( aIo )
1723{
1724 /*
1725 * <!ELEMENT device (connects?, package3dinstances?, technologies?)>
1726 * <!ATTLIST device
1727 * name %String; ""
1728 * package %String; #IMPLIED
1729 */
1730 name = parseRequiredAttribute<wxString>( aDevice, "name" );
1731 opt_wxString pack = parseOptionalAttribute<wxString>( aDevice, "package" );
1732
1733 if( pack )
1734 {
1735 std::string p( pack->c_str() );
1737 package.Set( wxString::FromUTF8( p.c_str() ) );
1738 }
1739
1740 for( wxXmlNode* child = aDevice->GetChildren(); child; child = child->GetNext() )
1741 {
1742 if( child->GetName() == "connects" )
1743 {
1744 for( wxXmlNode* connect = child->GetChildren(); connect; connect = connect->GetNext() )
1745 {
1746 if( connect->GetName() == "connect" )
1747 connects.emplace_back( std::make_unique<ECONNECT>( connect, aIo ) );
1748 }
1749
1751 }
1752 else if( child->GetName() == "packages3dinstances" )
1753 {
1754 for( wxXmlNode* package3dinst = child->GetChildren(); package3dinst;
1755 package3dinst = package3dinst->GetNext() )
1756 {
1757 if( package3dinst->GetName() == "package3dinstance" )
1758 package3dinstances.emplace_back( std::make_unique<EPACKAGE3DINST>( package3dinst, aIo ) );
1759 }
1760
1762 }
1763 else if( child->GetName() == "technologies" )
1764 {
1765 for( wxXmlNode* technology = child->GetChildren(); technology; technology = technology->GetNext() )
1766 {
1767 if( technology->GetName() == "technology" )
1768 {
1769 std::unique_ptr<ETECHNOLOGY> tmp = std::make_unique<ETECHNOLOGY>( technology, aIo );
1770 technologies[tmp->name] = std::move( tmp );
1771 }
1772 }
1773
1775 }
1776 }
1777
1779}
1780
1781
1782EDEVICE_SET::EDEVICE_SET( wxXmlNode* aDeviceSet, IO_BASE* aIo ) :
1783 EAGLE_BASE( aIo )
1784{
1785 /*
1786 * <!ELEMENT deviceset (description?, gates, devices, spice?)>
1787 * <!ATTLIST deviceset
1788 * name %String; #REQUIRED
1789 * urn %Urn; ""
1790 * locally_modified %Bool; "no"
1791 * prefix %String; ""
1792 * uservalue %Bool; "no"
1793 * library_version %Int; ""
1794 * library_locally_modified %Bool; "no"
1795 * >
1796 * <!-- library_version and library_locally_modified: Only in managed libraries
1797 * inside boards or schematics -->
1798 */
1799 name = parseRequiredAttribute<wxString>( aDeviceSet, "name" );
1800 urn = parseOptionalAttribute<EURN>( aDeviceSet, "urn" );
1801 locally_modified = parseOptionalAttribute<bool>( aDeviceSet, "locally_modified" );
1802 prefix = parseOptionalAttribute<wxString>( aDeviceSet, "prefix" );
1803 uservalue = parseOptionalAttribute<bool>( aDeviceSet, "uservalue" );
1804 library_version = parseOptionalAttribute<int>( aDeviceSet, "library_version" );
1806 parseOptionalAttribute<bool>( aDeviceSet, "library_locally_modified" );
1807
1808 for( wxXmlNode* child = aDeviceSet->GetChildren(); child; child = child->GetNext() )
1809 {
1810 if( child->GetName() == "description" )
1811 {
1812 description = std::make_optional<EDESCRIPTION>( child, aIo );
1813 }
1814 else if( child->GetName() == "gates" )
1815 {
1816 for( wxXmlNode* gate = child->GetChildren(); gate; gate = gate->GetNext() )
1817 {
1818 std::unique_ptr<EGATE> tmp = std::make_unique<EGATE>( gate, aIo );
1819 gates[tmp->name] = std::move( tmp );
1820 }
1821
1823 }
1824 else if( child->GetName() == "devices" )
1825 {
1826 for( wxXmlNode* device = child->GetChildren(); device; device = device->GetNext() )
1827 {
1828 std::unique_ptr<EDEVICE> tmp = std::make_unique<EDEVICE>( device, aIo );
1829 devices[tmp->name] = std::move( tmp );
1830 }
1831
1833 }
1834 else if( child->GetName() == "spice" )
1835 {
1836 spice = std::make_optional<ESPICE>( child, aIo );
1837 }
1838 }
1839
1841}
1842
1843
1844ECLASS::ECLASS( wxXmlNode* aClass, IO_BASE* aIo ) :
1845 EAGLE_BASE( aIo )
1846{
1847 /*
1848 * <!ELEMENT class (clearance)*>
1849 * <!ATTLIST class
1850 * number %Class; #REQUIRED
1851 * name %String; #REQUIRED
1852 * width %Dimension; "0"
1853 * drill %Dimension; "0"
1854 * >
1855 */
1856 number = parseRequiredAttribute<wxString>( aClass, "number" );
1857 name = parseRequiredAttribute<wxString>( aClass, "name" );
1858 width = parseOptionalAttribute<ECOORD>( aClass, "width" );
1859 drill = parseOptionalAttribute<ECOORD>( aClass, "drill" );
1860
1861 for( wxXmlNode* child = aClass->GetChildren(); child; child = child->GetNext() )
1862 {
1863 if( child->GetName() == "clearance" )
1864 {
1865 wxString to = parseRequiredAttribute<wxString>( child, "class" );
1866 ECOORD value = parseRequiredAttribute<ECOORD>( child, "value" );
1867
1868 clearanceMap[to] = value;
1869
1871 }
1872 }
1873
1875}
1876
1877
1878EPLAIN::EPLAIN( wxXmlNode* aPlain, IO_BASE* aIo ) :
1879 EAGLE_BASE( aIo )
1880{
1881 /*
1882 * <!ELEMENT plain (polygon | wire | text | dimension | circle | spline | rectangle |
1883 * frame | hole)*>
1884 */
1885 for( wxXmlNode* child = aPlain->GetChildren(); child; child = child->GetNext() )
1886 {
1887 if( child->GetName() == "polygon" )
1888 polygons.emplace_back( std::make_unique<EPOLYGON>( child, aIo ) );
1889 else if( child->GetName() == "wire" )
1890 wires.emplace_back( std::make_unique<EWIRE>( child, aIo ) );
1891 else if( child->GetName() == "text" )
1892 texts.emplace_back( std::make_unique<ETEXT>( child, aIo ) );
1893 else if( child->GetName() == "dimension" )
1894 dimensions.emplace_back( std::make_unique<EDIMENSION>( child, aIo ) );
1895 else if( child->GetName() == "circle" )
1896 circles.emplace_back( std::make_unique<ECIRCLE>( child, aIo ) );
1897 else if( child->GetName() == "spline" )
1898 splines.emplace_back( std::make_unique<ESPLINE>( child, aIo ) );
1899 else if( child->GetName() == "rectangle" )
1900 rectangles.emplace_back( std::make_unique<ERECT>( child, aIo ) );
1901 else if( child->GetName() == "frame" )
1902 frames.emplace_back( std::make_unique<EFRAME>( child, aIo ) );
1903 else if( child->GetName() == "hole" )
1904 holes.emplace_back( std::make_unique<EHOLE>( child, aIo ) );
1905 }
1906
1908}
1909
1910
1911EMODULEINST::EMODULEINST( wxXmlNode* aModuleInst, IO_BASE* aIo ) :
1912 EAGLE_BASE( aIo )
1913{
1914 /*
1915 * <!ELEMENT moduleinst (attribute)*>
1916 * <!ATTLIST moduleinst
1917 * name %String; #REQUIRED
1918 * module %String; #REQUIRED
1919 * modulevariant %String; ""
1920 * x %Coord; #REQUIRED
1921 * y %Coord; #REQUIRED
1922 * offset %Int; "0"
1923 * smashed %Bool; "no"
1924 * rot %Rotation; "R0"
1925 * >
1926 * <!-- rot: Only 0, 90, 180 or 270 -->
1927 */
1928 name = parseRequiredAttribute<wxString>( aModuleInst, "name" );
1929 moduleinst = parseRequiredAttribute<wxString>( aModuleInst, "module" );
1930 moduleVariant = parseOptionalAttribute<wxString>( aModuleInst, "modulevariant" );
1931 x = parseRequiredAttribute<ECOORD>( aModuleInst, "x" );
1932 y = parseRequiredAttribute<ECOORD>( aModuleInst, "y" );
1933 offset = parseOptionalAttribute<int>( aModuleInst, "offset" );
1934 smashed = parseOptionalAttribute<bool>( aModuleInst, "smashed" );
1935 rotation = parseOptionalAttribute<EROT>( aModuleInst, "rot" );
1936
1938}
1939
1940
1941ESHEET::ESHEET( wxXmlNode* aSheet, IO_BASE* aIo ) :
1942 EAGLE_BASE( aIo )
1943{
1944 /*
1945 * <!ELEMENT sheet (description?, plain?, moduleinsts?, instances?, busses?, nets?)>
1946 */
1947 for( wxXmlNode* child = aSheet->GetChildren(); child; child = child->GetNext() )
1948 {
1949 if( child->GetName() == "description" )
1950 {
1951 description = std::make_optional<EDESCRIPTION>( child, aIo );
1952 }
1953 else if( child->GetName() == "plain" )
1954 {
1955 plain = std::make_unique<EPLAIN>( child, aIo );
1956 }
1957 else if( child->GetName() == "moduleinsts" )
1958 {
1959 for( wxXmlNode* moduleinst = child->GetChildren(); moduleinst;
1960 moduleinst = moduleinst->GetNext() )
1961 {
1962 if( moduleinst->GetName() == "moduleinst" )
1963 {
1964 std::unique_ptr<EMODULEINST> inst = std::make_unique<EMODULEINST>( moduleinst, aIo );
1965 moduleinsts[ inst->name ] = std::move( inst );
1966 }
1967 }
1968
1970 }
1971 else if( child->GetName() == "instances" )
1972 {
1973 for( wxXmlNode* instance = child->GetChildren(); instance; instance = instance->GetNext() )
1974 {
1975 if( instance->GetName() == "instance" )
1976 instances.emplace_back( std::make_unique<EINSTANCE>( instance, aIo ) );
1977 }
1978
1979 AdvanceProgressPhase();
1980 }
1981 else if( child->GetName() == "busses" )
1982 {
1983 for( wxXmlNode* bus = child->GetChildren(); bus; bus = bus->GetNext() )
1984 {
1985 if( bus->GetName() == "bus" )
1986 busses.emplace_back( std::make_unique<EBUS>( bus, aIo ) );
1987 }
1988
1989 AdvanceProgressPhase();
1990 }
1991 else if( child->GetName() == "nets" )
1992 {
1993 for( wxXmlNode* net = child->GetChildren(); net; net = net->GetNext() )
1994 {
1995 if( net->GetName() == "net" )
1996 nets.emplace_back( std::make_unique<ENET>( net, aIo ) );
1997 }
1998
1999 AdvanceProgressPhase();
2000 }
2001 }
2002
2003 AdvanceProgressPhase();
2004}
2005
2006
2007ESCHEMATIC_GROUP::ESCHEMATIC_GROUP( wxXmlNode* aSchematicGroup, IO_BASE* aIo ) :
2008 EAGLE_BASE( aIo )
2009{
2010 /*
2011 * <!ELEMENT schematic_group (attribute*, description?)>
2012 * <!ATTLIST schematic_group
2013 * name ID #REQUIRED
2014 * selectable %Bool; #IMPLIED
2015 * width %Dimension; #IMPLIED
2016 * titleSize %Dimension; #IMPLIED
2017 * titleFont %TextFont; #IMPLIED
2018 * style %WireStyle; #IMPLIED
2019 * showAnnotations %Bool; #IMPLIED
2020 * layer %Layer; #IMPLIED
2021 * grouprefs IDREFS #IMPLIED
2022 * >
2023 */
2024 name = parseRequiredAttribute<wxString>( aSchematicGroup, "name" );
2025 selectable = parseOptionalAttribute<bool>( aSchematicGroup, "selectable" );
2026 width = parseOptionalAttribute<ECOORD>( aSchematicGroup, "width" );
2027 titleSize = parseOptionalAttribute<ECOORD>( aSchematicGroup, "titleSize" );
2028 titleFont = parseOptionalAttribute<wxString>( aSchematicGroup, "font" );
2029 wireStyle = parseOptionalAttribute<wxString>( aSchematicGroup, "style" );
2030 showAnnotations = parseOptionalAttribute<bool>( aSchematicGroup, "showAnnotations" );
2031 layer = parseOptionalAttribute<int>( aSchematicGroup, "layer" );
2032 grouprefs = parseOptionalAttribute<wxString>( aSchematicGroup, "grouprefs" );
2033
2034 for( wxXmlNode* child = aSchematicGroup->GetChildren(); child; child = child->GetNext() )
2035 {
2036 if( child->GetName() == "description" )
2037 {
2038 description = std::make_optional<EDESCRIPTION>( child, aIo );
2039 }
2040 else if( child->GetName() == "attribute" )
2041 {
2042 attributes.emplace_back( std::make_unique<EATTR>( child, aIo ) );
2043 }
2044 }
2045
2047}
2048
2049
2050EMODULE::EMODULE( wxXmlNode* aModule, IO_BASE* aIo ) :
2051 EAGLE_BASE( aIo )
2052{
2053 /*
2054 * <!ELEMENT module (description?, ports?, variantdefs?, groups?, parts?, sheets?)>
2055 * <!ATTLIST module
2056 * name %String; #REQUIRED
2057 * prefix %String; ""
2058 * dx %Coord; #REQUIRED
2059 * dy %Coord; #REQUIRED
2060 * >
2061 */
2062 name = parseRequiredAttribute<wxString>( aModule, "name" );
2063 prefix = parseOptionalAttribute<wxString>( aModule, "prefix" );
2064 dx = parseRequiredAttribute<ECOORD>( aModule, "dx" );
2065 dy = parseRequiredAttribute<ECOORD>( aModule, "dy" );
2066
2067 for( wxXmlNode* child = aModule->GetChildren(); child; child = child->GetNext() )
2068 {
2069 if( child->GetName() == "description" )
2070 {
2071 description = std::make_optional<EDESCRIPTION>( child, aIo );
2072 }
2073 else if( child->GetName() == "ports" )
2074 {
2075 for( wxXmlNode* port = child->GetChildren(); port; port = port->GetNext() )
2076 {
2077 if( port->GetName() == "port" )
2078 {
2079 std::unique_ptr<EPORT> tmp = std::make_unique<EPORT>( port, aIo );
2080 ports[ tmp->name ] = std::move( tmp );
2081 }
2082 }
2083
2085 }
2086 else if( child->GetName() == "variantdefs" )
2087 {
2088 for( wxXmlNode* variantdef = child->GetChildren(); variantdef;
2089 variantdef = variantdef->GetNext() )
2090 {
2091 if( variantdef->GetName() == "variantdef" )
2092 {
2093 std::unique_ptr<EVARIANTDEF> tmp = std::make_unique<EVARIANTDEF>( variantdef,
2094 aIo );
2095 variantdefs[ tmp->name ] = std::move( tmp );
2096 }
2097 }
2098
2100 }
2101 else if( child->GetName() == "groups" )
2102 {
2103 for( wxXmlNode* group = child->GetChildren(); group; group = group->GetNext() )
2104 {
2105 if( group->GetName() == "schematic_group" )
2106 {
2107 std::unique_ptr<ESCHEMATIC_GROUP> tmp =
2108 std::make_unique<ESCHEMATIC_GROUP>( group, aIo );
2109 groups[ tmp->name ] = std::move( tmp );
2110 }
2111 }
2112
2114 }
2115 else if( child->GetName() == "parts" )
2116 {
2117 for( wxXmlNode* part = child->GetChildren(); part; part = part->GetNext() )
2118 {
2119 if( part->GetName() == "part" )
2120 {
2121 std::unique_ptr<EPART> tmp = std::make_unique<EPART>( part, aIo );
2122 parts[ tmp->name ] = std::move( tmp );
2123 }
2124 }
2125
2127 }
2128 else if( child->GetName() == "sheets" )
2129 {
2130 for( wxXmlNode* sheet = child->GetChildren(); sheet; sheet = sheet->GetNext() )
2131 {
2132 if( sheet->GetName() == "sheet" )
2133 sheets.emplace_back( std::make_unique<ESHEET>( sheet, aIo ) );
2134 }
2135
2137 }
2138 }
2139
2141}
2142
2143
2144EPORT::EPORT( wxXmlNode* aPort, IO_BASE* aIo ) :
2145 EAGLE_BASE( aIo )
2146{
2147 /*
2148 * <!ELEMENT port EMPTY>
2149 * <!ATTLIST port
2150 * name %String; #REQUIRED
2151 * side %Int; #REQUIRED
2152 * coord %Coord; #REQUIRED
2153 * direction %PortDirection; "io"
2154 * >
2155 */
2156 name = parseRequiredAttribute<wxString>( aPort, "name" );
2157 side = parseRequiredAttribute<wxString>( aPort, "side" );
2158 coord = parseRequiredAttribute<ECOORD>( aPort, "coord" );
2159 direction = parseOptionalAttribute<wxString>( aPort, "direction" );
2160
2162}
2163
2164
2165EVARIANTDEF::EVARIANTDEF( wxXmlNode* aVariantDef, IO_BASE* aIo ) :
2166 EAGLE_BASE( aIo )
2167{
2168 /*
2169 * <!ELEMENT variantdef EMPTY>
2170 * <!ATTLIST variantdef
2171 * name %String; #REQUIRED
2172 * current %Bool; "no"
2173 * >
2174 */
2175 name = parseRequiredAttribute<wxString>( aVariantDef, "name" );
2176 current = parseOptionalAttribute<bool>( aVariantDef, "current" );
2177
2179}
2180
2181
2182ENOTE::ENOTE( wxXmlNode* aNote, IO_BASE* aIo ) :
2183 EAGLE_BASE( aIo )
2184{
2185 /*
2186 * <!ELEMENT note (#PCDATA)>
2187 * <!ATTLIST note
2188 * version %Real; #REQUIRED
2189 * severity %Severity; #REQUIRED
2190 * >
2191 * <!-- version: The EAGLE program version that introduced this compatibility note -->
2192 */
2193 version = parseRequiredAttribute<double>( aNote, "version" );
2194 severity = parseRequiredAttribute<wxString>( aNote, "severity" );
2195
2196 note = aNote->GetNodeContent();
2197
2199}
2200
2201
2202ECOMPATIBILITY::ECOMPATIBILITY( wxXmlNode* aCompatibility, IO_BASE* aIo ) :
2203 EAGLE_BASE( aIo )
2204{
2205 /*
2206 * <!ELEMENT compatibility (note)*>
2207 */
2208 for( wxXmlNode* child = aCompatibility->GetNext(); child; child = child->GetNext() )
2209 {
2210 if( child->GetName() == "note" )
2211 notes.emplace_back( std::make_unique<ENOTE>( child ) );
2212 }
2213
2215}
2216
2217
2218ESETTING::ESETTING( wxXmlNode* aSetting, IO_BASE* aIo ) :
2219 EAGLE_BASE( aIo )
2220{
2221 /*
2222 * <!ELEMENT setting EMPTY>
2223 * <!ATTLIST setting
2224 * alwaysvectorfont %Bool; #IMPLIED
2225 * verticaltext %VerticalText; "up"
2226 * keepoldvectorfont %Bool; "no"
2227 * >
2228 */
2229 alwaysvectorfont = parseOptionalAttribute<bool>( aSetting, "alwaysvectorfont" );
2230 verticaltext = parseOptionalAttribute<wxString>( aSetting, "verticaltext" );
2231 keepoldvectorfont = parseOptionalAttribute<bool>( aSetting, "keepoldvectorfont" );
2232
2234}
2235
2236
2237EGRID::EGRID( wxXmlNode* aGrid, IO_BASE* aIo ) :
2238 EAGLE_BASE( aIo )
2239{
2240 /*
2241 * <!ELEMENT grid EMPTY>
2242 * <!ATTLIST grid
2243 * distance %Real; #IMPLIED
2244 * unitdist %GridUnit; #IMPLIED
2245 * unit %GridUnit; #IMPLIED
2246 * style %GridStyle; "lines"
2247 * multiple %Int; "1"
2248 * display %Bool; "no"
2249 * altdistance %Real; #IMPLIED
2250 * altunitdist %GridUnit; #IMPLIED
2251 * altunit %GridUnit; #IMPLIED
2252 * >
2253 */
2254 distance = parseOptionalAttribute<double>( aGrid, "distance" );
2255 unitdist = parseOptionalAttribute<wxString>( aGrid, "unitdist" );
2256 unit = parseOptionalAttribute<wxString>( aGrid, "unit" );
2257 style = parseOptionalAttribute<wxString>( aGrid, "style" );
2258 multiple = parseOptionalAttribute<int>( aGrid, "multiple" );
2259 display = parseOptionalAttribute<bool>( aGrid, "display" );
2260 altdistance = parseOptionalAttribute<double>( aGrid, "altdistance" );
2261 altunitdist = parseOptionalAttribute<wxString>( aGrid, "altunitdist" );
2262 altunit = parseOptionalAttribute<wxString>( aGrid, "altunit" );
2263
2265}
2266
2267
2268EFILTER::EFILTER( wxXmlNode* aFilter, IO_BASE* aIo ) :
2269 EAGLE_BASE( aIo )
2270{
2271 /*
2272 * <!ELEMENT filter EMPTY>
2273 * <!ATTLIST filter
2274 * name %String; #REQUIRED
2275 * expression %String; #REQUIRED
2276 * >
2277 */
2278 name = parseRequiredAttribute<wxString>( aFilter, "name" );
2279 expression = parseRequiredAttribute<wxString>( aFilter, "expression" );
2280
2282};
2283
2284
2285EPACKAGE::EPACKAGE( wxXmlNode* aPackage, IO_BASE* aIo ) :
2286 EAGLE_BASE( aIo )
2287{
2288 /*
2289 * <!ELEMENT package (description?, (polygon | wire | text | dimension | circle |
2290 * rectangle | frame | hole | pad | smd)*)>
2291 * <!ATTLIST package
2292 * name %String; #REQUIRED
2293 * urn %Urn; ""
2294 * locally_modified %Bool; "no"
2295 * library_version %Int; ""
2296 * library_locally_modified %Bool; "no"
2297 * >
2298 * <!-- library_version and library_locally_modified: Only in managed libraries
2299 * inside boards or schematics -->
2300 */
2301 name = parseRequiredAttribute<wxString>( aPackage, "name" );
2302 urn = parseOptionalAttribute<EURN>( aPackage, "urn" );
2303 locally_modified = parseOptionalAttribute<bool>( aPackage, "locally_modified" );
2304 library_version = parseOptionalAttribute<int>( aPackage, "library_version" );
2305 library_locally_modified = parseOptionalAttribute<bool>( aPackage, "library_locally_modified" );
2306
2307 for( wxXmlNode* child = aPackage->GetChildren(); child; child = child->GetNext() )
2308 {
2309 if( child->GetName() == "description" )
2310 {
2311 description = std::make_optional<EDESCRIPTION>( child, aIo );
2312 }
2313 else if( child->GetName() == "polygon" )
2314 {
2315 polygons.emplace_back( std::make_unique<EPOLYGON>( child, aIo ) );
2316 }
2317 else if( child->GetName() == "wire" )
2318 {
2319 wires.emplace_back( std::make_unique<EWIRE>( child, aIo ) );
2320 }
2321 else if( child->GetName() == "text" )
2322 {
2323 texts.emplace_back( std::make_unique<ETEXT>( child, aIo ) );
2324 }
2325 else if( child->GetName() == "dimension" )
2326 {
2327 dimensions.emplace_back( std::make_unique<EDIMENSION>( child, aIo ) );
2328 }
2329 else if( child->GetName() == "circle" )
2330 {
2331 circles.emplace_back( std::make_unique<ECIRCLE>( child, aIo ) );
2332 }
2333 else if( child->GetName() == "rectangle" )
2334 {
2335 rectangles.emplace_back( std::make_unique<ERECT>( child, aIo ) );
2336 }
2337 else if( child->GetName() == "frame" )
2338 {
2339 frames.emplace_back( std::make_unique<EFRAME>( child, aIo ) );
2340 }
2341 else if( child->GetName() == "hole" )
2342 {
2343 holes.emplace_back( std::make_unique<EHOLE>( child, aIo ) );
2344 }
2345 else if( child->GetName() == "pad" )
2346 {
2347 thtpads.emplace_back( std::make_unique<EPAD>( child, aIo ) );
2348 }
2349 else if( child->GetName() == "smd" )
2350 {
2351 smdpads.emplace_back( std::make_unique<ESMD>( child, aIo ) );
2352 }
2353 }
2354
2356}
2357
2358
2359EPACKAGEINSTANCE::EPACKAGEINSTANCE( wxXmlNode* aPackageInstance, IO_BASE* aIo ) :
2360 EAGLE_BASE( aIo )
2361{
2362 /*
2363 * <!ELEMENT packageinstance EMPTY>
2364 * <!ATTLIST packageinstance
2365 * name %String; #REQUIRED
2366 * >
2367 */
2368 name = parseRequiredAttribute<wxString>( aPackageInstance, "name" );
2369
2371}
2372
2373
2374EPACKAGE3D::EPACKAGE3D( wxXmlNode* aPackage3d, IO_BASE* aIo ) :
2375 EAGLE_BASE( aIo )
2376{
2377 /*
2378 * <!ELEMENT package3d (description?, packageinstances?)>
2379 * <!ATTLIST package3d
2380 * name %String; ""
2381 * urn %Urn; #REQUIRED
2382 * type %Package3dType; #REQUIRED
2383 * library_version %Int; ""
2384 * library_locally_modified %Bool; "no"
2385 * >
2386 * <!-- library_version and library_locally_modified: Only in managed libraries
2387 * inside boards or schematics -->
2388 */
2389 name = parseRequiredAttribute<wxString>( aPackage3d, "name" );
2390 urn = parseRequiredAttribute<wxString>( aPackage3d, "urn" );
2391 type = parseRequiredAttribute<wxString>( aPackage3d, "type" );
2392 library_version = parseOptionalAttribute<int>( aPackage3d, "library_version" );
2394 "library_locally_modified" );
2395
2396 for( wxXmlNode* child = aPackage3d->GetChildren(); child; child = child->GetNext() )
2397 {
2398 if( child->GetName() == "description" )
2399 {
2400 description = std::make_optional<EDESCRIPTION>( child, aIo );
2401 }
2402 else if( child->GetName() == "packageinstances" )
2403 {
2404 for( wxXmlNode* instance = child->GetChildren(); instance;
2405 instance = instance->GetNext() )
2406 packageinstances.emplace_back( std::make_unique<EPACKAGEINSTANCE>( instance,
2407 aIo ) );
2408
2410 }
2411 }
2412
2414}
2415
2416
2417ESYMBOL::ESYMBOL( wxXmlNode* aSymbol, IO_BASE* aIo ) :
2418 EAGLE_BASE( aIo )
2419{
2420 /*
2421 * <!ELEMENT symbol (description?, (polygon | wire | text | dimension | pin | circle |
2422 * rectangle | frame)*)>
2423 * <!ATTLIST symbol
2424 * name %String; #REQUIRED
2425 * urn %Urn; ""
2426 * locally_modified %Bool; "no"
2427 * library_version %Int; ""
2428 * library_locally_modified %Bool; "no"
2429 * >
2430 * <!-- library_version and library_locally_modified: Only in managed libraries
2431 * inside boards or schematics -->
2432 */
2433
2434 name = parseRequiredAttribute<wxString>( aSymbol, "name" );
2435 urn = parseOptionalAttribute<EURN>( aSymbol, "urn" );
2436 locally_modified = parseOptionalAttribute<bool>( aSymbol, "locally_modified" );
2437 library_version = parseOptionalAttribute<int>( aSymbol, "library_version" );
2438 library_locally_modified = parseOptionalAttribute<bool>( aSymbol, "library_locally_modified" );
2439
2440 for( wxXmlNode* child = aSymbol->GetChildren(); child; child = child->GetNext() )
2441 {
2442 if( child->GetName() == "description" )
2443 {
2444 description = std::make_optional<EDESCRIPTION>( child, aIo );
2445 }
2446 else if( child->GetName() == "polygon" )
2447 {
2448 polygons.emplace_back( std::make_unique<EPOLYGON>( child, aIo ) );
2449 }
2450 else if( child->GetName() == "wire" )
2451 {
2452 wires.emplace_back( std::make_unique<EWIRE>( child, aIo ) );
2453 }
2454 else if( child->GetName() == "text" )
2455 {
2456 texts.emplace_back( std::make_unique<ETEXT>( child, aIo ) );
2457 }
2458 else if( child->GetName() == "dimension" )
2459 {
2460 dimensions.emplace_back( std::make_unique<EDIMENSION>( child, aIo ) );
2461 }
2462 else if( child->GetName() == "pin" )
2463 {
2464 pins.emplace_back( std::make_unique<EPIN>( child, aIo ) );
2465 }
2466 else if( child->GetName() == "circle" )
2467 {
2468 circles.emplace_back( std::make_unique<ECIRCLE>( child, aIo ) );
2469 }
2470 else if( child->GetName() == "rectangle" )
2471 {
2472 rectangles.emplace_back( std::make_unique<ERECT>( child, aIo ) );
2473 }
2474 else if( child->GetName() == "frame" )
2475 {
2476 frames.emplace_back( std::make_unique<EFRAME>( child, aIo ) );
2477 }
2478 }
2479
2481}
2482
2483
2484ELIBRARY::ELIBRARY( wxXmlNode* aLibrary, IO_BASE* aIo ) :
2485 EAGLE_BASE( aIo )
2486{
2487 /*
2488 * <!ELEMENT library (description?, packages?, packages3d?, symbols?, devicesets?)>
2489 * <!ATTLIST library
2490 * name %String; #REQUIRED
2491 * urn %Urn; ""
2492 * >
2493 * <!-- name: Only in libraries used inside boards or schematics -->
2494 * <!-- urn: Only in online libraries used inside boards or schematics -->
2495 */
2496
2497 // The name and urn attributes are only valid in schematic and board files.
2498 wxString parentNodeName;
2499
2500 if( aLibrary->GetParent() )
2501 parentNodeName = aLibrary->GetParent()->GetName();
2502
2503 if( parentNodeName == "libraries" )
2504 {
2505 name = parseRequiredAttribute<wxString>( aLibrary, "name" );
2506 urn = parseOptionalAttribute<EURN>( aLibrary, "urn" );
2507 }
2508
2509 for( wxXmlNode* child = aLibrary->GetChildren(); child; child = child->GetNext() )
2510 {
2511 if( child->GetName() == "description" )
2512 {
2513 description = std::make_optional<EDESCRIPTION>( child, aIo );
2514 }
2515 else if( child->GetName() == "packages" )
2516 {
2517 for( wxXmlNode* package = child->GetChildren(); package; package = package->GetNext() )
2518 {
2519 if( package->GetName() == "package" )
2520 {
2521 std::unique_ptr<EPACKAGE> tmp = std::make_unique<EPACKAGE>( package, aIo );
2522 packages[ tmp->name ] = std::move( tmp );
2523 }
2524 }
2525
2527 }
2528 else if( child->GetName() == "packages3d" )
2529 {
2530 for( wxXmlNode* package3d = child->GetChildren(); package3d;
2531 package3d = package3d->GetNext() )
2532 {
2533 if( package3d->GetName() == "package3d" )
2534 {
2535 std::unique_ptr<EPACKAGE3D> tmp = std::make_unique<EPACKAGE3D>( package3d,
2536 aIo );
2537 packages3d[ tmp->name ] = std::move( tmp );
2538 }
2539 }
2540
2541 AdvanceProgressPhase();
2542 }
2543 else if( child->GetName() == "symbols" )
2544 {
2545 for( wxXmlNode* symbol = child->GetChildren(); symbol; symbol = symbol->GetNext() )
2546 {
2547 if( symbol->GetName() == "symbol" )
2548 {
2549 std::unique_ptr<ESYMBOL> tmp = std::make_unique<ESYMBOL>( symbol, aIo );
2550 symbols[ tmp->name ] = std::move( tmp );
2551 }
2552 }
2553
2554 AdvanceProgressPhase();
2555 }
2556 else if( child->GetName() == "devicesets" )
2557 {
2558 for( wxXmlNode* deviceset = child->GetChildren(); deviceset;
2559 deviceset = deviceset->GetNext() )
2560 {
2561 if( deviceset->GetName() == "deviceset" )
2562 {
2563 std::unique_ptr<EDEVICE_SET> tmp = std::make_unique<EDEVICE_SET>( deviceset,
2564 aIo );
2565 devicesets[ tmp->name ] = std::move( tmp );
2566 }
2567 }
2568
2569 AdvanceProgressPhase();
2570 }
2571 }
2572
2573 AdvanceProgressPhase();
2574}
2575
2576
2577wxString ELIBRARY::GetName() const
2578{
2579 wxString libName = name;
2580
2581 // Use the name when no library urn exists.
2582 if( !urn )
2583 return libName;
2584
2585 // Suffix the library name with the urn library identifier. Eagle schematics can have
2586 // mulitple libraries with the same name. The urn library identifier is used to prevent
2587 // library name clashes.
2588 if( urn->IsValid() )
2589 libName += wxS( "_" ) + urn->assetId;
2590
2591 return libName;
2592}
2593
2594
2595EAPPROVED::EAPPROVED( wxXmlNode* aApproved, IO_BASE* aIo ) :
2596 EAGLE_BASE( aIo )
2597{
2598 /*
2599 * <!ELEMENT approved EMPTY>
2600 * <!ATTLIST approved
2601 * hash %String; #REQUIRED
2602 * >
2603 */
2604 hash = parseRequiredAttribute<wxString>( aApproved, "hash" );
2605
2607}
2608
2609
2610ESCHEMATIC::ESCHEMATIC( wxXmlNode* aSchematic, IO_BASE* aIo ) :
2611 EAGLE_BASE( aIo )
2612{
2613 /*
2614 * <!ELEMENT schematic (description?, libraries?, attributes?, variantdefs?, classes?,
2615 * modules?, groups?, parts?, sheets?, errors?)>
2616 * <!ATTLIST schematic
2617 * xreflabel %String; #IMPLIED
2618 * xrefpart %String; #IMPLIED
2619 * >
2620 */
2621 xreflabel = parseOptionalAttribute<wxString>( aSchematic, "xreflabel" );
2622 xrefpart = parseOptionalAttribute<wxString>( aSchematic, "xrefpart" );
2623
2624 for( wxXmlNode* child = aSchematic->GetChildren(); child; child = child->GetNext() )
2625 {
2626 if( child->GetName() == "description" )
2627 {
2628 description = std::make_optional<EDESCRIPTION>( child, aIo );
2629 }
2630 else if( child->GetName() == "libraries" )
2631 {
2632 for( wxXmlNode* library = child->GetChildren(); library; library = library->GetNext() )
2633 {
2634 if( library->GetName() == "library" )
2635 {
2636 std::unique_ptr<ELIBRARY> tmp = std::make_unique<ELIBRARY>( library, aIo );
2637
2638 wxString libName = tmp->GetName();
2639
2640 // Prevent duplicate library names. This should only happen if the Eagle
2641 // file has an invalid format.
2642 if( libraries.find( libName ) != libraries.end() )
2643 {
2644 wxString uniqueName;
2645 std::set<wxString> usedNames;
2646
2647 for( const auto& [setName, setLibrary] : libraries )
2648 usedNames.emplace( setName );
2649
2650 // One of _1.._N+1 is always free (pigeonhole); the bound also
2651 // stops an infinite loop on malformed names (e.g. embedded
2652 // NULs) whose suffixed variants all compare equal.
2653 for( int i = 1; i <= (int) usedNames.size() + 1; i++ )
2654 {
2655 uniqueName.Format( wxS( "%s_%d" ), libName, i );
2656
2657 if( usedNames.find( uniqueName ) == usedNames.end() )
2658 break;
2659 }
2660
2661 libName = uniqueName;
2662 }
2663
2664 libraries[ libName ] = std::move( tmp );
2665 }
2666 }
2667
2669 }
2670 else if( child->GetName() == "attributes" )
2671 {
2672 for( wxXmlNode* attribute = child->GetChildren(); attribute;
2673 attribute = attribute->GetNext() )
2674 {
2675 if( attribute->GetName() == "attribute" )
2676 {
2677 std::unique_ptr<EATTR> tmp = std::make_unique<EATTR>( attribute, aIo );
2678 attributes[ tmp->name ] = std::move( tmp );
2679 }
2680 }
2681
2683 }
2684 else if( child->GetName() == "variantdefs" )
2685 {
2686 for( wxXmlNode* variantdef = child->GetChildren(); variantdef;
2687 variantdef = variantdef->GetNext() )
2688 {
2689 if( variantdef->GetName() == "variantdef" )
2690 {
2691 std::unique_ptr<EVARIANTDEF> tmp = std::make_unique<EVARIANTDEF>( variantdef,
2692 aIo );
2693 variantdefs[ tmp->name ] = std::move( tmp );
2694 }
2695 }
2696
2698 }
2699 else if( child->GetName() == "classes" )
2700 {
2701 for( wxXmlNode* eclass = child->GetChildren(); eclass; eclass = eclass->GetNext() )
2702 {
2703 if( eclass->GetName() == "class" )
2704 {
2705 std::unique_ptr<ECLASS> tmp = std::make_unique<ECLASS>( eclass, aIo );
2706 classes[ tmp->number ] = std::move( tmp );
2707 }
2708 }
2709
2711 }
2712 else if( child->GetName() == "modules" )
2713 {
2714 for( wxXmlNode* mod = child->GetChildren(); mod; mod = mod->GetNext() )
2715 {
2716 if( mod->GetName() == "module" )
2717 {
2718 std::unique_ptr<EMODULE> tmp = std::make_unique<EMODULE>( mod, aIo );
2719 modules[ tmp->name ] = std::move( tmp );
2720 }
2721 }
2722
2724 }
2725 else if( child->GetName() == "groups" )
2726 {
2727 for( wxXmlNode* group = child->GetChildren(); group; group = group->GetNext() )
2728 {
2729 if( group->GetName() == "schematic_group" )
2730 {
2731 std::unique_ptr<ESCHEMATIC_GROUP> tmp =
2732 std::make_unique<ESCHEMATIC_GROUP>( group, aIo );
2733 groups[ tmp->name ] = std::move( tmp );
2734 }
2735 }
2736
2738 }
2739 else if( child->GetName() == "parts" )
2740 {
2741 for( wxXmlNode* part = child->GetChildren(); part; part = part->GetNext() )
2742 {
2743 if( part->GetName() == "part" )
2744 {
2745 std::unique_ptr<EPART> tmp = std::make_unique<EPART>( part, aIo );
2746 parts[ tmp->name ] = std::move( tmp );
2747 }
2748 }
2749
2751 }
2752 else if( child->GetName() == "sheets" )
2753 {
2754 for( wxXmlNode* sheet = child->GetChildren(); sheet; sheet = sheet->GetNext() )
2755 {
2756 if( sheet->GetName() == "sheet" )
2757 sheets.emplace_back( std::make_unique<ESHEET>( sheet, aIo ) );
2758 }
2759
2761 }
2762 else if( child->GetName() == "errors" )
2763 {
2764 for( wxXmlNode* error = child->GetChildren(); error; error = error->GetNext() )
2765 {
2766 if( error->GetName() == "approved" )
2767 errors.emplace_back( std::make_unique<EAPPROVED>( error, aIo ) );
2768 }
2769
2771 }
2772 }
2773
2775}
2776
2777
2778EDRAWING::EDRAWING( wxXmlNode* aDrawing, IO_BASE* aIo ) :
2779 EAGLE_BASE( aIo )
2780{
2781 /*
2782 * <!ELEMENT drawing (settings?, grid?, filters?, layers, (library | schematic | board))>
2783 */
2784 for( wxXmlNode* child = aDrawing->GetChildren(); child; child = child->GetNext() )
2785 {
2786 if( child->GetName() == "settings" )
2787 {
2788 for( wxXmlNode* setting = child->GetChildren(); setting; setting = setting->GetNext() )
2789 settings.emplace_back( std::make_unique<ESETTING>( setting, aIo ) );
2790
2791 AdvanceProgressPhase();
2792 }
2793 else if( child->GetName() == "grid" )
2794 {
2795 grid = std::make_optional<EGRID>( child, aIo );
2796 }
2797 else if( child->GetName() == "filters" )
2798 {
2799 for( wxXmlNode* filter = child->GetChildren(); filter; filter = filter->GetNext() )
2800 {
2801 if( filter->GetName() == "filter" )
2802 filters.emplace_back( std::make_unique<EFILTER>( filter, aIo ) );
2803 }
2804
2806 }
2807 else if( child->GetName() == "layers" )
2808 {
2809 for( wxXmlNode* layer = child->GetChildren(); layer; layer = layer->GetNext() )
2810 {
2811 if( layer->GetName() == "layer" )
2812 layers.emplace_back( std::make_unique<ELAYER>( layer, aIo ) );
2813 }
2814
2815 AdvanceProgressPhase();
2816 }
2817 else if( child->GetName() == "schematic" )
2818 {
2819 schematic = std::make_optional<ESCHEMATIC>( child, aIo );
2820 }
2821 else if( child->GetName() == "library" )
2822 {
2823 library = std::make_optional<ELIBRARY>( child, aIo );
2824 }
2825 }
2826
2827 // std::optional<std::unique_ptr<EBOARD>> board;
2828
2829 AdvanceProgressPhase();
2830}
2831
2832
2833EAGLE_DOC::EAGLE_DOC( wxXmlNode* aEagleDoc, IO_BASE* aIo ) :
2834 EAGLE_BASE( aIo )
2835{
2836 /*
2837 * <!ELEMENT eagle (compatibility?, drawing, compatibility?)>
2838 * <!ATTLIST eagle
2839 * version %Real; #REQUIRED
2840 * >
2841 * <!-- version: The EAGLE program version that generated this file, in the
2842 * form V.RR -->
2843 */
2844
2845 version = parseRequiredAttribute<wxString>( aEagleDoc, "version" );
2846
2847 for( wxXmlNode* child = aEagleDoc->GetChildren(); child; child = child->GetNext() )
2848 {
2849 if( child->GetName() == "compitibility" )
2850 compatibility = std::make_optional<ECOMPATIBILITY>( child, aIo );
2851 else if( child->GetName() == "drawing" )
2852 drawing = std::make_unique<EDRAWING>( child, aIo );
2853 }
2854
2856}
Model an optional XML attribute.
const T & CGet() const
Return a constant reference to the value of the attribute assuming it is available.
void Set(const wxString &aString)
OPTIONAL_XML_ATTRIBUTE()
Construct a default OPTIONAL_XML_ATTRIBUTE, whose data is not available.
A small class to help profiling.
Definition profile.h:46
void Stop()
Save the time when this function was called, and set the counter stane to stop.
Definition profile.h:86
double msecs(bool aSinceLast=false)
Definition profile.h:147
EURN Convert< EURN >(const wxString &aUrn)
std::string Convert< std::string >(const wxString &aValue)
static int parseAlignment(const wxString &aAlignment)
NODE_MAP MapChildren(wxXmlNode *aCurrentNode)
Provide an easy access to the children of an XML node via their names.
double Convert< double >(const wxString &aValue)
wxString escapeName(const wxString &aNetName)
Translates Eagle special characters to their counterparts in KiCad.
wxString interpretText(const wxString &aText)
Interprets special characters in Eagle text and converts them to KiCAD notation.
bool substituteVariable(wxString *aText)
Translates Eagle special text reference to a KiCad variable reference.
constexpr auto DEFAULT_ALIGNMENT
int Convert< int >(const wxString &aValue)
wxString Convert< wxString >(const wxString &aValue)
size_t GetNodeCount(const wxXmlNode *aNode)
Fetch the number of XML nodes within aNode.
EROT Convert< EROT >(const wxString &aRot)
parse an Eagle XML "rot" field.
T parseRequiredAttribute(wxXmlNode *aNode, const wxString &aAttribute)
Parse aAttribute of the XML node aNode.
bool Convert< bool >(const wxString &aValue)
ECOORD Convert< ECOORD >(const wxString &aCoord)
VECTOR2I ConvertEagleTextSize(const opt_wxString &font, const ECOORD &size)
Converts Eagle's text size to KiCad text size depending on the font used.
OPTIONAL_XML_ATTRIBUTE< T > parseOptionalAttribute(wxXmlNode *aNode, const wxString &aAttribute)
Parse option aAttribute of the XML node aNode.
VECTOR2I ConvertArcCenter(const VECTOR2I &aStart, const VECTOR2I &aEnd, double aAngle)
Convert an Eagle curve end to a KiCad center for S_ARC.
wxString convertDescription(wxString aDescr)
Converts Eagle's HTML description into KiCad description format.
T Convert(const wxString &aValue)
Convert a wxString to a generic type T.
OPTIONAL_XML_ATTRIBUTE< wxString > opt_wxString
std::unordered_map< wxString, wxXmlNode * > NODE_MAP
VECTOR2I ConvertEagleTextSize(const opt_wxString &font, const ECOORD &size)
Converts Eagle's text size to KiCad text size depending on the font used.
#define _(s)
const wxChar *const traceEagleIo
#define THROW_IO_ERRORF(msg,...)
SEVERITY
wxString RemoveHTMLTags(const wxString &aInput)
Removes HTML tags from a string.
wxString ConvertToNewOverbarNotation(const wxString &aOldStr)
Convert the old ~...~ overbar notation to the new ~{...} one.
bool ReplaceIllegalFileNameChars(std::string &aName, int aReplaceChar)
Checks aName for illegal file name characters.
EAGLE_BASE(IO_BASE *aIo=nullptr)
IO_BASE * io
void AdvanceProgressPhase()
void Report(const wxString &aMsg, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Send a message to the IO_BASE REPORTER object if one exists.
EAGLE_DOC(wxXmlNode *aEagleDoc, IO_BASE *aIo=nullptr)
std::optional< ECOMPATIBILITY > compatibility
wxString version
The Eagle XML file version.
std::unique_ptr< EDRAWING > drawing
EAPPROVED(wxXmlNode *aApproved, IO_BASE *aIo=nullptr)
wxString hash
opt_double ratio
opt_wxString value
opt_ecoord size
opt_ecoord y
wxString name
opt_erot rot
opt_int align
opt_int display
opt_ecoord x
opt_int layer
EBUS(wxXmlNode *aBus, IO_BASE *aIo=nullptr)
wxString name
std::vector< std::unique_ptr< ESEGMENT > > segments
ECOORD x
ECOORD radius
ECOORD y
ECIRCLE(wxXmlNode *aCircle, IO_BASE *aIo=nullptr)
ECOORD width
wxString number
opt_ecoord drill
std::map< wxString, ECOORD > clearanceMap
opt_ecoord width
ECLASS(wxXmlNode *aClass, IO_BASE *aIo=nullptr)
wxString name
ECOMPATIBILITY(wxXmlNode *aCompatibility, IO_BASE *aIo=nullptr)
opt_wxString contactroute
wxString pad
ECONNECT(wxXmlNode *aConnect, IO_BASE *aIo=nullptr)
wxString gate
wxString pin
@ EU_NM
nanometers
@ EU_MM
millimeters
@ EU_MIL
mils/thous
@ EU_INCH
inches
int ToSchUnits() const
long long int value
Value expressed in nanometers.
static long long int ConvertToNm(int aValue, enum EAGLE_UNIT aUnit)
Converts a size expressed in a certain unit to nanometers.
opt_wxString language
wxString text
EDESCRIPTION(wxXmlNode *aDescription, IO_BASE *aIo=nullptr)
std::map< wxString, std::unique_ptr< EDEVICE > > devices
opt_bool uservalue
opt_bool library_locally_modified
opt_bool locally_modified
std::optional< EDESCRIPTION > description
opt_int library_version
opt_wxString prefix
EDEVICE_SET(wxXmlNode *aDeviceSet, IO_BASE *aIo=nullptr)
std::map< wxString, std::unique_ptr< EGATE > > gates
std::optional< ESPICE > spice
wxString name
wxString name
std::vector< std::unique_ptr< EPACKAGE3DINST > > package3dinstances
std::vector< std::unique_ptr< ECONNECT > > connects
EDEVICE(wxXmlNode *aDevice, IO_BASE *aIo=nullptr)
opt_wxString package
std::map< wxString, std::unique_ptr< ETECHNOLOGY > > technologies
opt_wxString dimensionType
opt_ecoord textsize
EDIMENSION(wxXmlNode *aDimension, IO_BASE *aIo=nullptr)
EDRAWING(wxXmlNode *aDrawing, IO_BASE *aIo=nullptr)
EELEMENT(wxXmlNode *aElement, IO_BASE *aIo=nullptr)
opt_erot rot
wxString name
wxString library
opt_bool smashed
wxString value
opt_bool locked
std::map< wxString, std::unique_ptr< EATTR > > attributes
std::map< wxString, std::unique_ptr< EVARIANT > > variants
opt_eurn library_urn
wxString expression
EFILTER(wxXmlNode *aGrid, IO_BASE *aIo=nullptr)
wxString name
ECOORD x1
opt_bool border_bottom
opt_bool border_left
opt_bool border_right
ECOORD y1
opt_bool border_top
ECOORD y2
EFRAME(wxXmlNode *aFrameNode, IO_BASE *aIo=nullptr)
ECOORD x2
opt_int swaplevel
ECOORD x
ECOORD y
wxString symbol
EGATE(wxXmlNode *aGate, IO_BASE *aIo=nullptr)
wxString name
opt_int addlevel
opt_wxString style
opt_int multiple
opt_wxString unit
opt_bool display
EGRID(wxXmlNode *aGrid, IO_BASE *aIo=nullptr)
opt_wxString altunit
opt_wxString unitdist
opt_wxString altunitdist
opt_double altdistance
opt_double distance
ECOORD y
ECOORD drill
ECOORD x
EHOLE(wxXmlNode *aHole, IO_BASE *aIo=nullptr)
wxString part
std::map< wxString, std::unique_ptr< EATTR > > attributes
opt_erot rot
wxString gate
opt_bool smashed
EINSTANCE(wxXmlNode *aInstance, IO_BASE *aIo=nullptr)
EJUNCTION(wxXmlNode *aJunction, IO_BASE *aIo=nullptr)
opt_erot rot
opt_wxString font
opt_int ratio
ELABEL(wxXmlNode *aLabel, IO_BASE *aIo=nullptr)
ECOORD size
opt_wxString align
opt_bool xref
ECOORD y
ECOORD x
wxString name
opt_bool visible
opt_bool active
ELAYER(wxXmlNode *aLayer, IO_BASE *aIo=nullptr)
wxString GetName() const
Fetch the fully unique library name.
wxString name
opt_eurn urn
ELIBRARY(wxXmlNode *aLibrary, IO_BASE *aIo=nullptr)
wxString name
wxString model
EMODEL(wxXmlNode *aModel, IO_BASE *aIo=nullptr)
opt_bool smashed
wxString name
EMODULEINST(wxXmlNode *aModuleInst, IO_BASE *aIo=nullptr)
opt_erot rotation
opt_wxString moduleVariant
wxString moduleinst
std::map< wxString, std::unique_ptr< EPART > > parts
ECOORD dy
std::map< wxString, std::unique_ptr< ESCHEMATIC_GROUP > > groups
std::vector< std::unique_ptr< ESHEET > > sheets
std::optional< EDESCRIPTION > description
EMODULE(wxXmlNode *aModule, IO_BASE *aIo=nullptr)
opt_wxString prefix
std::map< wxString, std::unique_ptr< EVARIANTDEF > > variantdefs
ECOORD dx
wxString name
std::map< wxString, std::unique_ptr< EPORT > > ports
int netcode
wxString netname
std::vector< std::unique_ptr< ESEGMENT > > segments
ENOTE(wxXmlNode *aNote, IO_BASE *aIo=nullptr)
wxString note
double version
wxString severity
EPACKAGE3DINST(wxXmlNode *aPackage3dInst, IO_BASE *aIo=nullptr)
wxString package3d_urn
opt_bool library_locally_modified
wxString name
std::optional< EDESCRIPTION > description
opt_int library_version
std::vector< std::unique_ptr< EPACKAGEINSTANCE > > packageinstances
wxString type
EPACKAGE3D(wxXmlNode *aPackage3d, IO_BASE *aIo=nullptr)
EPACKAGEINSTANCE(wxXmlNode *aPackageInstance, IO_BASE *aIo=nullptr)
std::vector< std::unique_ptr< EPOLYGON > > polygons
std::vector< std::unique_ptr< EPAD > > thtpads
std::vector< std::unique_ptr< ECIRCLE > > circles
std::vector< std::unique_ptr< ESMD > > smdpads
std::vector< std::unique_ptr< EDIMENSION > > dimensions
opt_bool library_locally_modified
std::vector< std::unique_ptr< EHOLE > > holes
opt_int library_version
wxString name
std::vector< std::unique_ptr< EFRAME > > frames
std::vector< std::unique_ptr< ERECT > > rectangles
std::vector< std::unique_ptr< ETEXT > > texts
std::vector< std::unique_ptr< EWIRE > > wires
std::optional< EDESCRIPTION > description
EPACKAGE(wxXmlNode *aPackage, IO_BASE *aIo=nullptr)
opt_eurn urn
opt_bool locally_modified
opt_bool thermals
EPAD_COMMON(wxXmlNode *aPad, IO_BASE *aIo=nullptr)
opt_bool stop
wxString name
opt_ecoord diameter
opt_bool first
opt_ecoord drill
opt_int shape
EPAD(wxXmlNode *aPad, IO_BASE *aIo=nullptr)
wxString device
std::unique_ptr< ESPICE > spice
opt_bool override_locally_modified
wxString library
opt_wxString override_package_urn
opt_wxString technology
std::map< wxString, std::unique_ptr< EATTR > > attributes
opt_eurn libraryUrn
opt_wxString override_package3d_urn
EPART(wxXmlNode *aPart, IO_BASE *aIo=nullptr)
wxString deviceset
opt_wxString package3d_urn
opt_wxString value
std::map< wxString, std::unique_ptr< EVARIANT > > variants
wxString name
EPINMAPPING(wxXmlNode *aPinMap, IO_BASE *aIo=nullptr)
opt_bool iddevicewide
opt_wxString spiceprefix
opt_bool isusermap
std::vector< std::unique_ptr< EPINMAP > > pinmaps
wxString pinorder
wxString gate
wxString pin
EPINMAP(wxXmlNode *aPinMap, IO_BASE *aIo=nullptr)
wxString gate
EPINREF(wxXmlNode *aPinRef, IO_BASE *aIo=nullptr)
wxString pin
wxString part
EPIN(wxXmlNode *aPin, IO_BASE *aIo=nullptr)
ECOORD x
wxString name
opt_int swaplevel
opt_wxString visible
opt_wxString direction
opt_wxString length
opt_wxString function
opt_erot rot
ECOORD y
EPLAIN(wxXmlNode *aPlain, IO_BASE *aIo=nullptr)
opt_bool orphans
opt_int rank
opt_bool thermals
opt_ecoord spacing
std::vector< std::unique_ptr< EVERTEX > > vertices
EPOLYGON(wxXmlNode *aPolygon, IO_BASE *aIo=nullptr)
ECOORD width
opt_ecoord isolate
wxString port
EPORTREF(wxXmlNode *aPortRef, IO_BASE *aIo=nullptr)
wxString moduleinst
opt_wxString direction
wxString name
EPORT(wxXmlNode *aPort, IO_BASE *aIo=nullptr)
wxString side
ECOORD coord
double size
ECOORD y
opt_erot rot
opt_wxString font
ECOORD x
EPROBE(wxXmlNode *aProbe, IO_BASE *aIo=nullptr)
opt_bool xref
ECOORD x2
ECOORD y1
opt_erot rot
int layer
ERECT(wxXmlNode *aRect, IO_BASE *aIo=nullptr)
ECOORD y2
ECOORD x1
Eagle rotation.
double degrees
bool spin
bool mirror
std::vector< std::unique_ptr< EATTR > > attributes
ESCHEMATIC_GROUP(wxXmlNode *aSchematicGroup, IO_BASE *aIo=nullptr)
opt_bool showAnnotations
std::optional< EDESCRIPTION > description
opt_wxString titleFont
opt_wxString grouprefs
opt_wxString wireStyle
opt_ecoord titleSize
std::map< wxString, std::unique_ptr< EMODULE > > modules
opt_wxString xreflabel
opt_wxString xrefpart
std::map< wxString, std::unique_ptr< EATTR > > attributes
std::vector< std::unique_ptr< EAPPROVED > > errors
std::optional< EDESCRIPTION > description
std::map< wxString, std::unique_ptr< ECLASS > > classes
std::vector< std::unique_ptr< ESHEET > > sheets
std::map< wxString, std::unique_ptr< EPART > > parts
ESCHEMATIC(wxXmlNode *aSchematic, IO_BASE *aIo=nullptr)
std::map< wxString, std::unique_ptr< ELIBRARY > > libraries
std::map< wxString, std::unique_ptr< EVARIANTDEF > > variantdefs
std::map< wxString, std::unique_ptr< ESCHEMATIC_GROUP > > groups
ESEGMENT(wxXmlNode *aSegment, IO_BASE *aIo=nullptr)
opt_bool alwaysvectorfont
opt_bool keepoldvectorfont
opt_wxString verticaltext
ESETTING(wxXmlNode *aSetting, IO_BASE *aIo=nullptr)
ESHEET(wxXmlNode *aSheet, IO_BASE *aIo=nullptr)
opt_int roundness
ECOORD dx
int layer
opt_bool cream
ECOORD dy
ESMD(wxXmlNode *aSMD, IO_BASE *aIo=nullptr)
ESPICE(wxXmlNode *aSpice, IO_BASE *aIo=nullptr)
std::unique_ptr< EMODEL > model
std::unique_ptr< EPINMAPPING > pinmapping
std::vector< std::unique_ptr< EVERTEX > > vertices
double width
ESPLINE(wxXmlNode *aSpline, IO_BASE *aIo=nullptr)
std::vector< std::unique_ptr< EFRAME > > frames
opt_int library_version
std::optional< EDESCRIPTION > description
std::vector< std::unique_ptr< EPIN > > pins
std::vector< std::unique_ptr< ECIRCLE > > circles
opt_bool library_locally_modified
std::vector< std::unique_ptr< ETEXT > > texts
std::vector< std::unique_ptr< EPOLYGON > > polygons
opt_eurn urn
std::vector< std::unique_ptr< ERECT > > rectangles
std::vector< std::unique_ptr< EWIRE > > wires
ESYMBOL(wxXmlNode *aSymbol, IO_BASE *aIo=nullptr)
opt_bool locally_modified
wxString name
std::vector< std::unique_ptr< EDIMENSION > > dimensions
wxString name
std::vector< std::unique_ptr< EATTR > > attributes
ETECHNOLOGY(wxXmlNode *aTechnology, IO_BASE *aIo=nullptr)
opt_double ratio
wxString text
@ BOTTOM_CENTER
@ BOTTOM_RIGHT
@ CENTER_RIGHT
@ CENTER_LEFT
@ BOTTOM_LEFT
ECOORD y
ECOORD size
ETEXT(wxXmlNode *aText, IO_BASE *aIo=nullptr)
opt_erot rot
opt_int align
ECOORD x
VECTOR2I ConvertSize() const
Calculate text size based on font type and size.
opt_wxString font
int layer
Container that parses Eagle library file "urn" definitions.
bool IsValid() const
Check if the string passed to the ctor was a valid Eagle urn.
wxString host
Should always be "urn".
void Parse(const wxString &aUrn)
wxString assetVersion
May be empty depending on the asset type.
wxString assetId
The unique asset identifier for the asset type.
wxString assetType
Must be "symbol", "footprint", "package", "component", or "library".
wxString path
Path to the asset type below.
EVARIANTDEF(wxXmlNode *aVariantDef, IO_BASE *aIo=nullptr)
opt_bool current
wxString name
opt_bool populate
opt_wxString technology
EVARIANT(wxXmlNode *aVariant, IO_BASE *aIo=nullptr)
wxString name
opt_wxString value
EVERTEX(wxXmlNode *aVertex, IO_BASE *aIo=nullptr)
ECOORD y
ECOORD x
opt_double curve
range is -359.9..359.9
opt_ecoord diam
ECOORD drill
< inclusive
ECOORD y
EVIA(wxXmlNode *aVia, IO_BASE *aIo=nullptr)
opt_wxString shape
int layer_front_most
int layer_back_most
< extent
ECOORD x
ECOORD width
int layer
EWIRE(wxXmlNode *aWire, IO_BASE *aIo=nullptr)
ECOORD x2
opt_int cap
opt_int style
ECOORD y2
ECOORD x1
ECOORD y1
opt_double curve
range is -359.9..359.9
Implement a simple wrapper around runtime_error to isolate the errors thrown by the Eagle XML parser.
VECTOR2I center
wxLogTrace helper definitions.
double DEG2RAD(double deg)
Definition trigo.h:162
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683