/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2012-2021 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2017 CERN. * * @author Alejandro GarcĂ­a Montoro * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include constexpr auto DEFAULT_ALIGNMENT = ETEXT::BOTTOM_LEFT; wxString escapeName( const wxString& aNetName ) { wxString ret( aNetName ); ret.Replace( wxT( "!" ), wxT( "~" ) ); return ConvertToNewOverbarNotation( ret ); } template<> template<> OPTIONAL_XML_ATTRIBUTE::OPTIONAL_XML_ATTRIBUTE( wxString aData ) { m_isAvailable = !aData.IsEmpty(); if( m_isAvailable ) Set( aData ); } ECOORD::ECOORD( const wxString& aValue, enum ECOORD::EAGLE_UNIT aUnit ) { // This array is used to adjust the fraction part value basing on the number of digits // in the fraction. constexpr int DIVIDERS[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 }; constexpr unsigned int DIVIDERS_MAX_IDX = sizeof( DIVIDERS ) / sizeof( DIVIDERS[0] ) - 1; int integer, fraction, pre_fraction, post_fraction; // The following check is needed to handle correctly negative fractions where the integer // part == 0. bool negative = ( aValue[0] == '-' ); // %n is used to find out how many digits contains the fraction part, e.g. 0.001 contains 3 // digits. int ret = sscanf( aValue.c_str(), "%d.%n%d%n", &integer, &pre_fraction, &fraction, &post_fraction ); if( ret == 0 ) throw XML_PARSER_ERROR( "Invalid coordinate" ); // process the integer part value = ConvertToNm( integer, aUnit ); // process the fraction part if( ret == 2 ) { int digits = post_fraction - pre_fraction; // adjust the number of digits if necessary as we cannot handle anything smaller than // nanometers (rounding). if( (unsigned) digits > DIVIDERS_MAX_IDX ) { int diff = digits - DIVIDERS_MAX_IDX; digits = DIVIDERS_MAX_IDX; fraction /= DIVIDERS[diff]; } int frac_value = ConvertToNm( fraction, aUnit ) / DIVIDERS[digits]; // keep the sign in mind value = negative ? value - frac_value : value + frac_value; } } long long int ECOORD::ConvertToNm( int aValue, enum EAGLE_UNIT aUnit ) { long long int ret; switch( aUnit ) { default: case EU_NM: ret = aValue; break; case EU_MM: ret = (long long) aValue * 1000000; break; case EU_INCH: ret = (long long) aValue * 25400000; break; case EU_MIL: ret = (long long) aValue * 25400; break; } if( ( ret > 0 ) != ( aValue > 0 ) ) wxLogError( _( "Invalid size %lld: too large" ), aValue ); return ret; } // Template specializations below parse wxString to the used types: // - wxString (preferred) // - string // - double // - int // - bool // - EROT // - ECOORD template <> wxString Convert( const wxString& aValue ) { return aValue; } template <> std::string Convert( const wxString& aValue ) { return std::string( aValue.ToUTF8() ); } template <> double Convert( const wxString& aValue ) { double value; if( aValue.ToCDouble( &value ) ) return value; else throw XML_PARSER_ERROR( "Conversion to double failed. Original value: '" + aValue.ToStdString() + "'." ); } template <> int Convert( const wxString& aValue ) { if( aValue.IsEmpty() ) throw XML_PARSER_ERROR( "Conversion to int failed. Original value is empty." ); return wxAtoi( aValue ); } template <> bool Convert( const wxString& aValue ) { if( aValue != wxT( "yes" ) && aValue != wxT( "no" ) ) throw XML_PARSER_ERROR( "Conversion to bool failed. Original value, '" + aValue.ToStdString() + "', is neither 'yes' nor 'no'." ); return aValue == wxT( "yes" ); } /// parse an Eagle XML "rot" field. Unfortunately the DTD seems not to explain /// this format very well. [S][M]R. Examples: "R90", "MR180", "SR180" template<> EROT Convert( const wxString& aRot ) { EROT value; value.spin = aRot.find( 'S' ) != aRot.npos; value.mirror = aRot.find( 'M' ) != aRot.npos; value.degrees = strtod( aRot.c_str() + 1 // skip leading 'R' + int( value.spin ) // skip optional leading 'S' + int( value.mirror ), // skip optional leading 'M' nullptr ); return value; } template<> ECOORD Convert( const wxString& aCoord ) { // Eagle uses millimeters as the default unit return ECOORD( aCoord, ECOORD::EAGLE_UNIT::EU_MM ); } /** * Parse \a aAttribute of the XML node \a aNode. * * @param aNode is the node whose attribute will be parsed. * @param aAttribute is the attribute that will be parsed. * @throw XML_PARSER_ERROR - exception thrown if the required attribute is missing * @return T - the attributed parsed as the specified type. */ template T parseRequiredAttribute( wxXmlNode* aNode, const wxString& aAttribute ) { wxString value; if( aNode->GetAttribute( aAttribute, &value ) ) return Convert( value ); else throw XML_PARSER_ERROR( "The required attribute " + aAttribute + " is missing." ); } /** * Parse option \a aAttribute of the XML node \a aNode. * * @param aNode is the node whose attribute will be parsed. * @param aAttribute is the attribute that will be parsed. * @return OPTIONAL_XML_ATTRIBUTE - an optional XML attribute, parsed as the specified type if * found. */ template OPTIONAL_XML_ATTRIBUTE parseOptionalAttribute( wxXmlNode* aNode, const wxString& aAttribute ) { return OPTIONAL_XML_ATTRIBUTE( aNode->GetAttribute( aAttribute ) ); } NODE_MAP MapChildren( wxXmlNode* aCurrentNode ) { // Map node_name -> node_pointer NODE_MAP nodesMap; // Loop through all children mapping them in nodesMap if( aCurrentNode ) aCurrentNode = aCurrentNode->GetChildren(); while( aCurrentNode ) { // Create a new pair in the map // key: current node name // value: current node pointer nodesMap[aCurrentNode->GetName()] = aCurrentNode; // Get next child aCurrentNode = aCurrentNode->GetNext(); } return nodesMap; } wxPoint ConvertArcCenter( const wxPoint& aStart, const wxPoint& aEnd, double aAngle ) { // Eagle give us start and end. // S_ARC wants start to give the center, and end to give the start. double dx = aEnd.x - aStart.x, dy = aEnd.y - aStart.y; wxPoint mid = ( aStart + aEnd ) / 2; double dlen = sqrt( dx*dx + dy*dy ); if( !std::isnormal( dlen ) || !std::isnormal( aAngle ) ) { THROW_IO_ERROR( wxString::Format( _( "Invalid Arc with radius %f and angle %f" ), dlen, aAngle ) ); } double dist = dlen / ( 2 * tan( DEG2RAD( aAngle ) / 2 ) ); wxPoint center( mid.x + dist * ( dy / dlen ), mid.y - dist * ( dx / dlen ) ); return center; } static int parseAlignment( const wxString& aAlignment ) { // (bottom-left | bottom-center | bottom-right | center-left | // center | center-right | top-left | top-center | top-right) if( aAlignment == wxT( "center" ) ) return ETEXT::CENTER; else if( aAlignment == wxT( "center-right" ) ) return ETEXT::CENTER_RIGHT; else if( aAlignment == wxT( "top-left" ) ) return ETEXT::TOP_LEFT; else if( aAlignment == wxT( "top-center" ) ) return ETEXT::TOP_CENTER; else if( aAlignment == wxT( "top-right" ) ) return ETEXT::TOP_RIGHT; else if( aAlignment == wxT( "bottom-left" ) ) return ETEXT::BOTTOM_LEFT; else if( aAlignment == wxT( "bottom-center" ) ) return ETEXT::BOTTOM_CENTER; else if( aAlignment == wxT( "bottom-right" ) ) return ETEXT::BOTTOM_RIGHT; else if( aAlignment == wxT( "center-left" ) ) return ETEXT::CENTER_LEFT; return DEFAULT_ALIGNMENT; } EWIRE::EWIRE( wxXmlNode* aWire ) { /* */ x1 = parseRequiredAttribute( aWire, wxT( "x1" ) ); y1 = parseRequiredAttribute( aWire, wxT( "y1" ) ); x2 = parseRequiredAttribute( aWire, wxT( "x2" ) ); y2 = parseRequiredAttribute( aWire, wxT( "y2" ) ); width = parseRequiredAttribute( aWire, wxT( "width" ) ); layer = parseRequiredAttribute( aWire, wxT( "layer" ) ); curve = parseOptionalAttribute( aWire, wxT( "curve" ) ); opt_wxString s = parseOptionalAttribute( aWire, wxT( "style" ) ); if( s == wxT( "continuous" ) ) style = EWIRE::CONTINUOUS; else if( s == wxT( "longdash" ) ) style = EWIRE::LONGDASH; else if( s == wxT( "shortdash" ) ) style = EWIRE::SHORTDASH; else if( s == wxT( "dashdot" ) ) style = EWIRE::DASHDOT; s = parseOptionalAttribute( aWire, wxT( "cap" ) ); if( s == wxT( "round" ) ) cap = EWIRE::ROUND; else if( s == wxT( "flat" ) ) cap = EWIRE::FLAT; } EJUNCTION::EJUNCTION( wxXmlNode* aJunction ) { /* */ x = parseRequiredAttribute( aJunction, wxT( "x" ) ); y = parseRequiredAttribute( aJunction, wxT( "y" ) ); } ELABEL::ELABEL( wxXmlNode* aLabel, const wxString& aNetName ) { /* */ x = parseRequiredAttribute( aLabel, wxT( "x" ) ); y = parseRequiredAttribute( aLabel, wxT( "y" ) ); size = parseRequiredAttribute( aLabel, wxT( "size" ) ); layer = parseRequiredAttribute( aLabel, wxT( "layer" ) ); rot = parseOptionalAttribute( aLabel, wxT( "rot" ) ); xref = parseOptionalAttribute( aLabel, wxT( "xref" ) ); netname = aNetName; } EVIA::EVIA( wxXmlNode* aVia ) { /* */ x = parseRequiredAttribute( aVia, wxT( "x" ) ); y = parseRequiredAttribute( aVia, wxT( "y" ) ); wxString ext = parseRequiredAttribute( aVia, wxT( "extent" ) ); sscanf( ext.c_str(), "%d-%d", &layer_front_most, &layer_back_most ); drill = parseRequiredAttribute( aVia, wxT( "drill" ) ); diam = parseOptionalAttribute( aVia, wxT( "diameter" ) ); shape = parseOptionalAttribute( aVia, wxT( "shape" ) ); } ECIRCLE::ECIRCLE( wxXmlNode* aCircle ) { /* */ x = parseRequiredAttribute( aCircle, wxT( "x" ) ); y = parseRequiredAttribute( aCircle, wxT( "y" ) ); radius = parseRequiredAttribute( aCircle, wxT( "radius" ) ); width = parseRequiredAttribute( aCircle, wxT( "width" ) ); layer = parseRequiredAttribute( aCircle, wxT( "layer" ) ); } ERECT::ERECT( wxXmlNode* aRect ) { /* */ x1 = parseRequiredAttribute( aRect, wxT( "x1" ) ); y1 = parseRequiredAttribute( aRect, wxT( "y1" ) ); x2 = parseRequiredAttribute( aRect, wxT( "x2" ) ); y2 = parseRequiredAttribute( aRect, wxT( "y2" ) ); layer = parseRequiredAttribute( aRect, wxT( "layer" ) ); rot = parseOptionalAttribute( aRect, wxT( "rot" ) ); } EATTR::EATTR( wxXmlNode* aTree ) { /* or context -- constant %Bool; "no" -- only in context -- > */ name = parseRequiredAttribute( aTree, wxT( "name" ) ); value = parseOptionalAttribute( aTree, wxT( "value" ) ); x = parseOptionalAttribute( aTree, wxT( "x" ) ); y = parseOptionalAttribute( aTree, wxT( "y" ) ); size = parseOptionalAttribute( aTree, wxT( "size" ) ); layer = parseOptionalAttribute( aTree, wxT( "layer" ) ); ratio = parseOptionalAttribute( aTree, wxT( "ratio" ) ); rot = parseOptionalAttribute( aTree, wxT( "rot" ) ); opt_wxString stemp = parseOptionalAttribute( aTree, wxT( "display" ) ); // (off | value | name | both) if( stemp == wxT( "off" ) ) display = EATTR::Off; else if( stemp == wxT( "name" ) ) display = EATTR::NAME; else if( stemp == wxT( "both" ) ) display = EATTR::BOTH; else // "value" is the default display = EATTR::VALUE; stemp = parseOptionalAttribute( aTree, wxT( "align" ) ); align = stemp ? parseAlignment( *stemp ) : DEFAULT_ALIGNMENT; } EDIMENSION::EDIMENSION( wxXmlNode* aDimension ) { /* */ x1 = parseRequiredAttribute( aDimension, wxT( "x1" ) ); y1 = parseRequiredAttribute( aDimension, wxT( "y1" ) ); x2 = parseRequiredAttribute( aDimension, wxT( "x2" ) ); y2 = parseRequiredAttribute( aDimension, wxT( "y2" ) ); x3 = parseRequiredAttribute( aDimension, wxT( "x3" ) ); y3 = parseRequiredAttribute( aDimension, wxT( "y3" ) ); textsize = parseOptionalAttribute( aDimension, wxT( "textsize" ) ); layer = parseRequiredAttribute( aDimension, wxT( "layer" ) ); dimensionType = parseOptionalAttribute( aDimension, wxT( "dtype" ) ); } ETEXT::ETEXT( wxXmlNode* aText ) { /* */ text = aText->GetNodeContent(); x = parseRequiredAttribute( aText, wxT( "x" ) ); y = parseRequiredAttribute( aText, wxT( "y" ) ); size = parseRequiredAttribute( aText, wxT( "size" ) ); layer = parseRequiredAttribute( aText, wxT( "layer" ) ); font = parseOptionalAttribute( aText, wxT( "font" ) ); ratio = parseOptionalAttribute( aText, wxT( "ratio" ) ); rot = parseOptionalAttribute( aText, wxT( "rot" ) ); opt_wxString stemp = parseOptionalAttribute( aText, wxT( "align" ) ); align = stemp ? parseAlignment( *stemp ) : DEFAULT_ALIGNMENT; } wxSize ETEXT::ConvertSize() const { wxSize textsize; if( font ) { const wxString& fontName = font.CGet(); if( fontName == wxT( "vector" ) ) { textsize = wxSize( size.ToSchUnits(), size.ToSchUnits() ); } else if( fontName == wxT( "fixed" ) ) { textsize = wxSize( size.ToSchUnits(), size.ToSchUnits() * 0.80 ); } else { textsize = wxSize( size.ToSchUnits(), size.ToSchUnits() ); } } else { textsize = wxSize( size.ToSchUnits() * 0.85, size.ToSchUnits() ); } return textsize; } EFRAME::EFRAME( wxXmlNode* aFrameNode ) { /* * * */ border_left = true; border_top = true; border_right = true; border_bottom = true; x1 = parseRequiredAttribute( aFrameNode, wxT( "x1" ) ); y1 = parseRequiredAttribute( aFrameNode, wxT( "y1" ) ); x2 = parseRequiredAttribute( aFrameNode, wxT( "x2" ) ); y2 = parseRequiredAttribute( aFrameNode, wxT( "y2" ) ); columns = parseRequiredAttribute( aFrameNode, wxT( "columns" ) ); rows = parseRequiredAttribute( aFrameNode, wxT( "rows" ) ); layer = parseRequiredAttribute( aFrameNode, wxT( "layer" ) ); border_left = parseOptionalAttribute( aFrameNode, wxT( "border-left" ) ); border_top = parseOptionalAttribute( aFrameNode, wxT( "border-top" ) ); border_right = parseOptionalAttribute( aFrameNode, wxT( "border-right" ) ); border_bottom = parseOptionalAttribute( aFrameNode, wxT( "border-bottom" ) ); } EPAD_COMMON::EPAD_COMMON( wxXmlNode* aPad ) { // #REQUIRED says DTD, throw exception if not found name = parseRequiredAttribute( aPad, wxT( "name" ) ); x = parseRequiredAttribute( aPad, wxT( "x" ) ); y = parseRequiredAttribute( aPad, wxT( "y" ) ); rot = parseOptionalAttribute( aPad, wxT( "rot" ) ); stop = parseOptionalAttribute( aPad, wxT( "stop" ) ); thermals = parseOptionalAttribute( aPad, wxT( "thermals" ) ); } EPAD::EPAD( wxXmlNode* aPad ) : EPAD_COMMON( aPad ) { /* */ // #REQUIRED says DTD, throw exception if not found drill = parseRequiredAttribute( aPad, wxT( "drill" ) ); // Optional attributes diameter = parseOptionalAttribute( aPad, wxT( "diameter" ) ); opt_wxString s = parseOptionalAttribute( aPad, wxT( "shape" ) ); // (square | round | octagon | long | offset) if( s == wxT( "square" ) ) shape = EPAD::SQUARE; else if( s == wxT( "round" ) ) shape = EPAD::ROUND; else if( s == wxT( "octagon" ) ) shape = EPAD::OCTAGON; else if( s == wxT( "long" ) ) shape = EPAD::LONG; else if( s == wxT( "offset" ) ) shape = EPAD::OFFSET; first = parseOptionalAttribute( aPad, wxT( "first" ) ); } ESMD::ESMD( wxXmlNode* aSMD ) : EPAD_COMMON( aSMD ) { /* */ // DTD #REQUIRED, throw exception if not found dx = parseRequiredAttribute( aSMD, wxT( "dx" ) ); dy = parseRequiredAttribute( aSMD, wxT( "dy" ) ); layer = parseRequiredAttribute( aSMD, wxT( "layer" ) ); roundness = parseOptionalAttribute( aSMD, wxT( "roundness" ) ); cream = parseOptionalAttribute( aSMD, wxT( "cream" ) ); } EPIN::EPIN( wxXmlNode* aPin ) { /* */ // DTD #REQUIRED, throw exception if not found name = parseRequiredAttribute( aPin, wxT( "name" ) ); x = parseRequiredAttribute( aPin, wxT( "x" ) ); y = parseRequiredAttribute( aPin, wxT( "y" ) ); visible = parseOptionalAttribute( aPin, wxT( "visible" ) ); length = parseOptionalAttribute( aPin, wxT( "length" ) ); direction = parseOptionalAttribute( aPin, wxT( "direction" ) ); function = parseOptionalAttribute( aPin, wxT( "function" ) ); swaplevel = parseOptionalAttribute( aPin, wxT( "swaplevel" ) ); rot = parseOptionalAttribute( aPin, wxT( "rot" ) ); } EVERTEX::EVERTEX( wxXmlNode* aVertex ) { /* */ x = parseRequiredAttribute( aVertex, wxT( "x" ) ); y = parseRequiredAttribute( aVertex, wxT( "y" ) ); curve = parseOptionalAttribute( aVertex, wxT( "curve" ) ); } EPOLYGON::EPOLYGON( wxXmlNode* aPolygon ) { /* or context -- orphans %Bool; "no" -- only in context -- thermals %Bool; "yes" -- only in context -- rank %Int; "0" -- 1..6 in context, 0 or 7 in context -- > */ width = parseRequiredAttribute( aPolygon, wxT( "width" ) ); layer = parseRequiredAttribute( aPolygon, wxT( "layer" ) ); spacing = parseOptionalAttribute( aPolygon, wxT( "spacing" ) ); isolate = parseOptionalAttribute( aPolygon, wxT( "isolate" ) ); opt_wxString s = parseOptionalAttribute( aPolygon, wxT( "pour" ) ); // default pour to solid fill pour = EPOLYGON::SOLID; // (solid | hatch | cutout) if( s == wxT( "hatch" ) ) pour = EPOLYGON::HATCH; else if( s == wxT( "cutout" ) ) pour = EPOLYGON::CUTOUT; orphans = parseOptionalAttribute( aPolygon, wxT( "orphans" ) ); thermals = parseOptionalAttribute( aPolygon, wxT( "thermals" ) ); rank = parseOptionalAttribute( aPolygon, wxT( "rank" ) ); } EHOLE::EHOLE( wxXmlNode* aHole ) { /* */ // #REQUIRED: x = parseRequiredAttribute( aHole, wxT( "x" ) ); y = parseRequiredAttribute( aHole, wxT( "y" ) ); drill = parseRequiredAttribute( aHole, wxT( "drill" ) ); } EELEMENT::EELEMENT( wxXmlNode* aElement ) { /* */ // #REQUIRED name = parseRequiredAttribute( aElement, wxT( "name" ) ); library = parseRequiredAttribute( aElement, wxT( "library" ) ); value = parseRequiredAttribute( aElement, wxT( "value" ) ); std::string p = parseRequiredAttribute( aElement, wxT( "package" ) ); ReplaceIllegalFileNameChars( &p, '_' ); package = wxString::FromUTF8( p.c_str() ); x = parseRequiredAttribute( aElement, wxT( "x" ) ); y = parseRequiredAttribute( aElement, wxT( "y" ) ); // optional locked = parseOptionalAttribute( aElement, wxT( "locked" ) ); smashed = parseOptionalAttribute( aElement, wxT( "smashed" ) ); rot = parseOptionalAttribute( aElement, wxT( "rot" ) ); } ELAYER::ELAYER( wxXmlNode* aLayer ) { /* */ number = parseRequiredAttribute( aLayer, wxT( "number" ) ); name = parseRequiredAttribute( aLayer, wxT( "name" ) ); color = parseRequiredAttribute( aLayer, wxT( "color" ) ); fill = 1; // Temporary value. visible = parseOptionalAttribute( aLayer, wxT( "visible" ) ); active = parseOptionalAttribute( aLayer, wxT( "active" ) ); } EPART::EPART( wxXmlNode* aPart ) { /* * * */ // #REQUIRED name = parseRequiredAttribute( aPart, wxT( "name" ) ); library = parseRequiredAttribute( aPart, wxT( "library" ) ); deviceset = parseRequiredAttribute( aPart, wxT( "deviceset" ) ); device = parseRequiredAttribute( aPart, wxT( "device" ) ); technology = parseOptionalAttribute( aPart, wxT( "technology" ) ); value = parseOptionalAttribute( aPart, wxT( "value" ) ); for( wxXmlNode* child = aPart->GetChildren(); child; child = child->GetNext() ) { if( child->GetName() == wxT( "attribute" ) ) { std::string aname, avalue; for( wxXmlAttribute* x = child->GetAttributes(); x; x = x->GetNext() ) { if( x->GetName() == wxT( "name" ) ) aname = x->GetValue(); else if( x->GetName() == wxT( "value" ) ) avalue = x->GetValue(); } if( aname.size() && avalue.size() ) attribute[aname] = avalue; } else if( child->GetName() == wxT( "variant" ) ) { std::string aname, avalue; for( wxXmlAttribute* x = child->GetAttributes(); x; x = x->GetNext() ) { if( x->GetName() == wxT( "name" ) ) aname = x->GetValue(); else if( x->GetName() == wxT( "value" ) ) avalue = x->GetValue(); } if( aname.size() && avalue.size() ) variant[aname] = avalue; } } } EINSTANCE::EINSTANCE( wxXmlNode* aInstance ) { /* * * */ part = parseRequiredAttribute( aInstance, wxT( "part" ) ); gate = parseRequiredAttribute( aInstance, wxT( "gate" ) ); x = parseRequiredAttribute( aInstance, wxT( "x" ) ); y = parseRequiredAttribute( aInstance, wxT( "y" ) ); // optional smashed = parseOptionalAttribute( aInstance, wxT( "smashed" ) ); rot = parseOptionalAttribute( aInstance, wxT( "rot" ) ); } EGATE::EGATE( wxXmlNode* aGate ) { /* * * */ name = parseRequiredAttribute( aGate, wxT( "name" ) ); symbol = parseRequiredAttribute( aGate, wxT( "symbol" ) ); x = parseRequiredAttribute( aGate, wxT( "x" ) ); y = parseRequiredAttribute( aGate, wxT( "y" ) ); opt_wxString stemp = parseOptionalAttribute( aGate, wxT( "addlevel" ) ); // (off | value | name | both) if( stemp == wxT( "must" ) ) addlevel = EGATE::MUST; else if( stemp == wxT( "can" ) ) addlevel = EGATE::CAN; else if( stemp == wxT( "next" ) ) addlevel = EGATE::NEXT; else if( stemp == wxT( "request" ) ) addlevel = EGATE::REQUEST; else if( stemp == wxT( "always" ) ) addlevel = EGATE::ALWAYS; else addlevel = EGATE::NEXT; } ECONNECT::ECONNECT( wxXmlNode* aConnect ) { /* * * */ gate = parseRequiredAttribute( aConnect, wxT( "gate" ) ); pin = parseRequiredAttribute( aConnect, wxT( "pin" ) ); pad = parseRequiredAttribute( aConnect, wxT( "pad" ) ); } EDEVICE::EDEVICE( wxXmlNode* aDevice ) { /* */ name = parseRequiredAttribute( aDevice, wxT( "name" ) ); opt_wxString pack = parseOptionalAttribute( aDevice, wxT( "package" ) ); if( pack ) { std::string p( pack->c_str() ); ReplaceIllegalFileNameChars( &p, '_' ); package.Set( wxString::FromUTF8( p.c_str() ) ); } NODE_MAP aDeviceChildren = MapChildren( aDevice ); wxXmlNode* connectNode = getChildrenNodes( aDeviceChildren, wxT( "connects" ) ); while( connectNode ) { connects.emplace_back( connectNode ); connectNode = connectNode->GetNext(); } } EDEVICE_SET::EDEVICE_SET( wxXmlNode* aDeviceSet ) { /* */ name = parseRequiredAttribute( aDeviceSet, wxT( "name" ) ); prefix = parseOptionalAttribute( aDeviceSet, wxT( "prefix" ) ); uservalue = parseOptionalAttribute( aDeviceSet, wxT( "uservalue" ) ); /* Russell: Parsing of devices and gates moved to sch_eagle_plugin.cpp * //TODO: description NODE_MAP aDeviceSetChildren = MapChildren(aDeviceSet); wxXmlNode* deviceNode = getChildrenNodes(aDeviceSetChildren, wxT( "device" )); while(deviceNode){ devices.push_back(EDEVICE(deviceNode)); deviceNode->GetNext(); } wxXmlNode* gateNode = getChildrenNodes(aDeviceSetChildren, wxT( "gate" )); while(gateNode){ gates.push_back(EGATE(gateNode)); gateNode->GetNext(); } */ } ECLASS::ECLASS( wxXmlNode* aClass ) { number = parseRequiredAttribute( aClass, wxT( "number" ) ); name = parseRequiredAttribute( aClass, wxT( "name" ) ); for( wxXmlNode* child = aClass->GetChildren(); child; child = child->GetNext() ) { if( child->GetName() == wxT( "clearance" ) ) { wxString to = parseRequiredAttribute( child, wxT( "class" ) ); ECOORD value = parseRequiredAttribute( child, wxT( "value" ) ); clearanceMap[to] = value; } } }