/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2012-2016 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 */ #ifndef _EAGLE_PARSER_H_ #define _EAGLE_PARSER_H_ #include #include #include #include #include #include #include #include #include #include using std::string; class MODULE; typedef std::unordered_map< string, wxXmlNode* > NODE_MAP; typedef std::map< string, MODULE* > MODULE_MAP; /** * Class XML_PARSER_ERROR * implements a simple wrapper around runtime_error to isolate the errors thrown by the * Eagle XML parser. */ struct XML_PARSER_ERROR : std::runtime_error { /** * Constructor XML_PARSER_ERROR * build an XML error by just calling its parent class constructor, std::runtime_error, with * the passed message. * @param aMessage is an explanatory error message. */ XML_PARSER_ERROR( const string& aMessage ) noexcept : std::runtime_error( "XML parser failed - " + aMessage ) {} }; /// segment (element) of our XPATH into the Eagle XML document tree in PTREE form. struct TRIPLET { const char* element; const char* attribute; const char* value; TRIPLET( const char* aElement, const char* aAttribute = "", const char* aValue = "" ) : element( aElement ), attribute( aAttribute ), value( aValue ) {} }; /** * Class XPATH * keeps track of what we are working on within a PTREE. * Then if an exception is thrown, the place within the tree that gave us * grief can be reported almost accurately. To minimally impact * speed, merely assign const char* pointers during the tree walking * expedition. The const char* pointers must be to C strings residing either in * the data or code segment (i.e. "compiled in") or within the XML document, but * not on the stack, since the stack is unwound during the throwing of the * exception. The XML document will not immediately vanish since we capture * the xpath (using function Contents()) before the XML document tree (PTREE) * is destroyed. */ class XPATH { std::vector p; public: void push( const char* aPathSegment, const char* aAttribute="" ) { p.push_back( TRIPLET( aPathSegment, aAttribute ) ); } void clear() { p.clear(); } void pop() { p.pop_back(); } /// modify the last path node's value void Value( const char* aValue ) { p.back().value = aValue; } /// modify the last path node's attribute void Attribute( const char* aAttribute ) { p.back().attribute = aAttribute; } /// return the contents of the XPATH as a single string string Contents() { typedef std::vector::const_iterator CITER_TRIPLET; string ret; for( CITER_TRIPLET it = p.begin(); it != p.end(); ++it ) { if( it != p.begin() ) ret += '.'; ret += it->element; if( it->attribute[0] && it->value[0] ) { ret += '['; ret += it->attribute; ret += '='; ret += it->value; ret += ']'; } } return ret; } }; /** * Function Convert * converts a wxString to a generic type T. * @param aValue is a wxString containing the value that will be converted to type T. * @throw XML_PARSER_ERROR - an exception is thrown if the parsing fails or if the conversion to * type T is unknown. */ template T Convert( const wxString& aValue ) { throw XML_PARSER_ERROR( "Conversion failed. Unknown type." ); } /** * Class OPTIONAL_XML_ATTRIBUTE * models an optional XML attribute. * This was implemented as an alternative to boost::optional. This class should be replaced with a * simple typedef per type using std::optional when C++17 is published. */ template class OPTIONAL_XML_ATTRIBUTE { private: /// A boolean indicating if the data is present or not. bool m_isAvailable; /// The actual data if m_isAvailable is true; otherwise, garbage. T m_data; public: /** * Constructor OPTIONAL_XML_ATTRIBUTE * construct a default OPTIONAL_XML_ATTRIBUTE, whose data is not available. */ OPTIONAL_XML_ATTRIBUTE() : m_isAvailable( false ) {} /** * Constructor OPTIONAL_XML_ATTRIBUTE * @param aData is a wxString containing the value that should be converted to type T. If * aData is empty, the attribute is understood as unavailable; otherwise, the * conversion to T is tried. */ OPTIONAL_XML_ATTRIBUTE( const wxString& aData ) { m_isAvailable = !aData.IsEmpty(); if( m_isAvailable ) Set( aData ); } /** * Constructor OPTIONAL_XML_ATTRIBUTE * @param aData is the value of the XML attribute. If this constructor is called, the * attribute is available. */ OPTIONAL_XML_ATTRIBUTE( T aData ) : m_isAvailable( true ), m_data( aData ) {} /** * Operator bool * @return bool - the availability of the attribute. */ operator bool() const { return m_isAvailable; } /** * Assignment operator * to a string (optionally) containing the data. * @param aData is a wxString that should be converted to T. If the string is empty, the * attribute is set to unavailable. */ OPTIONAL_XML_ATTRIBUTE& operator =( const wxString& aData ) { m_isAvailable = !aData.IsEmpty(); if( m_isAvailable ) Set( aData ); return *this; } /** * Assignment operator * to an object of the base type containing the data. * @param aData is the actual value of the attribute. Calling this assignment, the attribute * is automatically made available. */ OPTIONAL_XML_ATTRIBUTE& operator =( T aData ) { m_data = aData; m_isAvailable = true; return *this; } /** * Equal operator * to an object of the base type. * @param aOther is the object of the base type that should be compared with this one. */ bool operator ==( const T& aOther ) const { return m_isAvailable && ( aOther == m_data ); } /** * Function Set * tries to convert a string to the base type. * @param aString is the string that will be converted to the base type. */ void Set( const wxString& aString ) { m_data = Convert( aString ); } /** * Function Get * returns a reference to the value of the attribute assuming it is available. * @return T& - the value of the attribute. */ T& Get() { assert( m_isAvailable ); return m_data; } /** * Function CGet * returns a constant reference to the value of the attribute assuming it is available. * @return const T& - the value of the attribute. */ const T& CGet() const { assert( m_isAvailable ); return m_data; } /** * Operator * * returns a reference to the value of the attribute assuming it is available. * @return T& - the value of the attribute. */ T& operator*() { return Get(); } /** * Operator * * returns a constant reference to the value of the attribute assuming it is available. * @return const T& - the value of the attribute. */ const T& operator*() const { return CGet(); } /** * Operator -> * returns a pointer to the value of the attribute assuming it is available. * @return T* - the value of the attribute. */ T* operator->() { return &Get(); } /** * Operator -> * returns a constant pointer to the value of the attribute assuming it is available. * @return const T* - the value of the attribute. */ const T* operator->() const { return &CGet(); } }; // Pre-declare for typedefs struct EROT; typedef OPTIONAL_XML_ATTRIBUTE opt_string; typedef OPTIONAL_XML_ATTRIBUTE opt_int; typedef OPTIONAL_XML_ATTRIBUTE opt_double; typedef OPTIONAL_XML_ATTRIBUTE opt_bool; typedef OPTIONAL_XML_ATTRIBUTE opt_erot; // All of the 'E'STRUCTS below merely hold Eagle XML information verbatim, in binary. // For maintenance and troubleshooting purposes, it was thought that we'd need to // separate the conversion process into distinct steps. There is no intent to have KiCad // forms of information in these 'E'STRUCTS. They are only binary forms // of the Eagle information in the corresponding Eagle XML nodes. /// Eagle net struct ENET { int netcode; std::string netname; ENET( int aNetCode, const std::string& aNetName ) : netcode( aNetCode ), netname( aNetName ) {} ENET() : netcode( 0 ) {} }; /// Eagle rotation struct EROT { bool mirror; bool spin; double degrees; EROT() : mirror( false ), spin( false ), degrees( 0 ) {} EROT( double aDegrees ) : mirror( false ), spin( false ), degrees( aDegrees ) {} }; /// Eagle wire struct EWIRE { double x1; double y1; double x2; double y2; double width; LAYER_NUM layer; // for style: (continuous | longdash | shortdash | dashdot) enum { CONTINUOUS, LONGDASH, SHORTDASH, DASHDOT, }; opt_int style; opt_double curve; ///< range is -359.9..359.9 // for cap: (flat | round) enum { FLAT, ROUND, }; opt_int cap; EWIRE( wxXmlNode* aWire ); }; /// Eagle via struct EVIA { double x; double y; int layer_front_most; /// < extent int layer_back_most; /// < inclusive double drill; opt_double diam; opt_string shape; EVIA( wxXmlNode* aVia ); }; /// Eagle circle struct ECIRCLE { double x; double y; double radius; double width; LAYER_NUM layer; ECIRCLE( wxXmlNode* aCircle ); }; /// Eagle XML rectangle in binary struct ERECT { double x1; double y1; double x2; double y2; int layer; opt_erot rot; ERECT( wxXmlNode* aRect ); }; /** * Class EATTR * parses an Eagle "attribute" XML element. Note that an attribute element * is different than an XML element attribute. The attribute element is a * full XML node in and of itself, and has attributes of its own. Blame Eagle. */ struct EATTR { string name; opt_string value; opt_double x; opt_double y; opt_double size; opt_int layer; opt_double ratio; opt_erot rot; enum { // for 'display' Off, VALUE, NAME, BOTH, }; opt_int display; EATTR( wxXmlNode* aTree ); EATTR() {} }; /// Eagle dimension element struct EDIMENSION { double x1; double y1; double x2; double y2; double x3; double y3; int layer; opt_string dimensionType; EDIMENSION( wxXmlNode* aDimension ); }; /// Eagle text element struct ETEXT { string text; double x; double y; double size; int layer; opt_string font; opt_double ratio; opt_erot rot; enum { // for align CENTER, CENTER_LEFT, TOP_CENTER, TOP_LEFT, TOP_RIGHT, // opposites are -1 x above, used by code tricks in here CENTER_RIGHT = -CENTER_LEFT, BOTTOM_CENTER = -TOP_CENTER, BOTTOM_LEFT = -TOP_RIGHT, BOTTOM_RIGHT = -TOP_LEFT, }; opt_int align; ETEXT( wxXmlNode* aText ); }; /// Eagle thru hol pad struct EPAD { string name; double x; double y; double drill; opt_double diameter; // for shape: (square | round | octagon | long | offset) enum { SQUARE, ROUND, OCTAGON, LONG, OFFSET, }; opt_int shape; opt_erot rot; opt_bool stop; opt_bool thermals; opt_bool first; EPAD( wxXmlNode* aPad ); }; /// Eagle SMD pad struct ESMD { string name; double x; double y; double dx; double dy; int layer; opt_int roundness; opt_erot rot; opt_bool stop; opt_bool thermals; opt_bool cream; ESMD( wxXmlNode* aSMD ); }; /// Eagle vertex struct EVERTEX { double x; double y; EVERTEX( wxXmlNode* aVertex ); }; /// Eagle polygon, without vertices which are parsed as needed struct EPOLYGON { double width; int layer; opt_double spacing; // KiCad priority is opposite of Eagle rank, that is: // - Eagle Low rank drawn first // - KiCad high priority drawn first // So since Eagle has an upper limit we define this, used for the cases // where no rank is specified. static const int max_priority = 6; enum { // for pour SOLID, HATCH, CUTOUT, }; int pour; opt_double isolate; opt_bool orphans; opt_bool thermals; opt_int rank; EPOLYGON( wxXmlNode* aPolygon ); }; /// Eagle hole element struct EHOLE { double x; double y; double drill; EHOLE( wxXmlNode* aHole ); }; /// Eagle element element struct EELEMENT { string name; string library; string package; string value; double x; double y; opt_bool locked; opt_bool smashed; opt_erot rot; EELEMENT( wxXmlNode* aElement ); }; struct ELAYER { int number; string name; int color; int fill; opt_bool visible; opt_bool active; ELAYER( wxXmlNode* aLayer ); }; struct EAGLE_LAYER { enum { TOP = 1, ROUTE2 = 2, ROUTE3 = 3, ROUTE4 = 4, ROUTE5 = 5, ROUTE6 = 6, ROUTE7 = 7, ROUTE8 = 8, ROUTE9 = 9, ROUTE10 = 10, ROUTE11 = 11, ROUTE12 = 12, ROUTE13 = 13, ROUTE14 = 14, ROUTE15 = 15, BOTTOM = 16, PADS = 17, VIAS = 18, UNROUTED = 19, DIMENSION = 20, TPLACE = 21, BPLACE = 22, TORIGINS = 23, BORIGINS = 24, TNAMES = 25, BNAMES = 26, TVALUES = 27, BVALUES = 28, TSTOP = 29, BSTOP = 30, TCREAM = 31, BCREAM = 32, TFINISH = 33, BFINISH = 34, TGLUE = 35, BGLUE = 36, TTEST = 37, BTEST = 38, TKEEPOUT = 39, BKEEPOUT = 40, TRESTRICT = 41, BRESTRICT = 42, VRESTRICT = 43, DRILLS = 44, HOLES = 45, MILLING = 46, MEASURES = 47, DOCUMENT = 48, REFERENCELC = 49, REFERENCELS = 50, TDOCU = 51, BDOCU = 52, NETS = 91, BUSSES = 92, PINS = 93, SYMBOLS = 94, NAMES = 95, VALUES = 96, INFO = 97, GUIDE = 98, USERLAYER1 = 160, USERLAYER2 = 161 }; }; /** * Function MapChildren * provides an easy access to the children of an XML node via their names. * @param currentNode is a pointer to a wxXmlNode, whose children will be mapped. * @return NODE_MAP - a map linking the name of each children to the children itself (via a * wxXmlNode*) */ NODE_MAP MapChildren( wxXmlNode* currentNode ); /// Assemble a two part key as a simple concatenation of aFirst and aSecond parts, /// using a separator. string makeKey( const string& aFirst, const string& aSecond ); /// Make a unique time stamp unsigned long timeStamp( wxXmlNode* aTree ); /// Convert an Eagle curve end to a KiCad center for S_ARC wxPoint kicad_arc_center( const wxPoint& aStart, const wxPoint& aEnd, double aAngle ); #endif // _EAGLE_PARSER_H_