2755 lines
82 KiB
C++
2755 lines
82 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2020-2021 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
|
|
* Copyright (C) 2020-2021 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/**
|
|
* @file cadstar_archive_parser.cpp
|
|
* @brief Helper functions and common defines between schematic and PCB Archive files
|
|
*/
|
|
#include <wx/filename.h>
|
|
#include <wx/log.h>
|
|
#include <wx/xml/xml.h>
|
|
|
|
#include <dsnlexer.h>
|
|
#include <geometry/shape_poly_set.h>
|
|
#include <plugins/cadstar/cadstar_archive_parser.h>
|
|
#include <eda_item.h>
|
|
#include <eda_text.h>
|
|
#include <macros.h>
|
|
#include <progress_reporter.h>
|
|
#include <string_utils.h>
|
|
#include <trigo.h>
|
|
|
|
// Ratio derived from CADSTAR default font. See doxygen comment in cadstar_archive_parser.h
|
|
const double CADSTAR_ARCHIVE_PARSER::TXT_HEIGHT_RATIO = ( 24.0 - 5.0 ) / 24.0;
|
|
|
|
// Cadstar fields and their KiCad equivalent
|
|
const std::map<CADSTAR_ARCHIVE_PARSER::TEXT_FIELD_NAME, wxString>
|
|
CADSTAR_ARCHIVE_PARSER::CADSTAR_TO_KICAD_FIELDS =
|
|
{ { TEXT_FIELD_NAME::DESIGN_TITLE, wxT( "DESIGN_TITLE" ) },
|
|
{ TEXT_FIELD_NAME::SHORT_JOBNAME, wxT( "SHORT_JOBNAME" ) },
|
|
{ TEXT_FIELD_NAME::LONG_JOBNAME, wxT( "LONG_JOBNAME" ) },
|
|
{ TEXT_FIELD_NAME::NUM_OF_SHEETS, wxT( "##" ) },
|
|
{ TEXT_FIELD_NAME::SHEET_NUMBER, wxT( "#" ) },
|
|
{ TEXT_FIELD_NAME::SHEET_NAME, wxT( "SHEETNAME" ) },
|
|
{ TEXT_FIELD_NAME::VARIANT_NAME, wxT( "VARIANT_NAME" ) },
|
|
{ TEXT_FIELD_NAME::VARIANT_DESCRIPTION, wxT( "VARIANT_DESCRIPTION" ) },
|
|
{ TEXT_FIELD_NAME::REG_USER, wxT( "REG_USER" ) },
|
|
{ TEXT_FIELD_NAME::COMPANY_NAME, wxT( "COMPANY_NAME" ) },
|
|
{ TEXT_FIELD_NAME::CURRENT_USER, wxT( "CURRENT_USER" ) },
|
|
{ TEXT_FIELD_NAME::DATE, wxT( "DATE" ) },
|
|
{ TEXT_FIELD_NAME::TIME, wxT( "TIME" ) },
|
|
{ TEXT_FIELD_NAME::MACHINE_NAME, wxT( "MACHINE_NAME" ) } };
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::FORMAT::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "FORMAT" ) );
|
|
|
|
Type = GetXmlAttributeIDString( aNode, 0 );
|
|
SomeInt = GetXmlAttributeIDLong( aNode, 1 );
|
|
Version = GetXmlAttributeIDLong( aNode, 2 );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::TIMESTAMP::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "TIMESTAMP" ) );
|
|
|
|
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 CADSTAR_ARCHIVE_PARSER::HEADER::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "HEADER" ) );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString nodeName = cNode->GetName();
|
|
|
|
if( nodeName == wxT( "FORMAT" ) )
|
|
{
|
|
Format.Parse( cNode, aContext );
|
|
}
|
|
else if( nodeName == wxT( "JOBFILE" ) )
|
|
{
|
|
JobFile = GetXmlAttributeIDString( cNode, 0 );
|
|
}
|
|
else if( nodeName == wxT( "JOBTITLE" ) )
|
|
{
|
|
JobTitle = GetXmlAttributeIDString( cNode, 0 );
|
|
}
|
|
else if( nodeName == wxT( "GENERATOR" ) )
|
|
{
|
|
Generator = GetXmlAttributeIDString( cNode, 0 );
|
|
}
|
|
else if( nodeName == wxT( "RESOLUTION" ) )
|
|
{
|
|
XNODE* subNode = cNode->GetChildren();
|
|
|
|
if( ( subNode->GetName() == wxT( "METRIC" ) )
|
|
&& ( GetXmlAttributeIDString( subNode, 0 ) == wxT( "HUNDREDTH" ) )
|
|
&& ( GetXmlAttributeIDString( subNode, 1 ) == wxT( "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"
|
|
// or "METRIC MM" but so far none of settings in CADSTAR generated a different
|
|
// output resolution to "HUNDREDTH MICRON"
|
|
THROW_UNKNOWN_NODE_IO_ERROR( subNode->GetName(), wxT( "HEADER->RESOLUTION" ) );
|
|
}
|
|
}
|
|
else if( nodeName == wxT( "TIMESTAMP" ) )
|
|
{
|
|
Timestamp.Parse( cNode, aContext );
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), wxT( "HEADER" ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::VARIANT::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "VMASTER" ) || aNode->GetName() == wxT( "VARIANT" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
|
|
if( aNode->GetName() == wxT( "VMASTER" ) )
|
|
{
|
|
Name = GetXmlAttributeIDString( aNode, 1 );
|
|
Description = GetXmlAttributeIDString( aNode, 2 );
|
|
}
|
|
else
|
|
{
|
|
ParentID = GetXmlAttributeIDString( aNode, 1 );
|
|
Name = GetXmlAttributeIDString( aNode, 2 );
|
|
Description = GetXmlAttributeIDString( aNode, 3 );
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::VARIANT_HIERARCHY::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "VHIERARCHY" ) );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
if( cNode->GetName() == wxT( "VMASTER" ) || cNode->GetName() == wxT( "VARIANT" ) )
|
|
{
|
|
VARIANT variant;
|
|
variant.Parse( cNode, aContext );
|
|
Variants.insert( std::make_pair( variant.ID, variant ) );
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), cNode->GetName() );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::LINECODE::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "LINECODE" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
Name = GetXmlAttributeIDString( aNode, 1 );
|
|
|
|
if( !GetXmlAttributeIDString( aNode, 2 ).ToLong( &Width ) )
|
|
THROW_PARSING_IO_ERROR( wxT( "Line Width" ), wxString::Format( "LINECODE -> %s", Name ) );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
if( !cNode || cNode->GetName() != wxT( "STYLE" ) )
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), wxString::Format( "LINECODE -> %s", Name ) );
|
|
|
|
wxString styleStr = GetXmlAttributeIDString( cNode, 0 );
|
|
|
|
if( styleStr == wxT( "SOLID" ) )
|
|
{
|
|
Style = LINESTYLE::SOLID;
|
|
}
|
|
else if( styleStr == wxT( "DASH" ) )
|
|
{
|
|
Style = LINESTYLE::DASH;
|
|
}
|
|
else if( styleStr == wxT( "DASHDOT" ) )
|
|
{
|
|
Style = LINESTYLE::DASHDOT;
|
|
}
|
|
else if( styleStr == wxT( "DASHDOTDOT" ) )
|
|
{
|
|
Style = LINESTYLE::DASHDOTDOT;
|
|
}
|
|
else if( styleStr == wxT( "DOT" ) )
|
|
{
|
|
Style = LINESTYLE::DOT;
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_PARAMETER_IO_ERROR( wxString::Format( "STYLE %s", styleStr ),
|
|
wxString::Format( "LINECODE -> %s", Name ) );
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::HATCH::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "HATCH" ) );
|
|
|
|
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 = GetXmlAttributeIDLong( cNode, 0 );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::HATCHCODE::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "HATCHCODE" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
Name = GetXmlAttributeIDString( aNode, 1 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
wxString location = wxString::Format( "HATCHCODE -> %s", Name );
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
if( cNode->GetName() != wxT( "HATCH" ) )
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), location );
|
|
|
|
HATCH hatch;
|
|
hatch.Parse( cNode, aContext );
|
|
Hatches.push_back( hatch );
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::FONT::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "FONT" ) );
|
|
|
|
Name = GetXmlAttributeIDString( aNode, 0 );
|
|
Modifier1 = GetXmlAttributeIDLong( aNode, 1 );
|
|
Modifier2 = GetXmlAttributeIDLong( aNode, 2 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "ITALIC" ) )
|
|
Italic = true;
|
|
else if( cNodeName == wxT( "KERNING" ) )
|
|
KerningPairs = true;
|
|
else
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::TEXTCODE::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "TEXTCODE" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
Name = GetXmlAttributeIDString( aNode, 1 );
|
|
|
|
LineWidth = GetXmlAttributeIDLong( aNode, 2 );
|
|
Height = GetXmlAttributeIDLong( aNode, 3 );
|
|
Width = GetXmlAttributeIDLong( aNode, 4 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
if( cNode )
|
|
{
|
|
if( cNode->GetName() == wxT( "FONT" ) )
|
|
Font.Parse( cNode, aContext );
|
|
else
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), aNode->GetName() );
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::ROUTEREASSIGN::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "ROUTEREASSIGN" ) );
|
|
|
|
LayerID = GetXmlAttributeIDString( aNode, 0 );
|
|
OptimalWidth = GetXmlAttributeIDLong( aNode, 1, false );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "NECKWIDTH" ) )
|
|
NeckedWidth = GetXmlAttributeIDLong( cNode, 0 );
|
|
else if( cNodeName == wxT( "SROUTEWIDTH" ) )
|
|
OptimalWidth = GetXmlAttributeIDLong( cNode, 0 );
|
|
else if( cNodeName == wxT( "MINWIDTH" ) )
|
|
MinWidth = GetXmlAttributeIDLong( cNode, 0 );
|
|
else if( cNodeName == wxT( "MAXWIDTH" ) )
|
|
MaxWidth = GetXmlAttributeIDLong( cNode, 0 );
|
|
else
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::ROUTECODE::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "ROUTECODE" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
Name = GetXmlAttributeIDString( aNode, 1 );
|
|
OptimalWidth = GetXmlAttributeIDLong( aNode, 2, false );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "NECKWIDTH" ) )
|
|
{
|
|
NeckedWidth = GetXmlAttributeIDLong( cNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "SROUTEWIDTH" ) )
|
|
{
|
|
OptimalWidth = GetXmlAttributeIDLong( cNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "MINWIDTH" ) )
|
|
{
|
|
MinWidth = GetXmlAttributeIDLong( cNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "MAXWIDTH" ) )
|
|
{
|
|
MaxWidth = GetXmlAttributeIDLong( cNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "ROUTEREASSIGN" ) )
|
|
{
|
|
ROUTEREASSIGN routereassign;
|
|
routereassign.Parse( cNode, aContext );
|
|
RouteReassigns.push_back( routereassign );
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
double CADSTAR_ARCHIVE_PARSER::EVALUE::GetDouble()
|
|
{
|
|
return Base * std::pow( 10.0, Exponent );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::EVALUE::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
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_PARSER::POINT::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "PT" ) );
|
|
|
|
x = GetXmlAttributeIDLong( aNode, 0 );
|
|
y = GetXmlAttributeIDLong( aNode, 1 );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::LONGPOINT::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "PT" ) );
|
|
|
|
x = GetXmlAttributeIDLong( aNode, 0 );
|
|
y = GetXmlAttributeIDLong( aNode, 1 );
|
|
}
|
|
|
|
|
|
bool CADSTAR_ARCHIVE_PARSER::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_PARSER::VERTEX::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
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, aContext );
|
|
}
|
|
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<POINT> pts = ParseAllChildPoints( aNode, aContext, 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<POINT> pts = ParseAllChildPoints( aNode, aContext, true, 1 );
|
|
|
|
End = pts[0];
|
|
}
|
|
else
|
|
{
|
|
wxASSERT_MSG( true, wxT( "Unknown VERTEX type" ) );
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::VERTEX::AppendToChain( SHAPE_LINE_CHAIN* aChainToAppendTo,
|
|
const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback,
|
|
double aAccuracy ) const
|
|
{
|
|
VECTOR2I endPoint = aCadstarToKicadPointCallback( End );
|
|
|
|
if( Type == VERTEX_TYPE::POINT )
|
|
{
|
|
aChainToAppendTo->Append( endPoint );
|
|
return;
|
|
}
|
|
|
|
wxCHECK_MSG( aChainToAppendTo->PointCount() > 0, /*void*/,
|
|
"Can't append an arc to vertex to an empty chain" );
|
|
|
|
VECTOR2I startPoint = aChainToAppendTo->GetPoint( -1 );
|
|
VECTOR2I centerPoint;
|
|
|
|
if( Type == VERTEX_TYPE::ANTICLOCKWISE_SEMICIRCLE || Type == VERTEX_TYPE::CLOCKWISE_SEMICIRCLE )
|
|
centerPoint = ( startPoint / 2 ) + ( endPoint / 2 );
|
|
else
|
|
centerPoint = aCadstarToKicadPointCallback( Center );
|
|
|
|
bool clockwise = Type == VERTEX_TYPE::CLOCKWISE_ARC
|
|
|| Type == VERTEX_TYPE::CLOCKWISE_SEMICIRCLE;
|
|
|
|
// A bit of a hack to figure out if we need to invert clockwise due to the transform
|
|
VECTOR2I transform = aCadstarToKicadPointCallback( { 500, 500 } )
|
|
- aCadstarToKicadPointCallback( { 0, 0 } );
|
|
|
|
if( ( transform.x > 0 && transform.y < 0 ) || ( transform.x < 0 && transform.y > 0 ) )
|
|
clockwise = !clockwise;
|
|
|
|
SHAPE_ARC arc;
|
|
arc.ConstructFromStartEndCenter( startPoint, endPoint, centerPoint, clockwise );
|
|
|
|
aChainToAppendTo->Append( arc, aAccuracy );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::CUTOUT::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "CUTOUT" ) );
|
|
|
|
Vertices = ParseAllChildVertices( aNode, aContext, true );
|
|
}
|
|
|
|
|
|
bool CADSTAR_ARCHIVE_PARSER::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_PARSER::SHAPE::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( IsShape( aNode ) );
|
|
|
|
wxString aNodeName = aNode->GetName();
|
|
|
|
if( aNodeName == wxT( "OPENSHAPE" ) )
|
|
{
|
|
Type = SHAPE_TYPE::OPENSHAPE;
|
|
Vertices = ParseAllChildVertices( aNode, aContext, true );
|
|
Cutouts.clear();
|
|
HatchCodeID = wxEmptyString;
|
|
}
|
|
else if( aNodeName == wxT( "OUTLINE" ) )
|
|
{
|
|
Type = SHAPE_TYPE::OUTLINE;
|
|
Vertices = ParseAllChildVertices( aNode, aContext, false );
|
|
Cutouts = ParseAllChildCutouts( aNode, aContext, false );
|
|
HatchCodeID = wxEmptyString;
|
|
}
|
|
else if( aNodeName == wxT( "SOLID" ) )
|
|
{
|
|
Type = SHAPE_TYPE::SOLID;
|
|
Vertices = ParseAllChildVertices( aNode, aContext, false );
|
|
Cutouts = ParseAllChildCutouts( aNode, aContext, false );
|
|
HatchCodeID = wxEmptyString;
|
|
}
|
|
else if( aNodeName == wxT( "HATCHED" ) )
|
|
{
|
|
Type = SHAPE_TYPE::HATCHED;
|
|
Vertices = ParseAllChildVertices( aNode, aContext, false );
|
|
Cutouts = ParseAllChildCutouts( aNode, aContext, false );
|
|
HatchCodeID = GetXmlAttributeIDString( aNode, 0 );
|
|
}
|
|
else
|
|
{
|
|
wxASSERT_MSG( true, wxT( "Unknown SHAPE type" ) );
|
|
}
|
|
}
|
|
|
|
SHAPE_LINE_CHAIN CADSTAR_ARCHIVE_PARSER::SHAPE::OutlineAsChain(
|
|
const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback,
|
|
double aAccuracy ) const
|
|
{
|
|
SHAPE_LINE_CHAIN outline;
|
|
|
|
if( Vertices.size() == 0 )
|
|
return outline;
|
|
|
|
for( const auto& vertex : Vertices )
|
|
vertex.AppendToChain( &outline, aCadstarToKicadPointCallback, aAccuracy );
|
|
|
|
if( Type != SHAPE_TYPE::OPENSHAPE )
|
|
{
|
|
outline.SetClosed( true );
|
|
|
|
// Append after closing, to ensre first and last point remain the same
|
|
Vertices.at( 0 ).AppendToChain( &outline, aCadstarToKicadPointCallback, aAccuracy );
|
|
}
|
|
|
|
return outline;
|
|
}
|
|
|
|
|
|
SHAPE_POLY_SET CADSTAR_ARCHIVE_PARSER::SHAPE::ConvertToPolySet(
|
|
const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback,
|
|
double aAccuracy ) const
|
|
{
|
|
SHAPE_POLY_SET polyset;
|
|
|
|
wxCHECK( Type != SHAPE_TYPE::OPENSHAPE, polyset ); // We shouldn't convert openshapes to polyset!
|
|
|
|
polyset.AddOutline( OutlineAsChain( aCadstarToKicadPointCallback, aAccuracy ) );
|
|
|
|
for( const auto& cutout : Cutouts )
|
|
{
|
|
SHAPE_LINE_CHAIN hole;
|
|
|
|
if( cutout.Vertices.size() == 0 )
|
|
continue;
|
|
|
|
for( const auto& cutoutVertex : cutout.Vertices )
|
|
cutoutVertex.AppendToChain( &hole, aCadstarToKicadPointCallback, aAccuracy );
|
|
|
|
hole.SetClosed( true );
|
|
|
|
// Append after closing, to ensre first and last point remain the same
|
|
cutout.Vertices.at( 0 ).AppendToChain( &hole, aCadstarToKicadPointCallback, aAccuracy );
|
|
|
|
polyset.AddHole( hole );
|
|
}
|
|
|
|
return polyset;
|
|
}
|
|
|
|
|
|
CADSTAR_ARCHIVE_PARSER::UNITS CADSTAR_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 if( unit == wxT( "DESIGN" ) )
|
|
return UNITS::DESIGN;
|
|
else
|
|
THROW_UNKNOWN_PARAMETER_IO_ERROR( unit, wxT( "UNITS" ) );
|
|
|
|
return UNITS();
|
|
}
|
|
|
|
|
|
CADSTAR_ARCHIVE_PARSER::ANGUNITS CADSTAR_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();
|
|
}
|
|
|
|
|
|
bool CADSTAR_ARCHIVE_PARSER::GRID::IsGrid( XNODE* aNode )
|
|
{
|
|
wxString aNodeName = aNode->GetName();
|
|
|
|
if( aNodeName == wxT( "FRACTIONALGRID" ) || aNodeName == wxT( "STEPGRID" ) )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::GRID::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( IsGrid( aNode ) );
|
|
|
|
wxString aNodeName = aNode->GetName();
|
|
|
|
if( aNodeName == wxT( "FRACTIONALGRID" ) )
|
|
Type = GRID_TYPE::FRACTIONALGRID;
|
|
else if( aNodeName == wxT( "STEPGRID" ) )
|
|
Type = GRID_TYPE::STEPGRID;
|
|
else
|
|
wxASSERT_MSG( true, wxT( "Unknown Grid Type" ) );
|
|
|
|
Name = GetXmlAttributeIDString( aNode, 0 );
|
|
Param1 = GetXmlAttributeIDLong( aNode, 1 );
|
|
Param2 = GetXmlAttributeIDLong( aNode, 2 );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::GRIDS::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "GRIDS" ) );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "WORKINGGRID" ) )
|
|
{
|
|
XNODE* workingGridNode = cNode->GetChildren();
|
|
|
|
if( !GRID::IsGrid( workingGridNode ) )
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR(
|
|
workingGridNode->GetName(), wxT( "GRIDS -> WORKINGGRID" ) );
|
|
}
|
|
else
|
|
{
|
|
WorkingGrid.Parse( workingGridNode, aContext );
|
|
}
|
|
}
|
|
else if( cNodeName == wxT( "SCREENGRID" ) )
|
|
{
|
|
XNODE* screenGridNode = cNode->GetChildren();
|
|
|
|
if( !GRID::IsGrid( screenGridNode ) )
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR(
|
|
screenGridNode->GetName(), wxT( "GRIDS -> SCREENGRID" ) );
|
|
}
|
|
else
|
|
{
|
|
ScreenGrid.Parse( screenGridNode, aContext );
|
|
}
|
|
}
|
|
else if( GRID::IsGrid( cNode ) )
|
|
{
|
|
GRID userGrid;
|
|
userGrid.Parse( cNode, aContext );
|
|
UserGrids.push_back( userGrid );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool CADSTAR_ARCHIVE_PARSER::SETTINGS::ParseSubNode( XNODE* aChildNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxString cNodeName = aChildNode->GetName();
|
|
|
|
if( cNodeName == wxT( "UNITS" ) )
|
|
{
|
|
Units = ParseUnits( aChildNode );
|
|
}
|
|
else if( cNodeName == wxT( "UNITSPRECISION" ) )
|
|
{
|
|
UnitDisplPrecision = GetXmlAttributeIDLong( aChildNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "INTERLINEGAP" ) )
|
|
{
|
|
InterlineGap = GetXmlAttributeIDLong( aChildNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "BARLINEGAP" ) )
|
|
{
|
|
BarlineGap = GetXmlAttributeIDLong( aChildNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "ALLOWBARTEXT" ) )
|
|
{
|
|
AllowBarredText = true;
|
|
}
|
|
else if( cNodeName == wxT( "ANGULARPRECISION" ) )
|
|
{
|
|
AngularPrecision = GetXmlAttributeIDLong( aChildNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "DESIGNORIGIN" ) )
|
|
{
|
|
DesignOrigin.Parse( aChildNode->GetChildren(), aContext );
|
|
}
|
|
else if( cNodeName == wxT( "DESIGNAREA" ) )
|
|
{
|
|
std::vector<POINT> pts = ParseAllChildPoints( aChildNode, aContext, true, 2 );
|
|
DesignArea = std::make_pair( pts[0], pts[1] );
|
|
}
|
|
else if( cNodeName == wxT( "DESIGNREF" ) )
|
|
{
|
|
DesignOrigin.Parse( aChildNode->GetChildren(), aContext );
|
|
}
|
|
else if( cNodeName == wxT( "DESIGNLIMIT" ) )
|
|
{
|
|
DesignLimit.Parse( aChildNode->GetChildren(), aContext );
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::SETTINGS::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "SETTINGS" ) );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( ParseSubNode( cNode, aContext ) )
|
|
continue;
|
|
else
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, wxT( "SETTINGS" ) );
|
|
}
|
|
}
|
|
|
|
|
|
wxString CADSTAR_ARCHIVE_PARSER::ParseTextFields( const wxString& aTextString,
|
|
PARSER_CONTEXT* aContext )
|
|
{
|
|
static const std::map<TEXT_FIELD_NAME, wxString> txtTokens =
|
|
{
|
|
{ TEXT_FIELD_NAME::DESIGN_TITLE, wxT( "DESIGN TITLE" ) },
|
|
{ TEXT_FIELD_NAME::SHORT_JOBNAME, wxT( "SHORT_JOBNAME" ) },
|
|
{ TEXT_FIELD_NAME::LONG_JOBNAME, wxT( "LONG_JOBNAME" ) },
|
|
{ TEXT_FIELD_NAME::NUM_OF_SHEETS, wxT( "NUM_OF_SHEETS" ) },
|
|
{ TEXT_FIELD_NAME::SHEET_NUMBER, wxT( "SHEET_NUMBER" ) },
|
|
{ TEXT_FIELD_NAME::SHEET_NAME, wxT( "SHEET_NAME" ) },
|
|
{ TEXT_FIELD_NAME::VARIANT_NAME, wxT( "VARIANT_NAME" ) },
|
|
{ TEXT_FIELD_NAME::VARIANT_DESCRIPTION, wxT( "VARIANT_DESCRIPTION" ) },
|
|
{ TEXT_FIELD_NAME::REG_USER, wxT( "REG_USER" ) },
|
|
{ TEXT_FIELD_NAME::COMPANY_NAME, wxT( "COMPANY_NAME" ) },
|
|
{ TEXT_FIELD_NAME::CURRENT_USER, wxT( "CURRENT_USER" ) },
|
|
{ TEXT_FIELD_NAME::DATE, wxT( "DATE" ) },
|
|
{ TEXT_FIELD_NAME::TIME, wxT( "TIME" ) },
|
|
{ TEXT_FIELD_NAME::MACHINE_NAME, wxT( "MACHINE_NAME" ) },
|
|
{ TEXT_FIELD_NAME::FROM_FILE, wxT( "FROM_FILE" ) },
|
|
{ TEXT_FIELD_NAME::DISTANCE, wxT( "DISTANCE" ) },
|
|
{ TEXT_FIELD_NAME::UNITS_SHORT, wxT( "UNITS SHORT" ) },
|
|
{ TEXT_FIELD_NAME::UNITS_ABBREV, wxT( "UNITS ABBREV" ) },
|
|
{ TEXT_FIELD_NAME::UNITS_FULL, wxT( "UNITS FULL" ) },
|
|
{ TEXT_FIELD_NAME::HYPERLINK, wxT( "HYPERLINK" ) }
|
|
};
|
|
|
|
wxString remainingStr = aTextString;
|
|
wxString returnStr;
|
|
|
|
while( remainingStr.size() > 0 )
|
|
{
|
|
//Find the start token
|
|
size_t startpos = remainingStr.Find( wxT( "<@" ) );
|
|
|
|
if( static_cast<int>( startpos ) == wxNOT_FOUND )
|
|
{
|
|
// No more fields to parse, add to return string
|
|
returnStr += remainingStr;
|
|
break;
|
|
}
|
|
|
|
if( startpos > 0 )
|
|
returnStr += remainingStr.SubString( 0, startpos - 1 );
|
|
|
|
if( ( startpos + 2 ) >= remainingStr.size() )
|
|
break;
|
|
|
|
remainingStr = remainingStr.Mid( startpos + 2 );
|
|
|
|
//Find the expected token for the field
|
|
TEXT_FIELD_NAME foundField = TEXT_FIELD_NAME::NONE;
|
|
|
|
for( std::pair<TEXT_FIELD_NAME, wxString> txtF : txtTokens )
|
|
{
|
|
if( remainingStr.StartsWith( txtF.second ) )
|
|
{
|
|
foundField = txtF.first;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( foundField == TEXT_FIELD_NAME::NONE )
|
|
{
|
|
// Not a valid field, lets keep looking
|
|
returnStr += wxT( "<@" );
|
|
continue;
|
|
}
|
|
|
|
//Now lets find the end token
|
|
size_t endpos = remainingStr.Find( wxT( "@>" ) );
|
|
|
|
if( static_cast<int>( endpos ) == wxNOT_FOUND )
|
|
{
|
|
// The field we found isn't valid as it doesn't have a termination
|
|
// Lets append the whole thing as plain text
|
|
returnStr += wxT( "<@" ) + remainingStr;
|
|
break;
|
|
}
|
|
|
|
size_t valueStart = txtTokens.at( foundField ).size();
|
|
wxString fieldValue = remainingStr.SubString( valueStart, endpos - 1 );
|
|
wxString address;
|
|
|
|
if( foundField == TEXT_FIELD_NAME::FROM_FILE || foundField == TEXT_FIELD_NAME::HYPERLINK )
|
|
{
|
|
// The first character should always be a double quotation mark
|
|
wxASSERT_MSG( fieldValue.at( 0 ) == '"', "Expected '\"' as the first character" );
|
|
|
|
size_t splitPos = fieldValue.find_first_of( '"', 1 );
|
|
address = fieldValue.SubString( 1, splitPos - 1 );
|
|
|
|
if( foundField == TEXT_FIELD_NAME::HYPERLINK )
|
|
{
|
|
// Assume the last two characters are "@>"
|
|
wxASSERT_MSG( remainingStr.EndsWith( wxT( "@>" ) ),
|
|
"Expected '@>' at the end of a hyperlink" );
|
|
|
|
fieldValue = remainingStr.SubString( valueStart + splitPos + 1,
|
|
remainingStr.Length() - 3 );
|
|
|
|
remainingStr = wxEmptyString;
|
|
}
|
|
else
|
|
{
|
|
fieldValue = fieldValue.Mid( splitPos + 1 );
|
|
}
|
|
}
|
|
|
|
switch( foundField )
|
|
{
|
|
case TEXT_FIELD_NAME::DESIGN_TITLE:
|
|
case TEXT_FIELD_NAME::SHORT_JOBNAME:
|
|
case TEXT_FIELD_NAME::LONG_JOBNAME:
|
|
case TEXT_FIELD_NAME::VARIANT_NAME:
|
|
case TEXT_FIELD_NAME::VARIANT_DESCRIPTION:
|
|
case TEXT_FIELD_NAME::REG_USER:
|
|
case TEXT_FIELD_NAME::COMPANY_NAME:
|
|
case TEXT_FIELD_NAME::CURRENT_USER:
|
|
case TEXT_FIELD_NAME::DATE:
|
|
case TEXT_FIELD_NAME::TIME:
|
|
case TEXT_FIELD_NAME::MACHINE_NAME:
|
|
|
|
if( aContext->TextFieldToValuesMap.find( foundField )
|
|
!= aContext->TextFieldToValuesMap.end() )
|
|
{
|
|
aContext->InconsistentTextFields.insert( foundField );
|
|
}
|
|
else
|
|
{
|
|
aContext->TextFieldToValuesMap.insert( { foundField, fieldValue } );
|
|
}
|
|
|
|
KI_FALLTHROUGH;
|
|
|
|
case TEXT_FIELD_NAME::NUM_OF_SHEETS:
|
|
case TEXT_FIELD_NAME::SHEET_NUMBER:
|
|
case TEXT_FIELD_NAME::SHEET_NAME:
|
|
returnStr += wxT( "${" ) + CADSTAR_TO_KICAD_FIELDS.at( foundField ) + wxT( "}" );
|
|
break;
|
|
|
|
case TEXT_FIELD_NAME::DISTANCE:
|
|
case TEXT_FIELD_NAME::UNITS_SHORT:
|
|
case TEXT_FIELD_NAME::UNITS_ABBREV:
|
|
case TEXT_FIELD_NAME::UNITS_FULL:
|
|
// Just flatten the text for distances
|
|
returnStr += fieldValue;
|
|
break;
|
|
|
|
case TEXT_FIELD_NAME::FROM_FILE:
|
|
{
|
|
wxFileName fn( address );
|
|
wxString fieldFmt = wxT( "FROM_FILE_%s_%s" );
|
|
wxString fieldName = wxString::Format( fieldFmt, fn.GetName(), fn.GetExt() );
|
|
|
|
int version = 1;
|
|
|
|
while(
|
|
aContext->FilenamesToTextMap.find( fieldName )
|
|
!= aContext->FilenamesToTextMap.end()
|
|
&& aContext->FilenamesToTextMap.at( fieldName ) != fieldValue )
|
|
{
|
|
fieldName = wxString::Format( fieldFmt, fn.GetName(), fn.GetExt() )
|
|
+ wxString::Format( wxT( "_%d" ), version++ );
|
|
}
|
|
|
|
aContext->FilenamesToTextMap[fieldName] = fieldValue;
|
|
returnStr += wxT( "${" ) + fieldName + wxT( "}" );
|
|
}
|
|
break;
|
|
|
|
case TEXT_FIELD_NAME::HYPERLINK:
|
|
{
|
|
aContext->TextToHyperlinksMap[fieldValue] = address;
|
|
returnStr += ParseTextFields( fieldValue, aContext );
|
|
}
|
|
break;
|
|
|
|
case TEXT_FIELD_NAME::NONE:
|
|
wxFAIL_MSG( "We should have already covered this scenario above" );
|
|
break;
|
|
}
|
|
|
|
|
|
if( ( endpos + 2 ) >= remainingStr.size() )
|
|
break;
|
|
|
|
remainingStr = remainingStr.Mid( endpos + 2 );
|
|
}
|
|
|
|
return returnStr;
|
|
}
|
|
|
|
|
|
CADSTAR_ARCHIVE_PARSER::ALIGNMENT CADSTAR_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_ARCHIVE_PARSER::JUSTIFICATION CADSTAR_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_ARCHIVE_PARSER::READABILITY CADSTAR_ARCHIVE_PARSER::ParseReadability( XNODE* aNode )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "READABILITY" ) );
|
|
|
|
wxString readabilityStr = GetXmlAttributeIDString( aNode, 0 );
|
|
|
|
if( readabilityStr == wxT( "BOTTOM_TO_TOP" ) )
|
|
return READABILITY::BOTTOM_TO_TOP;
|
|
else if( readabilityStr == wxT( "TOP_TO_BOTTOM" ) )
|
|
return READABILITY::TOP_TO_BOTTOM;
|
|
else
|
|
THROW_UNKNOWN_PARAMETER_IO_ERROR( readabilityStr, wxT( "READABILITY" ) );
|
|
|
|
return READABILITY::BOTTOM_TO_TOP;
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::ATTRIBUTE_LOCATION::ParseIdentifiers( XNODE* aNode,
|
|
PARSER_CONTEXT* aContext )
|
|
{
|
|
TextCodeID = GetXmlAttributeIDString( aNode, 0 );
|
|
LayerID = GetXmlAttributeIDString( aNode, 1 );
|
|
}
|
|
|
|
|
|
bool CADSTAR_ARCHIVE_PARSER::ATTRIBUTE_LOCATION::ParseSubNode( XNODE* aChildNode,
|
|
PARSER_CONTEXT* aContext )
|
|
{
|
|
wxString cNodeName = aChildNode->GetName();
|
|
|
|
if( cNodeName == wxT( "PT" ) )
|
|
Position.Parse( aChildNode, aContext );
|
|
else if( cNodeName == wxT( "ORIENT" ) )
|
|
OrientAngle = GetXmlAttributeIDLong( aChildNode, 0 );
|
|
else if( cNodeName == wxT( "MIRROR" ) )
|
|
Mirror = true;
|
|
else if( cNodeName == wxT( "FIX" ) )
|
|
Fixed = true;
|
|
else if( cNodeName == wxT( "ALIGN" ) )
|
|
Alignment = ParseAlignment( aChildNode );
|
|
else if( cNodeName == wxT( "JUSTIFICATION" ) )
|
|
Justification = ParseJustification( aChildNode );
|
|
else
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::ATTRIBUTE_LOCATION::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "ATTRLOC" ) );
|
|
|
|
ParseIdentifiers( aNode, aContext );
|
|
|
|
//Parse child nodes
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
if( ParseSubNode( cNode, aContext ) )
|
|
continue;
|
|
else
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), wxT( "ATTRLOC" ) );
|
|
}
|
|
|
|
if( !Position.IsFullySpecified() )
|
|
THROW_MISSING_NODE_IO_ERROR( wxT( "PT" ), wxT( "ATTRLOC" ) );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::ATTRNAME::COLUMNORDER::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "COLUMNORDER" ) );
|
|
|
|
ID = GetXmlAttributeIDLong( aNode, 0 );
|
|
Order = GetXmlAttributeIDLong( aNode, 1 );
|
|
|
|
CheckNoChildNodes( aNode );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::ATTRNAME::COLUMNWIDTH::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "COLUMNWIDTH" ) );
|
|
|
|
ID = GetXmlAttributeIDLong( aNode, 0 );
|
|
Width = GetXmlAttributeIDLong( aNode, 1 );
|
|
|
|
CheckNoChildNodes( aNode );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::ATTRNAME::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "ATTRNAME" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
Name = GetXmlAttributeIDString( aNode, 1 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
wxString location = wxString::Format( "ATTRNAME -> %s", Name );
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "ATTROWNER" ) )
|
|
{
|
|
wxString attOwnerVal = GetXmlAttributeIDString( cNode, 0 );
|
|
|
|
if( attOwnerVal == wxT( "ALL_ITEMS" ) )
|
|
AttributeOwner = ATTROWNER::ALL_ITEMS;
|
|
else if( attOwnerVal == wxT( "AREA" ) )
|
|
AttributeOwner = ATTROWNER::AREA;
|
|
else if( attOwnerVal == wxT( "BOARD" ) )
|
|
AttributeOwner = ATTROWNER::BOARD;
|
|
else if( attOwnerVal == wxT( "COMPONENT" ) )
|
|
AttributeOwner = ATTROWNER::COMPONENT;
|
|
else if( attOwnerVal == wxT( "CONNECTION" ) )
|
|
AttributeOwner = ATTROWNER::CONNECTION;
|
|
else if( attOwnerVal == wxT( "COPPER" ) )
|
|
AttributeOwner = ATTROWNER::COPPER;
|
|
else if( attOwnerVal == wxT( "DOCSYMBOL" ) )
|
|
AttributeOwner = ATTROWNER::DOCSYMBOL;
|
|
else if( attOwnerVal == wxT( "FIGURE" ) )
|
|
AttributeOwner = ATTROWNER::FIGURE;
|
|
else if( attOwnerVal == wxT( "NET" ) )
|
|
AttributeOwner = ATTROWNER::NET;
|
|
else if( attOwnerVal == wxT( "NETCLASS" ) )
|
|
AttributeOwner = ATTROWNER::NETCLASS;
|
|
else if( attOwnerVal == wxT( "PART" ) )
|
|
AttributeOwner = ATTROWNER::PART;
|
|
else if( attOwnerVal == wxT( "PART_DEFINITION" ) )
|
|
AttributeOwner = ATTROWNER::PART_DEFINITION;
|
|
else if( attOwnerVal == wxT( "PIN" ) )
|
|
AttributeOwner = ATTROWNER::PIN;
|
|
else if( attOwnerVal == wxT( "SIGNALREF" ) )
|
|
AttributeOwner = ATTROWNER::SIGNALREF;
|
|
else if( attOwnerVal == wxT( "SYMBOL" ) )
|
|
AttributeOwner = ATTROWNER::SYMBOL;
|
|
else if( attOwnerVal == wxT( "SYMDEF" ) )
|
|
AttributeOwner = ATTROWNER::SYMDEF;
|
|
else if( attOwnerVal == wxT( "TEMPLATE" ) )
|
|
AttributeOwner = ATTROWNER::TEMPLATE;
|
|
else if( attOwnerVal == wxT( "TESTPOINT" ) )
|
|
AttributeOwner = ATTROWNER::TESTPOINT;
|
|
else
|
|
THROW_UNKNOWN_PARAMETER_IO_ERROR( attOwnerVal, location );
|
|
}
|
|
else if( cNodeName == wxT( "ATTRUSAGE" ) )
|
|
{
|
|
wxString attUsageVal = GetXmlAttributeIDString( cNode, 0 );
|
|
|
|
if( attUsageVal == wxT( "BOTH" ) )
|
|
AttributeUsage = ATTRUSAGE::BOTH;
|
|
else if( attUsageVal == wxT( "COMPONENT" ) )
|
|
AttributeUsage = ATTRUSAGE::COMPONENT;
|
|
else if( attUsageVal == wxT( "PART_DEFINITION" ) )
|
|
AttributeUsage = ATTRUSAGE::PART_DEFINITION;
|
|
else if( attUsageVal == wxT( "PART_LIBRARY" ) )
|
|
AttributeUsage = ATTRUSAGE::PART_LIBRARY;
|
|
else if( attUsageVal == wxT( "SYMBOL" ) )
|
|
AttributeUsage = ATTRUSAGE::SYMBOL;
|
|
else
|
|
THROW_UNKNOWN_PARAMETER_IO_ERROR( attUsageVal, location );
|
|
}
|
|
else if( cNodeName == wxT( "NOTRANSFER" ) )
|
|
{
|
|
NoTransfer = true;
|
|
}
|
|
else if( cNodeName == wxT( "COLUMNORDER" ) )
|
|
{
|
|
COLUMNORDER cOrder;
|
|
cOrder.Parse( cNode, aContext );
|
|
ColumnOrders.push_back( cOrder );
|
|
}
|
|
else if( cNodeName == wxT( "COLUMNWIDTH" ) )
|
|
{
|
|
COLUMNWIDTH cWidth;
|
|
cWidth.Parse( cNode, aContext );
|
|
ColumnWidths.push_back( cWidth );
|
|
}
|
|
else if( cNodeName == wxT( "COLUMNINVISIBLE" ) )
|
|
{
|
|
ColumnInvisible = true;
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, location );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::ATTRIBUTE_VALUE::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "ATTR" ) );
|
|
|
|
AttributeID = GetXmlAttributeIDString( aNode, 0 );
|
|
Value = GetXmlAttributeIDString( aNode, 1 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
if( cNode->GetName() == wxT( "READONLY" ) )
|
|
{
|
|
ReadOnly = true;
|
|
}
|
|
else if( cNode->GetName() == wxT( "ATTRLOC" ) )
|
|
{
|
|
AttributeLocation.Parse( cNode, aContext );
|
|
HasLocation = true;
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), wxT( "ATTR" ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::TEXT_LOCATION::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
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( "SYMBOL_NAME" ) )
|
|
{
|
|
AttributeID = SYMBOL_NAME_ATTRID;
|
|
attributeIDisSet = true;
|
|
}
|
|
else if( attributeStr == wxT( "LINK_ORIGIN" ) )
|
|
{
|
|
AttributeID = LINK_ORIGIN_ATTRID;
|
|
attributeIDisSet = true;
|
|
}
|
|
else if( attributeStr == wxT( "SIGNALNAME_ORIGIN" ) )
|
|
{
|
|
AttributeID = SIGNALNAME_ORIGIN_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, false );
|
|
|
|
//Parse child nodes
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( ParseSubNode( cNode, aContext ) )
|
|
{
|
|
continue;
|
|
}
|
|
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( "FIX" ) )
|
|
{
|
|
Fixed = 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" ) );
|
|
}
|
|
}
|
|
|
|
if( !Position.IsFullySpecified() )
|
|
THROW_MISSING_NODE_IO_ERROR( wxT( "PT" ), wxT( "TEXTLOC" ) );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::CADSTAR_NETCLASS::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "NETCLASS" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
Name = GetXmlAttributeIDString( aNode, 1 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
wxString location = wxString::Format( "NETCLASS -> %s", Name );
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "ATTR" ) )
|
|
{
|
|
ATTRIBUTE_VALUE attribute_val;
|
|
attribute_val.Parse( cNode, aContext );
|
|
Attributes.push_back( attribute_val );
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, location );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::SPCCLASSNAME::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "SPCCLASSNAME" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
Name = GetXmlAttributeIDString( aNode, 1 );
|
|
}
|
|
|
|
|
|
bool CADSTAR_ARCHIVE_PARSER::CODEDEFS::ParseSubNode( XNODE* aChildNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxString nodeName = aChildNode->GetName();
|
|
|
|
if( nodeName == wxT( "LINECODE" ) )
|
|
{
|
|
LINECODE linecode;
|
|
linecode.Parse( aChildNode, aContext );
|
|
LineCodes.insert( std::make_pair( linecode.ID, linecode ) );
|
|
}
|
|
else if( nodeName == wxT( "HATCHCODE" ) )
|
|
{
|
|
HATCHCODE hatchcode;
|
|
hatchcode.Parse( aChildNode, aContext );
|
|
HatchCodes.insert( std::make_pair( hatchcode.ID, hatchcode ) );
|
|
}
|
|
else if( nodeName == wxT( "TEXTCODE" ) )
|
|
{
|
|
TEXTCODE textcode;
|
|
textcode.Parse( aChildNode, aContext );
|
|
TextCodes.insert( std::make_pair( textcode.ID, textcode ) );
|
|
}
|
|
else if( nodeName == wxT( "ROUTECODE" ) )
|
|
{
|
|
ROUTECODE routecode;
|
|
routecode.Parse( aChildNode, aContext );
|
|
RouteCodes.insert( std::make_pair( routecode.ID, routecode ) );
|
|
}
|
|
else if( nodeName == wxT( "ATTRNAME" ) )
|
|
{
|
|
ATTRNAME attrname;
|
|
attrname.Parse( aChildNode, aContext );
|
|
AttributeNames.insert( std::make_pair( attrname.ID, attrname ) );
|
|
}
|
|
else if( nodeName == wxT( "NETCLASS" ) )
|
|
{
|
|
CADSTAR_NETCLASS netclass;
|
|
netclass.Parse( aChildNode, aContext );
|
|
NetClasses.insert( std::make_pair( netclass.ID, netclass ) );
|
|
}
|
|
else if( nodeName == wxT( "SPCCLASSNAME" ) )
|
|
{
|
|
SPCCLASSNAME spcclassname;
|
|
spcclassname.Parse( aChildNode, aContext );
|
|
SpacingClassNames.insert( std::make_pair( spcclassname.ID, spcclassname ) );
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
CADSTAR_ARCHIVE_PARSER::SWAP_RULE CADSTAR_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_ARCHIVE_PARSER::REUSEBLOCK::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "REUSEBLOCK" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
Name = GetXmlAttributeIDString( aNode, 1 );
|
|
FileName = GetXmlAttributeIDString( aNode, 2 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "MIRROR" ) )
|
|
Mirror = true;
|
|
else if( cNodeName == wxT( "ORIENT" ) )
|
|
OrientAngle = GetXmlAttributeIDLong( cNode, 0 );
|
|
else
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, wxT( "REUSEBLOCK" ) );
|
|
}
|
|
}
|
|
|
|
|
|
bool CADSTAR_ARCHIVE_PARSER::REUSEBLOCKREF::IsEmpty()
|
|
{
|
|
return ReuseBlockID == wxEmptyString && ItemReference == wxEmptyString;
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::REUSEBLOCKREF::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "REUSEBLOCKREF" ) );
|
|
|
|
ReuseBlockID = GetXmlAttributeIDString( aNode, 0 );
|
|
ItemReference = GetXmlAttributeIDString( aNode, 1 );
|
|
|
|
CheckNoChildNodes( aNode );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::GROUP::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "GROUP" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
Name = GetXmlAttributeIDString( aNode, 1 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "FIX" ) )
|
|
Fixed = true;
|
|
else if( cNodeName == wxT( "TRANSFER" ) )
|
|
Transfer = true;
|
|
else if( cNodeName == wxT( "GROUPREF" ) )
|
|
GroupID = GetXmlAttributeIDString( cNode, 0 );
|
|
else if( cNodeName == wxT( "REUSEBLOCKREF" ) )
|
|
ReuseBlockRef.Parse( cNode, aContext );
|
|
else
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, wxT( "GROUP" ) );
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::FIGURE::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
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, aContext );
|
|
shapeIsInitialised = true;
|
|
}
|
|
else if( cNodeName == wxT( "SWAPRULE" ) )
|
|
{
|
|
SwapRule = ParseSwapRule( cNode );
|
|
}
|
|
else if( cNodeName == wxT( "FIX" ) )
|
|
{
|
|
Fixed = true;
|
|
}
|
|
else if( cNodeName == wxT( "GROUPREF" ) )
|
|
{
|
|
|
|
GroupID = GetXmlAttributeIDString( cNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "REUSEBLOCKREF" ) )
|
|
{
|
|
ReuseBlockRef.Parse( cNode, aContext );
|
|
}
|
|
else if( cNodeName == wxT( "ATTR" ) )
|
|
{
|
|
ATTRIBUTE_VALUE attr;
|
|
attr.Parse( cNode, aContext );
|
|
AttributeValues.insert( std::make_pair( attr.AttributeID, attr ) );
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, location );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::TEXT::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
Parse( aNode, aContext, true );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::TEXT::Parse( XNODE* aNode, PARSER_CONTEXT* aContext,
|
|
bool aParseFields )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "TEXT" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
Text = GetXmlAttributeIDString( aNode, 1 );
|
|
|
|
if( aParseFields )
|
|
Text = ParseTextFields( Text, aContext );
|
|
|
|
TextCodeID = GetXmlAttributeIDString( aNode, 2 );
|
|
LayerID = GetXmlAttributeIDString( aNode, 3 );
|
|
|
|
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, aContext );
|
|
else if( cNodeName == wxT( "ORIENT" ) )
|
|
OrientAngle = GetXmlAttributeIDLong( cNode, 0 );
|
|
else if( cNodeName == wxT( "MIRROR" ) )
|
|
Mirror = true;
|
|
else if( cNodeName == wxT( "FIX" ) )
|
|
Fixed = 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 if( cNodeName == wxT( "GROUPREF" ) )
|
|
GroupID = GetXmlAttributeIDString( cNode, 0 );
|
|
else if( cNodeName == wxT( "REUSEBLOCKREF" ) )
|
|
ReuseBlockRef.Parse( cNode, aContext );
|
|
else
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, wxT( "TEXT" ) );
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::SYMDEF::ParseIdentifiers( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "SYMDEF" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
ReferenceName = GetXmlAttributeIDString( aNode, 1 );
|
|
Alternate = GetXmlAttributeIDString( aNode, 2 );
|
|
}
|
|
|
|
|
|
bool CADSTAR_ARCHIVE_PARSER::SYMDEF::ParseSubNode( XNODE* aChildNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxString cNodeName = aChildNode->GetName();
|
|
|
|
if( cNodeName == wxT( "PT" ) )
|
|
{
|
|
Origin.Parse( aChildNode, aContext );
|
|
}
|
|
else if( cNodeName == wxT( "STUB" ) )
|
|
{
|
|
Stub = true;
|
|
}
|
|
else if( cNodeName == wxT( "VERSION" ) )
|
|
{
|
|
Version = GetXmlAttributeIDLong( aChildNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "FIGURE" ) )
|
|
{
|
|
FIGURE figure;
|
|
figure.Parse( aChildNode, aContext );
|
|
Figures.insert( std::make_pair( figure.ID, figure ) );
|
|
}
|
|
else if( cNodeName == wxT( "TEXT" ) )
|
|
{
|
|
TEXT txt;
|
|
txt.Parse( aChildNode, aContext );
|
|
Texts.insert( std::make_pair( txt.ID, txt ) );
|
|
}
|
|
else if( cNodeName == wxT( "TEXTLOC" ) )
|
|
{
|
|
TEXT_LOCATION textloc;
|
|
textloc.Parse( aChildNode, aContext );
|
|
TextLocations.insert( std::make_pair( textloc.AttributeID, textloc ) );
|
|
}
|
|
else if( cNodeName == wxT( "ATTR" ) )
|
|
{
|
|
ATTRIBUTE_VALUE attrVal;
|
|
attrVal.Parse( aChildNode, aContext );
|
|
AttributeValues.insert( std::make_pair( attrVal.AttributeID, attrVal ) );
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::PART::DEFINITION::GATE::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "GATEDEFINITION" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
Name = GetXmlAttributeIDString( aNode, 1 );
|
|
Alternate = GetXmlAttributeIDString( aNode, 2 );
|
|
PinCount = GetXmlAttributeIDLong( aNode, 3 );
|
|
|
|
CheckNoChildNodes( aNode );
|
|
}
|
|
|
|
|
|
CADSTAR_ARCHIVE_PARSER::PART::PIN_TYPE CADSTAR_ARCHIVE_PARSER::PART::GetPinType( XNODE* aNode )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "PINTYPE" ) );
|
|
|
|
wxString pinTypeStr = GetXmlAttributeIDString( aNode, 0 );
|
|
|
|
std::map<wxString, PIN_TYPE> pinTypeMap = { { wxT( "INPUT" ), PIN_TYPE::INPUT },
|
|
{ wxT( "OUTPUT_OR" ), PIN_TYPE::OUTPUT_OR },
|
|
{ wxT( "OUTPUT_NOT_OR" ), PIN_TYPE::OUTPUT_NOT_OR },
|
|
{ wxT( "OUTPUT_NOT_NORM_OR" ), PIN_TYPE::OUTPUT_NOT_NORM_OR },
|
|
{ wxT( "POWER" ), PIN_TYPE::POWER }, { wxT( "GROUND" ), PIN_TYPE::GROUND },
|
|
{ wxT( "TRISTATE_BIDIR" ), PIN_TYPE::TRISTATE_BIDIR },
|
|
{ wxT( "TRISTATE_INPUT" ), PIN_TYPE::TRISTATE_INPUT },
|
|
{ wxT( "TRISTATE_DRIVER" ), PIN_TYPE::TRISTATE_DRIVER } };
|
|
|
|
if( pinTypeMap.find( pinTypeStr ) == pinTypeMap.end() )
|
|
THROW_UNKNOWN_PARAMETER_IO_ERROR( pinTypeStr, aNode->GetName() );
|
|
|
|
return pinTypeMap[pinTypeStr];
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::PART::DEFINITION::PIN::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "PARTDEFINITIONPIN" ) );
|
|
|
|
ID = GetXmlAttributeIDLong( aNode, 0 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "PINNAME" ) )
|
|
{
|
|
Name = GetXmlAttributeIDString( cNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "PINLABEL" ) )
|
|
{
|
|
Label = GetXmlAttributeIDString( cNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "PINSIGNAL" ) )
|
|
{
|
|
Signal = GetXmlAttributeIDString( cNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "PINTERM" ) )
|
|
{
|
|
TerminalGate = GetXmlAttributeIDString( cNode, 0 );
|
|
TerminalPin = GetXmlAttributeIDLong( cNode, 1 );
|
|
}
|
|
else if( cNodeName == wxT( "PINTYPE" ) )
|
|
{
|
|
Type = GetPinType( cNode );
|
|
}
|
|
else if( cNodeName == wxT( "PINLOAD" ) )
|
|
{
|
|
Load = GetXmlAttributeIDLong( cNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "PINPOSITION" ) )
|
|
{
|
|
Position = (POSITION) GetXmlAttributeIDLong( cNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "PINIDENTIFIER" ) )
|
|
{
|
|
Identifier = GetXmlAttributeIDString( cNode, 0 );
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::PART::PART_PIN::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "PARTPIN" ) );
|
|
|
|
ID = GetXmlAttributeIDLong( aNode, 0 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "PINNAME" ) )
|
|
Name = GetXmlAttributeIDString( cNode, 0 );
|
|
else if( cNodeName == wxT( "PINTYPE" ) )
|
|
Type = GetPinType( cNode );
|
|
else if( cNodeName == wxT( "PINIDENTIFIER" ) )
|
|
Identifier = GetXmlAttributeIDString( cNode, 0 );
|
|
else
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::PART::DEFINITION::PIN_EQUIVALENCE::Parse( XNODE* aNode,
|
|
PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "PINEQUIVALENCE" ) );
|
|
|
|
wxXmlAttribute* xmlAttribute = aNode->GetAttributes();
|
|
|
|
for( ; xmlAttribute; xmlAttribute = xmlAttribute->GetNext() )
|
|
{
|
|
if( !IsValidAttribute( xmlAttribute ) )
|
|
continue;
|
|
|
|
long pinId;
|
|
|
|
if( !xmlAttribute->GetValue().ToLong( &pinId ) )
|
|
THROW_UNKNOWN_PARAMETER_IO_ERROR( xmlAttribute->GetValue(), aNode->GetName() );
|
|
|
|
PinIDs.push_back( (PART_DEFINITION_PIN_ID) pinId );
|
|
}
|
|
|
|
CheckNoChildNodes( aNode );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::PART::DEFINITION::SWAP_GATE::Parse( XNODE* aNode,
|
|
PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "SWAPGATE" ) );
|
|
|
|
wxXmlAttribute* xmlAttribute = aNode->GetAttributes();
|
|
|
|
for( ; xmlAttribute; xmlAttribute = xmlAttribute->GetNext() )
|
|
{
|
|
if( !IsValidAttribute( xmlAttribute ) )
|
|
continue;
|
|
|
|
long pinId;
|
|
|
|
if( !xmlAttribute->GetValue().ToLong( &pinId ) )
|
|
THROW_UNKNOWN_PARAMETER_IO_ERROR( xmlAttribute->GetValue(), aNode->GetName() );
|
|
|
|
PinIDs.push_back( (PART_DEFINITION_PIN_ID) pinId );
|
|
}
|
|
|
|
CheckNoChildNodes( aNode );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::PART::DEFINITION::SWAP_GROUP::Parse( XNODE* aNode,
|
|
PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "SWAPGROUP" ) );
|
|
|
|
GateName = GetXmlAttributeIDString( aNode, 0 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "EXTERNAL" ) )
|
|
{
|
|
External = true;
|
|
}
|
|
else if( cNodeName == wxT( "SWAPGATE" ) )
|
|
{
|
|
SWAP_GATE swapGate;
|
|
swapGate.Parse( cNode, aContext );
|
|
SwapGates.push_back( swapGate );
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::PART::DEFINITION::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "PARTDEFINITION" ) );
|
|
|
|
Name = GetXmlAttributeIDString( aNode, 0 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "HIDEPINNAMES" ) )
|
|
{
|
|
HidePinNames = true;
|
|
}
|
|
else if( cNodeName == wxT( "MAXPIN" ) )
|
|
{
|
|
MaxPinCount = GetXmlAttributeIDLong( cNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "GATEDEFINITION" ) )
|
|
{
|
|
GATE gate;
|
|
gate.Parse( cNode, aContext );
|
|
GateSymbols.insert( std::make_pair( gate.ID, gate ) );
|
|
}
|
|
else if( cNodeName == wxT( "PARTDEFINITIONPIN" ) )
|
|
{
|
|
PIN pin;
|
|
pin.Parse( cNode, aContext );
|
|
Pins.insert( std::make_pair( pin.ID, pin ) );
|
|
}
|
|
else if( cNodeName == wxT( "ATTR" ) )
|
|
{
|
|
ATTRIBUTE_VALUE attr;
|
|
attr.Parse( cNode, aContext );
|
|
AttributeValues.insert( std::make_pair( attr.AttributeID, attr ) );
|
|
}
|
|
else if( cNodeName == wxT( "PINEQUIVALENCE" ) )
|
|
{
|
|
PIN_EQUIVALENCE pinEq;
|
|
pinEq.Parse( cNode, aContext );
|
|
PinEquivalences.push_back( pinEq );
|
|
}
|
|
else if( cNodeName == wxT( "SWAPGROUP" ) )
|
|
{
|
|
SWAP_GROUP swapGroup;
|
|
swapGroup.Parse( cNode, aContext );
|
|
SwapGroups.push_back( swapGroup );
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::PART::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "PART" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
Name = GetXmlAttributeIDString( aNode, 1 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "VERSION" ) )
|
|
{
|
|
Version = GetXmlAttributeIDLong( cNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "HIDEPINNAMES" ) )
|
|
{
|
|
HidePinNames = true;
|
|
}
|
|
else if( cNodeName == wxT( "PARTDEFINITION" ) )
|
|
{
|
|
Definition.Parse( cNode, aContext );
|
|
}
|
|
else if( cNodeName == wxT( "PARTPIN" ) )
|
|
{
|
|
PART_PIN pin;
|
|
pin.Parse( cNode, aContext );
|
|
PartPins.insert( std::make_pair( pin.ID, pin ) );
|
|
}
|
|
else if( cNodeName == wxT( "ATTR" ) )
|
|
{
|
|
ATTRIBUTE_VALUE attr;
|
|
attr.Parse( cNode, aContext );
|
|
AttributeValues.insert( std::make_pair( attr.AttributeID, attr ) );
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::PARTS::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "PARTS" ) );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "PART" ) )
|
|
{
|
|
PART part;
|
|
part.Parse( cNode, aContext );
|
|
PartDefinitions.insert( std::make_pair( part.ID, part ) );
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
|
|
}
|
|
|
|
aContext->CheckPointCallback();
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::NET::JUNCTION::ParseIdentifiers( XNODE* aNode,
|
|
PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "JPT" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
LayerID = GetXmlAttributeIDString( aNode, 1 );
|
|
}
|
|
|
|
|
|
bool CADSTAR_ARCHIVE_PARSER::NET::JUNCTION::ParseSubNode( XNODE* aChildNode,
|
|
PARSER_CONTEXT* aContext )
|
|
{
|
|
wxString cNodeName = aChildNode->GetName();
|
|
|
|
if( cNodeName == wxT( "PT" ) )
|
|
Location.Parse( aChildNode, aContext );
|
|
else if( cNodeName == wxT( "FIX" ) )
|
|
Fixed = true;
|
|
else if( cNodeName == wxT( "GROUPREF" ) )
|
|
GroupID = GetXmlAttributeIDString( aChildNode, 0 );
|
|
else if( cNodeName == wxT( "REUSEBLOCKREF" ) )
|
|
ReuseBlockRef.Parse( aChildNode, aContext );
|
|
else
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::NET::JUNCTION::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
ParseIdentifiers( aNode, aContext );
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
if( ParseSubNode( cNode, aContext ) )
|
|
continue;
|
|
else
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), aNode->GetName() );
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::NET::CONNECTION::ParseIdentifiers( XNODE* aNode,
|
|
PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "CONN" ) );
|
|
|
|
StartNode = GetXmlAttributeIDString( aNode, 0 );
|
|
EndNode = GetXmlAttributeIDString( aNode, 1 );
|
|
RouteCodeID = GetXmlAttributeIDString( aNode, 2 );
|
|
}
|
|
|
|
|
|
bool CADSTAR_ARCHIVE_PARSER::NET::CONNECTION::ParseSubNode( XNODE* aChildNode,
|
|
PARSER_CONTEXT* aContext )
|
|
{
|
|
wxString cNodeName = aChildNode->GetName();
|
|
|
|
if( cNodeName == wxT( "FIX" ) )
|
|
{
|
|
Fixed = true;
|
|
}
|
|
else if( cNodeName == wxT( "HIDDEN" ) )
|
|
{
|
|
Hidden = true;
|
|
}
|
|
else if( cNodeName == wxT( "GROUPREF" ) )
|
|
{
|
|
GroupID = GetXmlAttributeIDString( aChildNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "REUSEBLOCKREF" ) )
|
|
{
|
|
ReuseBlockRef.Parse( aChildNode, aContext );
|
|
}
|
|
else if( cNodeName == wxT( "ATTR" ) )
|
|
{
|
|
ATTRIBUTE_VALUE attrVal;
|
|
attrVal.Parse( aChildNode, aContext );
|
|
AttributeValues.insert( std::make_pair( attrVal.AttributeID, attrVal ) );
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::NET::ParseIdentifiers( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "NET" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
}
|
|
|
|
|
|
bool CADSTAR_ARCHIVE_PARSER::NET::ParseSubNode( XNODE* aChildNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxString cNodeName = aChildNode->GetName();
|
|
|
|
if( cNodeName == wxT( "NETCODE" ) )
|
|
{
|
|
RouteCodeID = GetXmlAttributeIDString( aChildNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "SIGNAME" ) )
|
|
{
|
|
Name = GetXmlAttributeIDString( aChildNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "SIGNUM" ) )
|
|
{
|
|
SignalNum = GetXmlAttributeIDLong( aChildNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "HIGHLIT" ) )
|
|
{
|
|
Highlight = true;
|
|
}
|
|
else if( cNodeName == wxT( "JPT" ) )
|
|
{
|
|
JUNCTION jpt;
|
|
jpt.Parse( aChildNode, aContext );
|
|
Junctions.insert( std::make_pair( jpt.ID, jpt ) );
|
|
}
|
|
else if( cNodeName == wxT( "NETCLASSREF" ) )
|
|
{
|
|
NetClassID = GetXmlAttributeIDString( aChildNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "SPACINGCLASS" ) )
|
|
{
|
|
SpacingClassID = GetXmlAttributeIDString( aChildNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "ATTR" ) )
|
|
{
|
|
ATTRIBUTE_VALUE attrVal;
|
|
attrVal.Parse( aChildNode, aContext );
|
|
AttributeValues.insert( std::make_pair( attrVal.AttributeID, attrVal ) );
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::DOCUMENTATION_SYMBOL::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "DOCSYMBOL" ) );
|
|
|
|
ID = GetXmlAttributeIDString( aNode, 0 );
|
|
SymdefID = GetXmlAttributeIDString( aNode, 1 );
|
|
LayerID = GetXmlAttributeIDString( aNode, 2 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
bool originParsed = false;
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( !originParsed && cNodeName == wxT( "PT" ) )
|
|
{
|
|
Origin.Parse( cNode, aContext );
|
|
originParsed = true;
|
|
}
|
|
else if( cNodeName == wxT( "GROUPREF" ) )
|
|
{
|
|
GroupID = GetXmlAttributeIDString( cNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "REUSEBLOCKREF" ) )
|
|
{
|
|
ReuseBlockRef.Parse( cNode, aContext );
|
|
}
|
|
else if( cNodeName == wxT( "FIX" ) )
|
|
{
|
|
Fixed = true;
|
|
}
|
|
else if( cNodeName == wxT( "MIRROR" ) )
|
|
{
|
|
Mirror = true;
|
|
}
|
|
else if( cNodeName == wxT( "READABILITY" ) )
|
|
{
|
|
Readability = ParseReadability( cNode );
|
|
}
|
|
else if( cNodeName == wxT( "ORIENT" ) )
|
|
{
|
|
OrientAngle = GetXmlAttributeIDLong( cNode, 0 );
|
|
}
|
|
else if( cNodeName == wxT( "ATTR" ) )
|
|
{
|
|
ATTRIBUTE_VALUE attr;
|
|
attr.Parse( cNode, aContext );
|
|
AttributeValues.insert( std::make_pair( attr.AttributeID, attr ) );
|
|
}
|
|
else if( cNodeName == wxT( "SCALE" ) )
|
|
{
|
|
ScaleRatioNumerator = GetXmlAttributeIDLong( cNode, 0 );
|
|
ScaleRatioDenominator = GetXmlAttributeIDLong( cNode, 1 );
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
|
|
}
|
|
}
|
|
|
|
if( !originParsed )
|
|
THROW_MISSING_PARAMETER_IO_ERROR( wxT( "PT" ), aNode->GetName() );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::DFLTSETTINGS::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "DFLTSETTINGS" ) );
|
|
|
|
Color = GetXmlAttributeIDString( aNode, 0 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "INVISIBLE" ) )
|
|
{
|
|
IsVisible = false;
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::ATTRCOL::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "ATTRCOL" ) );
|
|
|
|
AttributeID = GetXmlAttributeIDString( aNode, 0 );
|
|
Color = GetXmlAttributeIDString( aNode, 1 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "INVISIBLE" ) )
|
|
{
|
|
IsVisible = false;
|
|
}
|
|
else if( cNodeName == wxT( "NOTPICKABLE" ) )
|
|
{
|
|
IsPickable = false;
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::ATTRCOLORS::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "ATTRCOLORS" ) );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "DFLTSETTINGS" ) )
|
|
{
|
|
DefaultSettings.Parse( cNode, aContext );
|
|
}
|
|
else if( cNodeName == wxT( "ATTRCOL" ) )
|
|
{
|
|
ATTRCOL attrcol;
|
|
attrcol.Parse( cNode, aContext );
|
|
AttributeColors.insert( { attrcol.AttributeID, attrcol } );
|
|
}
|
|
else if( cNodeName == wxT( "INVISIBLE" ) )
|
|
{
|
|
IsVisible = false;
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::PARTNAMECOL::Parse( XNODE* aNode, PARSER_CONTEXT* aContext )
|
|
{
|
|
wxASSERT( aNode->GetName() == wxT( "PARTNAMECOL" ) );
|
|
|
|
Color = GetXmlAttributeIDString( aNode, 0 );
|
|
|
|
XNODE* cNode = aNode->GetChildren();
|
|
|
|
for( ; cNode; cNode = cNode->GetNext() )
|
|
{
|
|
wxString cNodeName = cNode->GetName();
|
|
|
|
if( cNodeName == wxT( "INVISIBLE" ) )
|
|
{
|
|
IsVisible = false;
|
|
}
|
|
else if( cNodeName == wxT( "NOTPICKABLE" ) )
|
|
{
|
|
IsPickable = false;
|
|
}
|
|
else
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::InsertAttributeAtEnd( XNODE* aNode, wxString aValue )
|
|
{
|
|
wxString result;
|
|
int numAttributes = 0;
|
|
|
|
if( aNode->GetAttribute( wxT( "numAttributes" ), &result ) )
|
|
{
|
|
numAttributes = wxAtoi( result );
|
|
aNode->DeleteAttribute( wxT( "numAttributes" ) );
|
|
++numAttributes;
|
|
}
|
|
|
|
aNode->AddAttribute( wxT( "numAttributes" ), wxString::Format( wxT( "%i" ), numAttributes ) );
|
|
|
|
wxString paramName = wxT( "attr" );
|
|
paramName << numAttributes;
|
|
|
|
aNode->AddAttribute( paramName, aValue );
|
|
}
|
|
|
|
|
|
XNODE* CADSTAR_ARCHIVE_PARSER::LoadArchiveFile( const wxString& aFileName,
|
|
const wxString& aFileTypeIdentifier, PROGRESS_REPORTER* aProgressReporter )
|
|
{
|
|
KEYWORD emptyKeywords[1] = {};
|
|
XNODE * iNode = nullptr, *cNode = nullptr;
|
|
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.
|
|
|
|
// Open the file and get the file size
|
|
FILE* fp = wxFopen( aFileName, wxT( "rt" ) );
|
|
|
|
if( !fp )
|
|
THROW_IO_ERROR( wxString::Format( _( "Cannot open file '%s'" ), aFileName ) );
|
|
|
|
fseek( fp, 0L, SEEK_END );
|
|
long fileSize = ftell( fp );
|
|
rewind( fp );
|
|
|
|
DSNLEXER lexer( emptyKeywords, 0, nullptr, fp, aFileName );
|
|
|
|
auto currentProgress = [&]() -> double
|
|
{
|
|
return static_cast<double>( ftell( fp ) ) / fileSize;
|
|
};
|
|
|
|
double previousReportedProgress = -1.0;
|
|
|
|
while( ( tok = lexer.NextTok() ) != DSN_EOF )
|
|
{
|
|
if( aProgressReporter && ( currentProgress() - previousReportedProgress ) > 0.01 )
|
|
{
|
|
if( !aProgressReporter->KeepRefreshing() )
|
|
THROW_IO_ERROR( _( "File import cancelled by user." ) );
|
|
|
|
aProgressReporter->SetCurrentProgress( currentProgress() );
|
|
previousReportedProgress = currentProgress();
|
|
}
|
|
|
|
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!" ) );
|
|
}
|
|
}
|
|
|
|
// Not enough closing brackets
|
|
if( iNode != nullptr )
|
|
THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
|
|
|
|
// Throw if no data was parsed
|
|
if( cNode )
|
|
return cNode;
|
|
else
|
|
THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
bool CADSTAR_ARCHIVE_PARSER::IsValidAttribute( wxXmlAttribute* aAttribute )
|
|
{
|
|
return aAttribute->GetName() != wxT( "numAttributes" );
|
|
}
|
|
|
|
|
|
wxString CADSTAR_ARCHIVE_PARSER::GetXmlAttributeIDString( XNODE* aNode, unsigned int aID,
|
|
bool aIsRequired )
|
|
{
|
|
wxString attrName, retVal;
|
|
attrName = "attr";
|
|
attrName << aID;
|
|
|
|
if( !aNode->GetAttribute( attrName, &retVal ) )
|
|
{
|
|
if( aIsRequired )
|
|
THROW_MISSING_PARAMETER_IO_ERROR( std::to_string( aID ), aNode->GetName() );
|
|
else
|
|
return wxEmptyString;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
long CADSTAR_ARCHIVE_PARSER::GetXmlAttributeIDLong( XNODE* aNode, unsigned int aID,
|
|
bool aIsRequired )
|
|
{
|
|
long retVal;
|
|
bool success = GetXmlAttributeIDString( aNode, aID, aIsRequired ).ToLong( &retVal );
|
|
|
|
if( !success )
|
|
{
|
|
if( aIsRequired )
|
|
THROW_PARSING_IO_ERROR( std::to_string( aID ), aNode->GetName() );
|
|
else
|
|
return UNDEFINED_VALUE;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::CheckNoChildNodes( XNODE* aNode )
|
|
{
|
|
if( aNode && aNode->GetChildren() )
|
|
THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetChildren()->GetName(), aNode->GetName() );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::CheckNoNextNodes( XNODE* aNode )
|
|
{
|
|
if( aNode && aNode->GetNext() )
|
|
THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetNext()->GetName(), aNode->GetParent()->GetName() );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::ParseChildEValue( XNODE* aNode, PARSER_CONTEXT* aContext,
|
|
EVALUE& aValueToParse )
|
|
{
|
|
if( aNode->GetChildren()->GetName() == wxT( "E" ) )
|
|
aValueToParse.Parse( aNode->GetChildren(), aContext );
|
|
else
|
|
THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetChildren()->GetName(), aNode->GetName() );
|
|
}
|
|
|
|
|
|
std::vector<CADSTAR_ARCHIVE_PARSER::POINT> CADSTAR_ARCHIVE_PARSER::ParseAllChildPoints(
|
|
XNODE* aNode, PARSER_CONTEXT* aContext, bool aTestAllChildNodes, int aExpectedNumPoints )
|
|
{
|
|
std::vector<POINT> 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, aContext );
|
|
retVal.push_back( pt );
|
|
}
|
|
else if( aTestAllChildNodes )
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), aNode->GetName() );
|
|
}
|
|
}
|
|
|
|
if( aExpectedNumPoints != UNDEFINED_VALUE
|
|
&& retVal.size() != static_cast<size_t>( 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_PARSER::VERTEX> CADSTAR_ARCHIVE_PARSER::ParseAllChildVertices(
|
|
XNODE* aNode, PARSER_CONTEXT* aContext, bool aTestAllChildNodes )
|
|
{
|
|
std::vector<VERTEX> 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, aContext );
|
|
retVal.push_back( vertex );
|
|
}
|
|
else if( aTestAllChildNodes )
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), aNode->GetName() );
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
std::vector<CADSTAR_ARCHIVE_PARSER::CUTOUT> CADSTAR_ARCHIVE_PARSER::ParseAllChildCutouts(
|
|
XNODE* aNode, PARSER_CONTEXT* aContext, bool aTestAllChildNodes )
|
|
{
|
|
std::vector<CUTOUT> 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, aContext );
|
|
retVal.push_back( cutout );
|
|
}
|
|
else if( aTestAllChildNodes )
|
|
{
|
|
THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), aNode->GetName() );
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
long CADSTAR_ARCHIVE_PARSER::GetNumberOfChildNodes( XNODE* aNode )
|
|
{
|
|
XNODE* childNodes = aNode->GetChildren();
|
|
long retval = 0;
|
|
|
|
for( ; childNodes; childNodes = childNodes->GetNext() )
|
|
retval++;
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
long CADSTAR_ARCHIVE_PARSER::GetNumberOfStepsForReporting( XNODE* aRootNode, std::vector<wxString> aSubNodeChildrenToCount )
|
|
{
|
|
XNODE* level1Node = aRootNode->GetChildren();
|
|
long retval = 0;
|
|
|
|
for( ; level1Node; level1Node = level1Node->GetNext() )
|
|
{
|
|
for( wxString childNodeName : aSubNodeChildrenToCount )
|
|
{
|
|
if( level1Node->GetName() == childNodeName )
|
|
retval += GetNumberOfChildNodes( level1Node );
|
|
}
|
|
|
|
retval++;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
wxString CADSTAR_ARCHIVE_PARSER::HandleTextOverbar( wxString aCadstarString )
|
|
{
|
|
wxString escapedText = aCadstarString;
|
|
|
|
escapedText.Replace( wxT( "'" ), wxT( "~" ) );
|
|
|
|
return ConvertToNewOverbarNotation( escapedText );
|
|
}
|
|
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::FixTextPositionNoAlignment( EDA_TEXT* aKiCadTextItem )
|
|
{
|
|
if( !aKiCadTextItem->GetText().IsEmpty() )
|
|
{
|
|
VECTOR2I positionOffset( 0, aKiCadTextItem->GetInterline() );
|
|
RotatePoint( positionOffset, aKiCadTextItem->GetTextAngle() );
|
|
|
|
EDA_ITEM* textEdaItem = dynamic_cast<EDA_ITEM*>( aKiCadTextItem );
|
|
|
|
if( textEdaItem &&
|
|
( textEdaItem->Type() == LIB_TEXT_T || textEdaItem->Type() == LIB_FIELD_T ) )
|
|
{
|
|
// Y coordinate increases upwards in the symbol editor
|
|
positionOffset.y = -positionOffset.y;
|
|
}
|
|
|
|
//Count num of additional lines
|
|
wxString text = aKiCadTextItem->GetText();
|
|
int numExtraLines = text.Replace( "\n", "\n" );
|
|
numExtraLines -= text.at( text.size() - 1 ) == '\n'; // Ignore new line character at end
|
|
positionOffset.x *= numExtraLines;
|
|
positionOffset.y *= numExtraLines;
|
|
|
|
aKiCadTextItem->Offset( positionOffset );
|
|
}
|
|
}
|
|
|
|
void CADSTAR_ARCHIVE_PARSER::checkPoint()
|
|
{
|
|
if( m_progressReporter )
|
|
{
|
|
m_progressReporter->AdvanceProgress();
|
|
|
|
if( !m_progressReporter->KeepRefreshing() )
|
|
THROW_IO_ERROR( _( "File import cancelled by user." ) );
|
|
}
|
|
}
|
|
|