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