KiCad PCB EDA Suite
Loading...
Searching...
No Matches
eagle_bin_parser.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Binary Eagle parsing logic and the eagle_script[] format table ported from
5 * pcb-rnd src_plugins/io_eagle (eagle_bin.c) by Tibor 'Igor2' Palinkas and
6 * Erich S. Heinzle.
7 *
8 * COPYRIGHT (pcb-rnd, eagle_bin.c / eagle_bin.h)
9 *
10 * pcb-rnd, interactive printed circuit board design
11 * Copyright (C) 2017 Tibor 'Igor2' Palinkas
12 * Copyright (C) 2017 Erich S. Heinzle
13 *
14 * Copyright (C) 2026 KiCad Developers, see AUTHORS.txt for contributors.
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program. If not, see <https://www.gnu.org/licenses/>.
28 */
29
30#ifndef EAGLE_BIN_PARSER_H_
31#define EAGLE_BIN_PARSER_H_
32
33#include <cstdint>
34#include <map>
35#include <memory>
36#include <vector>
37
38#include <wx/string.h>
39
40class wxXmlDocument;
41class wxXmlNode;
42class wxInputStream;
43
59{
60public:
66 static bool IsBinaryEagle( wxInputStream& aStream );
67
70
77 std::unique_ptr<wxXmlDocument> Parse( const std::vector<uint8_t>& aBytes );
78
79private:
81 struct EGB_NODE
82 {
83 int id = 0;
84 wxString name;
85 wxString content;
86 std::map<wxString, wxString> props;
87 std::vector<std::unique_ptr<EGB_NODE>> children;
88 EGB_NODE* parent = nullptr;
89
90 EGB_NODE* AddChild( int aId, const wxString& aName );
91
93 EGB_NODE* AdoptChild( std::unique_ptr<EGB_NODE> aChild );
94
95 bool HasProp( const wxString& aKey ) const { return props.count( aKey ) != 0; }
96 wxString Prop( const wxString& aKey ) const;
97 long PropLong( const wxString& aKey ) const;
98
101 wxString PropDoubled( const wxString& aKey ) const;
102 EGB_NODE* FindChildById( int aId ) const;
103 EGB_NODE* FindChildByName( const wxString& aName ) const;
104
106 template <typename FN>
107 void ForEach( FN&& aFn )
108 {
109 aFn( this );
110
111 for( const auto& child : children )
112 child->ForEach( aFn );
113 }
114 };
115
117 struct DRC_CTX
118 {
119 long mdWireWire = 12;
120 long msWidth = 10;
121 double rvPadTop = 0.25;
122 double rvPadInner = 0.25;
123 double rvPadBottom = 0.25;
124 };
125
126 // Recursive descent over the 24-byte block stream.
127 int readBlock( long& aNumBlocks, EGB_NODE* aParent );
128
129 // Trailing optional sections (v4/v5 only).
130 bool readNotes();
131 bool readDrc( DRC_CTX& aDrc );
132
133 const wxString& nextLongText();
134
135 // Each 0x7F-marked string field holds a little-endian pointer into the free-text
136 // blob; resolve them by offset so the result is independent of traversal order.
137 void resolveLongPointers();
138
139 void postProcess( EGB_NODE* aRoot, const DRC_CTX& aDrc );
140
141 // Schematic assembly, split into ordered steps. resolveSchLibraries returns the
142 // library list that resegmentSchSheets needs to resolve part references.
143 void postProcessSchematic( EGB_NODE* aRoot );
144 void postprocRequiredAttrs( EGB_NODE* aRoot );
145 void postprocSchAttrs( EGB_NODE* aRoot );
146 void renameSchSections( EGB_NODE* aSchematic );
147 std::vector<EGB_NODE*> resolveSchLibraries( EGB_NODE* aSchematic );
148 void resegmentSchSheets( EGB_NODE* aSchematic, const std::vector<EGB_NODE*>& aLibList );
149
150 static std::vector<EGB_NODE*> childrenById( EGB_NODE* aParent, int aChildId );
151 static wxString nameByOrdinal( const std::vector<EGB_NODE*>& aList, long aIdx );
152 void postprocLayers( EGB_NODE* aDrawing, EGB_NODE* aLayers );
153 void postprocDrc( EGB_NODE* aDrcNode, const DRC_CTX& aDrc );
154 void postprocLibs( EGB_NODE* aLibraries );
155 void postprocElements( EGB_NODE* aElements );
156 void postprocAttributes( EGB_NODE* aRoot );
157 void postprocNames( EGB_NODE* aLibraries, EGB_NODE* aElements );
158 void postprocSignals( EGB_NODE* aSignals );
159 void postprocContactRefs( EGB_NODE* aSignals, EGB_NODE* aElements, EGB_NODE* aLibraries );
160 void postprocWires( EGB_NODE* aRoot );
161 void postprocArcs( EGB_NODE* aRoot );
162 void postprocVias( EGB_NODE* aRoot );
163 void postprocUnits( EGB_NODE* aRoot );
164 void postprocCircles( EGB_NODE* aRoot );
165 void postprocSmd( EGB_NODE* aRoot );
166 void postprocDimensions( EGB_NODE* aRoot );
167 void postprocFreeText( EGB_NODE* aRoot );
168 void postprocLongText( EGB_NODE* aRoot );
169 void postprocTextContent( EGB_NODE* aRoot );
170 void postprocRotation( EGB_NODE* aRoot );
171 bool isRotatable( int aId ) const;
172 bool isLongTextHost( int aId ) const;
173
174 void arcDecode( EGB_NODE* aElem, int aArcType, int aLineType );
175 void fixLongText( EGB_NODE* aNode, const wxString& aField );
176
177 // Convert the finished intermediate tree into wxXmlNode form.
178 wxXmlNode* toXml( const EGB_NODE* aNode ) const;
179
180 // Throw IO_ERROR unless [aOffs, aOffs + aLen) lies within m_buf.
181 void requireBytes( size_t aOffs, size_t aLen ) const;
182
183 // Little-endian field extractors over m_buf.
184 uint32_t loadU32( size_t aOffs, unsigned aLen ) const;
185 int32_t loadS32( size_t aOffs, unsigned aLen ) const;
186 bool loadBmb( size_t aOffs, uint32_t aMask ) const;
187 uint32_t loadUbf( size_t aOffs, uint32_t aField ) const;
188 wxString loadStr( size_t aOffs, unsigned aLen ) const;
189 double loadDouble( size_t aOffs ) const;
190
191 const std::vector<uint8_t>* m_buf = nullptr;
192 size_t m_pos = 0;
193
194 std::unique_ptr<EGB_NODE> m_root;
195
196 std::vector<wxString> m_freeText;
198 wxString m_invalidText;
199
202 std::map<size_t, wxString> m_freeTextByOffset;
203
206 struct LONG_REF
207 {
209 wxString field;
210 uint32_t ptr;
211 };
212
213 std::vector<LONG_REF> m_longRefs;
214};
215
216#endif // EAGLE_BIN_PARSER_H_
wxXmlNode * toXml(const EGB_NODE *aNode) const
void postprocSignals(EGB_NODE *aSignals)
std::unique_ptr< wxXmlDocument > Parse(const std::vector< uint8_t > &aBytes)
Parse a binary Eagle board into an XML DOM compatible with the XML walker.
static wxString nameByOrdinal(const std::vector< EGB_NODE * > &aList, long aIdx)
void requireBytes(size_t aOffs, size_t aLen) const
uint32_t loadUbf(size_t aOffs, uint32_t aField) const
void postprocCircles(EGB_NODE *aRoot)
bool readDrc(DRC_CTX &aDrc)
void postprocSchAttrs(EGB_NODE *aRoot)
void postprocFreeText(EGB_NODE *aRoot)
std::vector< EGB_NODE * > resolveSchLibraries(EGB_NODE *aSchematic)
bool isRotatable(int aId) const
void postprocLibs(EGB_NODE *aLibraries)
std::vector< LONG_REF > m_longRefs
const wxString & nextLongText()
uint32_t loadU32(size_t aOffs, unsigned aLen) const
void postprocTextContent(EGB_NODE *aRoot)
size_t m_pos
current read cursor
void postprocUnits(EGB_NODE *aRoot)
void postprocArcs(EGB_NODE *aRoot)
wxString loadStr(size_t aOffs, unsigned aLen) const
void fixLongText(EGB_NODE *aNode, const wxString &aField)
void renameSchSections(EGB_NODE *aSchematic)
void postProcess(EGB_NODE *aRoot, const DRC_CTX &aDrc)
int readBlock(long &aNumBlocks, EGB_NODE *aParent)
void postprocSmd(EGB_NODE *aRoot)
const std::vector< uint8_t > * m_buf
file contents, not owned
void postprocContactRefs(EGB_NODE *aSignals, EGB_NODE *aElements, EGB_NODE *aLibraries)
void postProcessSchematic(EGB_NODE *aRoot)
void postprocWires(EGB_NODE *aRoot)
std::vector< wxString > m_freeText
NUL-delimited notes strings.
void postprocLongText(EGB_NODE *aRoot)
void postprocLayers(EGB_NODE *aDrawing, EGB_NODE *aLayers)
bool loadBmb(size_t aOffs, uint32_t aMask) const
void postprocRotation(EGB_NODE *aRoot)
void postprocAttributes(EGB_NODE *aRoot)
void arcDecode(EGB_NODE *aElem, int aArcType, int aLineType)
double loadDouble(size_t aOffs) const
bool isLongTextHost(int aId) const
static bool IsBinaryEagle(wxInputStream &aStream)
Probe the first two bytes for the binary magic.
void postprocDimensions(EGB_NODE *aRoot)
void resegmentSchSheets(EGB_NODE *aSchematic, const std::vector< EGB_NODE * > &aLibList)
std::unique_ptr< EGB_NODE > m_root
wxString m_invalidText
returned when out of strings
static std::vector< EGB_NODE * > childrenById(EGB_NODE *aParent, int aChildId)
void postprocRequiredAttrs(EGB_NODE *aRoot)
std::map< size_t, wxString > m_freeTextByOffset
Free-text strings keyed by their byte offset within the blob, for pointer (0x7F-reference) resolution...
void postprocDrc(EGB_NODE *aDrcNode, const DRC_CTX &aDrc)
void postprocVias(EGB_NODE *aRoot)
void postprocNames(EGB_NODE *aLibraries, EGB_NODE *aElements)
void postprocElements(EGB_NODE *aElements)
int32_t loadS32(size_t aOffs, unsigned aLen) const
DRC values pulled from the trailing 244-byte block (or sane defaults).
Lightweight mutable tree node for the intermediate Eagle binary tree.
std::map< wxString, wxString > props
long PropLong(const wxString &aKey) const
EGB_NODE * AdoptChild(std::unique_ptr< EGB_NODE > aChild)
Move an existing node in as a child, repointing its parent link.
std::vector< std::unique_ptr< EGB_NODE > > children
EGB_NODE * FindChildById(int aId) const
bool HasProp(const wxString &aKey) const
void ForEach(FN &&aFn)
Apply aFn to this node and every descendant, pre-order.
EGB_NODE * AddChild(int aId, const wxString &aName)
wxString PropDoubled(const wxString &aKey) const
Format a property doubled in 64-bit so the half-to-full widening cannot overflow a 32-bit long.
wxString Prop(const wxString &aKey) const
EGB_NODE * FindChildByName(const wxString &aName) const
wxString content
PCDATA emitted as the XML node's text body.
A deferred string field and the absolute blob pointer it resolves to, recorded by readBlock() for res...