Fix some issues in .gbrjob file.

2 issues are fixed: a missing double quote, and a incorrect handling of unicode chars

Fixes: lp:1836448
https://bugs.launchpad.net/kicad/+bug/1836448
This commit is contained in:
jean-pierre charras 2019-07-14 10:19:53 +02:00
parent be5f3717c7
commit fc2379ca8a
4 changed files with 69 additions and 27 deletions

View File

@ -1,8 +1,8 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2007-2017 Jean-Pierre Charras jp.charras at wanadoo.fr * Copyright (C) 2007-2019 Jean-Pierre Charras jp.charras at wanadoo.fr
* Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -89,6 +89,11 @@ private:
REPORTER* m_reporter; REPORTER* m_reporter;
wxFileName m_filename; wxFileName m_filename;
wxArrayString m_GerberFiles; // List of gerber files in job wxArrayString m_GerberFiles; // List of gerber files in job
// Convert a JSON string, that uses escaped sequence of 4 hexdecimal digits
// to encode unicode chars when not ASCII7 codes
// json11 converts this sequence to UTF8 string
wxString formatStringFromJSON( const std::string& name );
}; };
@ -133,10 +138,8 @@ bool GERBER_JOBFILE_READER::ReadGerberJobFile()
for( auto& entry : json_parser["FilesAttributes"].array_items() ) for( auto& entry : json_parser["FilesAttributes"].array_items() )
{ {
//wxLogMessage( entry.dump().c_str() );
std::string name = entry["Path"].string_value(); std::string name = entry["Path"].string_value();
//wxLogMessage( name.c_str() ); m_GerberFiles.Add( formatStringFromJSON( name ) );
m_GerberFiles.Add( FormatStringFromGerber( name ) );
} }
} }
else else
@ -152,6 +155,18 @@ bool GERBER_JOBFILE_READER::ReadGerberJobFile()
} }
wxString GERBER_JOBFILE_READER::formatStringFromJSON( const std::string& name )
{
// Convert a JSON string, that uses a escaped sequence of 4 hexdecimal digits
// to encode unicode chars
// Our json11 library returns in this case a UTF8 sequence. Just convert it to
// a wxString.
wxString wstr = FROM_UTF8( name.c_str() );
return wstr;
}
bool GERBVIEW_FRAME::LoadGerberJobFile( const wxString& aFullFileName ) bool GERBVIEW_FRAME::LoadGerberJobFile( const wxString& aFullFileName )
{ {
wxFileName filename = aFullFileName; wxFileName filename = aFullFileName;
@ -221,5 +236,3 @@ bool GERBVIEW_FRAME::LoadGerberJobFile( const wxString& aFullFileName )
return success; return success;
} }

View File

@ -25,6 +25,7 @@
#include <layers_id_colors_and_visibility.h> #include <layers_id_colors_and_visibility.h>
#include <board_design_settings.h> #include <board_design_settings.h>
#include <class_board.h> #include <class_board.h>
#include <i18n_utility.h> // For _HKI definition
#include "stackup_predefined_prms.h" #include "stackup_predefined_prms.h"
// A reasonable thickness for copper layers: // A reasonable thickness for copper layers:
@ -310,6 +311,9 @@ bool BOARD_STACKUP::SynchronizeWithBoard( BOARD_DESIGN_SETTINGS* aSettings )
void BOARD_STACKUP::BuildDefaultStackupList( BOARD_DESIGN_SETTINGS* aSettings ) void BOARD_STACKUP::BuildDefaultStackupList( BOARD_DESIGN_SETTINGS* aSettings )
{ {
// Creates a default stackup, according to the current BOARD_DESIGN_SETTINGS settings. // Creates a default stackup, according to the current BOARD_DESIGN_SETTINGS settings.
// Note: the m_TypeName string is made translatable using _HKI marker, but is not
// translated when building the stackup.
// It will be used as this in files, and can be translated only in dialog
LSET enabledLayer = aSettings->GetEnabledLayers(); LSET enabledLayer = aSettings->GetEnabledLayers();
int copperLayerCount = aSettings->GetCopperLayerCount(); int copperLayerCount = aSettings->GetCopperLayerCount();
double diel_thickness = aSettings->GetBoardThickness() double diel_thickness = aSettings->GetBoardThickness()
@ -323,7 +327,7 @@ void BOARD_STACKUP::BuildDefaultStackupList( BOARD_DESIGN_SETTINGS* aSettings )
{ {
BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SILKSCREEN ); BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SILKSCREEN );
item->m_LayerId = F_SilkS; item->m_LayerId = F_SilkS;
item->m_TypeName = _( "Top Silk Screen" ); item->m_TypeName = _HKI( "Top Silk Screen" );
Add( item ); Add( item );
} }
@ -331,7 +335,7 @@ void BOARD_STACKUP::BuildDefaultStackupList( BOARD_DESIGN_SETTINGS* aSettings )
{ {
BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SOLDERPASTE ); BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SOLDERPASTE );
item->m_LayerId = F_Paste; item->m_LayerId = F_Paste;
item->m_TypeName = _( "Top Solder Paste" ); item->m_TypeName = _HKI( "Top Solder Paste" );
Add( item ); Add( item );
} }
@ -339,7 +343,7 @@ void BOARD_STACKUP::BuildDefaultStackupList( BOARD_DESIGN_SETTINGS* aSettings )
{ {
BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SOLDERMASK ); BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SOLDERMASK );
item->m_LayerId = F_Mask; item->m_LayerId = F_Mask;
item->m_TypeName = _( "Top Solder Mask" ); item->m_TypeName = _HKI( "Top Solder Mask" );
Add( item ); Add( item );
} }
@ -364,12 +368,12 @@ void BOARD_STACKUP::BuildDefaultStackupList( BOARD_DESIGN_SETTINGS* aSettings )
// Display a dielectric default layer name: // Display a dielectric default layer name:
if( (dielectric_idx & 1) == 0 ) if( (dielectric_idx & 1) == 0 )
{ {
item->m_TypeName = _( "core" ); item->m_TypeName = _HKI( "core" );
item->m_Material = "FR4"; item->m_Material = "FR4";
} }
else else
{ {
item->m_TypeName = _( "prepreg" ); item->m_TypeName = _HKI( "prepreg" );
item->m_Material = "FR4"; item->m_Material = "FR4";
} }
@ -382,7 +386,7 @@ void BOARD_STACKUP::BuildDefaultStackupList( BOARD_DESIGN_SETTINGS* aSettings )
{ {
BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SOLDERMASK ); BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SOLDERMASK );
item->m_LayerId = B_Mask; item->m_LayerId = B_Mask;
item->m_TypeName = _( "Bottom Solder Mask" ); item->m_TypeName = _HKI( "Bottom Solder Mask" );
Add( item ); Add( item );
} }
@ -390,7 +394,7 @@ void BOARD_STACKUP::BuildDefaultStackupList( BOARD_DESIGN_SETTINGS* aSettings )
{ {
BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SOLDERPASTE ); BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SOLDERPASTE );
item->m_LayerId = B_Paste; item->m_LayerId = B_Paste;
item->m_TypeName = _( "Bottom Solder Paste" ); item->m_TypeName = _HKI( "Bottom Solder Paste" );
Add( item ); Add( item );
} }
@ -398,7 +402,7 @@ void BOARD_STACKUP::BuildDefaultStackupList( BOARD_DESIGN_SETTINGS* aSettings )
{ {
BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SILKSCREEN ); BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SILKSCREEN );
item->m_LayerId = B_SilkS; item->m_LayerId = B_SilkS;
item->m_TypeName = _( "Bottom Silk Screen" ); item->m_TypeName = _HKI( "Bottom Silk Screen" );
Add( item ); Add( item );
} }

View File

@ -56,6 +56,25 @@ GERBER_JOBFILE_WRITER::GERBER_JOBFILE_WRITER( BOARD* aPcb, REPORTER* aReporter )
m_indent = 0; m_indent = 0;
} }
std::string GERBER_JOBFILE_WRITER::formatStringFromUTF32( const wxString& aText )
{
std::string fmt_text; // the text after UTF32 to UTF8 conversion
for( unsigned long letter: aText )
{
if( letter >= ' ' && letter <= 0x7F )
fmt_text += char( letter );
else
{
char buff[10];
sprintf( buff, "\\u%4.4lX", letter );
fmt_text += buff;
}
}
return fmt_text;
}
enum ONSIDE GERBER_JOBFILE_WRITER::hasSilkLayers() enum ONSIDE GERBER_JOBFILE_WRITER::hasSilkLayers()
{ {
int flag = SIDE_NONE; int flag = SIDE_NONE;
@ -249,7 +268,7 @@ void GERBER_JOBFILE_WRITER::addJSONGeneralSpecs()
wxString guid = GbrMakeProjectGUIDfromString( msg ); wxString guid = GbrMakeProjectGUIDfromString( msg );
// build the <project id> string: this is the board short filename (without ext) // build the <project id> string: this is the board short filename (without ext)
// and all non ASCII chars are replaced by '_' // and all non ASCII chars are replaced by '_', to be compatible with .gbr files.
msg = fn.GetName(); msg = fn.GetName();
// build the <rec> string. All non ASCII chars and comma are replaced by '_' // build the <rec> string. All non ASCII chars and comma are replaced by '_'
@ -421,9 +440,8 @@ void GERBER_JOBFILE_WRITER::addJSONFilesAttributes()
if( !skip_file ) if( !skip_file )
{ {
// name can contain non ASCII7 chars. // name can contain non ASCII7 chars.
// Only ASCII7 chars are accepted in gerber files. others must be converted to // Ensure the name is JSON compatible.
// a gerber hexa sequence. std::string strname = formatStringFromUTF32( name );
std::string strname = formatStringToGerber( name );
openBlock(); openBlock();
addJSONObject( wxString::Format( "\"Path\": \"%s\",\n", strname.c_str() ) ); addJSONObject( wxString::Format( "\"Path\": \"%s\",\n", strname.c_str() ) );
@ -604,28 +622,28 @@ void GERBER_JOBFILE_WRITER::addJSONMaterialStackup()
{ {
case BS_ITEM_TYPE_COPPER: case BS_ITEM_TYPE_COPPER:
layer_type = "Copper"; layer_type = "Copper";
layer_name = formatStringToGerber( m_pcb->GetLayerName( item->m_LayerId ) ); layer_name = formatStringFromUTF32( m_pcb->GetLayerName( item->m_LayerId ) );
last_copper_layer = item->m_LayerId; last_copper_layer = item->m_LayerId;
break; break;
case BS_ITEM_TYPE_SILKSCREEN: case BS_ITEM_TYPE_SILKSCREEN:
layer_type = "Legend"; layer_type = "Legend";
layer_name = formatStringToGerber( item->m_TypeName ); layer_name = formatStringFromUTF32( item->m_TypeName );
break; break;
case BS_ITEM_TYPE_SOLDERMASK: case BS_ITEM_TYPE_SOLDERMASK:
layer_type = "SolderMask"; layer_type = "SolderMask";
layer_name = formatStringToGerber( item->m_TypeName ); layer_name = formatStringFromUTF32( item->m_TypeName );
break; break;
case BS_ITEM_TYPE_SOLDERPASTE: case BS_ITEM_TYPE_SOLDERPASTE:
layer_type = "SolderPaste"; layer_type = "SolderPaste";
layer_name = formatStringToGerber( item->m_TypeName ); layer_name = formatStringFromUTF32( item->m_TypeName );
break; break;
case BS_ITEM_TYPE_DIELECTRIC: case BS_ITEM_TYPE_DIELECTRIC:
layer_type = "Dielectric"; layer_type = "Dielectric";
layer_name = formatStringToGerber( wxString::Format( "dielectric layer %d (%s)", layer_name = formatStringFromUTF32( wxString::Format( "dielectric layer %d (%s)",
item->m_DielectricLayerId, item->m_TypeName ) ); item->m_DielectricLayerId, item->m_TypeName ) );
break; break;
@ -670,14 +688,16 @@ void GERBER_JOBFILE_WRITER::addJSONMaterialStackup()
if( uptodate ) // We can add the dielectric variant ("core" "prepreg" ...): if( uptodate ) // We can add the dielectric variant ("core" "prepreg" ...):
note << wxString::Format( " \"Type: %s", layer_name.c_str() ); note << wxString::Format( " \"Type: %s", layer_name.c_str() );
note << wxString::Format( " (from %s to %s)\"\n", note << wxString::Format( " \"(from %s to %s)\"\n",
formatStringToGerber( m_pcb->GetLayerName( last_copper_layer ) ), formatStringFromUTF32( m_pcb->GetLayerName( last_copper_layer ) ),
formatStringToGerber( m_pcb->GetLayerName( next_copper_layer ) ) ); formatStringFromUTF32( m_pcb->GetLayerName( next_copper_layer ) ) );
addJSONObject( note ); addJSONObject( note );
} }
else else
{
addJSONObject( wxString::Format( "\"Notes\": \"Layer: %s\",\n", layer_name.c_str() ) ); addJSONObject( wxString::Format( "\"Notes\": \"Layer: %s\",\n", layer_name.c_str() ) );
}
removeJSONSepararator(); removeJSONSepararator();
closeBlockWithSep(); closeBlockWithSep();

View File

@ -202,6 +202,11 @@ private:
addIndent(); m_JSONbuffer << aParam; addIndent(); m_JSONbuffer << aParam;
} }
/** A helper function to convert a wxString ( therefore a Unicode text ) to
* a JSON compatible string (a escaped unicode sequence of 4 hexa).
*/
std::string formatStringFromUTF32( const wxString& aText );
private: private:
BOARD* m_pcb; // The board BOARD* m_pcb; // The board
REPORTER* m_reporter; // a reporter for messages (can be null) REPORTER* m_reporter; // a reporter for messages (can be null)