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:
parent
78dfbca9a3
commit
b707c84b62
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -88,6 +88,7 @@ set_target_properties( cvpcb_kiface PROPERTIES
|
|||
target_link_libraries( cvpcb_kiface
|
||||
pcbcommon
|
||||
pcad2kicadpcb
|
||||
altium2kicadpcb
|
||||
3d-viewer
|
||||
gal
|
||||
common
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
)
|
|
@ -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;
|
||||
}
|
|
@ -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_
|
|
@ -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;
|
||||
}
|
|
@ -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_
|
|
@ -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;
|
||||
}
|
|
@ -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_
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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" ) );
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -76,6 +76,8 @@ 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;
|
||||
|
@ -84,9 +86,13 @@ bool AskLoadBoardFileName( wxWindow* aParent, int* aCtl, wxString* aFileName, bo
|
|||
{
|
||||
{ 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
|
||||
{ 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.
|
||||
|
||||
|
@ -370,6 +376,18 @@ IO_MGR::PCB_FILE_T plugin_type( const wxString& aFileName, int aCtl )
|
|||
{
|
||||
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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -57,6 +57,9 @@ public:
|
|||
KICAD_SEXP, ///< S-expression Pcbnew file format.
|
||||
EAGLE,
|
||||
PCAD,
|
||||
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
|
||||
|
@ -65,7 +68,6 @@ public:
|
|||
#endif
|
||||
// add your type here.
|
||||
|
||||
// ALTIUM,
|
||||
// etc.
|
||||
|
||||
FILE_TYPE_NONE
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -67,6 +67,7 @@ target_link_libraries( qa_pcbnew
|
|||
pcbcommon
|
||||
pnsrouter
|
||||
pcad2kicadpcb
|
||||
altium2kicadpcb
|
||||
gal
|
||||
common
|
||||
gal
|
||||
|
|
|
@ -54,6 +54,7 @@ target_link_libraries( qa_pcbnew_tools
|
|||
pcbcommon
|
||||
pnsrouter
|
||||
pcad2kicadpcb
|
||||
altium2kicadpcb
|
||||
gal
|
||||
dxflib_qcad
|
||||
tinyspline_lib
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#
|
||||
|
||||
add_subdirectory( clipper )
|
||||
add_subdirectory( compoundfilereader )
|
||||
add_subdirectory( dxflib_qcad )
|
||||
add_subdirectory( libcontext )
|
||||
add_subdirectory( markdown2html )
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
add_library( compoundfilereader INTERFACE )
|
||||
|
||||
target_include_directories( compoundfilereader INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} )
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
This directory contains the microsoft/compoundfilereader project from https://github.com/microsoft/compoundfilereader.
|
||||
|
||||
They are licensed under MIT, with the license text in this directory.
|
||||
|
|
@ -0,0 +1,480 @@
|
|||
/**
|
||||
Microsoft Compound File (and Property Set) Reader
|
||||
http://en.wikipedia.org/wiki/Compound_File_Binary_Format
|
||||
|
||||
Format specification:
|
||||
MS-CFB: https://msdn.microsoft.com/en-us/library/dd942138.aspx
|
||||
MS-OLEPS: https://msdn.microsoft.com/en-us/library/dd942421.aspx
|
||||
|
||||
Note:
|
||||
1. For simplification, the code assumes that the target system is little-endian.
|
||||
|
||||
2. The reader operates the passed buffer in-place.
|
||||
You must keep the input buffer valid when you are using the reader.
|
||||
|
||||
3. Single thread usage.
|
||||
|
||||
Example 1: print all streams in a compound file
|
||||
\code
|
||||
CFB::CompoundFileReader reader(buffer, len);
|
||||
reader.EnumFiles(reader.GetRootEntry(), -1,
|
||||
[&](const CFB::COMPOUND_FILE_ENTRY* entry, const CFB::utf16string& dir, int level)->void
|
||||
{
|
||||
bool isDirectory = !reader.IsStream(entry);
|
||||
std::string name = UTF16ToUTF8(entry->name);
|
||||
std::string indentstr(level * 4, ' ');
|
||||
printf("%s%s%s%s\n", indentstr.c_str(), isDirectory ? "[" : "", name.c_str(), isDirectory ? "]" : "");
|
||||
});
|
||||
\endcode
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
|
||||
namespace CFB
|
||||
{
|
||||
struct CFBException : public std::runtime_error
|
||||
{
|
||||
CFBException(const char* desc) : std::runtime_error(desc) {}
|
||||
};
|
||||
struct WrongFormat : public CFBException
|
||||
{
|
||||
WrongFormat() : CFBException("Wrong file format") {}
|
||||
};
|
||||
struct FileCorrupted : public CFBException
|
||||
{
|
||||
FileCorrupted() : CFBException("File corrupted") {}
|
||||
};
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
struct COMPOUND_FILE_HDR
|
||||
{
|
||||
unsigned char signature[8];
|
||||
unsigned char unused_clsid[16];
|
||||
uint16_t minorVersion;
|
||||
uint16_t majorVersion;
|
||||
uint16_t byteOrder;
|
||||
uint16_t sectorShift;
|
||||
uint16_t miniSectorShift;
|
||||
unsigned char reserved[6];
|
||||
uint32_t numDirectorySector;
|
||||
uint32_t numFATSector;
|
||||
uint32_t firstDirectorySectorLocation;
|
||||
uint32_t transactionSignatureNumber;
|
||||
uint32_t miniStreamCutoffSize;
|
||||
uint32_t firstMiniFATSectorLocation;
|
||||
uint32_t numMiniFATSector;
|
||||
uint32_t firstDIFATSectorLocation;
|
||||
uint32_t numDIFATSector;
|
||||
uint32_t headerDIFAT[109];
|
||||
};
|
||||
|
||||
struct COMPOUND_FILE_ENTRY
|
||||
{
|
||||
uint16_t name[32];
|
||||
uint16_t nameLen;
|
||||
uint8_t type;
|
||||
uint8_t colorFlag;
|
||||
uint32_t leftSiblingID; // Note that it's actually the left/right child in the RB-tree.
|
||||
uint32_t rightSiblingID; // So entry.leftSibling.rightSibling does NOT go back to entry.
|
||||
uint32_t childID;
|
||||
unsigned char clsid[16];
|
||||
uint32_t stateBits;
|
||||
uint64_t creationTime;
|
||||
uint64_t modifiedTime;
|
||||
uint32_t startSectorLocation;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
struct PROPERTY_SET_STREAM_HDR
|
||||
{
|
||||
unsigned char byteOrder[2];
|
||||
uint16_t version;
|
||||
uint32_t systemIdentifier;
|
||||
unsigned char clsid[16];
|
||||
uint32_t numPropertySets;
|
||||
struct
|
||||
{
|
||||
char fmtid[16];
|
||||
uint32_t offset;
|
||||
} propertySetInfo[1];
|
||||
};
|
||||
|
||||
struct PROPERTY_SET_HDR
|
||||
{
|
||||
uint32_t size;
|
||||
uint32_t NumProperties;
|
||||
struct
|
||||
{
|
||||
uint32_t id;
|
||||
uint32_t offset;
|
||||
} propertyIdentifierAndOffset[1];
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
const size_t MAXREGSECT = 0xFFFFFFFA;
|
||||
|
||||
struct helper
|
||||
{
|
||||
static uint32_t ParseUint32(const void* buffer)
|
||||
{
|
||||
return *static_cast<const uint32_t*>(buffer);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::basic_string<uint16_t> utf16string;
|
||||
typedef std::function<void(const COMPOUND_FILE_ENTRY*, const utf16string& dir, int level)>
|
||||
EnumFilesCallback;
|
||||
|
||||
class CompoundFileReader
|
||||
{
|
||||
public:
|
||||
CompoundFileReader(const void* buffer, size_t len)
|
||||
: m_buffer(static_cast<const unsigned char*>(buffer))
|
||||
, m_bufferLen(len)
|
||||
, m_hdr(static_cast<const COMPOUND_FILE_HDR*>(buffer))
|
||||
, m_sectorSize(512)
|
||||
, m_minisectorSize(64)
|
||||
, m_miniStreamStartSector(0)
|
||||
{
|
||||
if (buffer == NULL || len == 0) throw std::invalid_argument("");
|
||||
|
||||
if (m_bufferLen < sizeof(*m_hdr) ||
|
||||
memcmp(m_hdr->signature, "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1", 8) != 0)
|
||||
{
|
||||
throw WrongFormat();
|
||||
}
|
||||
|
||||
m_sectorSize = m_hdr->majorVersion == 3 ? 512 : 4096;
|
||||
|
||||
// The file must contains at least 3 sectors
|
||||
if (m_bufferLen < m_sectorSize * 3) throw FileCorrupted();
|
||||
|
||||
const COMPOUND_FILE_ENTRY* root = GetEntry(0);
|
||||
if (root == NULL) throw FileCorrupted();
|
||||
|
||||
m_miniStreamStartSector = root->startSectorLocation;
|
||||
}
|
||||
|
||||
/// Get entry (directory or file) by its ID.
|
||||
/// Pass "0" to get the root directory entry. -- This is the start point to navigate the compound file.
|
||||
/// Use the returned object to access child entries.
|
||||
const COMPOUND_FILE_ENTRY* GetEntry(size_t entryID) const
|
||||
{
|
||||
if (entryID == 0xFFFFFFFF)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (m_bufferLen / sizeof(COMPOUND_FILE_ENTRY) <= entryID)
|
||||
{
|
||||
throw std::invalid_argument("");
|
||||
}
|
||||
|
||||
size_t sector = 0;
|
||||
size_t offset = 0;
|
||||
LocateFinalSector(m_hdr->firstDirectorySectorLocation, entryID * sizeof(COMPOUND_FILE_ENTRY), §or, &offset);
|
||||
return reinterpret_cast<const COMPOUND_FILE_ENTRY*>(SectorOffsetToAddress(sector, offset));
|
||||
}
|
||||
|
||||
const COMPOUND_FILE_ENTRY* GetRootEntry() const
|
||||
{
|
||||
return GetEntry(0);
|
||||
}
|
||||
|
||||
const COMPOUND_FILE_HDR* GetFileInfo() const
|
||||
{
|
||||
return m_hdr;
|
||||
}
|
||||
|
||||
/// Get file(stream) data start with "offset".
|
||||
/// The buffer must have enough space to store "len" bytes. Typically "len" is derived by the steam length.
|
||||
void ReadFile(const COMPOUND_FILE_ENTRY* entry, size_t offset, char* buffer, size_t len) const
|
||||
{
|
||||
if (entry->size < offset || entry->size - offset < len) throw std::invalid_argument("");
|
||||
|
||||
if (entry->size < m_hdr->miniStreamCutoffSize)
|
||||
{
|
||||
ReadMiniStream(entry->startSectorLocation, offset, buffer, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadStream(entry->startSectorLocation, offset, buffer, len);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsPropertyStream(const COMPOUND_FILE_ENTRY* entry) const
|
||||
{
|
||||
// defined in [MS-OLEPS] 2.23 "Property Set Stream and Storage Names"
|
||||
return entry->name[0] == 5;
|
||||
}
|
||||
|
||||
bool IsStream(const COMPOUND_FILE_ENTRY* entry) const
|
||||
{
|
||||
return entry->type == 2;
|
||||
}
|
||||
|
||||
void EnumFiles(const COMPOUND_FILE_ENTRY* entry, int maxLevel, EnumFilesCallback callback) const
|
||||
{
|
||||
utf16string dir;
|
||||
EnumNodes(GetEntry(entry->childID), 0, maxLevel, dir, callback);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Enum entries with same level, including 'entry' itself
|
||||
void EnumNodes(const COMPOUND_FILE_ENTRY* entry, int currentLevel, int maxLevel,
|
||||
const utf16string& dir, EnumFilesCallback callback) const
|
||||
{
|
||||
if (maxLevel > 0 && currentLevel >= maxLevel)
|
||||
return;
|
||||
if (entry == nullptr)
|
||||
return;
|
||||
|
||||
callback(entry, dir, currentLevel + 1);
|
||||
|
||||
const COMPOUND_FILE_ENTRY* child = GetEntry(entry->childID);
|
||||
if (child != nullptr)
|
||||
{
|
||||
utf16string newDir = dir;
|
||||
if (dir.length() != 0)
|
||||
newDir.append(1, '\n');
|
||||
newDir.append(entry->name, entry->nameLen / 2);
|
||||
EnumNodes(GetEntry(entry->childID), currentLevel + 1, maxLevel, newDir, callback);
|
||||
}
|
||||
|
||||
EnumNodes(GetEntry(entry->leftSiblingID), currentLevel, maxLevel, dir, callback);
|
||||
EnumNodes(GetEntry(entry->rightSiblingID), currentLevel, maxLevel, dir, callback);
|
||||
}
|
||||
|
||||
void ReadStream(size_t sector, size_t offset, char* buffer, size_t len) const
|
||||
{
|
||||
LocateFinalSector(sector, offset, §or, &offset);
|
||||
|
||||
// copy as many as possible in each step
|
||||
// copylen typically iterate as: m_sectorSize - offset --> m_sectorSize --> m_sectorSize --> ... --> remaining
|
||||
while (len > 0)
|
||||
{
|
||||
const unsigned char* src = SectorOffsetToAddress(sector, offset);
|
||||
size_t copylen = std::min(len, m_sectorSize - offset);
|
||||
if (m_buffer + m_bufferLen < src + copylen) throw FileCorrupted();
|
||||
|
||||
memcpy(buffer, src, copylen);
|
||||
buffer += copylen;
|
||||
len -= copylen;
|
||||
sector = GetNextSector(sector);
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Same logic as "ReadStream" except that use MiniStream functions instead
|
||||
void ReadMiniStream(size_t sector, size_t offset, char* buffer, size_t len) const
|
||||
{
|
||||
LocateFinalMiniSector(sector, offset, §or, &offset);
|
||||
|
||||
// copy as many as possible in each step
|
||||
// copylen typically iterate as: m_sectorSize - offset --> m_sectorSize --> m_sectorSize --> ... --> remaining
|
||||
while (len > 0)
|
||||
{
|
||||
const unsigned char* src = MiniSectorOffsetToAddress(sector, offset);
|
||||
size_t copylen = std::min(len, m_minisectorSize - offset);
|
||||
if (m_buffer + m_bufferLen < src + copylen) throw FileCorrupted();
|
||||
|
||||
memcpy(buffer, src, copylen);
|
||||
buffer += copylen;
|
||||
len -= copylen;
|
||||
sector = GetNextMiniSector(sector);
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t GetNextSector(size_t sector) const
|
||||
{
|
||||
// lookup FAT
|
||||
size_t entriesPerSector = m_sectorSize / 4;
|
||||
size_t fatSectorNumber = sector / entriesPerSector;
|
||||
size_t fatSectorLocation = GetFATSectorLocation(fatSectorNumber);
|
||||
return helper::ParseUint32(SectorOffsetToAddress(fatSectorLocation, sector % entriesPerSector * 4));
|
||||
}
|
||||
|
||||
size_t GetNextMiniSector(size_t miniSector) const
|
||||
{
|
||||
size_t sector, offset;
|
||||
LocateFinalSector(m_hdr->firstMiniFATSectorLocation, miniSector * 4, §or, &offset);
|
||||
return helper::ParseUint32(SectorOffsetToAddress(sector, offset));
|
||||
}
|
||||
|
||||
// Get absolute address from sector and offset.
|
||||
const unsigned char* SectorOffsetToAddress(size_t sector, size_t offset) const
|
||||
{
|
||||
if (sector >= MAXREGSECT ||
|
||||
offset >= m_sectorSize ||
|
||||
m_bufferLen <= static_cast<uint64_t>(m_sectorSize) * sector + m_sectorSize + offset)
|
||||
{
|
||||
throw FileCorrupted();
|
||||
}
|
||||
|
||||
return m_buffer + m_sectorSize + m_sectorSize * sector + offset;
|
||||
}
|
||||
|
||||
const unsigned char* MiniSectorOffsetToAddress(size_t sector, size_t offset) const
|
||||
{
|
||||
if (sector >= MAXREGSECT ||
|
||||
offset >= m_minisectorSize ||
|
||||
m_bufferLen <= static_cast<uint64_t>(m_minisectorSize) * sector + offset)
|
||||
{
|
||||
throw FileCorrupted();
|
||||
}
|
||||
|
||||
|
||||
LocateFinalSector(m_miniStreamStartSector, sector * m_minisectorSize + offset, §or, &offset);
|
||||
return SectorOffsetToAddress(sector, offset);
|
||||
}
|
||||
|
||||
// Locate the final sector/offset when original offset expands multiple sectors
|
||||
void LocateFinalSector(size_t sector, size_t offset, size_t* finalSector, size_t* finalOffset) const
|
||||
{
|
||||
while (offset >= m_sectorSize)
|
||||
{
|
||||
offset -= m_sectorSize;
|
||||
sector = GetNextSector(sector);
|
||||
}
|
||||
*finalSector = sector;
|
||||
*finalOffset = offset;
|
||||
}
|
||||
|
||||
void LocateFinalMiniSector(size_t sector, size_t offset, size_t* finalSector, size_t* finalOffset) const
|
||||
{
|
||||
while (offset >= m_minisectorSize)
|
||||
{
|
||||
offset -= m_minisectorSize;
|
||||
sector = GetNextMiniSector(sector);
|
||||
}
|
||||
*finalSector = sector;
|
||||
*finalOffset = offset;
|
||||
}
|
||||
|
||||
size_t GetFATSectorLocation(size_t fatSectorNumber) const
|
||||
{
|
||||
if (fatSectorNumber < 109)
|
||||
{
|
||||
return m_hdr->headerDIFAT[fatSectorNumber];
|
||||
}
|
||||
else
|
||||
{
|
||||
fatSectorNumber -= 109;
|
||||
size_t entriesPerSector = m_sectorSize / 4 - 1;
|
||||
size_t difatSectorLocation = m_hdr->firstDIFATSectorLocation;
|
||||
while (fatSectorNumber >= entriesPerSector)
|
||||
{
|
||||
fatSectorNumber -= entriesPerSector;
|
||||
const unsigned char* addr = SectorOffsetToAddress(difatSectorLocation, m_sectorSize - 4);
|
||||
difatSectorLocation = helper::ParseUint32(addr);
|
||||
}
|
||||
return helper::ParseUint32(SectorOffsetToAddress(difatSectorLocation, fatSectorNumber * 4));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const unsigned char * m_buffer;
|
||||
size_t m_bufferLen;
|
||||
|
||||
const COMPOUND_FILE_HDR* m_hdr;
|
||||
size_t m_sectorSize;
|
||||
size_t m_minisectorSize;
|
||||
size_t m_miniStreamStartSector;
|
||||
};
|
||||
|
||||
class PropertySet
|
||||
{
|
||||
public:
|
||||
PropertySet(const void* buffer, size_t len, const char* fmtid)
|
||||
: m_buffer(static_cast<const unsigned char*>(buffer))
|
||||
, m_bufferLen(len)
|
||||
, m_hdr(reinterpret_cast<const PROPERTY_SET_HDR*>(buffer))
|
||||
, m_fmtid(fmtid)
|
||||
{
|
||||
if (m_bufferLen < sizeof(*m_hdr) ||
|
||||
m_bufferLen < sizeof(*m_hdr) + (m_hdr->NumProperties - 1) * sizeof(m_hdr->propertyIdentifierAndOffset[0]))
|
||||
{
|
||||
throw FileCorrupted();
|
||||
}
|
||||
}
|
||||
|
||||
/// return the string property in UTF-16 format
|
||||
const uint16_t* GetStringProperty(uint32_t propertyID)
|
||||
{
|
||||
for (uint32_t i = 0; i < m_hdr->NumProperties; i++)
|
||||
{
|
||||
if (m_hdr->propertyIdentifierAndOffset[i].id == propertyID)
|
||||
{
|
||||
uint32_t offset = m_hdr->propertyIdentifierAndOffset[i].offset;
|
||||
if (m_bufferLen < offset + 8) throw FileCorrupted();
|
||||
uint32_t stringLengthInChar = helper::ParseUint32(m_buffer + offset + 4);
|
||||
if (m_bufferLen < offset + 8 + stringLengthInChar*2) throw FileCorrupted();
|
||||
return reinterpret_cast<const uint16_t*>(m_buffer + offset + 8);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Note: Getting property of types other than "string" is not implemented yet.
|
||||
/// However most other types are simpler than string so can be easily added. see [MS-OLEPS]
|
||||
|
||||
const char* GetFmtID()
|
||||
{
|
||||
return m_fmtid;
|
||||
}
|
||||
|
||||
private:
|
||||
const unsigned char* m_buffer;
|
||||
size_t m_bufferLen;
|
||||
const PROPERTY_SET_HDR* m_hdr;
|
||||
const char* m_fmtid; // 16 bytes
|
||||
};
|
||||
|
||||
class PropertySetStream
|
||||
{
|
||||
public:
|
||||
PropertySetStream(const void* buffer, size_t len)
|
||||
: m_buffer(static_cast<const unsigned char*>(buffer))
|
||||
, m_bufferLen(len)
|
||||
, m_hdr(reinterpret_cast<const PROPERTY_SET_STREAM_HDR*>(buffer))
|
||||
{
|
||||
if (m_bufferLen < sizeof(*m_hdr) ||
|
||||
m_bufferLen < sizeof(*m_hdr) + (m_hdr->numPropertySets - 1) * sizeof(m_hdr->propertySetInfo[0]))
|
||||
{
|
||||
throw FileCorrupted();
|
||||
}
|
||||
}
|
||||
|
||||
size_t GetPropertySetCount()
|
||||
{
|
||||
return m_hdr->numPropertySets;
|
||||
}
|
||||
|
||||
PropertySet GetPropertySet(size_t index)
|
||||
{
|
||||
if (index >= GetPropertySetCount()) throw FileCorrupted();
|
||||
uint32_t offset = m_hdr->propertySetInfo[index].offset;
|
||||
if (m_bufferLen < offset + 4) throw FileCorrupted();
|
||||
uint32_t size = helper::ParseUint32(m_buffer + offset);
|
||||
if (m_bufferLen < offset + size) throw FileCorrupted();
|
||||
return PropertySet(m_buffer + offset, size, m_hdr->propertySetInfo[index].fmtid);
|
||||
}
|
||||
|
||||
private:
|
||||
const unsigned char * m_buffer;
|
||||
size_t m_bufferLen;
|
||||
const PROPERTY_SET_STREAM_HDR* m_hdr;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
template <typename T>
|
||||
static bool GetNextCodePointFromUTF16z(const T* u16, size_t* pos, uint32_t* cp)
|
||||
{
|
||||
*cp = static_cast<uint32_t>(u16[*pos]);
|
||||
if (*cp == 0)
|
||||
return false;
|
||||
|
||||
(*pos)++;
|
||||
if ((*cp & 0xFC00) == 0xD800)
|
||||
{
|
||||
uint16_t cp2 = static_cast<uint16_t>(u16[*pos]);
|
||||
if ((cp2 & 0xFC00) == 0xDC00)
|
||||
{
|
||||
(*pos)++;
|
||||
*cp = (*cp << 10) + cp2 - 0x35FDC00;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static bool GetNextCodePointFromUTF16(const T* u16, size_t len, size_t* pos, uint32_t* cp)
|
||||
{
|
||||
if (len == 0)
|
||||
return GetNextCodePointFromUTF16z(u16, pos, cp);
|
||||
|
||||
if (*pos >= len)
|
||||
return false;
|
||||
|
||||
*cp = static_cast<uint32_t>(u16[*pos]);
|
||||
(*pos)++;
|
||||
if ((*cp & 0xFC00) == 0xD800)
|
||||
{
|
||||
if (*pos < len)
|
||||
{
|
||||
uint16_t cp2 = static_cast<uint16_t>(u16[*pos]);
|
||||
if ((cp2 & 0xFC00) == 0xDC00)
|
||||
{
|
||||
(*pos)++;
|
||||
*cp = (*cp << 10) + cp2 - 0x35FDC00;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int CodePointToUTF8(uint32_t cp, uint32_t* c1, uint32_t* c2, uint32_t* c3, uint32_t* c4)
|
||||
{
|
||||
if (cp < 0x80)
|
||||
{
|
||||
*c1 = cp;
|
||||
return 1;
|
||||
}
|
||||
else if (cp <= 0x7FF)
|
||||
{
|
||||
*c1 = (cp >> 6) + 0xC0;
|
||||
*c2 = (cp & 0x3F) + 0x80;
|
||||
return 2;
|
||||
}
|
||||
else if (cp <= 0xFFFF)
|
||||
{
|
||||
*c1 = (cp >> 12) + 0xE0;
|
||||
*c2 = ((cp >> 6) & 0x3F) + 0x80;
|
||||
*c3 = (cp & 0x3F) + 0x80;
|
||||
return 3;
|
||||
}
|
||||
else if (cp <= 0x10FFFF)
|
||||
{
|
||||
*c1 = (cp >> 18) + 0xF0;
|
||||
*c2 = ((cp >> 12) & 0x3F) + 0x80;
|
||||
*c3 = ((cp >> 6) & 0x3F) + 0x80;
|
||||
*c4 = (cp & 0x3F) + 0x80;
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string UTF16ToUTF8(const T* u16, size_t len = 0)
|
||||
{
|
||||
std::string u8;
|
||||
uint32_t cp;
|
||||
size_t pos = 0;
|
||||
while (GetNextCodePointFromUTF16(u16, len, &pos, &cp))
|
||||
{
|
||||
uint32_t c[4];
|
||||
int count = CodePointToUTF8(cp, c, c+1, c+2, c+3);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
u8 += static_cast<char>(c[i]);
|
||||
}
|
||||
}
|
||||
return u8;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::wstring UTF16ToWstring(const T* u16, size_t len = 0)
|
||||
{
|
||||
std::wstring ret;
|
||||
#ifdef _MSC_VER
|
||||
while (*u16) ret += *u16++;
|
||||
#else
|
||||
uint32_t cp;
|
||||
size_t pos = 0;
|
||||
while (GetNextCodePointFromUTF16(u16, len, &pos, &cp))
|
||||
{
|
||||
ret += cp;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string WstringToUTF8(const T* wstr)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return UTF16ToUTF8(wstr);
|
||||
#else
|
||||
std::string u8;
|
||||
uint32_t cp;
|
||||
while ((cp = *wstr++) != 0)
|
||||
{
|
||||
uint32_t c[4];
|
||||
int count = CodePointToUTF8(cp, c, c+1, c+2, c+3);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
u8 += static_cast<char>(c[i]);
|
||||
}
|
||||
}
|
||||
return u8;
|
||||
#endif
|
||||
}
|
Loading…
Reference in New Issue