Gerbview: fix a subtle issue when reading parameter values in Gerber files.

In Gerber files the char 'X' is used as separator.
But when reading parameter values, the sequence "0xnnn" is a number in hexadecimal format, and the 'X' char is not seen as separator by usual strtod or strtol C functions.
This is now fixed.
This commit is contained in:
jean-pierre charras 2017-04-08 12:53:40 +02:00
parent 675eb37163
commit ba517db96c
7 changed files with 63 additions and 9 deletions

View File

@ -75,6 +75,7 @@ double AM_PARAM::GetValue( const D_CODE* aDcode ) const
for( unsigned ii = 0; ii < m_paramStack.size(); ii++ ) for( unsigned ii = 0; ii < m_paramStack.size(); ii++ )
{ {
AM_PARAM_ITEM item = m_paramStack[ii]; AM_PARAM_ITEM item = m_paramStack[ii];
switch( item.GetType() ) switch( item.GetType() )
{ {
case ADD: case ADD:
@ -89,7 +90,9 @@ double AM_PARAM::GetValue( const D_CODE* aDcode ) const
if( aDcode ) // should be always true here if( aDcode ) // should be always true here
{ {
if( item.GetIndex() <= aDcode->GetParamCount() ) if( item.GetIndex() <= aDcode->GetParamCount() )
{
curr_value = aDcode->GetParam( item.GetIndex() ); curr_value = aDcode->GetParam( item.GetIndex() );
}
else // Get parameter from local param definition else // Get parameter from local param definition
{ {
const APERTURE_MACRO * am_parent = aDcode->GetMacro(); const APERTURE_MACRO * am_parent = aDcode->GetMacro();
@ -104,6 +107,7 @@ double AM_PARAM::GetValue( const D_CODE* aDcode ) const
case PUSHVALUE: // a value is on the stack: case PUSHVALUE: // a value is on the stack:
if( item.GetType() == PUSHVALUE ) if( item.GetType() == PUSHVALUE )
curr_value = item.GetValue(); curr_value = item.GetValue();
switch( state ) switch( state )
{ {
case POPVALUE: case POPVALUE:
@ -137,6 +141,7 @@ double AM_PARAM::GetValue( const D_CODE* aDcode ) const
break; break;
} }
} }
return paramvalue; return paramvalue;
} }

View File

@ -162,6 +162,7 @@ public:
m_dvalue = aValue; m_dvalue = aValue;
m_ivalue = 0; m_ivalue = 0;
} }
AM_PARAM_ITEM( parm_item_type aType, int aValue ) AM_PARAM_ITEM( parm_item_type aType, int aValue )
{ {
m_type = aType; m_type = aType;
@ -173,18 +174,22 @@ public:
{ {
m_dvalue = aValue; m_dvalue = aValue;
} }
double GetValue( ) const double GetValue( ) const
{ {
return m_dvalue; return m_dvalue;
} }
parm_item_type GetType() const parm_item_type GetType() const
{ {
return m_type; return m_type;
} }
unsigned GetIndex() const unsigned GetIndex() const
{ {
return (unsigned) m_ivalue; return (unsigned) m_ivalue;
} }
bool IsOperator() const bool IsOperator() const
{ {
return m_type == ADD || m_type == SUB || m_type == MUL || m_type == DIV; return m_type == ADD || m_type == SUB || m_type == MUL || m_type == DIV;
@ -193,6 +198,7 @@ public:
{ {
return m_type == PUSHVALUE || m_type == PUSHPARM; return m_type == PUSHVALUE || m_type == PUSHPARM;
} }
bool IsDefered() const bool IsDefered() const
{ {
return m_type == PUSHPARM; return m_type == PUSHPARM;

View File

@ -143,6 +143,7 @@ void AM_PRIMITIVE::DrawBasicShape( GERBER_DRAW_ITEM* aParent,
// shape rotation: // shape rotation:
rotation = params[6].GetValue( tool ) * 10.0; rotation = params[6].GetValue( tool ) * 10.0;
if( rotation != 0) if( rotation != 0)
{ {
for( unsigned ii = 0; ii < polybuffer.size(); ii++ ) for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
@ -793,6 +794,7 @@ double APERTURE_MACRO::GetLocalParam( const D_CODE* aDcode, unsigned aParamId )
{ {
// find parameter descr. // find parameter descr.
const AM_PARAM * param = NULL; const AM_PARAM * param = NULL;
for( unsigned ii = 0; ii < m_localparamStack.size(); ii ++ ) for( unsigned ii = 0; ii < m_localparamStack.size(); ii ++ )
{ {
if( m_localparamStack[ii].GetIndex() == aParamId ) if( m_localparamStack[ii].GetIndex() == aParamId )
@ -801,9 +803,12 @@ double APERTURE_MACRO::GetLocalParam( const D_CODE* aDcode, unsigned aParamId )
break; break;
} }
} }
if ( param == NULL ) // not found if ( param == NULL ) // not found
return 0.0; return 0.0;
// Evaluate parameter // Evaluate parameter
double value = param->GetValue( aDcode ); double value = param->GetValue( aDcode );
return value; return value;
} }

View File

@ -5,6 +5,7 @@ G04 Handcoded by Stefan Petersen *
%OFA0.0000B0.0000*% %OFA0.0000B0.0000*%
G90* G90*
%AMCIRCLE* %AMCIRCLE*
0 this is a comment*
1,1,$1,0,0* 1,1,$1,0,0*
% %
%AMVECTOR* %AMVECTOR*

View File

@ -173,6 +173,7 @@ bool GERBER_FILE_IMAGE::LoadGerberFile( const wxString& aFullFileName )
case 'I': case 'I':
case 'J': /* Auxiliary Move command */ case 'J': /* Auxiliary Move command */
m_IJPos = ReadIJCoord( text ); m_IJPos = ReadIJCoord( text );
if( *text == '*' ) // command like X35142Y15945J504* if( *text == '*' ) // command like X35142Y15945J504*
{ {
Execute_DCODE_Command( text, Execute_DCODE_Command( text,

View File

@ -267,7 +267,18 @@ wxPoint GERBER_FILE_IMAGE::ReadIJCoord( char*& Text )
*/ */
int ReadInt( char*& text, bool aSkipSeparator = true ) int ReadInt( char*& text, bool aSkipSeparator = true )
{ {
int ret = (int) strtol( text, &text, 10 ); int ret;
// For strtol, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
// However, 'X' is a separator in Gerber strings with numbers.
// We need to detect that
if( strnicmp( text, "0X", 2 ) == 0 )
{
text++;
ret = 0;
}
else
ret = (int) strtol( text, &text, 10 );
if( *text == ',' || isspace( *text ) ) if( *text == ',' || isspace( *text ) )
{ {
@ -290,7 +301,18 @@ int ReadInt( char*& text, bool aSkipSeparator = true )
*/ */
double ReadDouble( char*& text, bool aSkipSeparator = true ) double ReadDouble( char*& text, bool aSkipSeparator = true )
{ {
double ret = strtod( text, &text ); double ret;
// For strtod, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
// However, 'X' is a separator in Gerber strings with numbers.
// We need to detect that
if( strnicmp( text, "0X", 2 ) == 0 )
{
text++;
ret = 0.0;
}
else
ret = strtod( text, &text );
if( *text == ',' || isspace( *text ) ) if( *text == ',' || isspace( *text ) )
{ {

View File

@ -733,7 +733,6 @@ bool GERBER_FILE_IMAGE::ExecuteRS274XCommand( int command, char* buff, char*& te
break; break;
case AP_DEFINITION: case AP_DEFINITION:
/* input example: %ADD30R,0.081800X0.101500*% /* input example: %ADD30R,0.081800X0.101500*%
* Aperture definition has 4 options: C, R, O, P * Aperture definition has 4 options: C, R, O, P
* (Circle, Rect, Oval, regular Polygon) * (Circle, Rect, Oval, regular Polygon)
@ -898,18 +897,24 @@ bool GERBER_FILE_IMAGE::ExecuteRS274XCommand( int command, char* buff, char*& te
if( *text == ',' ) if( *text == ',' )
{ // Read aperture macro parameters and store them { // Read aperture macro parameters and store them
text++; // text points the first parameter text++; // text points the first parameter
while( *text && *text != '*' ) while( *text && *text != '*' )
{ {
double param = ReadDouble( text ); double param = ReadDouble( text );
dcode->AppendParam( param ); dcode->AppendParam( param );
while( isspace( *text ) ) text++;
if( *text == 'X' ) while( isspace( *text ) )
++text; text++;
// Skip 'X' separator:
if( *text == 'X' || *text == 'x' )
text++;
} }
} }
// lookup the aperture macro here. // lookup the aperture macro here.
APERTURE_MACRO* pam = FindApertureMacro( am_lookup ); APERTURE_MACRO* pam = FindApertureMacro( am_lookup );
if( !pam ) if( !pam )
{ {
msg.Printf( wxT( "RS274X: aperture macro %s not found\n" ), msg.Printf( wxT( "RS274X: aperture macro %s not found\n" ),
@ -922,6 +927,7 @@ bool GERBER_FILE_IMAGE::ExecuteRS274XCommand( int command, char* buff, char*& te
dcode->m_Shape = APT_MACRO; dcode->m_Shape = APT_MACRO;
dcode->SetMacro( pam ); dcode->SetMacro( pam );
} }
break; break;
default: default:
@ -1024,7 +1030,8 @@ bool GERBER_FILE_IMAGE::ReadApertureMacro( char *buff,
if( *text == '*' ) if( *text == '*' )
++text; ++text;
text = GetNextLine( buff, text, gerber_file ); // Get next line text = GetNextLine( buff, text, gerber_file );
if( text == NULL ) // End of File if( text == NULL ) // End of File
return false; return false;
@ -1034,6 +1041,7 @@ bool GERBER_FILE_IMAGE::ReadApertureMacro( char *buff,
// last line is % or *% sometime found. // last line is % or *% sometime found.
if( *text == '*' ) if( *text == '*' )
++text; ++text;
if( *text == '%' ) if( *text == '%' )
break; // exit with text still pointing at % break; // exit with text still pointing at %
@ -1063,10 +1071,13 @@ bool GERBER_FILE_IMAGE::ReadApertureMacro( char *buff,
else else
primitive_type = ReadInt( text ); primitive_type = ReadInt( text );
bool is_comment = false;
switch( primitive_type ) switch( primitive_type )
{ {
case AMP_COMMENT: // lines starting by 0 are a comment case AMP_COMMENT: // lines starting by 0 are a comment
paramCount = 0; paramCount = 0;
is_comment = true;
// Skip comment // Skip comment
while( *text && ( *text != '*' ) ) while( *text && ( *text != '*' ) )
text++; text++;
@ -1114,6 +1125,9 @@ bool GERBER_FILE_IMAGE::ReadApertureMacro( char *buff,
return false; return false;
} }
if( is_comment )
continue;
AM_PRIMITIVE prim( m_GerbMetric ); AM_PRIMITIVE prim( m_GerbMetric );
prim.primitive_id = (AM_PRIMITIVE_ID) primitive_type; prim.primitive_id = (AM_PRIMITIVE_ID) primitive_type;
int ii; int ii;