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++ )
{
AM_PARAM_ITEM item = m_paramStack[ii];
switch( item.GetType() )
{
case ADD:
@ -89,7 +90,9 @@ double AM_PARAM::GetValue( const D_CODE* aDcode ) const
if( aDcode ) // should be always true here
{
if( item.GetIndex() <= aDcode->GetParamCount() )
{
curr_value = aDcode->GetParam( item.GetIndex() );
}
else // Get parameter from local param definition
{
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:
if( item.GetType() == PUSHVALUE )
curr_value = item.GetValue();
switch( state )
{
case POPVALUE:
@ -137,6 +141,7 @@ double AM_PARAM::GetValue( const D_CODE* aDcode ) const
break;
}
}
return paramvalue;
}

View File

@ -162,6 +162,7 @@ public:
m_dvalue = aValue;
m_ivalue = 0;
}
AM_PARAM_ITEM( parm_item_type aType, int aValue )
{
m_type = aType;
@ -173,18 +174,22 @@ public:
{
m_dvalue = aValue;
}
double GetValue( ) const
{
return m_dvalue;
}
parm_item_type GetType() const
{
return m_type;
}
unsigned GetIndex() const
{
return (unsigned) m_ivalue;
}
bool IsOperator() const
{
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;
}
bool IsDefered() const
{
return m_type == PUSHPARM;

View File

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

View File

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

View File

@ -173,6 +173,7 @@ bool GERBER_FILE_IMAGE::LoadGerberFile( const wxString& aFullFileName )
case 'I':
case 'J': /* Auxiliary Move command */
m_IJPos = ReadIJCoord( text );
if( *text == '*' ) // command like X35142Y15945J504*
{
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 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 ) )
{
@ -290,7 +301,18 @@ int ReadInt( 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 ) )
{

View File

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