From 4c2f38f1ad34293e30b6400e4716c7f6c59c75b7 Mon Sep 17 00:00:00 2001 From: Roberto Fernandez Bautista Date: Thu, 30 Jul 2020 23:42:56 +0100 Subject: [PATCH] CADSTAR PCB Archive Importer: Parse LIBRARY section + code refactoring code refactoring: - Renamed CADSTAR_COMMON to CADSTAR_ARCHIVE_COMMON - Renamed CPA_FILE to CADSTAR_PCB_ARCHIVE_PARSER - Made CADSTAR_PCB_ARCHIVE_PARSER a derived class of CADSTAR_ARCHIVE_COMMON - Moved all structures in cadstar_pcb_archive_parser.h/.cpp to be defined inside CADSTAR_PCB_ARCHIVE_PARSER class --- pcbnew/cadstar2kicadpcb_plugin/CMakeLists.txt | 2 +- .../cadstar_archive_common.cpp | 403 ++++ .../cadstar_archive_common.h | 251 +++ .../cadstar_common.cpp | 253 --- .../cadstar2kicadpcb_plugin/cadstar_common.h | 164 -- .../cadstar2kicadpcb_plugin/cadstar_pcb.cpp | 94 +- pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb.h | 22 +- .../cadstar_pcb_archive_parser.cpp | 1472 +++++++++++--- .../cadstar_pcb_archive_parser.h | 1762 +++++++++++------ .../cadstar_pcb_archive_plugin.cpp | 8 +- qa/drc_proto/CMakeLists.txt | 1 + 11 files changed, 3041 insertions(+), 1391 deletions(-) create mode 100644 pcbnew/cadstar2kicadpcb_plugin/cadstar_archive_common.cpp create mode 100644 pcbnew/cadstar2kicadpcb_plugin/cadstar_archive_common.h delete mode 100644 pcbnew/cadstar2kicadpcb_plugin/cadstar_common.cpp delete mode 100644 pcbnew/cadstar2kicadpcb_plugin/cadstar_common.h diff --git a/pcbnew/cadstar2kicadpcb_plugin/CMakeLists.txt b/pcbnew/cadstar2kicadpcb_plugin/CMakeLists.txt index ae3136155b..dd52ee6a70 100644 --- a/pcbnew/cadstar2kicadpcb_plugin/CMakeLists.txt +++ b/pcbnew/cadstar2kicadpcb_plugin/CMakeLists.txt @@ -5,7 +5,7 @@ include_directories( . ) set( CADSTAR2PCBNEW_SRCS cadstar_pcb_archive_plugin.cpp cadstar_pcb_archive_parser.cpp - cadstar_common.cpp + cadstar_archive_common.cpp cadstar_pcb.cpp ) diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_archive_common.cpp b/pcbnew/cadstar2kicadpcb_plugin/cadstar_archive_common.cpp new file mode 100644 index 0000000000..a3e4126e78 --- /dev/null +++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_archive_common.cpp @@ -0,0 +1,403 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2020 Roberto Fernandez Bautista <@Qbort> + * Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors. + * + * 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 3 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, see . + */ + +/** + * @file cadstar_common.cpp + * @brief Helper functions and common defines + */ + +#include + + +void CADSTAR_ARCHIVE_COMMON::EVALUE::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "E" ) ); + + if( ( !GetXmlAttributeIDString( aNode, 0 ).ToLong( &Base ) ) + || ( !GetXmlAttributeIDString( aNode, 1 ).ToLong( &Exponent ) ) ) + THROW_PARSING_IO_ERROR( wxT( "Base and Exponent" ), + wxString::Format( + "%s->%s", aNode->GetParent()->GetName(), aNode->GetParent()->GetName() ) ); +} + + +void CADSTAR_ARCHIVE_COMMON::POINT::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "PT" ) ); + + X = GetXmlAttributeIDLong( aNode, 0 ); + Y = GetXmlAttributeIDLong( aNode, 1 ); +} + + +bool CADSTAR_ARCHIVE_COMMON::VERTEX::IsVertex( XNODE* aNode ) +{ + wxString aNodeName = aNode->GetName(); + + if( aNodeName == wxT( "PT" ) || aNodeName == wxT( "ACWARC" ) || aNodeName == wxT( "CWARC" ) + || aNodeName == wxT( "CWSEMI" ) || aNodeName == wxT( "ACWSEMI" ) ) + return true; + else + return false; +} + + +void CADSTAR_ARCHIVE_COMMON::VERTEX::Parse( XNODE* aNode ) +{ + wxASSERT( IsVertex( aNode ) ); + + wxString aNodeName = aNode->GetName(); + + if( aNodeName == wxT( "PT" ) ) + { + Type = VERTEX_TYPE::POINT; + Center.X = UNDEFINED_VALUE; + Center.Y = UNDEFINED_VALUE; + End.Parse( aNode ); + } + else if( aNodeName == wxT( "ACWARC" ) || aNodeName == wxT( "CWARC" ) ) + { + if( aNodeName == wxT( "ACWARC" ) ) + Type = VERTEX_TYPE::ANTICLOCKWISE_ARC; + else + Type = VERTEX_TYPE::CLOCKWISE_ARC; + + std::vector pts = ParseAllChildPoints( aNode, true, 2 ); + + Center = pts[0]; + End = pts[1]; + } + else if( aNodeName == wxT( "ACWSEMI" ) || aNodeName == wxT( "CWSEMI" ) ) + { + if( aNodeName == wxT( "ACWSEMI" ) ) + Type = VERTEX_TYPE::ANTICLOCKWISE_SEMICIRCLE; + else + Type = VERTEX_TYPE::CLOCKWISE_SEMICIRCLE; + + Center.X = UNDEFINED_VALUE; + Center.Y = UNDEFINED_VALUE; + + std::vector pts = ParseAllChildPoints( aNode, true, 1 ); + + End = pts[0]; + } + else + { + wxASSERT_MSG( true, wxT( "Unknown VERTEX type" ) ); + } +} + + +double CADSTAR_ARCHIVE_COMMON::EVALUE::GetDouble() +{ + return Base * std::pow( 10.0, Exponent ); +} + + +void CADSTAR_ARCHIVE_COMMON::InsertAttributeAtEnd( XNODE* aNode, wxString aValue ) +{ + wxString result, paramName = "attr0"; + int i = 0; + + while( aNode->GetAttribute( paramName, &result ) ) + { + paramName = wxT( "attr" ); + paramName << i++; + } + + aNode->AddAttribute( paramName, aValue ); +} + + +XNODE* CADSTAR_ARCHIVE_COMMON::LoadArchiveFile( + const wxString& aFileName, const wxString& aFileTypeIdentifier ) +{ + KEYWORD emptyKeywords[1] = {}; + XNODE * iNode = NULL, *cNode = NULL; + int tok; + bool cadstarFileCheckDone = false; + wxString str; + wxCSConv win1252( wxT( "windows-1252" ) ); + wxMBConv* conv = &win1252; // Initial testing suggests file encoding to be Windows-1252 + // More samples required. + FILE* fp = wxFopen( aFileName, wxT( "rt" ) ); + + if( !fp ) + THROW_IO_ERROR( wxString::Format( _( "Cannot open file '%s'" ), aFileName ) ); + + DSNLEXER lexer( emptyKeywords, 0, fp, aFileName ); + + while( ( tok = lexer.NextTok() ) != DSN_EOF ) + { + if( tok == DSN_RIGHT ) + { + cNode = iNode; + if( cNode ) + { + iNode = cNode->GetParent(); + } + else + { + //too many closing brackets + THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) ); + } + } + else if( tok == DSN_LEFT ) + { + tok = lexer.NextTok(); + str = wxString( lexer.CurText(), *conv ); + cNode = new XNODE( wxXML_ELEMENT_NODE, str ); + + if( iNode ) + { + //we will add it as attribute as well as child node + InsertAttributeAtEnd( iNode, str ); + iNode->AddChild( cNode ); + } + else if( !cadstarFileCheckDone ) + { + + if( cNode->GetName() != aFileTypeIdentifier ) + { + THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) ); + } + cadstarFileCheckDone = true; + } + + iNode = cNode; + } + else if( iNode ) + { + str = wxString( lexer.CurText(), *conv ); + //Insert even if string is empty + InsertAttributeAtEnd( iNode, str ); + } + else + { + //not enough closing brackets + THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) ); + } + } + + if( iNode != NULL ) + { + //not enough closing brackets + THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) ); + } + + if( cNode ) + { + return cNode; + } + else + { + //no data? + THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) ); + } + + return NULL; +} + +wxString CADSTAR_ARCHIVE_COMMON::GetXmlAttributeIDString( XNODE* aNode, unsigned int aID ) +{ + wxString attrName, retVal; + attrName = "attr"; + attrName << aID; + + if( !aNode->GetAttribute( attrName, &retVal ) ) + THROW_MISSING_PARAMETER_IO_ERROR( std::to_string( aID ), aNode->GetName() ); + + return retVal; +} + + +long CADSTAR_ARCHIVE_COMMON::GetXmlAttributeIDLong( XNODE* aNode, unsigned int aID ) +{ + long retVal; + + if( !GetXmlAttributeIDString( aNode, aID ).ToLong( &retVal ) ) + THROW_PARSING_IO_ERROR( std::to_string( aID ), aNode->GetName() ); + + return retVal; +} + + +void CADSTAR_ARCHIVE_COMMON::CheckNoChildNodes( XNODE* aNode ) +{ + if( aNode->GetChildren() ) + { + THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetChildren()->GetName(), aNode->GetName() ); + } +} + + +void CADSTAR_ARCHIVE_COMMON::CheckNoNextNodes( XNODE* aNode ) +{ + if( aNode->GetNext() ) + { + THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetNext()->GetName(), aNode->GetParent()->GetName() ); + } +} + + +void CADSTAR_ARCHIVE_COMMON::ParseChildEValue( XNODE* aNode, EVALUE& aValueToParse ) +{ + if( aNode->GetChildren()->GetName() == wxT( "E" ) ) + { + aValueToParse.Parse( aNode->GetChildren() ); + } + else + { + THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetChildren()->GetName(), aNode->GetName() ); + } +} + +std::vector CADSTAR_ARCHIVE_COMMON::ParseAllChildPoints( + XNODE* aNode, bool aTestAllChildNodes, int aExpectedNumPoints ) +{ + std::vector retVal; + + XNODE* cNode = aNode->GetChildren(); + + for( ; cNode; cNode = cNode->GetNext() ) + { + if( cNode->GetName() == wxT( "PT" ) ) + { + POINT pt; + //TODO try.. catch + throw again with more detailed error information + pt.Parse( cNode ); + retVal.push_back( pt ); + } + else if( aTestAllChildNodes ) + THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), aNode->GetName() ); + } + + if( aExpectedNumPoints != UNDEFINED_VALUE && retVal.size() != aExpectedNumPoints ) + THROW_IO_ERROR( wxString::Format( + _( "Unexpected number of points in '%s'. Found %d but expected %d." ), + aNode->GetName(), retVal.size(), aExpectedNumPoints ) ); + + return retVal; +} + + +std::vector CADSTAR_ARCHIVE_COMMON::ParseAllChildVertices( + XNODE* aNode, bool aTestAllChildNodes ) +{ + std::vector retVal; + + XNODE* cNode = aNode->GetChildren(); + + for( ; cNode; cNode = cNode->GetNext() ) + { + if( VERTEX::IsVertex( cNode ) ) + { + VERTEX vertex; + //TODO try.. catch + throw again with more detailed error information + vertex.Parse( cNode ); + retVal.push_back( vertex ); + } + else if( aTestAllChildNodes ) + THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), aNode->GetName() ); + } + + return retVal; +} + + +std::vector CADSTAR_ARCHIVE_COMMON::ParseAllChildCutouts( + XNODE* aNode, bool aTestAllChildNodes ) +{ + std::vector retVal; + + XNODE* cNode = aNode->GetChildren(); + + for( ; cNode; cNode = cNode->GetNext() ) + { + if( cNode->GetName() == wxT( "CUTOUT" ) ) + { + CUTOUT cutout; + //TODO try.. catch + throw again with more detailed error information + cutout.Parse( cNode ); + retVal.push_back( cutout ); + } + else if( aTestAllChildNodes ) + THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), aNode->GetName() ); + } + + return retVal; +} + +void CADSTAR_ARCHIVE_COMMON::CUTOUT::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "CUTOUT" ) ); + + Vertices = ParseAllChildVertices( aNode, true ); +} + + +bool CADSTAR_ARCHIVE_COMMON::SHAPE::IsShape( XNODE* aNode ) +{ + wxString aNodeName = aNode->GetName(); + + if( aNodeName == wxT( "OPENSHAPE" ) || aNodeName == wxT( "OUTLINE" ) + || aNodeName == wxT( "SOLID" ) || aNodeName == wxT( "HATCHED" ) ) + return true; + else + return false; +} + +void CADSTAR_ARCHIVE_COMMON::SHAPE::Parse( XNODE* aNode ) +{ + wxASSERT( IsShape( aNode ) ); + + wxString aNodeName = aNode->GetName(); + + if( aNodeName == wxT( "OPENSHAPE" ) ) + { + Type = SHAPE_TYPE::OPENSHAPE; + Vertices = ParseAllChildVertices( aNode, true ); + Cutouts.clear(); + HatchCodeID = wxEmptyString; + } + else if( aNodeName == wxT( "OUTLINE" ) ) + { + Type = SHAPE_TYPE::OUTLINE; + Vertices = ParseAllChildVertices( aNode, false ); + Cutouts = ParseAllChildCutouts( aNode, false ); + HatchCodeID = wxEmptyString; + } + else if( aNodeName == wxT( "SOLID" ) ) + { + Type = SHAPE_TYPE::SOLID; + Vertices = ParseAllChildVertices( aNode, false ); + Cutouts = ParseAllChildCutouts( aNode, false ); + HatchCodeID = wxEmptyString; + } + else if( aNodeName == wxT( "HATCHED" ) ) + { + Type = SHAPE_TYPE::HATCHED; + Vertices = ParseAllChildVertices( aNode, false ); + Cutouts = ParseAllChildCutouts( aNode, false ); + HatchCodeID = GetXmlAttributeIDString( aNode, 0 ); + } + else + wxASSERT_MSG( true, wxT( "Unknown SHAPE type" ) ); +} diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_archive_common.h b/pcbnew/cadstar2kicadpcb_plugin/cadstar_archive_common.h new file mode 100644 index 0000000000..9dda06ffa6 --- /dev/null +++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_archive_common.h @@ -0,0 +1,251 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2020 Roberto Fernandez Bautista <@Qbort> + * Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors. + * + * 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 3 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, see . + */ + +/** + * @file cadstar_common.h + * @brief Helper functions and common defines + */ + +#ifndef CADSTAR_ARHIVE_COMMON_H_ +#define CADSTAR_ARHIVE_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include + +// THROW_IO_ERROR definitions to ensure consident wording is used in the error messages + +#define THROW_MISSING_NODE_IO_ERROR( nodename, location ) \ + THROW_IO_ERROR( wxString::Format( _( "Missing node '%s' in '%s'" ), nodename, location ) ) + +#define THROW_UNKNOWN_NODE_IO_ERROR( nodename, location ) \ + THROW_IO_ERROR( wxString::Format( _( "Unknown node '%s' in '%s'" ), nodename, location ) ) + +#define THROW_MISSING_PARAMETER_IO_ERROR( param, location ) \ + THROW_IO_ERROR( wxString::Format( _( "Missing Parameter '%s' in '%s'" ), param, location ) ) + +#define THROW_UNKNOWN_PARAMETER_IO_ERROR( param, location ) \ + THROW_IO_ERROR( wxString::Format( _( "Unknown Parameter '%s' in '%s'" ), param, location ) ) + +#define THROW_PARSING_IO_ERROR( param, location ) \ + THROW_IO_ERROR( wxString::Format( _( "Unable to parse '%s' in '%s'" ), param, location ) ) + +/** + * @brief Helper functions and common structures for CADSTAR PCB and Schematic archive files. +*/ +class CADSTAR_ARCHIVE_COMMON +{ +public: + static const long UNDEFINED_VALUE = -1; + + /** + * @brief Represents a floating value in E notation + */ + struct EVALUE + { + long Base = 0; + long Exponent = 0; + + void Parse( XNODE* aNode ); + double GetDouble(); + }; + + /** + * @brief Represents a point in x,y coordinates + */ + struct POINT + { + long X = UNDEFINED_VALUE; + long Y = UNDEFINED_VALUE; + + void Parse( XNODE* aNode ); + }; + + + enum class VERTEX_TYPE + { + POINT, + CLOCKWISE_ARC, + CLOCKWISE_SEMICIRCLE, + ANTICLOCKWISE_ARC, + ANTICLOCKWISE_SEMICIRCLE + }; + + + /** + * @brief Represents a vertex in a shape. E.g. A circle is made by two semicircles with the same + * center point. + */ + struct VERTEX + { + VERTEX_TYPE Type; + POINT Center; + POINT End; + + static bool IsVertex( XNODE* aNode ); + void Parse( XNODE* aNode ); + }; + + + /** + * @brief Represents a cutout in a closed shape (e.g. OUTLINE) + */ + struct CUTOUT + { + std::vector Vertices; + + void Parse( XNODE* aNode ); + }; + + + enum class SHAPE_TYPE + { + OPENSHAPE, //< Unfilled open shape. Cannot have cutouts. + OUTLINE, //< Unfilled closed shape. + SOLID, //< Filled closed shape (solid fill). + HATCHED //< Filled closed shape (hatch fill). + }; + + + struct SHAPE + { + SHAPE_TYPE Type; + std::vector Vertices; + std::vector Cutouts; ///< Not Applicable to OPENSHAPE Type + wxString HatchCodeID; ///< Only Applicable for HATCHED Type + + static bool IsShape( XNODE* aNode ); + void Parse( XNODE* aNode ); + }; + + + static void InsertAttributeAtEnd( XNODE* aNode, wxString aValue ); + + /** + * @brief Reads a CADSTAR Archive file (S-parameter format) + * @param aFileName + * @param aFileTypeIdentifier Identifier of the first node in the file to check against. + E.g. "CADSTARPCB" + * @return XNODE pointing to the top of the tree for further parsing. Each node has the first + * element as the node's name and subsequent elements as node attributes ("attr0", + * "attr1", "attr2", etc.). Caller is responsible for deleting to avoid memory leaks. + * @throws IO_ERROR + */ + static XNODE* LoadArchiveFile( const wxString& aFileName, const wxString& aFileTypeIdentifier ); + + + /** + * @brief + * @param aNode + * @param aID + * @return returns the value of attribute "attrX" in aNode where 'X' is aID + * @throws IO_ERROR if attribute does not exist + */ + static wxString GetXmlAttributeIDString( XNODE* aNode, unsigned int aID ); + + + /** + * @brief + * @param aNode + * @param aID + * @return returns the value of attribute "attrX" in aNode where 'X' is aID + * @throws IO_ERROR if attribute does not exist + */ + static long GetXmlAttributeIDLong( XNODE* aNode, unsigned int aID ); + + + /** + * @brief + * @param aNode + * @throw IO_ERROR if a child node was found + */ + static void CheckNoChildNodes( XNODE* aNode ); + + + /** + * @brief + * @param aNode + * @throw IO_ERROR if a node adjacent to aNode was found + */ + static void CheckNoNextNodes( XNODE* aNode ); + + + /** + * @brief + * @param aNode with a child node containing an EVALUE + * @param aValueToParse + * @throw IO_ERROR if unable to parse or node is not an EVALUE + */ + static void ParseChildEValue( XNODE* aNode, EVALUE& aValueToParse ); + + + /** + * @brief if no childs are present, it just returns an empty + * vector (without throwing an exception) + * @param aNode containing a series of POINT objects + * @param aTestAllChildNodes + * @param aExpectedNumPoints if UNDEFINED_VALUE (i.e. -1), this is check is disabled + * @return std::vector containing all POINT objects + * @throw IO_ERROR if one of the following: + * - Unable to parse a POINT object + * - aTestAllChildNodes is true and one of the child nodes is not a valid POINT object + * - aExpectedNumPoints is non-negative and the number of POINT objects found is different + */ + static std::vector ParseAllChildPoints( XNODE* aNode, bool aTestAllChildNodes = false, + int aExpectedNumPoints = UNDEFINED_VALUE ); + + + /** + * @brief if no childs are present, it just returns an empty + * vector (without throwing an exception) + * @param aNode containing a series of VERTEX objects + * @param aTestAllChildNodes + * @param aExpectedNumPoints if -1, this is check is disabled + * @return std::vector containing all VERTEX objects + * @throw IO_ERROR if one of the following: + * - Unable to parse a VERTEX object + * - aTestAllChildNodes is true and one of the child nodes is not a valid VERTEX object + */ + static std::vector ParseAllChildVertices( + XNODE* aNode, bool aTestAllChildNodes = false ); + + + /** + * @brief if no childs are present, it just returns an empty + * vector (without throwing an exception) + * @param aNode containing a series of CUTOUT objects + * @param aTestAllChildNodes + * @param aExpectedNumPoints if -1, this is check is disabled + * @return std::vector containing all CUTOUT objects + * @throw IO_ERROR if one of the following: + * - Unable to parse a CUTOUT object + * - aTestAllChildNodes is true and one of the child nodes is not a valid CUTOUT object + */ + static std::vector ParseAllChildCutouts( + XNODE* aNode, bool aTestAllChildNodes = false ); + + +}; // class CADSTAR_ARCHIVE_COMMON + +#endif // CADSTAR_COMMON_H_ diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.cpp b/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.cpp deleted file mode 100644 index 74a4d903fc..0000000000 --- a/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2020 Roberto Fernandez Bautista <@Qbort> - * Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors. - * - * 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 3 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, see . - */ - -/** - * @file cadstar_common.cpp - * @brief Helper functions and common defines - */ - -#include - - -void CADSTAR_COMMON::EVALUE::Parse( XNODE* aNode ) -{ - wxASSERT( aNode->GetName() == wxT( "E" ) ); - - if( ( !CADSTAR_COMMON::GetAttributeID( aNode, 0 ).ToLong( &Base ) ) - || ( !CADSTAR_COMMON::GetAttributeID( aNode, 1 ).ToLong( &Exponent ) ) ) - THROW_PARSING_IO_ERROR( wxT( "Base and Exponent" ), - wxString::Format( - "%s->%s", aNode->GetParent()->GetName(), aNode->GetParent()->GetName() ) ); -} - - -void CADSTAR_COMMON::POINT::Parse( XNODE* aNode ) -{ - wxASSERT( aNode->GetName() == wxT( "PT" ) ); - - X = CADSTAR_COMMON::GetAttributeIDLong( aNode, 0 ); - Y = CADSTAR_COMMON::GetAttributeIDLong( aNode, 1 ); -} - - -double CADSTAR_COMMON::EVALUE::GetDouble() -{ - return Base * std::pow( 10.0, Exponent ); -} - - -void CADSTAR_COMMON::InsertAttributeAtEnd( XNODE* aNode, wxString aValue ) -{ - wxString result, paramName = "attr0"; - int i = 0; - - while( aNode->GetAttribute( paramName, &result ) ) - { - paramName = wxT( "attr" ); - paramName << i++; - } - - aNode->AddAttribute( paramName, aValue ); -} - - -XNODE* CADSTAR_COMMON::LoadArchiveFile( const wxString& aFileName, FILE_TYPE aType ) -{ - KEYWORD emptyKeywords[1] = {}; - XNODE * iNode = NULL, *cNode = NULL; - int tok; - bool cadstarFileCheckDone = false; - wxString str, fileIdentifier; - wxCSConv win1252( wxT( "windows-1252" ) ); - wxMBConv* conv = &win1252; // Initial testing suggests file encoding to be Windows-1252 - // More samples required. - FILE* fp = wxFopen( aFileName, wxT( "rt" ) ); - - if( !fp ) - THROW_IO_ERROR( wxString::Format( _( "Cannot open file '%s'" ), aFileName ) ); - - - switch( aType ) - { - case FILE_TYPE::PCB_ARCHIVE: - fileIdentifier = wxT( "CADSTARPCB" ); - break; - - //add others here - // SCHEMATIC_ARCHIVE - // ... - - default: - wxASSERT_MSG( true, "Unknown CADSTAR filetype specified" ); - } - - DSNLEXER lexer( emptyKeywords, 0, fp, aFileName ); - - while( ( tok = lexer.NextTok() ) != DSN_EOF ) - { - if( tok == DSN_RIGHT ) - { - cNode = iNode; - if( cNode ) - { - iNode = cNode->GetParent(); - } - else - { - //too many closing brackets - THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) ); - } - } - else if( tok == DSN_LEFT ) - { - tok = lexer.NextTok(); - str = wxString( lexer.CurText(), *conv ); - cNode = new XNODE( wxXML_ELEMENT_NODE, str ); - - if( iNode ) - { - //we will add it as attribute as well as child node - InsertAttributeAtEnd( iNode, str ); - iNode->AddChild( cNode ); - } - else if( !cadstarFileCheckDone ) - { - - if( cNode->GetName() != fileIdentifier ) - { - THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) ); - } - } - - iNode = cNode; - } - else if( iNode ) - { - str = wxString( lexer.CurText(), *conv ); - //Insert even if string is empty - InsertAttributeAtEnd( iNode, str ); - } - else - { - //not enough closing brackets - THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) ); - } - } - - if( iNode != NULL ) - { - //not enough closing brackets - THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) ); - } - - if( cNode ) - { - return cNode; - } - else - { - //no data? - THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) ); - } - - return NULL; -} - -wxString CADSTAR_COMMON::GetAttributeID( XNODE* aNode, unsigned int aID ) -{ - wxString attrName, retVal; - attrName = "attr"; - attrName << aID; - - if( !aNode->GetAttribute( attrName, &retVal ) ) - THROW_MISSING_PARAMETER_IO_ERROR( std::to_string( aID ), aNode->GetName() ); - - return retVal; -} - - -long CADSTAR_COMMON::GetAttributeIDLong( XNODE* aNode, unsigned int aID ) -{ - long retVal; - - if( !CADSTAR_COMMON::GetAttributeID( aNode, aID ).ToLong( &retVal ) ) - THROW_PARSING_IO_ERROR( std::to_string( aID ), aNode->GetName() ); - - return retVal; -} - - -void CADSTAR_COMMON::CheckNoChildNodes( XNODE* aNode ) -{ - if( aNode->GetChildren() ) - { - THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetChildren()->GetName(), aNode->GetName() ); - } -} - - -void CADSTAR_COMMON::CheckNoNextNodes( XNODE* aNode ) -{ - if( aNode->GetNext() ) - { - THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetNext()->GetName(), aNode->GetParent()->GetName() ); - } -} - - -void CADSTAR_COMMON::ParseChildEValue( XNODE* aNode, CADSTAR_COMMON::EVALUE& aValueToParse ) -{ - if( aNode->GetChildren()->GetName() == wxT( "E" ) ) - { - aValueToParse.Parse( aNode->GetChildren() ); - } - else - { - THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetChildren()->GetName(), aNode->GetName() ); - } -} - -std::vector CADSTAR_COMMON::ParseAllChildPoints( - XNODE* aNode, bool aTestAllChildNodes, int aExpectedNumPoints ) -{ - std::vector retVal; - - XNODE* cNode = aNode->GetChildren(); - - for( ; cNode; cNode = cNode->GetNext() ) - { - if( cNode->GetName() == wxT( "PT" ) ) - { - POINT pt; - //TODO try.. catch + throw again with more detailed error information - pt.Parse( cNode ); - retVal.push_back( pt ); - } - else if( aTestAllChildNodes ) - THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), aNode->GetName() ); - } - - if( aExpectedNumPoints >= 0 && retVal.size() != aExpectedNumPoints ) - THROW_IO_ERROR( wxString::Format( - _( "Unexpected number of points in '%s'. Found %d but expected %d." ), - aNode->GetName(), retVal.size(), aExpectedNumPoints ) ); - - return retVal; -} diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.h b/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.h deleted file mode 100644 index 49c701513c..0000000000 --- a/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2020 Roberto Fernandez Bautista <@Qbort> - * Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors. - * - * 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 3 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, see . - */ - -/** - * @file cadstar_common.h - * @brief Helper functions and common defines - */ - -#ifndef CADSTAR_COMMON_H_ -#define CADSTAR_COMMON_H_ - -#include -#include -#include -#include -#include -#include -#include - -#define THROW_MISSING_NODE_IO_ERROR( nodename, location ) \ - THROW_IO_ERROR( wxString::Format( _( "Missing node '%s' in '%s'" ), nodename, location ) ) - -#define THROW_UNKNOWN_NODE_IO_ERROR( nodename, location ) \ - THROW_IO_ERROR( wxString::Format( _( "Unknown node '%s' in '%s'" ), nodename, location ) ) - -#define THROW_MISSING_PARAMETER_IO_ERROR( param, location ) \ - THROW_IO_ERROR( wxString::Format( _( "Missing Parameter '%s' in '%s'" ), param, location ) ) - -#define THROW_UNKNOWN_PARAMETER_IO_ERROR( param, location ) \ - THROW_IO_ERROR( wxString::Format( _( "Unknown Parameter '%s' in '%s'" ), param, location ) ) - -#define THROW_PARSING_IO_ERROR( param, location ) \ - THROW_IO_ERROR( wxString::Format( _( "Unable to parse '%s' in '%s'" ), param, location ) ) - - -namespace CADSTAR_COMMON -{ -enum class FILE_TYPE -{ - PCB_ARCHIVE, - SCHEMATIC_ARCHIVE //for future schematic importer - //cadstar libraries? - //etc. -}; - - -/** - * @brief Represents a floating value in E notation - */ -struct EVALUE -{ - long Base = 0; - long Exponent = 0; - - void Parse( XNODE* aNode ); - double GetDouble(); -}; - -/** - * @brief Represents a point in x,y coordinates -*/ -struct POINT -{ - long X; - long Y; - - void Parse( XNODE* aNode ); -}; - - -extern void InsertAttributeAtEnd( XNODE* aNode, wxString aValue ); - -/** - * @brief Reads a CADSTAR Archive file (S-parameter format) - * @param aFileName - * @param aType - * @return XNODE pointing to the top of the tree for further parsing. Each node has the first - * element as the node's name and subsequent elements as node attributes ("attr0", - * "attr1", "attr2", etc.). Caller is responsible for deleting to avoid memory leaks. - * @throws IO_ERROR - */ -extern XNODE* LoadArchiveFile( - const wxString& aFileName, FILE_TYPE aType = FILE_TYPE::PCB_ARCHIVE ); - - -/** - * @brief - * @param aNode - * @param aID - * @return returns the value of attribute "attrX" in aNode where 'X' is aID - * @throws IO_ERROR if attribute does not exist - */ -extern wxString GetAttributeID( XNODE* aNode, unsigned int aID ); - - -/** - * @brief - * @param aNode - * @param aID - * @return returns the value of attribute "attrX" in aNode where 'X' is aID - * @throws IO_ERROR if attribute does not exist - */ -extern long GetAttributeIDLong( XNODE* aNode, unsigned int aID ); - - -/** - * @brief - * @param aNode - * @throw IO_ERROR if a child node was found - */ -extern void CheckNoChildNodes( XNODE* aNode ); - - -/** - * @brief - * @param aNode - * @throw IO_ERROR if a node adjacent to aNode was found - */ -extern void CheckNoNextNodes( XNODE* aNode ); - - -/** - * @brief - * @param aNode with a child node containing an EVALUE - * @param aValueToParse - * @throw IO_ERROR if unable to parse or node is not an EVALUE - */ -extern void ParseChildEValue( XNODE* aNode, EVALUE& aValueToParse ); - -/** - * @brief if no childs are present, it just returns an empty - * vector (without throwing an exception) - * @param aNode containing a series of POINT objects - * @param aTestAllChildNodes - * @param aExpectedNumPoints if -1, this is check is disabled - * @return std::vector containing all POINT objects - * @throw IO_ERROR if one of the following: - * - Unable to parse a POINT object - * - aTestAllChildNodes is true and one of the child nodes is not a valid POINT object - * - aExpectedNumPoints is non-negative and the number of POINT objects found is different - */ -extern std::vector ParseAllChildPoints( - XNODE* aNode, bool aTestAllChildNodes = true, int aExpectedNumPoints = -1 ); - -} // namespace CADSTAR_COMMON - -#endif // CADSTAR_COMMON_H_ diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb.cpp b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb.cpp index 051e900453..e2078ed7ad 100644 --- a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb.cpp +++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb.cpp @@ -20,36 +20,38 @@ /** * @file cadstar_pcb.cpp - * @brief Converts a CPA_FILE object into a KiCad BOARD object + * @brief Converts a CADSTAR_PCB_ARCHIVE_PARSER object into a KiCad BOARD object */ #include //KEY_COPPER, KEY_CORE, KEY_PREPREG #include -void CADSTAR_PCB::Load( CPA_FILE* aCPAfile ) +void CADSTAR_PCB::Load( BOARD* aBoard ) { - loadBoardStackup( aCPAfile ); + mBoard = aBoard; + Parse(); + loadBoardStackup(); //TODO: process all other items } -void CADSTAR_PCB::loadBoardStackup( CPA_FILE* aCPAfile ) +void CADSTAR_PCB::loadBoardStackup() { - std::map& cpaLayers = aCPAfile->Assignments.Layerdefs.Layers; - std::map& cpaMaterials = aCPAfile->Assignments.Layerdefs.Materials; - std::vector& cpaLayerStack = aCPAfile->Assignments.Layerdefs.LayerStack; - unsigned numElectricalAndPowerLayers = 0; - BOARD_DESIGN_SETTINGS& designSettings = mBoard->GetDesignSettings(); - BOARD_STACKUP& stackup = designSettings.GetStackupDescriptor(); - int noOfKiCadStackupLayers = 0; - int lastElectricalLayerIndex = 0; - int dielectricSublayer = 0; - int numDielectricLayers = 0; - bool prevWasDielectric = false; - BOARD_STACKUP_ITEM* tempKiCadLayer; - std::vector layerIDs; + std::map& cpaLayers = Assignments.Layerdefs.Layers; + std::map& cpaMaterials = Assignments.Layerdefs.Materials; + std::vector& cpaLayerStack = Assignments.Layerdefs.LayerStack; + unsigned numElecAndPowerLayers = 0; + BOARD_DESIGN_SETTINGS& designSettings = mBoard->GetDesignSettings(); + BOARD_STACKUP& stackup = designSettings.GetStackupDescriptor(); + int noOfKiCadStackupLayers = 0; + int lastElectricalLayerIndex = 0; + int dielectricSublayer = 0; + int numDielectricLayers = 0; + bool prevWasDielectric = false; + BOARD_STACKUP_ITEM* tempKiCadLayer; + std::vector layerIDs; //Remove all layers except required ones stackup.RemoveAll(); @@ -61,7 +63,7 @@ void CADSTAR_PCB::loadBoardStackup( CPA_FILE* aCPAfile ) for( auto it = cpaLayerStack.begin(); it != cpaLayerStack.end(); ++it ) { - CPA_LAYER curLayer = cpaLayers[*it]; + LAYER curLayer = cpaLayers[*it]; BOARD_STACKUP_ITEM_TYPE kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_UNDEFINED; LAYER_T copperType = LAYER_T::LT_UNDEFINED; PCB_LAYER_ID kicadLayerID = PCB_LAYER_ID::UNDEFINED_LAYER; @@ -70,7 +72,7 @@ void CADSTAR_PCB::loadBoardStackup( CPA_FILE* aCPAfile ) if( cpaLayers.count( *it ) == 0 ) wxASSERT_MSG( true, wxT( "Unable to find layer index" ) ); - if( prevWasDielectric && ( curLayer.Type != CPA_LAYER_TYPE::CONSTRUCTION ) ) + if( prevWasDielectric && ( curLayer.Type != LAYER_TYPE::CONSTRUCTION ) ) { stackup.Add( tempKiCadLayer ); //only add dielectric layers here after all are done dielectricSublayer = 0; @@ -80,34 +82,34 @@ void CADSTAR_PCB::loadBoardStackup( CPA_FILE* aCPAfile ) switch( curLayer.Type ) { - case CPA_LAYER_TYPE::ALLDOC: - case CPA_LAYER_TYPE::ALLELEC: - case CPA_LAYER_TYPE::ALLLAYER: - case CPA_LAYER_TYPE::ASSCOMPCOPP: - case CPA_LAYER_TYPE::NOLAYER: + case LAYER_TYPE::ALLDOC: + case LAYER_TYPE::ALLELEC: + case LAYER_TYPE::ALLLAYER: + case LAYER_TYPE::ASSCOMPCOPP: + case LAYER_TYPE::NOLAYER: //Shouldn't be here if CPA file is correctly parsed and not corrupt THROW_IO_ERROR( wxString::Format( _( "Unexpected layer '%s' in layer stack." ), curLayer.Name ) ); continue; - case CPA_LAYER_TYPE::JUMPERLAYER: + case LAYER_TYPE::JUMPERLAYER: copperType = LAYER_T::LT_JUMPER; - kicadLayerID = getKiCadCopperLayerID( numElectricalAndPowerLayers++ ); + kicadLayerID = getKiCadCopperLayerID( numElecAndPowerLayers++ ); kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_COPPER; layerTypeName = KEY_COPPER; break; - case CPA_LAYER_TYPE::ELEC: + case LAYER_TYPE::ELEC: copperType = LAYER_T::LT_SIGNAL; - kicadLayerID = getKiCadCopperLayerID( numElectricalAndPowerLayers++ ); + kicadLayerID = getKiCadCopperLayerID( numElecAndPowerLayers++ ); kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_COPPER; layerTypeName = KEY_COPPER; break; - case CPA_LAYER_TYPE::POWER: + case LAYER_TYPE::POWER: copperType = LAYER_T::LT_POWER; - kicadLayerID = getKiCadCopperLayerID( numElectricalAndPowerLayers++ ); + kicadLayerID = getKiCadCopperLayerID( numElecAndPowerLayers++ ); kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_COPPER; layerTypeName = KEY_COPPER; break; - case CPA_LAYER_TYPE::CONSTRUCTION: + case LAYER_TYPE::CONSTRUCTION: kicadLayerID = PCB_LAYER_ID::UNDEFINED_LAYER; kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_DIELECTRIC; prevWasDielectric = true; @@ -117,20 +119,20 @@ void CADSTAR_PCB::loadBoardStackup( CPA_FILE* aCPAfile ) //check electrical layers above and below to decide if current layer is prepreg // or core break; - case CPA_LAYER_TYPE::DOC: + case LAYER_TYPE::DOC: //TODO find out a suitable KiCad Layer alternative for this CADSTAR type continue; //ignore - case CPA_LAYER_TYPE::NONELEC: + case LAYER_TYPE::NONELEC: switch( curLayer.SubType ) { - case CPA_LAYER_SUBTYPE::LAYERSUBTYPE_ASSEMBLY: - case CPA_LAYER_SUBTYPE::LAYERSUBTYPE_NONE: - case CPA_LAYER_SUBTYPE::LAYERSUBTYPE_PLACEMENT: + case LAYER_SUBTYPE::LAYERSUBTYPE_ASSEMBLY: + case LAYER_SUBTYPE::LAYERSUBTYPE_NONE: + case LAYER_SUBTYPE::LAYERSUBTYPE_PLACEMENT: //TODO find out a suitable KiCad Layer alternative for these CADSTAR types continue; //ignore these layer types for now - case CPA_LAYER_SUBTYPE::LAYERSUBTYPE_PASTE: + case LAYER_SUBTYPE::LAYERSUBTYPE_PASTE: kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_SOLDERPASTE; - if( numElectricalAndPowerLayers > 0 ) + if( numElecAndPowerLayers > 0 ) { kicadLayerID = PCB_LAYER_ID::F_Paste; layerTypeName = _HKI( "Top Solder Paste" ); @@ -141,9 +143,9 @@ void CADSTAR_PCB::loadBoardStackup( CPA_FILE* aCPAfile ) layerTypeName = _HKI( "Bottom Solder Paste" ); } break; - case CPA_LAYER_SUBTYPE::LAYERSUBTYPE_SILKSCREEN: + case LAYER_SUBTYPE::LAYERSUBTYPE_SILKSCREEN: kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_SILKSCREEN; - if( numElectricalAndPowerLayers > 0 ) + if( numElecAndPowerLayers > 0 ) { kicadLayerID = PCB_LAYER_ID::F_SilkS; layerTypeName = _HKI( "Top Silk Screen" ); @@ -154,9 +156,9 @@ void CADSTAR_PCB::loadBoardStackup( CPA_FILE* aCPAfile ) layerTypeName = _HKI( "Bottom Silk Screen" ); } break; - case CPA_LAYER_SUBTYPE::LAYERSUBTYPE_SOLDERRESIST: + case LAYER_SUBTYPE::LAYERSUBTYPE_SOLDERRESIST: kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_SOLDERMASK; - if( numElectricalAndPowerLayers > 0 ) + if( numElecAndPowerLayers > 0 ) { kicadLayerID = PCB_LAYER_ID::F_Mask; layerTypeName = _HKI( "Top Solder Mask" ); @@ -195,7 +197,7 @@ void CADSTAR_PCB::loadBoardStackup( CPA_FILE* aCPAfile ) tempKiCadLayer->AddDielectricPrms( dielectricSublayer ); } - if( !curLayer.MaterialId.IsEmpty() ) + if( curLayer.MaterialId != UNDEFINED_MATERIAL_ID ) { tempKiCadLayer->SetMaterial( cpaMaterials[curLayer.MaterialId].Name, dielectricSublayer ); @@ -206,8 +208,8 @@ void CADSTAR_PCB::loadBoardStackup( CPA_FILE* aCPAfile ) //TODO add Resistivity when KiCad supports it } - int unitMultiplier = aCPAfile->KiCadUnitMultiplier; - tempKiCadLayer->SetThickness( curLayer.Thickness * unitMultiplier, dielectricSublayer ); + tempKiCadLayer->SetThickness( + curLayer.Thickness * KiCadUnitMultiplier, dielectricSublayer ); wxASSERT( layerTypeName != wxEmptyString ); tempKiCadLayer->SetTypeName( layerTypeName ); @@ -250,7 +252,7 @@ void CADSTAR_PCB::loadBoardStackup( CPA_FILE* aCPAfile ) mBoard->SetEnabledLayers( LSET( &layerIDs[0], layerIDs.size() ) ); mBoard->SetVisibleLayers( LSET( &layerIDs[0], layerIDs.size() ) ); - mBoard->SetCopperLayerCount( numElectricalAndPowerLayers ); + mBoard->SetCopperLayerCount( numElecAndPowerLayers ); } diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb.h b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb.h index c854fe46e6..3a8ca8b754 100644 --- a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb.h +++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb.h @@ -20,7 +20,7 @@ /** * @file cadstar_pcb.h - * @brief Converts a CPA_FILE object into a KiCad BOARD object + * @brief Converts a CADSTAR_PCB_ARCHIVE_PARSER object into a KiCad BOARD object */ #ifndef CADSTAR_PCB_H_ @@ -30,25 +30,25 @@ class BOARD; -class CADSTAR_PCB +class CADSTAR_PCB : public CADSTAR_PCB_ARCHIVE_PARSER { public: - explicit CADSTAR_PCB( BOARD* aBoard ) : mBoard( aBoard ) + explicit CADSTAR_PCB( wxString aFilename ) : CADSTAR_PCB_ARCHIVE_PARSER( aFilename ) { } /** - * @brief Loads a CADSTAR PCB Archive into the KiCad BOARD - * @param aCPAfile + * @brief Loads a CADSTAR PCB Archive file into the KiCad BOARD object given + * @param aBoard */ - void Load( CPA_FILE* aCPAfile ); + void Load( BOARD* aBoard ); private: - BOARD* mBoard; - std::map mLayermap; // mCopperLayers; - void loadBoardStackup( CPA_FILE* aCPAfile ); - PCB_LAYER_ID getKiCadCopperLayerID( unsigned int aLayerNum ); + BOARD* mBoard; + std::map mLayermap; // mCopperLayers; + void loadBoardStackup(); + PCB_LAYER_ID getKiCadCopperLayerID( unsigned int aLayerNum ); }; diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.cpp b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.cpp index 23d940afdc..08d6e2a868 100644 --- a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.cpp +++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.cpp @@ -27,10 +27,9 @@ #include // pow() -void CPA_FILE::Parse() +void CADSTAR_PCB_ARCHIVE_PARSER::Parse() { - XNODE* fileRootNode = - CADSTAR_COMMON::LoadArchiveFile( Filename, CADSTAR_COMMON::FILE_TYPE::PCB_ARCHIVE ); + XNODE* fileRootNode = LoadArchiveFile( Filename, wxT( "CADSTARPCB" ) ); XNODE* cNode = fileRootNode->GetChildren(); @@ -46,7 +45,7 @@ void CPA_FILE::Parse() switch( Header.Resolution ) { - case CPA_RESOLUTION::HUNDREDTH_MICRON: + case RESOLUTION::HUNDREDTH_MICRON: KiCadUnitMultiplier = 10; break; @@ -57,6 +56,8 @@ void CPA_FILE::Parse() } else if( cNode->GetName() == wxT( "ASSIGNMENTS" ) ) Assignments.Parse( cNode ); + else if( cNode->GetName() == wxT( "LIBRARY" ) ) + Library.Parse( cNode ); //TODO need to parse everything else! } @@ -72,7 +73,75 @@ void CPA_FILE::Parse() } -void CPA_ASSIGNMENTS::Parse( XNODE* aNode ) +CADSTAR_PCB_ARCHIVE_PARSER::ALIGNMENT CADSTAR_PCB_ARCHIVE_PARSER::ParseAlignment( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "ALIGN" ) ); + + wxString alignmentStr = GetXmlAttributeIDString( aNode, 0 ); + + if( alignmentStr == wxT( "BOTTOMCENTER" ) ) + return ALIGNMENT::BOTTOMCENTER; + else if( alignmentStr == wxT( "BOTTOMLEFT" ) ) + return ALIGNMENT::BOTTOMLEFT; + else if( alignmentStr == wxT( "BOTTOMRIGHT" ) ) + return ALIGNMENT::BOTTOMRIGHT; + else if( alignmentStr == wxT( "CENTERCENTER" ) ) + return ALIGNMENT::CENTERCENTER; + else if( alignmentStr == wxT( "CENTERLEFT" ) ) + return ALIGNMENT::CENTERLEFT; + else if( alignmentStr == wxT( "CENTERRIGHT" ) ) + return ALIGNMENT::CENTERRIGHT; + else if( alignmentStr == wxT( "TOPCENTER" ) ) + return ALIGNMENT::TOPCENTER; + else if( alignmentStr == wxT( "TOPLEFT" ) ) + return ALIGNMENT::TOPLEFT; + else if( alignmentStr == wxT( "TOPRIGHT" ) ) + return ALIGNMENT::TOPRIGHT; + else + THROW_UNKNOWN_PARAMETER_IO_ERROR( alignmentStr, wxT( "ALIGN" ) ); + + //shouldn't be here but avoids compiler warning + return ALIGNMENT::NO_ALIGNMENT; +} + + +CADSTAR_PCB_ARCHIVE_PARSER::JUSTIFICATION CADSTAR_PCB_ARCHIVE_PARSER::ParseJustification( + XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "JUSTIFICATION" ) ); + + wxString justificationStr = GetXmlAttributeIDString( aNode, 0 ); + + if( justificationStr == wxT( "LEFT" ) ) + return JUSTIFICATION::LEFT; + else if( justificationStr == wxT( "RIGHT" ) ) + return JUSTIFICATION::RIGHT; + else if( justificationStr == wxT( "CENTER" ) ) + return JUSTIFICATION::CENTER; + else + THROW_UNKNOWN_PARAMETER_IO_ERROR( justificationStr, wxT( "JUSTIFICATION" ) ); + + return JUSTIFICATION::LEFT; +} + +CADSTAR_PCB_ARCHIVE_PARSER::ANGUNITS CADSTAR_PCB_ARCHIVE_PARSER::ParseAngunits( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "ANGUNITS" ) ); + + wxString angUnitStr = GetXmlAttributeIDString( aNode, 0 ); + + if( angUnitStr == wxT( "DEGREES" ) ) + return ANGUNITS::DEGREES; + else if( angUnitStr == wxT( "RADIANS" ) ) + return ANGUNITS::RADIANS; + else + THROW_UNKNOWN_PARAMETER_IO_ERROR( angUnitStr, aNode->GetName() ); + + return ANGUNITS(); +} + + +void CADSTAR_PCB_ARCHIVE_PARSER::ASSIGNMENTS::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "ASSIGNMENTS" ) ); @@ -105,7 +174,7 @@ void CPA_ASSIGNMENTS::Parse( XNODE* aNode ) } -void CPA_LAYERDEFS::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::LAYERDEFS::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "LAYERDEFS" ) ); @@ -126,29 +195,29 @@ void CPA_LAYERDEFS::Parse( XNODE* aNode ) for( ; xmlAttribute; xmlAttribute = xmlAttribute->GetNext() ) { - LayerStack.push_back( xmlAttribute->GetValue() ); + LayerStack.push_back( (LAYER_ID) xmlAttribute->GetValue() ); } - CADSTAR_COMMON::CheckNoChildNodes( cNode ); + CheckNoChildNodes( cNode ); } else if( nodeName == wxT( "MATERIAL" ) ) { - CPA_MATERIAL material; + MATERIAL material; //TODO try.. catch + throw again with more detailed error information material.Parse( cNode ); Materials.insert( std::make_pair( material.ID, material ) ); } else if( nodeName == wxT( "LAYER" ) ) { - CPA_LAYER layer; + LAYER layer; //TODO try.. catch + throw again with more detailed error information layer.Parse( cNode ); Layers.insert( std::make_pair( layer.ID, layer ) ); } else if( nodeName == wxT( "SWAPPAIR" ) ) { - wxString layerId = CADSTAR_COMMON::GetAttributeID( cNode, 0 ); - wxString swapLayerId = CADSTAR_COMMON::GetAttributeID( cNode, 1 ); + LAYER_ID layerId = (LAYER_ID) GetXmlAttributeIDString( cNode, 0 ); + LAYER_ID swapLayerId = (LAYER_ID) GetXmlAttributeIDString( cNode, 1 ); Layers[layerId].SwapLayerID = swapLayerId; } @@ -160,9 +229,9 @@ void CPA_LAYERDEFS::Parse( XNODE* aNode ) } -void CPA_CODEDEFS::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::CODEDEFS::Parse( XNODE* aNode ) { - wxASSERT( aNode->GetName() != wxT( "CODEDEFS" ) ); + wxASSERT( aNode->GetName() == wxT( "CODEDEFS" ) ); XNODE* cNode = aNode->GetChildren(); @@ -172,91 +241,91 @@ void CPA_CODEDEFS::Parse( XNODE* aNode ) if( nodeName == wxT( "LINECODE" ) ) { - CPA_LINECODE linecode; + LINECODE linecode; //TODO try.. catch + throw again with more detailed error information linecode.Parse( cNode ); LineCodes.insert( std::make_pair( linecode.ID, linecode ) ); } else if( nodeName == wxT( "HATCHCODE" ) ) { - CPA_HATCHCODE hatchcode; + HATCHCODE hatchcode; //TODO try.. catch + throw again with more detailed error information hatchcode.Parse( cNode ); HatchCodes.insert( std::make_pair( hatchcode.ID, hatchcode ) ); } else if( nodeName == wxT( "TEXTCODE" ) ) { - CPA_TEXTCODE textcode; + TEXTCODE textcode; //TODO try.. catch + throw again with more detailed error information textcode.Parse( cNode ); TextCodes.insert( std::make_pair( textcode.ID, textcode ) ); } else if( nodeName == wxT( "ROUTECODE" ) ) { - CPA_ROUTECODE routecode; + ROUTECODE routecode; //TODO try.. catch + throw again with more detailed error information routecode.Parse( cNode ); RouteCodes.insert( std::make_pair( routecode.ID, routecode ) ); } else if( nodeName == wxT( "COPPERCODE" ) ) { - CPA_COPPERCODE coppercode; + COPPERCODE coppercode; //TODO try.. catch + throw again with more detailed error information coppercode.Parse( cNode ); CopperCodes.insert( std::make_pair( coppercode.ID, coppercode ) ); } else if( nodeName == wxT( "SPACINGCODE" ) ) { - CPA_SPACINGCODE spacingcode; + SPACINGCODE spacingcode; //TODO try.. catch + throw again with more detailed error information spacingcode.Parse( cNode ); SpacingCodes.push_back( spacingcode ); } else if( nodeName == wxT( "PADCODE" ) ) { - CPA_PADCODE padcode; + PADCODE padcode; //TODO try.. catch + throw again with more detailed error information padcode.Parse( cNode ); PadCodes.insert( std::make_pair( padcode.ID, padcode ) ); } else if( nodeName == wxT( "VIACODE" ) ) { - CPA_VIACODE viacode; + VIACODE viacode; //TODO try.. catch + throw again with more detailed error information viacode.Parse( cNode ); ViaCodes.insert( std::make_pair( viacode.ID, viacode ) ); } else if( nodeName == wxT( "LAYERPAIR" ) ) { - CPA_LAYERPAIR layerpair; + LAYERPAIR layerpair; //TODO try.. catch + throw again with more detailed error information layerpair.Parse( cNode ); LayerPairs.insert( std::make_pair( layerpair.ID, layerpair ) ); } else if( nodeName == wxT( "ATTRNAME" ) ) { - CPA_ATTRNAME attrname; + ATTRNAME attrname; //TODO try.. catch + throw again with more detailed error information attrname.Parse( cNode ); AttributeNames.insert( std::make_pair( attrname.ID, attrname ) ); } else if( nodeName == wxT( "NETCLASS" ) ) { - CPA_NETCLASS netclass; + NETCLASS netclass; //TODO try.. catch + throw again with more detailed error information netclass.Parse( cNode ); NetClasses.insert( std::make_pair( netclass.ID, netclass ) ); } else if( nodeName == wxT( "SPCCLASSNAME" ) ) { - CPA_SPCCLASSNAME spcclassname; + SPCCLASSNAME spcclassname; //TODO try.. catch + throw again with more detailed error information spcclassname.Parse( cNode ); SpacingClassNames.insert( std::make_pair( spcclassname.ID, spcclassname ) ); } else if( nodeName == wxT( "SPCCLASSSPACE" ) ) { - CPA_SPCCLASSSPACE spcclassspace; + SPCCLASSSPACE spcclassspace; //TODO try.. catch + throw again with more detailed error information spcclassspace.Parse( cNode ); SpacingClasses.push_back( spcclassspace ); @@ -269,28 +338,28 @@ void CPA_CODEDEFS::Parse( XNODE* aNode ) } -void CPA_MATERIAL::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::MATERIAL::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "MATERIAL" ) ); //Process Name & ID - ID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - Name = CADSTAR_COMMON::GetAttributeID( aNode, 1 ); + ID = GetXmlAttributeIDString( aNode, 0 ); + Name = GetXmlAttributeIDString( aNode, 1 ); //Process Type - wxString sType = CADSTAR_COMMON::GetAttributeID( aNode, 2 ); + wxString sType = GetXmlAttributeIDString( aNode, 2 ); if( sType == wxT( "CONSTRUCTION" ) ) { - Type = CPA_MATERIAL_LAYER_TYPE::CONSTRUCTION; + Type = MATERIAL_LAYER_TYPE::CONSTRUCTION; } else if( sType == wxT( "ELECTRICAL" ) ) { - Type = CPA_MATERIAL_LAYER_TYPE::ELECTRICAL; + Type = MATERIAL_LAYER_TYPE::ELECTRICAL; } else if( sType == wxT( "NONELEC" ) ) { - Type = CPA_MATERIAL_LAYER_TYPE::NON_ELECTRICAL; + Type = MATERIAL_LAYER_TYPE::NON_ELECTRICAL; } else { @@ -311,17 +380,17 @@ void CPA_MATERIAL::Parse( XNODE* aNode ) if( nodeName == wxT( "RELPERMIT" ) ) { //TODO try.. catch + throw again with more detailed error information - CADSTAR_COMMON::ParseChildEValue( iNode, Permittivity ); + ParseChildEValue( iNode, Permittivity ); } else if( nodeName == wxT( "LOSSTANGENT" ) ) { //TODO try.. catch + throw again with more detailed error information - CADSTAR_COMMON::ParseChildEValue( iNode, LossTangent ); + ParseChildEValue( iNode, LossTangent ); } else if( nodeName == wxT( "RESISTIVITY" ) ) { //TODO try.. catch + throw again with more detailed error information - CADSTAR_COMMON::ParseChildEValue( iNode, Resistivity ); + ParseChildEValue( iNode, Resistivity ); } else { @@ -331,13 +400,13 @@ void CPA_MATERIAL::Parse( XNODE* aNode ) } -void CPA_LAYER::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::LAYER::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "LAYER" ) ); //Process Name & ID - ID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - Name = CADSTAR_COMMON::GetAttributeID( aNode, 1 ); + ID = GetXmlAttributeIDString( aNode, 0 ); + Name = GetXmlAttributeIDString( aNode, 1 ); XNODE* cNode = aNode->GetChildren(); auto processLayerMaterialDetails = [&]() { @@ -349,9 +418,9 @@ void CPA_LAYER::Parse( XNODE* aNode ) if( tempNodeName == wxT( "MAKE" ) ) { //Process material ID and layer width - MaterialId = CADSTAR_COMMON::GetAttributeID( tempNode, 0 ); + MaterialId = GetXmlAttributeIDString( tempNode, 0 ); - Thickness = CADSTAR_COMMON::GetAttributeIDLong( tempNode, 1 ); + Thickness = GetXmlAttributeIDLong( tempNode, 1 ); XNODE* childOfTempNode = tempNode->GetChildren(); @@ -359,16 +428,15 @@ void CPA_LAYER::Parse( XNODE* aNode ) { if( childOfTempNode->GetName() == wxT( "EMBEDS" ) ) { - // if( UPWARDS - wxString embedsValue = CADSTAR_COMMON::GetAttributeID( childOfTempNode, 0 ); + wxString embedsValue = GetXmlAttributeIDString( childOfTempNode, 0 ); if( embedsValue == wxT( "UPWARDS" ) ) { - Embedding = CPA_EMBEDDING::ABOVE; + Embedding = EMBEDDING::ABOVE; } else if( embedsValue == wxT( "DOWNWARDS" ) ) { - Embedding = CPA_EMBEDDING::BELOW; + Embedding = EMBEDDING::BELOW; } else { @@ -385,27 +453,27 @@ void CPA_LAYER::Parse( XNODE* aNode ) } else if( tempNodeName == wxT( "BIAS" ) ) { - wxString bias = CADSTAR_COMMON::GetAttributeID( tempNode, 0 ); + wxString bias = GetXmlAttributeIDString( tempNode, 0 ); if( bias == wxT( "X_BIASED" ) ) { - RoutingBias = CPA_ROUTING_BIAS::X; + RoutingBias = ROUTING_BIAS::X; } else if( bias == wxT( "Y_BIASED" ) ) { - RoutingBias = CPA_ROUTING_BIAS::Y; + RoutingBias = ROUTING_BIAS::Y; } else if( bias == wxT( "ANTITRACK" ) ) { - RoutingBias = CPA_ROUTING_BIAS::ANTI_ROUTE; + RoutingBias = ROUTING_BIAS::ANTI_ROUTE; } else if( bias == wxT( "OBSTACLE" ) ) { - RoutingBias = CPA_ROUTING_BIAS::OBSTACLE; + RoutingBias = ROUTING_BIAS::OBSTACLE; } else if( bias == wxT( "UNBIASED" ) ) { - RoutingBias = CPA_ROUTING_BIAS::UNBIASED; + RoutingBias = ROUTING_BIAS::UNBIASED; } else { @@ -428,91 +496,79 @@ void CPA_LAYER::Parse( XNODE* aNode ) if( cNodeName == wxT( "ALLDOC" ) ) { - Type = CPA_LAYER_TYPE::ALLDOC; + Type = LAYER_TYPE::ALLDOC; } else if( cNodeName == wxT( "ALLELEC" ) ) { - Type = CPA_LAYER_TYPE::ALLELEC; + Type = LAYER_TYPE::ALLELEC; } else if( cNodeName == wxT( "ALLLAYER" ) ) { - Type = CPA_LAYER_TYPE::ALLLAYER; + Type = LAYER_TYPE::ALLLAYER; } else if( cNodeName == wxT( "ASSCOMPCOPP" ) ) { - Type = CPA_LAYER_TYPE::ASSCOMPCOPP; + Type = LAYER_TYPE::ASSCOMPCOPP; } else if( cNodeName == wxT( "JUMPERLAYER" ) ) { - Type = CPA_LAYER_TYPE::JUMPERLAYER; + Type = LAYER_TYPE::JUMPERLAYER; } else if( cNodeName == wxT( "NOLAYER" ) ) { - Type = CPA_LAYER_TYPE::NOLAYER; + Type = LAYER_TYPE::NOLAYER; } else if( cNodeName == wxT( "POWER" ) ) { - Type = CPA_LAYER_TYPE::POWER; - - if( !CADSTAR_COMMON::GetAttributeID( cNode, 0 ).ToLong( &PhysicalLayer ) ) - THROW_PARSING_IO_ERROR( - wxT( "Physical Layer" ), wxString::Format( "LAYER %s", Name ) ); - + Type = LAYER_TYPE::POWER; + PhysicalLayer = GetXmlAttributeIDLong( cNode, 0 ); processLayerMaterialDetails(); } else if( cNodeName == wxT( "DOC" ) ) { - Type = CPA_LAYER_TYPE::DOC; + Type = LAYER_TYPE::DOC; } else if( cNodeName == wxT( "CONSTRUCTION" ) ) { - Type = CPA_LAYER_TYPE::CONSTRUCTION; + Type = LAYER_TYPE::CONSTRUCTION; processLayerMaterialDetails(); } else if( cNodeName == wxT( "ELEC" ) ) { - Type = CPA_LAYER_TYPE::ELEC; - - if( !CADSTAR_COMMON::GetAttributeID( cNode, 0 ).ToLong( &PhysicalLayer ) ) - THROW_PARSING_IO_ERROR( - wxT( "Physical Layer" ), wxString::Format( "LAYER %s", Name ) ); - + Type = LAYER_TYPE::ELEC; + PhysicalLayer = GetXmlAttributeIDLong( cNode, 0 ); processLayerMaterialDetails(); } else if( cNodeName == wxT( "NONELEC" ) ) { - Type = CPA_LAYER_TYPE::NONELEC; - - if( !CADSTAR_COMMON::GetAttributeID( cNode, 0 ).ToLong( &PhysicalLayer ) ) - THROW_PARSING_IO_ERROR( - wxT( "Physical Layer" ), wxString::Format( "LAYER %s", Name ) ); - + Type = LAYER_TYPE::NONELEC; + PhysicalLayer = GetXmlAttributeIDLong( cNode, 0 ); processLayerMaterialDetails(); } else if( cNodeName == wxT( "LASUBTYP" ) ) { //Process subtype - wxString sSubType = CADSTAR_COMMON::GetAttributeID( cNode, 0 ); + wxString sSubType = GetXmlAttributeIDString( cNode, 0 ); if( sSubType == wxT( "LAYERSUBTYPE_ASSEMBLY" ) ) { - this->SubType = CPA_LAYER_SUBTYPE::LAYERSUBTYPE_ASSEMBLY; + this->SubType = LAYER_SUBTYPE::LAYERSUBTYPE_ASSEMBLY; } else if( sSubType == wxT( "LAYERSUBTYPE_PASTE" ) ) { - this->SubType = CPA_LAYER_SUBTYPE::LAYERSUBTYPE_PASTE; + this->SubType = LAYER_SUBTYPE::LAYERSUBTYPE_PASTE; } else if( sSubType == wxT( "LAYERSUBTYPE_PLACEMENT" ) ) { - this->SubType = CPA_LAYER_SUBTYPE::LAYERSUBTYPE_PLACEMENT; + this->SubType = LAYER_SUBTYPE::LAYERSUBTYPE_PLACEMENT; } else if( sSubType == wxT( "LAYERSUBTYPE_SILKSCREEN" ) ) { - this->SubType = CPA_LAYER_SUBTYPE::LAYERSUBTYPE_SILKSCREEN; + this->SubType = LAYER_SUBTYPE::LAYERSUBTYPE_SILKSCREEN; } else if( sSubType == wxT( "LAYERSUBTYPE_SOLDERRESIST" ) ) { - this->SubType = CPA_LAYER_SUBTYPE::LAYERSUBTYPE_SOLDERRESIST; + this->SubType = LAYER_SUBTYPE::LAYERSUBTYPE_SOLDERRESIST; } else { @@ -528,31 +584,31 @@ void CPA_LAYER::Parse( XNODE* aNode ) } -void CPA_FORMAT::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::FORMAT::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "FORMAT" ) ); - Type = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - SomeInt = CADSTAR_COMMON::GetAttributeIDLong( aNode, 1 ); - Version = CADSTAR_COMMON::GetAttributeIDLong( aNode, 2 ); + Type = GetXmlAttributeIDString( aNode, 0 ); + SomeInt = GetXmlAttributeIDLong( aNode, 1 ); + Version = GetXmlAttributeIDLong( aNode, 2 ); } -void CPA_TIMESTAMP::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::TIMESTAMP::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "TIMESTAMP" ) ); - if( !CADSTAR_COMMON::GetAttributeID( aNode, 0 ).ToLong( &Year ) - || !CADSTAR_COMMON::GetAttributeID( aNode, 1 ).ToLong( &Month ) - || !CADSTAR_COMMON::GetAttributeID( aNode, 2 ).ToLong( &Day ) - || !CADSTAR_COMMON::GetAttributeID( aNode, 3 ).ToLong( &Hour ) - || !CADSTAR_COMMON::GetAttributeID( aNode, 4 ).ToLong( &Minute ) - || !CADSTAR_COMMON::GetAttributeID( aNode, 5 ).ToLong( &Second ) ) + if( !GetXmlAttributeIDString( aNode, 0 ).ToLong( &Year ) + || !GetXmlAttributeIDString( aNode, 1 ).ToLong( &Month ) + || !GetXmlAttributeIDString( aNode, 2 ).ToLong( &Day ) + || !GetXmlAttributeIDString( aNode, 3 ).ToLong( &Hour ) + || !GetXmlAttributeIDString( aNode, 4 ).ToLong( &Minute ) + || !GetXmlAttributeIDString( aNode, 5 ).ToLong( &Second ) ) THROW_PARSING_IO_ERROR( wxT( "TIMESTAMP" ), wxString::Format( "HEADER" ) ); } -void CPA_HEADER::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::HEADER::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "HEADER" ) ); @@ -563,22 +619,26 @@ void CPA_HEADER::Parse( XNODE* aNode ) wxString nodeName = cNode->GetName(); if( nodeName == wxT( "FORMAT" ) ) - //TODO try.. catch + throw again with more detailed error information + { //TODO try.. catch + throw again with more detailed error information Format.Parse( cNode ); + + if( Format.Type != wxT( "LAYOUT" ) ) + THROW_IO_ERROR( "Not a CADSTAR PCB Layout file!" ); + } else if( nodeName == wxT( "JOBFILE" ) ) - JobFile = CADSTAR_COMMON::GetAttributeID( cNode, 0 ); + JobFile = GetXmlAttributeIDString( cNode, 0 ); else if( nodeName == wxT( "JOBTITLE" ) ) - JobTitle = CADSTAR_COMMON::GetAttributeID( cNode, 0 ); + JobTitle = GetXmlAttributeIDString( cNode, 0 ); else if( nodeName == wxT( "GENERATOR" ) ) - Generator = CADSTAR_COMMON::GetAttributeID( cNode, 0 ); + Generator = GetXmlAttributeIDString( cNode, 0 ); else if( nodeName == wxT( "RESOLUTION" ) ) { XNODE* subNode = cNode->GetChildren(); if( ( subNode->GetName() == wxT( "METRIC" ) ) - && ( CADSTAR_COMMON::GetAttributeID( subNode, 0 ) == wxT( "HUNDREDTH" ) ) - && ( CADSTAR_COMMON::GetAttributeID( subNode, 1 ) == wxT( "MICRON" ) ) ) + && ( GetXmlAttributeIDString( subNode, 0 ) == wxT( "HUNDREDTH" ) ) + && ( GetXmlAttributeIDString( subNode, 1 ) == wxT( "MICRON" ) ) ) { - Resolution = CPA_RESOLUTION::HUNDREDTH_MICRON; + Resolution = RESOLUTION::HUNDREDTH_MICRON; } else //TODO Need to find out if there are other possible resolutions. Logically // there must be other base units that could be used, such as "IMPERIAL INCH" @@ -595,15 +655,15 @@ void CPA_HEADER::Parse( XNODE* aNode ) } -void CPA_LINECODE::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::LINECODE::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "LINECODE" ) ); //Process Name & ID - ID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - Name = CADSTAR_COMMON::GetAttributeID( aNode, 1 ); + ID = GetXmlAttributeIDString( aNode, 0 ); + Name = GetXmlAttributeIDString( aNode, 1 ); - if( !CADSTAR_COMMON::GetAttributeID( aNode, 2 ).ToLong( &Width ) ) + if( !GetXmlAttributeIDString( aNode, 2 ).ToLong( &Width ) ) THROW_PARSING_IO_ERROR( wxT( "Line Width" ), wxString::Format( "LINECODE -> %s", Name ) ); XNODE* cNode = aNode->GetChildren(); @@ -611,47 +671,47 @@ void CPA_LINECODE::Parse( XNODE* aNode ) if( cNode->GetName() != wxT( "STYLE" ) ) THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), wxString::Format( "LINECODE -> %s", Name ) ); - wxString styleStr = CADSTAR_COMMON::GetAttributeID( cNode, 0 ); + wxString styleStr = GetXmlAttributeIDString( cNode, 0 ); if( styleStr == wxT( "SOLID" ) ) - Style = CPA_LINESTYLE::SOLID; + Style = LINESTYLE::SOLID; else if( styleStr == wxT( "DASH" ) ) - Style = CPA_LINESTYLE::DASH; + Style = LINESTYLE::DASH; else if( styleStr == wxT( "DASHDOT" ) ) - Style = CPA_LINESTYLE::DASHDOT; + Style = LINESTYLE::DASHDOT; else if( styleStr == wxT( "DASHDOTDOT" ) ) - Style = CPA_LINESTYLE::DASHDOTDOT; + Style = LINESTYLE::DASHDOTDOT; else if( styleStr == wxT( "DOT" ) ) - Style = CPA_LINESTYLE::DOT; + Style = LINESTYLE::DOT; else THROW_UNKNOWN_PARAMETER_IO_ERROR( wxString::Format( "STYLE %s", styleStr ), wxString::Format( "LINECODE -> %s", Name ) ); } -void CPA_HATCH::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::HATCH::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "HATCH" ) ); - Step = CADSTAR_COMMON::GetAttributeIDLong( aNode, 0 ); - LineWidth = CADSTAR_COMMON::GetAttributeIDLong( aNode, 2 ); + Step = GetXmlAttributeIDLong( aNode, 0 ); + LineWidth = GetXmlAttributeIDLong( aNode, 2 ); XNODE* cNode = aNode->GetChildren(); if( !cNode || cNode->GetName() != wxT( "ORIENT" ) ) THROW_MISSING_NODE_IO_ERROR( wxT( "ORIENT" ), wxT( "HATCH" ) ); - OrientAngle = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + OrientAngle = GetXmlAttributeIDLong( cNode, 0 ); } -void CPA_HATCHCODE::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::HATCHCODE::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "HATCHCODE" ) ); //Process Name & ID - ID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - Name = CADSTAR_COMMON::GetAttributeID( aNode, 1 ); + ID = GetXmlAttributeIDString( aNode, 0 ); + Name = GetXmlAttributeIDString( aNode, 1 ); XNODE* cNode = aNode->GetChildren(); wxString location = wxString::Format( "HATCHCODE -> %s", Name ); @@ -661,7 +721,7 @@ void CPA_HATCHCODE::Parse( XNODE* aNode ) if( cNode->GetName() != wxT( "HATCH" ) ) THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), location ); - CPA_HATCH hatch; + HATCH hatch; //TODO try.. catch + throw again with more detailed error information hatch.Parse( cNode ); Hatches.push_back( hatch ); @@ -669,13 +729,13 @@ void CPA_HATCHCODE::Parse( XNODE* aNode ) } -void CPA_FONT::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::FONT::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "FONT" ) ); - Name = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - Modifier1 = CADSTAR_COMMON::GetAttributeIDLong( aNode, 1 ); - Modifier2 = CADSTAR_COMMON::GetAttributeIDLong( aNode, 2 ); + Name = GetXmlAttributeIDString( aNode, 0 ); + Modifier1 = GetXmlAttributeIDLong( aNode, 1 ); + Modifier2 = GetXmlAttributeIDLong( aNode, 2 ); XNODE* cNode = aNode->GetChildren(); @@ -692,17 +752,17 @@ void CPA_FONT::Parse( XNODE* aNode ) } } -void CPA_TEXTCODE::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::TEXTCODE::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "TEXTCODE" ) ); //Process Name & ID - ID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - Name = CADSTAR_COMMON::GetAttributeID( aNode, 1 ); + ID = GetXmlAttributeIDString( aNode, 0 ); + Name = GetXmlAttributeIDString( aNode, 1 ); - LineWidth = CADSTAR_COMMON::GetAttributeIDLong( aNode, 2 ); - Height = CADSTAR_COMMON::GetAttributeIDLong( aNode, 3 ); - Width = CADSTAR_COMMON::GetAttributeIDLong( aNode, 4 ); + LineWidth = GetXmlAttributeIDLong( aNode, 2 ); + Height = GetXmlAttributeIDLong( aNode, 3 ); + Width = GetXmlAttributeIDLong( aNode, 4 ); XNODE* cNode = aNode->GetChildren(); @@ -717,15 +777,15 @@ void CPA_TEXTCODE::Parse( XNODE* aNode ) } -void CPA_ROUTECODE::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::ROUTECODE::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "ROUTECODE" ) ); //Process Name & ID - ID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - Name = CADSTAR_COMMON::GetAttributeID( aNode, 1 ); + ID = GetXmlAttributeIDString( aNode, 0 ); + Name = GetXmlAttributeIDString( aNode, 1 ); - OptimalWidth = CADSTAR_COMMON::GetAttributeIDLong( aNode, 2 ); + OptimalWidth = GetXmlAttributeIDLong( aNode, 2 ); XNODE* cNode = aNode->GetChildren(); @@ -734,36 +794,36 @@ void CPA_ROUTECODE::Parse( XNODE* aNode ) wxString cNodeName = cNode->GetName(); if( cNodeName == wxT( "NECKWIDTH" ) ) - NeckedWidth = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + NeckedWidth = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "MINWIDTH" ) ) - MinWidth = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + MinWidth = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "MAXWIDTH" ) ) - MaxWidth = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + MaxWidth = GetXmlAttributeIDLong( cNode, 0 ); else THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() ); } } -void CPA_COPREASSIGN::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::COPREASSIGN::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "COPREASSIGN" ) ); - LayerID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); + LayerID = GetXmlAttributeIDString( aNode, 0 ); - CopperWidth = CADSTAR_COMMON::GetAttributeIDLong( aNode, 1 ); + CopperWidth = GetXmlAttributeIDLong( aNode, 1 ); } -void CPA_COPPERCODE::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::COPPERCODE::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "COPPERCODE" ) ); //Process Name & ID - ID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - Name = CADSTAR_COMMON::GetAttributeID( aNode, 1 ); + ID = GetXmlAttributeIDString( aNode, 0 ); + Name = GetXmlAttributeIDString( aNode, 1 ); - CopperWidth = CADSTAR_COMMON::GetAttributeIDLong( aNode, 2 ); + CopperWidth = GetXmlAttributeIDLong( aNode, 2 ); XNODE* cNode = aNode->GetChildren(); @@ -772,7 +832,7 @@ void CPA_COPPERCODE::Parse( XNODE* aNode ) if( cNode->GetName() == wxT( "COPREASSIGN" ) ) { //TODO try.. catch + throw again with more detailed error information - CPA_COPREASSIGN reassign; + CADSTAR_PCB_ARCHIVE_PARSER::COPREASSIGN reassign; reassign.Parse( cNode ); Reassigns.push_back( reassign ); } @@ -782,17 +842,17 @@ void CPA_COPPERCODE::Parse( XNODE* aNode ) } -void CPA_SPACINGCODE::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::SPACINGCODE::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "SPACINGCODE" ) ); - Code = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); + Code = GetXmlAttributeIDString( aNode, 0 ); - Spacing = CADSTAR_COMMON::GetAttributeIDLong( aNode, 1 ); + Spacing = GetXmlAttributeIDLong( aNode, 1 ); } -bool CPA_PAD_SHAPE::IsShape( XNODE* aNode ) +bool CADSTAR_PCB_ARCHIVE_PARSER::PAD_SHAPE::IsPadShape( XNODE* aNode ) { wxString aNodeName = aNode->GetName(); @@ -806,92 +866,92 @@ bool CPA_PAD_SHAPE::IsShape( XNODE* aNode ) } -void CPA_PAD_SHAPE::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::PAD_SHAPE::Parse( XNODE* aNode ) { - wxASSERT( IsShape( aNode ) ); + wxASSERT( IsPadShape( aNode ) ); wxString aNodeName = aNode->GetName(); if( aNodeName == wxT( "ANNULUS" ) ) - ShapeType = CPA_SHAPE_TYPE::ANNULUS; + ShapeType = PAD_SHAPE_TYPE::ANNULUS; else if( aNodeName == wxT( "BULLET" ) ) - ShapeType = CPA_SHAPE_TYPE::BULLET; + ShapeType = PAD_SHAPE_TYPE::BULLET; else if( aNodeName == wxT( "ROUND" ) ) - ShapeType = CPA_SHAPE_TYPE::CIRCLE; + ShapeType = PAD_SHAPE_TYPE::CIRCLE; else if( aNodeName == wxT( "DIAMOND" ) ) - ShapeType = CPA_SHAPE_TYPE::DIAMOND; + ShapeType = PAD_SHAPE_TYPE::DIAMOND; else if( aNodeName == wxT( "FINGER" ) ) - ShapeType = CPA_SHAPE_TYPE::FINGER; + ShapeType = PAD_SHAPE_TYPE::FINGER; else if( aNodeName == wxT( "OCTAGON" ) ) - ShapeType = CPA_SHAPE_TYPE::OCTAGON; + ShapeType = PAD_SHAPE_TYPE::OCTAGON; else if( aNodeName == wxT( "RECTANGLE" ) ) - ShapeType = CPA_SHAPE_TYPE::RECTANGLE; + ShapeType = PAD_SHAPE_TYPE::RECTANGLE; else if( aNodeName == wxT( "ROUNDED" ) ) - ShapeType = CPA_SHAPE_TYPE::ROUNDED_RECT; + ShapeType = PAD_SHAPE_TYPE::ROUNDED_RECT; else if( aNodeName == wxT( "SQUARE" ) ) - ShapeType = CPA_SHAPE_TYPE::SQUARE; + ShapeType = PAD_SHAPE_TYPE::SQUARE; else wxASSERT( true ); switch( ShapeType ) { - case CPA_SHAPE_TYPE::ANNULUS: - Size = CADSTAR_COMMON::GetAttributeIDLong( aNode, 0 ); - InternalFeature = CADSTAR_COMMON::GetAttributeIDLong( aNode, 1 ); + case PAD_SHAPE_TYPE::ANNULUS: + Size = GetXmlAttributeIDLong( aNode, 0 ); + InternalFeature = GetXmlAttributeIDLong( aNode, 1 ); break; - case CPA_SHAPE_TYPE::ROUNDED_RECT: - InternalFeature = CADSTAR_COMMON::GetAttributeIDLong( aNode, 3 ); + case PAD_SHAPE_TYPE::ROUNDED_RECT: + InternalFeature = GetXmlAttributeIDLong( aNode, 3 ); //Fall through - case CPA_SHAPE_TYPE::BULLET: - case CPA_SHAPE_TYPE::FINGER: - case CPA_SHAPE_TYPE::RECTANGLE: - RightLength = CADSTAR_COMMON::GetAttributeIDLong( aNode, 2 ); - LeftLength = CADSTAR_COMMON::GetAttributeIDLong( aNode, 1 ); + case PAD_SHAPE_TYPE::BULLET: + case PAD_SHAPE_TYPE::FINGER: + case PAD_SHAPE_TYPE::RECTANGLE: + RightLength = GetXmlAttributeIDLong( aNode, 2 ); + LeftLength = GetXmlAttributeIDLong( aNode, 1 ); //Fall through - case CPA_SHAPE_TYPE::SQUARE: + case PAD_SHAPE_TYPE::SQUARE: if( aNode->GetChildren() ) { if( aNode->GetChildren()->GetName() == wxT( "ORIENT" ) ) { - OrientAngle = CADSTAR_COMMON::GetAttributeIDLong( aNode->GetChildren(), 0 ); + OrientAngle = GetXmlAttributeIDLong( aNode->GetChildren(), 0 ); } else THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetChildren()->GetName(), aNode->GetName() ); - CADSTAR_COMMON::CheckNoNextNodes( aNode->GetChildren() ); + CheckNoNextNodes( aNode->GetChildren() ); } //Fall through - case CPA_SHAPE_TYPE::CIRCLE: - Size = CADSTAR_COMMON::GetAttributeIDLong( aNode, 0 ); + case PAD_SHAPE_TYPE::CIRCLE: + Size = GetXmlAttributeIDLong( aNode, 0 ); break; } } -void CPA_PADREASSIGN::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::PADREASSIGN::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "PADREASSIGN" ) ); - LayerID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); + LayerID = GetXmlAttributeIDString( aNode, 0 ); - if( CPA_PAD_SHAPE::IsShape( aNode->GetChildren() ) ) + if( PAD_SHAPE::IsPadShape( aNode->GetChildren() ) ) //TODO try.. catch + throw again with more detailed error information Shape.Parse( aNode->GetChildren() ); else THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetChildren()->GetName(), aNode->GetName() ); - CADSTAR_COMMON::CheckNoNextNodes( aNode->GetChildren() ); + CheckNoNextNodes( aNode->GetChildren() ); } -void CPA_PADCODE::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::PADCODE::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "PADCODE" ) ); //Process Name & ID - ID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - Name = CADSTAR_COMMON::GetAttributeID( aNode, 1 ); + ID = GetXmlAttributeIDString( aNode, 0 ); + Name = GetXmlAttributeIDString( aNode, 1 ); XNODE* cNode = aNode->GetChildren(); wxString location = wxString::Format( "PADCODE -> %s", Name ); @@ -900,16 +960,16 @@ void CPA_PADCODE::Parse( XNODE* aNode ) { wxString cNodeName = cNode->GetName(); - if( CPA_PAD_SHAPE::IsShape( cNode ) ) + if( PAD_SHAPE::IsPadShape( cNode ) ) //TODO try.. catch + throw again with more detailed error information Shape.Parse( cNode ); else if( cNodeName == wxT( "CLEARANCE" ) ) - ReliefClearance = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + ReliefClearance = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "RELIEFWIDTH" ) ) - ReliefWidth = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + ReliefWidth = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "DRILL" ) ) { - DrillDiameter = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + DrillDiameter = GetXmlAttributeIDLong( cNode, 0 ); XNODE* subNode = cNode->GetChildren(); for( ; subNode; subNode = subNode->GetNext() ) @@ -919,25 +979,25 @@ void CPA_PADCODE::Parse( XNODE* aNode ) if( subNodeName == wxT( "NONPLATED" ) ) Plated = false; else if( subNodeName == wxT( "OVERSIZE" ) ) - DrillOversize = CADSTAR_COMMON::GetAttributeIDLong( subNode, 0 ); + DrillOversize = GetXmlAttributeIDLong( subNode, 0 ); else THROW_UNKNOWN_NODE_IO_ERROR( subNode->GetName(), location ); } } else if( cNodeName == wxT( "DRILLLENGTH" ) ) - SlotLength = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + SlotLength = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "DRILLORIENTATION" ) ) - SlotOrientation = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + SlotOrientation = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "DRILLXOFFSET" ) ) - DrillXoffset = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + DrillXoffset = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "DRILLYOFFSET" ) ) - DrillYoffset = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + DrillYoffset = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "PADREASSIGN" ) ) { //TODO try.. catch + throw again with more detailed error information - CPA_PADREASSIGN reassign; + PADREASSIGN reassign; reassign.Parse( cNode ); - Reassigns.push_back( reassign ); + Reassigns.insert( std::make_pair( reassign.LayerID, reassign.Shape ) ); } else THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, location ); @@ -945,29 +1005,29 @@ void CPA_PADCODE::Parse( XNODE* aNode ) } -void CPA_VIAREASSIGN::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::VIAREASSIGN::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "VIAREASSIGN" ) ); - LayerID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); + LayerID = GetXmlAttributeIDString( aNode, 0 ); - if( CPA_PAD_SHAPE::IsShape( aNode->GetChildren() ) ) + if( PAD_SHAPE::IsPadShape( aNode->GetChildren() ) ) //TODO try.. catch + throw again with more detailed error information Shape.Parse( aNode->GetChildren() ); else THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetChildren()->GetName(), aNode->GetName() ); - CADSTAR_COMMON::CheckNoNextNodes( aNode->GetChildren() ); + CheckNoNextNodes( aNode->GetChildren() ); } -void CPA_VIACODE::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::VIACODE::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "VIACODE" ) ); //Process Name & ID - ID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - Name = CADSTAR_COMMON::GetAttributeID( aNode, 1 ); + ID = GetXmlAttributeIDString( aNode, 0 ); + Name = GetXmlAttributeIDString( aNode, 1 ); XNODE* cNode = aNode->GetChildren(); wxString location = wxString::Format( "VIACODE -> %s", Name ); @@ -976,16 +1036,16 @@ void CPA_VIACODE::Parse( XNODE* aNode ) { wxString cNodeName = cNode->GetName(); - if( CPA_PAD_SHAPE::IsShape( cNode ) ) + if( PAD_SHAPE::IsPadShape( cNode ) ) //TODO try.. catch + throw again with more detailed error information Shape.Parse( cNode ); else if( cNodeName == wxT( "CLEARANCE" ) ) - ReliefClearance = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + ReliefClearance = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "RELIEFWIDTH" ) ) - ReliefWidth = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + ReliefWidth = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "DRILL" ) ) { - DrillDiameter = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + DrillDiameter = GetXmlAttributeIDLong( cNode, 0 ); XNODE* subNode = cNode->GetChildren(); for( ; subNode; subNode = subNode->GetNext() ) @@ -993,7 +1053,7 @@ void CPA_VIACODE::Parse( XNODE* aNode ) wxString subNodeName = subNode->GetName(); if( subNodeName == wxT( "OVERSIZE" ) ) - DrillOversize = CADSTAR_COMMON::GetAttributeIDLong( subNode, 0 ); + DrillOversize = GetXmlAttributeIDLong( subNode, 0 ); else THROW_UNKNOWN_NODE_IO_ERROR( subNode->GetName(), location ); } @@ -1001,9 +1061,9 @@ void CPA_VIACODE::Parse( XNODE* aNode ) else if( cNodeName == wxT( "VIAREASSIGN" ) ) { //TODO try.. catch + throw again with more detailed error information - CPA_VIAREASSIGN reassign; + VIAREASSIGN reassign; reassign.Parse( cNode ); - Reassigns.push_back( reassign ); + Reassigns.insert( std::make_pair( reassign.LayerID, reassign.Shape ) ); } else THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, location ); @@ -1011,16 +1071,16 @@ void CPA_VIACODE::Parse( XNODE* aNode ) } -void CPA_LAYERPAIR::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::LAYERPAIR::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "LAYERPAIR" ) ); //Process Name & ID - ID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - Name = CADSTAR_COMMON::GetAttributeID( aNode, 1 ); + ID = GetXmlAttributeIDString( aNode, 0 ); + Name = GetXmlAttributeIDString( aNode, 1 ); - PhysicalLayerStart = CADSTAR_COMMON::GetAttributeIDLong( aNode, 2 ); - PhysicalLayerEnd = CADSTAR_COMMON::GetAttributeIDLong( aNode, 3 ); + PhysicalLayerStart = GetXmlAttributeIDLong( aNode, 2 ); + PhysicalLayerEnd = GetXmlAttributeIDLong( aNode, 3 ); wxString location = wxString::Format( "LAYERPAIR -> %s", Name ); @@ -1028,23 +1088,23 @@ void CPA_LAYERPAIR::Parse( XNODE* aNode ) { if( aNode->GetChildren()->GetName() == wxT( "VIACODEREF" ) ) { - ViacodeID = CADSTAR_COMMON::GetAttributeID( aNode->GetChildren(), 0 ); + ViacodeID = GetXmlAttributeIDString( aNode->GetChildren(), 0 ); } else THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetChildren()->GetName(), location ); - CADSTAR_COMMON::CheckNoNextNodes( aNode->GetChildren() ); + CheckNoNextNodes( aNode->GetChildren() ); } } -void CPA_ATTRNAME::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::ATTRNAME::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "ATTRNAME" ) ); //Process Name & ID - ID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - Name = CADSTAR_COMMON::GetAttributeID( aNode, 1 ); + ID = GetXmlAttributeIDString( aNode, 0 ); + Name = GetXmlAttributeIDString( aNode, 1 ); XNODE* cNode = aNode->GetChildren(); wxString location = wxString::Format( "ATTRNAME -> %s", Name ); @@ -1055,57 +1115,57 @@ void CPA_ATTRNAME::Parse( XNODE* aNode ) if( cNodeName == wxT( "ATTROWNER" ) ) { - wxString attOwnerVal = CADSTAR_COMMON::GetAttributeID( cNode, 0 ); + wxString attOwnerVal = GetXmlAttributeIDString( cNode, 0 ); if( attOwnerVal == wxT( "ALL_ITEMS" ) ) - AttributeOwner = CPA_ATTROWNER::ALL_ITEMS; + AttributeOwner = ATTROWNER::ALL_ITEMS; else if( attOwnerVal == wxT( "AREA" ) ) - AttributeOwner = CPA_ATTROWNER::AREA; + AttributeOwner = ATTROWNER::AREA; else if( attOwnerVal == wxT( "BOARD" ) ) - AttributeOwner = CPA_ATTROWNER::BOARD; + AttributeOwner = ATTROWNER::BOARD; else if( attOwnerVal == wxT( "COMPONENT" ) ) - AttributeOwner = CPA_ATTROWNER::COMPONENT; + AttributeOwner = ATTROWNER::COMPONENT; else if( attOwnerVal == wxT( "CONNECTION" ) ) - AttributeOwner = CPA_ATTROWNER::CONNECTION; + AttributeOwner = ATTROWNER::CONNECTION; else if( attOwnerVal == wxT( "COPPER" ) ) - AttributeOwner = CPA_ATTROWNER::COPPER; + AttributeOwner = ATTROWNER::COPPER; else if( attOwnerVal == wxT( "DOCSYMBOL" ) ) - AttributeOwner = CPA_ATTROWNER::DOCSYMBOL; + AttributeOwner = ATTROWNER::DOCSYMBOL; else if( attOwnerVal == wxT( "FIGURE" ) ) - AttributeOwner = CPA_ATTROWNER::FIGURE; + AttributeOwner = ATTROWNER::FIGURE; else if( attOwnerVal == wxT( "NET" ) ) - AttributeOwner = CPA_ATTROWNER::NET; + AttributeOwner = ATTROWNER::NET; else if( attOwnerVal == wxT( "NETCLASS" ) ) - AttributeOwner = CPA_ATTROWNER::NETCLASS; + AttributeOwner = ATTROWNER::NETCLASS; else if( attOwnerVal == wxT( "PART" ) ) - AttributeOwner = CPA_ATTROWNER::PART; + AttributeOwner = ATTROWNER::PART; else if( attOwnerVal == wxT( "PART_DEFINITION" ) ) - AttributeOwner = CPA_ATTROWNER::PART_DEFINITION; + AttributeOwner = ATTROWNER::PART_DEFINITION; else if( attOwnerVal == wxT( "PIN" ) ) - AttributeOwner = CPA_ATTROWNER::PIN; + AttributeOwner = ATTROWNER::PIN; else if( attOwnerVal == wxT( "SYMDEF" ) ) - AttributeOwner = CPA_ATTROWNER::SYMDEF; + AttributeOwner = ATTROWNER::SYMDEF; else if( attOwnerVal == wxT( "TEMPLATE" ) ) - AttributeOwner = CPA_ATTROWNER::TEMPLATE; + AttributeOwner = ATTROWNER::TEMPLATE; else if( attOwnerVal == wxT( "TESTPOINT" ) ) - AttributeOwner = CPA_ATTROWNER::TESTPOINT; + AttributeOwner = ATTROWNER::TESTPOINT; else THROW_UNKNOWN_PARAMETER_IO_ERROR( attOwnerVal, location ); } else if( cNodeName == wxT( "ATTRUSAGE" ) ) { - wxString attUsageVal = CADSTAR_COMMON::GetAttributeID( cNode, 0 ); + wxString attUsageVal = GetXmlAttributeIDString( cNode, 0 ); if( attUsageVal == wxT( "BOTH" ) ) - AttributeUsage = CPA_ATTRUSAGE::BOTH; + AttributeUsage = ATTRUSAGE::BOTH; else if( attUsageVal == wxT( "COMPONENT" ) ) - AttributeUsage = CPA_ATTRUSAGE::COMPONENT; + AttributeUsage = ATTRUSAGE::COMPONENT; else if( attUsageVal == wxT( "PART_DEFINITION" ) ) - AttributeUsage = CPA_ATTRUSAGE::PART_DEFINITION; + AttributeUsage = ATTRUSAGE::PART_DEFINITION; else if( attUsageVal == wxT( "PART_LIBRARY" ) ) - AttributeUsage = CPA_ATTRUSAGE::PART_LIBRARY; + AttributeUsage = ATTRUSAGE::PART_LIBRARY; else if( attUsageVal == wxT( "SYMBOL" ) ) - AttributeUsage = CPA_ATTRUSAGE::SYMBOL; + AttributeUsage = ATTRUSAGE::SYMBOL; else THROW_UNKNOWN_PARAMETER_IO_ERROR( attUsageVal, location ); } @@ -1117,22 +1177,22 @@ void CPA_ATTRNAME::Parse( XNODE* aNode ) } -void CPA_ATTRIBUTE_VALUE::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::ATTRIBUTE_VALUE::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "ATTR" ) ); - AttributeID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - Value = CADSTAR_COMMON::GetAttributeID( aNode, 1 ); + AttributeID = GetXmlAttributeIDString( aNode, 0 ); + Value = GetXmlAttributeIDString( aNode, 1 ); } -void CPA_NETCLASS::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::NETCLASS::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "NETCLASS" ) ); //Process Name & ID - ID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - Name = CADSTAR_COMMON::GetAttributeID( aNode, 1 ); + ID = GetXmlAttributeIDString( aNode, 0 ); + Name = GetXmlAttributeIDString( aNode, 1 ); XNODE* cNode = aNode->GetChildren(); wxString location = wxString::Format( "NETCLASS -> %s", Name ); @@ -1143,7 +1203,7 @@ void CPA_NETCLASS::Parse( XNODE* aNode ) if( cNodeName == wxT( "ATTR" ) ) { - CPA_ATTRIBUTE_VALUE attribute_val; + ATTRIBUTE_VALUE attribute_val; //TODO try.. catch + throw again with more detailed error information attribute_val.Parse( cNode ); Attributes.push_back( attribute_val ); @@ -1154,28 +1214,53 @@ void CPA_NETCLASS::Parse( XNODE* aNode ) } -void CPA_SPCCLASSNAME::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::SPCCLASSNAME::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "SPCCLASSNAME" ) ); //Process Name & ID - ID = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - Name = CADSTAR_COMMON::GetAttributeID( aNode, 1 ); + ID = GetXmlAttributeIDString( aNode, 0 ); + Name = GetXmlAttributeIDString( aNode, 1 ); } -void CPA_SPCCLASSSPACE::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::SPCCLASSSPACE::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "SPCCLASSSPACE" ) ); - SpacingClassID1 = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - SpacingClassID2 = CADSTAR_COMMON::GetAttributeID( aNode, 1 ); - LayerID = CADSTAR_COMMON::GetAttributeID( aNode, 2 ); - Spacing = CADSTAR_COMMON::GetAttributeIDLong( aNode, 3 ); + SpacingClassID1 = GetXmlAttributeIDString( aNode, 0 ); + SpacingClassID2 = GetXmlAttributeIDString( aNode, 1 ); + LayerID = GetXmlAttributeIDString( aNode, 2 ); + Spacing = GetXmlAttributeIDLong( aNode, 3 ); } -void CPA_TECHNOLOGY::Parse( XNODE* aNode ) +CADSTAR_PCB_ARCHIVE_PARSER::UNITS CADSTAR_PCB_ARCHIVE_PARSER::ParseUnits( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "UNITS" ) ); + + wxString unit = GetXmlAttributeIDString( aNode, 0 ); + + if( unit == wxT( "CENTIMETER" ) ) + return UNITS::CENTIMETER; + else if( unit == wxT( "INCH" ) ) + return UNITS::INCH; + else if( unit == wxT( "METER" ) ) + return UNITS::METER; + else if( unit == wxT( "MICROMETRE" ) ) + return UNITS::MICROMETRE; + else if( unit == wxT( "MM" ) ) + return UNITS::MM; + else if( unit == wxT( "THOU" ) ) + return UNITS::THOU; + else + THROW_UNKNOWN_PARAMETER_IO_ERROR( unit, wxT( "UNITS" ) ); + + return UNITS(); +} + + +void CADSTAR_PCB_ARCHIVE_PARSER::TECHNOLOGY_SECTION::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "TECHNOLOGY" ) ); @@ -1186,73 +1271,52 @@ void CPA_TECHNOLOGY::Parse( XNODE* aNode ) wxString cNodeName = cNode->GetName(); if( cNodeName == wxT( "UNITS" ) ) - { - wxString unit = CADSTAR_COMMON::GetAttributeID( cNode, 0 ); - - if( unit == wxT( "CENTIMETER" ) ) - Unit = CPA_UNITS::CENTIMETER; - else if( unit == wxT( "INCH" ) ) - Unit = CPA_UNITS::INCH; - else if( unit == wxT( "METER" ) ) - Unit = CPA_UNITS::METER; - else if( unit == wxT( "MICROMETRE" ) ) - Unit = CPA_UNITS::MICROMETRE; - else if( unit == wxT( "MM" ) ) - Unit = CPA_UNITS::MM; - else if( unit == wxT( "THOU" ) ) - Unit = CPA_UNITS::THOU; - else - THROW_UNKNOWN_PARAMETER_IO_ERROR( unit, wxT( "TECHNOLOGY -> UNITS" ) ); - } + Units = ParseUnits( cNode ); else if( cNodeName == wxT( "UNITSPRECISION" ) ) - UnitDisplPrecision = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + UnitDisplPrecision = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "INTERLINEGAP" ) ) - InterlineGap = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + InterlineGap = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "BARLINEGAP" ) ) - BarlineGap = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + BarlineGap = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "ALLOWBARTEXT" ) ) AllowBarredText = true; else if( cNodeName == wxT( "ANGULARPRECISION" ) ) - AngularPrecision = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + AngularPrecision = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "MINROUTEWIDTH" ) ) - MinRouteWidth = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + MinRouteWidth = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "MINNECKED" ) ) - MinNeckedLength = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + MinNeckedLength = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "MINUNNECKED" ) ) - MinUnneckedLength = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + MinUnneckedLength = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "MINMITER" ) ) - MinMitre = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + MinMitre = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "MAXMITER" ) ) - MaxMitre = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + MaxMitre = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "MAXPHYSLAYER" ) ) - MaxPhysicalLayer = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + MaxPhysicalLayer = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "TRACKGRID" ) ) - TrackGrid = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + TrackGrid = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "VIAGRID" ) ) - ViaGrid = CADSTAR_COMMON::GetAttributeIDLong( cNode, 0 ); + ViaGrid = GetXmlAttributeIDLong( cNode, 0 ); else if( cNodeName == wxT( "DESIGNORIGIN" ) ) { - std::vector pts = - CADSTAR_COMMON::ParseAllChildPoints( cNode, true, 1 ); - DesignOrigin = pts[0]; + std::vector pts = ParseAllChildPoints( cNode, true, 1 ); + DesignOrigin = pts[0]; } else if( cNodeName == wxT( "DESIGNAREA" ) ) { - std::vector pts = - CADSTAR_COMMON::ParseAllChildPoints( cNode, true, 2 ); - DesignArea = std::make_pair( pts[0], pts[1] ); + std::vector pts = ParseAllChildPoints( cNode, true, 2 ); + DesignArea = std::make_pair( pts[0], pts[1] ); } else if( cNodeName == wxT( "DESIGNREF" ) ) { - std::vector pts = - CADSTAR_COMMON::ParseAllChildPoints( cNode, true, 1 ); - DesignRef = pts[0]; + std::vector pts = ParseAllChildPoints( cNode, true, 1 ); + DesignRef = pts[0]; } else if( cNodeName == wxT( "DESIGNLIMIT" ) ) { - std::vector pts = - CADSTAR_COMMON::ParseAllChildPoints( cNode, true, 1 ); - DesignLimit = pts[0]; + std::vector pts = ParseAllChildPoints( cNode, true, 1 ); + DesignLimit = pts[0]; } else if( cNodeName == wxT( "BACKOFFJCTS" ) ) BackOffJunctions = true; @@ -1264,7 +1328,7 @@ void CPA_TECHNOLOGY::Parse( XNODE* aNode ) } -bool CPA_GRID::IsGrid( XNODE* aNode ) +bool CADSTAR_PCB_ARCHIVE_PARSER::GRID::IsGrid( XNODE* aNode ) { wxString aNodeName = aNode->GetName(); @@ -1275,26 +1339,26 @@ bool CPA_GRID::IsGrid( XNODE* aNode ) } -void CPA_GRID::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::GRID::Parse( XNODE* aNode ) { wxASSERT( IsGrid( aNode ) ); wxString aNodeName = aNode->GetName(); if( aNodeName == wxT( "FRACTIONALGRID" ) ) - Type = CPA_GRID_TYPE::FRACTIONALGRID; + Type = GRID_TYPE::FRACTIONALGRID; else if( aNodeName == wxT( "STEPGRID" ) ) - Type = CPA_GRID_TYPE::STEPGRID; + Type = GRID_TYPE::STEPGRID; else wxASSERT_MSG( true, wxT( "Unknown Grid Type" ) ); - Name = CADSTAR_COMMON::GetAttributeID( aNode, 0 ); - Param1 = CADSTAR_COMMON::GetAttributeIDLong( aNode, 1 ); - Param2 = CADSTAR_COMMON::GetAttributeIDLong( aNode, 2 ); + Name = GetXmlAttributeIDString( aNode, 0 ); + Param1 = GetXmlAttributeIDLong( aNode, 1 ); + Param2 = GetXmlAttributeIDLong( aNode, 2 ); } -void CPA_GRIDS::Parse( XNODE* aNode ) +void CADSTAR_PCB_ARCHIVE_PARSER::GRIDS::Parse( XNODE* aNode ) { wxASSERT( aNode->GetName() == wxT( "GRIDS" ) ); @@ -1308,7 +1372,7 @@ void CPA_GRIDS::Parse( XNODE* aNode ) { XNODE* workingGridNode = cNode->GetChildren(); - if( !CPA_GRID::IsGrid( workingGridNode ) ) + if( !GRID::IsGrid( workingGridNode ) ) THROW_UNKNOWN_NODE_IO_ERROR( workingGridNode->GetName(), wxT( "GRIDS -> WORKINGGRID" ) ); else @@ -1318,17 +1382,803 @@ void CPA_GRIDS::Parse( XNODE* aNode ) { XNODE* screenGridNode = cNode->GetChildren(); - if( !CPA_GRID::IsGrid( screenGridNode ) ) + if( !GRID::IsGrid( screenGridNode ) ) THROW_UNKNOWN_NODE_IO_ERROR( screenGridNode->GetName(), wxT( "GRIDS -> SCREENGRID" ) ); else ScreenGrid.Parse( screenGridNode ); } - else if( CPA_GRID::IsGrid( cNode ) ) + else if( GRID::IsGrid( cNode ) ) { - CPA_GRID userGrid; + GRID userGrid; userGrid.Parse( cNode ); UserGrids.push_back( userGrid ); } } } + + +void CADSTAR_PCB_ARCHIVE_PARSER::FIGURE::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "FIGURE" ) ); + + ID = GetXmlAttributeIDString( aNode, 0 ); + LineCodeID = GetXmlAttributeIDString( aNode, 1 ); + LayerID = GetXmlAttributeIDString( aNode, 2 ); + + XNODE* cNode = aNode->GetChildren(); + bool shapeIsInitialised = false; //< Stop more than one Shape Object + wxString location = wxString::Format( "Figure %s", ID ); + + if( !cNode ) + THROW_MISSING_NODE_IO_ERROR( wxT( "Shape" ), location ); + + for( ; cNode; cNode = cNode->GetNext() ) + { + wxString cNodeName = cNode->GetName(); + + if( !shapeIsInitialised && Shape.IsShape( cNode ) ) + { + Shape.Parse( cNode ); + shapeIsInitialised = true; + } + else if( cNodeName == wxT( "SWAPRULE" ) ) + { + SwapRule = ParseSwapRule( cNode ); + } + else + THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, location ); + } +} + + +CADSTAR_PCB_ARCHIVE_PARSER::SWAP_RULE CADSTAR_PCB_ARCHIVE_PARSER::ParseSwapRule( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "SWAPRULE" ) ); + + SWAP_RULE retval; + wxString swapRuleStr = GetXmlAttributeIDString( aNode, 0 ); + + if( swapRuleStr == wxT( "NO_SWAP" ) ) + retval = SWAP_RULE::NO_SWAP; + else if( swapRuleStr == wxT( "USE_SWAP_LAYER" ) ) + retval = SWAP_RULE::USE_SWAP_LAYER; + else + THROW_UNKNOWN_PARAMETER_IO_ERROR( swapRuleStr, wxT( "SWAPRULE" ) ); + + return retval; +} + + +void CADSTAR_PCB_ARCHIVE_PARSER::COMPONENT_COPPER::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "COMPCOPPER" ) ); + + CopperCodeID = GetXmlAttributeIDString( aNode, 0 ); + LayerID = GetXmlAttributeIDString( aNode, 1 ); + + XNODE* cNode = aNode->GetChildren(); + bool shapeIsInitialised = false; //< Stop more than one Shape Object + wxString location = wxT( "COMPCOPPER" ); + + if( !cNode ) + THROW_MISSING_NODE_IO_ERROR( wxT( "Shape" ), location ); + + for( ; cNode; cNode = cNode->GetNext() ) + { + wxString cNodeName = cNode->GetName(); + + if( !shapeIsInitialised && Shape.IsShape( cNode ) ) + { + Shape.Parse( cNode ); + shapeIsInitialised = true; + } + else if( cNodeName == wxT( "SWAPRULE" ) ) + { + SwapRule = ParseSwapRule( cNode ); + } + else if( cNodeName == wxT( "ASSOCPIN" ) ) + { + wxXmlAttribute* xmlAttribute = cNode->GetAttributes(); + + for( ; xmlAttribute; xmlAttribute = xmlAttribute->GetNext() ) + { + long padId; + + if( !xmlAttribute->GetValue().ToLong( &padId ) ) + THROW_PARSING_IO_ERROR( wxT( "ASSOCPIN" ), location ); + + AssociatedPadIDs.push_back( (PAD_ID) padId ); + } + + CheckNoChildNodes( cNode ); + } + else + THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, location ); + } +} + + +void CADSTAR_PCB_ARCHIVE_PARSER::COMPONENT_AREA::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "COMPAREA" ) ); + + ID = GetXmlAttributeIDString( aNode, 0 ); + LineCodeID = GetXmlAttributeIDString( aNode, 1 ); + LayerID = GetXmlAttributeIDString( aNode, 3 ); + + XNODE* cNode = aNode->GetChildren(); + bool shapeIsInitialised = false; //< Stop more than one Shape Object + wxString location = wxString::Format( "COMPAREA %s", ID ); + + if( !cNode ) + THROW_MISSING_NODE_IO_ERROR( wxT( "Shape" ), location ); + + for( ; cNode; cNode = cNode->GetNext() ) + { + wxString cNodeName = cNode->GetName(); + + if( !shapeIsInitialised && SHAPE::IsShape( cNode ) ) + { + Shape.Parse( cNode ); + shapeIsInitialised = true; + } + else if( cNodeName == wxT( "SWAPRULE" ) ) + { + SwapRule = ParseSwapRule( cNode ); + } + else if( cNodeName == wxT( "USAGE" ) ) + { + wxXmlAttribute* xmlAttribute = cNode->GetAttributes(); + + for( ; xmlAttribute; xmlAttribute = xmlAttribute->GetNext() ) + { + if( xmlAttribute->GetValue() == wxT( "NO_TRACKS" ) ) + NoTracks = true; + else if( xmlAttribute->GetValue() == wxT( "NO_VIAS" ) ) + NoVias = true; + else + THROW_UNKNOWN_PARAMETER_IO_ERROR( xmlAttribute->GetValue(), location ); + } + + CheckNoChildNodes( cNode ); + } + else + THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, location ); + } +} + + +void CADSTAR_PCB_ARCHIVE_PARSER::PAD_EXITS::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "EXITS" ) ); + + wxXmlAttribute* xmlAttribute = aNode->GetAttributes(); + + for( ; xmlAttribute; xmlAttribute = xmlAttribute->GetNext() ) + { + if( xmlAttribute->GetValue() == wxT( "FREE" ) ) + FreeAngle = true; + else if( xmlAttribute->GetValue() == wxT( "N" ) ) + North = true; + else if( xmlAttribute->GetValue() == wxT( "S" ) ) + South = true; + else if( xmlAttribute->GetValue() == wxT( "E" ) ) + East = true; + else if( xmlAttribute->GetValue() == wxT( "W" ) ) + West = true; + else if( xmlAttribute->GetValue() == wxT( "NE" ) ) + NorthEast = true; + else if( xmlAttribute->GetValue() == wxT( "NW" ) ) + NorthWest = true; + else if( xmlAttribute->GetValue() == wxT( "SE" ) ) + SouthEast = true; + else if( xmlAttribute->GetValue() == wxT( "SW" ) ) + SouthWest = true; + else + THROW_UNKNOWN_PARAMETER_IO_ERROR( xmlAttribute->GetValue(), wxT( "EXITS" ) ); + } + + CheckNoChildNodes( aNode ); +} + + +void CADSTAR_PCB_ARCHIVE_PARSER::PAD::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "PAD" ) ); + + ID = GetXmlAttributeIDLong( aNode, 0 ); + PadCodeID = GetXmlAttributeIDString( aNode, 2 ); + + wxString padSideStr = GetXmlAttributeIDString( aNode, 3 ); + + if( padSideStr == wxT( "THRU" ) ) + Side = PAD_SIDE::THROUGH_HOLE; + else if( padSideStr == wxT( "BOTTOM" ) ) + Side = PAD_SIDE::MAXIMUM; + else if( padSideStr == wxT( "TOP" ) ) + Side = PAD_SIDE::MINIMUM; + + XNODE* cNode = aNode->GetChildren(); + wxString location = wxString::Format( "PAD %d", ID ); + + if( !cNode ) + THROW_MISSING_NODE_IO_ERROR( wxT( "PADIDENTIFIER" ), location ); + + for( ; cNode; cNode = cNode->GetNext() ) + { + wxString cNodeName = cNode->GetName(); + + if( cNodeName == wxT( "ORIENT" ) ) + OrientAngle = GetXmlAttributeIDLong( cNode, 0 ); + else if( cNodeName == wxT( "FIRSTPAD" ) ) + FirstPad = true; + else if( cNodeName == wxT( "EXITS" ) ) + Exits.Parse( cNode ); + else if( cNodeName == wxT( "PADIDENTIFIER" ) ) + Identifier = GetXmlAttributeIDString( cNode, 0 ); + else if( cNodeName == wxT( "PCBONLYPAD" ) ) + PCBonlyPad = true; + else if( cNodeName == wxT( "PT" ) ) + Position.Parse( cNode ); + else + THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, location ); + } +} + + +void CADSTAR_PCB_ARCHIVE_PARSER::TEXT_LOCATION::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "TEXTLOC" ) ); + + wxString attributeStr = GetXmlAttributeIDString( aNode, 0 ); + bool attributeIDisSet = false; + + if( attributeStr == wxT( "PART_NAME" ) ) + { + AttributeID = PART_NAME_ATTRID; + attributeIDisSet = true; + } + else if( attributeStr == wxT( "COMP_NAME" ) ) + { + AttributeID = COMPONENT_NAME_ATTRID; + attributeIDisSet = true; + } + else if( attributeStr == wxT( "COMP_NAME2" ) ) + { + AttributeID = COMPONENT_NAME_2_ATTRID; + attributeIDisSet = true; + } + else if( attributeStr == wxT( "ATTRREF" ) ) + { + //We will initialise when we parse all child nodes + attributeIDisSet = false; + } + else + { + THROW_UNKNOWN_PARAMETER_IO_ERROR( attributeStr, wxT( "TEXTLOC" ) ); + } + + TextCodeID = GetXmlAttributeIDString( aNode, 1 ); + LayerID = GetXmlAttributeIDString( aNode, 2 ); + + //Parse child nodes + XNODE* cNode = aNode->GetChildren(); + + if( !cNode ) + THROW_MISSING_NODE_IO_ERROR( wxT( "PT" ), wxT( "TEXTLOC" ) ); + + for( ; cNode; cNode = cNode->GetNext() ) + { + wxString cNodeName = cNode->GetName(); + + if( cNodeName == wxT( "PT" ) ) + Position.Parse( cNode ); + else if( !attributeIDisSet && cNodeName == wxT( "ATTRREF" ) ) + { + AttributeID = GetXmlAttributeIDString( cNode, 0 ); + attributeIDisSet = true; + } + else if( cNodeName == wxT( "ORIENT" ) ) + OrientAngle = GetXmlAttributeIDLong( cNode, 0 ); + else if( cNodeName == wxT( "MIRROR" ) ) + Mirror = true; + else if( cNodeName == wxT( "ALIGN" ) ) + Alignment = ParseAlignment( cNode ); + else if( cNodeName == wxT( "JUSTIFICATION" ) ) + Justification = ParseJustification( cNode ); + else + THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, wxT( "TEXTLOC" ) ); + } +} + +void CADSTAR_PCB_ARCHIVE_PARSER::TEXT::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "TEXT" ) ); + + ID = GetXmlAttributeIDString( aNode, 0 ); + //TODO: Need to lex/parse "Text" to identify design fields (e.g "<@DESIGN_TITLE@>") and + // hyperlinks (e.g. "<@HYPERLINK\"[link]\"[link text]@>") + Text = GetXmlAttributeIDString( aNode, 1 ); + TextCodeID = GetXmlAttributeIDString( aNode, 2 ); + LayerID = GetXmlAttributeIDString( aNode, 3 ); + + //Parse child nodes + XNODE* cNode = aNode->GetChildren(); + + if( !cNode ) + THROW_MISSING_NODE_IO_ERROR( wxT( "PT" ), wxT( "TEXT" ) ); + + for( ; cNode; cNode = cNode->GetNext() ) + { + wxString cNodeName = cNode->GetName(); + + if( cNodeName == wxT( "PT" ) ) + Position.Parse( cNode ); + else if( cNodeName == wxT( "ORIENT" ) ) + OrientAngle = GetXmlAttributeIDLong( cNode, 0 ); + else if( cNodeName == wxT( "MIRROR" ) ) + Mirror = true; + else if( cNodeName == wxT( "SWAPRULE" ) ) + SwapRule = ParseSwapRule( cNode ); + else if( cNodeName == wxT( "ALIGN" ) ) + Alignment = ParseAlignment( cNode ); + else if( cNodeName == wxT( "JUSTIFICATION" ) ) + Justification = ParseJustification( cNode ); + else + THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, wxT( "TEXT" ) ); + } +} + + +void CADSTAR_PCB_ARCHIVE_PARSER::DIMENSION::ARROW::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "DIMARROW" ) ); + bool arrowStyleInitialised = false; + bool upperAngleInitialised = false; + bool lowerAngleInitialised = false; + + ArrowLength = GetXmlAttributeIDLong( aNode, 3 ); + + XNODE* cNode = aNode->GetChildren(); + + + for( ; cNode; cNode = cNode->GetNext() ) + { + wxString cNodeName = cNode->GetName(); + + if( cNodeName == wxT( "ARROWSTYLE" ) ) + { + wxString arrowStyleStr = GetXmlAttributeIDString( cNode, 0 ); + arrowStyleInitialised = true; + + if( arrowStyleStr == wxT( "DIMENSION_ARROWOPEN" ) ) + ArrowStyle = STYLE::OPEN; + else if( arrowStyleStr == wxT( "DIMENSION_ARROWCLOSED" ) ) + ArrowStyle = STYLE::CLOSED; + else if( arrowStyleStr == wxT( "DIMENSION_ARROWCLEAR" ) ) + ArrowStyle = STYLE::CLEAR; + else if( arrowStyleStr == wxT( "DIMENSION_ARROWCLOSEDFILLED" ) ) + ArrowStyle = STYLE::CLOSED_FILLED; + else + THROW_UNKNOWN_PARAMETER_IO_ERROR( arrowStyleStr, cNodeName ); + } + else if( cNodeName == wxT( "ARROWANGLEA" ) ) + { + UpperAngle = GetXmlAttributeIDLong( cNode, 0 ); + upperAngleInitialised = true; + } + else if( cNodeName == wxT( "ARROWANGLEB" ) ) + { + UpperAngle = GetXmlAttributeIDLong( cNode, 0 ); + lowerAngleInitialised = true; + } + else + { + THROW_UNKNOWN_PARAMETER_IO_ERROR( cNodeName, wxT( "DIMARROW" ) ); + } + } + + if( !arrowStyleInitialised ) + THROW_MISSING_PARAMETER_IO_ERROR( wxT( "ARROWSTYLE" ), wxT( "DIMARROW" ) ); + + if( !upperAngleInitialised ) + THROW_MISSING_PARAMETER_IO_ERROR( wxT( "ARROWANGLEA" ), wxT( "DIMARROW" ) ); + + if( !lowerAngleInitialised ) + THROW_MISSING_PARAMETER_IO_ERROR( wxT( "ARROWANGLEB" ), wxT( "DIMARROW" ) ); +} + + +void CADSTAR_PCB_ARCHIVE_PARSER::DIMENSION::TEXTFORMAT::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "DIMTEXT" ) ); + + TextGap = GetXmlAttributeIDLong( aNode, 1 ); + TextOffset = GetXmlAttributeIDLong( aNode, 2 ); + + XNODE* cNode = aNode->GetChildren(); + + if( cNode->GetName() != wxT( "TXTSTYLE" ) ) + THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), wxT( "DIMTEXT" ) ); + + wxString styleStr = GetXmlAttributeIDString( cNode, 0 ); + + if( styleStr == wxT( "DIMENSION_INTERNAL" ) ) + Style = STYLE::INSIDE; + else if( styleStr == wxT( "DIMENSION_EXTERNAL" ) ) + Style = STYLE::OUTSIDE; + else + THROW_UNKNOWN_PARAMETER_IO_ERROR( styleStr, wxT( "TXTSTYLE" ) ); + + CheckNoNextNodes( cNode ); +} + + +void CADSTAR_PCB_ARCHIVE_PARSER::DIMENSION::EXTENSION_LINE::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "EXTLINE" ) ); + + LineCodeID = GetXmlAttributeIDString( aNode, 0 ); + Overshoot = GetXmlAttributeIDLong( aNode, 3 ); + Offset = GetXmlAttributeIDLong( aNode, 4 ); + + XNODE* cNode = aNode->GetChildren(); + int noOfPoints = 0; + + for( ; cNode; cNode = cNode->GetNext() ) + { + wxString cNodeName = cNode->GetName(); + + if( noOfPoints < 2 && cNodeName == wxT( "PT" ) ) + { + ++noOfPoints; + + if( noOfPoints == 1 ) + Start.Parse( cNode ); + else + End.Parse( cNode ); + } + else if( cNodeName == wxT( "SUPPRESSFIRST" ) ) + SuppressFirst = true; + else + THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, wxT( "EXTLINE" ) ); + } + + if( noOfPoints != 2 ) + THROW_MISSING_PARAMETER_IO_ERROR( wxT( "PT" ), wxT( "EXTLINE" ) ); +} + + +bool CADSTAR_PCB_ARCHIVE_PARSER::DIMENSION::LINE::IsLine( XNODE* aNode ) +{ + if( aNode->GetName() == wxT( "LEADERLINE" ) || aNode->GetName() == wxT( "LINEARLINE" ) + || aNode->GetName() == wxT( "ANGULARLINE" ) ) + return true; + else + return false; +} + + +void CADSTAR_PCB_ARCHIVE_PARSER::DIMENSION::LINE::Parse( XNODE* aNode ) +{ + wxASSERT( IsLine( aNode ) ); + + if( aNode->GetName() == wxT( "LINEARLINE" ) ) + Type = TYPE::LINEARLINE; + else if( aNode->GetName() == wxT( "LEADERLINE" ) ) + Type = TYPE::LEADERLINE; + else if( aNode->GetName() == wxT( "ANGULARLINE" ) ) + Type = TYPE::ANGULARLINE; + else + wxASSERT_MSG( true, "Not a valid type. What happened to the node Name?" ); + + LineCodeID = GetXmlAttributeIDString( aNode, 0 ); + + if( Type == TYPE::LEADERLINE ) + { + LeaderLineLength = GetXmlAttributeIDLong( aNode, 5 ); + LeaderLineExtensionLength = GetXmlAttributeIDLong( aNode, 6 ); + } + + XNODE* cNode = aNode->GetChildren(); + int noOfPoints = 0; + int requiredNoOfPoints = 2; + + if( Type == TYPE::ANGULARLINE ) + requiredNoOfPoints = 3; + + for( ; cNode; cNode = cNode->GetNext() ) + { + wxString cNodeName = cNode->GetName(); + + if( cNodeName == wxT( "DIMLINETYPE" ) ) + { + wxString styleStr = GetXmlAttributeIDString( cNode, 0 ); + + if( styleStr == wxT( "DIMENSION_INTERNAL" ) ) + Style = STYLE::INTERNAL; + else if( styleStr == wxT( "DIMENSION_EXTERNAL" ) ) + Style = STYLE::EXTERNAL; + else + THROW_UNKNOWN_PARAMETER_IO_ERROR( styleStr, cNodeName ); + } + else if( noOfPoints < requiredNoOfPoints && cNodeName == wxT( "PT" ) ) + { + ++noOfPoints; + + if( noOfPoints == 1 ) + Start.Parse( cNode ); + else if( noOfPoints == 2 ) + End.Parse( cNode ); + else + Centre.Parse( cNode ); + } + else if( Type == TYPE::LEADERLINE && cNodeName == wxT( "LEADERANG" ) ) + { + LeaderAngle = GetXmlAttributeIDLong( cNode, 0 ); + } + else + { + THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() ); + } + } + + if( noOfPoints != requiredNoOfPoints ) + THROW_MISSING_PARAMETER_IO_ERROR( wxT( "PT" ), aNode->GetName() ); +} + + +bool CADSTAR_PCB_ARCHIVE_PARSER::DIMENSION::IsDimension( XNODE* aNode ) +{ + if( aNode->GetName() == wxT( "LINEARDIM" ) || aNode->GetName() == wxT( "LEADERDIM" ) + || aNode->GetName() == wxT( "ANGLEDIM" ) ) + return true; + else + return false; +} + +void CADSTAR_PCB_ARCHIVE_PARSER::DIMENSION::Parse( XNODE* aNode ) +{ + wxASSERT( IsDimension( aNode ) ); + + std::map typeMap = { + { wxT( "LINEARDIM" ), TYPE::LINEARDIM }, ///////////////////////////////////////////// + { wxT( "LEADERDIM" ), TYPE::LEADERDIM }, ///////////////////////////////////////////// + { wxT( "ANGLEDIM" ), TYPE::ANGLEDIM } + }; + + //make sure aNode is valid TYPE + wxASSERT_MSG( typeMap.find( aNode->GetName() ) != typeMap.end(), + "Not a valid type. What happened to the node Name?" ); + + Type = typeMap[aNode->GetName()]; + LayerID = GetXmlAttributeIDString( aNode, 1 ); + wxString subTypeStr = GetXmlAttributeIDString( aNode, 2 ); + + std::map subTypeMap = { + { wxT( "DIMENSION_ORTHOGONAL" ), SUBTYPE::ORTHOGONAL }, ////////////////////////////// + { wxT( "DIMENSION_DIRECT" ), SUBTYPE::DIRECT }, ////////////////////////////// + { wxT( "DIMENSION_ANGLED" ), SUBTYPE::ANGLED }, ////////////////////////////// + { wxT( "DIMENSION_DIAMETER" ), SUBTYPE::DIAMETER }, ////////////////////////////// + { wxT( "DIMENSION_RADIUS" ), SUBTYPE::RADIUS }, ////////////////////////////// + { wxT( "DIMENSION_ANGULAR" ), SUBTYPE::ANGULAR } + }; + + if( subTypeMap.find( subTypeStr ) == subTypeMap.end() ) + THROW_UNKNOWN_PARAMETER_IO_ERROR( subTypeStr, aNode->GetName() ); + + Subtype = subTypeMap[subTypeStr]; + Precision = GetXmlAttributeIDLong( aNode, 3 ); + + XNODE* cNode = aNode->GetChildren(); + + bool idParsed = false; + bool unitsParsed = false; //UNITS or ANGUNITS + bool arrowParsed = false; + bool textFormatParsed = false; + bool extLineParsed = false; + bool lineParsed = false; + bool textParsed = false; + + for( ; cNode; cNode = cNode->GetNext() ) + { + wxString cNodeName = cNode->GetName(); + + if( !idParsed && cNodeName == wxT( "DIMREF" ) ) + { + ID = GetXmlAttributeIDString( cNode, 0 ); + idParsed = true; + } + else if( !unitsParsed && cNodeName == wxT( "UNITS" ) ) + { + LinearUnits = ParseUnits( cNode ); + unitsParsed = true; + } + else if( !unitsParsed && cNodeName == wxT( "ANGUNITS" ) ) + { + AngularUnits = ParseAngunits( cNode ); + unitsParsed = true; + } + else if( !arrowParsed && cNodeName == wxT( "DIMARROW" ) ) + { + Arrow.Parse( cNode ); + arrowParsed = true; + } + else if( !textFormatParsed && cNodeName == wxT( "DIMTEXT" ) ) + { + TextParams.Parse( cNode ); + textFormatParsed = true; + } + else if( !extLineParsed && cNodeName == wxT( "EXTLINE" ) ) + { + ExtensionLineParams.Parse( cNode ); + extLineParsed = true; + } + else if( !lineParsed && LINE::IsLine( cNode ) ) + { + Line.Parse( cNode ); + lineParsed = true; + } + else if( !textParsed && cNodeName == wxT( "TEXT" ) ) + { + Text.Parse( cNode ); + textParsed = true; + } + else + { + THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() ); + } + } +} + +void CADSTAR_PCB_ARCHIVE_PARSER::SYMDEF::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "SYMDEF" ) ); + + ID = GetXmlAttributeIDString( aNode, 0 ); + ReferenceName = GetXmlAttributeIDString( aNode, 1 ); + wxString rest; + + if( ReferenceName.StartsWith( wxT( "JUMPERNF" ), &rest ) ) + Type = SYMDEF_TYPE::JUMPER; + else if( ReferenceName.StartsWith( wxT( "STARPOINTNF" ), &rest ) ) + Type = SYMDEF_TYPE::STARPOINT; + else if( ReferenceName == wxT( "TESTPOINT" ) ) + Type = SYMDEF_TYPE::TESTPOINT; + else + Type = SYMDEF_TYPE::COMPONENT; + + Alternate = GetXmlAttributeIDString( aNode, 2 ); + + XNODE* cNode = aNode->GetChildren(); + bool originParsed = false; + bool symHeightParsed = false; + bool vesionParsed = false; + bool dimensionsParsed = false; + + for( ; cNode; cNode = cNode->GetNext() ) + { + wxString cNodeName = cNode->GetName(); + + if( !originParsed && cNodeName == wxT( "PT" ) ) + { + Origin.Parse( cNode ); + originParsed = true; + } + else if( cNodeName == wxT( "STUB" ) ) + { + Stub = true; + } + else if( !symHeightParsed && cNodeName == wxT( "SYMHEIGHT" ) ) + { + SymHeight = GetXmlAttributeIDLong( cNode, 0 ); + symHeightParsed = true; + } + else if( !vesionParsed && cNodeName == wxT( "VERSION" ) ) + { + Version = GetXmlAttributeIDLong( cNode, 0 ); + vesionParsed = true; + } + else if( cNodeName == wxT( "FIGURE" ) ) + { + FIGURE figure; + //TODO try.. catch + throw again with more detailed error information + figure.Parse( cNode ); + Figures.insert( std::make_pair( figure.ID, figure ) ); + } + else if( cNodeName == wxT( "COMPCOPPER" ) ) + { + COMPONENT_COPPER compcopper; + //TODO try.. catch + throw again with more detailed error information + compcopper.Parse( cNode ); + ComponentCoppers.push_back( compcopper ); + } + else if( cNodeName == wxT( "COMPAREA" ) ) + { + COMPONENT_AREA area; + //TODO try.. catch + throw again with more detailed error information + area.Parse( cNode ); + ComponentAreas.insert( std::make_pair( area.ID, area ) ); + } + else if( cNodeName == wxT( "TEXT" ) ) + { + TEXT txt; + //TODO try.. catch + throw again with more detailed error information + txt.Parse( cNode ); + Texts.insert( std::make_pair( txt.ID, txt ) ); + } + else if( cNodeName == wxT( "PAD" ) ) + { + PAD pad; + //TODO try.. catch + throw again with more detailed error information + pad.Parse( cNode ); + Pads.insert( std::make_pair( pad.ID, pad ) ); + } + else if( cNodeName == wxT( "TEXTLOC" ) ) + { + TEXT_LOCATION textloc; + //TODO try.. catch + throw again with more detailed error information + textloc.Parse( cNode ); + TextLocations.insert( std::make_pair( textloc.AttributeID, textloc ) ); + } + else if( cNodeName == wxT( "ATTR" ) ) + { + ATTRIBUTE_VALUE attrVal; + //TODO try.. catch + throw again with more detailed error information + attrVal.Parse( cNode ); + AttributeValues.insert( std::make_pair( attrVal.AttributeID, attrVal ) ); + } + else if( !dimensionsParsed && cNodeName == wxT( "DIMENSIONS" ) ) + { + XNODE* dimensionNode = cNode->GetChildren(); + + for( ; dimensionNode; dimensionNode = dimensionNode->GetNext() ) + { + if( DIMENSION::IsDimension( dimensionNode ) ) + { + DIMENSION dim; + //TODO try.. catch + throw again with more detailed error information + dim.Parse( dimensionNode ); + Dimensions.insert( std::make_pair( dim.ID, dim ) ); + } + else + THROW_UNKNOWN_NODE_IO_ERROR( dimensionNode->GetName(), cNodeName ); + } + + dimensionsParsed = true; + } + else + { + THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() ); + } + } + + if( !originParsed ) + THROW_MISSING_PARAMETER_IO_ERROR( wxT( "PT" ), aNode->GetName() ); +} + + +void CADSTAR_PCB_ARCHIVE_PARSER::LIBRARY::Parse( XNODE* aNode ) +{ + wxASSERT( aNode->GetName() == wxT( "LIBRARY" ) ); + + XNODE* cNode = aNode->GetChildren(); + + for( ; cNode; cNode = cNode->GetNext() ) + { + wxString cNodeName = cNode->GetName(); + + if( cNodeName == wxT( "SYMDEF" ) ) + { + SYMDEF symdef; + //TODO try.. catch + throw again with more detailed error information + symdef.Parse( cNode ); + ComponentDefinitions.insert( std::make_pair( symdef.ID, symdef ) ); + } + else + { + THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() ); + } + } +} diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.h b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.h index 51cd639845..43ce0338be 100644 --- a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.h +++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.h @@ -26,621 +26,47 @@ #ifndef CADSTAR_PCB_ARCHIVE_PARSER_H_ #define CADSTAR_PCB_ARCHIVE_PARSER_H_ -#include +#include +#include #include #include -const long CPA_UNDEFINED = -1; ///< Undefined Parameter - -typedef wxString CPA_ID; - //================================= -// HEADER +// MACRO DEFINITIONS //================================= - - -struct CPA_FORMAT -{ - wxString Type; - long SomeInt; ///< It is unclear what this parameter is used for - long Version; ///< Archive version number (e.g. 21 => CADSTAR 2018.0 and 2019.0 arhive, - ///< 20=> CADSTAR 18.0 archive, 19=> CADSTAR 17.0 archive, etc.) - void Parse( XNODE* aNode ); -}; - - -struct CPA_TIMESTAMP -{ - long Year; - long Month; - long Day; - long Hour; - long Minute; - long Second; - - void Parse( XNODE* aNode ); -}; - -//Note: there are possibly several other resolutions, but HUNDREDTH MICRON is only one known -enum class CPA_RESOLUTION -{ - HUNDREDTH_MICRON -}; - - -struct CPA_HEADER -{ - CPA_FORMAT Format; - wxString JobFile; - wxString JobTitle; - wxString Generator; - CPA_RESOLUTION Resolution; - CPA_TIMESTAMP Timestamp; - - void Parse( XNODE* aNode ); -}; - - -//================================= -// ASSIGNMENTS -//================================= - -//................................. -// ASSIGNMENTS -> LAYERDEFS -//................................. - +#define UNDEFINED_LAYER_ID ( LAYER_ID ) wxEmptyString +#define UNDEFINED_MATERIAL_ID ( MATERIAL_ID ) wxEmptyString +#define UNDEFINED_PHYSICAL_LAYER ( PHYSICAL_LAYER ) - 1 /** - * @brief subset of CPA_LAYER_TYPE - for materials only -*/ -enum class CPA_MATERIAL_LAYER_TYPE -{ - CONSTRUCTION, - ELECTRICAL, - NON_ELECTRICAL -}; - - -struct CPA_MATERIAL -{ - CPA_ID ID; - wxString Name; - CPA_MATERIAL_LAYER_TYPE Type; ///< Type of layer appropriate for the material being set up - CADSTAR_COMMON::EVALUE Permittivity; - CADSTAR_COMMON::EVALUE LossTangent; - CADSTAR_COMMON::EVALUE Resistivity; ///< x10^-8 ohm*metre - - void Parse( XNODE* aNode ); -}; - - -enum class CPA_LAYER_TYPE -{ - UNDEFINED, ///< Only used for error detection - ALLLAYER, ///< Inbuilt layer type (cannot be assigned to user layers) - ALLELEC, ///< Inbuilt layer type (cannot be assigned to user layers) - ALLDOC, ///< Inbuilt layer type (cannot be assigned to user layers) - NOLAYER, ///< Inbuilt layer type (cannot be assigned to user layers) - ASSCOMPCOPP, ///< Inbuilt layer type (cannot be assigned to user layers) - JUMPERLAYER, ///< Inbuilt layer type (cannot be assigned to user layers) - ELEC, - POWER, - NONELEC, ///< This type has subtypes - CONSTRUCTION, - DOC -}; - - -enum class CPA_LAYER_SUBTYPE -{ - LAYERSUBTYPE_NONE, - LAYERSUBTYPE_SILKSCREEN, - LAYERSUBTYPE_PLACEMENT, - LAYERSUBTYPE_ASSEMBLY, - LAYERSUBTYPE_SOLDERRESIST, - LAYERSUBTYPE_PASTE -}; - - -enum class CPA_ROUTING_BIAS -{ - UNBIASED, ///< Keyword "UNBIASED" (default) - X, ///< Keyword "X_BIASED" - Y, ///< Keyword "Y_BIASED" - ANTI_ROUTE, ///< Keyword "ANTITRACK" - OBSTACLE ///< Keyword "OBSTACLE" -}; - - -enum class CPA_EMBEDDING -{ - NONE, - ABOVE, - BELOW -}; - -typedef long CPA_PHYSICAL_LAYER; - -struct CPA_LAYER -{ - CPA_ID ID; - wxString Name; - CPA_LAYER_TYPE Type = CPA_LAYER_TYPE::UNDEFINED; - CPA_LAYER_SUBTYPE SubType = CPA_LAYER_SUBTYPE::LAYERSUBTYPE_NONE; - CPA_PHYSICAL_LAYER PhysicalLayer = CPA_UNDEFINED; ///< If CPA_UNDEFINED, no physical layer is - ///< assigned (e.g. documentation and - ///< construction layers) - CPA_ID SwapLayerID = wxEmptyString; ///< If empty, no swap layer - CPA_ROUTING_BIAS RoutingBias = CPA_ROUTING_BIAS::UNBIASED; - long Thickness = 0; ///< Note: Units of length are defined in file header - CPA_ID MaterialId; - CPA_EMBEDDING Embedding = CPA_EMBEDDING::NONE; - - void Parse( XNODE* aNode ); -}; - - -struct CPA_LAYERDEFS -{ - std::map Materials; - std::map Layers; - std::vector LayerStack; - - void Parse( XNODE* aNode ); -}; - - -//................................. -// ASSIGNMENTS -> CODEDEFS -//................................. - -enum class CPA_LINESTYLE -{ - SOLID, - DASH, - DASHDOT, - DASHDOTDOT, - DOT -}; - -struct CPA_LINECODE -{ - CPA_ID ID; - wxString Name; - long Width; - CPA_LINESTYLE Style; - - void Parse( XNODE* aNode ); -}; - - -struct CPA_HATCH -{ - long Step; - long LineWidth; - long OrientAngle; ///< 1/1000 of a Degree - - void Parse( XNODE* aNode ); -}; - - -struct CPA_HATCHCODE -{ - CPA_ID ID; - wxString Name; - std::vector Hatches; - - void Parse( XNODE* aNode ); -}; - - -const long CPA_FONT_NORMAL = 400; -const long CPA_FONT_BOLD = 700; - - -struct CPA_FONT -{ - wxString Name = wxT( "CADSTAR" ); - long Modifier1 = CPA_FONT_NORMAL; ///< It seems this is related to weight. 400=Normal, 700=Bold. - long Modifier2 = 0; ///< It seems this is always 0 regardless of settings - bool KerningPairs = false; ///< From CADSTAR Help: "Kerning Pairs is for causing the system to - ///< automatically reduce the spacing between certain pairs of - ///< characters in order to improve the appearance of the text" - bool Italic = false; - - void Parse( XNODE* aNode ); -}; - - -struct CPA_TEXTCODE -{ - CPA_ID ID; - wxString Name; - long LineWidth; - long Height; - long Width; ///< Defaults to 0 if using system fonts or, if using CADSTAR font, default to - ///< equal height (1:1 aspect ratio). Allows for system fonts to be rendered in - ///< a different aspect ratio. - CPA_FONT Font; - - void Parse( XNODE* aNode ); -}; - - -struct CPA_ROUTECODE -{ - CPA_ID ID; - wxString Name; - long OptimalWidth; - long MinWidth; - long MaxWidth; - long NeckedWidth; - - void Parse( XNODE* aNode ); -}; - - -struct CPA_COPREASSIGN -{ - CPA_ID LayerID; - long CopperWidth; - - void Parse( XNODE* aNode ); -}; - - -struct CPA_COPPERCODE -{ - CPA_ID ID; - wxString Name; - long CopperWidth; - std::vector Reassigns; - - void Parse( XNODE* aNode ); -}; - - -struct CPA_SPACINGCODE -{ - wxString Code; - long Spacing; - - void Parse( XNODE* aNode ); -}; - - -enum class CPA_SHAPE_TYPE -{ - ANNULUS, - BULLET, - CIRCLE, ///< Keyword "ROUND" - DIAMOND, - FINGER, - OCTAGON, - RECTANGLE, - ROUNDED_RECT, ///< Keyword "ROUNDED" - SQUARE -}; - - -struct CPA_PAD_SHAPE -{ - CPA_SHAPE_TYPE ShapeType; - long Size = CPA_UNDEFINED; - long LeftLength = CPA_UNDEFINED; - long RightLength = CPA_UNDEFINED; - long InternalFeature = CPA_UNDEFINED; - long OrientAngle = 0; ///< 1/1000 of a Degree - - static bool IsShape( XNODE* aNode ); - void Parse( XNODE* aNode ); -}; - - -struct CPA_PADREASSIGN -{ - CPA_ID LayerID; - CPA_PAD_SHAPE Shape; - - void Parse( XNODE* aNode ); -}; - - -struct CPA_PADCODE -{ - CPA_ID ID; - wxString Name; - CPA_PAD_SHAPE Shape; - long ReliefClearance = CPA_UNDEFINED; ///< if undefined inherits from design - long ReliefWidth = CPA_UNDEFINED; ///< if undefined inherits from design - bool Plated = true; - long DrillDiameter = CPA_UNDEFINED; - long DrillOversize = CPA_UNDEFINED; - long SlotLength = CPA_UNDEFINED; - long SlotOrientation = CPA_UNDEFINED; - long DrillXoffset = CPA_UNDEFINED; - long DrillYoffset = CPA_UNDEFINED; - - std::vector Reassigns; - - void Parse( XNODE* aNode ); -}; - - -struct CPA_VIAREASSIGN -{ - CPA_ID LayerID; - CPA_PAD_SHAPE Shape; - - void Parse( XNODE* aNode ); -}; - - -struct CPA_VIACODE -{ - CPA_ID ID; - wxString Name; - CPA_PAD_SHAPE Shape; - long ReliefClearance = CPA_UNDEFINED; ///< if undefined inherits from design - long ReliefWidth = CPA_UNDEFINED; ///< if undefined inherits from design - long DrillDiameter = CPA_UNDEFINED; - long DrillOversize = CPA_UNDEFINED; - - std::vector Reassigns; - - void Parse( XNODE* aNode ); -}; - - -struct CPA_LAYERPAIR -{ - CPA_ID ID; - wxString Name; - CPA_PHYSICAL_LAYER PhysicalLayerStart; - CPA_PHYSICAL_LAYER PhysicalLayerEnd; - CPA_ID ViacodeID; - - void Parse( XNODE* aNode ); -}; - - -enum class CPA_ATTROWNER -{ - ALL_ITEMS, - AREA, - BOARD, - COMPONENT, - CONNECTION, - COPPER, - DOCSYMBOL, - FIGURE, - NET, - NETCLASS, - PART, ///< Only library Attributes - PART_DEFINITION, ///< Only library Attributes - PIN, - SYMDEF, - TEMPLATE, - TESTPOINT -}; - - -enum class CPA_ATTRUSAGE -{ - BOTH, ///< From CADSTAR Help: Assigned to both Schematic symbols and PCB components, - ///< and displayed on Schematic and PCB designs. - COMPONENT, ///< From CADSTAR Help: Assigned to PCB components and displayed on PCB designs - PART_DEFINITION, ///< From CADSTAR Help: Assigned to Parts library Definitions and displayed - ///< by the Library searcher - PART_LIBRARY, ///< From CADSTAR Help: Only used by non-Cadstar applicationws - SYMBOL, ///< From CADSTAR Help: Assigned to Schematic Symbols and displayed on - ///< Schematic Designs - UNDEFINED ///< Note: It seems that some attribute have no "ATTRUSAGE" defined. It appears - ///< that the attributes that fall under this category arethe ones associated - ///< with the design itself (i.e. not inherited from the library) -}; - -/** - * @brief NOTE from CADSTAR help: To convert a Part Definition Attribute into a hyperlink, prefix - * the attribute name with "Link " + * Default spacing class for all nets */ -struct CPA_ATTRNAME -{ - CPA_ID ID; - wxString Name; - CPA_ATTROWNER AttributeOwner = CPA_ATTROWNER::ALL_ITEMS; - CPA_ATTRUSAGE AttributeUsage = CPA_ATTRUSAGE::UNDEFINED; - bool NoTransfer = false; ///< True="All Design Types", False="Current Design Type" - ///< "All Design Types" Description from CADSTAR Help: - ///< "The selected attribute name will beavailable when - ///< any design is displayed" - ///< "Current Design Type" From CADSTAR Help: This - ///< restricts the availability of the selected attribute - ///< name to the current design. +#define NO_SPACE_CLASS_ID ( SPACING_CLASS_ID ) wxT( "NO_SPACE_CLASS" ) - void Parse( XNODE* aNode ); -}; +/** + * Component Name Attribute ID - typically used for placement of designators on silk screen. + */ +#define COMPONENT_NAME_ATTRID ( ATTRIBUTE_ID ) wxT( "__COMPONENT_NAME__" ) +/** + * Component Name 2 Attribute ID - typically used for indicating the placement of designators in + * placement drawings. + */ +#define COMPONENT_NAME_2_ATTRID ( ATTRIBUTE_ID ) wxT( "__COMPONENT_NAME_2__" ) +#define PART_NAME_ATTRID ( ATTRIBUTE_ID ) wxT( "__PART_NAME__" ) -struct CPA_ATTRIBUTE_VALUE -{ - CPA_ID AttributeID; - wxString Value; - - void Parse( XNODE* aNode ); -}; - - -struct CPA_NETCLASS -{ - CPA_ID ID; - wxString Name; - std::vector Attributes; - - void Parse( XNODE* aNode ); -}; - - -struct CPA_SPCCLASSNAME -{ - CPA_ID ID; //TODO convert to an enum class containing all valid spacings - wxString Name; - - void Parse( XNODE* aNode ); -}; - -const CPA_ID CPA_NO_SPACE_CLASS_ID = wxT( "NO_SPACE_CLASS" ); ///< Default spacing class - -struct CPA_SPCCLASSSPACE -{ - CPA_ID SpacingClassID1; - CPA_ID SpacingClassID2; - CPA_ID LayerID; ///< Normally LAY0, which corresponds to (All Layers) - long Spacing; - - void Parse( XNODE* aNode ); -}; - - -struct CPA_CODEDEFS -{ - std::map LineCodes; - std::map HatchCodes; - std::map TextCodes; - std::map RouteCodes; - std::map CopperCodes; - std::vector SpacingCodes; ///< Spacing Design Rules - std::map PadCodes; - std::map ViaCodes; - std::map LayerPairs; ///< Default vias to use between pairs of layers - std::map AttributeNames; - std::map NetClasses; - std::map SpacingClassNames; - std::vector SpacingClasses; - - void Parse( XNODE* aNode ); -}; - -//................................. -// ASSIGNMENTS -> TECHNOLOGY -//................................. - -enum class CPA_UNITS -{ - THOU, - INCH, - MICROMETRE, - MM, - CENTIMETER, - METER -}; - -struct CPA_TECHNOLOGY -{ - CPA_UNITS Unit; ///< Unit to display for linear dimensions - long UnitDisplPrecision; ///< Number of decimal points to display for linear dimensions - long InterlineGap; ///< For CADSTAR font only, distance between lines of text, - ///< expressed as a percentage of the text height (accepted - ///< values are 0-100) - long BarlineGap; ///< For CADSTAR font only, distance between top bar and - ///< character, expressed as a percentage of the text height - ///< (accepted values are 0-100) - bool AllowBarredText = false; ///< Specifies if barring is allowed in the design - long AngularPrecision; ///< Number of decimal points to display for angular dimensions - long MinRouteWidth; ///< Manufacturing Design Rule. Corresponds to "Thin Route Width" - long MinNeckedLength; ///< Manufacturing Design Rule. Corresponds to - ///< "Minimum Thinner Track Length" - long MinUnneckedLength; ///< Manufacturing Design Rule. Corresponds to - ///< "Minimum Thicker Track Length" - long MinMitre; ///< Manufacturing Design Rule. Corresponds to "Minimum Mitre" - long MaxMitre; ///< Manufacturing Design Rule. Corresponds to "Maximum Mitre" - long MaxPhysicalLayer; ///< Should equal number of copper layers. However, it seems this - ///< can be set to any arbitrarily high number as long as it is - ///< greater or equal to the number of copper layers. Also the - ///< last copper layer (bottom) must have this set as its value. - long TrackGrid; ///< Grid for Routes (equal X and Y steps) - long ViaGrid; ///< Grid for Vias (equal X and Y steps) - - CADSTAR_COMMON::POINT DesignOrigin; - std::pair DesignArea; - CADSTAR_COMMON::POINT DesignRef; ///< Appears to be 0,0 always - CADSTAR_COMMON::POINT DesignLimit; - - bool BackOffJunctions = false; - bool BackOffWidthChange = false; - - void Parse( XNODE* aNode ); -}; - -//................................. -// ASSIGNMENTS -> GRIDS -//................................. - -enum class CPA_GRID_TYPE -{ - FRACTIONALGRID, ///< Param1 = Unit, Param2 = Divisor. The grid is equal in X and Y dimensions - ///< with a step size equal to Param1/Param2 - STEPGRID ///< Param1 = X Step, Param2 = Y Step. A standard x,y grid. -}; - - -struct CPA_GRID -{ - CPA_GRID_TYPE Type; - wxString Name; - long Param1; ///< Either Unit or X step, depending on Type (see CPA_GRID_TYPE for - ///< more details) - long Param2; ///< Either Divisor or Y step, depending on Type (see CPA_GRID_TYPE for - ///< more details) - - static bool IsGrid( XNODE* aNode ); - void Parse( XNODE* aNode ); -}; - - -struct CPA_GRIDS -{ - CPA_GRID WorkingGrid; - CPA_GRID ScreenGrid; ///< From CADSTAR Help: "There is one Screen Grid, which is - ///< visible as dots on the screen. You cannot specify your - ///< own name for the Screen Grid. The visibility and colour - ///< of the dots representing the Screen Grid is set up by - ///< the Highlight category on the Colours dialog. - ///< - ///< The type of Screen grid displayed(Lined or Points) is - ///< set up on the Display dialog within Options(File menu)." - std::vector UserGrids; ///< List of predefined grids created by the user - - void Parse( XNODE* aNode ); -}; - - -struct CPA_ASSIGNMENTS -{ - CPA_LAYERDEFS Layerdefs; - CPA_CODEDEFS Codedefs; - CPA_TECHNOLOGY Technology; - CPA_GRIDS Grids; - bool NetclassEditAttributeSettings = false; //< Unclear what this does - bool SpacingclassEditAttributeSettings = false; //< Unclear what this does - - void Parse( XNODE* aNode ); -}; - - -//================================= -// CPA_FILE -//================================= /** * @brief Represents a CADSTAR PCB Archive (CPA) file */ -class CPA_FILE +class CADSTAR_PCB_ARCHIVE_PARSER : public CADSTAR_ARCHIVE_COMMON { public: - explicit CPA_FILE( wxString aFilename ) : Filename( aFilename ) + explicit CADSTAR_PCB_ARCHIVE_PARSER( wxString aFilename ) + : Filename( aFilename ), CADSTAR_ARCHIVE_COMMON() { + KiCadUnitMultiplier = 10; // assume hundredth micron } /** @@ -650,14 +76,1152 @@ public: */ void Parse(); + typedef wxString MATERIAL_ID; + typedef wxString LAYER_ID; + typedef long PHYSICAL_LAYER; + typedef wxString LINECODE_ID; + typedef wxString HATCHCODE_ID; + typedef wxString TEXTCODE_ID; + typedef wxString ROUTECODE_ID; + typedef wxString COPPERCODE_ID; + typedef wxString PADCODE_ID; + typedef wxString VIACODE_ID; + typedef wxString LAYERPAIR_ID; + typedef wxString ATTRIBUTE_ID; + typedef wxString NETCLASS_ID; + typedef wxString SPACING_CLASS_ID; + typedef wxString FIGURE_ID; + typedef wxString COMP_AREA_ID; + typedef long PAD_ID; + typedef wxString TEXT_ID; + typedef wxString DIMENSION_ID; + typedef wxString SYMDEF_ID; + + + //================================= + // HEADER + //================================= + + + struct FORMAT + { + wxString Type; + long SomeInt; ///< It is unclear what this parameter is used for + long Version; ///< Archive version number (e.g. 21 => CADSTAR 2018.0 and 2019.0 arhive, + ///< 20=> CADSTAR 18.0 archive, 19=> CADSTAR 17.0 archive, etc.) + void Parse( XNODE* aNode ); + }; + + + struct TIMESTAMP + { + long Year; + long Month; + long Day; + long Hour; + long Minute; + long Second; + + void Parse( XNODE* aNode ); + }; + + //Note: there are possibly several other resolutions, but HUNDREDTH MICRON is only one known + enum class RESOLUTION + { + HUNDREDTH_MICRON + }; + + + struct HEADER + { + FORMAT Format; + wxString JobFile; + wxString JobTitle; + wxString Generator; + RESOLUTION Resolution; + TIMESTAMP Timestamp; + + void Parse( XNODE* aNode ); + }; + + + //================================= + // ASSIGNMENTS + //================================= + + //................................. + // ASSIGNMENTS -> LAYERDEFS + //................................. + + + /** + * @brief Type of layer appropriate for the material being set up + */ + enum class MATERIAL_LAYER_TYPE + { + CONSTRUCTION, + ELECTRICAL, ///< Either @see LAYER_TYPE::ELEC or @see LAYER_TYPE::POWER + NON_ELECTRICAL + }; + + + struct MATERIAL + { + MATERIAL_ID ID; + wxString Name; + MATERIAL_LAYER_TYPE Type; + EVALUE Permittivity; + EVALUE LossTangent; + EVALUE Resistivity; ///< x10^-8 ohm*metre + + void Parse( XNODE* aNode ); + }; + + + enum class LAYER_TYPE + { + UNDEFINED, ///< Only used for error detection + ALLLAYER, ///< Inbuilt layer type (cannot be assigned to user layers) + ALLELEC, ///< Inbuilt layer type (cannot be assigned to user layers) + ALLDOC, ///< Inbuilt layer type (cannot be assigned to user layers) + NOLAYER, ///< Inbuilt layer type (cannot be assigned to user layers) + ASSCOMPCOPP, ///< Inbuilt layer type (cannot be assigned to user layers) + JUMPERLAYER, ///< Inbuilt layer type (cannot be assigned to user layers) + ELEC, + POWER, + NONELEC, ///< This type has subtypes + CONSTRUCTION, + DOC + }; + + + enum class LAYER_SUBTYPE + { + LAYERSUBTYPE_NONE, + LAYERSUBTYPE_SILKSCREEN, + LAYERSUBTYPE_PLACEMENT, + LAYERSUBTYPE_ASSEMBLY, + LAYERSUBTYPE_SOLDERRESIST, + LAYERSUBTYPE_PASTE + }; + + + enum class ROUTING_BIAS + { + UNBIASED, ///< Keyword "UNBIASED" (default) + X, ///< Keyword "X_BIASED" + Y, ///< Keyword "Y_BIASED" + ANTI_ROUTE, ///< Keyword "ANTITRACK" + OBSTACLE ///< Keyword "OBSTACLE" + }; + + + enum class EMBEDDING + { + NONE, + ABOVE, + BELOW + }; + + struct LAYER + { + LAYER_ID ID; + wxString Name; + LAYER_TYPE Type = LAYER_TYPE::UNDEFINED; + LAYER_SUBTYPE SubType = LAYER_SUBTYPE::LAYERSUBTYPE_NONE; + PHYSICAL_LAYER PhysicalLayer = + UNDEFINED_PHYSICAL_LAYER; ///< If UNDEFINED, no physical layer is + ///< assigned (e.g. documentation and + ///< construction layers) + LAYER_ID SwapLayerID = UNDEFINED_LAYER_ID; ///< If UNDEFINED_LAYER_ID, no swap layer + ROUTING_BIAS RoutingBias = ROUTING_BIAS::UNBIASED; + long Thickness = 0; ///< Note: Units of length are defined in file header + MATERIAL_ID MaterialId; + EMBEDDING Embedding = EMBEDDING::NONE; + + void Parse( XNODE* aNode ); + }; + + + struct LAYERDEFS + { + std::map Materials; + std::map Layers; + std::vector LayerStack; + + void Parse( XNODE* aNode ); + }; + + + //................................. + // ASSIGNMENTS -> CODEDEFS + //................................. + + enum class LINESTYLE + { + SOLID, + DASH, + DASHDOT, + DASHDOTDOT, + DOT + }; + + struct LINECODE + { + LINECODE_ID ID; + wxString Name; + long Width; + LINESTYLE Style; + + void Parse( XNODE* aNode ); + }; + + + struct HATCH + { + long Step; + long LineWidth; + long OrientAngle; ///< 1/1000 of a Degree + + void Parse( XNODE* aNode ); + }; + + + struct HATCHCODE + { + HATCHCODE_ID ID; + wxString Name; + std::vector Hatches; + + void Parse( XNODE* aNode ); + }; + + + static const long FONT_NORMAL = 400; + static const long FONT_BOLD = 700; + + + struct FONT + { + wxString Name = wxT( "CADSTAR" ); + long Modifier1 = FONT_NORMAL; ///< It seems this is related to weight. 400=Normal, 700=Bold. + long Modifier2 = 0; ///< It seems this is always 0 regardless of settings + bool KerningPairs = + false; ///< From CADSTAR Help: "Kerning Pairs is for causing the system to + ///< automatically reduce the spacing between certain pairs of + ///< characters in order to improve the appearance of the text" + bool Italic = false; + + void Parse( XNODE* aNode ); + }; + + + struct TEXTCODE + { + TEXTCODE_ID ID; + wxString Name; + long LineWidth; + long Height; + long Width; ///< Defaults to 0 if using system fonts or, if using CADSTAR font, default to + ///< equal height (1:1 aspect ratio). Allows for system fonts to be rendered in + ///< a different aspect ratio. + FONT Font; + + void Parse( XNODE* aNode ); + }; + + + struct ROUTECODE + { + //TODO: Generalise this so it can also be used with CSA files + // (CSA files use "SROUTEWIDTH" subnode, instead of attribute) + + ROUTECODE_ID ID; + wxString Name; + long OptimalWidth; + long MinWidth; + long MaxWidth; + long NeckedWidth; + + void Parse( XNODE* aNode ); + }; + + + struct COPREASSIGN + { + LAYER_ID LayerID; + long CopperWidth; + + void Parse( XNODE* aNode ); + }; + + + struct COPPERCODE + { + COPPERCODE_ID ID; + wxString Name; + long CopperWidth; + std::vector Reassigns; + + void Parse( XNODE* aNode ); + }; + + + struct SPACINGCODE + { + wxString Code; //TODO convert to an enum class containing all valid spacings + long Spacing; + + void Parse( XNODE* aNode ); + }; + + + enum class PAD_SHAPE_TYPE + { + ANNULUS, + BULLET, + CIRCLE, ///< Keyword "ROUND" + DIAMOND, + FINGER, + OCTAGON, + RECTANGLE, + ROUNDED_RECT, ///< Keyword "ROUNDED" + SQUARE + }; + + + struct PAD_SHAPE + { + PAD_SHAPE_TYPE ShapeType; + long Size = UNDEFINED_VALUE; + long LeftLength = UNDEFINED_VALUE; + long RightLength = UNDEFINED_VALUE; + long InternalFeature = UNDEFINED_VALUE; + long OrientAngle = 0; ///< 1/1000 of a Degree + + static bool IsPadShape( XNODE* aNode ); + void Parse( XNODE* aNode ); + }; + + + struct PADREASSIGN + { + LAYER_ID LayerID; + PAD_SHAPE Shape; + + void Parse( XNODE* aNode ); + }; + + + struct PADCODE + { + PADCODE_ID ID; + wxString Name; + PAD_SHAPE Shape; + long ReliefClearance = UNDEFINED_VALUE; ///< if undefined inherits from design + long ReliefWidth = UNDEFINED_VALUE; ///< if undefined inherits from design + bool Plated = true; + long DrillDiameter = UNDEFINED_VALUE; + long DrillOversize = UNDEFINED_VALUE; + long SlotLength = UNDEFINED_VALUE; + long SlotOrientation = UNDEFINED_VALUE; + long DrillXoffset = UNDEFINED_VALUE; + long DrillYoffset = UNDEFINED_VALUE; + + std::map Reassigns; + + void Parse( XNODE* aNode ); + }; + + + struct VIAREASSIGN + { + LAYER_ID LayerID; + PAD_SHAPE Shape; + + void Parse( XNODE* aNode ); + }; + + + struct VIACODE + { + VIACODE_ID ID; + wxString Name; + PAD_SHAPE Shape; + long ReliefClearance = UNDEFINED_VALUE; ///< if undefined inherits from design + long ReliefWidth = UNDEFINED_VALUE; ///< if undefined inherits from design + long DrillDiameter = UNDEFINED_VALUE; + long DrillOversize = UNDEFINED_VALUE; + + std::map Reassigns; + + void Parse( XNODE* aNode ); + }; + + + struct LAYERPAIR + { + LAYERPAIR_ID ID; + wxString Name; + PHYSICAL_LAYER PhysicalLayerStart; + PHYSICAL_LAYER PhysicalLayerEnd; + VIACODE_ID ViacodeID; + + void Parse( XNODE* aNode ); + }; + + + enum class ATTROWNER + { + ALL_ITEMS, + AREA, + BOARD, + COMPONENT, + CONNECTION, + COPPER, + DOCSYMBOL, + FIGURE, + NET, + NETCLASS, + PART, ///< Only library Attributes + PART_DEFINITION, ///< Only library Attributes + PIN, + SYMDEF, + TEMPLATE, + TESTPOINT + }; + + + enum class ATTRUSAGE + { + BOTH, ///< From CADSTAR Help: Assigned to both Schematic symbols and PCB components, + ///< and displayed on Schematic and PCB designs. + COMPONENT, ///< From CADSTAR Help: Assigned to PCB components and displayed on PCB designs + PART_DEFINITION, ///< From CADSTAR Help: Assigned to Parts library Definitions and displayed + ///< by the Library searcher + PART_LIBRARY, ///< From CADSTAR Help: Only used by non-Cadstar applications + SYMBOL, ///< From CADSTAR Help: Assigned to Schematic Symbols and displayed on + ///< Schematic Designs + UNDEFINED ///< Note: It seems that some attribute have no "ATTRUSAGE" defined. It appears + ///< that the attributes that fall under this category arethe ones associated + ///< with the design itself (i.e. not inherited from the library) + }; + + /** + * @brief NOTE from CADSTAR help: To convert a Part Definition Attribute into a hyperlink, prefix + * the attribute name with "Link " + */ + struct ATTRNAME + { + ATTRIBUTE_ID ID; + wxString Name; + ATTROWNER AttributeOwner = ATTROWNER::ALL_ITEMS; + ATTRUSAGE AttributeUsage = ATTRUSAGE::UNDEFINED; + bool NoTransfer = false; ///< True="All Design Types", False="Current Design Type" + ///< "All Design Types" Description from CADSTAR Help: + ///< "The selected attribute name will beavailable when + ///< any design is displayed" + ///< "Current Design Type" From CADSTAR Help: This + ///< restricts the availability of the selected attribute + ///< name to the current design. + + void Parse( XNODE* aNode ); + }; + + + struct ATTRIBUTE_VALUE + { + ATTRIBUTE_ID AttributeID; + wxString Value; + + void Parse( XNODE* aNode ); + }; + + + struct NETCLASS + { + NETCLASS_ID ID; + wxString Name; + std::vector Attributes; + + void Parse( XNODE* aNode ); + }; + + + struct SPCCLASSNAME + { + SPACING_CLASS_ID ID; + wxString Name; + + void Parse( XNODE* aNode ); + }; + + + struct SPCCLASSSPACE + { + SPACING_CLASS_ID SpacingClassID1; + SPACING_CLASS_ID SpacingClassID2; + LAYER_ID LayerID; ///< Normally LAY0, which corresponds to (All Layers) + long Spacing; + + void Parse( XNODE* aNode ); + }; + + + struct CODEDEFS + { + std::map LineCodes; + std::map HatchCodes; + std::map TextCodes; + std::map RouteCodes; + std::map CopperCodes; + std::vector SpacingCodes; ///< Spacing Design Rules + std::map PadCodes; + std::map ViaCodes; + std::map + LayerPairs; ///< Default vias to use between pairs of layers + + std::map AttributeNames; + std::map NetClasses; + std::map SpacingClassNames; + std::vector SpacingClasses; + + void Parse( XNODE* aNode ); + }; + + //................................. + // ASSIGNMENTS -> TECHNOLOGY + //................................. + + enum class UNITS + { + THOU, + INCH, + MICROMETRE, + MM, + CENTIMETER, + METER + }; + + static UNITS ParseUnits( XNODE* aNode ); + + struct TECHNOLOGY_SECTION + { + UNITS Units; ///< Units to display for linear dimensions + long UnitDisplPrecision; ///< Number of decimal points to display for linear dimensions + long InterlineGap; ///< For CADSTAR font only, distance between lines of text, + ///< expressed as a percentage of the text height (accepted + ///< values are 0-100) + long BarlineGap; ///< For CADSTAR font only, distance between top bar and + ///< character, expressed as a percentage of the text height + ///< (accepted values are 0-100) + bool AllowBarredText = false; ///< Specifies if barring is allowed in the design + long AngularPrecision; ///< Number of decimal points to display for angular dimensions + long MinRouteWidth; ///< Manufacturing Design Rule. Corresponds to "Thin Route Width" + long MinNeckedLength; ///< Manufacturing Design Rule. Corresponds to + ///< "Minimum Thinner Track Length" + long MinUnneckedLength; ///< Manufacturing Design Rule. Corresponds to + ///< "Minimum Thicker Track Length" + long MinMitre; ///< Manufacturing Design Rule. Corresponds to "Minimum Mitre" + long MaxMitre; ///< Manufacturing Design Rule. Corresponds to "Maximum Mitre" + long MaxPhysicalLayer; ///< Should equal number of copper layers. However, it seems this + ///< can be set to any arbitrarily high number as long as it is + ///< greater or equal to the number of copper layers. Also the + ///< last copper layer (bottom) must have this set as its value. + long TrackGrid; ///< Grid for Routes (equal X and Y steps) + long ViaGrid; ///< Grid for Vias (equal X and Y steps) + + POINT DesignOrigin; + std::pair DesignArea; + POINT DesignRef; ///< Appears to be 0,0 always + POINT DesignLimit; + + bool BackOffJunctions = false; + bool BackOffWidthChange = false; + + void Parse( XNODE* aNode ); + }; + + //................................. + // ASSIGNMENTS -> GRIDS + //................................. + + enum class GRID_TYPE + { + FRACTIONALGRID, ///< Param1 = Units, Param2 = Divisor. The grid is equal in X and Y + ///< dimensions with a step size equal to Param1/Param2 + STEPGRID ///< Param1 = X Step, Param2 = Y Step. A standard x,y grid. + }; + + + struct GRID + { + GRID_TYPE Type; + wxString Name; + long Param1; ///< Either Units or X step, depending on Type (see GRID_TYPE for + ///< more details) + long Param2; ///< Either Divisor or Y step, depending on Type (see GRID_TYPE for + ///< more details) + + static bool IsGrid( XNODE* aNode ); + void Parse( XNODE* aNode ); + }; + + + struct GRIDS + { + GRID WorkingGrid; + GRID ScreenGrid; ///< From CADSTAR Help: "There is one Screen Grid, which is + ///< visible as dots on the screen. You cannot specify your + ///< own name for the Screen Grid. The visibility and colour + ///< of the dots representing the Screen Grid is set up by + ///< the Highlight category on the Colours dialog. + ///< + ///< The type of Screen grid displayed(Lined or Points) is + ///< set up on the Display dialog within Options(File menu)." + std::vector UserGrids; ///< List of predefined grids created by the user + + void Parse( XNODE* aNode ); + }; + + + struct ASSIGNMENTS + { + LAYERDEFS Layerdefs; + CODEDEFS Codedefs; + TECHNOLOGY_SECTION Technology; + GRIDS Grids; + bool NetclassEditAttributeSettings = false; //< Unclear what this does + bool SpacingclassEditAttributeSettings = false; //< Unclear what this does + + void Parse( XNODE* aNode ); + }; + + + /** + * @brief Corresponds to "Display when" Item property. From CADSTAR + * Help: "This parameter enables you to make the visibility of + * a component outline/area (or an area of component copper, or + * a string of component text) dependent on the current mirror + * status of the component. + * + * For example, you may require a string of component text to + * be displayed only when the component is mirrored." + */ + enum class SWAP_RULE + { + NO_SWAP, ///< Display when Unmirrored + USE_SWAP_LAYER, ///< Display when Mirrored + BOTH ///< Always display (Mirrored and Unmirrored) + }; + + static SWAP_RULE ParseSwapRule( XNODE* aNode ); + + + struct FIGURE + { + FIGURE_ID ID; + LINECODE_ID LineCodeID; + LAYER_ID LayerID; + SHAPE Shape; //< Uses the component's coordinate frame if within a component + //< definition, otherwise uses the design's coordinate frame. + SWAP_RULE SwapRule = SWAP_RULE::BOTH; + + void Parse( XNODE* aNode ); + }; + + /** + * @brief A shape of copper in the component footprint. For KiCad import, this could + * be converted to a custom shaped pad (as long as AssociatedPadIDs is not empty) + */ + struct COMPONENT_COPPER + { + COPPERCODE_ID CopperCodeID; + LAYER_ID LayerID; + SHAPE Shape; //< Uses the component's coordinate frame. + SWAP_RULE SwapRule = SWAP_RULE::BOTH; + std::vector AssociatedPadIDs; + + void Parse( XNODE* aNode ); + }; + + /** + * @brief From CADSTAR Help: "Area is for creating areas within which, and nowhere else, certain + * operations are carried out (e.g. Placement.); and for creating 'keep out' areas, within which + * no operations are carried out and where no items are placed by operations such as Placement + * and Routing." + */ + struct COMPONENT_AREA + { + COMP_AREA_ID ID; + LINECODE_ID LineCodeID; + LAYER_ID LayerID; + SHAPE Shape; //< Uses the component's coordinate frame. + SWAP_RULE SwapRule = SWAP_RULE::BOTH; + + bool NoTracks = false; ///< From CADSTAR Help: "Check this button to specify that any area + ///< created by the Rectangle, Circle and Polygon icons can be used + ///< by the Auto Router and Route Editor options as the area within + ///< which no routes are placed during automatic routing." + bool NoVias = false; ///< From CADSTAR Help: "Check this button to specify that any area + ///< created by the Rectangle, Circle and Polygon icons can be used + ///< by the Auto Router and Route Editor options as the area within + ///< which no vias are placed during automatic routing." + + void Parse( XNODE* aNode ); + }; + + + /** + * @brief From CADSTAR Help: "This parameter indicates the physical layers on which the selected + * pad is placed. Note: When you change the Side parameter in PCB Design, the Side assigned to the + * pad in the library is not overwritten." + */ + enum class PAD_SIDE + { + MINIMUM, ///< PHYSICAL_LAYER_ID 1 (i.e. front / top side). Normally used for surface + ///< mount devices. + MAXIMUM, ///< The highest PHYSICAL_LAYER_ID currently defined (i.e. back / bottom + ///< side). Normally used for surface mount devices. + THROUGH_HOLE ///< All physical layers currently defined + }; + + + /** + * @brief From CADSTAR help: "For specifying the directions in which routes can enter or exit the + * pad. There are eight pre-defined directions to choose from, North, South, East, West, + * North-East, North-West, South-East and South-West, plus "Free Angle" which allows routes to exit + * in any direction. + * + * If none of the direction boxes are checked, the system uses the default which is all directions + * (as shown above) for all pad shapes, except the long (drawn) Routes exit from the short sides of + * long pads - in other words in line with the long axis. + * + * Note: These Exit Directions are applied to the PCB component. If the PCB component is rotated + * when it is used on a PCB Design, the Exit Directions will rotate with it." + * + * The main thing to note is that the exit angle is not relative to the pad (even if the pad is + * at an angle): it is relative to the component as a whole. This is confusing, considering this + * property belongs to the pad... + */ + struct PAD_EXITS + { + bool FreeAngle = false; + bool North = false; + bool NorthEast = false; + bool East = false; + bool SouthEast = false; + bool South = false; + bool SouthWest = false; + bool West = false; + bool NorthWest = false; + + void Parse( XNODE* aNode ); + }; + + + struct PAD + { + PAD_ID ID; + POINT Position; ///< Pad position within the component's coordinate frame. + PADCODE_ID PadCodeID; + PAD_SIDE Side; ///< See PAD_SIDE + long OrientAngle = 0; + PAD_EXITS Exits; ///< See PAD_EXITS + + wxString Identifier; ///< This is an identifier that is displayed to the user. + ///< Internally, the pad is identified by sequential Pad ID + ///< (see ID). From CADSTAR Help: "This is how the pin is + ///< identified, and is used when creating a part and for reload + ///< and replace. It replaces the CADSTAR 13.0 pad sequence + ///< number but is much less restrictive i.e. It need not be 1, 2, + ///< 3 etc. and can contain alpha and / or numeric characters." + bool FirstPad = false; ///< From CADSTAR Help: "Only one pad can have this property; if an + ///< existing pad in the design already has this property it will be + ///< removed from the existing pad when this new pad is added. The + ///< property is used by the 'First Pad' highlight when in a PCB + ///< design." + bool PCBonlyPad = + false; ///< From CADSTAR Help: "The PCB Only Pad property can be used to stop + ///< ECO Update, Back Annotation, and Design Comparison incorrectly + ///< acting on mechanical pads / components that only appear in the + ///< PCB design." + + void Parse( XNODE* aNode ); + }; + + + /** + * @brief From CADSTAR Help: "Text Alignment enables you to define the position of an alignment + * origin for all text items in CADSTAR. The alignment origin is a point on or within the text + * boundary and defines how the text is displayed. + * + * For example, with an alignment of bottom-right the origin will be positioned at the bottom + * right of the text boundary. This makes it easier to right-align several text items + * regardless of the length of text displayed. + * + * Text Alignment applies to all CADSTAR text. [...] + * + * Note: Unaligned text operates in the way CADSTAR text always has. In most cases this behaves + * as Bottom Left alignment, but there are a few exceptions, e.g. pin names. Also unaligned + * multiline text has an origin Bottom Left of the first line." + * + * See also JUSTIFICATION + */ + enum class ALIGNMENT + { + NO_ALIGNMENT, ///< NO_ALIGNMENT has different meaning depending on the object type + TOPLEFT, + TOPCENTER, + TOPRIGHT, + CENTERLEFT, + CENTERCENTER, + CENTERRIGHT, + BOTTOMLEFT, + BOTTOMCENTER, + BOTTOMRIGHT + }; + + static ALIGNMENT ParseAlignment( XNODE* aNode ); + + /** + * @brief From CADSTAR Help: "Multi Line Text can also be justified as Left, Centre or Right. + * This does not affect the text alignment. Note: Justification of single line text has no + * affect." + * + * This only affects multiline text + * + * See also ALIGNMENT + */ + enum class JUSTIFICATION + { + LEFT, + CENTER, + RIGHT + }; + + static JUSTIFICATION ParseJustification( XNODE* aNode ); + + + /** + * @brief Corresponds to CADSTAR "origin". This is used for setting a location of an attribute + * e.g. Designator (called Component Name in CADSTAR), Part Name (name of component in the + * libary), etc. The atom identifier is "TEXTLOC" + */ + struct TEXT_LOCATION + { + ATTRIBUTE_ID AttributeID; + TEXTCODE_ID TextCodeID; + LAYER_ID LayerID; + POINT Position; + long OrientAngle = 0; + bool Mirror = false; + JUSTIFICATION Justification = + JUSTIFICATION::LEFT; ///< Note: Justification has no effect on single lines of text + ALIGNMENT Alignment = ALIGNMENT:: + BOTTOMLEFT; ///< The default alignment for TEXT_LOCATION (when "NO_ALIGNMENT" is + ///< selected) is Bottom left, matching CADSTAR's default behaviour + + void Parse( XNODE* aNode ); + }; + + + struct TEXT + { + TEXT_ID ID; + wxString Text; //TODO: Need to lex/parse to identify design fields and hyperlinks + TEXTCODE_ID TextCodeID; + LAYER_ID LayerID; + POINT Position; + long OrientAngle = 0; + bool Mirror = false; + SWAP_RULE SwapRule = SWAP_RULE::BOTH; + JUSTIFICATION Justification = + JUSTIFICATION::LEFT; ///< Note: Justification has no effect on single lines of text + ALIGNMENT Alignment = ALIGNMENT:: + NO_ALIGNMENT; ///< In CADSTAR The default alignment for a TEXT object (when + ///< "(No Alignment()" is selected) Bottom Left of the *first line*. + ///< Note that this is different from BOTTOM_LEFT (which is bottom + ///< left of the whole text block) + + void Parse( XNODE* aNode ); + }; + + + enum class ANGUNITS + { + DEGREES, + RADIANS + }; + + static ANGUNITS ParseAngunits( XNODE* aNode ); + + /** + * @brief Linear, leader (radius/diameter) or angular dimension + */ + struct DIMENSION + { + enum class TYPE + { + LINEARDIM, ///< Linear Dimension + LEADERDIM, ///< Typically used for Radius/Diameter Dimension + ANGLEDIM ///< Angular Dimension + }; + + enum class SUBTYPE + { + ORTHOGONAL, ///< An orthogonal dimension (either x or y measurement) + ///< token=DIMENSION_ORTHOGONAL + DIRECT, ///< A linear dimension parallel to measurement with perpendicular + ///< extension lines token=DIMENSION_DIRECT + ANGLED, ///< A linear dimension parallel to measurement but with orthogonal + ///< extension lines (i.e. x or y axis, angled with respect to measurement) + ///< token=DIMENSION_ANGLED + DIAMETER, ///< token=DIMENSION_DIAMETER + RADIUS, ///< token=DIMENSION_RADIUS + ANGULAR ///< token=DIMENSION_ANGULAR + }; + + struct ARROW //"DIMARROW" + { + enum class STYLE + { + OPEN, ///< The arrow head is made up of two angled lines either side of + ///< main line. "DIMENSION_ARROWOPEN" + CLOSED, ///< The arrow head is made up of two angled lines either side of + ///< main line plus two other lines perpendicular to the main line + ///< finishing at the end of each of the two angled lines, with the + ///< main line still reaching tip of the arrow. + ///< "DIMENSION_ARROWCLOSED" + CLEAR, ///< Same as closed but the main line finishes at the start of the + ///< perpendicular lines."DIMENSION_ARROWCLEAR" + CLOSED_FILLED ///< The same as CLOSED or CLEAR arrows, but with a solid fill + ///< "DIMENSION_ARROWCLOSEDFILLED" + }; + + STYLE ArrowStyle; ///< Subnode="ARROWSTYLE" + long UpperAngle; ///< token="ARROWANGLEA" + long LowerAngle; ///< token="ARROWANGLEB" + long ArrowLength; ///< The length of the angled lines that make up the arrow head + + void Parse( XNODE* aNode ); + }; + + /** + * @brief Contains formatting specific for a CADSTAR_PCB_ARCHIVE_PARSER::DIMENSION object. + * Note that none of the parameters has any effect on the position of the dimension text - + * it is more of an "intention" of where it should be placed. The user can manually + * drag the location of the dimension text. Therefore, the actual position of the dimension + * text is as defined in the `Text` object within CADSTAR_PCB_ARCHIVE_PARSER::DIMENSION. + * + * However, TEXTFORMAT does specifify `TextGap` (i.e. how far to pull back the dimension + * line from the dimension text which does get used when the dimension text is placed + * on top of the dimension line, if the dimension line is STYLE::INTERNAL). + * + * Note: the token is "DIMTEXT" in the CADSTAR format, but this has been renamed to + * TEXTFORMAT in the cadstar2kicadplugin for ease of understanding. + */ + struct TEXTFORMAT + { + enum class STYLE ///< Token "TXTSTYLE" + { + INSIDE, ///< Embedded with the line (the Gap parameter specifies the gap between + ///< the text and the end of the line) DIMENSION_INTERNAL + OUTSIDE ///< Above the line (the Offset parameter specifies how far above the line + ///< the text is) DIMENSION_EXTERNAL + }; + + STYLE Style; + long TextGap; ///< Specifies the gap between the text and the end of the line + long TextOffset; ///< Specifies how far above the line the text is (doesn't have + ///< an effect on actual position!) + + void Parse( XNODE* aNode ); + }; + + + struct EXTENSION_LINE ///< Token "EXTLINE" + { + LINECODE_ID LineCodeID; + + POINT Start; + POINT End; + long Overshoot; ///< Overshoot of the extension line past the arrow line + long Offset; ///< Offset from the measurement point + bool SuppressFirst = false; ///< If true, excludes the first extension line (only + ///< shows extension line at end) + + void Parse( XNODE* aNode ); + }; + + + struct LINE ///< Token can be either "LEADERLINE", "LINEARLINE" or "ANGULARLINE" + { + enum class TYPE + { + LINEARLINE, ///< Only for dimensions of type LINEARDIM + LEADERLINE, ///< Only for dimensions of type LEADERRDIM. If STYLE = INTERNAL, the + ///< result is the same as a LINEARLINE, i.e. all Leader Line-specific + ///< elements are ignored. + ANGULARLINE ///< Only for dimensions of type ANGULARDIM + }; + + enum class STYLE //DIMLINETYPE + { + INTERNAL, ///< The lines are placed inside the measurement + ///< token=DIMENSION_INTERNAL + EXTERNAL ///< The lines are placed outside the measurement + ///< (typically used when limited space) token=DIMENSION_EXTERNAL + }; + + TYPE Type; + LINECODE_ID LineCodeID; ///< param0 + STYLE Style; ///< Subnode="DIMLINETYPE" + + POINT Start; ///< [point1] + POINT End; ///< [point2] + POINT Centre; ///< Only for TYPE=ANGULARLINE [point3] + + long LeaderAngle = UNDEFINED_VALUE; ///< Only for TYPE=LEADERLINE subnode "LEADERANG" + long LeaderLineLength = UNDEFINED_VALUE; ///< Only for TYPE=LEADERLINE Length of the + ///< angled part of the leader line [param5] + long LeaderLineExtensionLength = UNDEFINED_VALUE; ///< Only for TYPE=LEADERLINE Length + ///< of the horizontal part of the + ///< leader line [param6] + + static bool IsLine( XNODE* aNode ); + void Parse( XNODE* aNode ); + }; + + + TYPE Type; + DIMENSION_ID ID; ///< Some ID (doesn't seem to be used) subnode="DIMREF" + LAYER_ID LayerID; ///< ID on which to draw this [param1] + SUBTYPE Subtype; ///< [param2] + long Precision; ///< Number of decimal points to display in the measurement + ///< [param3] + UNITS LinearUnits; ///< + ANGUNITS AngularUnits; ///< Only Applicable to TYPE=ANGLEDIM + ARROW Arrow; + TEXTFORMAT TextParams; + EXTENSION_LINE ExtensionLineParams; ///< Not applicable to TYPE=LEADERDIM + LINE Line; + TEXT Text; + + static bool IsDimension( XNODE* aNode ); + void Parse( XNODE* aNode ); + }; + + /** + * @brief A symbol definition can represent a number of different objects in CADSTAR. + * SYMDEF_TYPE is used in cadstar2kicadplugin to simplify identification of each type. + */ + enum class SYMDEF_TYPE + { + COMPONENT, ///< Standard PCB Component definition + JUMPER, ///< From CADSTAR Help: "Jumpers are components used primarily for the purpose + ///< of routing. A jumper's two pins are connected with a wire, joining together + ///< the nets on either side. Typically, a jumper is used to bridge across other + ///< routes where a routing problem is particularly difficult or to make a small + ///< modification to a design when most of the routing has been finalised. + ///< + ///< In CADSTAR, components are designated as jumpers in the component footprint. + ///< If the footprint has two pins and the first eight letters of the reference + ///< name spell "JUMPERNF" then the component will be treated as a jumper. + ///< + ///< From CADSTAR 8.0 archive format onwards, jumpers are saved as jumpers. For + ///< older archive formats and for most other export formats and post + ///< processing, jumpers are treated just as components. When CADSTAR saves a PCB + ///< design in an old archive format, the implied connection between the + ///< jumper's pins is added as an actual connection. When an old archive or + ///< binary PCB design is opened in the latest CADSTAR, any component footprint + ///< with two pins and whose first eight letters spell "JUMPERNF" will be + ///< treated as a jumper footprint automatically. If there is an actual + ///< connection between the pins, it will be removed and one implied from then + ///< on. If there isn't an actual connection, the nets connected to the pins + ///< will be merged. If a merge is needed and if each net has a user-supplied + ///< name (not $...), you will be asked to choose which name to use." + STARPOINT, ///< From CADSTAR Help: "Starpoints are special symbols/components that can be + ///< used to electrically connect different nets together, whilst avoiding any + ///< of the standard design rule error codes that would normally occur. + ///< + ///< If the first eleven letters of the reference name spell "STARPOINTNF" then + ///< the component will be treated as a starpoint. + ///< + ///< For a starpoint component to be valid: + ///< - There must be at least two pads + ///< - All pads must have the same position + ///< - All pads must have the same orientation + ///< - All pads must be on the same side + ///< - All pad codes must be the same + ///< - All pads must have the same exit direction + ///< - All pads must have the same PCB Only Pad setting + ///< + ///< If a starpoint component is not valid you will get an error message when + ///< trying to add it to the PCB component library." + TESTPOINT ///< From CADSTAR Help: "A testpoint is an area of copper connected to a net. It + ///< allows a test probe to investigate the electrical properties of that net. + ///< The Testpoint Symbols provided in the CADSTAR libraries are the Alternates + ///< for a pre-defined symbol called TESTPOINT." + ///< + ///< If the ReferenceName equals "TESTPOINT", then the component is treated + ///< as such. Note that the library manager does not permit adding a component + ///< with the name "TESTPOINT" if it has more than one pad defined. + }; + + + struct SYMDEF + { + SYMDEF_ID ID; + SYMDEF_TYPE Type = SYMDEF_TYPE::COMPONENT; + wxString ReferenceName; ///< This is the name which identifies the symbol in the library + ///< Multiple components may exist with the same ReferenceName. + wxString Alternate; ///< This is in addition to ReferenceName. It allows defining + ///< different versions, views etc. of the same basic symbol. + POINT Origin; ///< Origin of the component (this is used as the reference point + ///< when placing the component in the design) + bool Stub = false; ///< When the CADSTAR Archive file is exported without the + ///< component library, if components on the board are still + ///< exported, the Reference and Alternate names will still be + ///< exported but the content is replaced with a "STUB" atom, + ///< requiring access to the original library for component + ///< definition. + long SymHeight; ///< The Height of the component (3D height in z direction) + long Version; ///< Version is a sequential integer number to identify + ///< discrepancies between the library and the design. + + std::map Figures; + std::vector ComponentCoppers; + std::map ComponentAreas; + std::map Texts; + std::map Pads; + std::map TextLocations; ///< This contains location of + ///< any attributes, including + ///< designator position + std::map AttributeValues; + std::map Dimensions; ///< inside "DIMENSIONS" subnode + + void Parse( XNODE* aNode ); + }; + + + struct LIBRARY + { + std::map ComponentDefinitions; + + void Parse( XNODE* aNode ); + }; + wxString Filename; - CPA_HEADER Header; - CPA_ASSIGNMENTS Assignments; + HEADER Header; + ASSIGNMENTS Assignments; + LIBRARY Library; + //TODO Add Library, Defaults, Parts, etc.. int KiCadUnitMultiplier; /// #include -#include #include #include @@ -61,10 +59,8 @@ BOARD* CADSTAR_PCB_ARCHIVE_PLUGIN::Load( m_props = aProperties; m_board = aAppendToMe ? aAppendToMe : new BOARD(); - CADSTAR_PCB tempPCB( m_board ); - CPA_FILE theFile( aFileName ); - theFile.Parse(); - tempPCB.Load( &theFile ); + CADSTAR_PCB tempPCB( aFileName ); + tempPCB.Load( m_board ); return m_board; } diff --git a/qa/drc_proto/CMakeLists.txt b/qa/drc_proto/CMakeLists.txt index 93b841cf91..b14a8f07da 100644 --- a/qa/drc_proto/CMakeLists.txt +++ b/qa/drc_proto/CMakeLists.txt @@ -103,6 +103,7 @@ target_link_libraries( drc_proto pcbcommon bitmaps gal + cadstar2kicadpcb common pcbcommon ${PCBNEW_IO_LIBRARIES}