Gerber files: update unicode coding to the 2019 06 Gerber specifications.

In gbr files, not allowed chars are coded using a 16 bit (4 hexa digits)
unicode sequence.
Previously, it was \XXXX and now is \uXXXX escape sequence.

Changes from master branch.
This commit is contained in:
jean-pierre charras 2019-12-21 12:41:06 +01:00
parent 7f1c7d808d
commit 8c03d1bdde
2 changed files with 59 additions and 59 deletions

View File

@ -268,33 +268,78 @@ std::string GBR_APERTURE_METADATA::FormatAttribute( GBR_APERTURE_ATTRIB aAttribu
return full_attribute_string;
}
// Helper function to convert a ascii hex char to its integer value
// If the char is not a hexa char, return -1
int char2Hex( unsigned aCode )
{
if( aCode >= '0' && aCode <= '9' )
return aCode - '0';
if( aCode >= 'A' && aCode <= 'F' )
return aCode - 'A' + 10;
if( aCode >= 'a' && aCode <= 'f' )
return aCode - 'a' + 10;
return -1;
}
wxString FormatStringFromGerber( const wxString& aString )
{
// make the inverse conversion of formatStringToGerber()
// It converts a "normalized" gerber string and convert it to a 16 bits sequence unicode
// and return a wxString (unicode 16) from the gerber string
// Note the initial gerber string can already contain unicode chars.
wxString txt;
for( unsigned ii = 0; ii < aString.Length(); ++ii )
unsigned count = aString.Length();
for( unsigned ii = 0; ii < count; ++ii )
{
unsigned code = aString[ii];
if( code == '\\' )
if( code == '\\' && ii < count-5 && aString[ii+1] == 'u' )
{
// Convert 4 hexadecimal digits to a 16 bit unicode
// Note the latest Gerber X2 spec (2019 06) uses \uXXXX to encode
// the unicode XXXX hexadecimal value
// If 4 chars next to 'u' are hexadecimal chars,
// convert these 4 hexadecimal digits to a 16 bit unicode
// (Gerber allows only 4 hexadecimal digits)
// If an error occurs, the escape sequence is not translated,
// and used "as this"
long value = 0;
bool error = false;
for( int jj = 0; jj < 4; jj++ )
{
value <<= 4;
code = aString[++ii];
// Very basic conversion, but it expects a valid gerber file
int hexa = (code <= '9' ? code - '0' : code - 'A' + 10) & 0xF;
value += hexa;
code = aString[ii+jj+2];
int hexa = char2Hex( code );
if( hexa >= 0 )
value += hexa;
else
{
error = true;
break;
}
}
txt.Append( wxChar( value ) );
if( !error )
{
if( value >= ' ' ) // Is a valid wxChar ?
txt.Append( wxChar( value ) );
ii += 5;
}
else
{
txt.Append( aString[ii] );
continue;
}
}
else
txt.Append( aString[ii] );
@ -334,12 +379,10 @@ std::string formatStringToGerber( const wxString& aString )
if( convert || code > 0x7F )
{
txt += '\\';
// Convert code to 4 hexadecimal digit
// (Gerber allows only 4 hexadecimal digit)
char hexa[32];
sprintf( hexa,"%4.4X", code & 0xFFFF);
sprintf( hexa,"\\u%4.4X", code & 0xFFFF);
txt += hexa;
}
else

View File

@ -34,6 +34,7 @@
#include <gerbview.h>
#include <gerber_file_image.h>
#include <X2_gerber_attributes.h>
#include <gbr_metadata.h>
extern int ReadInt( char*& text, bool aSkipSeparator = true );
extern double ReadDouble( char*& text, bool aSkipSeparator = true );
@ -138,50 +139,6 @@ int GERBER_FILE_IMAGE::ReadXCommandID( char*& text )
return result;
}
/**
* Convert a string read from a gerber file to an unicode string
* Usual chars (ASCII7 values) are the only values allowed in Gerber files,
* and are just copied.
* However Gerber format allows using non ASCII7 values by coding them in a
* sequence of 4 hexadecimal chars (16 bits hexadecimal value)
* Hexadecimal coded values ("\hhhh") are converted to
* the unicode char value
*/
static const wxString fromGerberString( const wxString& aGbrString )
{
wxString text;
for( unsigned ii = 0; ii < aGbrString.size(); ++ii )
{
if( aGbrString[ii] == '\\' )
{
unsigned value = 0;
for( int jj = 0; jj < 4; jj++ )
{ // Convert 4 hexa digits to binary value:
ii++;
value <<= 4;
int digit = aGbrString[ii];
if( digit >= '0' && digit <= '9' )
digit -= '0';
else if( digit >= 'A' && digit <= 'F' )
digit -= 'A' - 10;
else if( digit >= 'a' && digit <= 'f' )
digit -= 'a' - 10;
else digit = 0;
value += digit & 0xF;
}
text.Append( wxUniChar( value ) );
}
else
text.Append( aGbrString[ii] );
}
return text;
}
bool GERBER_FILE_IMAGE::ReadRS274XCommand( char *aBuff, unsigned int aBuffSize, char*& aText )
{
@ -451,18 +408,18 @@ bool GERBER_FILE_IMAGE::ExecuteRS274XCommand( int aCommand, char* aBuff,
if( dummy.GetAttribute() == ".N" )
{
m_NetAttributeDict.m_NetAttribType |= GBR_NETLIST_METADATA::GBR_NETINFO_NET;
m_NetAttributeDict.m_Netname = fromGerberString( dummy.GetPrm( 1 ) );
m_NetAttributeDict.m_Netname = FormatStringFromGerber( dummy.GetPrm( 1 ) );
}
else if( dummy.GetAttribute() == ".C" )
{
m_NetAttributeDict.m_NetAttribType |= GBR_NETLIST_METADATA::GBR_NETINFO_CMP;
m_NetAttributeDict.m_Cmpref = fromGerberString( dummy.GetPrm( 1 ) );
m_NetAttributeDict.m_Cmpref = FormatStringFromGerber( dummy.GetPrm( 1 ) );
}
else if( dummy.GetAttribute() == ".P" )
{
m_NetAttributeDict.m_NetAttribType |= GBR_NETLIST_METADATA::GBR_NETINFO_PAD;
m_NetAttributeDict.m_Cmpref = fromGerberString( dummy.GetPrm( 1 ) );
m_NetAttributeDict.m_Padname = fromGerberString( dummy.GetPrm( 2 ) );
m_NetAttributeDict.m_Cmpref = FormatStringFromGerber( dummy.GetPrm( 1 ) );
m_NetAttributeDict.m_Padname = FormatStringFromGerber( dummy.GetPrm( 2 ) );
}
}
break;