7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-18 20:59:17 +00:00

Use Record handling for parsing

Now, we know how big a record is, and should be able to parse all boards without missing bytes?
This commit is contained in:
Thomas Pointhuber 2020-04-03 23:22:24 +00:00 committed by Ian McInerney
parent 78dfbca9a3
commit b707c84b62
32 changed files with 6089 additions and 27 deletions

View File

@ -245,6 +245,20 @@ wxString PCadPcbFileWildcard()
return _( "P-Cad 200x ASCII PCB files" ) + AddFileExtListToFilter( { "pcb" } );
}
wxString AltiumDesignerPcbFileWildcard()
{
return _( "Altium Designer PCB files" ) + AddFileExtListToFilter( { "PcbDoc" } );
}
wxString AltiumCircuitStudioPcbFileWildcard()
{
return _( "Altium Circuit Studio PCB files" ) + AddFileExtListToFilter( { "CSPcbDoc" } );
}
wxString AltiumCircuitMakerPcbFileWildcard()
{
return _( "Altium Circuit Maker PCB files" ) + AddFileExtListToFilter( { "CMPcbDoc" } );
}
wxString PcbFileWildcard()
{

View File

@ -88,6 +88,7 @@ set_target_properties( cvpcb_kiface PROPERTIES
target_link_libraries( cvpcb_kiface
pcbcommon
pcad2kicadpcb
altium2kicadpcb
3d-viewer
gal
common

View File

@ -51,15 +51,15 @@ public:
* has been a plugin written.
*/
DEFINE_ENUM_VECTOR( SCH_FILE_T,
{
SCH_LEGACY, ///< Legacy Eeschema file formats prior to s-expression.
SCH_KICAD, ///< The s-expression version of the schematic file formats.
SCH_EAGLE, ///< Autodesk Eagle file format
// Add your schematic type here.
{
SCH_LEGACY, ///< Legacy Eeschema file formats prior to s-expression.
SCH_KICAD, ///< The s-expression version of the schematic file formats.
SCH_EAGLE, ///< Autodesk Eagle file format
// Add your schematic type here.
// ALTIUM,
// etc.
} )
// ALTIUM,
// etc.
} )
/**
* Return a #SCH_PLUGIN which the caller can use to import, export, save, or load

View File

@ -188,6 +188,9 @@ extern wxString EaglePcbFileWildcard();
extern wxString EagleSchematicFileWildcard();
extern wxString EagleFilesWildcard();
extern wxString PCadPcbFileWildcard();
extern wxString AltiumDesignerPcbFileWildcard();
extern wxString AltiumCircuitStudioPcbFileWildcard();
extern wxString AltiumCircuitMakerPcbFileWildcard();
extern wxString PdfFileWildcard();
extern wxString PSFileWildcard();
extern wxString MacrosFileWildcard();

View File

@ -569,6 +569,7 @@ endif()
add_subdirectory( pcad2kicadpcb_plugin )
add_subdirectory( altium2kicadpcb_plugin )
if( BUILD_GITHUB_PLUGIN )
add_subdirectory( github )
@ -666,6 +667,7 @@ set( PCBNEW_KIFACE_LIBRARIES
pcbcommon
pnsrouter
pcad2kicadpcb
altium2kicadpcb
common
gal
dxflib_qcad

View File

@ -0,0 +1,22 @@
# Sources for the pcbnew PLUGIN called ALTIUM_DESIGNER_PLUGIN, ALTIUM_CIRCUIT_STUDIO_PLUGIN and ALTIUM_CIRCUIT_MAKER_PLUGIN
set( ALTIUM2PCBNEW_SRCS
altium_circuit_maker_plugin.cpp
altium_circuit_studio_plugin.cpp
altium_designer_plugin.cpp
altium_pcb.cpp
altium_parser.cpp
altium_parser_pcb.cpp
)
add_library( altium2kicadpcb STATIC ${ALTIUM2PCBNEW_SRCS} )
add_dependencies( altium2kicadpcb compoundfilereader )
target_link_libraries( altium2kicadpcb pcbcommon )
target_include_directories( altium2kicadpcb PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
$<TARGET_PROPERTY:compoundfilereader,INTERFACE_INCLUDE_DIRECTORIES>
)

View File

@ -0,0 +1,101 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 Thomas Pointhuber <thomas.pointhuber@gmx.at>
*
* 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
*/
/**
* @file altium_plugin.cpp
* @brief Pcbnew PLUGIN for Altium *.PcbDoc format.
*/
#include <iomanip>
#include <wx/string.h>
#include <altium_circuit_maker_plugin.h>
#include <altium_pcb.h>
#include <class_board.h>
#include <compoundfilereader.h>
#include <utf.h>
ALTIUM_CIRCUIT_MAKER_PLUGIN::ALTIUM_CIRCUIT_MAKER_PLUGIN()
{
m_board = nullptr;
m_props = nullptr;
}
ALTIUM_CIRCUIT_MAKER_PLUGIN::~ALTIUM_CIRCUIT_MAKER_PLUGIN()
{
}
const wxString ALTIUM_CIRCUIT_MAKER_PLUGIN::PluginName() const
{
return wxT( "Altium Circuit Maker" );
}
const wxString ALTIUM_CIRCUIT_MAKER_PLUGIN::GetFileExtension() const
{
return wxT( "CMPcbDoc" );
}
BOARD* ALTIUM_CIRCUIT_MAKER_PLUGIN::Load(
const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties )
{
m_props = aProperties;
m_board = aAppendToMe ? aAppendToMe : new BOARD();
// Give the filename to the board if it's new
if( !aAppendToMe )
m_board->SetFileName( aFileName );
// clang-format off
const std::map<ALTIUM_PCB_DIR, std::string> mapping = {
{ ALTIUM_PCB_DIR::FILE_HEADER, "FileHeader" },
{ ALTIUM_PCB_DIR::ARCS6, "1CEEB63FB33847F8AFC4485F64735E\\Data" },
{ ALTIUM_PCB_DIR::BOARD6, "96B09F5C6CEE434FBCE0DEB3E88E70\\Data" },
{ ALTIUM_PCB_DIR::BOARDREGIONS, "E3A544335C30403A991912052C936F\\Data" },
{ ALTIUM_PCB_DIR::CLASSES6, "4F71DD45B09143988210841EA1C28D\\Data" },
{ ALTIUM_PCB_DIR::COMPONENTS6, "F9D060ACC7DD4A85BC73CB785BAC81\\Data" },
{ ALTIUM_PCB_DIR::DIMENSIONS6, "068B9422DBB241258BA2DE9A6BA1A6\\Data" },
{ ALTIUM_PCB_DIR::FILLS6, "6FFE038462A940E9B422EFC8F5D85E\\Data" },
{ ALTIUM_PCB_DIR::NETS6, "35D7CF51BB9B4875B3A138B32D80DC\\Data" },
{ ALTIUM_PCB_DIR::PADS6, "4F501041A9BC4A06BDBDAB67D3820E\\Data" },
{ ALTIUM_PCB_DIR::POLYGONS6, "A1931C8B0B084A61AA45146575FDD3\\Data" },
{ ALTIUM_PCB_DIR::REGIONS6, "F513A5885418472886D3EF18A09E46\\Data" },
{ ALTIUM_PCB_DIR::RULES6, "C27718A40C94421388FAE5BD7785D7\\Data" },
{ ALTIUM_PCB_DIR::SHAPEBASEDREGIONS6,"BDAA2C70289849078C8EBEEC7F0848\\Data" },
{ ALTIUM_PCB_DIR::TEXTS6, "A34BC67C2A5F408D8F377378C5C5E2\\Data" },
{ ALTIUM_PCB_DIR::TRACKS6, "412A754DBB864645BF01CD6A80C358\\Data" },
{ ALTIUM_PCB_DIR::VIAS6, "C87A685A0EFA4A90BEEFD666198B56\\Data" }
};
// clang-format on
ParseAltiumPcb( m_board, aFileName, mapping );
return m_board;
}

View File

@ -0,0 +1,63 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 Thomas Pointhuber <thomas.pointhuber@gmx.at>
*
* 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
*/
/**
* @file pcad_plugin.h
* @brief Pcbnew PLUGIN for Altium *.PcbDoc format.
*/
#ifndef ALTIUM_CIRCUIT_MAKER_PLUGIN_H_
#define ALTIUM_CIRCUIT_MAKER_PLUGIN_H_
#include <io_mgr.h>
class ALTIUM_CIRCUIT_MAKER_PLUGIN : public PLUGIN
{
public:
// -----<PUBLIC PLUGIN API>--------------------------------------------------
const wxString PluginName() const override;
BOARD* Load(
const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties ) override;
const wxString GetFileExtension() const override;
long long GetLibraryTimestamp( const wxString& aLibraryPath ) const override
{
// TODO?
return 0;
}
// -----</PUBLIC PLUGIN API>-------------------------------------------------
ALTIUM_CIRCUIT_MAKER_PLUGIN();
~ALTIUM_CIRCUIT_MAKER_PLUGIN();
private:
const PROPERTIES* m_props;
BOARD* m_board;
};
#endif // ALTIUM_CIRCUIT_MAKER_PLUGIN_H_

View File

@ -0,0 +1,101 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 Thomas Pointhuber <thomas.pointhuber@gmx.at>
*
* 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
*/
/**
* @file altium_plugin.cpp
* @brief Pcbnew PLUGIN for Altium *.PcbDoc format.
*/
#include <iomanip>
#include <wx/string.h>
#include <altium_circuit_studio_plugin.h>
#include <altium_pcb.h>
#include <class_board.h>
#include <compoundfilereader.h>
#include <utf.h>
ALTIUM_CIRCUIT_STUDIO_PLUGIN::ALTIUM_CIRCUIT_STUDIO_PLUGIN()
{
m_board = nullptr;
m_props = nullptr;
}
ALTIUM_CIRCUIT_STUDIO_PLUGIN::~ALTIUM_CIRCUIT_STUDIO_PLUGIN()
{
}
const wxString ALTIUM_CIRCUIT_STUDIO_PLUGIN::PluginName() const
{
return wxT( "Altium Circuit Studio" );
}
const wxString ALTIUM_CIRCUIT_STUDIO_PLUGIN::GetFileExtension() const
{
return wxT( "CSPcbDoc" );
}
BOARD* ALTIUM_CIRCUIT_STUDIO_PLUGIN::Load(
const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties )
{
m_props = aProperties;
m_board = aAppendToMe ? aAppendToMe : new BOARD();
// Give the filename to the board if it's new
if( !aAppendToMe )
m_board->SetFileName( aFileName );
// clang-format off
const std::map<ALTIUM_PCB_DIR, std::string> mapping = {
{ ALTIUM_PCB_DIR::FILE_HEADER, "FileHeader" },
{ ALTIUM_PCB_DIR::ARCS6, "00C595EB90524FFC8C3BD9670020A2\\Data" },
{ ALTIUM_PCB_DIR::BOARD6, "88857D7F1DF64F7BBB61848C965636\\Data" },
{ ALTIUM_PCB_DIR::BOARDREGIONS, "8957CF30F167408D9D263D23FE7C89\\Data" },
{ ALTIUM_PCB_DIR::CLASSES6, "847EFBF87A5149B1AA326A52AD6357\\Data" },
{ ALTIUM_PCB_DIR::COMPONENTS6, "465416896A15486999A39C643935D2\\Data" },
{ ALTIUM_PCB_DIR::DIMENSIONS6, "16C81DBC13C447FF8B42A426677F3C\\Data" },
{ ALTIUM_PCB_DIR::FILLS6, "4E83BDC3253747F08E9006D7F57020\\Data" },
{ ALTIUM_PCB_DIR::NETS6, "D95A0DA2FE9047779A5194C127F30B\\Data" },
{ ALTIUM_PCB_DIR::PADS6, "47D69BC5107A4B8DB8DAA23E39C238\\Data" },
{ ALTIUM_PCB_DIR::POLYGONS6, "D7038392280E4E229B9D9B5426B295\\Data" },
{ ALTIUM_PCB_DIR::REGIONS6, "FFDDC21382BB42FE8A7D0C328D272C\\Data" },
{ ALTIUM_PCB_DIR::RULES6, "48B2FA96DB7546818752B34373D6C6\\Data" },
{ ALTIUM_PCB_DIR::SHAPEBASEDREGIONS6, "D5F54B536E124FB89E2D51B1121508\\Data" },
{ ALTIUM_PCB_DIR::TEXTS6, "349ABBB211DB4F5B8AE41B1B49555A\\Data" },
{ ALTIUM_PCB_DIR::TRACKS6, "530C20C225354B858B2578CAB8C08D\\Data" },
{ ALTIUM_PCB_DIR::VIAS6, "CA5F5989BCDB404DA70A9D1D3D5758\\Data" }
};
// clang-format on
ParseAltiumPcb( m_board, aFileName, mapping );
return m_board;
}

View File

@ -0,0 +1,63 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 Thomas Pointhuber <thomas.pointhuber@gmx.at>
*
* 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
*/
/**
* @file pcad_plugin.h
* @brief Pcbnew PLUGIN for Altium *.PcbDoc format.
*/
#ifndef ALTIUM_CIRCUIT_STUDIO_PLUGIN_H_
#define ALTIUM_CIRCUIT_STUDIO_PLUGIN_H_
#include <io_mgr.h>
class ALTIUM_CIRCUIT_STUDIO_PLUGIN : public PLUGIN
{
public:
// -----<PUBLIC PLUGIN API>--------------------------------------------------
const wxString PluginName() const override;
BOARD* Load(
const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties ) override;
const wxString GetFileExtension() const override;
long long GetLibraryTimestamp( const wxString& aLibraryPath ) const override
{
// TODO?
return 0;
}
// -----</PUBLIC PLUGIN API>-------------------------------------------------
ALTIUM_CIRCUIT_STUDIO_PLUGIN();
~ALTIUM_CIRCUIT_STUDIO_PLUGIN();
private:
const PROPERTIES* m_props;
BOARD* m_board;
};
#endif // ALTIUM_CIRCUIT_STUDIO_PLUGIN_H_

View File

@ -0,0 +1,101 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 Thomas Pointhuber <thomas.pointhuber@gmx.at>
*
* 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
*/
/**
* @file altium_plugin.cpp
* @brief Pcbnew PLUGIN for Altium *.PcbDoc format.
*/
#include <iomanip>
#include <wx/string.h>
#include <altium_designer_plugin.h>
#include <altium_pcb.h>
#include <class_board.h>
#include <compoundfilereader.h>
#include <utf.h>
ALTIUM_DESIGNER_PLUGIN::ALTIUM_DESIGNER_PLUGIN()
{
m_board = nullptr;
m_props = nullptr;
}
ALTIUM_DESIGNER_PLUGIN::~ALTIUM_DESIGNER_PLUGIN()
{
}
const wxString ALTIUM_DESIGNER_PLUGIN::PluginName() const
{
return wxT( "Altium Designer" );
}
const wxString ALTIUM_DESIGNER_PLUGIN::GetFileExtension() const
{
return wxT( "PcbDoc" );
}
BOARD* ALTIUM_DESIGNER_PLUGIN::Load(
const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties )
{
m_props = aProperties;
m_board = aAppendToMe ? aAppendToMe : new BOARD();
// Give the filename to the board if it's new
if( !aAppendToMe )
m_board->SetFileName( aFileName );
// clang-format off
const std::map<ALTIUM_PCB_DIR, std::string> mapping = {
{ ALTIUM_PCB_DIR::FILE_HEADER, "FileHeader" },
{ ALTIUM_PCB_DIR::ARCS6, "Arcs6\\Data" },
{ ALTIUM_PCB_DIR::BOARD6, "Board6\\Data" },
{ ALTIUM_PCB_DIR::BOARDREGIONS, "BoardRegions\\Data" },
{ ALTIUM_PCB_DIR::CLASSES6, "Classes6\\Data" },
{ ALTIUM_PCB_DIR::COMPONENTS6, "Components6\\Data" },
{ ALTIUM_PCB_DIR::DIMENSIONS6, "Dimensions6\\Data" },
{ ALTIUM_PCB_DIR::FILLS6, "Fills6\\Data" },
{ ALTIUM_PCB_DIR::NETS6, "Nets6\\Data" },
{ ALTIUM_PCB_DIR::PADS6, "Pads6\\Data" },
{ ALTIUM_PCB_DIR::POLYGONS6, "Polygons6\\Data" },
{ ALTIUM_PCB_DIR::REGIONS6, "Regions6\\Data" },
{ ALTIUM_PCB_DIR::RULES6, "Rules6\\Data" },
{ ALTIUM_PCB_DIR::SHAPEBASEDREGIONS6, "ShapeBasedRegions6\\Data" },
{ ALTIUM_PCB_DIR::TEXTS6, "Texts6\\Data" },
{ ALTIUM_PCB_DIR::TRACKS6, "Tracks6\\Data" },
{ ALTIUM_PCB_DIR::VIAS6, "Vias6\\Data" }
};
// clang-format on
ParseAltiumPcb( m_board, aFileName, mapping );
return m_board;
}

View File

@ -0,0 +1,63 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 Thomas Pointhuber <thomas.pointhuber@gmx.at>
*
* 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
*/
/**
* @file pcad_plugin.h
* @brief Pcbnew PLUGIN for Altium *.PcbDoc format.
*/
#ifndef ALTIUM_DESIGNER_PLUGIN_H_
#define ALTIUM_DESIGNER_PLUGIN_H_
#include <io_mgr.h>
class ALTIUM_DESIGNER_PLUGIN : public PLUGIN
{
public:
// -----<PUBLIC PLUGIN API>--------------------------------------------------
const wxString PluginName() const override;
BOARD* Load(
const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties ) override;
const wxString GetFileExtension() const override;
long long GetLibraryTimestamp( const wxString& aLibraryPath ) const override
{
// TODO?
return 0;
}
// -----</PUBLIC PLUGIN API>-------------------------------------------------
ALTIUM_DESIGNER_PLUGIN();
~ALTIUM_DESIGNER_PLUGIN();
private:
const PROPERTIES* m_props;
BOARD* m_board;
};
#endif // ALTIUM_DESIGNER_PLUGIN_H_

View File

@ -0,0 +1,234 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019-2020 Thomas Pointhuber <thomas.pointhuber@gmx.at>
*
* 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 "altium_parser.h"
#include <compoundfilereader.h>
#include <ki_exception.h>
#include <sstream>
#include <utf.h>
#include <wx/translation.h>
#include <wx/wx.h>
const CFB::COMPOUND_FILE_ENTRY* FindStream(
const CFB::CompoundFileReader& aReader, const char* aStreamName )
{
const CFB::COMPOUND_FILE_ENTRY* ret = nullptr;
aReader.EnumFiles( aReader.GetRootEntry(), -1,
[&]( const CFB::COMPOUND_FILE_ENTRY* aEntry, const CFB::utf16string& aU16dir,
int level ) -> void {
if( aReader.IsStream( aEntry ) )
{
std::string name = UTF16ToUTF8( aEntry->name );
if( aU16dir.length() > 0 )
{
std::string dir = UTF16ToUTF8( aU16dir.c_str() );
if( strncmp( aStreamName, dir.c_str(), dir.length() ) == 0
&& aStreamName[dir.length()] == '\\'
&& strcmp( aStreamName + dir.length() + 1, name.c_str() ) == 0 )
{
ret = aEntry;
}
}
else
{
if( strcmp( aStreamName, name.c_str() ) == 0 )
{
ret = aEntry;
}
}
}
} );
return ret;
}
ALTIUM_PARSER::ALTIUM_PARSER(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry )
{
m_subrecord_end = nullptr;
if( aEntry->size > std::numeric_limits<size_t>::max() )
{
THROW_IO_ERROR( _( "stream too large" ) );
}
m_size = static_cast<size_t>( aEntry->size );
m_error = false;
m_content.reset( new char[m_size] );
m_pos = m_content.get();
// read file into buffer
aReader.ReadFile( aEntry, 0, m_content.get(), m_size );
}
std::map<wxString, wxString> ALTIUM_PARSER::ReadProperties()
{
std::map<wxString, wxString> kv;
uint32_t length = Read<uint32_t>();
if( length > GetRemainingBytes() || m_pos[length - 1] != '\0' )
{
m_error = true;
return kv;
}
//we use std::string because std::string can handle NULL-bytes
//wxString would end the string at the first NULL-byte
std::string str = std::string( m_pos, length - 1 );
m_pos += length;
std::size_t token_end = 0;
while( token_end < str.size() && token_end != std::string::npos )
{
std::size_t token_start = str.find( '|', token_end );
std::size_t token_equal = str.find( '=', token_start );
token_end = str.find( '|', token_equal );
std::string keyS = str.substr( token_start + 1, token_equal - token_start - 1 );
std::string valueS = str.substr( token_equal + 1, token_end - token_equal - 1 );
//convert the strings to wxStrings, since we use them everywhere
//value can have non-ASCII characters, so we convert them from LATIN1/ISO8859-1
wxString key( keyS.c_str(), wxConvISO8859_1 );
wxString value( valueS.c_str(), wxConvISO8859_1 );
kv.insert( { key, value } );
}
return kv;
}
int ALTIUM_PARSER::PropertiesReadInt(
const std::map<wxString, wxString>& aProperties, const wxString& aKey, int aDefault )
{
try
{
const wxString& value = aProperties.at( aKey );
return wxAtoi( value );
}
catch( const std::out_of_range& oor )
{
return aDefault;
}
}
double ALTIUM_PARSER::PropertiesReadDouble(
const std::map<wxString, wxString>& aProperties, const wxString& aKey, double aDefault )
{
try
{
const wxString& value = aProperties.at( aKey );
// Locale independent str -> double conversation
std::istringstream istr( (const char*) value.mb_str() );
istr.imbue( std::locale( "C" ) );
double doubleValue;
istr >> doubleValue;
return doubleValue;
}
catch( const std::out_of_range& oor )
{
return aDefault;
}
}
bool ALTIUM_PARSER::PropertiesReadBool(
const std::map<wxString, wxString>& aProperties, const wxString& aKey, bool aDefault )
{
try
{
const wxString& value = aProperties.at( aKey );
return value == "TRUE";
}
catch( const std::out_of_range& oor )
{
return aDefault;
}
}
int32_t ALTIUM_PARSER::PropertiesReadKicadUnit( const std::map<wxString, wxString>& aProperties,
const wxString& aKey, const wxString& aDefault )
{
const wxString& value = PropertiesReadString( aProperties, aKey, aDefault );
size_t decimal_point = value.find( '.' );
size_t value_end = value.find_first_not_of( "+-0123456789." );
wxString before_decimal_str = value.Left( decimal_point );
int before_decimal = wxAtoi( before_decimal_str );
int after_decimal = 0;
size_t after_decimal_digits = 0;
if( decimal_point != wxString::npos )
{
if( value_end != wxString::npos )
{
after_decimal_digits = value_end - ( decimal_point + 1 );
}
else
{
after_decimal_digits = value.size() - ( decimal_point + 1 ); // TODO: correct?
}
wxString after_decimal_str = value.Mid( decimal_point + 1, after_decimal_digits );
after_decimal = wxAtoi( after_decimal_str );
}
if( value.length() > 3 && value.compare( value.length() - 3, 3, "mil" ) == 0 )
{
// ensure after_decimal is formatted to base 1000
int after_decimal_1000;
if( after_decimal_digits <= 4 )
{
after_decimal_1000 =
static_cast<int>( after_decimal * std::pow( 10, 4 - after_decimal_digits ) );
}
else
{
after_decimal_1000 =
static_cast<int>( after_decimal / std::pow( 10, after_decimal_digits - 4 ) );
}
int32_t mils = before_decimal * 10000 + after_decimal_1000;
return ConvertToKicadUnit( mils );
}
wxLogError( wxString::Format( _( "Unit '%s' does not end with mils" ) ), value );
return 0;
}
wxString ALTIUM_PARSER::PropertiesReadString( const std::map<wxString, wxString>& aProperties,
const wxString& aKey, const wxString& aDefault )
{
try
{
return aProperties.at( aKey );
}
catch( const std::out_of_range& oor )
{
return aDefault;
}
}

View File

@ -0,0 +1,199 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019-2020 Thomas Pointhuber <thomas.pointhuber@gmx.at>
*
* 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 ALTIUM_PARSER_H
#define ALTIUM_PARSER_H
#include <map>
#include <memory>
#include <math/util.h>
#include <wx/gdicmn.h>
namespace CFB
{
class CompoundFileReader;
struct COMPOUND_FILE_ENTRY;
} // namespace CFB
// Helper method to find file inside compound file
const CFB::COMPOUND_FILE_ENTRY* FindStream(
const CFB::CompoundFileReader& aReader, const char* aStreamName );
class ALTIUM_PARSER
{
public:
ALTIUM_PARSER( const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
~ALTIUM_PARSER() = default;
template <typename Type>
Type Read()
{
if( GetRemainingBytes() >= sizeof( Type ) )
{
Type val = *(Type*) ( m_pos );
m_pos += sizeof( Type );
return val;
}
else
{
m_error = true;
return 0;
}
}
wxString ReadWxString()
{
uint8_t len = Read<uint8_t>();
if( GetRemainingBytes() >= len )
{
//altium uses LATIN1/ISO 8859-1, convert it
wxString val = wxString( m_pos, wxConvISO8859_1, len );
m_pos += len;
return val;
}
else
{
m_error = true;
return wxString( "" );
}
}
int32_t ReadKicadUnit()
{
return ConvertToKicadUnit( Read<int32_t>() );
}
int32_t ReadKicadUnitX()
{
return ReadKicadUnit();
}
int32_t ReadKicadUnitY()
{
return -ReadKicadUnit();
}
wxPoint ReadWxPoint()
{
int32_t x = ReadKicadUnitX();
int32_t y = ReadKicadUnitY();
return { x, y };
}
wxSize ReadWxSize()
{
int32_t x = ReadKicadUnit();
int32_t y = ReadKicadUnit();
return { x, y };
}
size_t ReadAndSetSubrecordLength()
{
uint32_t length = Read<uint32_t>();
m_subrecord_end = m_pos + length;
return length;
}
std::map<wxString, wxString> ReadProperties();
static int32_t ConvertToKicadUnit( const int32_t aValue )
{
return ( ( (int64_t) aValue ) * 254L ) / 100;
}
static int32_t ConvertToKicadUnit( const double aValue )
{
return KiROUND( aValue * 2.54L );
}
static int PropertiesReadInt(
const std::map<wxString, wxString>& aProperties, const wxString& aKey, int aDefault );
static double PropertiesReadDouble( const std::map<wxString, wxString>& aProperties,
const wxString& aKey, double aDefault );
static bool PropertiesReadBool(
const std::map<wxString, wxString>& aProperties, const wxString& aKey, bool aDefault );
static int32_t PropertiesReadKicadUnit( const std::map<wxString, wxString>& aProperties,
const wxString& aKey, const wxString& aDefault );
static wxString PropertiesReadString( const std::map<wxString, wxString>& aProperties,
const wxString& aKey, const wxString& aDefault );
void Skip( size_t aLength )
{
if( GetRemainingBytes() >= aLength )
{
m_pos += aLength;
}
else
{
m_error = true;
}
}
void SkipSubrecord()
{
if( m_subrecord_end == nullptr || m_subrecord_end < m_pos )
{
m_error = true;
}
else
{
m_pos = m_subrecord_end;
}
};
size_t GetRemainingBytes() const
{
return m_pos == nullptr ? 0 : m_size - ( m_pos - m_content.get() );
}
size_t GetRemainingSubrecordBytes() const
{
return m_pos == nullptr || m_subrecord_end == nullptr || m_subrecord_end <= m_pos ?
0 :
m_subrecord_end - m_pos;
};
bool HasParsingError()
{
return m_error;
}
private:
std::unique_ptr<char[]> m_content;
size_t m_size;
char* m_pos; // current read pointer
char* m_subrecord_end; // pointer which points to next subrecord start
bool m_error;
};
#endif //ALTIUM_PARSER_H

View File

@ -0,0 +1,658 @@
# Can be viewed in: https://ide.kaitai.io/
#
# This file is a formal specification of the binary format used in Altium.
# Files need to manually extracted using a program which can read the Microsoft Compound File Format.
#
# While I do not create a parser using this file, it is still very helpful to understand the binary
# format.
meta:
id: altium_binary
endian: le
encoding: ISO8859-1
seq:
- id: record
type: record
repeat: eos
# https://github.com/thesourcerer8/altium2kicad/blob/master/convertpcb.pl#L1291
types:
record:
seq:
- id: recordtype
type: u1
enum: record_id
- id: record
type:
switch-on: recordtype
cases:
record_id::arc6: arc
record_id::pad6: pad
record_id::via6: via
record_id::track6: track
record_id::text6: text
record_id::fill6: fill
record_id::region6: region
arc:
seq:
- id: sub1_len
type: u4
- id: data
type: arc_sub1
size: sub1_len
arc_sub1:
seq:
- id: layer
type: u1
- #id: flags_u7
type: b1
- #id: flags_u6
type: b1
- #id: flags_u5
type: b1
- #id: flags_u4
type: b1
- #id: flags_u3
type: b1
- id: is_not_locked
type: b1
- id: is_not_polygonoutline
type: b1
- #id: flags_u0
type: b1
- id: is_keepout
type: u1 # KEEPOUT = 2
- id: net
type: u2
- id: subpolyindex
type: u2
- id: component
type: u2
- size: 4
- id: center
type: xy
- id: radius
type: u4
- id: start_angle
type: f8
- id: end_angle
type: f8
- id: width
type: u4
pad:
seq:
- id: sub1_len
type: u4
- id: designator
type: pad_sub1
size: sub1_len
- id: sub2_len
type: u4
- size: sub2_len
- id: sub3_len
type: u4
- size: sub3_len
- id: sub4_len
type: u4
- size: sub4_len
- id: sub5_len
type: u4
- id: size_and_shape
type: pad_sub5
size: sub5_len
- id: sub6_len
type: u4
- id: size_and_shape_by_layer
type: pad_sub6
size: sub6_len
if: sub6_len > 0
pad_sub1:
seq:
- id: name_len # = len-1?
type: u1
- id: name
type: str
size: name_len
pad_sub5:
seq:
- id: layer # $pos+23
type: u1
enum: layer
- id: test_fab_top
type: b1
- id: tent_bottom
type: b1
- id: tent_top
type: b1
- #id: flags_u4
type: b1
- #id: flags_u3
type: b1
- id: is_not_locked
type: b1
- #id: flags_u1
type: b1
- #id: flags_u0
type: b1
- #id: flags2_u7
type: b1
- #id: flags2_u6
type: b1
- #id: flags2_u5
type: b1
- #id: flags2_u4
type: b1
- #id: flags2_u3
type: b1
- #id: flags2_u2
type: b1
- #id: flags2_u1
type: b1
- id: test_fab_bottom
type: b1
#- id: u
# size: 1
- id: net # $pos+26
type: u2
- size: 2
- id: component # $pos+30
type: u2
- size: 4
- id: position # $pos+36, $pos+40
type: xy
- id: topsize # $pos+44, $pos+48
type: xy
- id: midsize # $pos+52, $pos+56
type: xy
- id: botsize # $pos+60, $pos+64
type: xy
- id: holesize # $pos+68
type: u4
- id: topshape # $pos+72
type: u1
enum: pad_shape
- id: midshape # $pos+73
type: u1
enum: pad_shape
- id: botshape # $pos+74
type: u1
enum: pad_shape
- id: direction # $pos+75
type: f8
- id: plated # $pos+83
type: u1
enum: boolean
- size: 1
- id: pad_mode # $pos+85
type: u1
enum: pad_mode
- size: 5
- id: ccw # $pos+91
type: u4
- id: cen # $pos+95
type: u1
- size: 1
- id: cag # $pos+97
type: u4
- id: cpr # $pos+101
type: u4
- id: cpc # $pos+105
type: u4
- id: pastemaskexpanionmanual
type: s4
- id: soldermaskexpansionmanual # $pos+113
type: s4
- id: cpl # $pos+117
type: u1
- size: 6
- id: pastemaskexpansionmode # $pos+124
type: u1
enum: pad_mode_rule
- id: soldermaskexpansionmode # $pos+125
type: u1
enum: pad_mode_rule
- size: 3
- id: holerotation # $pos+129
type: f8
- size: 4
- id: testpoint_assembly_top
type: u1
enum: boolean
- id: testpoint_assembly_bottom
type: u1
enum: boolean
pad_sub6:
seq:
- id: x
type: s4
repeat: expr
repeat-expr: 29
- id: y
type: s4
repeat: expr
repeat-expr: 29
- id: shape
type: u1
enum: pad_shape
repeat: expr
repeat-expr: 29
- size: 1
- id: hole_type
type: u1
enum: pad_hole_type
- id: slot_length
type: s4
- id: slot_rotation
type: f8
- id: holeoffset_x
type: s4
repeat: expr
repeat-expr: 32
- id: holeoffset_y
type: s4
repeat: expr
repeat-expr: 32
- size: 1
- id: shape_alt
type: u1
enum: pad_shape_alt
repeat: expr
repeat-expr: 32
- id: corner_radius
type: u1
repeat: expr
repeat-expr: 32
- size: 32
via:
seq:
- id: sub1_len
type: u4
- id: data
type: via_sub1
size: sub1_len
via_sub1:
seq:
- size: 1
- id: test_fab_top
type: b1
- id: tent_bottom
type: b1
- id: tent_top
type: b1
- #id: flags_u4
type: b1
- #id: flags_u3
type: b1
- id: is_not_locked
type: b1
- #id: flags_u1
type: b1
- #id: flags_u0
type: b1
- #id: flags2_u7
type: b1
- #id: flags2_u6
type: b1
- #id: flags2_u5
type: b1
- #id: flags2_u4
type: b1
- #id: flags2_u3
type: b1
- #id: flags2_u2
type: b1
- #id: flags2_u1
type: b1
- id: test_fab_bottom
type: b1
- id: net
type: u2
- size: 2
- id: component
type: u2
- size: 4
- id: pos # 13
type: xy
- id: diameter # 21
type: s4
- id: holesize # 29
type: s4
- id: start_layer
type: u1
enum: layer
- id: end_layer
type: u1
enum: layer
- size: 43
- id: via_mode
type: u1
enum: pad_mode
- id: diameter_alt
type: s4
repeat: expr
repeat-expr: 32
track:
seq:
- id: sub1_len
type: u4
- id: data
type: track_sub1
size: sub1_len
track_sub1:
seq:
- id: layer
type: u1
enum: layer
- #id: flags_u7
type: b1
- #id: flags_u6
type: b1
- #id: flags_u5
type: b1
- #id: flags_u4
type: b1
- #id: flags_u3
type: b1
- id: is_not_locked
type: b1
- id: is_not_polygonoutline
type: b1
- #id: flags_u0
type: b1
- id: is_keepout
type: u1 # KEEPOUT = 2
- id: net
type: u2
- id: subpolyindex
type: u2
- id: component
type: u2
- size: 4
- id: start # 13
type: xy
- id: end # 21
type: xy
- id: width # 29
type: s4
text:
seq:
- id: sub1_len
type: u4
- id: properties
type: text_sub1
size: sub1_len
- id: sub2_len
type: u4
- id: text
type: text_sub2
size: sub2_len
text_sub1:
seq:
- id: layer
type: u1
- #id: flags_u7
type: b1
- #id: flags_u6
type: b1
- #id: flags_u5
type: b1
- #id: flags_u4
type: b1
- #id: flags_u3
type: b1
- id: is_not_locked
type: b1
- #id: flags_u1
type: b1
- #id: flags_u0
type: b1
- size: 1
- id: net
type: u2
- size: 2
- id: component
type: u2
- size: 4
- id: pos
type: xy
- id: height
type: u4
- id: font_name_id
type: u1
- size: 1
- id: rotation
type: f8
- id: mirrored
type: u1
enum: boolean
- id: strokewidth
type: u4
- id: is_comment
type: u1
enum: boolean
- id: is_designator
type: u1
enum: boolean
- size: 4
- id: font_name
size: 64
type: str # TODO: terminates with [0, 0]
encoding: UTF-16
- size: 22
- id: position
type: u1
enum: text_position
- size: 27
- id: truetype
type: u1
enum: boolean
- id: barcode_name
size: 64
type: str # TODO: terminates with [0, 0]
encoding: UTF-16
text_sub2:
seq:
- id: len
type: u1
- id: name
type: str
size: len
fill:
seq:
- id: sub1_len
type: u4
- id: data
type: fill_sub1
size: sub1_len
fill_sub1:
seq:
- id: layer
type: u1
- #id: flags_u7
type: b1
- #id: flags_u6
type: b1
- #id: flags_u5
type: b1
- #id: flags_u4
type: b1
- #id: flags_u3
type: b1
- id: is_not_locked
type: b1
- #id: flags_u1
type: b1
- #id: flags_u0
type: b1
- id: is_keepout
type: u1 # KEEPOUT = 2
- id: net
type: u2
- size: 2
- id: component
type: u2
- size: 4
- id: pos1
type: xy
- id: pos2
type: xy
- id: rotation
type: f8
region:
seq:
- id: sub1_len
type: u4
- id: data
type: region_sub1
size: sub1_len
region_sub1:
seq:
- id: layer
type: u1
- #id: flags_u7
type: b1
- #id: flags_u6
type: b1
- #id: flags_u5
type: b1
- #id: flags_u4
type: b1
- #id: flags_u3
type: b1
- id: is_not_locked
type: b1
- #id: flags_u1
type: b1
- #id: flags_u0
type: b1
- id: is_keepout
type: u1 # KEEPOUT = 2
- id: net
type: u2
- size: 2
- id: component
type: u2
- size: 5
- id: holecount # TODO: check
type: u2
- size: 2
- id: propterties_len
type: u4
- id: properties
size: propterties_len
type: str
- id: vertices_num
type: u4
- id: vertices # region1 type
repeat: expr
repeat-expr: vertices_num
type: xyf
#- id: vertices2 # region2 type
# repeat: expr
# repeat-expr: vertices_num+1
# type: xyf2
xy:
seq:
- id: x
type: s4
- id: y
type: s4
xyf: # no idea why two different formats?
seq:
- id: x
type: f8
- id: y
type: f8
xyf2: # no idea why two different formats?
seq:
- id: is_round
type: u1
enum: boolean
- id: position
type: xy
- id: center
type: xy
- id: radius
type: u4
- id: angle1
type: f8
- id: angle2
type: f8
enums:
record_id:
0x01: arc6
0x02: pad6
0x03: via6
0x04: track6
0x05: text6
0x06: fill6
0x0b: region6
boolean:
0: false
1: true
pad_shape:
0: unknown
1: circle
2: rect
3: octagonal
pad_shape_alt:
0: unknown
1: round
2: rect
3: octagonal
9: roundrectangle
pad_hole_type:
0: normal
1: square
2: slot
pad_mode:
0: simple
1: top_middle_bottom
2: full_stack
pad_mode_rule:
0: unknown
1: rule
2: manual
text_position:
1: left_top
2: left_center
3: left_bottom
4: center_top
5: center_center
6: center_bottom
7: right_top
8: right_center
9: right_bottom
layer:
1: f_cu
32: b_cu

View File

@ -0,0 +1,941 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 Thomas Pointhuber <thomas.pointhuber@gmx.at>
*
* 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 <map>
#include <unordered_map>
#include <ki_exception.h>
#include <math/util.h>
#include <wx/translation.h>
#include "altium_parser.h"
#include "altium_parser_pcb.h"
ALTIUM_LAYER altium_layer_from_name( const wxString& aName )
{
static const std::unordered_map<std::string, ALTIUM_LAYER> hash_map = {
{ "TOP", ALTIUM_LAYER::TOP_LAYER },
{ "MID1", ALTIUM_LAYER::MID_LAYER_1 },
{ "MID2", ALTIUM_LAYER::MID_LAYER_2 },
{ "MID3", ALTIUM_LAYER::MID_LAYER_3 },
{ "MID4", ALTIUM_LAYER::MID_LAYER_4 },
{ "MID5", ALTIUM_LAYER::MID_LAYER_5 },
{ "MID6", ALTIUM_LAYER::MID_LAYER_6 },
{ "MID7", ALTIUM_LAYER::MID_LAYER_7 },
{ "MID8", ALTIUM_LAYER::MID_LAYER_8 },
{ "MID9", ALTIUM_LAYER::MID_LAYER_9 },
{ "MID10", ALTIUM_LAYER::MID_LAYER_10 },
{ "MID11", ALTIUM_LAYER::MID_LAYER_11 },
{ "MID12", ALTIUM_LAYER::MID_LAYER_12 },
{ "MID13", ALTIUM_LAYER::MID_LAYER_13 },
{ "MID14", ALTIUM_LAYER::MID_LAYER_14 },
{ "MID15", ALTIUM_LAYER::MID_LAYER_15 },
{ "MID16", ALTIUM_LAYER::MID_LAYER_16 },
{ "MID17", ALTIUM_LAYER::MID_LAYER_17 },
{ "MID18", ALTIUM_LAYER::MID_LAYER_18 },
{ "MID19", ALTIUM_LAYER::MID_LAYER_19 },
{ "MID20", ALTIUM_LAYER::MID_LAYER_20 },
{ "MID21", ALTIUM_LAYER::MID_LAYER_21 },
{ "MID22", ALTIUM_LAYER::MID_LAYER_22 },
{ "MID23", ALTIUM_LAYER::MID_LAYER_23 },
{ "MID24", ALTIUM_LAYER::MID_LAYER_24 },
{ "MID25", ALTIUM_LAYER::MID_LAYER_25 },
{ "MID26", ALTIUM_LAYER::MID_LAYER_26 },
{ "MID27", ALTIUM_LAYER::MID_LAYER_27 },
{ "MID28", ALTIUM_LAYER::MID_LAYER_28 },
{ "MID29", ALTIUM_LAYER::MID_LAYER_29 },
{ "MID30", ALTIUM_LAYER::MID_LAYER_30 },
{ "BOTTOM", ALTIUM_LAYER::BOTTOM_LAYER },
{ "PLANE1", ALTIUM_LAYER::INTERNAL_PLANE_1 },
{ "PLANE2", ALTIUM_LAYER::INTERNAL_PLANE_2 },
{ "PLANE3", ALTIUM_LAYER::INTERNAL_PLANE_3 },
{ "PLANE4", ALTIUM_LAYER::INTERNAL_PLANE_4 },
{ "PLANE5", ALTIUM_LAYER::INTERNAL_PLANE_5 },
{ "PLANE6", ALTIUM_LAYER::INTERNAL_PLANE_6 },
{ "PLANE7", ALTIUM_LAYER::INTERNAL_PLANE_7 },
{ "PLANE8", ALTIUM_LAYER::INTERNAL_PLANE_8 },
{ "PLANE9", ALTIUM_LAYER::INTERNAL_PLANE_9 },
{ "PLANE10", ALTIUM_LAYER::INTERNAL_PLANE_10 },
{ "PLANE11", ALTIUM_LAYER::INTERNAL_PLANE_11 },
{ "PLANE12", ALTIUM_LAYER::INTERNAL_PLANE_12 },
{ "PLANE13", ALTIUM_LAYER::INTERNAL_PLANE_13 },
{ "PLANE14", ALTIUM_LAYER::INTERNAL_PLANE_14 },
{ "PLANE15", ALTIUM_LAYER::INTERNAL_PLANE_15 },
{ "PLANE16", ALTIUM_LAYER::INTERNAL_PLANE_16 },
{ "MECHANICAL1", ALTIUM_LAYER::MECHANICAL_1 },
{ "MECHANICAL2", ALTIUM_LAYER::MECHANICAL_2 },
{ "MECHANICAL3", ALTIUM_LAYER::MECHANICAL_3 },
{ "MECHANICAL4", ALTIUM_LAYER::MECHANICAL_4 },
{ "MECHANICAL5", ALTIUM_LAYER::MECHANICAL_5 },
{ "MECHANICAL6", ALTIUM_LAYER::MECHANICAL_6 },
{ "MECHANICAL7", ALTIUM_LAYER::MECHANICAL_7 },
{ "MECHANICAL8", ALTIUM_LAYER::MECHANICAL_8 },
{ "MECHANICAL9", ALTIUM_LAYER::MECHANICAL_9 },
{ "MECHANICAL10", ALTIUM_LAYER::MECHANICAL_10 },
{ "MECHANICAL11", ALTIUM_LAYER::MECHANICAL_11 },
{ "MECHANICAL12", ALTIUM_LAYER::MECHANICAL_12 },
{ "MECHANICAL13", ALTIUM_LAYER::MECHANICAL_13 },
{ "MECHANICAL14", ALTIUM_LAYER::MECHANICAL_14 },
{ "MECHANICAL15", ALTIUM_LAYER::MECHANICAL_15 },
{ "MECHANICAL16", ALTIUM_LAYER::MECHANICAL_16 },
};
auto it = hash_map.find( std::string( aName.c_str() ) );
if( it == hash_map.end() )
{
wxLogError( wxString::Format(
_( "Unknown mapping of the Altium layer '%s'. Please report as issue." ), aName ) );
return ALTIUM_LAYER::UNKNOWN;
}
else
{
return it->second;
}
}
void altium_parse_polygons(
std::map<wxString, wxString>& aProperties, std::vector<ALTIUM_VERTICE>& aVertices )
{
for( size_t i = 0; i < std::numeric_limits<size_t>::max(); i++ )
{
const wxString si = std::to_string( i );
const wxString vxi = "VX" + si;
const wxString vyi = "VY" + si;
if( aProperties.find( vxi ) == aProperties.end()
|| aProperties.find( vyi ) == aProperties.end() )
{
break; // it doesn't seem like we know beforehand how many vertices are inside a polygon
}
const bool isRound = ALTIUM_PARSER::PropertiesReadInt( aProperties, "KIND" + si, 0 ) != 0;
const int32_t radius =
ALTIUM_PARSER::PropertiesReadKicadUnit( aProperties, "R" + si, "0mil" );
const double sa = ALTIUM_PARSER::PropertiesReadDouble( aProperties, "SA" + si, 0. );
const double ea = ALTIUM_PARSER::PropertiesReadDouble( aProperties, "EA" + si, 0. );
const wxPoint vp =
wxPoint( ALTIUM_PARSER::PropertiesReadKicadUnit( aProperties, vxi, "0mil" ),
-ALTIUM_PARSER::PropertiesReadKicadUnit( aProperties, vyi, "0mil" ) );
const wxPoint cp =
wxPoint( ALTIUM_PARSER::PropertiesReadKicadUnit( aProperties, "CX" + si, "0mil" ),
-ALTIUM_PARSER::PropertiesReadKicadUnit( aProperties, "CY" + si, "0mil" ) );
aVertices.emplace_back( isRound, radius, sa, ea, vp, cp );
}
}
ABOARD6::ABOARD6( ALTIUM_PARSER& aReader )
{
std::map<wxString, wxString> properties = aReader.ReadProperties();
if( properties.empty() )
{
THROW_IO_ERROR( _( "Board6 stream has no properties!" ) );
}
/*for (auto & property : properties) {
std::cout << " * '" << property.first << "' = '" << property.second << "'" << std::endl;
}*/
sheetpos = wxPoint( ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "SHEETX", "0mil" ),
-ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "SHEETY", "0mil" ) );
sheetsize = wxSize( ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "SHEETWIDTH", "0mil" ),
ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "SHEETHEIGHT", "0mil" ) );
layercount = ALTIUM_PARSER::PropertiesReadInt( properties, "LAYERSETSCOUNT", 1 ) + 1;
for( size_t i = 1; i < std::numeric_limits<size_t>::max(); i++ )
{
const wxString layeri = "LAYER" + std::to_string( i );
const wxString layername = layeri + "NAME";
auto layernameit = properties.find( layername );
if( layernameit == properties.end() )
{
break; // it doesn't seem like we know beforehand how many vertices are inside a polygon
}
ABOARD6_LAYER_STACKUP curlayer;
curlayer.name = ALTIUM_PARSER::PropertiesReadString(
properties, layername, "" ); // TODO: trim string
curlayer.nextId = ALTIUM_PARSER::PropertiesReadInt( properties, layeri + "NEXT", 0 );
curlayer.prevId = ALTIUM_PARSER::PropertiesReadInt( properties, layeri + "PREV", 0 );
curlayer.copperthick =
ALTIUM_PARSER::PropertiesReadKicadUnit( properties, layeri + "COPTHICK", "1.4mil" );
curlayer.dielectricconst =
ALTIUM_PARSER::PropertiesReadDouble( properties, layeri + "DIELCONST", 0. );
curlayer.dielectricthick = ALTIUM_PARSER::PropertiesReadKicadUnit(
properties, layeri + "DIELHEIGHT", "60mil" );
curlayer.dielectricmaterial =
ALTIUM_PARSER::PropertiesReadString( properties, layeri + "DIELMATERIAL", "FR-4" );
stackup.push_back( curlayer );
}
altium_parse_polygons( properties, board_vertices );
if( aReader.HasParsingError() )
{
THROW_IO_ERROR( _( "Board6 stream was not parsed correctly!" ) );
}
}
ACLASS6::ACLASS6( ALTIUM_PARSER& aReader )
{
std::map<wxString, wxString> properties = aReader.ReadProperties();
if( properties.empty() )
{
THROW_IO_ERROR( _( "Classes6 stream has no properties!" ) );
}
name = ALTIUM_PARSER::PropertiesReadString( properties, "NAME", "" );
uniqueid = ALTIUM_PARSER::PropertiesReadString( properties, "UNIQUEID", "" );
kind = static_cast<ALTIUM_CLASS_KIND>(
ALTIUM_PARSER::PropertiesReadInt( properties, "KIND", -1 ) );
for( size_t i = 0; i < std::numeric_limits<size_t>::max(); i++ )
{
auto mit = properties.find( "M" + std::to_string( i ) );
if( mit == properties.end() )
{
break; // it doesn't seem like we know beforehand how many components are in the netclass
}
names.push_back( mit->second );
}
if( aReader.HasParsingError() )
{
THROW_IO_ERROR( _( "Classes6 stream was not parsed correctly!" ) );
}
}
ACOMPONENT6::ACOMPONENT6( ALTIUM_PARSER& aReader )
{
std::map<wxString, wxString> properties = aReader.ReadProperties();
if( properties.empty() )
{
THROW_IO_ERROR( _( "Components6 stream has no properties!" ) );
}
layer = altium_layer_from_name(
ALTIUM_PARSER::PropertiesReadString( properties, "LAYER", "" ) );
position = wxPoint( ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "X", "0mil" ),
-ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "Y", "0mil" ) );
rotation = ALTIUM_PARSER::PropertiesReadDouble( properties, "ROTATION", 0. );
locked = ALTIUM_PARSER::PropertiesReadBool( properties, "LOCKED", false );
nameon = ALTIUM_PARSER::PropertiesReadBool( properties, "NAMEON", true );
commenton = ALTIUM_PARSER::PropertiesReadBool( properties, "COMMENTON", false );
sourcedesignator = ALTIUM_PARSER::PropertiesReadString( properties, "SOURCEDESIGNATOR", "" );
sourcefootprintlibrary =
ALTIUM_PARSER::PropertiesReadString( properties, "SOURCEFOOTPRINTLIBRARY", "" );
sourcecomponentlibrary =
ALTIUM_PARSER::PropertiesReadString( properties, "SOURCECOMPONENTLIBRARY", "" );
sourcelibreference =
ALTIUM_PARSER::PropertiesReadString( properties, "SOURCELIBREFERENCE", "" );
if( aReader.HasParsingError() )
{
THROW_IO_ERROR( _( "Components6 stream was not parsed correctly" ) );
}
}
ADIMENSION6::ADIMENSION6( ALTIUM_PARSER& aReader )
{
aReader.Skip( 2 );
std::map<wxString, wxString> properties = aReader.ReadProperties();
if( properties.empty() )
{
THROW_IO_ERROR( _( "Dimensions6 stream has no properties" ) );
}
layer = altium_layer_from_name(
ALTIUM_PARSER::PropertiesReadString( properties, "LAYER", "" ) );
kind = static_cast<ALTIUM_DIMENSION_KIND>(
ALTIUM_PARSER::PropertiesReadInt( properties, "DIMENSIONKIND", 0 ) );
textformat = ALTIUM_PARSER::PropertiesReadString( properties, "TEXTFORMAT", "" );
height = ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "HEIGHT", "0mil" );
angle = ALTIUM_PARSER::PropertiesReadDouble( properties, "ANGLE", 0. );
linewidth = ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "LINEWIDTH", "10mil" );
textheight = ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "TEXTHEIGHT", "10mil" );
textlinewidth = ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "TEXTLINEWIDTH", "6mil" );
textprecission = ALTIUM_PARSER::PropertiesReadInt( properties, "TEXTPRECISION", 2 );
textbold = ALTIUM_PARSER::PropertiesReadBool( properties, "TEXTLINEWIDTH", false );
textitalic = ALTIUM_PARSER::PropertiesReadBool( properties, "ITALIC", false );
arrowsize = ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "ARROWSIZE", "60mil" );
xy1 = wxPoint( ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "X1", "0mil" ),
-ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "Y1", "0mil" ) );
int refcount = ALTIUM_PARSER::PropertiesReadInt( properties, "REFERENCES_COUNT", 0 );
for( int i = 0; i < refcount; i++ )
{
const std::string refi = "REFERENCE" + std::to_string( i );
referencePoint.emplace_back(
ALTIUM_PARSER::PropertiesReadKicadUnit( properties, refi + "POINTX", "0mil" ),
-ALTIUM_PARSER::PropertiesReadKicadUnit( properties, refi + "POINTY", "0mil" ) );
}
for( size_t i = 1; i < std::numeric_limits<size_t>::max(); i++ )
{
const std::string texti = "TEXT" + std::to_string( i );
const std::string textix = texti + "X";
const std::string textiy = texti + "Y";
if( properties.find( textix ) == properties.end()
|| properties.find( textiy ) == properties.end() )
{
break; // it doesn't seem like we know beforehand how many vertices are inside a polygon
}
textPoint.emplace_back(
ALTIUM_PARSER::PropertiesReadKicadUnit( properties, textix, "0mil" ),
-ALTIUM_PARSER::PropertiesReadKicadUnit( properties, textiy, "0mil" ) );
}
wxString dimensionunit =
ALTIUM_PARSER::PropertiesReadString( properties, "TEXTDIMENSIONUNIT", "Millimeters" );
if( dimensionunit == "Inches" )
{
textunit = ALTIUM_UNIT::INCHES;
}
else if( dimensionunit == "Mils" )
{
textunit = ALTIUM_UNIT::MILS;
}
else if( dimensionunit == "Millimeters" )
{
textunit = ALTIUM_UNIT::MILLIMETERS;
}
else if( dimensionunit == "Centimeters" )
{
textunit = ALTIUM_UNIT::CENTIMETER;
}
else
{
textunit = ALTIUM_UNIT::UNKNOWN;
}
if( aReader.HasParsingError() )
{
THROW_IO_ERROR( _( "Dimensions6 stream was not parsed correctly" ) );
}
}
ANET6::ANET6( ALTIUM_PARSER& aReader )
{
std::map<wxString, wxString> properties = aReader.ReadProperties();
if( properties.empty() )
{
THROW_IO_ERROR( _( "Nets6 stream has no properties" ) );
}
name = ALTIUM_PARSER::PropertiesReadString( properties, "NAME", "" );
if( aReader.HasParsingError() )
{
THROW_IO_ERROR( _( "Nets6 stream was not parsed correctly" ) );
}
}
APOLYGON6::APOLYGON6( ALTIUM_PARSER& aReader )
{
std::map<wxString, wxString> properties = aReader.ReadProperties();
if( properties.empty() )
{
THROW_IO_ERROR( _( "Polygons6 stream has no properties" ) );
}
layer = altium_layer_from_name(
ALTIUM_PARSER::PropertiesReadString( properties, "LAYER", "" ) );
net = ALTIUM_PARSER::PropertiesReadInt( properties, "NET", ALTIUM_NET_UNCONNECTED );
locked = ALTIUM_PARSER::PropertiesReadBool( properties, "LOCKED", false );
// TODO: kind
gridsize = ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "GRIDSIZE", "0mil" );
trackwidth = ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "TRACKWIDTH", "0mil" );
minprimlength = ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "MINPRIMLENGTH", "0mil" );
useoctagons = ALTIUM_PARSER::PropertiesReadBool( properties, "USEOCTAGONS", false );
wxString hatchstyleraw = ALTIUM_PARSER::PropertiesReadString( properties, "HATCHSTYLE", "" );
if( hatchstyleraw == "Solid" )
{
hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::SOLID;
}
else if( hatchstyleraw == "45Degree" )
{
hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::DEGREE_45;
}
else if( hatchstyleraw == "90Degree" )
{
hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::DEGREE_90;
}
else if( hatchstyleraw == "Horizontal" )
{
hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::HORIZONTAL;
}
else if( hatchstyleraw == "Vertical" )
{
hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::VERTICAL;
}
else if( hatchstyleraw == "None" )
{
hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::NONE;
}
else
{
hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::UNKNOWN;
}
altium_parse_polygons( properties, vertices );
if( aReader.HasParsingError() )
{
THROW_IO_ERROR( _( "Polygons6 stream was not parsed correctly" ) );
}
}
ARULE6::ARULE6( ALTIUM_PARSER& aReader )
{
aReader.Skip( 2 );
std::map<wxString, wxString> properties = aReader.ReadProperties();
if( properties.empty() )
{
THROW_IO_ERROR( _( "Rules6 stream has no properties" ) );
}
name = ALTIUM_PARSER::PropertiesReadString( properties, "NAME", "" );
priority = ALTIUM_PARSER::PropertiesReadInt( properties, "PRIORITY", 1 );
scope1expr = ALTIUM_PARSER::PropertiesReadString( properties, "SCOPE1EXPRESSION", "" );
scope2expr = ALTIUM_PARSER::PropertiesReadString( properties, "SCOPE2EXPRESSION", "" );
wxString rulekind = ALTIUM_PARSER::PropertiesReadString( properties, "RULEKIND", "" );
if( rulekind == "Clearance" )
{
kind = ALTIUM_RULE_KIND::CLEARANCE;
clearanceGap = ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "GAP", "10mil" );
}
else if( rulekind == "DiffPairsRouting" )
{
kind = ALTIUM_RULE_KIND::DIFF_PAIR_ROUTINGS;
}
else if( rulekind == "Height" )
{
kind = ALTIUM_RULE_KIND::HEIGHT;
}
else if( rulekind == "HoleSize" )
{
kind = ALTIUM_RULE_KIND::HOLE_SIZE;
}
else if( rulekind == "HoleToHoleClearance" )
{
kind = ALTIUM_RULE_KIND::HOLE_TO_HOLE_CLEARANCE;
}
else if( rulekind == "Width" )
{
kind = ALTIUM_RULE_KIND::WIDTH;
}
else if( rulekind == "PasteMaskExpansion" )
{
kind = ALTIUM_RULE_KIND::PASTE_MASK_EXPANSION;
}
else if( rulekind == "PlaneClearance" )
{
kind = ALTIUM_RULE_KIND::PLANE_CLEARANCE;
planeclearanceClearance =
ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "CLEARANCE", "10mil" );
}
else if( rulekind == "PolygonConnect" )
{
kind = ALTIUM_RULE_KIND::POLYGON_CONNECT;
polygonconnectAirgapwidth =
ALTIUM_PARSER::PropertiesReadKicadUnit( properties, "AIRGAPWIDTH", "10mil" );
polygonconnectReliefconductorwidth = ALTIUM_PARSER::PropertiesReadKicadUnit(
properties, "RELIEFCONDUCTORWIDTH", "10mil" );
polygonconnectReliefentries =
ALTIUM_PARSER::PropertiesReadInt( properties, "RELIEFENTRIES", 4 );
}
else
{
kind = ALTIUM_RULE_KIND::UNKNOWN;
}
if( aReader.HasParsingError() )
{
THROW_IO_ERROR( _( "Rules6 stream was not parsed correctly" ) );
}
}
AARC6::AARC6( ALTIUM_PARSER& aReader )
{
ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
if( recordtype != ALTIUM_RECORD::ARC )
{
THROW_IO_ERROR( _( "Arcs6 stream has invalid recordtype" ) );
}
// Subrecord 1
aReader.ReadAndSetSubrecordLength();
layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
uint8_t flags1 = aReader.Read<uint8_t>();
is_locked = ( flags1 & 0x04 ) == 0;
is_polygonoutline = ( flags1 & 0x02 ) != 0;
uint8_t flags2 = aReader.Read<uint8_t>();
is_keepout = flags2 == 2;
net = aReader.Read<uint16_t>();
subpolyindex = aReader.Read<uint16_t>();
component = aReader.Read<uint16_t>();
aReader.Skip( 4 );
center = aReader.ReadWxPoint();
radius = aReader.ReadKicadUnit();
startangle = aReader.Read<double>();
endangle = aReader.Read<double>();
width = aReader.ReadKicadUnit();
aReader.SkipSubrecord();
if( aReader.HasParsingError() )
{
THROW_IO_ERROR( _( "Arcs6 stream was not parsed correctly" ) );
}
}
APAD6::APAD6( ALTIUM_PARSER& aReader )
{
ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
if( recordtype != ALTIUM_RECORD::PAD )
{
THROW_IO_ERROR( _( "Pads6 stream has invalid recordtype" ) );
}
// Subrecord 1
size_t subrecord1 = aReader.ReadAndSetSubrecordLength();
if( subrecord1 == 0 )
{
THROW_IO_ERROR( _( "Pads6 stream has no subrecord1 data" ) );
}
name = aReader.ReadWxString();
if( aReader.GetRemainingSubrecordBytes() != 0 )
{
THROW_IO_ERROR( _( "Pads6 stream has invalid subrecord1 length" ) );
}
aReader.SkipSubrecord();
// Subrecord 2
aReader.ReadAndSetSubrecordLength();
aReader.SkipSubrecord();
// Subrecord 3
aReader.ReadAndSetSubrecordLength();
aReader.SkipSubrecord();
// Subrecord 4
aReader.ReadAndSetSubrecordLength();
aReader.SkipSubrecord();
// Subrecord 5
size_t subrecord5 = aReader.ReadAndSetSubrecordLength();
if( subrecord5 < 120 )
{
THROW_IO_ERROR( _(
"Pads6 stream subrecord has length < 120, which is unexpected" ) ); // TODO: exact minimum length we know?
}
layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
uint8_t flags1 = aReader.Read<uint8_t>();
is_test_fab_top = ( flags1 & 0x80 ) != 0;
is_tent_bottom = ( flags1 & 0x40 ) != 0;
is_tent_top = ( flags1 & 0x20 ) != 0;
is_locked = ( flags1 & 0x04 ) == 0;
uint8_t flags2 = aReader.Read<uint8_t>();
is_test_fab_bottom = ( flags2 & 0x01 ) != 0;
net = aReader.Read<uint16_t>();
aReader.Skip( 2 );
component = aReader.Read<uint16_t>();
aReader.Skip( 4 );
position = aReader.ReadWxPoint();
topsize = aReader.ReadWxSize();
midsize = aReader.ReadWxSize();
botsize = aReader.ReadWxSize();
holesize = aReader.ReadKicadUnit();
topshape = static_cast<ALTIUM_PAD_SHAPE>( aReader.Read<uint8_t>() );
midshape = static_cast<ALTIUM_PAD_SHAPE>( aReader.Read<uint8_t>() );
botshape = static_cast<ALTIUM_PAD_SHAPE>( aReader.Read<uint8_t>() );
direction = aReader.Read<double>();
plated = aReader.Read<uint8_t>() != 0;
aReader.Skip( 1 );
padmode = static_cast<ALTIUM_PAD_MODE>( aReader.Read<uint8_t>() );
aReader.Skip( 23 );
pastemaskexpansionmanual = aReader.ReadKicadUnit();
soldermaskexpansionmanual = aReader.ReadKicadUnit();
aReader.Skip( 7 );
pastemaskexpansionmode = static_cast<ALTIUM_PAD_RULE>( aReader.Read<uint8_t>() );
soldermaskexpansionmode = static_cast<ALTIUM_PAD_RULE>( aReader.Read<uint8_t>() );
aReader.Skip( 3 );
holerotation = aReader.Read<double>();
if( subrecord5 == 120 )
{
tolayer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
aReader.Skip( 2 );
fromlayer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
//aReader.skip( 2 );
}
else if( subrecord5 == 171 )
{
}
aReader.SkipSubrecord();
// Subrecord 6
size_t subrecord6 = aReader.ReadAndSetSubrecordLength();
if( subrecord6 == 651
|| subrecord6 == 628 ) // TODO: better detection mechanism (Altium 14 = 628)
{ // TODO: detect type from something else than the size?
sizeAndShape = std::make_unique<APAD6_SIZE_AND_SHAPE>();
for( int i = 0; i < 29; i++ )
{
sizeAndShape->inner_size[i].x = aReader.ReadKicadUnitX();
}
for( int i = 0; i < 29; i++ )
{
sizeAndShape->inner_size[i].y = aReader.ReadKicadUnitY();
}
for( int i = 0; i < 29; i++ )
{
sizeAndShape->inner_shape[i] = static_cast<ALTIUM_PAD_SHAPE>( aReader.Read<uint8_t>() );
}
aReader.Skip( 1 );
sizeAndShape->holeshape = static_cast<ALTIUM_PAD_HOLE_SHAPE>( aReader.Read<uint8_t>() );
sizeAndShape->slotsize = aReader.ReadKicadUnit();
sizeAndShape->slotrotation = aReader.Read<double>();
for( int i = 0; i < 32; i++ )
{
sizeAndShape->holeoffset[i].x = aReader.ReadKicadUnitX();
}
for( int i = 0; i < 32; i++ )
{
sizeAndShape->holeoffset[i].y = aReader.ReadKicadUnitY();
}
aReader.Skip( 1 );
for( int i = 0; i < 32; i++ )
{
sizeAndShape->alt_shape[i] =
static_cast<ALTIUM_PAD_SHAPE_ALT>( aReader.Read<uint8_t>() );
}
for( int i = 0; i < 32; i++ )
{
sizeAndShape->cornerradius[i] = aReader.Read<uint8_t>();
}
}
aReader.SkipSubrecord();
if( aReader.HasParsingError() )
{
THROW_IO_ERROR( _( "Pads6 stream was not parsed correctly" ) );
}
}
AVIA6::AVIA6( ALTIUM_PARSER& aReader )
{
ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
if( recordtype != ALTIUM_RECORD::VIA )
{
THROW_IO_ERROR( _( "Vias6 stream has invalid recordtype" ) );
}
// Subrecord 1
aReader.ReadAndSetSubrecordLength();
aReader.Skip( 1 );
uint8_t flags1 = aReader.Read<uint8_t>();
is_test_fab_top = ( flags1 & 0x80 ) != 0;
is_tent_bottom = ( flags1 & 0x40 ) != 0;
is_tent_top = ( flags1 & 0x20 ) != 0;
is_locked = ( flags1 & 0x04 ) == 0;
uint8_t flags2 = aReader.Read<uint8_t>();
is_test_fab_bottom = ( flags2 & 0x01 ) != 0;
net = aReader.Read<uint16_t>();
aReader.Skip( 8 );
position = aReader.ReadWxPoint();
diameter = aReader.ReadKicadUnit();
holesize = aReader.ReadKicadUnit();
layer_start = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
layer_end = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
aReader.Skip( 43 );
viamode = static_cast<ALTIUM_PAD_MODE>( aReader.Read<uint8_t>() );
aReader.SkipSubrecord();
if( aReader.HasParsingError() )
{
THROW_IO_ERROR( _( "Vias6 stream was not parsed correctly" ) );
}
}
ATRACK6::ATRACK6( ALTIUM_PARSER& aReader )
{
ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
if( recordtype != ALTIUM_RECORD::TRACK )
{
THROW_IO_ERROR( _( "Tracks6 stream has invalid recordtype" ) );
}
// Subrecord 1
aReader.ReadAndSetSubrecordLength();
layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
uint8_t flags1 = aReader.Read<uint8_t>();
is_locked = ( flags1 & 0x04 ) == 0;
is_polygonoutline = ( flags1 & 0x02 ) != 0;
uint8_t flags2 = aReader.Read<uint8_t>();
is_keepout = flags2 == 2;
net = aReader.Read<uint16_t>();
subpolyindex = aReader.Read<uint16_t>();
component = aReader.Read<uint16_t>();
aReader.Skip( 4 );
start = aReader.ReadWxPoint();
end = aReader.ReadWxPoint();
width = aReader.ReadKicadUnit();
aReader.SkipSubrecord();
if( aReader.HasParsingError() )
{
THROW_IO_ERROR( _( "Tracks6 stream was not parsed correctly" ) );
}
}
ATEXT6::ATEXT6( ALTIUM_PARSER& aReader )
{
ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
if( recordtype != ALTIUM_RECORD::TEXT )
{
THROW_IO_ERROR( _( "Texts6 stream has invalid recordtype" ) );
}
// Subrecord 1 - Properties
size_t subrecord1 = aReader.ReadAndSetSubrecordLength();
layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
aReader.Skip( 6 );
component = aReader.Read<uint16_t>();
aReader.Skip( 4 );
position = aReader.ReadWxPoint();
height = aReader.ReadKicadUnit();
aReader.Skip( 2 );
rotation = aReader.Read<double>();
mirrored = aReader.Read<uint8_t>() != 0;
strokewidth = aReader.ReadKicadUnit();
isComment = aReader.Read<uint8_t>() != 0;
isDesignator = aReader.Read<uint8_t>() != 0;
aReader.Skip( 90 );
textposition = static_cast<ALTIUM_TEXT_POSITION>( aReader.Read<uint8_t>() );
/**
* In Altium 14 (subrecord1 == 230) only left bottom is valid? I think there is a bit missing.
* https://gitlab.com/kicad/code/kicad/merge_requests/60#note_274913397
*/
if( subrecord1 <= 230 )
{
textposition = ALTIUM_TEXT_POSITION::LEFT_BOTTOM;
}
aReader.Skip( 27 );
isTruetype = aReader.Read<uint8_t>() != 0;
aReader.SkipSubrecord();
// Subrecord 2 - String
aReader.ReadAndSetSubrecordLength();
text = aReader.ReadWxString(); // TODO: what about strings with length > 255?
aReader.SkipSubrecord();
if( aReader.HasParsingError() )
{
THROW_IO_ERROR( _( "Texts6 stream was not parsed correctly" ) );
}
}
AFILL6::AFILL6( ALTIUM_PARSER& aReader )
{
ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
if( recordtype != ALTIUM_RECORD::FILL )
{
THROW_IO_ERROR( _( "Fills6 stream has invalid recordtype" ) );
}
// Subrecord 1
aReader.ReadAndSetSubrecordLength();
layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
uint8_t flags1 = aReader.Read<uint8_t>();
is_locked = ( flags1 & 0x04 ) == 0;
uint8_t flags2 = aReader.Read<uint8_t>();
is_keepout = flags2 == 2;
net = aReader.Read<uint16_t>();
aReader.Skip( 2 );
component = aReader.Read<uint16_t>();
aReader.Skip( 4 );
pos1 = aReader.ReadWxPoint();
pos2 = aReader.ReadWxPoint();
rotation = aReader.Read<double>();
aReader.SkipSubrecord();
if( aReader.HasParsingError() )
{
THROW_IO_ERROR( _( "Fills6 stream was not parsed correctly" ) );
}
}
AREGION6::AREGION6( ALTIUM_PARSER& aReader, bool aExtendedVertices )
{
ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
if( recordtype != ALTIUM_RECORD::REGION )
{
THROW_IO_ERROR( _( "Regions6 stream has invalid recordtype" ) );
}
// Subrecord 1
aReader.ReadAndSetSubrecordLength();
layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
uint8_t flags1 = aReader.Read<uint8_t>();
is_locked = ( flags1 & 0x04 ) == 0;
uint8_t flags2 = aReader.Read<uint8_t>();
is_keepout = flags2 == 2;
net = aReader.Read<uint16_t>();
aReader.Skip( 2 );
component = aReader.Read<uint16_t>();
aReader.Skip( 9 );
std::map<wxString, wxString> properties = aReader.ReadProperties();
if( properties.empty() )
{
THROW_IO_ERROR( _( "Regions6 stream has empty properties" ) );
}
int pkind = ALTIUM_PARSER::PropertiesReadInt( properties, "KIND", 0 );
bool is_cutout = ALTIUM_PARSER::PropertiesReadBool( properties, "ISBOARDCUTOUT", false );
is_shapebased = ALTIUM_PARSER::PropertiesReadBool( properties, "ISSHAPEBASED", false );
subpolyindex = static_cast<uint16_t>(
ALTIUM_PARSER::PropertiesReadInt( properties, "SUBPOLYINDEX", ALTIUM_POLYGON_NONE ) );
switch( pkind )
{
case 0:
if( is_cutout )
{
kind = ALTIUM_REGION_KIND::BOARD_CUTOUT;
}
else
{
kind = ALTIUM_REGION_KIND::COPPER;
}
break;
case 1:
kind = ALTIUM_REGION_KIND::POLYGON_CUTOUT;
break;
case 4:
kind = ALTIUM_REGION_KIND::CAVITY_DEFINITION;
break;
default:
kind = ALTIUM_REGION_KIND::UNKNOWN;
break;
}
uint32_t num_vertices = aReader.Read<uint32_t>();
for( uint32_t i = 0; i < num_vertices; i++ )
{
if( aExtendedVertices )
{
bool isRound = aReader.Read<uint8_t>() != 0;
wxPoint position = aReader.ReadWxPoint();
wxPoint center = aReader.ReadWxPoint();
int32_t radius = aReader.ReadKicadUnit();
double angle1 = aReader.Read<double>();
double angle2 = aReader.Read<double>();
vertices.emplace_back( isRound, radius, angle1, angle2, position, center );
}
else
{
// For some regions the coordinates are stored as double and not as int32_t
int32_t x = ALTIUM_PARSER::ConvertToKicadUnit( aReader.Read<double>() );
int32_t y = ALTIUM_PARSER::ConvertToKicadUnit( -aReader.Read<double>() );
vertices.emplace_back( wxPoint( x, y ) );
}
}
aReader.SkipSubrecord();
if( aReader.HasParsingError() )
{
THROW_IO_ERROR( _( "Regions6 stream was not parsed correctly" ) );
}
}

View File

@ -0,0 +1,616 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 Thomas Pointhuber <thomas.pointhuber@gmx.at>
*
* 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 ALTIUM_PARSER_PCB_H
#define ALTIUM_PARSER_PCB_H
#include <cstdint>
#include <cstring>
#include <memory>
#include <vector>
#include <wx/gdicmn.h>
// tthis constant specifies an unconnected net
const uint16_t ALTIUM_NET_UNCONNECTED = std::numeric_limits<uint16_t>::max();
// this constant specifies a item which is not inside an component
const uint16_t ALTIUM_COMPONENT_NONE = std::numeric_limits<uint16_t>::max();
// this constant specifies a item which does not define a polygon
const uint16_t ALTIUM_POLYGON_NONE = std::numeric_limits<uint16_t>::max();
enum class ALTIUM_UNIT
{
UNKNOWN = 0,
INCHES = 1,
MILS = 2,
MILLIMETERS = 3,
CENTIMETER = 4
};
enum class ALTIUM_CLASS_KIND
{
UNKNOWN = -1,
NET_CLASS = 0,
SOURCE_SCHEMATIC_CLASS = 1,
FROM_TO = 2,
PAD_CLASS = 3,
LAYER_CLASS = 4,
UNKNOWN_CLASS = 5,
DIFF_PAIR_CLASS = 6,
POLYGON_CLASS = 7
};
enum class ALTIUM_DIMENSION_KIND
{
UNKNOWN = 0,
LINEAR = 1,
ANGULAR = 2,
RADIAL = 3,
LEADER = 4,
DATUM = 5,
BASELINE = 6,
CENTER = 7,
LINEAR_DIAMETER = 8,
RADIAL_DIAMETER = 9
};
enum class ALTIUM_REGION_KIND
{
UNKNOWN = -1,
COPPER = 0, // KIND=0
POLYGON_CUTOUT = 1, // KIND=1
BOARD_CUTOUT = 2, // KIND=0 AND ISBOARDCUTOUT=TRUE
CAVITY_DEFINITION = 3, // KIND=4
};
enum class ALTIUM_RULE_KIND
{
UNKNOWN = 0,
CLEARANCE = 1,
DIFF_PAIR_ROUTINGS = 2,
HEIGHT = 3,
HOLE_SIZE = 4,
HOLE_TO_HOLE_CLEARANCE = 5,
WIDTH = 6,
PASTE_MASK_EXPANSION = 7,
PLANE_CLEARANCE = 8,
POLYGON_CONNECT = 9,
};
enum class ALTIUM_RECORD
{
ARC = 1,
PAD = 2,
VIA = 3,
TRACK = 4,
TEXT = 5,
FILL = 6,
REGION = 11,
MODEL = 12
};
enum class ALTIUM_PAD_SHAPE
{
UNKNOWN = 0,
CIRCLE = 1,
RECT = 2,
OCTAGONAL = 3
};
enum class ALTIUM_PAD_SHAPE_ALT
{
UNKNOWN = 0,
CIRCLE = 1,
RECT = 2, // TODO: valid?
OCTAGONAL = 3, // TODO: valid?
ROUNDRECT = 9
};
enum class ALTIUM_PAD_HOLE_SHAPE
{
UNKNOWN = -1,
ROUND = 0,
SQUARE = 1,
SLOT = 2
};
enum class ALTIUM_PAD_MODE
{
SIMPLE = 0,
TOP_MIDDLE_BOTTOM = 1,
FULL_STACK = 2
};
enum class ALTIUM_PAD_RULE
{
UNKNOWN = 0,
RULE = 1,
MANUAL = 2
};
enum class ALTIUM_POLYGON_HATCHSTYLE
{
UNKNOWN = 0,
SOLID = 1,
DEGREE_45 = 2,
DEGREE_90 = 3,
HORIZONTAL = 4,
VERTICAL = 5,
NONE = 6
};
enum class ALTIUM_TEXT_POSITION
{
LEFT_TOP = 1,
LEFT_CENTER = 2,
LEFT_BOTTOM = 3,
CENTER_TOP = 4,
CENTER_CENTER = 5,
CENTER_BOTTOM = 6,
RIGHT_TOP = 7,
RIGHT_CENTER = 8,
RIGHT_BOTTOM = 9
};
struct ALTIUM_VERTICE
{
const bool isRound;
const int32_t radius;
const double startangle;
const double endangle;
const wxPoint position;
const wxPoint center;
explicit ALTIUM_VERTICE( const wxPoint aPosition )
: isRound( false ),
radius( 0 ),
startangle( 0. ),
endangle( 0. ),
position( aPosition ),
center( wxPoint( 0, 0 ) )
{
}
explicit ALTIUM_VERTICE( bool aIsRound, int32_t aRadius, double aStartAngle, double aEndAngle,
const wxPoint aPosition, const wxPoint aCenter )
: isRound( aIsRound ),
radius( aRadius ),
startangle( aStartAngle ),
endangle( aEndAngle ),
position( aPosition ),
center( aCenter )
{
}
};
enum class ALTIUM_LAYER
{
UNKNOWN = 0,
TOP_LAYER = 1,
MID_LAYER_1 = 2,
MID_LAYER_2 = 3,
MID_LAYER_3 = 4,
MID_LAYER_4 = 5,
MID_LAYER_5 = 6,
MID_LAYER_6 = 7,
MID_LAYER_7 = 8,
MID_LAYER_8 = 9,
MID_LAYER_9 = 10,
MID_LAYER_10 = 11,
MID_LAYER_11 = 12,
MID_LAYER_12 = 13,
MID_LAYER_13 = 14,
MID_LAYER_14 = 15,
MID_LAYER_15 = 16,
MID_LAYER_16 = 17,
MID_LAYER_17 = 18,
MID_LAYER_18 = 19,
MID_LAYER_19 = 20,
MID_LAYER_20 = 21,
MID_LAYER_21 = 22,
MID_LAYER_22 = 23,
MID_LAYER_23 = 24,
MID_LAYER_24 = 25,
MID_LAYER_25 = 26,
MID_LAYER_26 = 27,
MID_LAYER_27 = 28,
MID_LAYER_28 = 29,
MID_LAYER_29 = 30,
MID_LAYER_30 = 31,
BOTTOM_LAYER = 32,
TOP_OVERLAY = 33,
BOTTOM_OVERLAY = 34,
TOP_PASTE = 35,
BOTTOM_PASTE = 36,
TOP_SOLDER = 37,
BOTTOM_SOLDER = 38,
INTERNAL_PLANE_1 = 39,
INTERNAL_PLANE_2 = 40,
INTERNAL_PLANE_3 = 41,
INTERNAL_PLANE_4 = 42,
INTERNAL_PLANE_5 = 43,
INTERNAL_PLANE_6 = 44,
INTERNAL_PLANE_7 = 45,
INTERNAL_PLANE_8 = 46,
INTERNAL_PLANE_9 = 47,
INTERNAL_PLANE_10 = 48,
INTERNAL_PLANE_11 = 49,
INTERNAL_PLANE_12 = 50,
INTERNAL_PLANE_13 = 51,
INTERNAL_PLANE_14 = 52,
INTERNAL_PLANE_15 = 53,
INTERNAL_PLANE_16 = 54,
DRILL_GUIDE = 55,
KEEP_OUT_LAYER = 56,
MECHANICAL_1 = 57,
MECHANICAL_2 = 58,
MECHANICAL_3 = 59,
MECHANICAL_4 = 60,
MECHANICAL_5 = 61,
MECHANICAL_6 = 62,
MECHANICAL_7 = 63,
MECHANICAL_8 = 64,
MECHANICAL_9 = 65,
MECHANICAL_10 = 66,
MECHANICAL_11 = 67,
MECHANICAL_12 = 68,
MECHANICAL_13 = 69,
MECHANICAL_14 = 70,
MECHANICAL_15 = 71,
MECHANICAL_16 = 72,
DRILL_DRAWING = 73,
MULTI_LAYER = 74,
CONNECTIONS = 75,
BACKGROUND = 76,
DRC_ERROR_MARKERS = 77,
SELECTIONS = 78,
VISIBLE_GRID_1 = 79,
VISIBLE_GRID_2 = 80,
PAD_HOLES = 81,
VIA_HOLES = 82,
};
class ALTIUM_PARSER;
struct ABOARD6_LAYER_STACKUP
{
wxString name;
size_t nextId;
size_t prevId;
int32_t copperthick;
double dielectricconst;
int32_t dielectricthick;
wxString dielectricmaterial;
};
struct ABOARD6
{
wxPoint sheetpos;
wxSize sheetsize;
int layercount;
std::vector<ABOARD6_LAYER_STACKUP> stackup;
std::vector<ALTIUM_VERTICE> board_vertices;
explicit ABOARD6( ALTIUM_PARSER& aReader );
};
struct ACLASS6
{
wxString name;
wxString uniqueid;
ALTIUM_CLASS_KIND kind;
std::vector<wxString> names;
explicit ACLASS6( ALTIUM_PARSER& aReader );
};
struct ACOMPONENT6
{
ALTIUM_LAYER layer;
wxPoint position;
double rotation;
bool locked;
bool nameon;
bool commenton;
wxString sourcedesignator;
wxString sourcefootprintlibrary;
wxString sourcecomponentlibrary;
wxString sourcelibreference;
explicit ACOMPONENT6( ALTIUM_PARSER& aReader );
};
struct ADIMENSION6
{
ALTIUM_LAYER layer;
ALTIUM_DIMENSION_KIND kind;
wxString textformat;
int32_t height;
double angle;
uint32_t linewidth;
uint32_t textheight;
uint32_t textlinewidth;
int32_t textprecission;
bool textbold;
bool textitalic;
int32_t arrowsize;
ALTIUM_UNIT textunit;
wxPoint xy1;
std::vector<wxPoint> referencePoint;
std::vector<wxPoint> textPoint;
explicit ADIMENSION6( ALTIUM_PARSER& aReader );
};
struct ANET6
{
wxString name;
explicit ANET6( ALTIUM_PARSER& aReader );
};
struct APOLYGON6
{
ALTIUM_LAYER layer;
uint16_t net;
bool locked;
ALTIUM_POLYGON_HATCHSTYLE hatchstyle;
int32_t gridsize;
int32_t trackwidth;
int32_t minprimlength;
bool useoctagons;
std::vector<ALTIUM_VERTICE> vertices;
explicit APOLYGON6( ALTIUM_PARSER& aReader );
};
struct ARULE6
{
wxString name;
int priority;
ALTIUM_RULE_KIND kind;
wxString scope1expr;
wxString scope2expr;
// ALTIUM_RULE_KIND::CLEARANCE
int clearanceGap;
// ALTIUM_RULE_KIND::PLANE_CLEARANCE
int planeclearanceClearance;
// ALTIUM_RULE_KIND::POLYGON_CONNECT
int32_t polygonconnectAirgapwidth;
int32_t polygonconnectReliefconductorwidth;
int polygonconnectReliefentries;
// TODO: implement different types of rules we need to parse
explicit ARULE6( ALTIUM_PARSER& aReader );
};
struct AREGION6
{
bool is_locked;
bool is_keepout;
bool is_shapebased;
ALTIUM_LAYER layer;
uint16_t net;
uint16_t component;
uint16_t subpolyindex;
ALTIUM_REGION_KIND kind; // I asume this means if normal or keepout?
std::vector<ALTIUM_VERTICE> vertices;
explicit AREGION6( ALTIUM_PARSER& aReader, bool aExtendedVertices );
};
struct AARC6
{
bool is_locked;
bool is_keepout;
bool is_polygonoutline;
ALTIUM_LAYER layer;
uint16_t net;
uint16_t component;
uint16_t subpolyindex;
wxPoint center;
uint32_t radius;
double startangle;
double endangle;
uint32_t width;
explicit AARC6( ALTIUM_PARSER& aReader );
};
struct APAD6_SIZE_AND_SHAPE
{
ALTIUM_PAD_HOLE_SHAPE holeshape;
uint32_t slotsize;
double slotrotation;
wxSize inner_size[29];
ALTIUM_PAD_SHAPE inner_shape[29];
wxPoint holeoffset[32];
ALTIUM_PAD_SHAPE_ALT alt_shape[32];
uint8_t cornerradius[32];
};
struct APAD6
{
bool is_locked;
bool is_tent_top;
bool is_tent_bottom;
bool is_test_fab_top;
bool is_test_fab_bottom;
wxString name;
ALTIUM_LAYER layer;
uint16_t net;
uint16_t component;
wxPoint position;
wxSize topsize;
wxSize midsize;
wxSize botsize;
uint32_t holesize;
ALTIUM_PAD_SHAPE topshape;
ALTIUM_PAD_SHAPE midshape;
ALTIUM_PAD_SHAPE botshape;
ALTIUM_PAD_MODE padmode;
double direction;
bool plated;
ALTIUM_PAD_RULE pastemaskexpansionmode;
int32_t pastemaskexpansionmanual;
ALTIUM_PAD_RULE soldermaskexpansionmode;
int32_t soldermaskexpansionmanual;
double holerotation;
ALTIUM_LAYER tolayer;
ALTIUM_LAYER fromlayer;
std::unique_ptr<APAD6_SIZE_AND_SHAPE> sizeAndShape;
explicit APAD6( ALTIUM_PARSER& aReader );
};
struct AVIA6
{
bool is_locked;
bool is_tent_top;
bool is_tent_bottom;
bool is_test_fab_top;
bool is_test_fab_bottom;
uint16_t net;
wxPoint position;
uint32_t diameter;
uint32_t holesize;
ALTIUM_LAYER layer_start;
ALTIUM_LAYER layer_end;
ALTIUM_PAD_MODE viamode;
explicit AVIA6( ALTIUM_PARSER& aReader );
};
struct ATRACK6
{
bool is_locked;
bool is_keepout;
bool is_polygonoutline;
ALTIUM_LAYER layer;
uint16_t net;
uint16_t component;
uint16_t subpolyindex;
wxPoint start;
wxPoint end;
uint32_t width;
explicit ATRACK6( ALTIUM_PARSER& aReader );
};
struct ATEXT6
{
ALTIUM_LAYER layer;
uint16_t component;
wxPoint position;
uint32_t height;
double rotation;
uint32_t strokewidth;
ALTIUM_TEXT_POSITION textposition;
bool mirrored;
bool isComment;
bool isDesignator;
bool isTruetype;
wxString text;
explicit ATEXT6( ALTIUM_PARSER& aReader );
};
struct AFILL6
{
bool is_locked;
bool is_keepout;
ALTIUM_LAYER layer;
uint16_t component;
uint16_t net;
wxPoint pos1;
wxPoint pos2;
double rotation;
explicit AFILL6( ALTIUM_PARSER& aReader );
};
#endif //ALTIUM_PARSER_PCB_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,187 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019-2020 Thomas Pointhuber <thomas.pointhuber@gmx.at>
*
* 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 ALTIUM_PCB_H
#define ALTIUM_PCB_H
#include <functional>
#include <layers_id_colors_and_visibility.h>
#include <vector>
#include <zconf.h>
#include <altium_parser_pcb.h>
enum class ALTIUM_PCB_DIR
{
FILE_HEADER,
ADVANCEDPLACEROPTIONS6,
ARCS6,
BOARD6,
BOARDREGIONS,
CLASSES6,
COMPONENTBODIES6,
COMPONENTS6,
CONNECTIONS6,
COORDINATES6,
DESIGNRULECHECKEROPTIONS6,
DIFFERENTIALPAIRS6,
DIMENSIONS6,
EMBEDDEDBOARDS6,
EMBEDDEDFONTS6,
EMBEDDEDS6,
EXTENDPRIMITIVEINFORMATION,
FILEVERSIONINFO,
FILLS6,
FROMTOS6,
MODELS,
MODELSNOEMBED,
NETS6,
PADS6,
PADVIALIBRARY,
PADVIALIBRARYCACHE,
PADVIALIBRARYLINKS,
PINSWAPOPTIONS6,
PINPAIRSSECTION,
POLYGONS6,
REGIONS6,
RULES6,
SHAPEBASEDCOMPONENTBODIES6,
SHAPEBASEDREGIONS6,
SIGNALCLASSES,
SMARTUNIONS,
TEXTS,
TEXTS6,
TEXTURES,
TRACKS6,
UNIONNAMES,
UNIQUEIDPRIMITIVEINFORMATION,
VIAS6,
WIDESTRINGS6
};
class BOARD;
class MODULE;
class ZONE_CONTAINER;
/**
* Helper method which opens a Altium Board File and parses it.
*
* @param aBoard board the pcb should be appended to
* @param aFileName file name of board file
* @param aFileMapping mapping how altium stream names are mapped
*/
void ParseAltiumPcb( BOARD* aBoard, const wxString& aFileName,
const std::map<ALTIUM_PCB_DIR, std::string>& aFileMapping );
namespace CFB
{
class CompoundFileReader;
struct COMPOUND_FILE_ENTRY;
} // namespace CFB
// type declaration required for a helper method
class ALTIUM_PCB;
typedef std::function<void( const CFB::CompoundFileReader&, const CFB::COMPOUND_FILE_ENTRY* )>
PARSE_FUNCTION_POINTER_fp;
class ALTIUM_PCB
{
public:
explicit ALTIUM_PCB( BOARD* aBoard );
~ALTIUM_PCB();
void Parse( const CFB::CompoundFileReader& aReader,
const std::map<ALTIUM_PCB_DIR, std::string>& aFileMapping );
private:
PCB_LAYER_ID GetKicadLayer( ALTIUM_LAYER aAltiumLayer ) const;
int GetNetCode( uint16_t aId ) const;
const ARULE6* GetRule( ALTIUM_RULE_KIND aKind, const wxString& aName ) const;
const ARULE6* GetRuleDefault( ALTIUM_RULE_KIND aKind ) const;
void ParseFileHeader(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
// Text Format
void ParseBoard6Data(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ParseClasses6Data(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ParseComponents6Data(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ParseDimensions6Data(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ParseNets6Data(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ParsePolygons6Data(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ParseRules6Data(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
// Binary Format
void ParseArcs6Data(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ParsePads6Data(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ParseVias6Data(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ParseTracks6Data(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ParseTexts6Data(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ParseFills6Data(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ParseBoardRegionsData(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ParseShapeBasedRegions6Data(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ParseRegions6Data(
const CFB::CompoundFileReader& aReader, const CFB::COMPOUND_FILE_ENTRY* aEntry );
// Helper Functions
void HelperParseDimensions6Linear( const ADIMENSION6& aElem );
void HelperParseDimensions6Leader( const ADIMENSION6& aElem );
void HelperParseDimensions6Datum( const ADIMENSION6& aElem );
void HelperParseDimensions6Center( const ADIMENSION6& aElem );
void HelperCreateBoardOutline( const std::vector<ALTIUM_VERTICE>& aVertices );
BOARD* m_board;
std::vector<MODULE*> m_components;
std::vector<ZONE_CONTAINER*> m_polygons;
size_t m_num_nets;
std::map<ALTIUM_LAYER, PCB_LAYER_ID> m_layermap; // used to correctly map copper layers
std::map<ALTIUM_RULE_KIND, std::vector<ARULE6>> m_rules;
std::map<ALTIUM_LAYER, ZONE_CONTAINER*> m_outer_plane;
};
#endif //ALTIUM_PCB_H

View File

@ -34,6 +34,7 @@
class D_PAD;
class TEXTE_MODULE;
class ZONE_CONTAINER;
typedef std::map<wxString, MODULE*> MODULE_MAP;
typedef std::vector<ZONE_CONTAINER*> ZONES;

View File

@ -76,17 +76,23 @@ bool AskLoadBoardFileName( wxWindow* aParent, int* aCtl, wxString* aFileName, bo
// load a BOARD. User may occasionally use the wrong plugin to load a
// *.brd file (since both legacy and eagle use *.brd extension),
// but eventually *.kicad_pcb will be more common than legacy *.brd files.
// clang-format off
static const struct
{
const wxString& filter;
IO_MGR::PCB_FILE_T pluginType;
} loaders[] =
{
{ PcbFileWildcard(), IO_MGR::KICAD_SEXP }, // Current Kicad board files
{ LegacyPcbFileWildcard(), IO_MGR::LEGACY }, // Old Kicad board files
{ EaglePcbFileWildcard(), IO_MGR::EAGLE }, // Import board files
{ PCadPcbFileWildcard(), IO_MGR::PCAD }, // Import board files
{ PcbFileWildcard(), IO_MGR::KICAD_SEXP }, // Current Kicad board files
{ LegacyPcbFileWildcard(), IO_MGR::LEGACY }, // Old Kicad board files
{ EaglePcbFileWildcard(), IO_MGR::EAGLE }, // Import Eagle board files
{ PCadPcbFileWildcard(), IO_MGR::PCAD }, // Import PCAD board files
{ AltiumDesignerPcbFileWildcard(), IO_MGR::ALTIUM_DESIGNER }, // Import Altium Designer board files
{ AltiumCircuitStudioPcbFileWildcard(), IO_MGR::ALTIUM_CIRCUIT_STUDIO }, // Import Altium Circuit Studio board files
{ AltiumCircuitMakerPcbFileWildcard(), IO_MGR::ALTIUM_CIRCUIT_MAKER }, // Import Altium Circuit Maker board files
};
// clang-format on
wxFileName fileName( *aFileName );
wxString fileFilters;
@ -357,7 +363,7 @@ IO_MGR::PCB_FILE_T plugin_type( const wxString& aFileName, int aCtl )
wxFileName fn = aFileName;
// Note: file extensions are expected to be in ower case.
// Note: file extensions are expected to be in lower case.
// This is not always true, especially when importing files, so the string
// comparisons are case insensitive to try to find the suitable plugin.
@ -366,10 +372,22 @@ IO_MGR::PCB_FILE_T plugin_type( const wxString& aFileName, int aCtl )
// both legacy and eagle share a common file extension.
pluginType = ( aCtl & KICTL_EAGLE_BRD ) ? IO_MGR::EAGLE : IO_MGR::LEGACY;
}
else if( fn.GetExt().CmpNoCase( IO_MGR::GetFileExtension( IO_MGR::PCAD ) ) == 0 )
else if( fn.GetExt().CmpNoCase( IO_MGR::GetFileExtension( IO_MGR::PCAD ) ) == 0 )
{
pluginType = IO_MGR::PCAD;
}
else if( fn.GetExt().CmpNoCase( IO_MGR::GetFileExtension( IO_MGR::ALTIUM_DESIGNER ) ) == 0 )
{
pluginType = IO_MGR::ALTIUM_DESIGNER;
}
else if( fn.GetExt().CmpNoCase( IO_MGR::GetFileExtension( IO_MGR::ALTIUM_CIRCUIT_STUDIO ) ) == 0 )
{
pluginType = IO_MGR::ALTIUM_CIRCUIT_STUDIO;
}
else if( fn.GetExt().CmpNoCase( IO_MGR::GetFileExtension( IO_MGR::ALTIUM_CIRCUIT_MAKER ) ) == 0 )
{
pluginType = IO_MGR::ALTIUM_CIRCUIT_MAKER;
}
else
{
pluginType = IO_MGR::KICAD_SEXP;

View File

@ -25,13 +25,16 @@
#include <wx/filename.h>
#include <wx/uri.h>
#include <io_mgr.h>
#include <legacy_plugin.h>
#include <kicad_plugin.h>
#include <eagle_plugin.h>
#include <pcad2kicadpcb_plugin/pcad_plugin.h>
#include <gpcb_plugin.h>
#include <altium2kicadpcb_plugin/altium_circuit_maker_plugin.h>
#include <altium2kicadpcb_plugin/altium_circuit_studio_plugin.h>
#include <altium2kicadpcb_plugin/altium_designer_plugin.h>
#include <config.h>
#include <eagle_plugin.h>
#include <gpcb_plugin.h>
#include <io_mgr.h>
#include <kicad_plugin.h>
#include <legacy_plugin.h>
#include <pcad2kicadpcb_plugin/pcad_plugin.h>
#if defined(BUILD_GITHUB_PLUGIN)
#include <github/github_plugin.h>
@ -204,6 +207,14 @@ void IO_MGR::Save( PCB_FILE_T aFileType, const wxString& aFileName, BOARD* aBoar
static IO_MGR::REGISTER_PLUGIN registerEaglePlugin( IO_MGR::EAGLE, wxT("Eagle"), []() -> PLUGIN* { return new EAGLE_PLUGIN; } );
static IO_MGR::REGISTER_PLUGIN registerKicadPlugin( IO_MGR::KICAD_SEXP, wxT("KiCad"), []() -> PLUGIN* { return new PCB_IO; } );
static IO_MGR::REGISTER_PLUGIN registerPcadPlugin( IO_MGR::PCAD, wxT("P-Cad"), []() -> PLUGIN* { return new PCAD_PLUGIN; } );
static IO_MGR::REGISTER_PLUGIN registerAltiumDesignerPlugin( IO_MGR::ALTIUM_DESIGNER,
wxT( "Altium Designer" ), []() -> PLUGIN* { return new ALTIUM_DESIGNER_PLUGIN; } );
static IO_MGR::REGISTER_PLUGIN registerAltiumCircuitStudioPlugin( IO_MGR::ALTIUM_CIRCUIT_STUDIO,
wxT( "Altium Circuit Studio" ),
[]() -> PLUGIN* { return new ALTIUM_CIRCUIT_STUDIO_PLUGIN; } );
static IO_MGR::REGISTER_PLUGIN registerAltiumCircuitMakerPlugin( IO_MGR::ALTIUM_CIRCUIT_MAKER,
wxT( "Altium Circuit Maker" ),
[]() -> PLUGIN* { return new ALTIUM_CIRCUIT_MAKER_PLUGIN; } );
#ifdef BUILD_GITHUB_PLUGIN
static IO_MGR::REGISTER_PLUGIN registerGithubPlugin( IO_MGR::GITHUB, wxT("Github"), []() -> PLUGIN* { return new GITHUB_PLUGIN; } );
#endif /* BUILD_GITHUB_PLUGIN */

View File

@ -53,19 +53,21 @@ public:
*/
enum PCB_FILE_T
{
LEGACY, ///< Legacy Pcbnew file formats prior to s-expression.
KICAD_SEXP, ///< S-expression Pcbnew file format.
LEGACY, ///< Legacy Pcbnew file formats prior to s-expression.
KICAD_SEXP, ///< S-expression Pcbnew file format.
EAGLE,
PCAD,
GEDA_PCB, ///< Geda PCB file formats.
ALTIUM_DESIGNER,
ALTIUM_CIRCUIT_STUDIO,
ALTIUM_CIRCUIT_MAKER,
GEDA_PCB, ///< Geda PCB file formats.
//N.B. This needs to be commented out to ensure compile-type errors
//N.B. This needs to be commented out to ensure compile-type errors
#if defined(BUILD_GITHUB_PLUGIN)
GITHUB, ///< Read only http://github.com repo holding pretty footprints
GITHUB, ///< Read only http://github.com repo holding pretty footprints
#endif
// add your type here.
// ALTIUM,
// etc.
FILE_TYPE_NONE

View File

@ -31,7 +31,7 @@ if( BUILD_GITHUB_PLUGIN )
set( GITHUB_PLUGIN_LIBRARIES github_plugin )
endif()
add_dependencies( pnsrouter pcbcommon pcad2kicadpcb ${GITHUB_PLUGIN_LIBRARIES} )
add_dependencies( pnsrouter pcbcommon pcad2kicadpcb altium2kicadpcb ${GITHUB_PLUGIN_LIBRARIES} )
add_executable(test_gal_pixel_alignment WIN32
test_gal_pixel_alignment.cpp
@ -72,6 +72,7 @@ target_link_libraries( test_gal_pixel_alignment
pnsrouter
pcbcommon
pcad2kicadpcb
altium2kicadpcb
bitmaps
3d-viewer
gal

View File

@ -67,6 +67,7 @@ target_link_libraries( qa_pcbnew
pcbcommon
pnsrouter
pcad2kicadpcb
altium2kicadpcb
gal
common
gal

Some files were not shown because too many files have changed in this diff Show More