← Back to team overview

kicad-developers team mailing list archive

Eagle XML parsing moved to common

 

Hi all,

I'm working in the eeschema plugin for importing Eagle schematics  :)

I've decided to reuse the good work done in pcbnew, so this patch moves the
XML parsing logic from there to common.

It also replaces Boost.PropertyTree to wxXml to help a little bit with our
quest against boost.

I've tested some boards and the output of the plugin with the current logic
and with this patch applied is exactly the same, but more tests are more
than welcome.

Hope this is useful.

Best,
Alejandro
From c0d1f91b2b3a3bb0748fc27e08e5e77845e3429e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alejandro=20Garc=C3=ADa=20Montoro?=
 <alejandro.garciamontoro@xxxxxxxxx>
Date: Fri, 7 Apr 2017 13:40:34 +0200
Subject: [PATCH] Moves Eagle XML parser to common, replacing boost with wx.
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="------------2.12.2"

This is a multi-part message in MIME format.
--------------2.12.2
Content-Type: text/plain; charset=UTF-8; format=fixed
Content-Transfer-Encoding: 8bit


All E'SRUCTS' are moved to common except for ERULES (which is
specific to pcbnew and needs its internal units), still in
pcbnew/eagle_plugin.{h,cpp}

In order to get rid of another boost dependency, this also changes
the parsing of the XML from Boost.PropertyTree to wxXml.

To replace boost::optional, an OPTIONAL_XML_ATTRIBUTE class has
been implemented. This could be replaced with std::optional when
C++17 is ready.
---
 common/CMakeLists.txt   |    1 +
 common/eagle_parser.cpp |  649 +++++++++++++++++++++
 include/eagle_parser.h  |  690 +++++++++++++++++++++++
 pcbnew/eagle_plugin.cpp | 1441 +++++++++--------------------------------------
 pcbnew/eagle_plugin.h   |   98 ++--
 5 files changed, 1646 insertions(+), 1233 deletions(-)
 create mode 100644 common/eagle_parser.cpp
 create mode 100644 include/eagle_parser.h


--------------2.12.2
Content-Type: text/x-patch; name="0001-Moves-Eagle-XML-parser-to-common-replacing-boost-wit.patch"
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="0001-Moves-Eagle-XML-parser-to-common-replacing-boost-wit.patch"

diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index e119d4b7e..0c5d1beb4 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -239,6 +239,7 @@ set( COMMON_SRCS
     draw_panel.cpp
     drawtxt.cpp
     dsnlexer.cpp
+    eagle_parser.cpp
     eda_dde.cpp
     eda_doc.cpp
     eda_pattern_match.cpp
diff --git a/common/eagle_parser.cpp b/common/eagle_parser.cpp
new file mode 100644
index 000000000..54f3c4195
--- /dev/null
+++ b/common/eagle_parser.cpp
@@ -0,0 +1,649 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@xxxxxxxxxxx>
+ * Copyright (C) 2012-2016 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 2017 CERN.
+ * @author Alejandro García Montoro <alejandro.garciamontoro@xxxxxxxxx>
+ *
+ * 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 <eagle_parser.h>
+
+#include <wx/xml/xml.h>
+#include <wx/string.h>
+#include <wx/filename.h>
+
+#include <convert_to_biu.h>
+
+using std::string;
+
+// Template specializations below parse wxString to the used types:
+//      - string
+//      - double
+//      - int
+//      - bool
+//      - EROT
+
+
+template<>
+string Convert<string>( wxString aValue )
+{
+    return aValue.ToStdString();
+}
+
+
+template <>
+double Convert<double>( wxString aValue )
+{
+    double value;
+
+    if( aValue.ToDouble( &value ) )
+        return value;
+    else
+        throw XML_PARSER_ERROR( "Conversion to double failed. Original value: '" +
+                                aValue.ToStdString() + "'." );
+}
+
+
+template <>
+int Convert<int>( wxString aValue )
+{
+    if( aValue.IsEmpty() )
+        throw XML_PARSER_ERROR( "Conversion to int failed. Original value is empty." );
+
+    return wxAtoi( aValue );
+}
+
+
+template <>
+bool Convert<bool>( wxString aValue )
+{
+    if( aValue != "yes" && aValue != "no" )
+        throw XML_PARSER_ERROR( "Conversion to bool failed. Original value, '" +
+                                aValue.ToStdString() +
+                                "', is neither 'yes' nor 'no'." );
+
+    return aValue == "yes";
+}
+
+/// parse an Eagle XML "rot" field.  Unfortunately the DTD seems not to explain
+/// this format very well.  [S][M]R<degrees>.   Examples: "R90", "MR180", "SR180"
+template<>
+EROT Convert<EROT>( 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'
+                            NULL );
+
+    return value;
+}
+
+/**
+ * Function parseRequiredAttribute
+ * parsese the aAttribute of the XML node 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<typename T>
+T parseRequiredAttribute( wxXmlNode* aNode, string aAttribute )
+{
+    wxString value;
+
+    if( aNode->GetAttribute( aAttribute, &value ) )
+        return Convert<T>( value );
+    else
+        throw XML_PARSER_ERROR( "The required attribute " + aAttribute + " is missing." );
+}
+
+/**
+ * Function parseOptionalAttribute
+ * parses the aAttribute of the XML node aNode.
+ * @param  aNode      is the node whose attribute will be parsed.
+ * @param  aAttribute is the attribute that will be parsed.
+ * @return OPTIONAL_XML_ATTRIBUTE<T> - an optional XML attribute, parsed as the specified type if
+ *                                   found.
+ */
+template<typename T>
+OPTIONAL_XML_ATTRIBUTE<T> parseOptionalAttribute( wxXmlNode* aNode, string aAttribute )
+{
+    return OPTIONAL_XML_ATTRIBUTE<T>( aNode->GetAttribute( aAttribute ) );
+}
+
+
+EWIRE::EWIRE( wxXmlNode* aWire )
+{
+    /*
+        <!ELEMENT wire EMPTY>
+        <!ATTLIST wire
+            x1            %Coord;        #REQUIRED
+            y1            %Coord;        #REQUIRED
+            x2            %Coord;        #REQUIRED
+            y2            %Coord;        #REQUIRED
+            width         %Dimension;    #REQUIRED
+            layer         %Layer;        #REQUIRED
+            extent        %Extent;       #IMPLIED  -- only applicable for airwires --
+            style         %WireStyle;    "continuous"
+            curve         %WireCurve;    "0"
+            cap           %WireCap;      "round"   -- only applicable if 'curve' is not zero --
+        >
+    */
+
+    x1    = parseRequiredAttribute<double>( aWire, "x1" );
+    y1    = parseRequiredAttribute<double>( aWire, "y1" );
+    x2    = parseRequiredAttribute<double>( aWire, "x2" );
+    y2    = parseRequiredAttribute<double>( aWire, "y2" );
+    width = parseRequiredAttribute<double>( aWire, "width" );
+    layer = parseRequiredAttribute<int>( aWire, "layer" );
+    curve = parseOptionalAttribute<double>( aWire, "curve" );
+
+    opt_string s = parseOptionalAttribute<string>( aWire, "style" );
+
+    if( s == "continuous" )
+        style = EWIRE::CONTINUOUS;
+    else if( s == "longdash" )
+        style = EWIRE::LONGDASH;
+    else if( s == "shortdash" )
+        style = EWIRE::SHORTDASH;
+    else if( s == "dashdot" )
+        style = EWIRE::DASHDOT;
+
+    s = parseOptionalAttribute<string>( aWire, "cap" );
+
+    if( s == "round" )
+        cap = EWIRE::ROUND;
+    else if( s == "flat" )
+        cap = EWIRE::FLAT;
+}
+
+
+EVIA::EVIA( wxXmlNode* aVia )
+{
+    /*
+    <!ELEMENT via EMPTY>
+    <!ATTLIST via
+          x             %Coord;        #REQUIRED
+          y             %Coord;        #REQUIRED
+          extent        %Extent;       #REQUIRED
+          drill         %Dimension;    #REQUIRED
+          diameter      %Dimension;    "0"
+          shape         %ViaShape;     "round"
+          alwaysstop    %Bool;         "no"
+          >
+    */
+
+    x = parseRequiredAttribute<double>( aVia, "x" );
+    y = parseRequiredAttribute<double>( aVia, "y" );
+
+    string ext = parseRequiredAttribute<string>( aVia, "extent" );
+
+    sscanf( ext.c_str(), "%d-%d", &layer_front_most, &layer_back_most );
+
+    drill = parseRequiredAttribute<double>( aVia, "drill" );
+    diam  = parseOptionalAttribute<double>( aVia, "diameter" );
+    shape = parseOptionalAttribute<string>( aVia, "shape" );
+}
+
+
+ECIRCLE::ECIRCLE( wxXmlNode* aCircle )
+{
+    /*
+    <!ELEMENT circle EMPTY>
+    <!ATTLIST circle
+          x             %Coord;        #REQUIRED
+          y             %Coord;        #REQUIRED
+          radius        %Coord;        #REQUIRED
+          width         %Dimension;    #REQUIRED
+          layer         %Layer;        #REQUIRED
+          >
+    */
+
+    x      = parseRequiredAttribute<double>( aCircle, "x" );
+    y      = parseRequiredAttribute<double>( aCircle, "y" );
+    radius = parseRequiredAttribute<double>( aCircle, "radius" );
+    width  = parseRequiredAttribute<double>( aCircle, "width" );
+    layer  = parseRequiredAttribute<int>( aCircle, "layer" );
+}
+
+
+ERECT::ERECT( wxXmlNode* aRect )
+{
+    /*
+    <!ELEMENT rectangle EMPTY>
+    <!ATTLIST rectangle
+          x1            %Coord;        #REQUIRED
+          y1            %Coord;        #REQUIRED
+          x2            %Coord;        #REQUIRED
+          y2            %Coord;        #REQUIRED
+          layer         %Layer;        #REQUIRED
+          rot           %Rotation;     "R0"
+          >
+    */
+
+    x1    = parseRequiredAttribute<double>( aRect, "x1" );
+    y1    = parseRequiredAttribute<double>( aRect, "y1" );
+    x2    = parseRequiredAttribute<double>( aRect, "x2" );
+    y2    = parseRequiredAttribute<double>( aRect, "y2" );
+    layer = parseRequiredAttribute<int>( aRect, "layer" );
+    rot   = parseOptionalAttribute<EROT>( aRect, "rot" );
+}
+
+
+EATTR::EATTR( wxXmlNode* aTree )
+{
+    /*
+    <!ELEMENT attribute EMPTY>
+    <!ATTLIST attribute
+        name          %String;       #REQUIRED
+        value         %String;       #IMPLIED
+        x             %Coord;        #IMPLIED
+        y             %Coord;        #IMPLIED
+        size          %Dimension;    #IMPLIED
+        layer         %Layer;        #IMPLIED
+        font          %TextFont;     #IMPLIED
+        ratio         %Int;          #IMPLIED
+        rot           %Rotation;     "R0"
+        display       %AttributeDisplay; "value" -- only in <element> or <instance> context --
+        constant      %Bool;         "no"     -- only in <device> context --
+        >
+    */
+
+    name  = parseRequiredAttribute<string>( aTree, "name" );
+    value = parseOptionalAttribute<string>( aTree, "value" );
+
+    x     = parseOptionalAttribute<double>( aTree, "x" );
+    y     = parseOptionalAttribute<double>( aTree, "y" );
+    size  = parseOptionalAttribute<double>( aTree, "size" );
+
+    // KiCad cannot currently put a TEXTE_MODULE on a different layer than the MODULE
+    // Eagle can it seems.
+    layer = parseOptionalAttribute<int>( aTree, "layer" );
+    ratio = parseOptionalAttribute<double>( aTree, "ratio" );
+    rot   = parseOptionalAttribute<EROT>( aTree, "rot" );
+
+    opt_string stemp = parseOptionalAttribute<string>( aTree, "display" );
+
+    // (off | value | name | both)
+    if( stemp == "off" )
+        display = EATTR::Off;
+    else if( stemp == "value" )
+        display = EATTR::VALUE;
+    else if( stemp == "name" )
+        display = EATTR::NAME;
+    else if( stemp == "both" )
+        display = EATTR::BOTH;
+}
+
+
+EDIMENSION::EDIMENSION( wxXmlNode* aDimension )
+{
+    /*
+    <!ELEMENT dimension EMPTY>
+    <!ATTLIST dimension
+          x1            %Coord;        #REQUIRED
+          y1            %Coord;        #REQUIRED
+          x2            %Coord;        #REQUIRED
+          y2            %Coord;        #REQUIRED
+          x3            %Coord;        #REQUIRED
+          y3            %Coord;        #REQUIRED
+          layer         %Layer;        #REQUIRED
+          dtype         %DimensionType; "parallel"
+          >
+    */
+
+    x1    = parseRequiredAttribute<double>( aDimension, "x1" );
+    y1    = parseRequiredAttribute<double>( aDimension, "y1" );
+    x2    = parseRequiredAttribute<double>( aDimension, "x2" );
+    y2    = parseRequiredAttribute<double>( aDimension, "y2" );
+    x3    = parseRequiredAttribute<double>( aDimension, "x3" );
+    y3    = parseRequiredAttribute<double>( aDimension, "y3" );
+    layer = parseRequiredAttribute<int>( aDimension, "layer" );
+
+    opt_string dimType = parseOptionalAttribute<string>( aDimension, "dtype" );
+
+    if( !dimType )
+    {
+        // default type is parallel
+    }
+}
+
+
+ETEXT::ETEXT( wxXmlNode* aText )
+{
+    /*
+    <!ELEMENT text (#PCDATA)>
+    <!ATTLIST text
+          x             %Coord;        #REQUIRED
+          y             %Coord;        #REQUIRED
+          size          %Dimension;    #REQUIRED
+          layer         %Layer;        #REQUIRED
+          font          %TextFont;     "proportional"
+          ratio         %Int;          "8"
+          rot           %Rotation;     "R0"
+          align         %Align;        "bottom-left"
+          >
+    */
+
+    text  = aText->GetNodeContent();
+    x     = parseRequiredAttribute<double>( aText, "x" );
+    y     = parseRequiredAttribute<double>( aText, "y" );
+    size  = parseRequiredAttribute<double>( aText, "size" );
+    layer = parseRequiredAttribute<int>( aText, "layer" );
+
+    font  = parseOptionalAttribute<string>( aText, "font" );
+    ratio = parseOptionalAttribute<double>( aText, "ratio" );
+    rot   = parseOptionalAttribute<EROT>( aText, "rot" );
+
+    opt_string stemp = parseOptionalAttribute<string>( aText, "align" );
+
+    // (bottom-left | bottom-center | bottom-right | center-left |
+    //   center | center-right | top-left | top-center | top-right)
+    if( stemp == "center" )
+        align = ETEXT::CENTER;
+    else if( stemp == "center-right" )
+        align = ETEXT::CENTER_RIGHT;
+    else if( stemp == "top-left" )
+        align = ETEXT::TOP_LEFT;
+    else if( stemp == "top-center" )
+        align = ETEXT::TOP_CENTER;
+    else if( stemp == "top-right" )
+        align = ETEXT::TOP_RIGHT;
+    else if( stemp == "bottom-left" )
+        align = ETEXT::BOTTOM_LEFT;
+    else if( stemp == "bottom-center" )
+        align = ETEXT::BOTTOM_CENTER;
+    else if( stemp == "bottom-right" )
+        align = ETEXT::BOTTOM_RIGHT;
+    else if( stemp == "center-left" )
+        align = ETEXT::CENTER_LEFT;
+}
+
+
+EPAD::EPAD( wxXmlNode* aPad )
+{
+    /*
+    <!ELEMENT pad EMPTY>
+    <!ATTLIST pad
+          name          %String;       #REQUIRED
+          x             %Coord;        #REQUIRED
+          y             %Coord;        #REQUIRED
+          drill         %Dimension;    #REQUIRED
+          diameter      %Dimension;    "0"
+          shape         %PadShape;     "round"
+          rot           %Rotation;     "R0"
+          stop          %Bool;         "yes"
+          thermals      %Bool;         "yes"
+          first         %Bool;         "no"
+          >
+    */
+
+    // #REQUIRED says DTD, throw exception if not found
+    name         = parseRequiredAttribute<string>( aPad, "name" );
+    x            = parseRequiredAttribute<double>( aPad, "x" );
+    y            = parseRequiredAttribute<double>( aPad, "y" );
+    drill        = parseRequiredAttribute<double>( aPad, "drill" );
+
+    // Optional attributes
+    diameter     = parseOptionalAttribute<double>( aPad, "diameter" );
+
+    opt_string s = parseOptionalAttribute<string>( aPad, "shape" );
+
+    // (square | round | octagon | long | offset)
+    if( s == "square" )
+        shape = EPAD::SQUARE;
+    else if( s == "round" )
+        shape = EPAD::ROUND;
+    else if( s == "octagon" )
+        shape = EPAD::OCTAGON;
+    else if( s == "long" )
+        shape = EPAD::LONG;
+    else if( s == "offset" )
+        shape = EPAD::OFFSET;
+
+    rot      = parseOptionalAttribute<EROT>( aPad, "rot" );
+    stop     = parseOptionalAttribute<bool>( aPad, "stop" );
+    thermals = parseOptionalAttribute<bool>( aPad, "thermals" );
+    first    = parseOptionalAttribute<bool>( aPad, "first" );
+}
+
+
+ESMD::ESMD( wxXmlNode* aSMD )
+{
+    /*
+    <!ATTLIST smd
+          name          %String;       #REQUIRED
+          x             %Coord;        #REQUIRED
+          y             %Coord;        #REQUIRED
+          dx            %Dimension;    #REQUIRED
+          dy            %Dimension;    #REQUIRED
+          layer         %Layer;        #REQUIRED
+          roundness     %Int;          "0"
+          rot           %Rotation;     "R0"
+          stop          %Bool;         "yes"
+          thermals      %Bool;         "yes"
+          cream         %Bool;         "yes"
+          >
+    */
+
+    // DTD #REQUIRED, throw exception if not found
+    name      = parseRequiredAttribute<string>( aSMD, "name" );
+    x         = parseRequiredAttribute<double>( aSMD, "x" );
+    y         = parseRequiredAttribute<double>( aSMD, "y" );
+    dx        = parseRequiredAttribute<double>( aSMD, "dx" );
+    dy        = parseRequiredAttribute<double>( aSMD, "dy" );
+    layer     = parseRequiredAttribute<int>( aSMD, "layer" );
+
+    roundness = parseOptionalAttribute<int>( aSMD, "roundness" );
+    rot       = parseOptionalAttribute<EROT>( aSMD, "rot" );
+    thermals  = parseOptionalAttribute<bool>( aSMD, "thermals" );
+    stop      = parseOptionalAttribute<bool>( aSMD, "stop" );
+    thermals  = parseOptionalAttribute<bool>( aSMD, "thermals" );
+    cream     = parseOptionalAttribute<bool>( aSMD, "cream" );
+}
+
+
+EVERTEX::EVERTEX( wxXmlNode* aVertex )
+{
+    /*
+    <!ELEMENT vertex EMPTY>
+    <!ATTLIST vertex
+          x             %Coord;        #REQUIRED
+          y             %Coord;        #REQUIRED
+          curve         %WireCurve;    "0" -- the curvature from this vertex to the next one --
+          >
+    */
+
+    x = parseRequiredAttribute<double>( aVertex, "x" );
+    y = parseRequiredAttribute<double>( aVertex, "y" );
+}
+
+
+EPOLYGON::EPOLYGON( wxXmlNode* aPolygon )
+{
+    /*
+    <!ATTLIST polygon
+          width         %Dimension;    #REQUIRED
+          layer         %Layer;        #REQUIRED
+          spacing       %Dimension;    #IMPLIED
+          pour          %PolygonPour;  "solid"
+          isolate       %Dimension;    #IMPLIED -- only in <signal> or <package> context --
+          orphans       %Bool;         "no"  -- only in <signal> context --
+          thermals      %Bool;         "yes" -- only in <signal> context --
+          rank          %Int;          "0"   -- 1..6 in <signal> context, 0 or 7 in <package> context --
+          >
+    */
+
+    width        = parseRequiredAttribute<double>( aPolygon, "width" );
+    layer        = parseRequiredAttribute<int>( aPolygon, "layer" );
+
+    spacing      = parseOptionalAttribute<double>( aPolygon, "spacing" );
+    isolate      = parseOptionalAttribute<double>( aPolygon, "isolate" );
+    opt_string s = parseOptionalAttribute<string>( aPolygon, "pour" );
+
+    // default pour to solid fill
+    pour = EPOLYGON::SOLID;
+
+    // (solid | hatch | cutout)
+    if( s == "hatch" )
+        pour = EPOLYGON::HATCH;
+    else if( s == "cutout" )
+        pour = EPOLYGON::CUTOUT;
+
+    orphans  = parseOptionalAttribute<bool>( aPolygon, "orphans" );
+    thermals = parseOptionalAttribute<bool>( aPolygon, "thermals" );
+    rank     = parseOptionalAttribute<int>( aPolygon, "rank" );
+}
+
+
+EHOLE::EHOLE( wxXmlNode* aHole )
+{
+    /*
+    <!ELEMENT hole EMPTY>
+    <!ATTLIST hole
+          x             %Coord;        #REQUIRED
+          y             %Coord;        #REQUIRED
+          drill         %Dimension;    #REQUIRED
+          >
+    */
+
+    // #REQUIRED:
+    x     = parseRequiredAttribute<double>( aHole, "x" );
+    y     = parseRequiredAttribute<double>( aHole, "y" );
+    drill = parseRequiredAttribute<double>( aHole, "drill" );
+}
+
+
+EELEMENT::EELEMENT( wxXmlNode* aElement )
+{
+    /*
+    <!ELEMENT element (attribute*, variant*)>
+    <!ATTLIST element
+          name          %String;       #REQUIRED
+          library       %String;       #REQUIRED
+          package       %String;       #REQUIRED
+          value         %String;       #REQUIRED
+          x             %Coord;        #REQUIRED
+          y             %Coord;        #REQUIRED
+          locked        %Bool;         "no"
+          smashed       %Bool;         "no"
+          rot           %Rotation;     "R0"
+          >
+    */
+
+    // #REQUIRED
+    name    = parseRequiredAttribute<string>( aElement, "name" );
+    library = parseRequiredAttribute<string>( aElement, "library" );
+    value   = parseRequiredAttribute<string>( aElement, "value" );
+    package = parseRequiredAttribute<string>( aElement, "package" );
+    ReplaceIllegalFileNameChars( &package );
+
+    x       = parseRequiredAttribute<double>( aElement, "x" );
+    y       = parseRequiredAttribute<double>( aElement, "y" );
+
+    // optional
+    locked  = parseOptionalAttribute<bool>( aElement, "locked" );
+    smashed = parseOptionalAttribute<bool>( aElement, "smashed" );
+    rot     = parseOptionalAttribute<EROT>( aElement, "rot" );
+}
+
+
+ELAYER::ELAYER( wxXmlNode* aLayer )
+{
+    /*
+    <!ELEMENT layer EMPTY>
+    <!ATTLIST layer
+          number        %Layer;        #REQUIRED
+          name          %String;       #REQUIRED
+          color         %Int;          #REQUIRED
+          fill          %Int;          #REQUIRED
+          visible       %Bool;         "yes"
+          active        %Bool;         "yes"
+          >
+    */
+
+    number  = parseRequiredAttribute<int>( aLayer, "number" );
+    name    = parseRequiredAttribute<string>( aLayer, "name" );
+    color   = parseRequiredAttribute<int>( aLayer, "color" );
+    fill    = 1;    // Temporary value.
+    visible = parseOptionalAttribute<bool>( aLayer, "visible" );
+    active  = parseOptionalAttribute<bool>( aLayer, "active" );
+}
+
+
+NODE_MAP MapChildren( wxXmlNode* currentNode )
+{
+    // Map node_name -> node_pointer
+    NODE_MAP nodesMap;
+
+    // Loop through all children mapping them in nodesMap
+    currentNode = currentNode->GetChildren();
+    while( currentNode )
+    {
+        // Create a new pair in the map
+        //      key: current node name
+        //      value: current node pointer
+        nodesMap[currentNode->GetName().ToStdString()] = currentNode;
+
+        // Get next child
+        currentNode = currentNode->GetNext();
+    }
+
+    return nodesMap;
+}
+
+
+string makeKey( const string& aFirst, const string& aSecond )
+{
+    string key = aFirst + '\x02' +  aSecond;
+    return key;
+}
+
+
+unsigned long timeStamp( wxXmlNode* aTree )
+{
+    // in this case from a unique tree memory location
+    return (unsigned long)(void*) aTree;
+}
+
+
+wxPoint kicad_arc_center( wxPoint start, wxPoint end, double angle )
+{
+    // Eagle give us start and end.
+    // S_ARC wants start to give the center, and end to give the start.
+    double dx = end.x - start.x, dy = end.y - start.y;
+    wxPoint mid = (start + end) / 2;
+
+    double dlen = sqrt( dx*dx + dy*dy );
+    double dist = dlen / ( 2 * tan( DEG2RAD( angle ) / 2 ) );
+
+    wxPoint center(
+        mid.x + dist * ( dy / dlen ),
+        mid.y - dist * ( dx / dlen )
+    );
+
+    return center;
+}
diff --git a/include/eagle_parser.h b/include/eagle_parser.h
new file mode 100644
index 000000000..2e1fdade5
--- /dev/null
+++ b/include/eagle_parser.h
@@ -0,0 +1,690 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@xxxxxxxxxxx>
+ * Copyright (C) 2012-2016 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 2017 CERN.
+ * @author Alejandro García Montoro <alejandro.garciamontoro@xxxxxxxxx>
+ *
+ * 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 <errno.h>
+#include <unordered_map>
+
+#include <wx/xml/xml.h>
+#include <wx/string.h>
+#include <wx/filename.h>
+
+#include <layers_id_colors_and_visibility.h>
+#include <convert_to_biu.h>
+#include <macros.h>
+#include <trigo.h>
+#include <kicad_string.h>
+
+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<TRIPLET>    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<TRIPLET>::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<typename T>
+T Convert( 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 T>
+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( 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<T>& operator =( 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<T>& 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( wxString aString )
+    {
+        m_data = Convert<T>( 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<string>  opt_string;
+typedef OPTIONAL_XML_ATTRIBUTE<int>     opt_int;
+typedef OPTIONAL_XML_ATTRIBUTE<double>  opt_double;
+typedef OPTIONAL_XML_ATTRIBUTE<bool>    opt_bool;
+typedef OPTIONAL_XML_ATTRIBUTE<EROT>    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 );
+};
+
+/**
+ * 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( wxPoint start, wxPoint end, double angle );
+
+#endif // _EAGLE_PARSER_H_
diff --git a/pcbnew/eagle_plugin.cpp b/pcbnew/eagle_plugin.cpp
index 04d884933..92b2cf0fe 100644
--- a/pcbnew/eagle_plugin.cpp
+++ b/pcbnew/eagle_plugin.cpp
@@ -54,10 +54,7 @@ Load() TODO's
 #include <errno.h>
 
 #include <wx/string.h>
-#include <boost/property_tree/ptree.hpp>
-#include <boost/property_tree/xml_parser.hpp>
-
-#include <eagle_plugin.h>
+#include <wx/xml/xml.h>
 
 #include <common.h>
 #include <macros.h>
@@ -76,948 +73,18 @@ Load() TODO's
 #include <class_pcb_text.h>
 #include <class_dimension.h>
 
-using namespace boost::property_tree;
-using namespace std;
-
-typedef EAGLE_PLUGIN::BIU                   BIU;
-typedef PTREE::const_assoc_iterator         CA_ITER;
-typedef PTREE::const_iterator               CITER;
-typedef std::pair<CA_ITER, CA_ITER>         CA_ITER_RANGE;
-
-typedef MODULE_MAP::iterator                MODULE_ITER;
-typedef MODULE_MAP::const_iterator          MODULE_CITER;
-
-typedef boost::optional<string>             opt_string;
-typedef boost::optional<int>                opt_int;
-typedef boost::optional<double>             opt_double;
-typedef boost::optional<bool>               opt_bool;
-
-
-/// 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<TRIPLET>    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<TRIPLET>::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 parseOptionalBool
- * returns an opt_bool and sets it true or false according to the presence
- * and value of an attribute within the CPTREE element.
- */
-static opt_bool parseOptionalBool( CPTREE& attribs, const char* aName )
-{
-    opt_bool    ret;
-    opt_string  stemp = attribs.get_optional<string>( aName );
-
-    if( stemp )
-        ret = !stemp->compare( "yes" );
-
-    return ret;
-}
-
-
-// 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 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 )
-    {}
-};
-
-typedef boost::optional<EROT>   opt_erot;
-
-/// parse an Eagle XML "rot" field.  Unfortunately the DTD seems not to explain
-/// this format very well.  [S][M]R<degrees>.   Examples: "R90", "MR180", "SR180"
-static EROT erot( const string& aRot )
-{
-    EROT    rot;
-
-    rot.spin    = aRot.find( 'S' ) != aRot.npos;
-    rot.mirror  = aRot.find( 'M' ) != aRot.npos;
-    rot.degrees = strtod( aRot.c_str()
-                        + 1                     // skip leading 'R'
-                        + int( rot.spin )       // skip optional leading 'S'
-                        + int( rot.mirror ),    // skip optional leading 'M'
-                        NULL );
-    return rot;
-}
-
-/// Eagle "rot" fields are optional, handle that by returning opt_erot.
-static opt_erot parseOptionalEROT( CPTREE& attribs )
-{
-    opt_erot    ret;
-    opt_string  stemp = attribs.get_optional<string>( "rot" );
-    if( stemp )
-        ret = erot( *stemp );
-    return ret;
-}
-
-/// 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( CPTREE& aWire );
-};
-
-/**
- * Constructor EWIRE
- * converts a "wire"'s xml attributes ( &ltwire&gt )
- * to binary without additional conversion.
- * This result is an EWIRE with the &ltwire&gt textual data merely converted to binary.
- */
-EWIRE::EWIRE( CPTREE& aWire )
-{
-    CPTREE& attribs = aWire.get_child( "<xmlattr>" );
-
-    /*
-    <!ELEMENT wire EMPTY>
-    <!ATTLIST wire
-          x1            %Coord;        #REQUIRED
-          y1            %Coord;        #REQUIRED
-          x2            %Coord;        #REQUIRED
-          y2            %Coord;        #REQUIRED
-          width         %Dimension;    #REQUIRED
-          layer         %Layer;        #REQUIRED
-          extent        %Extent;       #IMPLIED  -- only applicable for airwires --
-          style         %WireStyle;    "continuous"
-          curve         %WireCurve;    "0"
-          cap           %WireCap;      "round"   -- only applicable if 'curve' is not zero --
-          >
-    */
-
-    x1    = attribs.get<double>( "x1" );
-    y1    = attribs.get<double>( "y1" );
-    x2    = attribs.get<double>( "x2" );
-    y2    = attribs.get<double>( "y2" );
-    width = attribs.get<double>( "width" );
-    layer = attribs.get<int>( "layer" );
-
-    curve = attribs.get_optional<double>( "curve" );
-
-    opt_string s = attribs.get_optional<string>( "style" );
-    if( s )
-    {
-        if( !s->compare( "continuous" ) )
-            style = EWIRE::CONTINUOUS;
-        else if( !s->compare( "longdash" ) )
-            style = EWIRE::LONGDASH;
-        else if( !s->compare( "shortdash" ) )
-            style = EWIRE::SHORTDASH;
-        else if( !s->compare( "dashdot" ) )
-            style = EWIRE::DASHDOT;
-    }
-
-    s = attribs.get_optional<string>( "cap" );
-    if( s )
-    {
-        if( !s->compare( "round" ) )
-            cap = EWIRE::ROUND;
-        else if( !s->compare( "flat" ) )
-            cap = EWIRE::FLAT;
-    }
-    // ignoring extent
-}
-
-
-/// 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( CPTREE& aVia );
-};
-
-EVIA::EVIA( CPTREE& aVia )
-{
-    CPTREE& attribs = aVia.get_child( "<xmlattr>" );
-
-    /*
-    <!ELEMENT via EMPTY>
-    <!ATTLIST via
-          x             %Coord;        #REQUIRED
-          y             %Coord;        #REQUIRED
-          extent        %Extent;       #REQUIRED
-          drill         %Dimension;    #REQUIRED
-          diameter      %Dimension;    "0"
-          shape         %ViaShape;     "round"
-          alwaysstop    %Bool;         "no"
-          >
-    */
-
-    x     = attribs.get<double>( "x" );
-    y     = attribs.get<double>( "y" );
-
-    string ext = attribs.get<string>( "extent" );
-
-    sscanf( ext.c_str(), "%d-%d", &layer_front_most, &layer_back_most );
-
-    drill = attribs.get<double>( "drill" );
-    diam  = attribs.get_optional<double>( "diameter" );
-    shape = attribs.get_optional<string>( "shape" );
-}
-
-
-/// Eagle circle
-struct ECIRCLE
-{
-    double  x;
-    double  y;
-    double  radius;
-    double  width;
-    LAYER_NUM layer;
-
-    ECIRCLE( CPTREE& aCircle );
-};
-
-ECIRCLE::ECIRCLE( CPTREE& aCircle )
-{
-    CPTREE& attribs = aCircle.get_child( "<xmlattr>" );
-
-    /*
-    <!ELEMENT circle EMPTY>
-    <!ATTLIST circle
-          x             %Coord;        #REQUIRED
-          y             %Coord;        #REQUIRED
-          radius        %Coord;        #REQUIRED
-          width         %Dimension;    #REQUIRED
-          layer         %Layer;        #REQUIRED
-          >
-    */
-
-    x      = attribs.get<double>( "x" );
-    y      = attribs.get<double>( "y" );
-    radius = attribs.get<double>( "radius" );
-    width  = attribs.get<double>( "width" );
-    layer  = attribs.get<int>( "layer" );
-}
-
-
-/// Eagle XML rectangle in binary
-struct ERECT
-{
-    double      x1;
-    double      y1;
-    double      x2;
-    double      y2;
-    int         layer;
-    opt_erot    rot;
-
-    ERECT( CPTREE& aRect );
-};
-
-ERECT::ERECT( CPTREE& aRect )
-{
-    CPTREE& attribs = aRect.get_child( "<xmlattr>" );
-
-    /*
-    <!ELEMENT rectangle EMPTY>
-    <!ATTLIST rectangle
-          x1            %Coord;        #REQUIRED
-          y1            %Coord;        #REQUIRED
-          x2            %Coord;        #REQUIRED
-          y2            %Coord;        #REQUIRED
-          layer         %Layer;        #REQUIRED
-          rot           %Rotation;     "R0"
-          >
-    */
-
-    x1    = attribs.get<double>( "x1" );
-    y1    = attribs.get<double>( "y1" );
-    x2    = attribs.get<double>( "x2" );
-    y2    = attribs.get<double>( "y2" );
-    layer = attribs.get<int>( "layer" );
-    rot   = parseOptionalEROT( attribs );
-}
-
-
-/// Eagle "attribute" XML element, no foolin'.
-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( CPTREE& aTree );
-    EATTR() {}
-};
-
-/**
- * Constructor 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.
- */
-EATTR::EATTR( CPTREE& aAttribute )
-{
-    CPTREE& attribs = aAttribute.get_child( "<xmlattr>" );
-
-    /*
-    <!ELEMENT attribute EMPTY>
-    <!ATTLIST attribute
-        name          %String;       #REQUIRED
-        value         %String;       #IMPLIED
-        x             %Coord;        #IMPLIED
-        y             %Coord;        #IMPLIED
-        size          %Dimension;    #IMPLIED
-        layer         %Layer;        #IMPLIED
-        font          %TextFont;     #IMPLIED
-        ratio         %Int;          #IMPLIED
-        rot           %Rotation;     "R0"
-        display       %AttributeDisplay; "value" -- only in <element> or <instance> context --
-        constant      %Bool;         "no"     -- only in <device> context --
-        >
-    */
-
-    name    = attribs.get<string>( "name" );                    // #REQUIRED
-    value   = attribs.get_optional<string>( "value" );
-
-    x       = attribs.get_optional<double>( "x" );
-    y       = attribs.get_optional<double>( "y" );
-    size    = attribs.get_optional<double>( "size" );
-
-    // KiCad cannot currently put a TEXTE_MODULE on a different layer than the MODULE
-    // Eagle can it seems.
-    layer   = attribs.get_optional<int>( "layer" );
-
-    ratio   = attribs.get_optional<double>( "ratio" );
-    rot     = parseOptionalEROT( attribs );
-
-    opt_string stemp = attribs.get_optional<string>( "display" );
-    if( stemp )
-    {
-        // (off | value | name | both)
-        if( !stemp->compare( "off" ) )
-            display = EATTR::Off;
-        else if( !stemp->compare( "value" ) )
-            display = EATTR::VALUE;
-        else if( !stemp->compare( "name" ) )
-            display = EATTR::NAME;
-        else if( !stemp->compare( "both" ) )
-            display = EATTR::BOTH;
-    }
-}
-
-/// Eagle dimension element
-struct EDIMENSION
-{
-    double      x1;
-    double      y1;
-    double      x2;
-    double      y2;
-    double      x3;
-    double      y3;
-    int         layer;
-
-    opt_string dimensionType;
-
-    EDIMENSION( CPTREE& aDimension );
-};
-
-EDIMENSION::EDIMENSION( CPTREE& aDimension )
-{
-    CPTREE& attribs = aDimension.get_child( "<xmlattr>" );
-
-    /*
-    <!ELEMENT dimension EMPTY>
-    <!ATTLIST dimension
-          x1            %Coord;        #REQUIRED
-          y1            %Coord;        #REQUIRED
-          x2            %Coord;        #REQUIRED
-          y2            %Coord;        #REQUIRED
-          x3            %Coord;        #REQUIRED
-          y3            %Coord;        #REQUIRED
-          layer         %Layer;        #REQUIRED
-          dtype         %DimensionType; "parallel"
-          >
-    */
-
-    x1      = attribs.get<double>( "x1" );
-    y1      = attribs.get<double>( "y1" );
-    x2      = attribs.get<double>( "x2" );
-    y2      = attribs.get<double>( "y2" );
-    x3      = attribs.get<double>( "x3" );
-    y3      = attribs.get<double>( "y3" );
-    layer   = attribs.get<int>( "layer" );
-
-    opt_string dimType = attribs.get_optional<string>( "dtype" );
-
-    if(!dimType)
-    {
-        // default type is parallel
-    }
-}
-
-/// 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( CPTREE& aText );
-};
-
-ETEXT::ETEXT( CPTREE& aText )
-{
-    CPTREE& attribs = aText.get_child( "<xmlattr>" );
-
-    /*
-    <!ELEMENT text (#PCDATA)>
-    <!ATTLIST text
-          x             %Coord;        #REQUIRED
-          y             %Coord;        #REQUIRED
-          size          %Dimension;    #REQUIRED
-          layer         %Layer;        #REQUIRED
-          font          %TextFont;     "proportional"
-          ratio         %Int;          "8"
-          rot           %Rotation;     "R0"
-          align         %Align;        "bottom-left"
-          >
-    */
-
-    text   = aText.data();
-    x      = attribs.get<double>( "x" );
-    y      = attribs.get<double>( "y" );
-    size   = attribs.get<double>( "size" );
-    layer  = attribs.get<int>( "layer" );
-
-    font   = attribs.get_optional<string>( "font" );
-    ratio  = attribs.get_optional<double>( "ratio" );
-    rot    = parseOptionalEROT( attribs );
-
-    opt_string stemp = attribs.get_optional<string>( "align" );
-    if( stemp )
-    {
-        // (bottom-left | bottom-center | bottom-right | center-left |
-        //   center | center-right | top-left | top-center | top-right)
-        if( !stemp->compare( "center" ) )
-            align = ETEXT::CENTER;
-        else if( !stemp->compare( "center-right" ) )
-            align = ETEXT::CENTER_RIGHT;
-        else if( !stemp->compare( "top-left" ) )
-            align = ETEXT::TOP_LEFT;
-        else if( !stemp->compare( "top-center" ) )
-            align = ETEXT::TOP_CENTER;
-        else if( !stemp->compare( "top-right" ) )
-            align = ETEXT::TOP_RIGHT;
-        else if( !stemp->compare( "bottom-left" ) )
-            align = ETEXT::BOTTOM_LEFT;
-        else if( !stemp->compare( "bottom-center" ) )
-            align = ETEXT::BOTTOM_CENTER;
-        else if( !stemp->compare( "bottom-right" ) )
-            align = ETEXT::BOTTOM_RIGHT;
-        else if( !stemp->compare( "center-left" ) )
-            align = ETEXT::CENTER_LEFT;
-    }
-}
-
-
-/// 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( CPTREE& aPad );
-};
-
-EPAD::EPAD( CPTREE& aPad )
-{
-    CPTREE& attribs = aPad.get_child( "<xmlattr>" );
-
-    /*
-    <!ELEMENT pad EMPTY>
-    <!ATTLIST pad
-          name          %String;       #REQUIRED
-          x             %Coord;        #REQUIRED
-          y             %Coord;        #REQUIRED
-          drill         %Dimension;    #REQUIRED
-          diameter      %Dimension;    "0"
-          shape         %PadShape;     "round"
-          rot           %Rotation;     "R0"
-          stop          %Bool;         "yes"
-          thermals      %Bool;         "yes"
-          first         %Bool;         "no"
-          >
-    */
-
-    // #REQUIRED says DTD, throw exception if not found
-    name  = attribs.get<string>( "name" );
-    x     = attribs.get<double>( "x" );
-    y     = attribs.get<double>( "y" );
-    drill = attribs.get<double>( "drill" );
-
-    diameter = attribs.get_optional<double>( "diameter" );
-
-    opt_string s = attribs.get_optional<string>( "shape" );
-    if( s )
-    {
-        // (square | round | octagon | long | offset)
-        if( !s->compare( "square" ) )
-            shape = EPAD::SQUARE;
-        else if( !s->compare( "round" ) )
-            shape = EPAD::ROUND;
-        else if( !s->compare( "octagon" ) )
-            shape = EPAD::OCTAGON;
-        else if( !s->compare( "long" ) )
-            shape = EPAD::LONG;
-        else if( !s->compare( "offset" ) )
-            shape = EPAD::OFFSET;
-    }
-
-    rot      = parseOptionalEROT( attribs );
-    stop     = parseOptionalBool( attribs, "stop" );
-    thermals = parseOptionalBool( attribs, "thermals" );
-    first    = parseOptionalBool( attribs, "first" );
-}
-
-
-/// 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( CPTREE& aSMD );
-};
-
-ESMD::ESMD( CPTREE& aSMD )
-{
-    CPTREE& attribs = aSMD.get_child( "<xmlattr>" );
-
-    /*
-    <!ATTLIST smd
-          name          %String;       #REQUIRED
-          x             %Coord;        #REQUIRED
-          y             %Coord;        #REQUIRED
-          dx            %Dimension;    #REQUIRED
-          dy            %Dimension;    #REQUIRED
-          layer         %Layer;        #REQUIRED
-          roundness     %Int;          "0"
-          rot           %Rotation;     "R0"
-          stop          %Bool;         "yes"
-          thermals      %Bool;         "yes"
-          cream         %Bool;         "yes"
-          >
-    */
-
-    // DTD #REQUIRED, throw exception if not found
-    name  = attribs.get<string>( "name" );
-    x     = attribs.get<double>( "x" );
-    y     = attribs.get<double>( "y" );
-    dx    = attribs.get<double>( "dx" );
-    dy    = attribs.get<double>( "dy" );
-    layer = attribs.get<int>( "layer" );
-    rot   = parseOptionalEROT( attribs );
-
-    roundness = attribs.get_optional<int>( "roundness" );
-    thermals  = parseOptionalBool( attribs, "thermals" );
-    stop      = parseOptionalBool( attribs, "stop" );
-    thermals  = parseOptionalBool( attribs, "thermals" );
-    cream     = parseOptionalBool( attribs, "cream" );
-}
-
-
-struct EVERTEX
-{
-    double      x;
-    double      y;
-
-    EVERTEX( CPTREE& aVertex );
-};
-
-EVERTEX::EVERTEX( CPTREE& aVertex )
-{
-    CPTREE& attribs = aVertex.get_child( "<xmlattr>" );
-
-    /*
-    <!ELEMENT vertex EMPTY>
-    <!ATTLIST vertex
-          x             %Coord;        #REQUIRED
-          y             %Coord;        #REQUIRED
-          curve         %WireCurve;    "0" -- the curvature from this vertex to the next one --
-          >
-    */
-
-    x = attribs.get<double>( "x" );
-    y = attribs.get<double>( "y" );
-}
-
-
-/// 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( CPTREE& aPolygon );
-};
-
-EPOLYGON::EPOLYGON( CPTREE& aPolygon )
-{
-    CPTREE& attribs = aPolygon.get_child( "<xmlattr>" );
-
-    /*
-    <!ATTLIST polygon
-          width         %Dimension;    #REQUIRED
-          layer         %Layer;        #REQUIRED
-          spacing       %Dimension;    #IMPLIED
-          pour          %PolygonPour;  "solid"
-          isolate       %Dimension;    #IMPLIED -- only in <signal> or <package> context --
-          orphans       %Bool;         "no"  -- only in <signal> context --
-          thermals      %Bool;         "yes" -- only in <signal> context --
-          rank          %Int;          "0"   -- 1..6 in <signal> context, 0 or 7 in <package> context --
-          >
-    */
-
-    width   = attribs.get<double>( "width" );
-    layer   = attribs.get<int>( "layer" );
-    spacing = attribs.get_optional<double>( "spacing" );
-    isolate = attribs.get_optional<double>( "isolate" );
-    // default pour to solid fill
-    pour    = EPOLYGON::SOLID;
-    opt_string s = attribs.get_optional<string>( "pour" );
-
-    if( s )
-    {
-        // (solid | hatch | cutout)
-        if( !s->compare( "hatch" ) )
-            pour = EPOLYGON::HATCH;
-        else if( !s->compare( "cutout" ) )
-            pour = EPOLYGON::CUTOUT;
-    }
-
-    orphans  = parseOptionalBool( attribs, "orphans" );
-    thermals = parseOptionalBool( attribs, "thermals" );
-    rank     = attribs.get_optional<int>( "rank" );
-}
-
-/// Eagle hole element
-struct EHOLE
-{
-    double      x;
-    double      y;
-    double      drill;
-
-    EHOLE( CPTREE& aHole );
-};
-
-EHOLE::EHOLE( CPTREE& aHole )
-{
-    CPTREE& attribs = aHole.get_child( "<xmlattr>" );
-
-    /*
-    <!ELEMENT hole EMPTY>
-    <!ATTLIST hole
-          x             %Coord;        #REQUIRED
-          y             %Coord;        #REQUIRED
-          drill         %Dimension;    #REQUIRED
-          >
-    */
-
-    // #REQUIRED:
-    x     = attribs.get<double>( "x" );
-    y     = attribs.get<double>( "y" );
-    drill = attribs.get<double>( "drill" );
-}
-
-
-/// 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( CPTREE& aElement );
-};
-
-EELEMENT::EELEMENT( CPTREE& aElement )
-{
-    CPTREE& attribs = aElement.get_child( "<xmlattr>" );
-
-    /*
-    <!ELEMENT element (attribute*, variant*)>
-    <!ATTLIST element
-          name          %String;       #REQUIRED
-          library       %String;       #REQUIRED
-          package       %String;       #REQUIRED
-          value         %String;       #REQUIRED
-          x             %Coord;        #REQUIRED
-          y             %Coord;        #REQUIRED
-          locked        %Bool;         "no"
-          smashed       %Bool;         "no"
-          rot           %Rotation;     "R0"
-          >
-    */
-
-    // #REQUIRED
-    name    = attribs.get<string>( "name" );
-    library = attribs.get<string>( "library" );
-    value   = attribs.get<string>( "value" );
-
-    package = attribs.get<string>( "package" );
-    ReplaceIllegalFileNameChars( &package );
-
-    x = attribs.get<double>( "x" );
-    y = attribs.get<double>( "y" );
-
-    // optional
-    locked  = parseOptionalBool( attribs, "locked" );
-    smashed = parseOptionalBool( attribs, "smashed" );
-    rot = parseOptionalEROT( attribs );
-}
-
+#include <eagle_plugin.h>
 
-struct ELAYER
-{
-    int         number;
-    string      name;
-    int         color;
-    int         fill;
-    opt_bool    visible;
-    opt_bool    active;
+using namespace std;
 
-    ELAYER( CPTREE& aLayer );
-};
 
-ELAYER::ELAYER( CPTREE& aLayer )
-{
-    CPTREE& attribs = aLayer.get_child( "<xmlattr>" );
-
-    /*
-    <!ELEMENT layer EMPTY>
-    <!ATTLIST layer
-          number        %Layer;        #REQUIRED
-          name          %String;       #REQUIRED
-          color         %Int;          #REQUIRED
-          fill          %Int;          #REQUIRED
-          visible       %Bool;         "yes"
-          active        %Bool;         "yes"
-          >
-    */
-
-    number = attribs.get<int>( "number" );
-    name   = attribs.get<string>( "name" );
-    color  = attribs.get<int>( "color" );
-    fill   = 1;    // Temporary value.
-    visible = parseOptionalBool( attribs, "visible" );
-    active  = parseOptionalBool( attribs, "active" );
-}
+typedef MODULE_MAP::iterator          MODULE_ITER;
+typedef MODULE_MAP::const_iterator    MODULE_CITER;
 
 
 /// Parse an eagle distance which is either mm, or mils if there is "mil" suffix.
 /// Return is in BIU.
-static double parseEagle( const string& aDistance )
+static double parseEagle( const wxString& aDistance )
 {
     double ret = strtod( aDistance.c_str(), NULL );
     if( aDistance.npos != aDistance.find( "mil" ) )
@@ -1029,113 +96,42 @@ static double parseEagle( const string& aDistance )
 }
 
 
-/// subset of eagle.drawing.board.designrules in the XML document
-struct ERULES
+void ERULES::parse( wxXmlNode* aRules )
 {
-    int         psElongationLong;   ///< percent over 100%.  0-> not elongated, 100->twice as wide as is tall
-                                    ///< Goes into making a scaling factor for "long" pads.
-
-    int         psElongationOffset; ///< the offset of the hole within the "long" pad.
-
-    double      rvPadTop;           ///< top pad size as percent of drill size
-    // double   rvPadBottom;        ///< bottom pad size as percent of drill size
-
-    double      rlMinPadTop;        ///< minimum copper annulus on through hole pads
-    double      rlMaxPadTop;        ///< maximum copper annulus on through hole pads
-
-    double      rvViaOuter;         ///< copper annulus is this percent of via hole
-    double      rlMinViaOuter;      ///< minimum copper annulus on via
-    double      rlMaxViaOuter;      ///< maximum copper annulus on via
-    double      mdWireWire;         ///< wire to wire spacing I presume.
+    wxXmlNode* child = aRules->GetChildren();
 
-
-    ERULES() :
-        psElongationLong    ( 100 ),
-        psElongationOffset  ( 0 ),
-        rvPadTop            ( 0.25 ),
-        // rvPadBottom      ( 0.25 ),
-        rlMinPadTop         ( Mils2iu( 10 ) ),
-        rlMaxPadTop         ( Mils2iu( 20 ) ),
-
-        rvViaOuter          ( 0.25 ),
-        rlMinViaOuter       ( Mils2iu( 10 ) ),
-        rlMaxViaOuter       ( Mils2iu( 20 ) ),
-        mdWireWire          ( 0 )
-    {}
-
-    void parse( CPTREE& aRules );
-};
-
-void ERULES::parse( CPTREE& aRules )
-{
-    for( CITER it = aRules.begin();  it != aRules.end();  ++it )
+    while( child )
     {
-        if( it->first != "param" )
-            continue;
+        if( child->GetName() == "param" )
+        {
+            const wxString& name = child->GetAttribute( "name" );
+            const wxString& value = child->GetAttribute( "value" );
+
+            if( name == "psElongationLong" )
+                psElongationLong = wxAtoi( value );
+            else if( name == "psElongationOffset" )
+                psElongationOffset = wxAtoi( value );
+            else if( name == "rvPadTop" )
+                value.ToDouble( &rvPadTop );
+            else if( name == "rlMinPadTop" )
+                rlMinPadTop = parseEagle( value );
+            else if( name == "rlMaxPadTop" )
+                rlMaxPadTop = parseEagle( value );
+            else if( name == "rvViaOuter" )
+                value.ToDouble( &rvViaOuter );
+            else if( name == "rlMinViaOuter" )
+                rlMinViaOuter = parseEagle( value );
+            else if( name == "rlMaxViaOuter" )
+                rlMaxViaOuter = parseEagle( value );
+            else if( name == "mdWireWire" )
+                mdWireWire = parseEagle( value );
+        }
 
-        CPTREE& attribs = it->second.get_child( "<xmlattr>" );
-
-        const string& name = attribs.get<string>( "name" );
-
-        if( name == "psElongationLong" )
-            psElongationLong = attribs.get<int>( "value" );
-        else if( name == "psElongationOffset" )
-            psElongationOffset = attribs.get<int>( "value" );
-        else if( name == "rvPadTop" )
-            rvPadTop = attribs.get<double>( "value" );
-        else if( name == "rlMinPadTop" )
-            rlMinPadTop = parseEagle( attribs.get<string>( "value" ) );
-        else if( name == "rlMaxPadTop" )
-            rlMaxPadTop = parseEagle( attribs.get<string>( "value" ) );
-        else if( name == "rvViaOuter" )
-            rvViaOuter = attribs.get<double>( "value" );
-        else if( name == "rlMinViaOuter" )
-            rlMinViaOuter = parseEagle( attribs.get<string>( "value" ) );
-        else if( name == "rlMaxViaOuter" )
-            rlMaxViaOuter = parseEagle( attribs.get<string>( "value" ) );
-        else if( name == "mdWireWire" )
-            mdWireWire = parseEagle( attribs.get<string>( "value" ) );
+        child = child->GetNext();
     }
 }
 
 
-/// Assemble a two part key as a simple concatonation of aFirst and aSecond parts,
-/// using a separator.
-static inline string makeKey( const string& aFirst, const string& aSecond )
-{
-    string key = aFirst + '\x02' +  aSecond;
-    return key;
-}
-
-
-/// Make a unique time stamp
-static inline unsigned long timeStamp( CPTREE& aTree )
-{
-    // in this case from a unique tree memory location
-    return (unsigned long)(void*) &aTree;
-}
-
-
-/// Convert an Eagle curve end to a KiCad center for S_ARC
-wxPoint kicad_arc_center( wxPoint start, wxPoint end, double angle )
-{
-    // Eagle give us start and end.
-    // S_ARC wants start to give the center, and end to give the start.
-    double dx = end.x - start.x, dy = end.y - start.y;
-    wxPoint mid = (start + end) / 2;
-
-    double dlen = sqrt( dx*dx + dy*dy );
-    double dist = dlen / ( 2 * tan( DEG2RAD( angle ) / 2 ) );
-
-    wxPoint center(
-        mid.x + dist * ( dy / dlen ),
-        mid.y - dist * ( dx / dlen )
-    );
-
-    return center;
-}
-
-
 EAGLE_PLUGIN::EAGLE_PLUGIN() :
     m_rules( new ERULES() ),
     m_xpath( new XPATH() ),
@@ -1182,8 +178,8 @@ wxSize inline EAGLE_PLUGIN::kicad_fontz( double d ) const
 
 BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe,  const PROPERTIES* aProperties )
 {
-    LOCALE_IO   toggle;     // toggles on, then off, the C locale.
-    PTREE       doc;
+    LOCALE_IO       toggle;     // toggles on, then off, the C locale.
+    wxXmlNode*      doc;
 
     init( aProperties );
 
@@ -1198,12 +194,15 @@ BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe,  const
 
     try
     {
-        // 8 bit "filename" should be encoded according to disk filename encoding,
-        // (maybe this is current locale, maybe not, its a filesystem issue),
-        // and is not necessarily utf8.
-        string filename = (const char*) aFileName.char_str( wxConvFile );
+        // Load the document
+        wxXmlDocument xmlDocument;
+        wxFileName fn = aFileName;
 
-        read_xml( filename, doc, xml_parser::no_comments );
+        if( !xmlDocument.Load( fn.GetFullPath() ) )
+            THROW_IO_ERROR( wxString::Format( _( "Unable to read file '%s'" ),
+                                              fn.GetFullPath() ) );
+
+        doc = xmlDocument.GetRoot();
 
         m_min_trace    = INT_MAX;
         m_min_via      = INT_MAX;
@@ -1234,21 +233,12 @@ BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe,  const
         // should be empty, else missing m_xpath->pop()
         wxASSERT( m_xpath->Contents().size() == 0 );
     }
-
-    catch( file_parser_error fpe )
-    {
-        // for xml_parser_error, what() has the line number in it,
-        // but no byte offset.  That should be an adequate error message.
-        THROW_IO_ERROR( fpe.what() );
-    }
-
-    // Class ptree_error is a base class for xml_parser_error & file_parser_error,
-    // so one catch should be OK for all errors.
-    catch( ptree_error pte )
+    // Catch all exceptions thrown from the parser.
+    catch( const XML_PARSER_ERROR &exc )
     {
-        string errmsg = pte.what();
+        string errmsg = exc.what();
 
-        errmsg += " @\n";
+        errmsg += "\n@ ";
         errmsg += m_xpath->Contents();
 
         THROW_IO_ERROR( errmsg );
@@ -1305,17 +295,20 @@ void EAGLE_PLUGIN::clear_cu_map()
 }
 
 
-void EAGLE_PLUGIN::loadAllSections( CPTREE& aDoc )
+void EAGLE_PLUGIN::loadAllSections( wxXmlNode* aDoc )
 {
-    CPTREE& drawing = aDoc.get_child( "eagle.drawing" );
-    CPTREE& board   = drawing.get_child( "board" );
+    wxXmlNode* drawing       = MapChildren( aDoc )["drawing"];
+    NODE_MAP drawingChildren = MapChildren( drawing );
+
+    wxXmlNode* board         = drawingChildren["board"];
+    NODE_MAP boardChildren   = MapChildren( board );
 
     m_xpath->push( "eagle.drawing" );
 
     {
         m_xpath->push( "board" );
 
-        CPTREE& designrules = board.get_child( "designrules" );
+        wxXmlNode* designrules = boardChildren["designrules"];
         loadDesignRules( designrules );
 
         m_xpath->pop();
@@ -1324,7 +317,7 @@ void EAGLE_PLUGIN::loadAllSections( CPTREE& aDoc )
     {
         m_xpath->push( "layers" );
 
-        CPTREE& layers = drawing.get_child( "layers" );
+        wxXmlNode* layers = drawingChildren["layers"];
         loadLayerDefs( layers );
 
         m_xpath->pop();
@@ -1333,16 +326,16 @@ void EAGLE_PLUGIN::loadAllSections( CPTREE& aDoc )
     {
         m_xpath->push( "board" );
 
-        CPTREE& plain = board.get_child( "plain" );
+        wxXmlNode* plain = boardChildren["plain"];
         loadPlain( plain );
 
-        CPTREE&  signals = board.get_child( "signals" );
+        wxXmlNode*  signals = boardChildren["signals"];
         loadSignals( signals );
 
-        CPTREE&  libs = board.get_child( "libraries" );
+        wxXmlNode*  libs = boardChildren["libraries"];
         loadLibraries( libs );
 
-        CPTREE& elems = board.get_child( "elements" );
+        wxXmlNode* elems = boardChildren["elements"];
         loadElements( elems );
 
         m_xpath->pop();     // "board"
@@ -1352,7 +345,7 @@ void EAGLE_PLUGIN::loadAllSections( CPTREE& aDoc )
 }
 
 
-void EAGLE_PLUGIN::loadDesignRules( CPTREE& aDesignRules )
+void EAGLE_PLUGIN::loadDesignRules( wxXmlNode* aDesignRules )
 {
     m_xpath->push( "designrules" );
     m_rules->parse( aDesignRules );
@@ -1360,22 +353,27 @@ void EAGLE_PLUGIN::loadDesignRules( CPTREE& aDesignRules )
 }
 
 
-void EAGLE_PLUGIN::loadLayerDefs( CPTREE& aLayers )
+void EAGLE_PLUGIN::loadLayerDefs( wxXmlNode* aLayers )
 {
     typedef std::vector<ELAYER>     ELAYERS;
     typedef ELAYERS::const_iterator EITER;
 
     ELAYERS     cu;  // copper layers
 
+    // Get the first layer and iterate
+    wxXmlNode* layerNode = aLayers->GetChildren();
+
     // find the subset of layers that are copper, and active
-    for( CITER layer = aLayers.begin();  layer != aLayers.end();  ++layer )
+    while( layerNode )
     {
-        ELAYER  elayer( layer->second );
+        ELAYER  elayer( layerNode );
 
         if( elayer.number >= 1 && elayer.number <= 16 && ( !elayer.active || *elayer.active ) )
         {
             cu.push_back( elayer );
         }
+
+        layerNode = layerNode->GetNext();
     }
 
     // establish cu layer map:
@@ -1426,18 +424,23 @@ void EAGLE_PLUGIN::loadLayerDefs( CPTREE& aLayers )
 }
 
 
-void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics )
+void EAGLE_PLUGIN::loadPlain( wxXmlNode* aGraphics )
 {
     m_xpath->push( "plain" );
 
+    // Get the first graphic and iterate
+    wxXmlNode* gr = aGraphics->GetChildren();
+
     // (polygon | wire | text | circle | rectangle | frame | hole)*
-    for( CITER gr = aGraphics.begin();  gr != aGraphics.end();  ++gr )
+    while( gr )
     {
-        if( gr->first == "wire" )
+        wxString grName = gr->GetName();
+
+        if( grName == "wire" )
         {
             m_xpath->push( "wire" );
 
-            EWIRE        w( gr->second );
+            EWIRE        w( gr );
             PCB_LAYER_ID layer = kicad_layer( w.layer );
 
             wxPoint start( kicad_x( w.x1 ), kicad_y( w.y1 ) );
@@ -1463,17 +466,17 @@ void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics )
                     dseg->SetAngle( *w.curve * -10.0 ); // KiCad rotates the other way
                 }
 
-                dseg->SetTimeStamp( timeStamp( gr->second ) );
+                dseg->SetTimeStamp( timeStamp( gr ) );
                 dseg->SetLayer( layer );
                 dseg->SetWidth( Millimeter2iu( DEFAULT_PCB_EDGE_THICKNESS ) );
             }
             m_xpath->pop();
         }
-        else if( gr->first == "text" )
+        else if( grName == "text" )
         {
             m_xpath->push( "text" );
 
-            ETEXT        t( gr->second );
+            ETEXT        t( gr );
             PCB_LAYER_ID layer = kicad_layer( t.layer );
 
             if( layer != UNDEFINED_LAYER )
@@ -1482,7 +485,7 @@ void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics )
                 m_board->Add( pcbtxt, ADD_APPEND );
 
                 pcbtxt->SetLayer( layer );
-                pcbtxt->SetTimeStamp( timeStamp( gr->second ) );
+                pcbtxt->SetTimeStamp( timeStamp( gr ) );
                 pcbtxt->SetText( FROM_UTF8( t.text.c_str() ) );
                 pcbtxt->SetTextPos( wxPoint( kicad_x( t.x ), kicad_y( t.y ) ) );
 
@@ -1557,11 +560,11 @@ void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics )
             }
             m_xpath->pop();
         }
-        else if( gr->first == "circle" )
+        else if( grName == "circle" )
         {
             m_xpath->push( "circle" );
 
-            ECIRCLE      c( gr->second );
+            ECIRCLE      c( gr );
             PCB_LAYER_ID layer = kicad_layer( c.layer );
 
             if( layer != UNDEFINED_LAYER )       // unsupported layer
@@ -1570,7 +573,7 @@ void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics )
                 m_board->Add( dseg, ADD_APPEND );
 
                 dseg->SetShape( S_CIRCLE );
-                dseg->SetTimeStamp( timeStamp( gr->second ) );
+                dseg->SetTimeStamp( timeStamp( gr ) );
                 dseg->SetLayer( layer );
                 dseg->SetStart( wxPoint( kicad_x( c.x ), kicad_y( c.y ) ) );
                 dseg->SetEnd( wxPoint( kicad_x( c.x + c.radius ), kicad_y( c.y ) ) );
@@ -1578,13 +581,13 @@ void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics )
             }
             m_xpath->pop();
         }
-        else if( gr->first == "rectangle" )
+        else if( grName == "rectangle" )
         {
             // This seems to be a simplified rectangular [copper] zone, cannot find any
             // net related info on it from the DTD.
             m_xpath->push( "rectangle" );
 
-            ERECT        r( gr->second );
+            ERECT        r( gr );
             PCB_LAYER_ID layer = kicad_layer( r.layer );
 
             if( IsCopperLayer( layer ) )
@@ -1593,7 +596,7 @@ void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics )
                 ZONE_CONTAINER* zone = new ZONE_CONTAINER( m_board );
                 m_board->Add( zone, ADD_APPEND );
 
-                zone->SetTimeStamp( timeStamp( gr->second ) );
+                zone->SetTimeStamp( timeStamp( gr ) );
                 zone->SetLayer( layer );
                 zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
 
@@ -1610,10 +613,10 @@ void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics )
 
             m_xpath->pop();
         }
-        else if( gr->first == "hole" )
+        else if( grName == "hole" )
         {
             m_xpath->push( "hole" );
-            EHOLE   e( gr->second );
+            EHOLE   e( gr );
 
             // Fabricate a MODULE with a single PAD_ATTRIB_HOLE_NOT_PLATED pad.
             // Use m_hole_count to gen up a unique name.
@@ -1652,18 +655,18 @@ void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics )
             pad->SetLayerSet( LSET::AllCuMask() );
             m_xpath->pop();
         }
-        else if( gr->first == "frame" )
+        else if( grName == "frame" )
         {
             // picture this
         }
-        else if( gr->first == "polygon" )
+        else if( grName == "polygon" )
         {
             // could be on a copper layer, could be on another layer.
             // copper layer would be done using netCode=0 type of ZONE_CONTAINER.
         }
-        else if( gr->first == "dimension" )
+        else if( grName == "dimension" )
         {
-            EDIMENSION d( gr->second );
+            EDIMENSION d( gr );
 
             DIMENSION* dimension = new DIMENSION( m_board );
             m_board->Add( dimension, ADD_APPEND );
@@ -1694,29 +697,36 @@ void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics )
 
             dimension->AdjustDimensionDetails();
          }
+
+        // Get next graphic
+        gr = gr->GetNext();
     }
     m_xpath->pop();
 }
 
 
-void EAGLE_PLUGIN::loadLibrary( CPTREE& aLib, const string* aLibName )
+void EAGLE_PLUGIN::loadLibrary( wxXmlNode* aLib, const string* aLibName )
 {
     m_xpath->push( "packages" );
 
     // library will have <xmlattr> node, skip that and get the single packages node
-    CPTREE& packages = aLib.get_child( "packages" );
+    wxXmlNode* packages = MapChildren( aLib )["packages"];
+
 
     // Create a MODULE for all the eagle packages, for use later via a copy constructor
     // to instantiate needed MODULES in our BOARD.  Save the MODULE templates in
     // a MODULE_MAP using a single lookup key consisting of libname+pkgname.
 
-    for( CITER package = packages.begin();  package != packages.end();  ++package )
+    // Get the first package and iterate
+    wxXmlNode* package = packages->GetChildren();
+
+    while( package )
     {
         m_xpath->push( "package", "name" );
 
-        const string& pack_ref = package->second.get<string>( "<xmlattr>.name" );
+        const wxString& pack_ref = package->GetAttribute( "name" );
 
-        string pack_name( pack_ref );
+        string pack_name( pack_ref.ToStdString() );
 
         ReplaceIllegalFileNameChars( &pack_name );
 
@@ -1724,10 +734,10 @@ void EAGLE_PLUGIN::loadLibrary( CPTREE& aLib, const string* aLibName )
 
         string key = aLibName ? makeKey( *aLibName, pack_name ) : pack_name;
 
-        MODULE* m = makeModule( package->second, pack_name );
+        MODULE* m = makeModule( package, pack_name );
 
         // add the templating MODULE to the MODULE template factory "m_templates"
-        std::pair<MODULE_ITER, bool> r = m_templates.insert( key, m );
+        std::pair<MODULE_ITER, bool> r = m_templates.insert( {key, m} );
 
         if( !r.second
             // && !( m_props && m_props->Value( "ignore_duplicates" ) )
@@ -1745,30 +755,37 @@ void EAGLE_PLUGIN::loadLibrary( CPTREE& aLib, const string* aLibName )
         }
 
         m_xpath->pop();
+
+        package = package->GetNext();
     }
 
     m_xpath->pop();     // "packages"
 }
 
 
-void EAGLE_PLUGIN::loadLibraries( CPTREE& aLibs )
+void EAGLE_PLUGIN::loadLibraries( wxXmlNode* aLibs )
 {
     m_xpath->push( "libraries.library", "name" );
 
-    for( CITER library = aLibs.begin();  library != aLibs.end();  ++library )
+    // Get the first library and iterate
+    wxXmlNode* library = aLibs->GetChildren();
+
+    while( library )
     {
-        const string& lib_name = library->second.get<string>( "<xmlattr>.name" );
+        const string& lib_name = library->GetAttribute( "name" ).ToStdString();
 
         m_xpath->Value( lib_name.c_str() );
 
-        loadLibrary( library->second, &lib_name );
+        loadLibrary( library, &lib_name );
+
+        library = library->GetNext();
     }
 
     m_xpath->pop();
 }
 
 
-void EAGLE_PLUGIN::loadElements( CPTREE& aElements )
+void EAGLE_PLUGIN::loadElements( wxXmlNode* aElements )
 {
     m_xpath->push( "elements.element", "name" );
 
@@ -1777,14 +794,15 @@ void EAGLE_PLUGIN::loadElements( CPTREE& aElements )
     bool refanceNamePresetInPackageLayout;
     bool valueNamePresetInPackageLayout;
 
+    // Get the first element and iterate
+    wxXmlNode* element = aElements->GetChildren();
 
-
-    for( CITER it = aElements.begin();  it != aElements.end();  ++it )
+    while( element )
     {
-        if( it->first != "element" )
+        if( element->GetName() != "element" )
             continue;
 
-        EELEMENT    e( it->second );
+        EELEMENT    e( element );
 
         // use "NULL-ness" as an indication of presence of the attribute:
         EATTR*      nameAttr  = 0;
@@ -1860,13 +878,16 @@ void EAGLE_PLUGIN::loadElements( CPTREE& aElements )
             // EATTR override the ones established in the package only if they are
             // present here (except for rot, which if not present means angle zero).
             // So the logic is a bit different than in packageText() and in plain text.
-            for( CITER ait = it->second.begin();  ait != it->second.end();  ++ait )
-            {
 
-                if( ait->first != "attribute" )
+            // Get the first attribute and iterate
+            wxXmlNode* attribute = element->GetChildren();
+
+            while( attribute )
+            {
+                if( attribute->GetName() != "attribute" )
                     continue;
 
-                EATTR   a( ait->second );
+                EATTR   a( attribute );
 
                 if( a.name == "NAME" )
                 {
@@ -1960,12 +981,17 @@ void EAGLE_PLUGIN::loadElements( CPTREE& aElements )
                         m->Value().SetVisible( true );
 
                 }
+
+                attribute = attribute->GetNext();
             }
 
             m_xpath->pop();     // "attribute"
         }
 
         orientModuleAndText( m, e, nameAttr, valueAttr );
+
+        // Get next element
+        element = element->GetNext();
     }
 
     m_xpath->pop();     // "elements.element"
@@ -2101,50 +1127,55 @@ void EAGLE_PLUGIN::orientModuleText( MODULE* m, const EELEMENT& e,
     }
 }
 
-MODULE* EAGLE_PLUGIN::makeModule( CPTREE& aPackage, const string& aPkgName ) const
+
+MODULE* EAGLE_PLUGIN::makeModule( wxXmlNode* aPackage, const string& aPkgName ) const
 {
     std::unique_ptr<MODULE>   m( new MODULE( m_board ) );
 
     m->SetFPID( LIB_ID( aPkgName ) );
 
-    opt_string description = aPackage.get_optional<string>( "description" );
-    if( description )
-        m->SetDescription( FROM_UTF8( description->c_str() ) );
+    // Get the first package item and iterate
+    wxXmlNode* packageItem = aPackage->GetChildren();
 
-    for( CITER it = aPackage.begin();  it != aPackage.end();  ++it )
+    while( packageItem )
     {
-        CPTREE& t = it->second;
+        const wxString& itemName = packageItem->GetName();
+
+        if( itemName == "description" )
+            m->SetDescription( FROM_UTF8( packageItem->GetNodeContent().c_str() ) );
 
-        if( it->first == "wire" )
-            packageWire( m.get(), t );
+        else if( itemName == "wire" )
+            packageWire( m.get(), packageItem );
 
-        else if( it->first == "pad" )
-            packagePad( m.get(), t );
+        else if( itemName == "pad" )
+            packagePad( m.get(), packageItem );
 
-        else if( it->first == "text" )
-            packageText( m.get(), t );
+        else if( itemName == "text" )
+            packageText( m.get(), packageItem );
 
-        else if( it->first == "rectangle" )
-            packageRectangle( m.get(), t );
+        else if( itemName == "rectangle" )
+            packageRectangle( m.get(), packageItem );
 
-        else if( it->first == "polygon" )
-            packagePolygon( m.get(), t );
+        else if( itemName == "polygon" )
+            packagePolygon( m.get(), packageItem );
 
-        else if( it->first == "circle" )
-            packageCircle( m.get(), t );
+        else if( itemName == "circle" )
+            packageCircle( m.get(), packageItem );
 
-        else if( it->first == "hole" )
-            packageHole( m.get(), t );
+        else if( itemName == "hole" )
+            packageHole( m.get(), packageItem );
 
-        else if( it->first == "smd" )
-            packageSMD( m.get(), t );
+        else if( itemName == "smd" )
+            packageSMD( m.get(), packageItem );
+
+        packageItem = packageItem->GetNext();
     }
 
     return m.release();
 }
 
 
-void EAGLE_PLUGIN::packageWire( MODULE* aModule, CPTREE& aTree ) const
+void EAGLE_PLUGIN::packageWire( MODULE* aModule, wxXmlNode* aTree ) const
 {
     EWIRE        w( aTree );
     PCB_LAYER_ID layer = kicad_layer( w.layer );
@@ -2183,7 +1214,7 @@ void EAGLE_PLUGIN::packageWire( MODULE* aModule, CPTREE& aTree ) const
 }
 
 
-void EAGLE_PLUGIN::packagePad( MODULE* aModule, CPTREE& aTree ) const
+void EAGLE_PLUGIN::packagePad( MODULE* aModule, wxXmlNode* aTree ) const
 {
     // this is thru hole technology here, no SMDs
     EPAD e( aTree );
@@ -2271,7 +1302,7 @@ void EAGLE_PLUGIN::packagePad( MODULE* aModule, CPTREE& aTree ) const
 }
 
 
-void EAGLE_PLUGIN::packageText( MODULE* aModule, CPTREE& aTree ) const
+void EAGLE_PLUGIN::packageText( MODULE* aModule, wxXmlNode* aTree ) const
 {
     ETEXT        t( aTree );
     PCB_LAYER_ID layer = kicad_layer( t.layer );
@@ -2377,7 +1408,7 @@ void EAGLE_PLUGIN::packageText( MODULE* aModule, CPTREE& aTree ) const
 }
 
 
-void EAGLE_PLUGIN::packageRectangle( MODULE* aModule, CPTREE& aTree ) const
+void EAGLE_PLUGIN::packageRectangle( MODULE* aModule, wxXmlNode* aTree ) const
 {
     ERECT        r( aTree );
     PCB_LAYER_ID layer = kicad_layer( r.layer );
@@ -2410,7 +1441,7 @@ void EAGLE_PLUGIN::packageRectangle( MODULE* aModule, CPTREE& aTree ) const
 }
 
 
-void EAGLE_PLUGIN::packagePolygon( MODULE* aModule, CPTREE& aTree ) const
+void EAGLE_PLUGIN::packagePolygon( MODULE* aModule, wxXmlNode* aTree ) const
 {
     EPOLYGON    p( aTree );
     PCB_LAYER_ID    layer = kicad_layer( p.layer );
@@ -2439,16 +1470,22 @@ void EAGLE_PLUGIN::packagePolygon( MODULE* aModule, CPTREE& aTree ) const
         dwg->SetTimeStamp( timeStamp( aTree ) );
 
         std::vector<wxPoint> pts;
-        pts.reserve( aTree.size() );
+        // TODO: I think there's no way to know a priori the number of children in wxXmlNode :()
+        // pts.reserve( aTree.size() );
+
+        // Get the first vertex and iterate
+        wxXmlNode* vertex = aTree->GetChildren();
 
-        for( CITER vi = aTree.begin();  vi != aTree.end();  ++vi )
+        while( vertex )
         {
-            if( vi->first != "vertex" )     // skip <xmlattr> node
+            if( vertex->GetName() != "vertex" )     // skip <xmlattr> node
                 continue;
 
-            EVERTEX v( vi->second );
+            EVERTEX v( vertex );
 
             pts.push_back( wxPoint( kicad_x( v.x ), kicad_y( v.y ) ) );
+
+            vertex = vertex->GetNext();
         }
 
         dwg->SetPolyPoints( pts );
@@ -2459,7 +1496,7 @@ void EAGLE_PLUGIN::packagePolygon( MODULE* aModule, CPTREE& aTree ) const
 }
 
 
-void EAGLE_PLUGIN::packageCircle( MODULE* aModule, CPTREE& aTree ) const
+void EAGLE_PLUGIN::packageCircle( MODULE* aModule, wxXmlNode* aTree ) const
 {
     ECIRCLE         e( aTree );
     PCB_LAYER_ID    layer = kicad_layer( e.layer );
@@ -2488,7 +1525,7 @@ void EAGLE_PLUGIN::packageCircle( MODULE* aModule, CPTREE& aTree ) const
 }
 
 
-void EAGLE_PLUGIN::packageHole( MODULE* aModule, CPTREE& aTree ) const
+void EAGLE_PLUGIN::packageHole( MODULE* aModule, wxXmlNode* aTree ) const
 {
     EHOLE   e( aTree );
 
@@ -2518,7 +1555,7 @@ void EAGLE_PLUGIN::packageHole( MODULE* aModule, CPTREE& aTree ) const
 }
 
 
-void EAGLE_PLUGIN::packageSMD( MODULE* aModule, CPTREE& aTree ) const
+void EAGLE_PLUGIN::packageSMD( MODULE* aModule, wxXmlNode* aTree ) const
 {
     ESMD         e( aTree );
     PCB_LAYER_ID layer = kicad_layer( e.layer );
@@ -2582,7 +1619,7 @@ void EAGLE_PLUGIN::packageSMD( MODULE* aModule, CPTREE& aTree ) const
 typedef std::vector<ZONE_CONTAINER*>    ZONES;
 
 
-void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals )
+void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
 {
     ZONES   zones;      // per net
 
@@ -2590,32 +1627,40 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals )
 
     int netCode = 1;
 
-    for( CITER net = aSignals.begin();  net != aSignals.end();  ++net )
+    // Get the first signal and iterate
+    wxXmlNode* net = aSignals->GetChildren();
+
+    while( net )
     {
         bool    sawPad = false;
 
         zones.clear();
 
-        const string& nname = net->second.get<string>( "<xmlattr>.name" );
+        const string& nname = net->GetAttribute( "name" ).ToStdString();
         wxString netName = FROM_UTF8( nname.c_str() );
         m_board->Add( new NETINFO_ITEM( m_board, netName, netCode ) );
 
         m_xpath->Value( nname.c_str() );
 
+        // Get the first net item and iterate
+        wxXmlNode* netItem = net->GetChildren();
+
         // (contactref | polygon | wire | via)*
-        for( CITER it = net->second.begin();  it != net->second.end();  ++it )
+        while( netItem )
         {
-            if( it->first == "wire" )
+            const wxString& itemName = netItem->GetName();
+            if( itemName == "wire" )
             {
                 m_xpath->push( "wire" );
-                EWIRE        w( it->second );
+
+                EWIRE        w( netItem );
                 PCB_LAYER_ID layer = kicad_layer( w.layer );
 
                 if( IsCopperLayer( layer ) )
                 {
                     TRACK*  t = new TRACK( m_board );
 
-                    t->SetTimeStamp( timeStamp( it->second ) );
+                    t->SetTimeStamp( timeStamp( netItem ) );
 
                     t->SetPosition( wxPoint( kicad_x( w.x1 ), kicad_y( w.y1 ) ) );
                     t->SetEnd( wxPoint( kicad_x( w.x2 ), kicad_y( w.y2 ) ) );
@@ -2638,10 +1683,10 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals )
                 m_xpath->pop();
             }
 
-            else if( it->first == "via" )
+            else if( itemName == "via" )
             {
                 m_xpath->push( "via" );
-                EVIA    v( it->second );
+                EVIA    v( netItem );
 
                 PCB_LAYER_ID  layer_front_most = kicad_layer( v.layer_front_most );
                 PCB_LAYER_ID  layer_back_most  = kicad_layer( v.layer_back_most );
@@ -2684,7 +1729,7 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals )
                     else
                         via->SetViaType( VIA_BLIND_BURIED );
 
-                    via->SetTimeStamp( timeStamp( it->second ) );
+                    via->SetTimeStamp( timeStamp( netItem ) );
 
                     wxPoint pos( kicad_x( v.x ), kicad_y( v.y ) );
 
@@ -2696,14 +1741,13 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals )
                 m_xpath->pop();
             }
 
-            else if( it->first == "contactref" )
+            else if( itemName == "contactref" )
             {
                 m_xpath->push( "contactref" );
                 // <contactref element="RN1" pad="7"/>
-                CPTREE& attribs = it->second.get_child( "<xmlattr>" );
 
-                const string& reference = attribs.get<string>( "element" );
-                const string& pad       = attribs.get<string>( "pad" );
+                const string& reference = netItem->GetAttribute( "element" ).ToStdString();
+                const string& pad       = netItem->GetAttribute( "pad" ).ToStdString();
 
                 string key = makeKey( reference, pad ) ;
 
@@ -2716,11 +1760,11 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals )
                 sawPad = true;
             }
 
-            else if( it->first == "polygon" )
+            else if( itemName == "polygon" )
             {
                 m_xpath->push( "polygon" );
 
-                EPOLYGON     p( it->second );
+                EPOLYGON     p( netItem );
                 PCB_LAYER_ID layer = kicad_layer( p.layer );
 
                 if( IsCopperLayer( layer ) )
@@ -2730,19 +1774,24 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals )
                     m_board->Add( zone, ADD_APPEND );
                     zones.push_back( zone );
 
-                    zone->SetTimeStamp( timeStamp( it->second ) );
+                    zone->SetTimeStamp( timeStamp( netItem ) );
                     zone->SetLayer( layer );
                     zone->SetNetCode( netCode );
 
-                    for( CITER vi = it->second.begin();  vi != it->second.end();  ++vi )
+                    // Get the first vertex and iterate
+                    wxXmlNode* vertex = netItem->GetChildren();
+
+                    while( vertex )
                     {
-                        if( vi->first != "vertex" )     // skip <xmlattr> node
+                        if( vertex->GetName() != "vertex" )     // skip <xmlattr> node
                             continue;
 
-                        EVERTEX v( vi->second );
+                        EVERTEX v( vertex );
 
                         // Append the corner
                         zone->AppendCorner( wxPoint( kicad_x( v.x ), kicad_y( v.y ) ) );
+
+                        vertex = vertex->GetNext();
                     }
 
                     // If the pour is a cutout it needs to be set to a keepout
@@ -2788,6 +1837,8 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals )
 
                 m_xpath->pop();     // "polygon"
             }
+
+            netItem = netItem->GetNext();
         }
 
         if( zones.size() && !sawPad )
@@ -2801,6 +1852,9 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals )
         }
         else
             netCode++;
+
+        // Get next signal
+        net = net->GetNext();
     }
 
     m_xpath->pop();     // "signals.signal"
@@ -3011,7 +2065,7 @@ void EAGLE_PLUGIN::cacheLib( const wxString& aLibPath )
 
         if( aLibPath != m_lib_path || load )
         {
-            PTREE       doc;
+            wxXmlNode*  doc;
             LOCALE_IO   toggle;     // toggles on, then off, the C locale.
 
             m_templates.clear();
@@ -3026,42 +2080,55 @@ void EAGLE_PLUGIN::cacheLib( const wxString& aLibPath )
             // and is not necessarily utf8.
             string filename = (const char*) aLibPath.char_str( wxConvFile );
 
-            read_xml( filename, doc, xml_parser::no_comments );
+            // Load the document
+            wxXmlDocument xmlDocument;
+            wxFileName fn( filename );
+
+            if( !xmlDocument.Load( fn.GetFullPath() ) )
+                THROW_IO_ERROR( wxString::Format( _( "Unable to read file '%s'" ),
+                                                  fn.GetFullPath() ) );
+
+            doc = xmlDocument.GetRoot();
+
+            wxXmlNode* drawing       = MapChildren( doc )["drawing"];
+            NODE_MAP drawingChildren = MapChildren( drawing );
 
             // clear the cu map and then rebuild it.
             clear_cu_map();
 
             m_xpath->push( "eagle.drawing.layers" );
-            CPTREE& layers  = doc.get_child( "eagle.drawing.layers" );
+            wxXmlNode* layers  = drawingChildren["layers"];
             loadLayerDefs( layers );
             m_xpath->pop();
 
             m_xpath->push( "eagle.drawing.library" );
-            CPTREE& library = doc.get_child( "eagle.drawing.library" );
+            wxXmlNode* library = drawingChildren["library"];
             loadLibrary( library, NULL );
             m_xpath->pop();
 
             m_mod_time = modtime;
         }
     }
-    catch( file_parser_error fpe )
-    {
-        // for xml_parser_error, what() has the line number in it,
-        // but no byte offset.  That should be an adequate error message.
-        THROW_IO_ERROR( fpe.what() );
-    }
-
-    // Class ptree_error is a base class for xml_parser_error & file_parser_error,
-    // so one catch should be OK for all errors.
-    catch( ptree_error pte )
-    {
-        string errmsg = pte.what();
-
-        errmsg += " @\n";
-        errmsg += m_xpath->Contents();
-
-        THROW_IO_ERROR( errmsg );
-    }
+    catch(...){}
+    // TODO: Handle exceptions
+    // catch( file_parser_error fpe )
+    // {
+    //     // for xml_parser_error, what() has the line number in it,
+    //     // but no byte offset.  That should be an adequate error message.
+    //     THROW_IO_ERROR( fpe.what() );
+    // }
+    //
+    // // Class ptree_error is a base class for xml_parser_error & file_parser_error,
+    // // so one catch should be OK for all errors.
+    // catch( ptree_error pte )
+    // {
+    //     string errmsg = pte.what();
+    //
+    //     errmsg += " @\n";
+    //     errmsg += m_xpath->Contents();
+    //
+    //     THROW_IO_ERROR( errmsg );
+    // }
 }
 
 
diff --git a/pcbnew/eagle_plugin.h b/pcbnew/eagle_plugin.h
index e550be6f5..c46dde4fa 100644
--- a/pcbnew/eagle_plugin.h
+++ b/pcbnew/eagle_plugin.h
@@ -27,47 +27,53 @@
 
 #include <io_mgr.h>
 #include <layers_id_colors_and_visibility.h>
+#include <eagle_parser.h>
 
-
-// forward declaration on ptree template so we can confine use of big boost
-// headers to only the implementation *.cpp file.
-
-#include <boost/property_tree/ptree_fwd.hpp>
-#include <boost/ptr_container/ptr_map.hpp>
 #include <map>
+#include <wx/xml/xml.h>
 
 
-class MODULE;
-typedef boost::ptr_map< std::string, MODULE >   MODULE_MAP;
+typedef std::map< std::string, MODULE* > MODULE_MAP;
+typedef std::map< std::string, ENET >    NET_MAP;
+typedef NET_MAP::const_iterator          NET_MAP_CITER;
 
 
-struct ENET
+/// subset of eagle.drawing.board.designrules in the XML document
+struct ERULES
 {
-    int         netcode;
-    std::string netname;
+    int         psElongationLong;   ///< percent over 100%.  0-> not elongated, 100->twice as wide as is tall
+                                    ///< Goes into making a scaling factor for "long" pads.
 
-    ENET( int aNetCode, const std::string& aNetName ) :
-        netcode( aNetCode ),
-        netname( aNetName )
-    {}
+    int         psElongationOffset; ///< the offset of the hole within the "long" pad.
 
-    ENET() :
-        netcode( 0 )
-    {}
-};
+    double      rvPadTop;           ///< top pad size as percent of drill size
+    // double   rvPadBottom;        ///< bottom pad size as percent of drill size
 
-typedef std::map< std::string, ENET >   NET_MAP;
-typedef NET_MAP::const_iterator         NET_MAP_CITER;
+    double      rlMinPadTop;        ///< minimum copper annulus on through hole pads
+    double      rlMaxPadTop;        ///< maximum copper annulus on through hole pads
 
-typedef boost::property_tree::ptree     PTREE;
-typedef const PTREE                     CPTREE;
+    double      rvViaOuter;         ///< copper annulus is this percent of via hole
+    double      rlMinViaOuter;      ///< minimum copper annulus on via
+    double      rlMaxViaOuter;      ///< maximum copper annulus on via
+    double      mdWireWire;         ///< wire to wire spacing I presume.
 
-struct EELEMENT;
-class XPATH;
-struct ERULES;
-struct EATTR;
-class TEXTE_MODULE;
 
+    ERULES() :
+        psElongationLong    ( 100 ),
+        psElongationOffset  ( 0 ),
+        rvPadTop            ( 0.25 ),
+        // rvPadBottom      ( 0.25 ),
+        rlMinPadTop         ( Mils2iu( 10 ) ),
+        rlMaxPadTop         ( Mils2iu( 20 ) ),
+
+        rvViaOuter          ( 0.25 ),
+        rlMinViaOuter       ( Mils2iu( 10 ) ),
+        rlMaxViaOuter       ( Mils2iu( 20 ) ),
+        mdWireWire          ( 0 )
+    {}
+
+    void parse( wxXmlNode* aRules );
+};
 
 /**
  * Class EAGLE_PLUGIN
@@ -175,11 +181,11 @@ private:
 
     // all these loadXXX() throw IO_ERROR or ptree_error exceptions:
 
-    void loadAllSections( CPTREE& aDocument );
-    void loadDesignRules( CPTREE& aDesignRules );
-    void loadLayerDefs( CPTREE& aLayers );
-    void loadPlain( CPTREE& aPlain );
-    void loadSignals( CPTREE& aSignals );
+    void loadAllSections( wxXmlNode* aDocument );
+    void loadDesignRules( wxXmlNode* aDesignRules );
+    void loadLayerDefs( wxXmlNode* aLayers );
+    void loadPlain( wxXmlNode* aPlain );
+    void loadSignals( wxXmlNode* aSignals );
 
     /**
      * Function loadLibrary
@@ -192,10 +198,10 @@ private:
      *   we are loading a *.lbr not a *.brd file and the key used in m_templates is to exclude
      *   the library name.
      */
-    void loadLibrary( CPTREE& aLib, const std::string* aLibName );
+    void loadLibrary( wxXmlNode* aLib, const std::string* aLibName );
 
-    void loadLibraries( CPTREE& aLibs );
-    void loadElements( CPTREE& aElements );
+    void loadLibraries( wxXmlNode* aLibs );
+    void loadElements( wxXmlNode* aElements );
 
     void orientModuleAndText( MODULE* m, const EELEMENT& e, const EATTR* nameAttr, const EATTR* valueAttr );
     void orientModuleText( MODULE* m, const EELEMENT& e, TEXTE_MODULE* txt, const EATTR* a );
@@ -216,16 +222,16 @@ private:
      * Function makeModule
      * creates a MODULE from an Eagle package.
      */
-    MODULE* makeModule( CPTREE& aPackage, const std::string& aPkgName ) const;
-
-    void packageWire( MODULE* aModule, CPTREE& aTree ) const;
-    void packagePad( MODULE* aModule, CPTREE& aTree ) const;
-    void packageText( MODULE* aModule, CPTREE& aTree ) const;
-    void packageRectangle( MODULE* aModule, CPTREE& aTree ) const;
-    void packagePolygon( MODULE* aModule, CPTREE& aTree ) const;
-    void packageCircle( MODULE* aModule, CPTREE& aTree ) const;
-    void packageHole( MODULE* aModule, CPTREE& aTree ) const;
-    void packageSMD( MODULE* aModule, CPTREE& aTree ) const;
+    MODULE* makeModule( wxXmlNode* aPackage, const std::string& aPkgName ) const;
+
+    void packageWire( MODULE* aModule, wxXmlNode* aTree ) const;
+    void packagePad( MODULE* aModule, wxXmlNode* aTree ) const;
+    void packageText( MODULE* aModule, wxXmlNode* aTree ) const;
+    void packageRectangle( MODULE* aModule, wxXmlNode* aTree ) const;
+    void packagePolygon( MODULE* aModule, wxXmlNode* aTree ) const;
+    void packageCircle( MODULE* aModule, wxXmlNode* aTree ) const;
+    void packageHole( MODULE* aModule, wxXmlNode* aTree ) const;
+    void packageSMD( MODULE* aModule, wxXmlNode* aTree ) const;
 };
 
 #endif  // EAGLE_PLUGIN_H_

--------------2.12.2--



Follow ups