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 wxLogError( _( "Invalid size %lld: 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_ERROR( wxString::Format( _( "Invalid Arc with radius %0.2f and angle %0.2f" ), //format:allow
525 dlen,
526 aAngle ) );
527 }
528
529 double dist = dlen / ( 2 * tan( DEG2RAD( aAngle ) / 2 ) );
530
532 mid.x + dist * ( dy / dlen ),
533 mid.y - dist * ( dx / dlen )
534 );
535
536 return center;
537}
538
539
540static int parseAlignment( const wxString& aAlignment )
541{
542 // (bottom-left | bottom-center | bottom-right | center-left |
543 // center | center-right | top-left | top-center | top-right)
544 if( aAlignment == "center" )
545 return ETEXT::CENTER;
546 else if( aAlignment == "center-right" )
547 return ETEXT::CENTER_RIGHT;
548 else if( aAlignment == "top-left" )
549 return ETEXT::TOP_LEFT;
550 else if( aAlignment == "top-center" )
551 return ETEXT::TOP_CENTER;
552 else if( aAlignment == "top-right" )
553 return ETEXT::TOP_RIGHT;
554 else if( aAlignment == "bottom-left" )
555 return ETEXT::BOTTOM_LEFT;
556 else if( aAlignment == "bottom-center" )
558 else if( aAlignment == "bottom-right" )
559 return ETEXT::BOTTOM_RIGHT;
560 else if( aAlignment == "center-left" )
561 return ETEXT::CENTER_LEFT;
562
563 return DEFAULT_ALIGNMENT;
564}
565
566
567void EAGLE_BASE::Report( const wxString& aMsg, SEVERITY aSeverity )
568{
569 if( !io )
570 return;
571
572 io->Report( aMsg, aSeverity );
573}
574
575
577{
578 if( !io )
579 return;
580
581 io->AdvanceProgressPhase();
582}
583
584
585EWIRE::EWIRE( wxXmlNode* aWire, IO_BASE* aIo ) :
586 EAGLE_BASE( aIo )
587{
588 /*
589 * <!ELEMENT wire EMPTY>
590 * <!ATTLIST wire
591 * x1 %Coord; #REQUIRED
592 * y1 %Coord; #REQUIRED
593 * x2 %Coord; #REQUIRED
594 * y2 %Coord; #REQUIRED
595 * width %Dimension; #REQUIRED
596 * layer %Layer; #REQUIRED
597 * extent %Extent; #IMPLIED -- only applicable for airwires --
598 * style %WireStyle; "continuous"
599 * curve %WireCurve; "0"
600 * cap %WireCap; "round" -- only applicable if 'curve' is not zero --
601 * >
602 */
603
604 x1 = parseRequiredAttribute<ECOORD>( aWire, "x1" );
605 y1 = parseRequiredAttribute<ECOORD>( aWire, "y1" );
606 x2 = parseRequiredAttribute<ECOORD>( aWire, "x2" );
607 y2 = parseRequiredAttribute<ECOORD>( aWire, "y2" );
608 width = parseRequiredAttribute<ECOORD>( aWire, "width" );
609 layer = parseRequiredAttribute<int>( aWire, "layer" );
610 curve = parseOptionalAttribute<double>( aWire, "curve" );
611
613
614 if( s == "continuous" )
616 else if( s == "longdash" )
618 else if( s == "shortdash" )
620 else if( s == "dashdot" )
622
623 s = parseOptionalAttribute<wxString>( aWire, "cap" );
624
625 if( s == "round" )
627 else if( s == "flat" )
629
631}
632
633
634ESEGMENT::ESEGMENT( wxXmlNode* aSegment, IO_BASE* aIo ) :
635 EAGLE_BASE( aIo )
636{
637 /*
638 * <!ELEMENT segment (pinref | portref | wire | junction | label | probe)*>
639 * <!-- 'pinref' and 'junction' are only valid in a <net> context -->
640 */
641 for( wxXmlNode* child = aSegment->GetChildren(); child; child = child->GetNext() )
642 {
643 if( child->GetName() == "pinref" )
644 pinRefs.emplace_back( std::make_unique<EPINREF>( child, aIo ) );
645 else if( child->GetName() == "portref" )
646 portRefs.emplace_back( std::make_unique<EPORTREF>( child, aIo ) );
647 else if( child->GetName() == "wire" )
648 wires.emplace_back( std::make_unique<EWIRE>( child, aIo ) );
649 else if( child->GetName() == "junction" )
650 junctions.emplace_back( std::make_unique<EJUNCTION>( child, aIo ) );
651 else if( child->GetName() == "label" )
652 labels.emplace_back( std::make_unique<ELABEL>( child, aIo ) );
653 else if( child->GetName() == "probe" )
654 probes.emplace_back( std::make_unique<EPROBE>( child, aIo ) );
655 }
656
658}
659
660
661EBUS::EBUS( wxXmlNode* aBus, IO_BASE* aIo ) :
662 EAGLE_BASE( aIo )
663{
664 /*
665 * <!ELEMENT bus (segment)*>
666 * <!ATTLIST bus
667 * name %String; #REQUIRED
668 * >
669 */
670 name = parseRequiredAttribute<wxString>( aBus, "name" );
671
672 for( wxXmlNode* child = aBus->GetChildren(); child; child = child->GetNext() )
673 {
674 if( child->GetName() == "segment" )
675 segments.emplace_back( std::make_unique<ESEGMENT>( child, aIo ) );
676 }
677
679}
680
681
682EJUNCTION::EJUNCTION( wxXmlNode* aJunction, IO_BASE* aIo ) :
683 EAGLE_BASE( aIo )
684{
685 /*
686 * <!ELEMENT junction EMPTY>
687 * <!ATTLIST junction
688 * x %Coord; #REQUIRED
689 * y %Coord; #REQUIRED
690 * >
691 */
692
693 x = parseRequiredAttribute<ECOORD>( aJunction, "x" );
694 y = parseRequiredAttribute<ECOORD>( aJunction, "y" );
695
697}
698
699
700ELABEL::ELABEL( wxXmlNode* aLabel, IO_BASE* aIo ) :
701 EAGLE_BASE( aIo )
702{
703 /*
704 * <!ELEMENT label EMPTY>
705 * <!ATTLIST label
706 * x %Coord; #REQUIRED
707 * y %Coord; #REQUIRED
708 * size %Dimension; #REQUIRED
709 * layer %Layer; #REQUIRED
710 * font %TextFont; "proportional"
711 * ratio %Int; "8"
712 * rot %Rotation; "R0"
713 * xref %Bool; "no"
714 * align %Align; "bottom-left"
715 * grouprefs IDREFS #IMPLIED
716 * >
717 * <!-- rot: Only 0, 90, 180 or 270 -->
718 * <!-- xref: Only in <net> context -->
719 */
720 x = parseRequiredAttribute<ECOORD>( aLabel, "x" );
721 y = parseRequiredAttribute<ECOORD>( aLabel, "y" );
722 size = parseRequiredAttribute<ECOORD>( aLabel, "size" );
723 layer = parseRequiredAttribute<int>( aLabel, "layer" );
724 font = parseOptionalAttribute<wxString>( aLabel, "font" );
725 ratio = parseOptionalAttribute<int>( aLabel, "ratio" );
726 rot = parseOptionalAttribute<EROT>( aLabel, "rot" );
727 xref = parseOptionalAttribute<wxString>( aLabel, "xref" );
728 align = parseOptionalAttribute<wxString>( aLabel, "align" );
729
731}
732
733
734ENET::ENET( wxXmlNode* aNet, IO_BASE* aIo ) :
735 EAGLE_BASE( aIo )
736{
737 /*
738 * <!ELEMENT net (segment)*>
739 * <!ATTLIST net
740 * name %String; #REQUIRED
741 * class %Class; "0"
742 * >
743 */
745 netcode = parseRequiredAttribute<int>( aNet, "class" );
746
747 for( wxXmlNode* segment = aNet->GetChildren(); segment; segment = segment->GetNext() )
748 segments.emplace_back( std::make_unique<ESEGMENT>( segment ) );
749
751}
752
753
754EVIA::EVIA( wxXmlNode* aVia, IO_BASE* aIo ) :
755 EAGLE_BASE( aIo )
756{
757 /*
758 * <!ELEMENT via EMPTY>
759 * <!ATTLIST via
760 * x %Coord; #REQUIRED
761 * y %Coord; #REQUIRED
762 * extent %Extent; #REQUIRED
763 * drill %Dimension; #REQUIRED
764 * diameter %Dimension; "0"
765 * shape %ViaShape; "round"
766 * alwaysstop %Bool; "no"
767 * >
768 */
769
770 x = parseRequiredAttribute<ECOORD>( aVia, "x" );
771 y = parseRequiredAttribute<ECOORD>( aVia, "y" );
772
773 wxString ext = parseRequiredAttribute<wxString>( aVia, "extent" );
774 sscanf( ext.c_str(), "%d-%d", &layer_front_most, &layer_back_most );
775
776 drill = parseRequiredAttribute<ECOORD>( aVia, "drill" );
777 diam = parseOptionalAttribute<ECOORD>( aVia, "diameter" );
778 shape = parseOptionalAttribute<wxString>( aVia, "shape" );
779
781}
782
783
784ECIRCLE::ECIRCLE( wxXmlNode* aCircle, IO_BASE* aIo ) :
785 EAGLE_BASE( aIo )
786{
787 /*
788 * <!ELEMENT circle EMPTY>
789 * <!ATTLIST circle
790 * x %Coord; #REQUIRED
791 * y %Coord; #REQUIRED
792 * radius %Coord; #REQUIRED
793 * width %Dimension; #REQUIRED
794 * layer %Layer; #REQUIRED
795 * >
796 */
797
798 x = parseRequiredAttribute<ECOORD>( aCircle, "x" );
799 y = parseRequiredAttribute<ECOORD>( aCircle, "y" );
800 radius = parseRequiredAttribute<ECOORD>( aCircle, "radius" );
801 width = parseRequiredAttribute<ECOORD>( aCircle, "width" );
802 layer = parseRequiredAttribute<int>( aCircle, "layer" );
803
805}
806
807
808ERECT::ERECT( wxXmlNode* aRect, IO_BASE* aIo ) :
809 EAGLE_BASE( aIo )
810{
811 /*
812 * <!ELEMENT rectangle EMPTY>
813 * <!ATTLIST rectangle
814 * x1 %Coord; #REQUIRED
815 * y1 %Coord; #REQUIRED
816 * x2 %Coord; #REQUIRED
817 * y2 %Coord; #REQUIRED
818 * layer %Layer; #REQUIRED
819 * rot %Rotation; "R0"
820 * >
821 */
822
823 x1 = parseRequiredAttribute<ECOORD>( aRect, "x1" );
824 y1 = parseRequiredAttribute<ECOORD>( aRect, "y1" );
825 x2 = parseRequiredAttribute<ECOORD>( aRect, "x2" );
826 y2 = parseRequiredAttribute<ECOORD>( aRect, "y2" );
827 layer = parseRequiredAttribute<int>( aRect, "layer" );
828 rot = parseOptionalAttribute<EROT>( aRect, "rot" );
829
831}
832
833
834EDESCRIPTION::EDESCRIPTION( wxXmlNode* aDescription, IO_BASE* aIo ) :
835 EAGLE_BASE( aIo )
836{
837 /*
838 * <!ELEMENT description (#PCDATA)>
839 * <!ATTLIST description
840 * language %String; "en"
841 * >
842 */
843
844 text = aDescription->GetNodeContent();
845 language = parseOptionalAttribute<wxString>( aDescription, "language" );
846
848}
849
850
851EATTR::EATTR( wxXmlNode* aTree, IO_BASE* aIo ) :
852 EAGLE_BASE( aIo )
853{
854 /*
855 * <!ELEMENT attribute EMPTY>
856 * <!ATTLIST attribute
857 * name %String; #REQUIRED
858 * value %String; #IMPLIED
859 * x %Coord; #IMPLIED
860 * y %Coord; #IMPLIED
861 * size %Dimension; #IMPLIED
862 * layer %Layer; #IMPLIED
863 * font %TextFont; #IMPLIED
864 * ratio %Int; #IMPLIED
865 * rot %Rotation; "R0"
866 * display %AttributeDisplay; "value" -- only in <element> or <instance> context --
867 * constant %Bool; "no" -- only in <device> context --
868 * >
869 */
870
871 name = parseRequiredAttribute<wxString>( aTree, "name" );
872 value = parseOptionalAttribute<wxString>( aTree, "value" );
873
874 x = parseOptionalAttribute<ECOORD>( aTree, "x" );
875 y = parseOptionalAttribute<ECOORD>( aTree, "y" );
876 size = parseOptionalAttribute<ECOORD>( aTree, "size" );
877
878 layer = parseOptionalAttribute<int>( aTree, "layer" );
879 ratio = parseOptionalAttribute<double>( aTree, "ratio" );
880 rot = parseOptionalAttribute<EROT>( aTree, "rot" );
881
882 opt_wxString stemp = parseOptionalAttribute<wxString>( aTree, "display" );
883
884 // (off | value | name | both)
885 if( stemp == "off" )
887 else if( stemp == "name" )
889 else if( stemp == "both" )
891 else // "value" is the default
893
894 stemp = parseOptionalAttribute<wxString>( aTree, "align" );
895
896 align = stemp ? parseAlignment( *stemp ) : DEFAULT_ALIGNMENT;
897
899}
900
901
902EPINREF::EPINREF( wxXmlNode* aPinRef, IO_BASE* aIo ) :
903 EAGLE_BASE( aIo )
904{
905 /*
906 * <!ELEMENT pinref EMPTY>
907 * <!ATTLIST pinref
908 * part %String; #REQUIRED
909 * gate %String; #REQUIRED
910 * pin %String; #REQUIRED
911 * >
912 */
913 part = parseRequiredAttribute<wxString>( aPinRef, "part" );
914 gate = parseRequiredAttribute<wxString>( aPinRef, "gate" );
915 pin = parseRequiredAttribute<wxString>( aPinRef, "pin" );
916
918}
919
920
921EPORTREF::EPORTREF( wxXmlNode* aPortRef, IO_BASE* aIo ) :
922 EAGLE_BASE( aIo )
923{
924 /*
925 * <!ELEMENT portref EMPTY>
926 * <!ATTLIST portref
927 * moduleinst %String; #REQUIRED
928 * port %String; #REQUIRED
929 * >
930 */
931 moduleinst = parseRequiredAttribute<wxString>( aPortRef, "moduleinst" );
932 port = parseRequiredAttribute<wxString>( aPortRef, "port" );
933
935}
936
937
938EPROBE::EPROBE( wxXmlNode* aProbe, IO_BASE* aIo ) :
939 EAGLE_BASE( aIo )
940{
941 /*
942 * <!ELEMENT probe EMPTY>
943 * <!ATTLIST probe
944 * x %Coord; #REQUIRED
945 * y %Coord; #REQUIRED
946 * size %Dimension; #REQUIRED
947 * layer %Layer; #REQUIRED
948 * font %TextFont; "proportional"
949 * ratio %Int; "8"
950 * rot %Rotation; "R0"
951 * xref %Bool; "no"
952 * grouprefs IDREFS #IMPLIED
953 * >
954 * <!-- rot: Only 0, 90, 180 or 270 -->
955 * <!-- xref: Only in <net> context -->
956 */
957 x = parseRequiredAttribute<ECOORD>( aProbe, "x" );
958 y = parseRequiredAttribute<ECOORD>( aProbe, "y" );
959 size = parseRequiredAttribute<double>( aProbe, "size" );
960 layer = parseRequiredAttribute<int>( aProbe, "layer" );
961 font = parseOptionalAttribute<wxString>( aProbe, "font" );
962 ratio = parseOptionalAttribute<int>( aProbe, "ratio" );
963 rot = parseOptionalAttribute<EROT>( aProbe, "rot" );
964 xref = parseOptionalAttribute<bool>( aProbe, "xref" );
965
967}
968
969
970EDIMENSION::EDIMENSION( wxXmlNode* aDimension, IO_BASE* aIo ) :
971 EAGLE_BASE( aIo )
972{
973 /*
974 * <!ELEMENT dimension EMPTY>
975 * <!ATTLIST dimension
976 * x1 %Coord; #REQUIRED
977 * y1 %Coord; #REQUIRED
978 * x2 %Coord; #REQUIRED
979 * y2 %Coord; #REQUIRED
980 * x3 %Coord; #REQUIRED
981 * y3 %Coord; #REQUIRED
982 * textsize %Coord;
983 * layer %Layer; #REQUIRED
984 * dtype %DimensionType; "parallel"
985 * >
986 */
987
988 x1 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "x1" ) );
989 y1 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "y1" ) );
990 x2 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "x2" ) );
991 y2 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "y2" ) );
992 x3 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "x3" ) );
993 y3 = parseRequiredAttribute<ECOORD>( aDimension, wxT( "y3" ) );
994 textsize = parseOptionalAttribute<ECOORD>( aDimension, wxT( "textsize" ) );
995 layer = parseRequiredAttribute<int>( aDimension, wxT( "layer" ) );
996 dimensionType = parseOptionalAttribute<wxString>( aDimension, wxT( "dtype" ) );
997
999}
1000
1001
1002ETEXT::ETEXT( wxXmlNode* aText, IO_BASE* aIo ) :
1003 EAGLE_BASE( aIo )
1004{
1005 /*
1006 <!ELEMENT text (#PCDATA)>
1007 <!ATTLIST text
1008 x %Coord; #REQUIRED
1009 y %Coord; #REQUIRED
1010 size %Dimension; #REQUIRED
1011 layer %Layer; #REQUIRED
1012 font %TextFont; "proportional"
1013 ratio %Int; "8"
1014 rot %Rotation; "R0"
1015 align %Align; "bottom-left"
1016 >
1017 */
1018
1019 text = aText->GetNodeContent();
1020 x = parseRequiredAttribute<ECOORD>( aText, "x" );
1021 y = parseRequiredAttribute<ECOORD>( aText, "y" );
1022 size = parseRequiredAttribute<ECOORD>( aText, "size" );
1023 layer = parseRequiredAttribute<int>( aText, "layer" );
1024
1025 font = parseOptionalAttribute<wxString>( aText, "font" );
1026 ratio = parseOptionalAttribute<double>( aText, "ratio" );
1027 rot = parseOptionalAttribute<EROT>( aText, "rot" );
1028
1029 opt_wxString stemp = parseOptionalAttribute<wxString>( aText, "align" );
1030
1031 align = stemp ? parseAlignment( *stemp ) : DEFAULT_ALIGNMENT;
1032
1034}
1035
1036
1038{
1039 VECTOR2I textsize;
1040
1041 if( font )
1042 {
1043 const wxString& fontName = font.CGet();
1044
1045 if( fontName == "vector" )
1046 {
1047 textsize = VECTOR2I( size.ToSchUnits(), size.ToSchUnits() );
1048 }
1049 else if( fontName == "fixed" )
1050 {
1051 textsize = VECTOR2I( size.ToSchUnits(), size.ToSchUnits() * 0.80 );
1052 }
1053 else
1054 {
1055 textsize = VECTOR2I( size.ToSchUnits(), size.ToSchUnits() );
1056 }
1057 }
1058 else
1059 {
1060 textsize = VECTOR2I( size.ToSchUnits() * 0.85, size.ToSchUnits() );
1061 }
1062
1063 return textsize;
1064}
1065
1066
1068{
1069 return ConvertEagleTextSize( font, size );
1070}
1071
1072
1073EFRAME::EFRAME( wxXmlNode* aFrameNode, IO_BASE* aIo ) :
1074 EAGLE_BASE( aIo )
1075{
1076 /*
1077 * <!ELEMENT frame EMPTY>
1078 * <!ATTLIST frame
1079 * x1 %Coord; #REQUIRED
1080 * y1 %Coord; #REQUIRED
1081 * x2 %Coord; #REQUIRED
1082 * y2 %Coord; #REQUIRED
1083 * columns %Int; #REQUIRED
1084 * rows %Int; #REQUIRED
1085 * layer %Layer; #REQUIRED
1086 * border-left %Bool; "yes"
1087 * border-top %Bool; "yes"
1088 * border-right %Bool; "yes"
1089 * border-bottom %Bool; "yes"
1090 * >
1091 */
1092 border_left = true;
1093 border_top = true;
1094 border_right = true;
1095 border_bottom = true;
1096
1097 x1 = parseRequiredAttribute<ECOORD>( aFrameNode, "x1" );
1098 y1 = parseRequiredAttribute<ECOORD>( aFrameNode, "y1" );
1099 x2 = parseRequiredAttribute<ECOORD>( aFrameNode, "x2" );
1100 y2 = parseRequiredAttribute<ECOORD>( aFrameNode, "y2" );
1101 columns = parseRequiredAttribute<int>( aFrameNode, "columns" );
1102 rows = parseRequiredAttribute<int>( aFrameNode, "rows" );
1103 layer = parseRequiredAttribute<int>( aFrameNode, "layer" );
1104 border_left = parseOptionalAttribute<bool>( aFrameNode, "border-left" );
1105 border_top = parseOptionalAttribute<bool>( aFrameNode, "border-top" );
1106 border_right = parseOptionalAttribute<bool>( aFrameNode, "border-right" );
1107 border_bottom = parseOptionalAttribute<bool>( aFrameNode, "border-bottom" );
1108
1110}
1111
1112
1113EPAD_COMMON::EPAD_COMMON( wxXmlNode* aPad, IO_BASE* aIo ) :
1114 EAGLE_BASE( aIo )
1115{
1116 // #REQUIRED says DTD, throw exception if not found
1117 name = parseRequiredAttribute<wxString>( aPad, "name" );
1118 x = parseRequiredAttribute<ECOORD>( aPad, "x" );
1119 y = parseRequiredAttribute<ECOORD>( aPad, "y" );
1120 rot = parseOptionalAttribute<EROT>( aPad, "rot" );
1121 stop = parseOptionalAttribute<bool>( aPad, "stop" );
1122 thermals = parseOptionalAttribute<bool>( aPad, "thermals" );
1123}
1124
1125
1126EPAD::EPAD( wxXmlNode* aPad, IO_BASE* aIo ) :
1127 EPAD_COMMON( aPad, aIo )
1128{
1129 /*
1130 <!ELEMENT pad EMPTY>
1131 <!ATTLIST pad
1132 name %String; #REQUIRED
1133 x %Coord; #REQUIRED
1134 y %Coord; #REQUIRED
1135 drill %Dimension; #REQUIRED
1136 diameter %Dimension; "0"
1137 shape %PadShape; "round"
1138 rot %Rotation; "R0"
1139 stop %Bool; "yes"
1140 thermals %Bool; "yes"
1141 first %Bool; "no"
1142 >
1143 */
1144
1145 // #REQUIRED says DTD, but DipTrace doesn't write it sometimes
1146 drill = parseOptionalAttribute<ECOORD>( aPad, "drill" );
1147
1148 // Optional attributes
1149 diameter = parseOptionalAttribute<ECOORD>( aPad, "diameter" );
1150
1152
1153 // (square | round | octagon | long | offset)
1154 if( s == "square" )
1156 else if( s == "round" )
1158 else if( s == "octagon" )
1160 else if( s == "long" )
1161 shape = EPAD::LONG;
1162 else if( s == "offset" )
1164
1165 first = parseOptionalAttribute<bool>( aPad, "first" );
1166
1168}
1169
1170
1171ESMD::ESMD( wxXmlNode* aSMD, IO_BASE* aIo ) :
1172 EPAD_COMMON( aSMD, aIo )
1173{
1174 /*
1175 <!ATTLIST smd
1176 name %String; #REQUIRED
1177 x %Coord; #REQUIRED
1178 y %Coord; #REQUIRED
1179 dx %Dimension; #REQUIRED
1180 dy %Dimension; #REQUIRED
1181 layer %Layer; #REQUIRED
1182 roundness %Int; "0"
1183 rot %Rotation; "R0"
1184 stop %Bool; "yes"
1185 thermals %Bool; "yes"
1186 cream %Bool; "yes"
1187 >
1188 */
1189
1190 // DTD #REQUIRED, throw exception if not found
1191 dx = parseRequiredAttribute<ECOORD>( aSMD, "dx" );
1192 dy = parseRequiredAttribute<ECOORD>( aSMD, "dy" );
1193 layer = parseRequiredAttribute<int>( aSMD, "layer" );
1194
1195 roundness = parseOptionalAttribute<int>( aSMD, "roundness" );
1196 cream = parseOptionalAttribute<bool>( aSMD, "cream" );
1197
1199}
1200
1201
1202EPIN::EPIN( wxXmlNode* aPin, IO_BASE* aIo ) :
1203 EAGLE_BASE( aIo )
1204{
1205 /*
1206 <!ELEMENT pin EMPTY>
1207 <!ATTLIST pin
1208 name %String; #REQUIRED
1209 x %Coord; #REQUIRED
1210 y %Coord; #REQUIRED
1211 visible %PinVisible; "both"
1212 length %PinLength; "long"
1213 direction %PinDirection; "io"
1214 function %PinFunction; "none"
1215 swaplevel %Int; "0"
1216 rot %Rotation; "R0"
1217 >
1218 */
1219
1220 // DTD #REQUIRED, throw exception if not found
1221 name = parseRequiredAttribute<wxString>( aPin, "name" );
1222 x = parseRequiredAttribute<ECOORD>( aPin, "x" );
1223 y = parseRequiredAttribute<ECOORD>( aPin, "y" );
1224
1225 visible = parseOptionalAttribute<wxString>( aPin, "visible" );
1226 length = parseOptionalAttribute<wxString>( aPin, "length" );
1227 direction = parseOptionalAttribute<wxString>( aPin, "direction" );
1228 function = parseOptionalAttribute<wxString>( aPin, "function" );
1229 swaplevel = parseOptionalAttribute<int>( aPin, "swaplevel" );
1230 rot = parseOptionalAttribute<EROT>( aPin, "rot" );
1231
1233}
1234
1235
1236EVERTEX::EVERTEX( wxXmlNode* aVertex, IO_BASE* aIo ) :
1237 EAGLE_BASE( aIo )
1238{
1239 /*
1240 * <!ELEMENT vertex EMPTY>
1241 * <!ATTLIST vertex
1242 * x %Coord; #REQUIRED
1243 * y %Coord; #REQUIRED
1244 * curve %WireCurve; "0" -- the curvature from this vertex to the next one --
1245 * >
1246 */
1247
1248 x = parseRequiredAttribute<ECOORD>( aVertex, "x" );
1249 y = parseRequiredAttribute<ECOORD>( aVertex, "y" );
1250 curve = parseOptionalAttribute<double>( aVertex, "curve" );
1251
1253}
1254
1255
1256EPOLYGON::EPOLYGON( wxXmlNode* aPolygon, IO_BASE* aIo ) :
1257 EAGLE_BASE( aIo )
1258{
1259 /*
1260 * <!ELEMENT polygon (vertex)*>
1261 * <!-- the vertices must define a valid polygon; if the last vertex is the same
1262 * as the first one, it is ignored -->
1263 * <!ATTLIST polygon
1264 * width %Dimension; #REQUIRED
1265 * layer %Layer; #REQUIRED
1266 * spacing %Dimension; #IMPLIED
1267 * pour %PolygonPour; "solid"
1268 * isolate %Dimension; #IMPLIED
1269 * orphans %Bool; "no"
1270 * thermals %Bool; "yes"
1271 * rank %Int; "0"
1272 * grouprefs IDREFS #IMPLIED
1273 * >
1274 * <!-- isolate: Only in <signal> or <package> context -->
1275 * <!-- orphans: Only in <signal> context -->
1276 * <!-- thermals:Only in <signal> context -->
1277 * <!-- rank: 1..6 in <signal> context, 0 or 7 in <package> context -->
1278 */
1279
1280 width = parseRequiredAttribute<ECOORD>( aPolygon, "width" );
1281 layer = parseRequiredAttribute<int>( aPolygon, "layer" );
1282
1283 spacing = parseOptionalAttribute<ECOORD>( aPolygon, "spacing" );
1284 isolate = parseOptionalAttribute<ECOORD>( aPolygon, "isolate" );
1285 opt_wxString s = parseOptionalAttribute<wxString>( aPolygon, "pour" );
1286
1287 // default pour to solid fill
1289
1290 // (solid | hatch | cutout)
1291 if( s == "hatch" )
1293 else if( s == "cutout" )
1295
1296 orphans = parseOptionalAttribute<bool>( aPolygon, "orphans" );
1297 thermals = parseOptionalAttribute<bool>( aPolygon, "thermals" );
1298 rank = parseOptionalAttribute<int>( aPolygon, "rank" );
1299
1300 for( wxXmlNode* child = aPolygon->GetChildren(); child; child = child->GetNext() )
1301 {
1302 if( child->GetName() == "vertex" )
1303 vertices.emplace_back( std::make_unique<EVERTEX>( child, aIo ) );
1304 }
1305
1307}
1308
1309
1310ESPLINE::ESPLINE( wxXmlNode* aSpline, IO_BASE* aIo ) :
1311 EAGLE_BASE( aIo )
1312{
1313 /*
1314 * <!ELEMENT spline (vertex)*>
1315 * <!-- Four simple (non-curve) vertices define the control points of a degree-3 spline
1316 * curve -->
1317 * <!ATTLIST spline
1318 * width %Dimension; #REQUIRED
1319 * >
1320 */
1321 width = parseRequiredAttribute<double>( aSpline, "width" );
1322
1323 for( wxXmlNode* child = aSpline->GetChildren(); child; child = child->GetNext() )
1324 {
1325 if( child->GetName() == "vertex" )
1326 vertices.emplace_back( std::make_unique<EVERTEX>( child, aIo ) );
1327 }
1328
1330}
1331
1332
1333EVARIANT::EVARIANT( wxXmlNode* aVariant, IO_BASE* aIo ) :
1334 EAGLE_BASE( aIo )
1335{
1336 /*
1337 * <!ELEMENT variant EMPTY>
1338 * <!ATTLIST variant
1339 * name %String; #REQUIRED
1340 * populate %Bool; "yes"
1341 * value %String; #IMPLIED
1342 * technology %String; #IMPLIED
1343 * >
1344 * <!-- technology: Only in part context -->
1345 */
1346 name = parseRequiredAttribute<wxString>( aVariant, "name" );
1347 populate = parseOptionalAttribute<bool>( aVariant, "populate" );
1348 value = parseOptionalAttribute<wxString>( aVariant, "value" );
1349 technology = parseOptionalAttribute<wxString>( aVariant, "technology" );
1350
1352}
1353
1354
1355EMODEL::EMODEL( wxXmlNode* aModel, IO_BASE* aIo ) :
1356 EAGLE_BASE( aIo )
1357{
1358 /*
1359 * <!ELEMENT model (#PCDATA)>
1360 * <!ATTLIST model
1361 * name %String; #REQUIRED
1362 * >
1363 */
1364 name = parseRequiredAttribute<wxString>( aModel, "name" );
1365 model = aModel->GetNodeContent();
1366
1368}
1369
1370
1371EPINMAP::EPINMAP( wxXmlNode* aPinMap, IO_BASE* aIo ) :
1372 EAGLE_BASE( aIo )
1373{
1374 /*
1375 * <!ELEMENT pinmap EMPTY>
1376 * <!ATTLIST pinmap
1377 * gate %String; #REQUIRED
1378 * pin %String; #REQUIRED
1379 * pinorder %String; #REQUIRED
1380 * >
1381 */
1382 gate = parseRequiredAttribute<wxString>( aPinMap, "gate" );
1383 pin = parseRequiredAttribute<wxString>( aPinMap, "pin" );
1384 pinorder = parseRequiredAttribute<wxString>( aPinMap, "pinorder" );
1385
1387}
1388
1389
1390EPINMAPPING::EPINMAPPING( wxXmlNode* aPinMapping, IO_BASE* aIo ) :
1391 EAGLE_BASE( aIo )
1392{
1393 /*
1394 * <!ELEMENT pinmapping (pinmap+)>
1395 * <!ATTLIST pinmapping
1396 * isusermap %Bool; "no"
1397 * iddevicewide %Bool; "yes"
1398 * spiceprefix %String; ""
1399 * >
1400 */
1401 isusermap = parseOptionalAttribute<bool>( aPinMapping, "isusermap" );
1402 iddevicewide = parseOptionalAttribute<bool>( aPinMapping, "iddevicewide" );
1403 spiceprefix = parseOptionalAttribute<wxString>( aPinMapping, "spiceprefix" );
1404
1405 for( wxXmlNode* child = aPinMapping->GetChildren(); child; child = child->GetNext() )
1406 {
1407 if( child->GetName() == "pinmap" )
1408 pinmaps.emplace_back( std::make_unique<EPINMAP>( child, aIo ) );
1409 }
1410
1412}
1413
1414
1415ESPICE::ESPICE( wxXmlNode* aSpice, IO_BASE* aIo ) :
1416 EAGLE_BASE( aIo )
1417{
1418 /*
1419 * <!ELEMENT spice (pinmapping, model)>
1420 */
1421 pinmapping = std::make_unique<EPINMAPPING>( aSpice );
1422
1423 if( aSpice->GetName() == "model" )
1424 model = std::make_unique<EMODEL>( aSpice );
1425
1427}
1428
1429
1430EHOLE::EHOLE( wxXmlNode* aHole, IO_BASE* aIo ) :
1431 EAGLE_BASE( aIo )
1432{
1433 /*
1434 <!ELEMENT hole EMPTY>
1435 <!ATTLIST hole
1436 x %Coord; #REQUIRED
1437 y %Coord; #REQUIRED
1438 drill %Dimension; #REQUIRED
1439 >
1440 */
1441
1442 // #REQUIRED:
1443 x = parseRequiredAttribute<ECOORD>( aHole, "x" );
1444 y = parseRequiredAttribute<ECOORD>( aHole, "y" );
1445 drill = parseRequiredAttribute<ECOORD>( aHole, "drill" );
1446
1448}
1449
1450
1451EELEMENT::EELEMENT( wxXmlNode* aElement, IO_BASE* aIo ) :
1452 EAGLE_BASE( aIo )
1453{
1454 /*
1455 <!ELEMENT element (attribute*, variant*)>
1456 <!ATTLIST element
1457 name %String; #REQUIRED
1458 library %String; #REQUIRED
1459 library_urn %Urn; ""
1460 package %String; #REQUIRED
1461 package3d_urn %Urn; ""
1462 override_package3d_urn %Urn; ""
1463 override_package_urn %Urn; ""
1464 override_locally_modified %Bool; "no"
1465 value %String; #REQUIRED
1466 x %Coord; #REQUIRED
1467 y %Coord; #REQUIRED
1468 locked %Bool; "no"
1469 populate %Bool; "yes"
1470 smashed %Bool; "no"
1471 rot %Rotation; "R0"
1472 grouprefs IDREFS #IMPLIED
1473 >
1474 */
1475
1476 // #REQUIRED
1477 name = parseRequiredAttribute<wxString>( aElement, "name" );
1478 library = parseRequiredAttribute<wxString>( aElement, "library" );
1479 value = parseRequiredAttribute<wxString>( aElement, "value" );
1480 std::string p = parseRequiredAttribute<std::string>( aElement, "package" );
1482 package = wxString::FromUTF8( p.c_str() );
1483
1484 x = parseRequiredAttribute<ECOORD>( aElement, "x" );
1485 y = parseRequiredAttribute<ECOORD>( aElement, "y" );
1486
1487 // optional
1488 library_urn = parseOptionalAttribute<EURN>( aElement, "library_urn" );
1489 locked = parseOptionalAttribute<bool>( aElement, "locked" );
1490 smashed = parseOptionalAttribute<bool>( aElement, "smashed" );
1491 rot = parseOptionalAttribute<EROT>( aElement, "rot" );
1492
1493 for( wxXmlNode* child = aElement->GetChildren(); child; child = child->GetNext() )
1494 {
1495 if( child->GetName() == "attribute" )
1496 {
1497 std::unique_ptr<EATTR> attr = std::make_unique<EATTR>( child, aIo );
1498 attributes[ attr->name ] = std::move( attr );
1499 }
1500 else if( child->GetName() == "variant" )
1501 {
1502 std::unique_ptr<EVARIANT> variant = std::make_unique<EVARIANT>( child, aIo );
1503 variants[ variant->name ] = std::move( variant );
1504 }
1505 }
1506
1508}
1509
1510
1511ELAYER::ELAYER( wxXmlNode* aLayer, IO_BASE* aIo ) :
1512 EAGLE_BASE( aIo )
1513{
1514 /*
1515 <!ELEMENT layer EMPTY>
1516 <!ATTLIST layer
1517 number %Layer; #REQUIRED
1518 name %String; #REQUIRED
1519 color %Int; #REQUIRED
1520 fill %Int; #REQUIRED
1521 visible %Bool; "yes"
1522 active %Bool; "yes"
1523 >
1524 */
1525
1526 number = parseRequiredAttribute<int>( aLayer, "number" );
1527 name = parseRequiredAttribute<wxString>( aLayer, "name" );
1528 color = parseRequiredAttribute<int>( aLayer, "color" );
1529 fill = parseRequiredAttribute<int>( aLayer, "fill" );
1530 visible = parseOptionalAttribute<bool>( aLayer, "visible" );
1531 active = parseOptionalAttribute<bool>( aLayer, "active" );
1532
1534}
1535
1536
1537EPART::EPART( wxXmlNode* aPart, IO_BASE* aIo ) :
1538 EAGLE_BASE( aIo )
1539{
1540 /*
1541 * <!ELEMENT part (attribute*, variant*)>
1542 * <!ATTLIST part
1543 * name %String; #REQUIRED
1544 * library %String; #REQUIRED
1545 * deviceset %String; #REQUIRED
1546 * device %String; #REQUIRED
1547 * technology %String; ""
1548 * value %String; #IMPLIED
1549 * >
1550 */
1551 name = parseRequiredAttribute<wxString>( aPart, "name" );
1552 library = parseRequiredAttribute<wxString>( aPart, "library" );
1553 libraryUrn = parseOptionalAttribute<EURN>( aPart, "library_urn" );
1554 deviceset = parseRequiredAttribute<wxString>( aPart, "deviceset" );
1555 device = parseRequiredAttribute<wxString>( aPart, "device" );
1556 package3d_urn = parseOptionalAttribute<wxString>( aPart, "package3d_urn" );
1557 override_package3d_urn = parseOptionalAttribute<wxString>( aPart, "override_package3d_urn" );
1558 override_package_urn = parseOptionalAttribute<wxString>( aPart, "override_package_urn" );
1559 override_locally_modified = parseOptionalAttribute<bool>( aPart, "override_locally_modified" );
1560 technology = parseOptionalAttribute<wxString>( aPart, "technology" );
1561 value = parseOptionalAttribute<wxString>( aPart, "value" );
1562
1563 for( wxXmlNode* child = aPart->GetChildren(); child; child = child->GetNext() )
1564 {
1565 if( child->GetName() == "attribute" )
1566 {
1567 std::unique_ptr<EATTR> attr = std::make_unique<EATTR>( child, aIo );
1568 attributes[ attr->name ] = std::move( attr );
1569 }
1570 else if( child->GetName() == "variant" )
1571 {
1572 std::unique_ptr<EVARIANT> variant = std::make_unique<EVARIANT>( child, aIo );
1573 variants[ variant->name ] = std::move( variant );
1574 }
1575 else if( child->GetName() == "spice" )
1576 {
1577 spice = std::make_unique<ESPICE>( child, aIo );
1578 }
1579 }
1580
1582}
1583
1584
1585EINSTANCE::EINSTANCE( wxXmlNode* aInstance, IO_BASE* aIo ) :
1586 EAGLE_BASE( aIo )
1587{
1588 /*
1589 * <!ELEMENT instance (attribute)*>
1590 * <!ATTLIST instance
1591 * part %String; #REQUIRED
1592 * gate %String; #REQUIRED
1593 * x %Coord; #REQUIRED
1594 * y %Coord; #REQUIRED
1595 * smashed %Bool; "no"
1596 * rot %Rotation; "R0"
1597 * >
1598 */
1599 part = parseRequiredAttribute<wxString>( aInstance, "part" );
1600 gate = parseRequiredAttribute<wxString>( aInstance, "gate" );
1601
1602 x = parseRequiredAttribute<ECOORD>( aInstance, "x" );
1603 y = parseRequiredAttribute<ECOORD>( aInstance, "y" );
1604
1605 // optional
1606 smashed = parseOptionalAttribute<bool>( aInstance, "smashed" );
1607 rot = parseOptionalAttribute<EROT>( aInstance, "rot" );
1608
1609 for( wxXmlNode* child = aInstance->GetChildren(); child; child = child->GetNext() )
1610 {
1611 if( child->GetName() == "attribute" )
1612 {
1613 std::unique_ptr<EATTR> attr = std::make_unique<EATTR>( child, aIo );
1614 attributes[ attr->name ] = std::move( attr );
1615 }
1616 }
1617
1619}
1620
1621
1622EGATE::EGATE( wxXmlNode* aGate, IO_BASE* aIo ) :
1623 EAGLE_BASE( aIo )
1624{
1625 /*
1626 * <!ELEMENT gate EMPTY>
1627 * <!ATTLIST gate
1628 * name %String; #REQUIRED
1629 * symbol %String; #REQUIRED
1630 * x %Coord; #REQUIRED
1631 * y %Coord; #REQUIRED
1632 * addlevel %GateAddLevel; "next"
1633 * swaplevel %Int; "0"
1634 * >
1635 */
1636
1637 name = parseRequiredAttribute<wxString>( aGate, "name" );
1638 symbol = parseRequiredAttribute<wxString>( aGate, "symbol" );
1639
1640 x = parseRequiredAttribute<ECOORD>( aGate, "x" );
1641 y = parseRequiredAttribute<ECOORD>( aGate, "y" );
1642
1643 opt_wxString stemp = parseOptionalAttribute<wxString>( aGate, "addlevel" );
1644
1645 // (off | value | name | both)
1646 if( stemp == "must" )
1648 else if( stemp == "can" )
1650 else if( stemp == "next" )
1652 else if( stemp == "request" )
1654 else if( stemp == "always" )
1656 else
1658
1659 swaplevel = parseOptionalAttribute<int>( aGate, "swaplevel" );
1660
1662}
1663
1664
1665ECONNECT::ECONNECT( wxXmlNode* aConnect, IO_BASE* aIo ) :
1666 EAGLE_BASE( aIo )
1667{
1668 /*
1669 * <!ELEMENT connect EMPTY>
1670 * <!ATTLIST connect
1671 * gate %String; #REQUIRED
1672 * pin %String; #REQUIRED
1673 * pad %String; #REQUIRED
1674 * route %ContactRoute; "all"
1675 * >
1676 */
1677 gate = parseRequiredAttribute<wxString>( aConnect, "gate" );
1678 pin = parseRequiredAttribute<wxString>( aConnect, "pin" );
1679 pad = parseRequiredAttribute<wxString>( aConnect, "pad" );
1680 contactroute = parseOptionalAttribute<wxString>( aConnect, "contactroute" );
1681
1683}
1684
1685
1686ETECHNOLOGY::ETECHNOLOGY( wxXmlNode* aTechnology, IO_BASE* aIo ) :
1687 EAGLE_BASE( aIo )
1688{
1689 /*
1690 * <!ELEMENT technology (attribute)*>
1691 * <!ATTLIST technology
1692 * name %String; #REQUIRED
1693 * >
1694 */
1695 name = parseRequiredAttribute<wxString>( aTechnology, "name" );
1696
1697 for( wxXmlNode* child = aTechnology->GetChildren(); child; child = child->GetNext() )
1698 {
1699 if( child->GetName() == "attribute" )
1700 attributes.emplace_back( std::make_unique<EATTR>( child, aIo ) );
1701 }
1702
1704}
1705
1706
1707EPACKAGE3DINST::EPACKAGE3DINST( wxXmlNode* aPackage3dInst, IO_BASE* aIo ) :
1708 EAGLE_BASE( aIo )
1709{
1710 /*
1711 * <!ELEMENT package3dinstance EMPTY>
1712 * <!ATTLIST package3dinstance
1713 * package3d_urn %Urn; #REQUIRED
1714 * >
1715 */
1716 package3d_urn = parseRequiredAttribute<wxString>( aPackage3dInst, "package3d_urn" );
1717
1719}
1720
1721
1722EDEVICE::EDEVICE( wxXmlNode* aDevice, IO_BASE* aIo ) :
1723 EAGLE_BASE( aIo )
1724{
1725 /*
1726 * <!ELEMENT device (connects?, package3dinstances?, technologies?)>
1727 * <!ATTLIST device
1728 * name %String; ""
1729 * package %String; #IMPLIED
1730 */
1731 name = parseRequiredAttribute<wxString>( aDevice, "name" );
1732 opt_wxString pack = parseOptionalAttribute<wxString>( aDevice, "package" );
1733
1734 if( pack )
1735 {
1736 std::string p( pack->c_str() );
1738 package.Set( wxString::FromUTF8( p.c_str() ) );
1739 }
1740
1741 for( wxXmlNode* child = aDevice->GetChildren(); child; child = child->GetNext() )
1742 {
1743 if( child->GetName() == "connects" )
1744 {
1745 for( wxXmlNode* connect = child->GetChildren(); connect; connect = connect->GetNext() )
1746 {
1747 if( connect->GetName() == "connect" )
1748 connects.emplace_back( std::make_unique<ECONNECT>( connect, aIo ) );
1749 }
1750
1752 }
1753 else if( child->GetName() == "packages3dinstances" )
1754 {
1755 for( wxXmlNode* package3dinst = child->GetChildren(); package3dinst;
1756 package3dinst = package3dinst->GetNext() )
1757 {
1758 if( package3dinst->GetName() == "package3dinstance" )
1759 package3dinstances.emplace_back( std::make_unique<EPACKAGE3DINST>( package3dinst, aIo ) );
1760 }
1761
1763 }
1764 else if( child->GetName() == "technologies" )
1765 {
1766 for( wxXmlNode* technology = child->GetChildren(); technology; technology = technology->GetNext() )
1767 {
1768 if( technology->GetName() == "technology" )
1769 {
1770 std::unique_ptr<ETECHNOLOGY> tmp = std::make_unique<ETECHNOLOGY>( technology, aIo );
1771 technologies[tmp->name] = std::move( tmp );
1772 }
1773 }
1774
1776 }
1777 }
1778
1780}
1781
1782
1783EDEVICE_SET::EDEVICE_SET( wxXmlNode* aDeviceSet, IO_BASE* aIo ) :
1784 EAGLE_BASE( aIo )
1785{
1786 /*
1787 * <!ELEMENT deviceset (description?, gates, devices, spice?)>
1788 * <!ATTLIST deviceset
1789 * name %String; #REQUIRED
1790 * urn %Urn; ""
1791 * locally_modified %Bool; "no"
1792 * prefix %String; ""
1793 * uservalue %Bool; "no"
1794 * library_version %Int; ""
1795 * library_locally_modified %Bool; "no"
1796 * >
1797 * <!-- library_version and library_locally_modified: Only in managed libraries
1798 * inside boards or schematics -->
1799 */
1800 name = parseRequiredAttribute<wxString>( aDeviceSet, "name" );
1801 urn = parseOptionalAttribute<EURN>( aDeviceSet, "urn" );
1802 locally_modified = parseOptionalAttribute<bool>( aDeviceSet, "locally_modified" );
1803 prefix = parseOptionalAttribute<wxString>( aDeviceSet, "prefix" );
1804 uservalue = parseOptionalAttribute<bool>( aDeviceSet, "uservalue" );
1805 library_version = parseOptionalAttribute<int>( aDeviceSet, "library_version" );
1807 parseOptionalAttribute<bool>( aDeviceSet, "library_locally_modified" );
1808
1809 for( wxXmlNode* child = aDeviceSet->GetChildren(); child; child = child->GetNext() )
1810 {
1811 if( child->GetName() == "description" )
1812 {
1813 description = std::make_optional<EDESCRIPTION>( child, aIo );
1814 }
1815 else if( child->GetName() == "gates" )
1816 {
1817 for( wxXmlNode* gate = child->GetChildren(); gate; gate = gate->GetNext() )
1818 {
1819 std::unique_ptr<EGATE> tmp = std::make_unique<EGATE>( gate, aIo );
1820 gates[tmp->name] = std::move( tmp );
1821 }
1822
1824 }
1825 else if( child->GetName() == "devices" )
1826 {
1827 for( wxXmlNode* device = child->GetChildren(); device; device = device->GetNext() )
1828 {
1829 std::unique_ptr<EDEVICE> tmp = std::make_unique<EDEVICE>( device, aIo );
1830 devices[tmp->name] = std::move( tmp );
1831 }
1832
1834 }
1835 else if( child->GetName() == "spice" )
1836 {
1837 spice = std::make_optional<ESPICE>( child, aIo );
1838 }
1839 }
1840
1842}
1843
1844
1845ECLASS::ECLASS( wxXmlNode* aClass, IO_BASE* aIo ) :
1846 EAGLE_BASE( aIo )
1847{
1848 /*
1849 * <!ELEMENT class (clearance)*>
1850 * <!ATTLIST class
1851 * number %Class; #REQUIRED
1852 * name %String; #REQUIRED
1853 * width %Dimension; "0"
1854 * drill %Dimension; "0"
1855 * >
1856 */
1857 number = parseRequiredAttribute<wxString>( aClass, "number" );
1858 name = parseRequiredAttribute<wxString>( aClass, "name" );
1859 width = parseOptionalAttribute<ECOORD>( aClass, "width" );
1860 drill = parseOptionalAttribute<ECOORD>( aClass, "drill" );
1861
1862 for( wxXmlNode* child = aClass->GetChildren(); child; child = child->GetNext() )
1863 {
1864 if( child->GetName() == "clearance" )
1865 {
1866 wxString to = parseRequiredAttribute<wxString>( child, "class" );
1867 ECOORD value = parseRequiredAttribute<ECOORD>( child, "value" );
1868
1869 clearanceMap[to] = value;
1870
1872 }
1873 }
1874
1876}
1877
1878
1879EPLAIN::EPLAIN( wxXmlNode* aPlain, IO_BASE* aIo ) :
1880 EAGLE_BASE( aIo )
1881{
1882 /*
1883 * <!ELEMENT plain (polygon | wire | text | dimension | circle | spline | rectangle |
1884 * frame | hole)*>
1885 */
1886 for( wxXmlNode* child = aPlain->GetChildren(); child; child = child->GetNext() )
1887 {
1888 if( child->GetName() == "polygon" )
1889 polygons.emplace_back( std::make_unique<EPOLYGON>( child, aIo ) );
1890 else if( child->GetName() == "wire" )
1891 wires.emplace_back( std::make_unique<EWIRE>( child, aIo ) );
1892 else if( child->GetName() == "text" )
1893 texts.emplace_back( std::make_unique<ETEXT>( child, aIo ) );
1894 else if( child->GetName() == "dimension" )
1895 dimensions.emplace_back( std::make_unique<EDIMENSION>( child, aIo ) );
1896 else if( child->GetName() == "circle" )
1897 circles.emplace_back( std::make_unique<ECIRCLE>( child, aIo ) );
1898 else if( child->GetName() == "spline" )
1899 splines.emplace_back( std::make_unique<ESPLINE>( child, aIo ) );
1900 else if( child->GetName() == "rectangle" )
1901 rectangles.emplace_back( std::make_unique<ERECT>( child, aIo ) );
1902 else if( child->GetName() == "frame" )
1903 frames.emplace_back( std::make_unique<EFRAME>( child, aIo ) );
1904 else if( child->GetName() == "hole" )
1905 holes.emplace_back( std::make_unique<EHOLE>( child, aIo ) );
1906 }
1907
1909}
1910
1911
1912EMODULEINST::EMODULEINST( wxXmlNode* aModuleInst, IO_BASE* aIo ) :
1913 EAGLE_BASE( aIo )
1914{
1915 /*
1916 * <!ELEMENT moduleinst (attribute)*>
1917 * <!ATTLIST moduleinst
1918 * name %String; #REQUIRED
1919 * module %String; #REQUIRED
1920 * modulevariant %String; ""
1921 * x %Coord; #REQUIRED
1922 * y %Coord; #REQUIRED
1923 * offset %Int; "0"
1924 * smashed %Bool; "no"
1925 * rot %Rotation; "R0"
1926 * >
1927 * <!-- rot: Only 0, 90, 180 or 270 -->
1928 */
1929 name = parseRequiredAttribute<wxString>( aModuleInst, "name" );
1930 moduleinst = parseRequiredAttribute<wxString>( aModuleInst, "module" );
1931 moduleVariant = parseOptionalAttribute<wxString>( aModuleInst, "modulevariant" );
1932 x = parseRequiredAttribute<ECOORD>( aModuleInst, "x" );
1933 y = parseRequiredAttribute<ECOORD>( aModuleInst, "y" );
1934 offset = parseOptionalAttribute<int>( aModuleInst, "offset" );
1935 smashed = parseOptionalAttribute<bool>( aModuleInst, "smashed" );
1936 rotation = parseOptionalAttribute<EROT>( aModuleInst, "rot" );
1937
1939}
1940
1941
1942ESHEET::ESHEET( wxXmlNode* aSheet, IO_BASE* aIo ) :
1943 EAGLE_BASE( aIo )
1944{
1945 /*
1946 * <!ELEMENT sheet (description?, plain?, moduleinsts?, instances?, busses?, nets?)>
1947 */
1948 for( wxXmlNode* child = aSheet->GetChildren(); child; child = child->GetNext() )
1949 {
1950 if( child->GetName() == "description" )
1951 {
1952 description = std::make_optional<EDESCRIPTION>( child, aIo );
1953 }
1954 else if( child->GetName() == "plain" )
1955 {
1956 plain = std::make_unique<EPLAIN>( child, aIo );
1957 }
1958 else if( child->GetName() == "moduleinsts" )
1959 {
1960 for( wxXmlNode* moduleinst = child->GetChildren(); moduleinst;
1961 moduleinst = moduleinst->GetNext() )
1962 {
1963 if( moduleinst->GetName() == "moduleinst" )
1964 {
1965 std::unique_ptr<EMODULEINST> inst = std::make_unique<EMODULEINST>( moduleinst, aIo );
1966 moduleinsts[ inst->name ] = std::move( inst );
1967 }
1968 }
1969
1971 }
1972 else if( child->GetName() == "instances" )
1973 {
1974 for( wxXmlNode* instance = child->GetChildren(); instance; instance = instance->GetNext() )
1975 {
1976 if( instance->GetName() == "instance" )
1977 instances.emplace_back( std::make_unique<EINSTANCE>( instance, aIo ) );
1978 }
1979
1980 AdvanceProgressPhase();
1981 }
1982 else if( child->GetName() == "busses" )
1983 {
1984 for( wxXmlNode* bus = child->GetChildren(); bus; bus = bus->GetNext() )
1985 {
1986 if( bus->GetName() == "bus" )
1987 busses.emplace_back( std::make_unique<EBUS>( bus, aIo ) );
1988 }
1989
1990 AdvanceProgressPhase();
1991 }
1992 else if( child->GetName() == "nets" )
1993 {
1994 for( wxXmlNode* net = child->GetChildren(); net; net = net->GetNext() )
1995 {
1996 if( net->GetName() == "net" )
1997 nets.emplace_back( std::make_unique<ENET>( net, aIo ) );
1998 }
1999
2000 AdvanceProgressPhase();
2001 }
2002 }
2003
2004 AdvanceProgressPhase();
2005}
2006
2007
2008ESCHEMATIC_GROUP::ESCHEMATIC_GROUP( wxXmlNode* aSchematicGroup, IO_BASE* aIo ) :
2009 EAGLE_BASE( aIo )
2010{
2011 /*
2012 * <!ELEMENT schematic_group (attribute*, description?)>
2013 * <!ATTLIST schematic_group
2014 * name ID #REQUIRED
2015 * selectable %Bool; #IMPLIED
2016 * width %Dimension; #IMPLIED
2017 * titleSize %Dimension; #IMPLIED
2018 * titleFont %TextFont; #IMPLIED
2019 * style %WireStyle; #IMPLIED
2020 * showAnnotations %Bool; #IMPLIED
2021 * layer %Layer; #IMPLIED
2022 * grouprefs IDREFS #IMPLIED
2023 * >
2024 */
2025 name = parseRequiredAttribute<wxString>( aSchematicGroup, "name" );
2026 selectable = parseOptionalAttribute<bool>( aSchematicGroup, "selectable" );
2027 width = parseOptionalAttribute<ECOORD>( aSchematicGroup, "width" );
2028 titleSize = parseOptionalAttribute<ECOORD>( aSchematicGroup, "titleSize" );
2029 titleFont = parseOptionalAttribute<wxString>( aSchematicGroup, "font" );
2030 wireStyle = parseOptionalAttribute<wxString>( aSchematicGroup, "style" );
2031 showAnnotations = parseOptionalAttribute<bool>( aSchematicGroup, "showAnnotations" );
2032 layer = parseOptionalAttribute<int>( aSchematicGroup, "layer" );
2033 grouprefs = parseOptionalAttribute<wxString>( aSchematicGroup, "grouprefs" );
2034
2035 for( wxXmlNode* child = aSchematicGroup->GetChildren(); child; child = child->GetNext() )
2036 {
2037 if( child->GetName() == "description" )
2038 {
2039 description = std::make_optional<EDESCRIPTION>( child, aIo );
2040 }
2041 else if( child->GetName() == "attribute" )
2042 {
2043 attributes.emplace_back( std::make_unique<EATTR>( child, aIo ) );
2044 }
2045 }
2046
2048}
2049
2050
2051EMODULE::EMODULE( wxXmlNode* aModule, IO_BASE* aIo ) :
2052 EAGLE_BASE( aIo )
2053{
2054 /*
2055 * <!ELEMENT module (description?, ports?, variantdefs?, groups?, parts?, sheets?)>
2056 * <!ATTLIST module
2057 * name %String; #REQUIRED
2058 * prefix %String; ""
2059 * dx %Coord; #REQUIRED
2060 * dy %Coord; #REQUIRED
2061 * >
2062 */
2063 name = parseRequiredAttribute<wxString>( aModule, "name" );
2064 prefix = parseOptionalAttribute<wxString>( aModule, "prefix" );
2065 dx = parseRequiredAttribute<ECOORD>( aModule, "dx" );
2066 dy = parseRequiredAttribute<ECOORD>( aModule, "dy" );
2067
2068 for( wxXmlNode* child = aModule->GetChildren(); child; child = child->GetNext() )
2069 {
2070 if( child->GetName() == "description" )
2071 {
2072 description = std::make_optional<EDESCRIPTION>( child, aIo );
2073 }
2074 else if( child->GetName() == "ports" )
2075 {
2076 for( wxXmlNode* port = child->GetChildren(); port; port = port->GetNext() )
2077 {
2078 if( port->GetName() == "port" )
2079 {
2080 std::unique_ptr<EPORT> tmp = std::make_unique<EPORT>( port, aIo );
2081 ports[ tmp->name ] = std::move( tmp );
2082 }
2083 }
2084
2086 }
2087 else if( child->GetName() == "variantdefs" )
2088 {
2089 for( wxXmlNode* variantdef = child->GetChildren(); variantdef;
2090 variantdef = variantdef->GetNext() )
2091 {
2092 if( variantdef->GetName() == "variantdef" )
2093 {
2094 std::unique_ptr<EVARIANTDEF> tmp = std::make_unique<EVARIANTDEF>( variantdef,
2095 aIo );
2096 variantdefs[ tmp->name ] = std::move( tmp );
2097 }
2098 }
2099
2101 }
2102 else if( child->GetName() == "groups" )
2103 {
2104 for( wxXmlNode* group = child->GetChildren(); group; group = group->GetNext() )
2105 {
2106 if( group->GetName() == "schematic_group" )
2107 {
2108 std::unique_ptr<ESCHEMATIC_GROUP> tmp =
2109 std::make_unique<ESCHEMATIC_GROUP>( group, aIo );
2110 groups[ tmp->name ] = std::move( tmp );
2111 }
2112 }
2113
2115 }
2116 else if( child->GetName() == "parts" )
2117 {
2118 for( wxXmlNode* part = child->GetChildren(); part; part = part->GetNext() )
2119 {
2120 if( part->GetName() == "part" )
2121 {
2122 std::unique_ptr<EPART> tmp = std::make_unique<EPART>( part, aIo );
2123 parts[ tmp->name ] = std::move( tmp );
2124 }
2125 }
2126
2128 }
2129 else if( child->GetName() == "sheets" )
2130 {
2131 for( wxXmlNode* sheet = child->GetChildren(); sheet; sheet = sheet->GetNext() )
2132 {
2133 if( sheet->GetName() == "sheet" )
2134 sheets.emplace_back( std::make_unique<ESHEET>( sheet, aIo ) );
2135 }
2136
2138 }
2139 }
2140
2142}
2143
2144
2145EPORT::EPORT( wxXmlNode* aPort, IO_BASE* aIo ) :
2146 EAGLE_BASE( aIo )
2147{
2148 /*
2149 * <!ELEMENT port EMPTY>
2150 * <!ATTLIST port
2151 * name %String; #REQUIRED
2152 * side %Int; #REQUIRED
2153 * coord %Coord; #REQUIRED
2154 * direction %PortDirection; "io"
2155 * >
2156 */
2157 name = parseRequiredAttribute<wxString>( aPort, "name" );
2158 side = parseRequiredAttribute<wxString>( aPort, "side" );
2159 coord = parseRequiredAttribute<ECOORD>( aPort, "coord" );
2160 direction = parseOptionalAttribute<wxString>( aPort, "direction" );
2161
2163}
2164
2165
2166EVARIANTDEF::EVARIANTDEF( wxXmlNode* aVariantDef, IO_BASE* aIo ) :
2167 EAGLE_BASE( aIo )
2168{
2169 /*
2170 * <!ELEMENT variantdef EMPTY>
2171 * <!ATTLIST variantdef
2172 * name %String; #REQUIRED
2173 * current %Bool; "no"
2174 * >
2175 */
2176 name = parseRequiredAttribute<wxString>( aVariantDef, "name" );
2177 current = parseOptionalAttribute<bool>( aVariantDef, "current" );
2178
2180}
2181
2182
2183ENOTE::ENOTE( wxXmlNode* aNote, IO_BASE* aIo ) :
2184 EAGLE_BASE( aIo )
2185{
2186 /*
2187 * <!ELEMENT note (#PCDATA)>
2188 * <!ATTLIST note
2189 * version %Real; #REQUIRED
2190 * severity %Severity; #REQUIRED
2191 * >
2192 * <!-- version: The EAGLE program version that introduced this compatibility note -->
2193 */
2194 version = parseRequiredAttribute<double>( aNote, "version" );
2195 severity = parseRequiredAttribute<wxString>( aNote, "severity" );
2196
2197 note = aNote->GetNodeContent();
2198
2200}
2201
2202
2203ECOMPATIBILITY::ECOMPATIBILITY( wxXmlNode* aCompatibility, IO_BASE* aIo ) :
2204 EAGLE_BASE( aIo )
2205{
2206 /*
2207 * <!ELEMENT compatibility (note)*>
2208 */
2209 for( wxXmlNode* child = aCompatibility->GetNext(); child; child = child->GetNext() )
2210 {
2211 if( child->GetName() == "note" )
2212 notes.emplace_back( std::make_unique<ENOTE>( child ) );
2213 }
2214
2216}
2217
2218
2219ESETTING::ESETTING( wxXmlNode* aSetting, IO_BASE* aIo ) :
2220 EAGLE_BASE( aIo )
2221{
2222 /*
2223 * <!ELEMENT setting EMPTY>
2224 * <!ATTLIST setting
2225 * alwaysvectorfont %Bool; #IMPLIED
2226 * verticaltext %VerticalText; "up"
2227 * keepoldvectorfont %Bool; "no"
2228 * >
2229 */
2230 alwaysvectorfont = parseOptionalAttribute<bool>( aSetting, "alwaysvectorfont" );
2231 verticaltext = parseOptionalAttribute<wxString>( aSetting, "verticaltext" );
2232 keepoldvectorfont = parseOptionalAttribute<bool>( aSetting, "keepoldvectorfont" );
2233
2235}
2236
2237
2238EGRID::EGRID( wxXmlNode* aGrid, IO_BASE* aIo ) :
2239 EAGLE_BASE( aIo )
2240{
2241 /*
2242 * <!ELEMENT grid EMPTY>
2243 * <!ATTLIST grid
2244 * distance %Real; #IMPLIED
2245 * unitdist %GridUnit; #IMPLIED
2246 * unit %GridUnit; #IMPLIED
2247 * style %GridStyle; "lines"
2248 * multiple %Int; "1"
2249 * display %Bool; "no"
2250 * altdistance %Real; #IMPLIED
2251 * altunitdist %GridUnit; #IMPLIED
2252 * altunit %GridUnit; #IMPLIED
2253 * >
2254 */
2255 distance = parseOptionalAttribute<double>( aGrid, "distance" );
2256 unitdist = parseOptionalAttribute<wxString>( aGrid, "unitdist" );
2257 unit = parseOptionalAttribute<wxString>( aGrid, "unit" );
2258 style = parseOptionalAttribute<wxString>( aGrid, "style" );
2259 multiple = parseOptionalAttribute<int>( aGrid, "multiple" );
2260 display = parseOptionalAttribute<bool>( aGrid, "display" );
2261 altdistance = parseOptionalAttribute<double>( aGrid, "altdistance" );
2262 altunitdist = parseOptionalAttribute<wxString>( aGrid, "altunitdist" );
2263 altunit = parseOptionalAttribute<wxString>( aGrid, "altunit" );
2264
2266}
2267
2268
2269EFILTER::EFILTER( wxXmlNode* aFilter, IO_BASE* aIo ) :
2270 EAGLE_BASE( aIo )
2271{
2272 /*
2273 * <!ELEMENT filter EMPTY>
2274 * <!ATTLIST filter
2275 * name %String; #REQUIRED
2276 * expression %String; #REQUIRED
2277 * >
2278 */
2279 name = parseRequiredAttribute<wxString>( aFilter, "name" );
2280 expression = parseRequiredAttribute<wxString>( aFilter, "expression" );
2281
2283};
2284
2285
2286EPACKAGE::EPACKAGE( wxXmlNode* aPackage, IO_BASE* aIo ) :
2287 EAGLE_BASE( aIo )
2288{
2289 /*
2290 * <!ELEMENT package (description?, (polygon | wire | text | dimension | circle |
2291 * rectangle | frame | hole | pad | smd)*)>
2292 * <!ATTLIST package
2293 * name %String; #REQUIRED
2294 * urn %Urn; ""
2295 * locally_modified %Bool; "no"
2296 * library_version %Int; ""
2297 * library_locally_modified %Bool; "no"
2298 * >
2299 * <!-- library_version and library_locally_modified: Only in managed libraries
2300 * inside boards or schematics -->
2301 */
2302 name = parseRequiredAttribute<wxString>( aPackage, "name" );
2303 urn = parseOptionalAttribute<EURN>( aPackage, "urn" );
2304 locally_modified = parseOptionalAttribute<bool>( aPackage, "locally_modified" );
2305 library_version = parseOptionalAttribute<int>( aPackage, "library_version" );
2306 library_locally_modified = parseOptionalAttribute<bool>( aPackage, "library_locally_modified" );
2307
2308 for( wxXmlNode* child = aPackage->GetChildren(); child; child = child->GetNext() )
2309 {
2310 if( child->GetName() == "description" )
2311 {
2312 description = std::make_optional<EDESCRIPTION>( child, aIo );
2313 }
2314 else if( child->GetName() == "polygon" )
2315 {
2316 polygons.emplace_back( std::make_unique<EPOLYGON>( child, aIo ) );
2317 }
2318 else if( child->GetName() == "wire" )
2319 {
2320 wires.emplace_back( std::make_unique<EWIRE>( child, aIo ) );
2321 }
2322 else if( child->GetName() == "text" )
2323 {
2324 texts.emplace_back( std::make_unique<ETEXT>( child, aIo ) );
2325 }
2326 else if( child->GetName() == "dimension" )
2327 {
2328 dimensions.emplace_back( std::make_unique<EDIMENSION>( child, aIo ) );
2329 }
2330 else if( child->GetName() == "circle" )
2331 {
2332 circles.emplace_back( std::make_unique<ECIRCLE>( child, aIo ) );
2333 }
2334 else if( child->GetName() == "rectangle" )
2335 {
2336 rectangles.emplace_back( std::make_unique<ERECT>( child, aIo ) );
2337 }
2338 else if( child->GetName() == "frame" )
2339 {
2340 frames.emplace_back( std::make_unique<EFRAME>( child, aIo ) );
2341 }
2342 else if( child->GetName() == "hole" )
2343 {
2344 holes.emplace_back( std::make_unique<EHOLE>( child, aIo ) );
2345 }
2346 else if( child->GetName() == "pad" )
2347 {
2348 thtpads.emplace_back( std::make_unique<EPAD>( child, aIo ) );
2349 }
2350 else if( child->GetName() == "smd" )
2351 {
2352 smdpads.emplace_back( std::make_unique<ESMD>( child, aIo ) );
2353 }
2354 }
2355
2357}
2358
2359
2360EPACKAGEINSTANCE::EPACKAGEINSTANCE( wxXmlNode* aPackageInstance, IO_BASE* aIo ) :
2361 EAGLE_BASE( aIo )
2362{
2363 /*
2364 * <!ELEMENT packageinstance EMPTY>
2365 * <!ATTLIST packageinstance
2366 * name %String; #REQUIRED
2367 * >
2368 */
2369 name = parseRequiredAttribute<wxString>( aPackageInstance, "name" );
2370
2372}
2373
2374
2375EPACKAGE3D::EPACKAGE3D( wxXmlNode* aPackage3d, IO_BASE* aIo ) :
2376 EAGLE_BASE( aIo )
2377{
2378 /*
2379 * <!ELEMENT package3d (description?, packageinstances?)>
2380 * <!ATTLIST package3d
2381 * name %String; ""
2382 * urn %Urn; #REQUIRED
2383 * type %Package3dType; #REQUIRED
2384 * library_version %Int; ""
2385 * library_locally_modified %Bool; "no"
2386 * >
2387 * <!-- library_version and library_locally_modified: Only in managed libraries
2388 * inside boards or schematics -->
2389 */
2390 name = parseRequiredAttribute<wxString>( aPackage3d, "name" );
2391 urn = parseRequiredAttribute<wxString>( aPackage3d, "urn" );
2392 type = parseRequiredAttribute<wxString>( aPackage3d, "type" );
2393 library_version = parseOptionalAttribute<int>( aPackage3d, "library_version" );
2395 "library_locally_modified" );
2396
2397 for( wxXmlNode* child = aPackage3d->GetChildren(); child; child = child->GetNext() )
2398 {
2399 if( child->GetName() == "description" )
2400 {
2401 description = std::make_optional<EDESCRIPTION>( child, aIo );
2402 }
2403 else if( child->GetName() == "packageinstances" )
2404 {
2405 for( wxXmlNode* instance = child->GetChildren(); instance;
2406 instance = instance->GetNext() )
2407 packageinstances.emplace_back( std::make_unique<EPACKAGEINSTANCE>( instance,
2408 aIo ) );
2409
2411 }
2412 }
2413
2415}
2416
2417
2418ESYMBOL::ESYMBOL( wxXmlNode* aSymbol, IO_BASE* aIo ) :
2419 EAGLE_BASE( aIo )
2420{
2421 /*
2422 * <!ELEMENT symbol (description?, (polygon | wire | text | dimension | pin | circle |
2423 * rectangle | frame)*)>
2424 * <!ATTLIST symbol
2425 * name %String; #REQUIRED
2426 * urn %Urn; ""
2427 * locally_modified %Bool; "no"
2428 * library_version %Int; ""
2429 * library_locally_modified %Bool; "no"
2430 * >
2431 * <!-- library_version and library_locally_modified: Only in managed libraries
2432 * inside boards or schematics -->
2433 */
2434
2435 name = parseRequiredAttribute<wxString>( aSymbol, "name" );
2436 urn = parseOptionalAttribute<EURN>( aSymbol, "urn" );
2437 locally_modified = parseOptionalAttribute<bool>( aSymbol, "locally_modified" );
2438 library_version = parseOptionalAttribute<int>( aSymbol, "library_version" );
2439 library_locally_modified = parseOptionalAttribute<bool>( aSymbol, "library_locally_modified" );
2440
2441 for( wxXmlNode* child = aSymbol->GetChildren(); child; child = child->GetNext() )
2442 {
2443 if( child->GetName() == "description" )
2444 {
2445 description = std::make_optional<EDESCRIPTION>( child, aIo );
2446 }
2447 else if( child->GetName() == "polygon" )
2448 {
2449 polygons.emplace_back( std::make_unique<EPOLYGON>( child, aIo ) );
2450 }
2451 else if( child->GetName() == "wire" )
2452 {
2453 wires.emplace_back( std::make_unique<EWIRE>( child, aIo ) );
2454 }
2455 else if( child->GetName() == "text" )
2456 {
2457 texts.emplace_back( std::make_unique<ETEXT>( child, aIo ) );
2458 }
2459 else if( child->GetName() == "dimension" )
2460 {
2461 dimensions.emplace_back( std::make_unique<EDIMENSION>( child, aIo ) );
2462 }
2463 else if( child->GetName() == "pin" )
2464 {
2465 pins.emplace_back( std::make_unique<EPIN>( child, aIo ) );
2466 }
2467 else if( child->GetName() == "circle" )
2468 {
2469 circles.emplace_back( std::make_unique<ECIRCLE>( child, aIo ) );
2470 }
2471 else if( child->GetName() == "rectangle" )
2472 {
2473 rectangles.emplace_back( std::make_unique<ERECT>( child, aIo ) );
2474 }
2475 else if( child->GetName() == "frame" )
2476 {
2477 frames.emplace_back( std::make_unique<EFRAME>( child, aIo ) );
2478 }
2479 }
2480
2482}
2483
2484
2485ELIBRARY::ELIBRARY( wxXmlNode* aLibrary, IO_BASE* aIo ) :
2486 EAGLE_BASE( aIo )
2487{
2488 /*
2489 * <!ELEMENT library (description?, packages?, packages3d?, symbols?, devicesets?)>
2490 * <!ATTLIST library
2491 * name %String; #REQUIRED
2492 * urn %Urn; ""
2493 * >
2494 * <!-- name: Only in libraries used inside boards or schematics -->
2495 * <!-- urn: Only in online libraries used inside boards or schematics -->
2496 */
2497
2498 // The name and urn attributes are only valid in schematic and board files.
2499 wxString parentNodeName;
2500
2501 if( aLibrary->GetParent() )
2502 parentNodeName = aLibrary->GetParent()->GetName();
2503
2504 if( parentNodeName == "libraries" )
2505 {
2506 name = parseRequiredAttribute<wxString>( aLibrary, "name" );
2507 urn = parseOptionalAttribute<EURN>( aLibrary, "urn" );
2508 }
2509
2510 for( wxXmlNode* child = aLibrary->GetChildren(); child; child = child->GetNext() )
2511 {
2512 if( child->GetName() == "description" )
2513 {
2514 description = std::make_optional<EDESCRIPTION>( child, aIo );
2515 }
2516 else if( child->GetName() == "packages" )
2517 {
2518 for( wxXmlNode* package = child->GetChildren(); package; package = package->GetNext() )
2519 {
2520 if( package->GetName() == "package" )
2521 {
2522 std::unique_ptr<EPACKAGE> tmp = std::make_unique<EPACKAGE>( package, aIo );
2523 packages[ tmp->name ] = std::move( tmp );
2524 }
2525 }
2526
2528 }
2529 else if( child->GetName() == "packages3d" )
2530 {
2531 for( wxXmlNode* package3d = child->GetChildren(); package3d;
2532 package3d = package3d->GetNext() )
2533 {
2534 if( package3d->GetName() == "package3d" )
2535 {
2536 std::unique_ptr<EPACKAGE3D> tmp = std::make_unique<EPACKAGE3D>( package3d,
2537 aIo );
2538 packages3d[ tmp->name ] = std::move( tmp );
2539 }
2540 }
2541
2542 AdvanceProgressPhase();
2543 }
2544 else if( child->GetName() == "symbols" )
2545 {
2546 for( wxXmlNode* symbol = child->GetChildren(); symbol; symbol = symbol->GetNext() )
2547 {
2548 if( symbol->GetName() == "symbol" )
2549 {
2550 std::unique_ptr<ESYMBOL> tmp = std::make_unique<ESYMBOL>( symbol, aIo );
2551 symbols[ tmp->name ] = std::move( tmp );
2552 }
2553 }
2554
2555 AdvanceProgressPhase();
2556 }
2557 else if( child->GetName() == "devicesets" )
2558 {
2559 for( wxXmlNode* deviceset = child->GetChildren(); deviceset;
2560 deviceset = deviceset->GetNext() )
2561 {
2562 if( deviceset->GetName() == "deviceset" )
2563 {
2564 std::unique_ptr<EDEVICE_SET> tmp = std::make_unique<EDEVICE_SET>( deviceset,
2565 aIo );
2566 devicesets[ tmp->name ] = std::move( tmp );
2567 }
2568 }
2569
2570 AdvanceProgressPhase();
2571 }
2572 }
2573
2574 AdvanceProgressPhase();
2575}
2576
2577
2578wxString ELIBRARY::GetName() const
2579{
2580 wxString libName = name;
2581
2582 // Use the name when no library urn exists.
2583 if( !urn )
2584 return libName;
2585
2586 // Suffix the library name with the urn library identifier. Eagle schematics can have
2587 // mulitple libraries with the same name. The urn library identifier is used to prevent
2588 // library name clashes.
2589 if( urn->IsValid() )
2590 libName += wxS( "_" ) + urn->assetId;
2591
2592 return libName;
2593}
2594
2595
2596EAPPROVED::EAPPROVED( wxXmlNode* aApproved, IO_BASE* aIo ) :
2597 EAGLE_BASE( aIo )
2598{
2599 /*
2600 * <!ELEMENT approved EMPTY>
2601 * <!ATTLIST approved
2602 * hash %String; #REQUIRED
2603 * >
2604 */
2605 hash = parseRequiredAttribute<wxString>( aApproved, "hash" );
2606
2608}
2609
2610
2611ESCHEMATIC::ESCHEMATIC( wxXmlNode* aSchematic, IO_BASE* aIo ) :
2612 EAGLE_BASE( aIo )
2613{
2614 /*
2615 * <!ELEMENT schematic (description?, libraries?, attributes?, variantdefs?, classes?,
2616 * modules?, groups?, parts?, sheets?, errors?)>
2617 * <!ATTLIST schematic
2618 * xreflabel %String; #IMPLIED
2619 * xrefpart %String; #IMPLIED
2620 * >
2621 */
2622 xreflabel = parseOptionalAttribute<wxString>( aSchematic, "xreflabel" );
2623 xrefpart = parseOptionalAttribute<wxString>( aSchematic, "xrefpart" );
2624
2625 for( wxXmlNode* child = aSchematic->GetChildren(); child; child = child->GetNext() )
2626 {
2627 if( child->GetName() == "description" )
2628 {
2629 description = std::make_optional<EDESCRIPTION>( child, aIo );
2630 }
2631 else if( child->GetName() == "libraries" )
2632 {
2633 for( wxXmlNode* library = child->GetChildren(); library; library = library->GetNext() )
2634 {
2635 if( library->GetName() == "library" )
2636 {
2637 std::unique_ptr<ELIBRARY> tmp = std::make_unique<ELIBRARY>( library, aIo );
2638
2639 wxString libName = tmp->GetName();
2640
2641 // Prevent duplicate library names. This should only happen if the Eagle
2642 // file has an invalid format.
2643 if( libraries.find( libName ) != libraries.end() )
2644 {
2645 wxString uniqueName;
2646 std::set<wxString> usedNames;
2647
2648 for( const auto& [setName, setLibrary] : libraries )
2649 usedNames.emplace( setName );
2650
2651 // One of _1.._N+1 is always free (pigeonhole); the bound also
2652 // stops an infinite loop on malformed names (e.g. embedded
2653 // NULs) whose suffixed variants all compare equal.
2654 for( int i = 1; i <= (int) usedNames.size() + 1; i++ )
2655 {
2656 uniqueName.Format( wxS( "%s_%d" ), libName, i );
2657
2658 if( usedNames.find( uniqueName ) == usedNames.end() )
2659 break;
2660 }
2661
2662 libName = uniqueName;
2663 }
2664
2665 libraries[ libName ] = std::move( tmp );
2666 }
2667 }
2668
2670 }
2671 else if( child->GetName() == "attributes" )
2672 {
2673 for( wxXmlNode* attribute = child->GetChildren(); attribute;
2674 attribute = attribute->GetNext() )
2675 {
2676 if( attribute->GetName() == "attribute" )
2677 {
2678 std::unique_ptr<EATTR> tmp = std::make_unique<EATTR>( attribute, aIo );
2679 attributes[ tmp->name ] = std::move( tmp );
2680 }
2681 }
2682
2684 }
2685 else if( child->GetName() == "variantdefs" )
2686 {
2687 for( wxXmlNode* variantdef = child->GetChildren(); variantdef;
2688 variantdef = variantdef->GetNext() )
2689 {
2690 if( variantdef->GetName() == "variantdef" )
2691 {
2692 std::unique_ptr<EVARIANTDEF> tmp = std::make_unique<EVARIANTDEF>( variantdef,
2693 aIo );
2694 variantdefs[ tmp->name ] = std::move( tmp );
2695 }
2696 }
2697
2699 }
2700 else if( child->GetName() == "classes" )
2701 {
2702 for( wxXmlNode* eclass = child->GetChildren(); eclass; eclass = eclass->GetNext() )
2703 {
2704 if( eclass->GetName() == "class" )
2705 {
2706 std::unique_ptr<ECLASS> tmp = std::make_unique<ECLASS>( eclass, aIo );
2707 classes[ tmp->number ] = std::move( tmp );
2708 }
2709 }
2710
2712 }
2713 else if( child->GetName() == "modules" )
2714 {
2715 for( wxXmlNode* mod = child->GetChildren(); mod; mod = mod->GetNext() )
2716 {
2717 if( mod->GetName() == "module" )
2718 {
2719 std::unique_ptr<EMODULE> tmp = std::make_unique<EMODULE>( mod, aIo );
2720 modules[ tmp->name ] = std::move( tmp );
2721 }
2722 }
2723
2725 }
2726 else if( child->GetName() == "groups" )
2727 {
2728 for( wxXmlNode* group = child->GetChildren(); group; group = group->GetNext() )
2729 {
2730 if( group->GetName() == "schematic_group" )
2731 {
2732 std::unique_ptr<ESCHEMATIC_GROUP> tmp =
2733 std::make_unique<ESCHEMATIC_GROUP>( group, aIo );
2734 groups[ tmp->name ] = std::move( tmp );
2735 }
2736 }
2737
2739 }
2740 else if( child->GetName() == "parts" )
2741 {
2742 for( wxXmlNode* part = child->GetChildren(); part; part = part->GetNext() )
2743 {
2744 if( part->GetName() == "part" )
2745 {
2746 std::unique_ptr<EPART> tmp = std::make_unique<EPART>( part, aIo );
2747 parts[ tmp->name ] = std::move( tmp );
2748 }
2749 }
2750
2752 }
2753 else if( child->GetName() == "sheets" )
2754 {
2755 for( wxXmlNode* sheet = child->GetChildren(); sheet; sheet = sheet->GetNext() )
2756 {
2757 if( sheet->GetName() == "sheet" )
2758 sheets.emplace_back( std::make_unique<ESHEET>( sheet, aIo ) );
2759 }
2760
2762 }
2763 else if( child->GetName() == "errors" )
2764 {
2765 for( wxXmlNode* error = child->GetChildren(); error; error = error->GetNext() )
2766 {
2767 if( error->GetName() == "approved" )
2768 errors.emplace_back( std::make_unique<EAPPROVED>( error, aIo ) );
2769 }
2770
2772 }
2773 }
2774
2776}
2777
2778
2779EDRAWING::EDRAWING( wxXmlNode* aDrawing, IO_BASE* aIo ) :
2780 EAGLE_BASE( aIo )
2781{
2782 /*
2783 * <!ELEMENT drawing (settings?, grid?, filters?, layers, (library | schematic | board))>
2784 */
2785 for( wxXmlNode* child = aDrawing->GetChildren(); child; child = child->GetNext() )
2786 {
2787 if( child->GetName() == "settings" )
2788 {
2789 for( wxXmlNode* setting = child->GetChildren(); setting; setting = setting->GetNext() )
2790 settings.emplace_back( std::make_unique<ESETTING>( setting, aIo ) );
2791
2792 AdvanceProgressPhase();
2793 }
2794 else if( child->GetName() == "grid" )
2795 {
2796 grid = std::make_optional<EGRID>( child, aIo );
2797 }
2798 else if( child->GetName() == "filters" )
2799 {
2800 for( wxXmlNode* filter = child->GetChildren(); filter; filter = filter->GetNext() )
2801 {
2802 if( filter->GetName() == "filter" )
2803 filters.emplace_back( std::make_unique<EFILTER>( filter, aIo ) );
2804 }
2805
2807 }
2808 else if( child->GetName() == "layers" )
2809 {
2810 for( wxXmlNode* layer = child->GetChildren(); layer; layer = layer->GetNext() )
2811 {
2812 if( layer->GetName() == "layer" )
2813 layers.emplace_back( std::make_unique<ELAYER>( layer, aIo ) );
2814 }
2815
2816 AdvanceProgressPhase();
2817 }
2818 else if( child->GetName() == "schematic" )
2819 {
2820 schematic = std::make_optional<ESCHEMATIC>( child, aIo );
2821 }
2822 else if( child->GetName() == "library" )
2823 {
2824 library = std::make_optional<ELIBRARY>( child, aIo );
2825 }
2826 }
2827
2828 // std::optional<std::unique_ptr<EBOARD>> board;
2829
2830 AdvanceProgressPhase();
2831}
2832
2833
2834EAGLE_DOC::EAGLE_DOC( wxXmlNode* aEagleDoc, IO_BASE* aIo ) :
2835 EAGLE_BASE( aIo )
2836{
2837 /*
2838 * <!ELEMENT eagle (compatibility?, drawing, compatibility?)>
2839 * <!ATTLIST eagle
2840 * version %Real; #REQUIRED
2841 * >
2842 * <!-- version: The EAGLE program version that generated this file, in the
2843 * form V.RR -->
2844 */
2845
2846 version = parseRequiredAttribute<wxString>( aEagleDoc, "version" );
2847
2848 for( wxXmlNode* child = aEagleDoc->GetChildren(); child; child = child->GetNext() )
2849 {
2850 if( child->GetName() == "compitibility" )
2851 compatibility = std::make_optional<ECOMPATIBILITY>( child, aIo );
2852 else if( child->GetName() == "drawing" )
2853 drawing = std::make_unique<EDRAWING>( child, aIo );
2854 }
2855
2857}
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_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
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