Review ReadXY/ReadIJ to avoid static char arrays

Tighten up the code a bit, removing extra calls and loops.  Removes
unchecked use of stack char array

Fixes https://gitlab.com/kicad/code/kicad/issues/10719

(cherry picked from commit 927afe313d)
This commit is contained in:
Seth Hillbrand 2022-02-02 17:15:01 -08:00
parent 08ee2671cc
commit 7ed569058c
1 changed files with 139 additions and 175 deletions

View File

@ -39,15 +39,15 @@
#define SCALE_LIST_SIZE 9 #define SCALE_LIST_SIZE 9
static double scale_list[SCALE_LIST_SIZE] = static double scale_list[SCALE_LIST_SIZE] =
{ {
1000.0 * IU_PER_MILS, // x.1 format (certainly useless) 1000.0 * GERB_IU_PER_MM * 0.0254, // x.1 format (certainly useless)
100.0 * IU_PER_MILS, // x.2 format (certainly useless) 100.0 * GERB_IU_PER_MM * 0.0254, // x.2 format (certainly useless)
10.0 * IU_PER_MILS, // x.3 format 10.0 * GERB_IU_PER_MM * 0.0254, // x.3 format
1.0 * IU_PER_MILS, // x.4 format 1.0 * GERB_IU_PER_MM * 0.0254, // x.4 format
0.1 * IU_PER_MILS, // x.5 format 0.1 * GERB_IU_PER_MM * 0.0254, // x.5 format
0.01 * IU_PER_MILS, // x.6 format 0.01 * GERB_IU_PER_MM * 0.0254, // x.6 format
0.001 * IU_PER_MILS, // x.7 format (currently the max allowed precision) 0.001 * GERB_IU_PER_MM * 0.0254, // x.7 format (currently the max allowed precision)
0.0001 * IU_PER_MILS, // provided, but not used 0.0001 * GERB_IU_PER_MM * 0.0254, // provided, but not used
0.00001 * IU_PER_MILS, // provided, but not used 0.00001 * GERB_IU_PER_MM * 0.0254, // provided, but not used
}; };
@ -60,129 +60,99 @@ int scaletoIU( double aCoord, bool isMetric )
int ret; int ret;
if( isMetric ) // gerber are units in mm if( isMetric ) // gerber are units in mm
ret = KiROUND( aCoord * IU_PER_MM ); ret = KiROUND( aCoord * GERB_IU_PER_MM );
else // gerber are units in inches else // gerber are units in inches
ret = KiROUND( aCoord * IU_PER_MILS * 1000.0 ); ret = KiROUND( aCoord * GERB_IU_PER_MM * 0.0254 );
return ret; return ret;
} }
VECTOR2I GERBER_FILE_IMAGE::ReadXYCoord( char*& Text, bool aExcellonMode ) VECTOR2I GERBER_FILE_IMAGE::ReadXYCoord( char*& aText, bool aExcellonMode )
{ {
VECTOR2I pos; VECTOR2I pos( 0, 0 );
int type_coord = 0, current_coord, nbdigits; bool is_float = false;
bool is_float = false;
char* text;
char line[256];
std::string line;
// Reserve the anticipated length plus an optional sign and decimal
line.reserve( std::max( m_FmtLen.x, m_FmtLen.y ) + 3 );
if( m_Relative ) if( m_Relative )
pos.x = pos.y = 0;
else
pos = m_CurrentPos; pos = m_CurrentPos;
if( Text == nullptr ) if( aText == nullptr )
return pos; return pos;
text = line; while( *aText && ( ( *aText == 'X' ) || ( *aText == 'Y' ) || ( *aText == 'A' ) ) )
while( *Text )
{ {
if( ( *Text == 'X' ) || ( *Text == 'Y' ) || ( *Text == 'A' ) ) double decimal_scale = 1.0;
int nbdigits = 0;
int current_coord = 0;
char type_coord = *aText++;
line.clear();
while( IsNumber( *aText ) )
{ {
type_coord = *Text; if( *aText == '.' ) // Force decimal format if reading a floating point number
Text++; is_float = true;
text = line;
nbdigits = 0;
while( IsNumber( *Text ) ) // count digits only (sign and decimal point are not counted)
{ if( (*aText >= '0') && (*aText <='9') )
if( *Text == '.' ) // Force decimal format if reading a floating point number nbdigits++;
is_float = true;
// count digits only (sign and decimal point are not counted) line.push_back( *( aText++ ) );
if( (*Text >= '0') && (*Text <='9') ) }
nbdigits++;
*(text++) = *(Text++); double val = strtod( line.data(), nullptr );
}
*text = 0; if( is_float )
{
if( is_float ) // When X or Y (or A) values are float numbers, they are given in mm or inches
{ if( m_GerbMetric ) // units are mm
// When X or Y (or A) values are float numbers, they are given in mm or inches current_coord = KiROUND( val * GERB_IU_PER_MM );
if( m_GerbMetric ) // units are mm else // units are inches
current_coord = KiROUND( atof( line ) * IU_PER_MILS / 0.0254 ); current_coord = KiROUND( val * GERB_IU_PER_MM * 0.0254 );
else // units are inches
current_coord = KiROUND( atof( line ) * IU_PER_MILS * 1000 );
}
else
{
int fmt_scale = (type_coord == 'X') ? m_FmtScale.x : m_FmtScale.y;
if( m_NoTrailingZeros )
{
// no trailing zero format, we need to add missing zeros.
int digit_count = (type_coord == 'X') ? m_FmtLen.x : m_FmtLen.y;
while( nbdigits < digit_count )
{
*(text++) = '0';
nbdigits++;
}
if( aExcellonMode )
{
// Truncate the extra digits if the len is more than expected
// because the conversion to internal units expect exactly
// digit_count digits
while( nbdigits > digit_count )
{
*(text--) = 0;
nbdigits--;
}
}
*text = 0;
}
current_coord = atoi( line );
double real_scale = scale_list[fmt_scale];
if( m_GerbMetric )
real_scale = real_scale / 25.4;
current_coord = KiROUND( current_coord * real_scale );
}
if( type_coord == 'X' )
{
pos.x = current_coord;
}
else if( type_coord == 'Y' )
{
pos.y = current_coord;
}
else if( type_coord == 'A' )
{
m_ArcRadius = current_coord;
m_LastArcDataType = ARC_INFO_TYPE_RADIUS;
}
continue;
} }
else else
{ {
break; int fmt_scale = (type_coord == 'X') ? m_FmtScale.x : m_FmtScale.y;
}
}
if( m_Relative ) if( m_NoTrailingZeros )
{ {
pos.x += m_CurrentPos.x; // no trailing zero format, we need to add missing zeros.
pos.y += m_CurrentPos.y; int digit_count = (type_coord == 'X') ? m_FmtLen.x : m_FmtLen.y;
// Truncate the extra digits if the len is more than expected
// because the conversion to internal units expect exactly
// digit_count digits. Alternatively, add some additional digits
// to pad out to the missing zeros
if( nbdigits < digit_count || ( aExcellonMode && ( nbdigits > digit_count ) ) )
decimal_scale = std::pow<double>( 10, digit_count - nbdigits );
}
double real_scale = scale_list[fmt_scale];
if( m_GerbMetric )
real_scale = real_scale / 25.4;
current_coord = KiROUND( val * real_scale * decimal_scale );
}
if( type_coord == 'X' )
{
pos.x += current_coord;
}
else if( type_coord == 'Y' )
{
pos.y += current_coord;
}
else if( type_coord == 'A' )
{
m_ArcRadius = current_coord;
m_LastArcDataType = ARC_INFO_TYPE_RADIUS;
}
} }
m_CurrentPos = pos; m_CurrentPos = pos;
@ -190,88 +160,82 @@ VECTOR2I GERBER_FILE_IMAGE::ReadXYCoord( char*& Text, bool aExcellonMode )
} }
VECTOR2I GERBER_FILE_IMAGE::ReadIJCoord( char*& Text ) VECTOR2I GERBER_FILE_IMAGE::ReadIJCoord( char*& aText )
{ {
VECTOR2I pos( 0, 0 ); VECTOR2I pos( 0, 0 );
int type_coord = 0, current_coord, nbdigits;
bool is_float = false; bool is_float = false;
char* text;
char line[256];
if( Text == nullptr ) std::string line;
// Reserve the anticipated length plus an optional sign and decimal
line.reserve( std::max( m_FmtLen.x, m_FmtLen.y ) + 3 );
if( aText == nullptr )
return pos; return pos;
text = line; while( *aText && ( ( *aText == 'I' ) || ( *aText == 'J' ) ) )
while( *Text )
{ {
if( ( *Text == 'I' ) || ( *Text == 'J' ) ) double decimal_scale = 1.0;
int nbdigits = 0;
int current_coord = 0;
char type_coord = *aText++;
line.clear();
while( IsNumber( *aText ) )
{ {
type_coord = *Text; if( *aText == '.' ) // Force decimal format if reading a floating point number
Text++; is_float = true;
text = line;
nbdigits = 0;
while( IsNumber( *Text ) ) // count digits only (sign and decimal point are not counted)
{ if( (*aText >= '0') && (*aText <='9') )
if( *Text == '.' ) nbdigits++;
is_float = true;
// count digits only (sign and decimal point are not counted) line.push_back( *( aText++ ) );
if( ( *Text >= '0' ) && ( *Text <= '9' ) ) }
nbdigits++;
*(text++) = *(Text++); double val = strtod( line.data(), nullptr );
}
*text = 0; if( is_float )
{
if( is_float ) // When X or Y (or A) values are float numbers, they are given in mm or inches
{ if( m_GerbMetric ) // units are mm
// When X or Y values are float numbers, they are given in mm or inches current_coord = KiROUND( val * GERB_IU_PER_MM );
if( m_GerbMetric ) // units are mm else // units are inches
current_coord = KiROUND( atof( line ) * IU_PER_MILS / 0.0254 ); current_coord = KiROUND( val * GERB_IU_PER_MM * 0.0254 );
else // units are inches
current_coord = KiROUND( atof( line ) * IU_PER_MILS * 1000 );
}
else
{
int fmt_scale = ( type_coord == 'I' ) ? m_FmtScale.x : m_FmtScale.y;
if( m_NoTrailingZeros )
{
int min_digit = ( type_coord == 'I' ) ? m_FmtLen.x : m_FmtLen.y;
while( nbdigits < min_digit )
{
*(text++) = '0';
nbdigits++;
}
*text = 0;
}
current_coord = atoi( line );
double real_scale = scale_list[fmt_scale];
if( m_GerbMetric )
real_scale = real_scale / 25.4;
current_coord = KiROUND( current_coord * real_scale );
}
if( type_coord == 'I' )
pos.x = current_coord;
else if( type_coord == 'J' )
pos.y = current_coord;
continue;
} }
else else
{ {
break; int fmt_scale = ( type_coord == 'I' ) ? m_FmtScale.x : m_FmtScale.y;
if( m_NoTrailingZeros )
{
// no trailing zero format, we need to add missing zeros.
int digit_count = ( type_coord == 'I' ) ? m_FmtLen.x : m_FmtLen.y;
// Truncate the extra digits if the len is more than expected
// because the conversion to internal units expect exactly
// digit_count digits. Alternatively, add some additional digits
// to pad out to the missing zeros
if( nbdigits < digit_count )
decimal_scale = std::pow<double>( 10, digit_count - nbdigits );
}
double real_scale = scale_list[fmt_scale];
if( m_GerbMetric )
real_scale = real_scale / 25.4;
current_coord = KiROUND( val * real_scale * decimal_scale );
}
if( type_coord == 'I' )
{
pos.x = current_coord;
}
else if( type_coord == 'J' )
{
pos.y = current_coord;
} }
} }