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; 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 ) wxString FormatStringFromGerber( const wxString& aString )
{ {
// make the inverse conversion of formatStringToGerber() // make the inverse conversion of formatStringToGerber()
// It converts a "normalized" gerber string and convert it to a 16 bits sequence unicode // 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 // and return a wxString (unicode 16) from the gerber string
// Note the initial gerber string can already contain unicode chars.
wxString txt; 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]; 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) // (Gerber allows only 4 hexadecimal digits)
// If an error occurs, the escape sequence is not translated,
// and used "as this"
long value = 0; long value = 0;
bool error = false;
for( int jj = 0; jj < 4; jj++ ) for( int jj = 0; jj < 4; jj++ )
{ {
value <<= 4; value <<= 4;
code = aString[++ii]; code = aString[ii+jj+2];
// Very basic conversion, but it expects a valid gerber file
int hexa = (code <= '9' ? code - '0' : code - 'A' + 10) & 0xF; int hexa = char2Hex( code );
if( hexa >= 0 )
value += hexa; value += hexa;
else
{
error = true;
break;
}
} }
if( !error )
{
if( value >= ' ' ) // Is a valid wxChar ?
txt.Append( wxChar( value ) ); txt.Append( wxChar( value ) );
ii += 5;
}
else
{
txt.Append( aString[ii] );
continue;
}
} }
else else
txt.Append( aString[ii] ); txt.Append( aString[ii] );
@ -334,12 +379,10 @@ std::string formatStringToGerber( const wxString& aString )
if( convert || code > 0x7F ) if( convert || code > 0x7F )
{ {
txt += '\\';
// Convert code to 4 hexadecimal digit // Convert code to 4 hexadecimal digit
// (Gerber allows only 4 hexadecimal digit) // (Gerber allows only 4 hexadecimal digit)
char hexa[32]; char hexa[32];
sprintf( hexa,"%4.4X", code & 0xFFFF); sprintf( hexa,"\\u%4.4X", code & 0xFFFF);
txt += hexa; txt += hexa;
} }
else else

View File

@ -34,6 +34,7 @@
#include <gerbview.h> #include <gerbview.h>
#include <gerber_file_image.h> #include <gerber_file_image.h>
#include <X2_gerber_attributes.h> #include <X2_gerber_attributes.h>
#include <gbr_metadata.h>
extern int ReadInt( char*& text, bool aSkipSeparator = true ); extern int ReadInt( char*& text, bool aSkipSeparator = true );
extern double ReadDouble( 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; 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 ) 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" ) if( dummy.GetAttribute() == ".N" )
{ {
m_NetAttributeDict.m_NetAttribType |= GBR_NETLIST_METADATA::GBR_NETINFO_NET; 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" ) else if( dummy.GetAttribute() == ".C" )
{ {
m_NetAttributeDict.m_NetAttribType |= GBR_NETLIST_METADATA::GBR_NETINFO_CMP; 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" ) else if( dummy.GetAttribute() == ".P" )
{ {
m_NetAttributeDict.m_NetAttribType |= GBR_NETLIST_METADATA::GBR_NETINFO_PAD; m_NetAttributeDict.m_NetAttribType |= GBR_NETLIST_METADATA::GBR_NETINFO_PAD;
m_NetAttributeDict.m_Cmpref = fromGerberString( dummy.GetPrm( 1 ) ); m_NetAttributeDict.m_Cmpref = FormatStringFromGerber( dummy.GetPrm( 1 ) );
m_NetAttributeDict.m_Padname = fromGerberString( dummy.GetPrm( 2 ) ); m_NetAttributeDict.m_Padname = FormatStringFromGerber( dummy.GetPrm( 2 ) );
} }
} }
break; break;