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