From 5b3202d8f38bde3f9eb6a08322f0aa5aeacfb876 Mon Sep 17 00:00:00 2001
From: jean-pierre charras <jp.charras@wanadoo.fr>
Date: Fri, 7 Dec 2018 10:07:43 +0100
Subject: [PATCH] dxf and svg import: accept unicode filenames

Fixes: lp:1805613
https://bugs.launchpad.net/kicad/+bug/1805613
---
 dxflib_qcad/dl_dxf.cpp                  | 32 +++++++++++++++++++++++++
 dxflib_qcad/dl_dxf.h                    |  7 +++---
 pcbnew/import_gfx/dxf_import_plugin.cpp | 14 +++++++----
 pcbnew/import_gfx/nanosvg.cpp           |  8 ++-----
 pcbnew/import_gfx/nanosvg.h             |  5 +++-
 pcbnew/import_gfx/svg_import_plugin.cpp |  9 ++++++-
 6 files changed, 58 insertions(+), 17 deletions(-)

diff --git a/dxflib_qcad/dl_dxf.cpp b/dxflib_qcad/dl_dxf.cpp
index 4f43db9a2b..a76cf1611f 100644
--- a/dxflib_qcad/dl_dxf.cpp
+++ b/dxflib_qcad/dl_dxf.cpp
@@ -117,12 +117,44 @@ DL_Dxf::~DL_Dxf()
 }
 
 
+/**
+ * @brief Reads the given file and calls the appropriate functions in
+ * the given creation interface for every entity found in the file.
+ *
+ * @param file Input the file pointer to read
+ * @param creationInterface
+ *      Pointer to the class which takes care of the entities in the file.
+ *
+ * @retval true if fp is valid (i.e. not NULL), false otherwise.
+ */
+bool DL_Dxf::in( FILE* fp, DL_CreationInterface* creationInterface )
+{
+    firstCall = true;
+    currentObjectType = DL_UNKNOWN;
+
+    if( fp )
+    {
+        std::locale oldLocale = std::locale::global( std::locale( "C" ) );    // use dot in numbers
+
+        while( readDxfGroups( fp, creationInterface ) )
+        {
+        }
+
+        std::locale::global( oldLocale );
+        fclose( fp );
+        return true;
+    }
+
+    return false;
+}
+
 /**
  * @brief Reads the given file and calls the appropriate functions in
  * the given creation interface for every entity found in the file.
  *
  * @param file Input
  *      Path and name of file to read
+ * Note: file is not very well utf8 compatible, depending on the platform.
  * @param creationInterface
  *      Pointer to the class which takes care of the entities in the file.
  *
diff --git a/dxflib_qcad/dl_dxf.h b/dxflib_qcad/dl_dxf.h
index 16aa90eca4..fd0bfa9ebe 100644
--- a/dxflib_qcad/dl_dxf.h
+++ b/dxflib_qcad/dl_dxf.h
@@ -124,10 +124,9 @@ public:
     DL_Dxf();
     ~DL_Dxf();
 
-    bool in( const std::string& file,
-            DL_CreationInterface* creationInterface );
-    bool readDxfGroups( FILE* fp,
-            DL_CreationInterface* creationInterface );
+    bool in( FILE* fp, DL_CreationInterface* creationInterface );
+    bool in( const std::string& file, DL_CreationInterface* creationInterface );
+    bool readDxfGroups( FILE* fp, DL_CreationInterface* creationInterface );
     static bool getStrippedLine( std::string& s, unsigned int size,
             FILE* stream, bool stripSpace = true );
 
diff --git a/pcbnew/import_gfx/dxf_import_plugin.cpp b/pcbnew/import_gfx/dxf_import_plugin.cpp
index 086f4f1de5..776a03883b 100644
--- a/pcbnew/import_gfx/dxf_import_plugin.cpp
+++ b/pcbnew/import_gfx/dxf_import_plugin.cpp
@@ -133,14 +133,18 @@ double DXF_IMPORT_PLUGIN::mapWidth( double aDxfWidth )
 
 bool DXF_IMPORT_PLUGIN::ImportDxfFile( const wxString& aFile )
 {
-    LOCALE_IO locale;
-
     DL_Dxf dxf_reader;
     std::string filename = TO_UTF8( aFile );
-    bool success = true;
 
-    if( !dxf_reader.in( filename, this ) )  // if file open failed
-        success = false;
+    // wxFopen takes care of unicode filenames across platforms
+    FILE* fp = wxFopen( aFile, "rt" );
+
+    if( fp == nullptr )
+        return false;
+
+    // Note the dxf reader takes care of switching to "C" locale before reading the file
+    // and will close the file after reading
+    bool success = dxf_reader.in( fp, this );
 
     return success;
 }
diff --git a/pcbnew/import_gfx/nanosvg.cpp b/pcbnew/import_gfx/nanosvg.cpp
index 55a490e2cd..438467bf4e 100644
--- a/pcbnew/import_gfx/nanosvg.cpp
+++ b/pcbnew/import_gfx/nanosvg.cpp
@@ -28,7 +28,6 @@
 
 #include "nanosvg.h"
 
-#include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <math.h>
@@ -3668,17 +3667,14 @@ NSVGimage* nsvgParse( char* input, const char* units, float dpi )
 }
 
 
-NSVGimage* nsvgParseFromFile( const char* filename, const char* units, float dpi )
+NSVGimage* nsvgParseFromFile( FILE *fp, const char* units, float dpi )
 {
-    FILE* fp = NULL;
     size_t  size;
     char*   data = NULL;
     NSVGimage* image = NULL;
 
-    fp = fopen( filename, "rb" );
-
     if( !fp )
-        goto error;
+        return NULL;
 
     fseek( fp, 0, SEEK_END );
     size = ftell( fp );
diff --git a/pcbnew/import_gfx/nanosvg.h b/pcbnew/import_gfx/nanosvg.h
index c4ed0617a2..04f05f9342 100644
--- a/pcbnew/import_gfx/nanosvg.h
+++ b/pcbnew/import_gfx/nanosvg.h
@@ -66,6 +66,8 @@
 	nsvgDelete(image);
 */
 
+#include <stdio.h>
+
 enum NSVGpaintType {
 	NSVG_PAINT_NONE = 0,
 	NSVG_PAINT_COLOR = 1,
@@ -158,7 +160,8 @@ typedef struct NSVGimage
 } NSVGimage;
 
 // Parses SVG file from a file, returns SVG image as paths.
-NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi);
+// fp will be closed after reading the file
+NSVGimage* nsvgParseFromFile( FILE* fp, const char* units, float dpi);
 
 // Parses SVG file from a null terminated string, returns SVG image as paths.
 // Important note: changes the string.
diff --git a/pcbnew/import_gfx/svg_import_plugin.cpp b/pcbnew/import_gfx/svg_import_plugin.cpp
index 13d4630f61..2d73e6a0dc 100644
--- a/pcbnew/import_gfx/svg_import_plugin.cpp
+++ b/pcbnew/import_gfx/svg_import_plugin.cpp
@@ -55,7 +55,14 @@ bool SVG_IMPORT_PLUGIN::Load( const wxString& aFileName )
 {
     wxCHECK( m_importer, false );
 
-    m_parsedImage = nsvgParseFromFile( aFileName.c_str(), "mm", 96 );
+    // wxFopen takes care of unicode filenames across platforms
+    FILE* fp = wxFopen( aFileName, "rt" );
+
+    if( fp == nullptr )
+        return false;
+
+    // nsvgParseFromFile will close the file after reading
+    m_parsedImage = nsvgParseFromFile( fp, "mm", 96 );
 
     wxCHECK( m_parsedImage, false );