← Back to team overview

kicad-developers team mailing list archive

PATCH: workaround for non-ASCII filenames in 3D files in MinGW

 

The attached patch fixes load/save issues for 3D files with
non-ascii characters in the filename. The problem is specific
to Windows builds and does not affect any of the UNIX-like
platforms. This patch does not fix the corresponding issues
with OCE/OpenCascade since that specific problem must
be fixed in the OCE code.

Regarding OCE, since we build it anyway to ensure binary
compatibility, I'm happy to maintain our own patch set to
fix this issue.  The question is whether to work on OCE0.18
(OCCT6.9) which doesn't currently build in MinGW and would
thus require extra work, or to work with OCE0.17 (OCCT6.8)
which we currently use and builds with no modifications.

- Cirilo
From 2649676641fba5633adcd4609901440803ff21f4 Mon Sep 17 00:00:00 2001
From: Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
Date: Fri, 3 Mar 2017 09:53:49 +1100
Subject: [PATCH] Workaround for non-ASCII filenames in Windows

---
 3d-viewer/3d_cache/sg/CMakeLists.txt    |  10 ++-
 3d-viewer/3d_cache/sg/ifsg_api.cpp      |  56 ++++---------
 3d-viewer/3d_cache/sg/scenegraph.cpp    |   6 +-
 3d-viewer/3d_cache/sg/scenegraph.h      |   6 +-
 3d-viewer/3d_cache/sg/sg_appearance.cpp |   8 +-
 3d-viewer/3d_cache/sg/sg_appearance.h   |   8 +-
 3d-viewer/3d_cache/sg/sg_colors.cpp     |   8 +-
 3d-viewer/3d_cache/sg/sg_colors.h       |   8 +-
 3d-viewer/3d_cache/sg/sg_coords.cpp     |   8 +-
 3d-viewer/3d_cache/sg/sg_coords.h       |   8 +-
 3d-viewer/3d_cache/sg/sg_faceset.cpp    |   8 +-
 3d-viewer/3d_cache/sg/sg_faceset.h      |   8 +-
 3d-viewer/3d_cache/sg/sg_helpers.cpp    |  16 ++--
 3d-viewer/3d_cache/sg/sg_helpers.h      |  18 ++--
 3d-viewer/3d_cache/sg/sg_index.cpp      |  15 ++--
 3d-viewer/3d_cache/sg/sg_index.h        |  14 ++--
 3d-viewer/3d_cache/sg/sg_node.h         |  10 +--
 3d-viewer/3d_cache/sg/sg_normals.cpp    |   8 +-
 3d-viewer/3d_cache/sg/sg_normals.h      |   8 +-
 3d-viewer/3d_cache/sg/sg_shape.cpp      |   9 +-
 3d-viewer/3d_cache/sg/sg_shape.h        |   8 +-
 common/streamwrapper.cpp                | 121 +++++++++++++++++++++++++++
 include/streamwrapper.h                 | 101 ++++++++++++++++++++++
 pcbnew/exporters/export_vrml.cpp        | 105 ++++++++++++-----------
 plugins/3d/idf/s3d_plugin_idf.cpp       |   4 +-
 plugins/3d/vrml/wrlfacet.cpp            |   4 +-
 utils/idftools/CMakeLists.txt           |  21 +++--
 utils/idftools/idf2vrml.cpp             |  48 +++++------
 utils/idftools/idf_common.cpp           |  11 ++-
 utils/idftools/idf_common.h             |  10 +--
 utils/idftools/idf_helpers.cpp          |   6 +-
 utils/idftools/idf_helpers.h            |   8 +-
 utils/idftools/idf_outlines.cpp         |  40 ++++-----
 utils/idftools/idf_outlines.h           |  42 +++++-----
 utils/idftools/idf_parser.cpp           | 144 +++++++++++++++++---------------
 utils/idftools/idf_parser.h             |  25 +++---
 utils/idftools/vrml_layer.cpp           |  20 ++---
 utils/idftools/vrml_layer.h             |  14 ++--
 38 files changed, 601 insertions(+), 371 deletions(-)
 create mode 100644 common/streamwrapper.cpp
 create mode 100644 include/streamwrapper.h

diff --git a/3d-viewer/3d_cache/sg/CMakeLists.txt b/3d-viewer/3d_cache/sg/CMakeLists.txt
index 244384dc6..f610347d6 100644
--- a/3d-viewer/3d_cache/sg/CMakeLists.txt
+++ b/3d-viewer/3d_cache/sg/CMakeLists.txt
@@ -1,9 +1,9 @@
 include_directories(
     ${CMAKE_SOURCE_DIR}/include
     ${CMAKE_SOURCE_DIR}/3d-viewer
-  )
+)
 
-add_library( kicad_3dsg SHARED
+set( SG_FILES
     sg_base.cpp
     sg_node.cpp
     sg_helpers.cpp
@@ -29,6 +29,12 @@ add_library( kicad_3dsg SHARED
     ifsg_api.cpp
 )
 
+if( MINGW )
+    list( APPEND SG_FILES ${CMAKE_SOURCE_DIR}/common/streamwrapper.cpp )
+endif( MINGW )
+
+add_library( kicad_3dsg SHARED ${SG_FILES} )
+
 if( APPLE )
     # puts library into the main kicad.app bundle in build tree
     set_target_properties( kicad_3dsg PROPERTIES
diff --git a/3d-viewer/3d_cache/sg/ifsg_api.cpp b/3d-viewer/3d_cache/sg/ifsg_api.cpp
index b440e7c4f..faab0d7a0 100644
--- a/3d-viewer/3d_cache/sg/ifsg_api.cpp
+++ b/3d-viewer/3d_cache/sg/ifsg_api.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -28,6 +28,7 @@
 #include <wx/log.h>
 #include "plugins/3dapi/ifsg_api.h"
 #include "plugins/3dapi/sg_version.h"
+#include "streamwrapper.h"
 #include "3d_cache/sg/sg_node.h"
 #include "3d_cache/sg/scenegraph.h"
 #include "3d_cache/sg/sg_appearance.h"
@@ -77,24 +78,6 @@ static void formatMaterial( SMATERIAL& mat, SGAPPEARANCE const* app )
 }
 
 
-class VRML_LOCALE
-{
-private:
-    std::string lname;
-
-public:
-    VRML_LOCALE() : lname( setlocale( LC_NUMERIC, NULL ) )
-    {
-        setlocale( LC_NUMERIC, "C" );   // switch the numerics locale to "C"
-    }
-
-    ~VRML_LOCALE()
-    {
-        setlocale( LC_NUMERIC, lname.c_str() ); // revert to the previous locale
-    }
-};
-
-
 bool S3D::WriteVRML( const char* filename, bool overwrite, SGNODE* aTopNode,
     bool reuse, bool renameNodes )
 {
@@ -141,12 +124,9 @@ bool S3D::WriteVRML( const char* filename, bool overwrite, SGNODE* aTopNode,
         return false;
     }
 
-    VRML_LOCALE vrmlLocale;
-    std::ofstream op;
-    op.open( filename, std::ios_base::out | std::ios_base::trunc
-                                 | std::ios_base::binary );
+    OPEN_OSTREAM( op, filename );
 
-    if( !op.is_open() )
+    if( op.fail() )
     {
         std::ostringstream ostr;
         ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
@@ -156,6 +136,7 @@ bool S3D::WriteVRML( const char* filename, bool overwrite, SGNODE* aTopNode,
         return false;
     }
 
+    op.imbue( std::locale( "C" ) );
     op << "#VRML V2.0 utf8\n";
 
     if( renameNodes )
@@ -168,11 +149,11 @@ bool S3D::WriteVRML( const char* filename, bool overwrite, SGNODE* aTopNode,
 
     if( !op.fail() )
     {
-        op.close();
+        CLOSE_STREAM( op );
         return true;
     }
 
-    op.close();
+    CLOSE_STREAM( op );
 
     do {
         std::ostringstream ostr;
@@ -302,11 +283,9 @@ bool S3D::WriteCache( const char* aFileName, bool overwrite, SGNODE* aNode,
         }
     }
 
-    std::ofstream output;
-    output.open( aFileName, std::ios_base::out | std::ios_base::trunc
-                                | std::ios_base::binary );
+    OPEN_OSTREAM( output, aFileName );
 
-    if( !output.is_open() )
+    if( output.fail() )
     {
         std::ostringstream ostr;
         ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
@@ -324,7 +303,7 @@ bool S3D::WriteCache( const char* aFileName, bool overwrite, SGNODE* aNode,
         output << "(INTERNAL:0.0.0.0)";
 
     bool rval = aNode->WriteCache( output, NULL );
-    output.close();
+    CLOSE_STREAM( output );
 
     if( !rval )
     {
@@ -382,10 +361,9 @@ SGNODE* S3D::ReadCache( const char* aFileName, void* aPluginMgr,
         return NULL;
     }
 
-    std::ifstream file;
-    file.open( aFileName, std::ios_base::in | std::ios_base::binary );
+    OPEN_ISTREAM( file, aFileName );
 
-    if( !file.is_open() )
+    if( file.fail() )
     {
         delete np;
         std::ostringstream ostr;
@@ -417,7 +395,7 @@ SGNODE* S3D::ReadCache( const char* aFileName, void* aPluginMgr,
             } while( 0 );
             #endif
 
-            file.close();
+            CLOSE_STREAM( file );
             return NULL;
         }
 
@@ -431,7 +409,7 @@ SGNODE* S3D::ReadCache( const char* aFileName, void* aPluginMgr,
 
         if( name.compare( SG_VERSION_TAG ) )
         {
-            file.close();
+            CLOSE_STREAM( file );
             return NULL;
         }
 
@@ -457,7 +435,7 @@ SGNODE* S3D::ReadCache( const char* aFileName, void* aPluginMgr,
             } while( 0 );
             #endif
 
-            file.close();
+            CLOSE_STREAM( file );
             return NULL;
         }
 
@@ -472,14 +450,14 @@ SGNODE* S3D::ReadCache( const char* aFileName, void* aPluginMgr,
         // check the plugin tag
         if( NULL != aTagCheck && NULL != aPluginMgr && !aTagCheck( name.c_str(), aPluginMgr ) )
         {
-            file.close();
+            CLOSE_STREAM( file );
             return NULL;
         }
 
     } while( 0 );
 
     bool rval = np->ReadCache( file, NULL );
-    file.close();
+    CLOSE_STREAM( file );
 
     if( !rval )
     {
diff --git a/3d-viewer/3d_cache/sg/scenegraph.cpp b/3d-viewer/3d_cache/sg/scenegraph.cpp
index 7932d4443..b99403242 100644
--- a/3d-viewer/3d_cache/sg/scenegraph.cpp
+++ b/3d-viewer/3d_cache/sg/scenegraph.cpp
@@ -257,7 +257,7 @@ void SCENEGRAPH::ReNameNodes( void )
 }
 
 
-bool SCENEGRAPH::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
+bool SCENEGRAPH::WriteVRML( std::ostream& aFile, bool aReuseFlag )
 {
     if( m_Transforms.empty() && m_RTransforms.empty()
         && m_Shape.empty() && m_RShape.empty() )
@@ -364,7 +364,7 @@ bool SCENEGRAPH::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
 }
 
 
-bool SCENEGRAPH::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
+bool SCENEGRAPH::WriteCache( std::ostream& aFile, SGNODE* parentNode )
 {
     if( NULL == parentNode && NULL != m_Parent )
     {
@@ -510,7 +510,7 @@ bool SCENEGRAPH::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
 }
 
 
-bool SCENEGRAPH::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
+bool SCENEGRAPH::ReadCache( std::istream& aFile, SGNODE* parentNode )
 {
     if( !m_Transforms.empty() || !m_RTransforms.empty()
         || !m_Shape.empty() || !m_RShape.empty() )
diff --git a/3d-viewer/3d_cache/sg/scenegraph.h b/3d-viewer/3d_cache/sg/scenegraph.h
index 801f304bb..c50e5c947 100644
--- a/3d-viewer/3d_cache/sg/scenegraph.h
+++ b/3d-viewer/3d_cache/sg/scenegraph.h
@@ -79,10 +79,10 @@ public:
     bool AddChildNode( SGNODE* aNode ) override;
 
     void ReNameNodes( void ) override;
-    bool WriteVRML( std::ofstream& aFile, bool aReuseFlag ) override;
+    bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
 
-    bool WriteCache( std::ofstream& aFile, SGNODE* parentNode ) override;
-    bool ReadCache( std::ifstream& aFile, SGNODE* parentNode ) override;
+    bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
+    bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
 
     bool Prepare( const glm::dmat4* aTransform,
         S3D::MATLIST& materials, std::vector< SMESH >& meshes );
diff --git a/3d-viewer/3d_cache/sg/sg_appearance.cpp b/3d-viewer/3d_cache/sg/sg_appearance.cpp
index 703f4ea93..eae3fbc29 100644
--- a/3d-viewer/3d_cache/sg/sg_appearance.cpp
+++ b/3d-viewer/3d_cache/sg/sg_appearance.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -289,7 +289,7 @@ void SGAPPEARANCE::ReNameNodes( void )
 }
 
 
-bool SGAPPEARANCE::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
+bool SGAPPEARANCE::WriteVRML( std::ostream& aFile, bool aReuseFlag )
 {
     if( aReuseFlag )
     {
@@ -366,7 +366,7 @@ bool SGAPPEARANCE::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
 }
 
 
-bool SGAPPEARANCE::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
+bool SGAPPEARANCE::WriteCache( std::ostream& aFile, SGNODE* parentNode )
 {
     if( NULL == parentNode )
     {
@@ -436,7 +436,7 @@ bool SGAPPEARANCE::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
 }
 
 
-bool SGAPPEARANCE::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
+bool SGAPPEARANCE::ReadCache( std::istream& aFile, SGNODE* parentNode )
 {
     S3D::ReadColor( aFile, ambient );
     aFile.read( (char*)&shininess, sizeof(shininess) );
diff --git a/3d-viewer/3d_cache/sg/sg_appearance.h b/3d-viewer/3d_cache/sg/sg_appearance.h
index 1916edbec..382d5805a 100644
--- a/3d-viewer/3d_cache/sg/sg_appearance.h
+++ b/3d-viewer/3d_cache/sg/sg_appearance.h
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -71,10 +71,10 @@ public:
     bool AddChildNode( SGNODE* aNode ) override;
 
     void ReNameNodes( void ) override;
-    bool WriteVRML( std::ofstream& aFile, bool aReuseFlag ) override;
+    bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
 
-    bool WriteCache( std::ofstream& aFile, SGNODE* parentNode ) override;
-    bool ReadCache( std::ifstream& aFile, SGNODE* parentNode ) override;
+    bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
+    bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
 };
 
 #endif  // SG_APPEARANCE_H
diff --git a/3d-viewer/3d_cache/sg/sg_colors.cpp b/3d-viewer/3d_cache/sg/sg_colors.cpp
index 18ad63a2b..d80bdc749 100644
--- a/3d-viewer/3d_cache/sg/sg_colors.cpp
+++ b/3d-viewer/3d_cache/sg/sg_colors.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -207,7 +207,7 @@ void SGCOLORS::ReNameNodes( void )
 }
 
 
-bool SGCOLORS::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
+bool SGCOLORS::WriteVRML( std::ostream& aFile, bool aReuseFlag )
 {
     if( colors.empty() )
         return false;
@@ -265,7 +265,7 @@ bool SGCOLORS::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
 }
 
 
-bool SGCOLORS::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
+bool SGCOLORS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
 {
     if( NULL == parentNode )
     {
@@ -334,7 +334,7 @@ bool SGCOLORS::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
 }
 
 
-bool SGCOLORS::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
+bool SGCOLORS::ReadCache( std::istream& aFile, SGNODE* parentNode )
 {
     if( !colors.empty() )
     {
diff --git a/3d-viewer/3d_cache/sg/sg_colors.h b/3d-viewer/3d_cache/sg/sg_colors.h
index 75a67cb9a..d4445db38 100644
--- a/3d-viewer/3d_cache/sg/sg_colors.h
+++ b/3d-viewer/3d_cache/sg/sg_colors.h
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -56,10 +56,10 @@ public:
     void AddColor( const SGCOLOR& aColor );
 
     void ReNameNodes( void ) override;
-    bool WriteVRML( std::ofstream& aFile, bool aReuseFlag ) override;
+    bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
 
-    bool WriteCache( std::ofstream& aFile, SGNODE* parentNode ) override;
-    bool ReadCache( std::ifstream& aFile, SGNODE* parentNode ) override;
+    bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
+    bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
 };
 
 #endif  // SG_COLORS_H
diff --git a/3d-viewer/3d_cache/sg/sg_coords.cpp b/3d-viewer/3d_cache/sg/sg_coords.cpp
index e6c136e3e..242f87d86 100644
--- a/3d-viewer/3d_cache/sg/sg_coords.cpp
+++ b/3d-viewer/3d_cache/sg/sg_coords.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -210,7 +210,7 @@ void SGCOORDS::ReNameNodes( void )
 }
 
 
-bool SGCOORDS::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
+bool SGCOORDS::WriteVRML( std::ostream& aFile, bool aReuseFlag )
 {
     if( coords.empty() )
         return false;
@@ -272,7 +272,7 @@ bool SGCOORDS::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
 }
 
 
-bool SGCOORDS::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
+bool SGCOORDS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
 {
     if( NULL == parentNode )
     {
@@ -341,7 +341,7 @@ bool SGCOORDS::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
 }
 
 
-bool SGCOORDS::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
+bool SGCOORDS::ReadCache( std::istream& aFile, SGNODE* parentNode )
 {
     if( !coords.empty() )
     {
diff --git a/3d-viewer/3d_cache/sg/sg_coords.h b/3d-viewer/3d_cache/sg/sg_coords.h
index 378b785f9..e444fe65a 100644
--- a/3d-viewer/3d_cache/sg/sg_coords.h
+++ b/3d-viewer/3d_cache/sg/sg_coords.h
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -65,10 +65,10 @@ public:
     bool CalcNormals( SGFACESET* callingNode, SGNODE** aPtr = NULL );
 
     void ReNameNodes( void ) override;
-    bool WriteVRML( std::ofstream& aFile, bool aReuseFlag ) override;
+    bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
 
-    bool WriteCache( std::ofstream& aFile, SGNODE* parentNode ) override;
-    bool ReadCache( std::ifstream& aFile, SGNODE* parentNode ) override;
+    bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
+    bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
 };
 
 #endif  // SG_COORDS_H
diff --git a/3d-viewer/3d_cache/sg/sg_faceset.cpp b/3d-viewer/3d_cache/sg/sg_faceset.cpp
index e505591d5..e8668b8c5 100644
--- a/3d-viewer/3d_cache/sg/sg_faceset.cpp
+++ b/3d-viewer/3d_cache/sg/sg_faceset.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -482,7 +482,7 @@ void SGFACESET::ReNameNodes( void )
 }
 
 
-bool SGFACESET::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
+bool SGFACESET::WriteVRML( std::ostream& aFile, bool aReuseFlag )
 {
     if( ( NULL == m_Coords && NULL == m_RCoords )
         || ( NULL == m_CoordIndices ) )
@@ -538,7 +538,7 @@ bool SGFACESET::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
 }
 
 
-bool SGFACESET::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
+bool SGFACESET::WriteCache( std::ostream& aFile, SGNODE* parentNode )
 {
     if( NULL == parentNode )
     {
@@ -670,7 +670,7 @@ bool SGFACESET::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
 }
 
 
-bool SGFACESET::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
+bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
 {
     if( m_Coords || m_RCoords || m_CoordIndices
         || m_Colors || m_RColors
diff --git a/3d-viewer/3d_cache/sg/sg_faceset.h b/3d-viewer/3d_cache/sg/sg_faceset.h
index c465f25f2..e62a5ea1c 100644
--- a/3d-viewer/3d_cache/sg/sg_faceset.h
+++ b/3d-viewer/3d_cache/sg/sg_faceset.h
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -78,10 +78,10 @@ public:
     bool CalcNormals( SGNODE** aPtr );
 
     void ReNameNodes( void ) override;
-    bool WriteVRML( std::ofstream& aFile, bool aReuseFlag ) override;
+    bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
 
-    bool WriteCache( std::ofstream& aFile, SGNODE* parentNode ) override;
-    bool ReadCache( std::ifstream& aFile, SGNODE* parentNode ) override;
+    bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
+    bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
 
     /**
      * Function GatherCoordIndices
diff --git a/3d-viewer/3d_cache/sg/sg_helpers.cpp b/3d-viewer/3d_cache/sg/sg_helpers.cpp
index 8b0ca0edd..e2b380943 100644
--- a/3d-viewer/3d_cache/sg/sg_helpers.cpp
+++ b/3d-viewer/3d_cache/sg/sg_helpers.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -162,7 +162,7 @@ void S3D::FormatColor( std::string& result, const SGCOLOR& aColor )
 }
 
 
-bool S3D::WritePoint( std::ofstream& aFile, const SGPOINT& aPoint )
+bool S3D::WritePoint( std::ostream& aFile, const SGPOINT& aPoint )
 {
     aFile.write( (char*)&aPoint.x, sizeof(aPoint.x) );
     aFile.write( (char*)&aPoint.y, sizeof(aPoint.y) );
@@ -175,7 +175,7 @@ bool S3D::WritePoint( std::ofstream& aFile, const SGPOINT& aPoint )
 }
 
 
-bool S3D::WriteVector( std::ofstream& aFile, const SGVECTOR& aVector )
+bool S3D::WriteVector( std::ostream& aFile, const SGVECTOR& aVector )
 {
     double x, y, z;
     aVector.GetVector( x, y, z );
@@ -190,7 +190,7 @@ bool S3D::WriteVector( std::ofstream& aFile, const SGVECTOR& aVector )
 }
 
 
-bool S3D::WriteColor( std::ofstream& aFile, const SGCOLOR& aColor )
+bool S3D::WriteColor( std::ostream& aFile, const SGCOLOR& aColor )
 {
     float r, g, b;
     aColor.GetColor( r, g, b );
@@ -205,7 +205,7 @@ bool S3D::WriteColor( std::ofstream& aFile, const SGCOLOR& aColor )
 }
 
 
-S3D::SGTYPES S3D::ReadTag( std::ifstream& aFile, std::string& aName )
+S3D::SGTYPES S3D::ReadTag( std::istream& aFile, std::string& aName )
 {
     char schar;
     aFile.get( schar );
@@ -293,7 +293,7 @@ S3D::SGTYPES S3D::ReadTag( std::ifstream& aFile, std::string& aName )
 }
 
 
-bool S3D::ReadPoint( std::ifstream& aFile, SGPOINT& aPoint )
+bool S3D::ReadPoint( std::istream& aFile, SGPOINT& aPoint )
 {
     aFile.read( (char*)&aPoint.x, sizeof( aPoint.x ) );
     aFile.read( (char*)&aPoint.y, sizeof( aPoint.y ) );
@@ -306,7 +306,7 @@ bool S3D::ReadPoint( std::ifstream& aFile, SGPOINT& aPoint )
 }
 
 
-bool S3D::ReadVector( std::ifstream& aFile, SGVECTOR& aVector )
+bool S3D::ReadVector( std::istream& aFile, SGVECTOR& aVector )
 {
     double x, y, z;
     aFile.read( (char*)&x, sizeof(double) );
@@ -321,7 +321,7 @@ bool S3D::ReadVector( std::ifstream& aFile, SGVECTOR& aVector )
 }
 
 
-bool S3D::ReadColor( std::ifstream& aFile, SGCOLOR& aColor )
+bool S3D::ReadColor( std::istream& aFile, SGCOLOR& aColor )
 {
     float r, g, b;
     aFile.read( (char*)&r, sizeof(float) );
diff --git a/3d-viewer/3d_cache/sg/sg_helpers.h b/3d-viewer/3d_cache/sg/sg_helpers.h
index 54b0c8076..a2f024139 100644
--- a/3d-viewer/3d_cache/sg/sg_helpers.h
+++ b/3d-viewer/3d_cache/sg/sg_helpers.h
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -32,7 +32,7 @@
 #ifndef SG_HELPERS_H
 #define SG_HELPERS_H
 
-#include <fstream>
+#include <iostream>
 #include <string>
 #include <algorithm>
 #include <vector>
@@ -210,13 +210,13 @@ namespace S3D
     //
 
     // write out an XYZ vertex
-    bool WritePoint( std::ofstream& aFile, const SGPOINT& aPoint );
+    bool WritePoint( std::ostream& aFile, const SGPOINT& aPoint );
 
     // write out a unit vector
-    bool WriteVector( std::ofstream& aFile, const SGVECTOR& aVector );
+    bool WriteVector( std::ostream& aFile, const SGVECTOR& aVector );
 
     // write out an RGB color
-    bool WriteColor( std::ofstream& aFile, const SGCOLOR& aColor );
+    bool WriteColor( std::ostream& aFile, const SGCOLOR& aColor );
 
     //
     // Cache related READ functions
@@ -232,16 +232,16 @@ namespace S3D
      * @return will be the NodeType which the tag represents or
      * S3D::SGTYPES::SGTYPE_END on failure
      */
-    S3D::SGTYPES ReadTag( std::ifstream& aFile, std::string& aName );
+    S3D::SGTYPES ReadTag( std::istream& aFile, std::string& aName );
 
     // read an XYZ vertex
-    bool ReadPoint( std::ifstream& aFile, SGPOINT& aPoint );
+    bool ReadPoint( std::istream& aFile, SGPOINT& aPoint );
 
     // read a unit vector
-    bool ReadVector( std::ifstream& aFile, SGVECTOR& aVector );
+    bool ReadVector( std::istream& aFile, SGVECTOR& aVector );
 
     // read an RGB color
-    bool ReadColor( std::ifstream& aFile, SGCOLOR& aColor );
+    bool ReadColor( std::istream& aFile, SGCOLOR& aColor );
 };
 
 #endif  // SG_HELPERS_H
diff --git a/3d-viewer/3d_cache/sg/sg_index.cpp b/3d-viewer/3d_cache/sg/sg_index.cpp
index 210ca038c..032255892 100644
--- a/3d-viewer/3d_cache/sg/sg_index.cpp
+++ b/3d-viewer/3d_cache/sg/sg_index.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -21,7 +21,6 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
  */
 
-#include <fstream>
 #include <iostream>
 #include <sstream>
 #include <wx/log.h>
@@ -195,7 +194,7 @@ void SGINDEX::ReNameNodes( void )
 }
 
 
-bool SGINDEX::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
+bool SGINDEX::WriteVRML( std::ostream& aFile, bool aReuseFlag )
 {
     if( index.empty() )
         return false;
@@ -207,7 +206,7 @@ bool SGINDEX::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
 }
 
 
-bool SGINDEX::writeCoordIndex( std::ofstream& aFile )
+bool SGINDEX::writeCoordIndex( std::ostream& aFile )
 {
     size_t n = index.size();
 
@@ -259,14 +258,14 @@ bool SGINDEX::writeCoordIndex( std::ofstream& aFile )
 }
 
 
-bool SGINDEX::writeColorIndex( std::ofstream& aFile )
+bool SGINDEX::writeColorIndex( std::ostream& aFile )
 {
     aFile << " colorIndex [\n  ";
     return writeIndexList( aFile );
 }
 
 
-bool SGINDEX::writeIndexList( std::ofstream& aFile )
+bool SGINDEX::writeIndexList( std::ostream& aFile )
 {
     // index to control formatting
     int nv = 0;
@@ -295,7 +294,7 @@ bool SGINDEX::writeIndexList( std::ofstream& aFile )
 }
 
 
-bool SGINDEX::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
+bool SGINDEX::WriteCache( std::ostream& aFile, SGNODE* parentNode )
 {
     if( NULL == parentNode )
     {
@@ -364,7 +363,7 @@ bool SGINDEX::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
 }
 
 
-bool SGINDEX::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
+bool SGINDEX::ReadCache( std::istream& aFile, SGNODE* parentNode )
 {
     if( !index.empty() )
     {
diff --git a/3d-viewer/3d_cache/sg/sg_index.h b/3d-viewer/3d_cache/sg/sg_index.h
index 61c114a1d..911d77f32 100644
--- a/3d-viewer/3d_cache/sg/sg_index.h
+++ b/3d-viewer/3d_cache/sg/sg_index.h
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -35,9 +35,9 @@
 class SGINDEX : public SGNODE
 {
 protected:
-    bool writeCoordIndex( std::ofstream& aFile );
-    bool writeColorIndex( std::ofstream& aFile );
-    bool writeIndexList( std::ofstream& aFile );
+    bool writeCoordIndex( std::ostream& aFile );
+    bool writeColorIndex( std::ostream& aFile );
+    bool writeIndexList( std::ostream& aFile );
 
 public:
     // for internal SG consumption only
@@ -89,10 +89,10 @@ public:
     void AddIndex( int aIndex );
 
     void ReNameNodes( void ) override;
-    bool WriteVRML( std::ofstream& aFile, bool aReuseFlag ) override;
+    bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
 
-    bool WriteCache( std::ofstream& aFile, SGNODE* parentNode ) override;
-    bool ReadCache( std::ifstream& aFile, SGNODE* parentNode ) override;
+    bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
+    bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
 };
 
 #endif  // SG_INDEX_H
diff --git a/3d-viewer/3d_cache/sg/sg_node.h b/3d-viewer/3d_cache/sg/sg_node.h
index 2379b42b0..fc6e646f2 100644
--- a/3d-viewer/3d_cache/sg/sg_node.h
+++ b/3d-viewer/3d_cache/sg/sg_node.h
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -30,7 +30,7 @@
 #ifndef SG_NODE_H
 #define SG_NODE_H
 
-#include <fstream>
+#include <iostream>
 #include <string>
 #include <list>
 #include <vector>
@@ -227,7 +227,7 @@ public:
      * writes this node's data to a VRML file; this includes
      * all data of child and referenced nodes.
      */
-    virtual bool WriteVRML( std::ofstream& aFile, bool aReuseFlag ) = 0;
+    virtual bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) = 0;
 
     /**
      * Function WriteCache
@@ -236,7 +236,7 @@ public:
      * If this function is invoked by the user, parentNode must be
      * set to NULL in order to ensure coherent data.
      */
-    virtual bool WriteCache( std::ofstream& aFile, SGNODE* parentNode ) = 0;
+    virtual bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) = 0;
 
     /**
      * Function ReadCache
@@ -244,7 +244,7 @@ public:
      * open the file for reading and invoke this function from a new
      * SCENEGRAPH node.
      */
-    virtual bool ReadCache( std::ifstream& aFile, SGNODE* parentNode ) = 0;
+    virtual bool ReadCache( std::istream& aFile, SGNODE* parentNode ) = 0;
 };
 
 #endif  // SG_NODE_H
diff --git a/3d-viewer/3d_cache/sg/sg_normals.cpp b/3d-viewer/3d_cache/sg/sg_normals.cpp
index 058884d39..c3bc11a2b 100644
--- a/3d-viewer/3d_cache/sg/sg_normals.cpp
+++ b/3d-viewer/3d_cache/sg/sg_normals.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -208,7 +208,7 @@ void SGNORMALS::ReNameNodes( void )
 }
 
 
-bool SGNORMALS::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
+bool SGNORMALS::WriteVRML( std::ostream& aFile, bool aReuseFlag )
 {
     if( norms.empty() )
         return false;
@@ -264,7 +264,7 @@ bool SGNORMALS::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
 }
 
 
-bool SGNORMALS::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
+bool SGNORMALS::WriteCache( std::ostream& aFile, SGNODE* parentNode )
 {
     if( NULL == parentNode )
     {
@@ -333,7 +333,7 @@ bool SGNORMALS::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
 }
 
 
-bool SGNORMALS::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
+bool SGNORMALS::ReadCache( std::istream& aFile, SGNODE* parentNode )
 {
     if( !norms.empty() )
     {
diff --git a/3d-viewer/3d_cache/sg/sg_normals.h b/3d-viewer/3d_cache/sg/sg_normals.h
index 01c929532..def7e7cfb 100644
--- a/3d-viewer/3d_cache/sg/sg_normals.h
+++ b/3d-viewer/3d_cache/sg/sg_normals.h
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -56,10 +56,10 @@ public:
     void AddNormal( const SGVECTOR& aNormal );
 
     void ReNameNodes( void ) override;
-    bool WriteVRML( std::ofstream& aFile, bool aReuseFlag ) override;
+    bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
 
-    bool WriteCache( std::ofstream& aFile, SGNODE* parentNode ) override;
-    bool ReadCache( std::ifstream& aFile, SGNODE* parentNode ) override;
+    bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
+    bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
 };
 
 #endif  // SG_NORMALS_H
diff --git a/3d-viewer/3d_cache/sg/sg_shape.cpp b/3d-viewer/3d_cache/sg/sg_shape.cpp
index aa4272afc..aa7fe206c 100644
--- a/3d-viewer/3d_cache/sg/sg_shape.cpp
+++ b/3d-viewer/3d_cache/sg/sg_shape.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -22,7 +22,6 @@
  */
 
 
-#include <fstream>
 #include <iostream>
 #include <sstream>
 #include <wx/log.h>
@@ -357,7 +356,7 @@ void SGSHAPE::ReNameNodes( void )
 }
 
 
-bool SGSHAPE::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
+bool SGSHAPE::WriteVRML( std::ostream& aFile, bool aReuseFlag )
 {
     if( !m_Appearance && !m_RAppearance
         && !m_FaceSet && !m_RFaceSet )
@@ -401,7 +400,7 @@ bool SGSHAPE::WriteVRML( std::ofstream& aFile, bool aReuseFlag )
 }
 
 
-bool SGSHAPE::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
+bool SGSHAPE::WriteCache( std::ostream& aFile, SGNODE* parentNode )
 {
     if( NULL == parentNode )
     {
@@ -509,7 +508,7 @@ bool SGSHAPE::WriteCache( std::ofstream& aFile, SGNODE* parentNode )
 }
 
 
-bool SGSHAPE::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
+bool SGSHAPE::ReadCache( std::istream& aFile, SGNODE* parentNode )
 {
     if( m_Appearance || m_RAppearance || m_FaceSet || m_RFaceSet )
     {
diff --git a/3d-viewer/3d_cache/sg/sg_shape.h b/3d-viewer/3d_cache/sg/sg_shape.h
index 0732f697e..d21f7351b 100644
--- a/3d-viewer/3d_cache/sg/sg_shape.h
+++ b/3d-viewer/3d_cache/sg/sg_shape.h
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -65,10 +65,10 @@ public:
     bool AddChildNode( SGNODE* aNode ) override;
 
     void ReNameNodes( void ) override;
-    bool WriteVRML( std::ofstream& aFile, bool aReuseFlag ) override;
+    bool WriteVRML( std::ostream& aFile, bool aReuseFlag ) override;
 
-    bool WriteCache( std::ofstream& aFile, SGNODE* parentNode ) override;
-    bool ReadCache( std::ifstream& aFile, SGNODE* parentNode ) override;
+    bool WriteCache( std::ostream& aFile, SGNODE* parentNode ) override;
+    bool ReadCache( std::istream& aFile, SGNODE* parentNode ) override;
 
     bool Prepare( const glm::dmat4* aTransform,
         S3D::MATLIST& materials, std::vector< SMESH >& meshes );
diff --git a/common/streamwrapper.cpp b/common/streamwrapper.cpp
new file mode 100644
index 000000000..5ec0db69f
--- /dev/null
+++ b/common/streamwrapper.cpp
@@ -0,0 +1,121 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#if !defined( WIN32 ) || !defined( __GNUC__ )
+    #error streamwrapper.cpp should not be included in this build
+#endif
+
+#include "streamwrapper.h"
+
+#include <wx/string.h>
+#include <iostream>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+
+kicad::stream::stream()
+{
+    m_buf = NULL;
+    m_stream = NULL;
+    return;
+}
+
+
+kicad::stream::~stream()
+{
+    if( NULL != m_stream )
+        delete m_stream;
+
+    if( NULL != m_buf )
+    {
+        m_buf->close(); // ensure file is closed regardless of m_buf's destructor
+        delete m_buf;
+    }
+
+    return;
+}
+
+
+std::iostream* kicad::stream::Open( const char* aFileName, std::ios_base::openmode aMode )
+{
+    if( NULL != m_stream )
+    {
+        delete m_stream;
+        m_stream = NULL;
+    }
+
+    if( NULL != m_buf )
+    {
+        m_buf->close();
+        delete m_buf;
+    }
+
+    int flags = 0;
+
+    if( aMode & std::ios_base::app )
+        flags |= _O_APPEND;
+
+    if( aMode & std::ios_base::out && aMode & std::ios_base::in )
+        flags |= _O_RDWR;
+    else if( aMode & std::ios_base::out )
+        flags |= _O_WRONLY;
+    else if( aMode & std::ios_base::in )
+        flags |= _O_RDONLY;
+
+    if( aMode & std::ios_base::binary )
+        flags |= _O_BINARY;
+
+    if( aMode & std::ios_base::out && aMode & std::ios_base::trunc
+        && !( aMode & std::ios_base::app ) && !( aMode & std::ios_base::ate ) )
+        flags |= _O_TRUNC;
+
+    if( aMode & std::ios_base::out )
+        flags |= _O_CREAT;
+
+    //int fd = open( "testfile.txt", flags, S_IRUSR | S_IWUSR );
+    wxString lstr( wxString::FromUTF8Unchecked( aFileName ) );
+    int fd = _wopen( lstr.wc_str(), flags, _S_IREAD | _S_IWRITE );
+
+    if( fd >= 0 && aMode & std::ios_base::ate )
+        lseek( fd, 0, SEEK_END );
+
+    // NOTE: _O_RDONLY in Windows, O_RDONLY in Linux
+    m_buf = new __gnu_cxx::stdio_filebuf<char>( fd, aMode );
+
+    m_stream = new std::iostream( m_buf );
+
+    return m_stream;
+}
+
+
+void kicad::stream::Close( void )
+{
+    if( m_buf )
+        m_buf->close();
+
+    return;
+}
+
+
+std::iostream* kicad::stream::GetStream( void )
+{
+    return m_stream;
+}
diff --git a/include/streamwrapper.h b/include/streamwrapper.h
new file mode 100644
index 000000000..42c683b73
--- /dev/null
+++ b/include/streamwrapper.h
@@ -0,0 +1,101 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef STREAMWRAPPER_H
+#define STREAMWRAPPER_H
+
+#include <iostream>
+
+
+#if defined( WIN32 ) && defined( __GNUC__ )
+    #include <ext/stdio_filebuf.h>
+
+    #define OPEN_OSTREAM( var, name ) \
+        kicad::stream var ## _BUF_; \
+        std::ostream& var = *var ## _BUF_.Open( name, std::ios_base::out | std::ios_base::trunc | std::ios_base::binary )
+
+    #define OPEN_ISTREAM( var, name ) \
+        kicad::stream var ## _BUF_; \
+        std::istream& var = *var ## _BUF_.Open( name, std::ios_base::in | std::ios_base::binary )
+
+    #define OPEN_IOSTREAM( var, name ) \
+        kicad::stream var ## _BUF_; \
+        std::iostream& var = *var ## _BUF_.Open( name, std::ios_base::out | std::ios_base::in | std::ios_base::binary )
+
+    #define CLOSE_STREAM( var ) var ## _BUF_.Close()
+
+    namespace kicad
+    {
+        class stream
+        {
+        private:
+            __gnu_cxx::stdio_filebuf<char>* m_buf;
+            std::iostream*                  m_stream;
+
+        public:
+            stream();
+            virtual ~stream();
+
+            std::iostream* Open( const char* aFileName, std::ios_base::openmode aMode );
+            void Close( void );
+
+            std::iostream* GetStream( void );
+        };
+    }
+
+
+#elif defined( _MSC_VER )   // defined( WIN32 ) && defined( __GNUC__ )
+
+    #define OPEN_OSTREAM( var, name ) \
+    std::ofstream var; \
+    var.open( wxString::FromUTF8Unchecked( name ).wc_str(), \
+    std::ios_base::out | std::ios_base::trunc | std::ios_base::binary )
+
+    #define OPEN_ISTREAM( var, name ) \
+    std::ifstream var; \
+    var.open( wxString::FromUTF8Unchecked( name ).wc_str(), \
+        std::ios_base::in | std::ios_base::binary )
+
+    #define OPEN_IOSTREAM( var, name ) \
+    std::fstream var; \
+    var.open( wxString::FromUTF8Unchecked( name ).wc_str(), \
+        std::ios_base::out | std::ios_base::in | std::ios_base::binary )
+
+    #define CLOSE_STREAM( var ) var.close()
+
+#else   // defined( WIN32 ) && defined( __GNUC__ )
+
+    #define OPEN_OSTREAM( var, name ) \
+        std::ofstream var; \
+        var.open( name, std::ios_base::out | std::ios_base::trunc )
+
+    #define OPEN_ISTREAM( var, name ) \
+        std::ifstream var; \
+        var.open( name, std::ios_base::in )
+
+    #define OPEN_IOSTREAM( var, name ) \
+        std::fstream var; \
+        var.open( name, std::ios_base::out | std::ios_base::in )
+
+    #define CLOSE_STREAM( var ) var.close()
+
+#endif  // defined( WIN32 ) && defined( __GNUC__ )
+
+#endif  // STREAMWRAPPER_H
diff --git a/pcbnew/exporters/export_vrml.cpp b/pcbnew/exporters/export_vrml.cpp
index e1ba044d2..590504584 100644
--- a/pcbnew/exporters/export_vrml.cpp
+++ b/pcbnew/exporters/export_vrml.cpp
@@ -2,7 +2,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2009-2013  Lorenzo Mercantonio
- * Copyright (C) 2014-2016  Cirilo Bernardo
+ * Copyright (C) 2014-2017  Cirilo Bernardo
  * Copyright (C) 2013 Jean-Pierre Charras jp.charras at wanadoo.fr
  * Copyright (C) 2004-2016 KiCad Developers, see AUTHORS.txt for contributors.
  *
@@ -44,6 +44,7 @@
 #include "macros.h"
 #include "pgm_base.h"
 #include "plugins/3dapi/ifsg_all.h"
+#include "streamwrapper.h"
 #include "vrml_layer.h"
 #include "wxPcbStruct.h"
 #include "../../kicad/kicad.h"
@@ -62,7 +63,6 @@ static bool USE_DEFS;               // true to reuse component definitions
 static bool USE_RELPATH;            // true to use relative paths in VRML inline{}
 static double WORLD_SCALE = 1.0;    // scaling from 0.1 in to desired VRML unit
 static double BOARD_SCALE;          // scaling from mm to desired VRML world scale
-static std::ofstream output_file;   // legacy VRML output stream
 static const int PRECISION = 6;     // legacy precision factor (now set to 6)
 static wxString SUBDIR_3D;          // legacy 3D subdirectory
 static wxString PROJ_DIR;           // project directory
@@ -315,7 +315,7 @@ static void create_vrml_shell( IFSG_TRANSFORM& PcbOutput, VRML_COLOR_INDEX color
 static void create_vrml_plane( IFSG_TRANSFORM& PcbOutput, VRML_COLOR_INDEX colorID,
     VRML_LAYER* layer, double aHeight, bool aTopPlane );
 
-static void write_triangle_bag( std::ofstream& aOut_file, VRML_COLOR& aColor,
+static void write_triangle_bag( std::ostream& aOut_file, VRML_COLOR& aColor,
                                 VRML_LAYER* aLayer, bool aPlane, bool aTop,
                                 double aTop_z, double aBottom_z )
 {
@@ -415,7 +415,8 @@ static void write_triangle_bag( std::ofstream& aOut_file, VRML_COLOR& aColor,
 }
 
 
-static void write_layers( MODEL_VRML& aModel, BOARD* aPcb, const char* aFileName )
+static void write_layers( MODEL_VRML& aModel, BOARD* aPcb,
+    const char* aFileName, std::ofstream* aOutputFile )
 {
     // VRML_LAYER board;
     aModel.m_board.Tesselate( &aModel.m_holes );
@@ -424,7 +425,7 @@ static void write_layers( MODEL_VRML& aModel, BOARD* aPcb, const char* aFileName
 
     if( USE_INLINES )
     {
-        write_triangle_bag( output_file, aModel.GetColor( VRML_COLOR_PCB ),
+        write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_PCB ),
                             &aModel.m_board, false, false, brdz, -brdz );
     }
     else
@@ -445,7 +446,7 @@ static void write_layers( MODEL_VRML& aModel, BOARD* aPcb, const char* aFileName
 
     if( USE_INLINES )
     {
-        write_triangle_bag( output_file, aModel.GetColor( VRML_COLOR_TRACK ),
+        write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_TRACK ),
                            &aModel.m_top_copper, true, true,
                            aModel.GetLayerZ( F_Cu ), 0 );
     }
@@ -460,7 +461,7 @@ static void write_layers( MODEL_VRML& aModel, BOARD* aPcb, const char* aFileName
 
     if( USE_INLINES )
     {
-        write_triangle_bag( output_file, aModel.GetColor( VRML_COLOR_TIN ),
+        write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_TIN ),
                             &aModel.m_top_tin, true, true,
                             aModel.GetLayerZ( F_Cu ) + Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE,
                             0 );
@@ -477,7 +478,7 @@ static void write_layers( MODEL_VRML& aModel, BOARD* aPcb, const char* aFileName
 
     if( USE_INLINES )
     {
-        write_triangle_bag( output_file, aModel.GetColor( VRML_COLOR_TRACK ),
+        write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_TRACK ),
                             &aModel.m_bot_copper, true, false,
                             aModel.GetLayerZ( B_Cu ), 0 );
     }
@@ -492,7 +493,7 @@ static void write_layers( MODEL_VRML& aModel, BOARD* aPcb, const char* aFileName
 
     if( USE_INLINES )
     {
-        write_triangle_bag( output_file, aModel.GetColor( VRML_COLOR_TIN ),
+        write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_TIN ),
                             &aModel.m_bot_tin, true, false,
                             aModel.GetLayerZ( B_Cu )
                             - Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE,
@@ -510,7 +511,7 @@ static void write_layers( MODEL_VRML& aModel, BOARD* aPcb, const char* aFileName
 
     if( USE_INLINES )
     {
-        write_triangle_bag( output_file, aModel.GetColor( VRML_COLOR_TIN ),
+        write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_TIN ),
                             &aModel.m_plated_holes, false, false,
                             aModel.GetLayerZ( F_Cu ) + Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE,
                             aModel.GetLayerZ( B_Cu ) - Millimeter2iu( ART_OFFSET / 2.0 ) * BOARD_SCALE );
@@ -527,7 +528,7 @@ static void write_layers( MODEL_VRML& aModel, BOARD* aPcb, const char* aFileName
 
     if( USE_INLINES )
     {
-        write_triangle_bag( output_file, aModel.GetColor( VRML_COLOR_SILK ), &aModel.m_top_silk,
+        write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_SILK ), &aModel.m_top_silk,
                             true, true, aModel.GetLayerZ( F_SilkS ), 0 );
     }
     else
@@ -541,7 +542,7 @@ static void write_layers( MODEL_VRML& aModel, BOARD* aPcb, const char* aFileName
 
     if( USE_INLINES )
     {
-        write_triangle_bag( output_file, aModel.GetColor( VRML_COLOR_SILK ), &aModel.m_bot_silk,
+        write_triangle_bag( *aOutputFile, aModel.GetColor( VRML_COLOR_SILK ), &aModel.m_bot_silk,
                             true, false, aModel.GetLayerZ( B_SilkS ), 0 );
     }
     else
@@ -1265,7 +1266,8 @@ static void compose_quat( double q1[4], double q2[4], double qr[4] )
 }
 
 
-static void export_vrml_module( MODEL_VRML& aModel, BOARD* aPcb, MODULE* aModule )
+static void export_vrml_module( MODEL_VRML& aModel, BOARD* aPcb,
+    MODULE* aModule, std::ostream* aOutputFile )
 {
     if( !aModel.m_plainPCB )
     {
@@ -1404,29 +1406,28 @@ static void export_vrml_module( MODEL_VRML& aModel, BOARD* aPcb, MODULE* aModule
                     if( !S3D::WriteVRML( dstFile.GetFullPath().ToUTF8(), true, mod3d, USE_DEFS, true ) )
                         continue;
                 }
-
             }
 
-            output_file << "Transform {\n";
+            (*aOutputFile) << "Transform {\n";
 
             // only write a rotation if it is >= 0.1 deg
             if( std::abs( rot[3] ) > 0.0001745 )
             {
-                output_file << "  rotation " << std::setprecision( 5 );
-                output_file << rot[0] << " " << rot[1] << " " << rot[2] << " " << rot[3] << "\n";
+                (*aOutputFile) << "  rotation " << std::setprecision( 5 );
+                (*aOutputFile) << rot[0] << " " << rot[1] << " " << rot[2] << " " << rot[3] << "\n";
             }
 
-            output_file << "  translation " << std::setprecision( PRECISION );
-            output_file << trans.x << " ";
-            output_file << trans.y << " ";
-            output_file << trans.z << "\n";
+            (*aOutputFile) << "  translation " << std::setprecision( PRECISION );
+            (*aOutputFile) << trans.x << " ";
+            (*aOutputFile) << trans.y << " ";
+            (*aOutputFile) << trans.z << "\n";
 
-            output_file << "  scale ";
-            output_file << sM->m_Scale.x << " ";
-            output_file << sM->m_Scale.y << " ";
-            output_file << sM->m_Scale.z << "\n";
+            (*aOutputFile) << "  scale ";
+            (*aOutputFile) << sM->m_Scale.x << " ";
+            (*aOutputFile) << sM->m_Scale.y << " ";
+            (*aOutputFile) << sM->m_Scale.z << "\n";
 
-            output_file << "  children [\n    Inline {\n      url \"";
+            (*aOutputFile) << "  children [\n    Inline {\n      url \"";
 
             if( USE_RELPATH )
             {
@@ -1439,8 +1440,8 @@ static void export_vrml_module( MODEL_VRML& aModel, BOARD* aPcb, MODULE* aModule
 
             wxString fn = dstFile.GetFullPath();
             fn.Replace( "\\", "/" );
-            output_file << TO_UTF8( fn ) << "\"\n    } ]\n";
-            output_file << "  }\n";
+            (*aOutputFile) << TO_UTF8( fn ) << "\"\n    } ]\n";
+            (*aOutputFile) << "  }\n";
         }
         else
         {
@@ -1503,9 +1504,6 @@ bool PCB_EDIT_FRAME::ExportVRML_File( const wxString& aFullFileName, double aMMt
     // plain PCB or else PCB with copper and silkscreen
     model3d.m_plainPCB = aUsePlainPCB;
 
-    // locale switch for C numeric output
-    LOCALE_IO* toggle = NULL;
-
     try
     {
 
@@ -1537,8 +1535,16 @@ bool PCB_EDIT_FRAME::ExportVRML_File( const wxString& aFullFileName, double aMMt
                     throw( std::runtime_error( "Could not create 3D model subdirectory" ) );
             }
 
-            toggle = new LOCALE_IO;
-            output_file.open( TO_UTF8( aFullFileName ), std::ios_base::out );
+            OPEN_OSTREAM( output_file, TO_UTF8( aFullFileName ) );
+
+            if( output_file.fail() )
+            {
+                std::ostringstream ostr;
+                ostr << "Could not open file '" << TO_UTF8( aFullFileName ) << "'";
+                throw( std::runtime_error( ostr.str().c_str() ) );
+            }
+
+            output_file.imbue( std::locale( "C" ) );
 
             // Begin with the usual VRML boilerplate
             wxString fn = aFullFileName;
@@ -1553,19 +1559,28 @@ bool PCB_EDIT_FRAME::ExportVRML_File( const wxString& aFullFileName, double aMMt
             output_file << WORLD_SCALE << " ";
             output_file << WORLD_SCALE << "\n";
             output_file << "  children [\n";
-        }
 
-        // Export footprints
-        for( MODULE* module = pcb->m_Modules; module != 0; module = module->Next() )
-            export_vrml_module( model3d, pcb, module );
+            // Export footprints
+            for( MODULE* module = pcb->m_Modules; module != 0; module = module->Next() )
+                export_vrml_module( model3d, pcb, module, &output_file );
 
-        // write out the board and all layers
-        write_layers( model3d, pcb, TO_UTF8( aFullFileName ) );
+            // write out the board and all layers
+            write_layers( model3d, pcb, TO_UTF8( aFullFileName ), &output_file );
 
-        // Close the outer 'transform' node
-        if( USE_INLINES )
+            // Close the outer 'transform' node
             output_file << "]\n}\n";
 
+            CLOSE_STREAM( output_file );
+        }
+        else
+        {
+            // Export footprints
+            for( MODULE* module = pcb->m_Modules; module != 0; module = module->Next() )
+                export_vrml_module( model3d, pcb, module, NULL );
+
+            // write out the board and all layers
+            write_layers( model3d, pcb, TO_UTF8( aFullFileName ), NULL );
+        }
     }
     catch( const std::exception& e )
     {
@@ -1576,14 +1591,6 @@ bool PCB_EDIT_FRAME::ExportVRML_File( const wxString& aFullFileName, double aMMt
         ok = false;
     }
 
-    if( USE_INLINES )
-    {
-        output_file.close();
-
-        if( toggle )
-            delete toggle;
-    }
-
     return ok;
 }
 
diff --git a/plugins/3d/idf/s3d_plugin_idf.cpp b/plugins/3d/idf/s3d_plugin_idf.cpp
index 53ed48769..39068ec3c 100644
--- a/plugins/3d/idf/s3d_plugin_idf.cpp
+++ b/plugins/3d/idf/s3d_plugin_idf.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2015-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -28,8 +28,10 @@
 #include <cmath>
 #include <string>
 #include <map>
+#include <wx/filename.h>
 #include <wx/log.h>
 #include <wx/string.h>
+
 #include "plugins/3d/3d_plugin.h"
 #include "plugins/3dapi/ifsg_all.h"
 #include "idf_parser.h"
diff --git a/plugins/3d/vrml/wrlfacet.cpp b/plugins/3d/vrml/wrlfacet.cpp
index 35c2fe35b..f09d5637c 100644
--- a/plugins/3d/vrml/wrlfacet.cpp
+++ b/plugins/3d/vrml/wrlfacet.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
+ * Copyright (C) 2016-2017 Cirilo Bernardo <cirilo.bernardo@xxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -277,7 +277,7 @@ float FACET::CalcFaceNormal()
         lCPts[2] = *sV;
         ++sV;
 
-        WRLVEC3F wnorm = face_normal;
+        wnorm = face_normal;
         a2 = acosf( VCalcCosAngle(  lCPts[1], lCPts[0], lCPts[2] ) );
         wnorm.x *= a1 * a2;
         wnorm.y *= a1 * a2;
diff --git a/utils/idftools/CMakeLists.txt b/utils/idftools/CMakeLists.txt
index f6bee990c..2982d48c3 100644
--- a/utils/idftools/CMakeLists.txt
+++ b/utils/idftools/CMakeLists.txt
@@ -1,17 +1,28 @@
 include_directories(
+    "${CMAKE_SOURCE_DIR}/include"
     "${CMAKE_SOURCE_DIR}/lib_dxf"
     "${CMAKE_SOURCE_DIR}/utils/idftools"
     ${OPENGL_INCLUDE_DIR}
     ${Boost_INCLUDE_DIR}
-  )
+)
 
 link_directories(
     "${CMAKE_BINARY_DIR}/lib_dxf"
-  )
+)
 
-add_library( idf3 STATIC
-    idf_helpers.cpp idf_common.cpp idf_outlines.cpp
-    idf_parser.cpp vrml_layer.cpp )
+set( IDF3_FILES
+    idf_helpers.cpp
+    idf_common.cpp
+    idf_outlines.cpp
+    idf_parser.cpp
+    vrml_layer.cpp
+)
+
+if( MINGW )
+    list( APPEND IDF3_FILES ${CMAKE_SOURCE_DIR}/common/streamwrapper.cpp )
+endif( MINGW )
+
+add_library( idf3 STATIC ${IDF3_FILES} )
 
 add_executable( idfcyl idf_cylinder.cpp )
 add_executable( idfrect idf_rect.cpp )
diff --git a/utils/idftools/idf2vrml.cpp b/utils/idftools/idf2vrml.cpp
index dc1203591..4eb34c6d1 100644
--- a/utils/idftools/idf2vrml.cpp
+++ b/utils/idftools/idf2vrml.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2014  Cirilo Bernardo
+ * Copyright (C) 2014-2017  Cirilo Bernardo
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -47,17 +47,17 @@
 #include <cerrno>
 #include <list>
 #include <utility>
-#include <clocale>
 #include <vector>
 #include <cstdlib>
 #include <cstring>
 #include <algorithm>
 #include <boost/ptr_container/ptr_map.hpp>
 
-#include <idf_helpers.h>
-#include <idf_common.h>
-#include <idf_parser.h>
-#include <vrml_layer.h>
+#include "idf_helpers.h"
+#include "idf_common.h"
+#include "idf_parser.h"
+#include "streamwrapper.h"
+#include "vrml_layer.h"
 
 #ifndef MIN_ANG
 #define MIN_ANG 0.01
@@ -198,14 +198,14 @@ VRML_COLOR colors[NCOLORS] =
     { { 0.102, 1, 0.984 },      { 0, 0, 0 },    { 0.102, 1, 0.984 },        0.9, 0, 0.1 }
 };
 
-bool WriteHeader( IDF3_BOARD& board, std::ofstream& file );
-bool MakeBoard( IDF3_BOARD& board, std::ofstream& file );
-bool MakeComponents( IDF3_BOARD& board, std::ofstream& file, bool compact );
-bool MakeOtherOutlines( IDF3_BOARD& board, std::ofstream& file );
+bool WriteHeader( IDF3_BOARD& board, std::ostream& file );
+bool MakeBoard( IDF3_BOARD& board, std::ostream& file );
+bool MakeComponents( IDF3_BOARD& board, std::ostream& file, bool compact );
+bool MakeOtherOutlines( IDF3_BOARD& board, std::ostream& file );
 bool PopulateVRML( VRML_LAYER& model, const std::list< IDF_OUTLINE* >* items, bool bottom,
                    double scale, double dX = 0.0, double dY = 0.0, double angle = 0.0 );
 bool AddSegment( VRML_LAYER& model, IDF_SEGMENT* seg, int icont, int iseg );
-bool WriteTriangles( std::ofstream& file, VRML_IDS* vID, VRML_LAYER* layer, bool plane,
+bool WriteTriangles( std::ostream& file, VRML_IDS* vID, VRML_LAYER* layer, bool plane,
                      bool top, double top_z, double bottom_z, int precision, bool compact );
 inline void TransformPoint( IDF_SEGMENT& seg, double frac, bool bottom,
                             double dX, double dY, double angle );
@@ -215,9 +215,6 @@ VRML_IDS* GetColor( boost::ptr_map<const std::string, VRML_IDS>& cmap,
 
 int IDF2VRML::OnRun()
 {
-    // IDF implicitly requires the C locale
-    setlocale( LC_ALL, "C" );
-
     // Essential inputs:
     // 1. IDF file
     // 2. Output scale: internal IDF units are mm, so 1 = 1mm per VRML unit,
@@ -264,9 +261,14 @@ int IDF2VRML::OnRun()
     fname.Normalize();
     wxLogMessage( "Writing file: '%s'", fname.GetFullName() );
 
-    std::ofstream ofile;
-    ofile.open( fname.GetFullPath().ToUTF8(), std::ios_base::out );
+    OPEN_OSTREAM( ofile, fname.GetFullPath().ToUTF8() );
+
+    if( ofile.fail() )
+    {
+        wxLogMessage( "Could not open file: '%s'", fname.GetFullName() );
+    }
 
+    ofile.imbue( std::locale( "C" ) );
     ofile << std::fixed; // do not use exponents in VRML output
     WriteHeader( pcb, ofile );
 
@@ -280,15 +282,13 @@ int IDF2VRML::OnRun()
     MakeOtherOutlines( pcb, ofile );
 
     ofile << "]\n}\n";
-    ofile.close();
+    CLOSE_STREAM( ofile );
 
-    // restore the locale
-    setlocale( LC_ALL, "" );
     return 0;
 }
 
 
-bool WriteHeader( IDF3_BOARD& board, std::ofstream& file )
+bool WriteHeader( IDF3_BOARD& board, std::ostream& file )
 {
     std::string bname = board.GetBoardName();
 
@@ -320,7 +320,7 @@ bool WriteHeader( IDF3_BOARD& board, std::ofstream& file )
 }
 
 
-bool MakeBoard( IDF3_BOARD& board, std::ofstream& file )
+bool MakeBoard( IDF3_BOARD& board, std::ostream& file )
 {
     VRML_LAYER vpcb;
 
@@ -484,7 +484,7 @@ bool AddSegment( VRML_LAYER& model, IDF_SEGMENT* seg, int icont, int iseg )
 }
 
 
-bool WriteTriangles( std::ofstream& file, VRML_IDS* vID, VRML_LAYER* layer, bool plane,
+bool WriteTriangles( std::ostream& file, VRML_IDS* vID, VRML_LAYER* layer, bool plane,
                      bool top, double top_z, double bottom_z, int precision, bool compact )
 {
     if( vID == NULL || layer == NULL )
@@ -699,7 +699,7 @@ inline void TransformPoint( IDF_SEGMENT& seg, double frac, bool bottom,
     return;
 }
 
-bool MakeComponents( IDF3_BOARD& board, std::ofstream& file, bool compact )
+bool MakeComponents( IDF3_BOARD& board, std::ostream& file, bool compact )
 {
     int cidx = 2;   // color index; start at 2 since 0,1 are special (board, NOGEOM_NOPART)
 
@@ -883,7 +883,7 @@ VRML_IDS* GetColor( boost::ptr_map<const std::string, VRML_IDS>& cmap, int& inde
 }
 
 
-bool MakeOtherOutlines( IDF3_BOARD& board, std::ofstream& file )
+bool MakeOtherOutlines( IDF3_BOARD& board, std::ostream& file )
 {
     int cidx = 2;   // color index; start at 2 since 0,1 are special (board, NOGEOM_NOPART)
 
diff --git a/utils/idftools/idf_common.cpp b/utils/idftools/idf_common.cpp
index a346af9cf..b742c1207 100644
--- a/utils/idftools/idf_common.cpp
+++ b/utils/idftools/idf_common.cpp
@@ -3,7 +3,7 @@
  *
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2013-2014  Cirilo Bernardo
+ * Copyright (C) 2013-2017  Cirilo Bernardo
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -28,7 +28,6 @@
 #include <list>
 #include <string>
 #include <iostream>
-#include <fstream>
 #include <sstream>
 #include <iomanip>
 #include <cerrno>
@@ -91,7 +90,7 @@ IDF_NOTE::IDF_NOTE()
 }
 
 
-bool IDF_NOTE::readNote( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState,
+bool IDF_NOTE::readNote( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState,
                          IDF3::IDF_UNIT aBoardUnit )
 {
     std::string iline;      // the input line
@@ -250,7 +249,7 @@ bool IDF_NOTE::readNote( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardStat
 }
 
 
-bool IDF_NOTE::writeNote( std::ofstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit )
+bool IDF_NOTE::writeNote( std::ostream& aBoardFile, IDF3::IDF_UNIT aBoardUnit )
 {
     if( aBoardUnit == UNIT_THOU )
     {
@@ -403,7 +402,7 @@ bool IDF_DRILL_DATA::Matches( double aDrillDia, double aPosX, double aPosY )
     return false;
 }
 
-bool IDF_DRILL_DATA::read( std::ifstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit,
+bool IDF_DRILL_DATA::read( std::istream& aBoardFile, IDF3::IDF_UNIT aBoardUnit,
                            IDF3::FILE_STATE aBoardState, IDF3::IDF_VERSION aIdfVersion )
 {
     std::string iline;      // the input line
@@ -651,7 +650,7 @@ bool IDF_DRILL_DATA::read( std::ifstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit,
     return true;
 }
 
-void IDF_DRILL_DATA::write( std::ofstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit )
+void IDF_DRILL_DATA::write( std::ostream& aBoardFile, IDF3::IDF_UNIT aBoardUnit )
 {
     std::string holestr;
     std::string refstr;
diff --git a/utils/idftools/idf_common.h b/utils/idftools/idf_common.h
index 806ec3cee..8e29f5531 100644
--- a/utils/idftools/idf_common.h
+++ b/utils/idftools/idf_common.h
@@ -5,7 +5,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2013-2014  Cirilo Bernardo
+ * Copyright (C) 2013-2017  Cirilo Bernardo
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -280,7 +280,7 @@ private:
      * @return bool: true if a note item was read, false otherwise. In case of unrecoverable errors
      * an exception is thrown
      */
-    bool readNote( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState, IDF3::IDF_UNIT aBoardUnit );
+    bool readNote( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState, IDF3::IDF_UNIT aBoardUnit );
 
     /**
      * Function writeNote
@@ -292,7 +292,7 @@ private:
      * @return bool: true if the item was successfully written, false otherwise. In case of
      * unrecoverable errors an exception is thrown
      */
-    bool writeNote( std::ofstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit );
+    bool writeNote( std::ostream& aBoardFile, IDF3::IDF_UNIT aBoardUnit );
 
 public:
     IDF_NOTE();
@@ -366,7 +366,7 @@ private:
      * @return bool: true if data was successfully read, otherwise false. In case of an
      * unrecoverable error an exception is thrown
      */
-    bool read( std::ifstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit, IDF3::FILE_STATE aBoardState,
+    bool read( std::istream& aBoardFile, IDF3::IDF_UNIT aBoardUnit, IDF3::FILE_STATE aBoardState,
                IDF3::IDF_VERSION aIdfVersion );
 
     /**
@@ -377,7 +377,7 @@ private:
      * @param aBoardFile is an open BOARD file
      * @param aBoardUnit is the native unit of the output file
      */
-    void write( std::ofstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit );
+    void write( std::ostream& aBoardFile, IDF3::IDF_UNIT aBoardUnit );
 
 public:
     /**
diff --git a/utils/idftools/idf_helpers.cpp b/utils/idftools/idf_helpers.cpp
index a9ab11e40..20bd00e47 100644
--- a/utils/idftools/idf_helpers.cpp
+++ b/utils/idftools/idf_helpers.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2014  Cirilo Bernardo
+ * Copyright (C) 2014-2017  Cirilo Bernardo
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -32,7 +32,7 @@ using namespace std;
 using namespace IDF3;
 
 // fetch a line from the given input file and trim the ends
-bool IDF3::FetchIDFLine( std::ifstream& aModel, std::string& aLine, bool& isComment, std::streampos& aFilePos )
+bool IDF3::FetchIDFLine( std::istream& aModel, std::string& aLine, bool& isComment, std::streampos& aFilePos )
 {
     aLine = "";
     aFilePos = aModel.tellg();
@@ -205,7 +205,7 @@ bool IDF3::ParseIDFLayer( const std::string& aToken, IDF3::IDF_LAYER& aLayer )
 }
 
 
-bool IDF3::WriteLayersText( std::ofstream& aBoardFile, IDF3::IDF_LAYER aLayer )
+bool IDF3::WriteLayersText( std::ostream& aBoardFile, IDF3::IDF_LAYER aLayer )
 {
     switch( aLayer )
     {
diff --git a/utils/idftools/idf_helpers.h b/utils/idftools/idf_helpers.h
index 561572ec3..a64ed352e 100644
--- a/utils/idftools/idf_helpers.h
+++ b/utils/idftools/idf_helpers.h
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2014  Cirilo Bernardo
+ * Copyright (C) 2014-2017  Cirilo Bernardo
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -25,7 +25,7 @@
 #define IDF_HELPERS_H
 
 #include <wx/wx.h>
-#include <fstream>
+#include <iostream>
 #include <string>
 #include <idf_common.h>
 
@@ -82,7 +82,7 @@ namespace IDF3
  *
  * @return bool: true if a line was read and was not empty; otherwise false
  */
-bool FetchIDFLine( std::ifstream& aModel, std::string& aLine, bool& isComment, std::streampos& aFilePos );
+bool FetchIDFLine( std::istream& aModel, std::string& aLine, bool& isComment, std::streampos& aFilePos );
 
 
 /**
@@ -145,7 +145,7 @@ bool ParseIDFLayer( const std::string& aToken, IDF3::IDF_LAYER& aLayer );
  *
  * @return bool: true if the data was successfully written, otherwise false
  */
-bool WriteLayersText( std::ofstream& aBoardFile, IDF3::IDF_LAYER aLayer );
+bool WriteLayersText( std::ostream& aBoardFile, IDF3::IDF_LAYER aLayer );
 
 
 /**
diff --git a/utils/idftools/idf_outlines.cpp b/utils/idftools/idf_outlines.cpp
index 43523f94e..a53ea200f 100644
--- a/utils/idftools/idf_outlines.cpp
+++ b/utils/idftools/idf_outlines.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2014  Cirilo Bernardo
+ * Copyright (C) 2014-2017  Cirilo Bernardo
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -151,7 +151,7 @@ IDF3::OUTLINE_TYPE BOARD_OUTLINE::GetOutlineType( void )
     return outlineType;
 }
 
-void BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile, IDF3::IDF_VERSION aIdfVersion )
+void BOARD_OUTLINE::readOutlines( std::istream& aBoardFile, IDF3::IDF_VERSION aIdfVersion )
 {
     // reads the outline data from a file
     double x, y, ang;
@@ -654,7 +654,7 @@ void BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile, IDF3::IDF_VERSION a
     return;
 }
 
-bool BOARD_OUTLINE::writeComments( std::ofstream& aBoardFile )
+bool BOARD_OUTLINE::writeComments( std::ostream& aBoardFile )
 {
     if( comments.empty() )
         return true;
@@ -671,7 +671,7 @@ bool BOARD_OUTLINE::writeComments( std::ofstream& aBoardFile )
     return !aBoardFile.fail();
 }
 
-bool BOARD_OUTLINE::writeOwner( std::ofstream& aBoardFile )
+bool BOARD_OUTLINE::writeOwner( std::ostream& aBoardFile )
 {
     switch( owner )
     {
@@ -691,7 +691,7 @@ bool BOARD_OUTLINE::writeOwner( std::ofstream& aBoardFile )
     return !aBoardFile.fail();
 }
 
-void BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutline, size_t aIndex )
+void BOARD_OUTLINE::writeOutline( std::ostream& aBoardFile, IDF_OUTLINE* aOutline, size_t aIndex )
 {
     std::list<IDF_SEGMENT*>::iterator bo;
     std::list<IDF_SEGMENT*>::iterator eo;
@@ -955,7 +955,7 @@ void BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli
     return;
 }
 
-void BOARD_OUTLINE::writeOutlines( std::ofstream& aBoardFile )
+void BOARD_OUTLINE::writeOutlines( std::ostream& aBoardFile )
 {
     if( outlines.empty() )
         return;
@@ -1029,7 +1029,7 @@ double BOARD_OUTLINE::GetThickness( void )
     return thickness;
 }
 
-void BOARD_OUTLINE::readData( std::ifstream& aBoardFile, const std::string& aHeader,
+void BOARD_OUTLINE::readData( std::istream& aBoardFile, const std::string& aHeader,
                               IDF3::IDF_VERSION aIdfVersion )
 {
     //  BOARD_OUTLINE (PANEL_OUTLINE)
@@ -1223,7 +1223,7 @@ void BOARD_OUTLINE::readData( std::ifstream& aBoardFile, const std::string& aHea
 }
 
 
-void BOARD_OUTLINE::writeData( std::ofstream& aBoardFile )
+void BOARD_OUTLINE::writeData( std::ostream& aBoardFile )
 {
     writeComments( aBoardFile );
 
@@ -1610,7 +1610,7 @@ IDF3::IDF_LAYER OTHER_OUTLINE::GetSide( void )
     return side;
 }
 
-void OTHER_OUTLINE::readData( std::ifstream& aBoardFile, const std::string& aHeader,
+void OTHER_OUTLINE::readData( std::istream& aBoardFile, const std::string& aHeader,
                               IDF3::IDF_VERSION aIdfVersion )
 {
     // OTHER_OUTLINE/VIA_KEEPOUT
@@ -1869,7 +1869,7 @@ void OTHER_OUTLINE::readData( std::ifstream& aBoardFile, const std::string& aHea
     return;
 }
 
-void OTHER_OUTLINE::writeData( std::ofstream& aBoardFile )
+void OTHER_OUTLINE::writeData( std::ostream& aBoardFile )
 {
     // this section is optional; do not write if not required
     if( outlines.empty() )
@@ -1970,7 +1970,7 @@ IDF3::IDF_LAYER ROUTE_OUTLINE::GetLayers( void )
     return layers;
 }
 
-void ROUTE_OUTLINE::readData( std::ifstream& aBoardFile, const std::string& aHeader,
+void ROUTE_OUTLINE::readData( std::istream& aBoardFile, const std::string& aHeader,
                               IDF3::IDF_VERSION aIdfVersion )
 {
     //  ROUTE_OUTLINE (or ROUTE_KEEPOUT)
@@ -2183,7 +2183,7 @@ void ROUTE_OUTLINE::readData( std::ifstream& aBoardFile, const std::string& aHea
 }
 
 
-void ROUTE_OUTLINE::writeData( std::ofstream& aBoardFile )
+void ROUTE_OUTLINE::writeData( std::ostream& aBoardFile )
 {
     // this section is optional; do not write if not required
     if( outlines.empty() )
@@ -2318,7 +2318,7 @@ double PLACE_OUTLINE::GetMaxHeight( void )
     return thickness;
 }
 
-void PLACE_OUTLINE::readData( std::ifstream& aBoardFile, const std::string& aHeader,
+void PLACE_OUTLINE::readData( std::istream& aBoardFile, const std::string& aHeader,
                               IDF3::IDF_VERSION aIdfVersion )
 {
     //  PLACE_OUTLINE/KEEPOUT
@@ -2558,7 +2558,7 @@ void PLACE_OUTLINE::readData( std::ifstream& aBoardFile, const std::string& aHea
     return;
 }
 
-void PLACE_OUTLINE::writeData( std::ofstream& aBoardFile )
+void PLACE_OUTLINE::writeData( std::ostream& aBoardFile )
 {
     // this section is optional; do not write if not required
     if( outlines.empty() )
@@ -2742,7 +2742,7 @@ const std::string& GROUP_OUTLINE::GetGroupName( void )
 }
 
 
-void GROUP_OUTLINE::readData( std::ifstream& aBoardFile, const std::string& aHeader,
+void GROUP_OUTLINE::readData( std::istream& aBoardFile, const std::string& aHeader,
                               IDF3::IDF_VERSION aIdfVersion )
 {
     //  Placement Group
@@ -2901,7 +2901,7 @@ void GROUP_OUTLINE::readData( std::ifstream& aBoardFile, const std::string& aHea
 }
 
 
-void GROUP_OUTLINE::writeData( std::ofstream& aBoardFile )
+void GROUP_OUTLINE::writeData( std::ostream& aBoardFile )
 {
     // this section is optional; do not write if not required
     if( outlines.empty() )
@@ -2974,7 +2974,7 @@ IDF3_COMP_OUTLINE::IDF3_COMP_OUTLINE( IDF3_BOARD* aParent )
     return;
 }
 
-void IDF3_COMP_OUTLINE::readProperties( std::ifstream& aLibFile )
+void IDF3_COMP_OUTLINE::readProperties( std::istream& aLibFile )
 {
     bool quoted = false;
     bool comment = false;
@@ -3094,7 +3094,7 @@ void IDF3_COMP_OUTLINE::readProperties( std::ifstream& aLibFile )
 }
 
 
-bool IDF3_COMP_OUTLINE::writeProperties( std::ofstream& aLibFile )
+bool IDF3_COMP_OUTLINE::writeProperties( std::ostream& aLibFile )
 {
     if( props.empty() )
         return true;
@@ -3111,7 +3111,7 @@ bool IDF3_COMP_OUTLINE::writeProperties( std::ofstream& aLibFile )
     return !aLibFile.fail();
 }
 
-void IDF3_COMP_OUTLINE::readData( std::ifstream& aLibFile, const std::string& aHeader,
+void IDF3_COMP_OUTLINE::readData( std::istream& aLibFile, const std::string& aHeader,
                                   IDF3::IDF_VERSION aIdfVersion )
 {
     //  .ELECTRICAL/.MECHANICAL
@@ -3377,7 +3377,7 @@ void IDF3_COMP_OUTLINE::readData( std::ifstream& aLibFile, const std::string& aH
 }
 
 
-void IDF3_COMP_OUTLINE::writeData( std::ofstream& aLibFile )
+void IDF3_COMP_OUTLINE::writeData( std::ostream& aLibFile )
 {
     if( refNum == 0 )
         return;    // nothing to do
diff --git a/utils/idftools/idf_outlines.h b/utils/idftools/idf_outlines.h
index d50d149a8..74149ab4f 100644
--- a/utils/idftools/idf_outlines.h
+++ b/utils/idftools/idf_outlines.h
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2014  Cirilo Bernardo
+ * Copyright (C) 2014-2017  Cirilo Bernardo
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -28,8 +28,6 @@
 #include <string>
 #include <list>
 #include <map>
-#include <wx/string.h>
-#include <wx/filename.h>
 
 #include <idf_common.h>
 
@@ -104,15 +102,15 @@ protected:
     double                      thickness;  // Board/Extrude Thickness or Height (IDF spec)
 
     // Read outline data from a BOARD or LIBRARY file's outline section
-    void readOutlines( std::ifstream& aBoardFile, IDF3::IDF_VERSION aIdfVersion );
+    void readOutlines( std::istream& aBoardFile, IDF3::IDF_VERSION aIdfVersion );
     // Write comments to a BOARD or LIBRARY file (must not be within a SECTION as per IDFv3 spec)
-    bool writeComments( std::ofstream& aBoardFile );
+    bool writeComments( std::ostream& aBoardFile );
     // Write the outline owner to a BOARD file
-    bool writeOwner( std::ofstream& aBoardFile );
+    bool writeOwner( std::ostream& aBoardFile );
     // Write the data of a single outline object
-    void writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutline, size_t aIndex );
+    void writeOutline( std::ostream& aBoardFile, IDF_OUTLINE* aOutline, size_t aIndex );
     // Iterate through the outlines and write out all data
-    void writeOutlines( std::ofstream& aBoardFile );  // write outline data (no headers)
+    void writeOutlines( std::ostream& aBoardFile );  // write outline data (no headers)
     // Clear internal list of outlines
     void clearOutlines( void );
     /**
@@ -135,7 +133,7 @@ protected:
      * @param aBoardFile is an IDFv3 file opened for reading
      * @param aHeader is the ".BOARD_OUTLINE" header line as read by FetchIDFLine
      */
-    virtual void readData( std::ifstream& aBoardFile, const std::string& aHeader,
+    virtual void readData( std::istream& aBoardFile, const std::string& aHeader,
                            IDF3::IDF_VERSION aIdfVersion );
 
     /**
@@ -145,7 +143,7 @@ protected:
      *
      * @param aBoardFile is an IDFv3 file opened for writing
      */
-    virtual void writeData( std::ofstream& aBoardFile );
+    virtual void writeData( std::ostream& aBoardFile );
 
 public:
     BOARD_OUTLINE();
@@ -363,7 +361,7 @@ private:
      * @param aBoardFile is an IDFv3 file open for reading
      * @param aHeader is the .OTHER_OUTLINE header as read via FetchIDFLine
      */
-    virtual void readData( std::ifstream& aBoardFile, const std::string& aHeader,
+    virtual void readData( std::istream& aBoardFile, const std::string& aHeader,
                            IDF3::IDF_VERSION aIdfVersion ) override;
 
     /**
@@ -374,7 +372,7 @@ private:
      *
      * @return bool: true if the data was successfully written, otherwise false.
      */
-    virtual void writeData( std::ofstream& aBoardFile ) override;
+    virtual void writeData( std::ostream& aBoardFile ) override;
 
 public:
     OTHER_OUTLINE( IDF3_BOARD* aParent );
@@ -431,14 +429,14 @@ private:
      * @param aBoardFile is an open IDFv3 board file
      * @param aHeader is the .ROUTE_OUTLINE header as returned by FetchIDFLine
      */
-    virtual void readData( std::ifstream& aBoardFile, const std::string& aHeader,
+    virtual void readData( std::istream& aBoardFile, const std::string& aHeader,
                            IDF3::IDF_VERSION aIdfVersion ) override;
 
     /**
      * Function writeData
      * writes the ROUTE_OUTLINE data to an open IDFv3 file
      */
-    virtual void writeData( std::ofstream& aBoardFile ) override;
+    virtual void writeData( std::ostream& aBoardFile ) override;
 
 protected:
     IDF3::IDF_LAYER layers; // Routing layers (IDF spec)
@@ -483,7 +481,7 @@ private:
      * @param aBoardFile is an IDFv3 file opened for reading
      * @param aHeader is the .PLACE_OUTLINE header as returned by FetchIDFLine
      */
-    virtual void readData( std::ifstream& aBoardFile, const std::string& aHeader,
+    virtual void readData( std::istream& aBoardFile, const std::string& aHeader,
                            IDF3::IDF_VERSION aIdfVersion ) override;
 
     /**
@@ -494,7 +492,7 @@ private:
      *
      * @return bool: true if the data was successfully written, otherwise false
      */
-    virtual void writeData( std::ofstream& aBoardFile ) override;
+    virtual void writeData( std::ostream& aBoardFile ) override;
 
 protected:
     IDF3::IDF_LAYER side;   // Board Side [TOP/BOTTOM/BOTH ONLY] (IDF spec)
@@ -592,7 +590,7 @@ private:
      * @param aBoardFile is an open IDFv3 file
      * @param aHeader is the .PLACE_REGION header as returned by FetchIDFLine
      */
-    virtual void readData( std::ifstream& aBoardFile, const std::string& aHeader,
+    virtual void readData( std::istream& aBoardFile, const std::string& aHeader,
                            IDF3::IDF_VERSION aIdfVersion ) override;
 
     /**
@@ -603,7 +601,7 @@ private:
      *
      * @return bool: true if the data is successfully written, otherwise false
      */
-    virtual void writeData( std::ofstream& aBoardFile ) override;
+    virtual void writeData( std::ostream& aBoardFile ) override;
 
 public:
     GROUP_OUTLINE( IDF3_BOARD* aParent );
@@ -661,8 +659,8 @@ private:
 
     std::map< std::string, std::string >    props;      // properties list
 
-    void readProperties( std::ifstream& aLibFile );
-    bool writeProperties( std::ofstream& aLibFile );
+    void readProperties( std::istream& aLibFile );
+    bool writeProperties( std::ostream& aLibFile );
 
     /**
      * Function readData
@@ -672,7 +670,7 @@ private:
      * @param aLibFile is an open IDFv3 Library file
      * @param aHeader is the .ELECTRICAL or .MECHANICAL header as returned by FetchIDFLine
      */
-    virtual void readData( std::ifstream& aLibFile, const std::string& aHeader,
+    virtual void readData( std::istream& aLibFile, const std::string& aHeader,
                            IDF3::IDF_VERSION aIdfVersion ) override;
 
     /**
@@ -683,7 +681,7 @@ private:
      *
      * @return bool: true if the data was successfully written, otherwise false
      */
-    virtual void writeData( std::ofstream& aLibFile ) override;
+    virtual void writeData( std::ostream& aLibFile ) override;
 
     /**
      * Function incrementRef
diff --git a/utils/idftools/idf_parser.cpp b/utils/idftools/idf_parser.cpp
index 5768c3056..fc159f328 100644
--- a/utils/idftools/idf_parser.cpp
+++ b/utils/idftools/idf_parser.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2014  Cirilo Bernardo
+ * Copyright (C) 2014-2017  Cirilo Bernardo
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -24,14 +24,16 @@
 
 #include <iostream>
 #include <iomanip>
-#include <fstream>
 #include <sstream>
 #include <cmath>
 #include <cerrno>
 #include <algorithm>
+#include <wx/string.h>
+#include <wx/filename.h>
 
-#include <idf_parser.h>
-#include <idf_helpers.h>
+#include "idf_parser.h"
+#include "idf_helpers.h"
+#include "streamwrapper.h"
 
 using namespace std;
 using namespace IDF3;
@@ -229,7 +231,7 @@ bool IDF3_COMP_OUTLINE_DATA::SetOutline( IDF3_COMP_OUTLINE* aOutline )
 }
 
 
-bool IDF3_COMP_OUTLINE_DATA::readPlaceData( std::ifstream &aBoardFile,
+bool IDF3_COMP_OUTLINE_DATA::readPlaceData( std::istream &aBoardFile,
                                             IDF3::FILE_STATE& aBoardState,
                                             IDF3_BOARD *aBoard,
                                             IDF3::IDF_VERSION aIdfVersion,
@@ -713,7 +715,7 @@ bool IDF3_COMP_OUTLINE_DATA::readPlaceData( std::ifstream &aBoardFile,
 }   // IDF3_COMP_OUTLINE_DATA::readPlaceData
 
 
-void IDF3_COMP_OUTLINE_DATA::writePlaceData( std::ofstream& aBoardFile,
+void IDF3_COMP_OUTLINE_DATA::writePlaceData( std::ostream& aBoardFile,
                                              double aXpos, double aYpos, double aAngle,
                                              const std::string aRefDes,
                                              IDF3::IDF_PLACEMENT aPlacement,
@@ -1291,7 +1293,7 @@ bool IDF3_COMPONENT::SetPlacement( IDF3::IDF_PLACEMENT aPlacementValue )
     return true;
 }
 
-bool IDF3_COMPONENT::writeDrillData( std::ofstream& aBoardFile )
+bool IDF3_COMPONENT::writeDrillData( std::ostream& aBoardFile )
 {
     if( drills.empty() )
         return true;
@@ -1309,7 +1311,7 @@ bool IDF3_COMPONENT::writeDrillData( std::ofstream& aBoardFile )
 }
 
 
-bool IDF3_COMPONENT::writePlaceData( std::ofstream& aBoardFile )
+bool IDF3_COMPONENT::writePlaceData( std::ostream& aBoardFile )
 {
     if( components.empty() )
         return true;
@@ -1330,7 +1332,6 @@ bool IDF3_COMPONENT::writePlaceData( std::ofstream& aBoardFile )
 IDF3_BOARD::IDF3_BOARD( IDF3::CAD_TYPE aCadType )
 {
     idfVer         = IDF_V3;
-    state          = FILE_START;
     cadType        = aCadType;
     userPrec       = 5;
     userScale      = 1.0;
@@ -1608,7 +1609,7 @@ double IDF3_BOARD::GetBoardThickness( void )
 
 
 // read the DRILLED HOLES section
-void IDF3_BOARD::readBrdDrills( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState )
+void IDF3_BOARD::readBrdDrills( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState )
 {
     IDF_DRILL_DATA drill;
 
@@ -1631,7 +1632,7 @@ void IDF3_BOARD::readBrdDrills( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBo
 
 
 // read the NOTES section
-void IDF3_BOARD::readBrdNotes( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState )
+void IDF3_BOARD::readBrdNotes( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState )
 {
     IDF_NOTE note;
 
@@ -1647,7 +1648,7 @@ void IDF3_BOARD::readBrdNotes( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoa
 
 
 // read the component placement section
-void IDF3_BOARD::readBrdPlacement( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState, bool aNoSubstituteOutlines )
+void IDF3_BOARD::readBrdPlacement( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState, bool aNoSubstituteOutlines )
 {
     IDF3_COMP_OUTLINE_DATA oldata;
 
@@ -1658,7 +1659,7 @@ void IDF3_BOARD::readBrdPlacement( std::ifstream& aBoardFile, IDF3::FILE_STATE&
 
 
 // read the board HEADER
-void IDF3_BOARD::readBrdHeader( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState )
+void IDF3_BOARD::readBrdHeader( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState )
 {
     std::string iline;      // the input line
     bool isComment;         // true if a line just read in is a comment line
@@ -1874,7 +1875,7 @@ void IDF3_BOARD::readBrdHeader( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBo
 
 
 // read individual board sections; pay attention to IDFv3 section specifications
-void IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState,
+void IDF3_BOARD::readBrdSection( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState,
                                  bool aNoSubstituteOutlines )
 {
     std::list< std::string > comments;  // comments associated with a section
@@ -2298,15 +2299,13 @@ void IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aB
 // read the board file data
 void IDF3_BOARD::readBoardFile( const std::string& aFileName, bool aNoSubstituteOutlines )
 {
-    std::ifstream brd;
-
-    brd.exceptions ( std::ifstream::badbit );
+    OPEN_ISTREAM( brd, aFileName.c_str() );
 
     try
     {
-        brd.open( aFileName.c_str(), std::ios_base::in | std::ios_base::binary );
+        brd.exceptions ( std::ios_base::badbit );
 
-        if( !brd.is_open() )
+        if( brd.fail() )
         {
             ostringstream ostr;
             ostr << "\n* could not open file: '" << aFileName << "'";
@@ -2314,6 +2313,7 @@ void IDF3_BOARD::readBoardFile( const std::string& aFileName, bool aNoSubstitute
             throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
         }
 
+        brd.imbue( std::locale( "C" ) );
         std::string iline;      // the input line
         bool isComment;         // true if a line just read in is a comment line
         std::streampos pos;
@@ -2341,12 +2341,11 @@ void IDF3_BOARD::readBoardFile( const std::string& aFileName, bool aNoSubstitute
             // check if we have valid data
             if( brd.eof() && state >= IDF3::FILE_OUTLINE && state < IDF3::FILE_INVALID )
             {
-                brd.close();
+                CLOSE_STREAM( brd );
                 return;
             }
 
-            brd.close();
-
+            CLOSE_STREAM( brd );
             ostringstream ostr;
             ostr << "\n* empty IDF file: '" << aFileName << "'";
 
@@ -2384,20 +2383,17 @@ void IDF3_BOARD::readBoardFile( const std::string& aFileName, bool aNoSubstitute
     catch( const std::exception& )
     {
         brd.exceptions ( std::ios_base::goodbit );
-
-        if( brd.is_open() )
-            brd.close();
-
+        CLOSE_STREAM( brd );
         throw;
     }
 
-    brd.close();
+    CLOSE_STREAM( brd );
     return;
 } // readBoardFile()
 
 
 // read the library sections (outlines)
-void IDF3_BOARD::readLibSection( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibState, IDF3_BOARD* aBoard )
+void IDF3_BOARD::readLibSection( std::istream& aLibFile, IDF3::FILE_STATE& aLibState, IDF3_BOARD* aBoard )
 {
     if( aBoard == NULL )
     {
@@ -2527,7 +2523,7 @@ void IDF3_BOARD::readLibSection( std::ifstream& aLibFile, IDF3::FILE_STATE& aLib
 
 
 // read the library HEADER
-void IDF3_BOARD::readLibHeader( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibState )
+void IDF3_BOARD::readLibHeader( std::istream& aLibFile, IDF3::FILE_STATE& aLibState )
 {
     std::string iline;      // the input line
     bool isComment;         // true if a line just read in is a comment line
@@ -2685,14 +2681,21 @@ void IDF3_BOARD::readLibHeader( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibS
 // read the library file data
 void IDF3_BOARD::readLibFile( const std::string& aFileName )
 {
-    std::ifstream lib;
-
-    lib.exceptions ( std::ifstream::badbit );
+    OPEN_ISTREAM( lib, aFileName.c_str() );
 
     try
     {
-        lib.open( aFileName.c_str(), std::ios_base::in | std::ios_base::binary );
+        lib.exceptions ( std::ios_base::badbit );
+
+        if( lib.fail() )
+        {
+            ostringstream ostr;
+            ostr << "\n* could not open file: '" << aFileName << "'";
+
+            throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
+        }
 
+        lib.imbue( std::locale( "C" ) );
         IDF3::FILE_STATE state = IDF3::FILE_START;
 
         readLibHeader( lib, state );
@@ -2702,14 +2705,11 @@ void IDF3_BOARD::readLibFile( const std::string& aFileName )
     catch( const std::exception& )
     {
         lib.exceptions ( std::ios_base::goodbit );
-
-        if( lib.is_open() )
-            lib.close();
-
+        CLOSE_STREAM( lib );
         throw;
     }
 
-    lib.close();
+    CLOSE_STREAM( lib );
     return;
 }
 
@@ -2820,13 +2820,21 @@ bool IDF3_BOARD::ReadFile( const wxString& aFullFileName, bool aNoSubstituteOutl
 // write the library file data
 bool IDF3_BOARD::writeLibFile( const std::string& aFileName )
 {
-    std::ofstream lib;
-    lib.exceptions( std::ofstream::failbit );
+    OPEN_OSTREAM( lib, aFileName.c_str() );
 
     try
     {
-        lib.open( aFileName.c_str(), std::ios_base::out );
+        lib.exceptions( std::ios_base::failbit );
 
+        if( lib.fail() )
+        {
+            ostringstream ostr;
+            ostr << "\n* could not open file: '" << aFileName << "'";
+
+            throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
+        }
+
+        lib.imbue( std::locale( "C" ) );
         wxDateTime tdate( time( NULL ) );
 
         if( idfSource.empty() )
@@ -2856,28 +2864,32 @@ bool IDF3_BOARD::writeLibFile( const std::string& aFileName )
     catch( const std::exception& )
     {
         lib.exceptions( std::ios_base::goodbit );
-
-        if( lib.is_open() )
-            lib.close();
-
+        CLOSE_STREAM( lib );
         throw;
     }
 
-    lib.close();
-
+    CLOSE_STREAM( lib );
     return true;
 }
 
 // write the board file data
 void IDF3_BOARD::writeBoardFile( const std::string& aFileName )
 {
-    std::ofstream brd;
-    brd.exceptions( std::ofstream::failbit );
+    OPEN_OSTREAM( brd, aFileName.c_str() );
 
     try
     {
-        brd.open( aFileName.c_str(), std::ios_base::out );
+        brd.exceptions( std::ostream::failbit );
+
+        if( brd.fail() )
+        {
+            ostringstream ostr;
+            ostr << "\n* could not open file: '" << aFileName << "'";
 
+            throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
+        }
+
+        brd.imbue( std::locale( "C" ) );
         wxDateTime tdate( time( NULL ) );
 
         if( idfSource.empty() )
@@ -3123,15 +3135,11 @@ void IDF3_BOARD::writeBoardFile( const std::string& aFileName )
     catch( const std::exception& )
     {
         brd.exceptions( std::ios_base::goodbit );
-
-        if( brd.is_open() )
-            brd.close();
-
+        CLOSE_STREAM( brd );
         throw;
     }
 
-    brd.close();
-
+    CLOSE_STREAM( brd );
     return;
 }
 
@@ -3889,14 +3897,22 @@ IDF3_COMP_OUTLINE* IDF3_BOARD::GetComponentOutline( wxString aFullFileName )
         return NULL;
     }
 
-    std::ifstream model;
-    model.exceptions ( std::ifstream::badbit );
+    OPEN_ISTREAM( model, fname.c_str() );
 
     try
     {
-        model.open( fname.c_str(), std::ios_base::in | std::ios_base::binary );
+        model.exceptions ( std::ios_base::badbit );
+
+        if( model.fail() )
+        {
+            ostringstream ostr;
+            ostr << "\n* could not open file: '" << fname << "'";
 
+            throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
+        }
 
+
+        model.imbue( std::locale( "C" ) );
         std::string iline;      // the input line
         bool isComment;         // true if a line just read in is a comment line
         std::streampos pos;
@@ -3939,18 +3955,13 @@ IDF3_COMP_OUTLINE* IDF3_BOARD::GetComponentOutline( wxString aFullFileName )
     catch( const std::exception& e )
     {
         delete cp;
-
         model.exceptions ( std::ios_base::goodbit );
-
-        if( model.is_open() )
-            model.close();
-
+        CLOSE_STREAM( model );
         errormsg = e.what();
-
         return NULL;
     }
 
-    model.close();
+    CLOSE_STREAM( model );
 
     // check the unique ID against the list from library components
     std::list< std::string >::iterator lsts = uidLibList.begin();
@@ -4291,7 +4302,6 @@ void IDF3_BOARD::Clear( void )
     boardName.clear();
     olnBoard.setThickness( thickness );
 
-    state     = FILE_START;
     unit      = UNIT_MM;
     userScale = 1.0;
     userXoff  = 0.0;
diff --git a/utils/idftools/idf_parser.h b/utils/idftools/idf_parser.h
index e666e17c7..b64fcf8b0 100644
--- a/utils/idftools/idf_parser.h
+++ b/utils/idftools/idf_parser.h
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2014  Cirilo Bernardo
+ * Copyright (C) 2014-2017  Cirilo Bernardo
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -91,7 +91,7 @@ private:
      * data was encountered or an error occurred. if an error occurred then
      * an exception is thrown.
      */
-    bool readPlaceData( std::ifstream &aBoardFile, IDF3::FILE_STATE& aBoardState,
+    bool readPlaceData( std::istream &aBoardFile, IDF3::FILE_STATE& aBoardState,
                         IDF3_BOARD *aBoard, IDF3::IDF_VERSION aIdfVersion,
                         bool aNoSubstituteOutlines );
 
@@ -109,7 +109,7 @@ private:
      *
      * @return bool: true if data was successfully written, otherwise false
      */
-    void writePlaceData( std::ofstream& aBoardFile, double aXpos, double aYpos, double aAngle,
+    void writePlaceData( std::ostream& aBoardFile, double aXpos, double aYpos, double aAngle,
                          const std::string aRefDes, IDF3::IDF_PLACEMENT aPlacement,
                          IDF3::IDF_LAYER aSide );
 
@@ -233,7 +233,7 @@ private:
      *
      * @return bool: true if the operation succeeded, otherwise false
      */
-    bool writeDrillData( std::ofstream& aBoardFile );
+    bool writeDrillData( std::ostream& aBoardFile );
 
     /**
      * Function WritePlaceData
@@ -243,7 +243,7 @@ private:
      *
      * @return bool: true if the operation succeeded, otherwise false
      */
-    bool writePlaceData( std::ofstream& aBoardFile );
+    bool writePlaceData( std::ostream& aBoardFile );
 
 #ifndef DISABLE_IDF_OWNERSHIP
     bool checkOwnership( int aSourceLine, const char* aSourceFunc );
@@ -474,7 +474,6 @@ private:
     std::map< std::string, IDF3_COMPONENT*> components;         // drill and placement data for components
     std::map< std::string, IDF3_COMP_OUTLINE*> compOutlines;    // component outlines (data for library file)
     std::string boardName;
-    IDF3::FILE_STATE state;
     IDF3::CAD_TYPE   cadType;
     IDF3::IDF_UNIT   unit;
     IDF3::IDF_VERSION   idfVer;                                 // IDF version of Board or Library
@@ -526,18 +525,18 @@ private:
     bool delCompDrill( double aDia, double aXpos, double aYpos, std::string aRefDes );
 
     // read the DRILLED HOLES section
-    void readBrdDrills( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState );
+    void readBrdDrills( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState );
     // read the NOTES section
-    void readBrdNotes( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState );
+    void readBrdNotes( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState );
     // read the component placement section
-    void readBrdPlacement( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState,
+    void readBrdPlacement( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState,
                            bool aNoSubstituteOutlines );
     // read the board HEADER
-    void readBrdHeader( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState );
+    void readBrdHeader( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState );
     // read individual board sections; pay attention to IDFv3 section specifications
     // exception thrown on unrecoverable errors. state flag set to FILE_PLACEMENT
     // upon reading the PLACEMENT file; according to IDFv3 this is the final section
-    void readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState,
+    void readBrdSection( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState,
                          bool aNoSubstituteOutlines );
     // read the board file data
     void readBoardFile( const std::string& aFileName, bool aNoSubstituteOutlines );
@@ -546,9 +545,9 @@ private:
     void writeBoardFile( const std::string& aFileName );
 
     // read the library sections (outlines)
-    void readLibSection( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibState, IDF3_BOARD* aBoard );
+    void readLibSection( std::istream& aLibFile, IDF3::FILE_STATE& aLibState, IDF3_BOARD* aBoard );
     // read the library HEADER
-    void readLibHeader( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibState );
+    void readLibHeader( std::istream& aLibFile, IDF3::FILE_STATE& aLibState );
     // read the library file data
     void readLibFile( const std::string& aFileName );
 
diff --git a/utils/idftools/vrml_layer.cpp b/utils/idftools/vrml_layer.cpp
index c9d4fc6b2..0cc328613 100644
--- a/utils/idftools/vrml_layer.cpp
+++ b/utils/idftools/vrml_layer.cpp
@@ -3,7 +3,7 @@
  *
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2013  Cirilo Bernardo
+ * Copyright (C) 2013-2017  Cirilo Bernardo
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -980,7 +980,7 @@ bool VRML_LAYER::pushOutline( VRML_LAYER* holes )
 
 
 // writes out the vertex list for a planar feature
-bool VRML_LAYER::WriteVertices( double aZcoord, std::ofstream& aOutFile, int aPrecision )
+bool VRML_LAYER::WriteVertices( double aZcoord, std::ostream& aOutFile, int aPrecision )
 {
     if( ordmap.size() < 3 )
     {
@@ -1026,7 +1026,7 @@ bool VRML_LAYER::WriteVertices( double aZcoord, std::ofstream& aOutFile, int aPr
 // writes out the vertex list for a 3D feature; top and bottom are the
 // Z values for the top and bottom; top must be > bottom
 bool VRML_LAYER::Write3DVertices( double aTopZ, double aBottomZ,
-                                  std::ofstream& aOutFile, int aPrecision )
+                                  std::ostream& aOutFile, int aPrecision )
 {
     if( ordmap.size() < 3 )
     {
@@ -1113,7 +1113,7 @@ bool VRML_LAYER::Write3DVertices( double aTopZ, double aBottomZ,
 // writes out the index list;
 // 'top' indicates the vertex ordering and should be
 // true for a polygon visible from above the PCB
-bool VRML_LAYER::WriteIndices( bool aTopFlag, std::ofstream& aOutFile )
+bool VRML_LAYER::WriteIndices( bool aTopFlag, std::ostream& aOutFile )
 {
     if( triplets.empty() )
     {
@@ -1161,7 +1161,7 @@ bool VRML_LAYER::WriteIndices( bool aTopFlag, std::ofstream& aOutFile )
 
 
 // writes out the index list for a 3D feature
-bool VRML_LAYER::Write3DIndices( std::ofstream& aOutFile, bool aIncludePlatedHoles )
+bool VRML_LAYER::Write3DIndices( std::ostream& aOutFile, bool aIncludePlatedHoles )
 {
     if( outline.empty() )
     {
@@ -1703,7 +1703,7 @@ int VRML_LAYER::GetSize( void )
 // renumbering of all vertices from 'start'. Returns the end number.
 // Take care when using this call since tesselators cannot work on
 // the internal data concurrently
-int VRML_LAYER::Import( int start, GLUtesselator* tess )
+int VRML_LAYER::Import( int start, GLUtesselator* aTesselator )
 {
     if( start < 0 )
     {
@@ -1711,7 +1711,7 @@ int VRML_LAYER::Import( int start, GLUtesselator* tess )
         return -1;
     }
 
-    if( !tess )
+    if( !aTesselator )
     {
         error = "Import(): NULL tesselator pointer";
         return -1;
@@ -1741,7 +1741,7 @@ int VRML_LAYER::Import( int start, GLUtesselator* tess )
         cbeg = contours[i]->begin();
         cend = contours[i]->end();
 
-        gluTessBeginContour( tess );
+        gluTessBeginContour( aTesselator );
 
         while( cbeg != cend )
         {
@@ -1749,10 +1749,10 @@ int VRML_LAYER::Import( int start, GLUtesselator* tess )
             pt[0] = vp->x;
             pt[1] = vp->y;
             pt[2] = 0.0;
-            gluTessVertex( tess, pt, vp );
+            gluTessVertex( aTesselator, pt, vp );
         }
 
-        gluTessEndContour( tess );
+        gluTessEndContour( aTesselator );
     }
 
     return start;
diff --git a/utils/idftools/vrml_layer.h b/utils/idftools/vrml_layer.h
index 3f75b8cda..0e27a7b75 100644
--- a/utils/idftools/vrml_layer.h
+++ b/utils/idftools/vrml_layer.h
@@ -3,7 +3,7 @@
  *
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2013  Cirilo Bernardo
+ * Copyright (C) 2013-2017  Cirilo Bernardo
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -49,7 +49,7 @@
 #  include <GL/glu.h>
 #endif
 
-#include <fstream>
+#include <iostream>
 #include <vector>
 #include <list>
 #include <utility>
@@ -336,7 +336,7 @@ public:
      *
      * @return bool: true if the operation succeeded
      */
-    bool WriteVertices( double aZcoord, std::ofstream& aOutFile, int aPrecision );
+    bool WriteVertices( double aZcoord, std::ostream& aOutFile, int aPrecision );
 
     /**
      * Function Write3DVertices
@@ -349,7 +349,7 @@ public:
      *
      * @return bool: true if the operation succeeded
      */
-    bool Write3DVertices( double aTopZ, double aBottomZ, std::ofstream& aOutFile, int aPrecision );
+    bool Write3DVertices( double aTopZ, double aBottomZ, std::ostream& aOutFile, int aPrecision );
 
     /**
      * Function WriteIndices
@@ -362,7 +362,7 @@ public:
      *
      * @return bool: true if the operation succeeded
      */
-    bool WriteIndices( bool aTopFlag, std::ofstream& aOutFile );
+    bool WriteIndices( bool aTopFlag, std::ostream& aOutFile );
 
     /**
      * Function Write3DIndices
@@ -375,7 +375,7 @@ public:
      *
      * @return bool: true if the operation succeeded
      */
-    bool Write3DIndices( std::ofstream& aOutFile, bool aIncludePlatedHoles = false );
+    bool Write3DIndices( std::ostream& aOutFile, bool aIncludePlatedHoles = false );
 
     /**
      * Function AddExtraVertex
@@ -436,7 +436,7 @@ public:
      *
      * @return int: the number of vertices exported
      */
-    int Import( int start, GLUtesselator* tess );
+    int Import( int start, GLUtesselator* aTesselator );
 
     /**
      * Function GetVertexByIndex
-- 
2.11.0


Follow ups