gnucash stable: Bug 798885 - Accented character in folder name on Account Export (bis)

John Ralls jralls at code.gnucash.org
Mon May 8 16:38:00 EDT 2023


Updated	 via  https://github.com/Gnucash/gnucash/commit/d696f0cf (commit)
	from  https://github.com/Gnucash/gnucash/commit/73337cff (commit)



commit d696f0cfcb882f864ce8b3d72b164c345ceba7a1
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun May 7 15:19:27 2023 -0700

    Bug 798885 - Accented character in folder name on Account Export (bis)
    
    Pass a boost::filesystem's c_str() rv to the ofstream constructor to
    keep libstdc++ from transcoding it back to UTF8 and creating a broken
    name or failing to match the directory name. Implemented in
    gnc-filepath-utils to avoid spreading the boost::filesystem dependency
    throughout the code base.
    
    See https://github.com/boostorg/filesystem/issues/181 for why other
    approaches don't work.

diff --git a/gnucash/gnucash-commands.cpp b/gnucash/gnucash-commands.cpp
index acbf9fb712..661a2b51c1 100644
--- a/gnucash/gnucash-commands.cpp
+++ b/gnucash/gnucash-commands.cpp
@@ -32,6 +32,7 @@
 #include "gnucash-commands.hpp"
 #include "gnucash-core-app.hpp"
 
+#include <gnc-filepath-utils.h>
 #include <gnc-engine-guile.h>
 #include <gnc-prefs.h>
 #include <gnc-prefs-utils.h>
@@ -107,7 +108,7 @@ static inline void
 write_report_file (const char *html, const char* file)
 {
     if (!file || !html || !*html) return;
-    std::ofstream ofs{file};
+    auto ofs{gnc_open_filestream(file)};
     if (!ofs)
     {
         std::cerr << "Failed to open file " << file << " for writing\n";
diff --git a/gnucash/import-export/csv-exp/csv-transactions-export.cpp b/gnucash/import-export/csv-exp/csv-transactions-export.cpp
index bec67baf95..a73b605cec 100644
--- a/gnucash/import-export/csv-exp/csv-transactions-export.cpp
+++ b/gnucash/import-export/csv-exp/csv-transactions-export.cpp
@@ -32,6 +32,7 @@
 #include <string>
 #include <unordered_set>
 
+#include <gnc-filepath-utils.h>
 #include "gnc-commodity.h"
 #include "gnc-ui-util.h"
 #include "Query.h"
@@ -350,9 +351,6 @@ void csv_transactions_export (CsvExportInfo *info)
     ENTER("");
     DEBUG("File name is : %s", info->file_name);
 
-    /* Open File for writing */
-    auto ss{std::ofstream (info->file_name, std::ofstream::out)};
-
     StringVec headers;
     bool num_action = qof_book_use_split_action_for_num_field (gnc_get_current_book());
 
@@ -398,6 +396,7 @@ void csv_transactions_export (CsvExportInfo *info)
         };
 
     /* Write header line */
+    auto ss{gnc_open_filestream(info->file_name)};
     info->failed = !gnc_csv_add_line (ss, headers, info->use_quotes, info->separator_str);
 
     /* Go through list of accounts */
diff --git a/gnucash/import-export/csv-exp/csv-tree-export.cpp b/gnucash/import-export/csv-exp/csv-tree-export.cpp
index 9b8810ec9b..6def848937 100644
--- a/gnucash/import-export/csv-exp/csv-tree-export.cpp
+++ b/gnucash/import-export/csv-exp/csv-tree-export.cpp
@@ -32,6 +32,7 @@
 #include <vector>
 #include <algorithm>
 
+#include <gnc-filepath-utils.h>
 #include "gnc-commodity.h"
 #include "gnc-ui-util.h"
 #include "csv-tree-export.h"
@@ -52,7 +53,7 @@ csv_tree_export (CsvExportInfo *info)
     DEBUG("File name is : %s", info->file_name);
 
     /* Open File for writing */
-    auto ss{std::ofstream (info->file_name, std::ofstream::out)};
+    auto ss{gnc_open_filestream(info->file_name)};
 
     /* Header string */
     StringVec headervec = {
diff --git a/libgnucash/core-utils/gnc-filepath-utils.cpp b/libgnucash/core-utils/gnc-filepath-utils.cpp
index 5de8c436d6..1fdf64942a 100644
--- a/libgnucash/core-utils/gnc-filepath-utils.cpp
+++ b/libgnucash/core-utils/gnc-filepath-utils.cpp
@@ -1347,4 +1347,11 @@ gboolean gnc_filename_is_datafile (const char *filename)
         std::regex_match (filename, datafile_regex);
 }
 
+std::ofstream
+gnc_open_filestream(const char* path)
+{
+    bfs::path bfs_path(path, cvt);
+    bfs_path.imbue(bfs_locale);
+    return std::ofstream(bfs_path.c_str());
+}
 /* =============================== END OF FILE ========================== */
diff --git a/libgnucash/core-utils/gnc-filepath-utils.h b/libgnucash/core-utils/gnc-filepath-utils.h
index fd10e186be..761573139d 100644
--- a/libgnucash/core-utils/gnc-filepath-utils.h
+++ b/libgnucash/core-utils/gnc-filepath-utils.h
@@ -29,6 +29,8 @@
 #ifndef GNC_FILEPATH_UTILS_H
 #define GNC_FILEPATH_UTILS_H
 
+#include <glib-2.0/glib.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -199,7 +201,22 @@ gboolean gnc_filename_is_backup (const char *filename);
 gboolean gnc_filename_is_datafile (const char *filename);
 
 #ifdef __cplusplus
-}
+} //extern "C"
+
+#include <fstream>
+
+/** Open std::ofstream from a UTF-8 encoded path. This is harder than
+ * it should because std::ofstream's constructor needs to be tricked
+ * into taking a wchar_t filename: Simply converting path to a
+ * wchar_t* with g_utf8_to_utf16() wouldn't compile. The workaround
+ * came from https://github.com/boostorg/filesystem/issues/181. As
+ * noted there passing the boost path directly to
+ * boost::filesystem::fstream doesn't work either.
+ * @param path UTF-8 path to the file
+ * @return a std::ofstream on the stack.
+ */
+std::ofstream gnc_open_filestream(const char *path);
+
 #endif
 
 #endif /* GNC_FILEPATH_UTILS_H */



Summary of changes:
 gnucash/gnucash-commands.cpp                          |  3 ++-
 .../import-export/csv-exp/csv-transactions-export.cpp |  5 ++---
 gnucash/import-export/csv-exp/csv-tree-export.cpp     |  3 ++-
 libgnucash/core-utils/gnc-filepath-utils.cpp          |  7 +++++++
 libgnucash/core-utils/gnc-filepath-utils.h            | 19 ++++++++++++++++++-
 5 files changed, 31 insertions(+), 6 deletions(-)



More information about the gnucash-changes mailing list