From 7f06006a34267c9d713f62da9f54cd20a25079b4 Mon Sep 17 00:00:00 2001
From: Lars Bilke <lars.bilke@ufz.de>
Date: Fri, 28 Jan 2022 20:12:15 +0100
Subject: [PATCH] [prj] Use xmlStrEqual instead of reinterpret_cast comparison.

---
 BaseLib/ConfigTreeUtil.cpp                  |  1 -
 BaseLib/ConfigTreeUtil.h                    |  2 +-
 BaseLib/PrjProcessing.cpp                   | 59 ++++++++++-----------
 BaseLib/PrjProcessing.h                     | 10 ++--
 ProcessLib/SteadyStateDiffusion/Tests.cmake |  2 +-
 5 files changed, 37 insertions(+), 37 deletions(-)

diff --git a/BaseLib/ConfigTreeUtil.cpp b/BaseLib/ConfigTreeUtil.cpp
index 13bae333c9c..786692aff08 100644
--- a/BaseLib/ConfigTreeUtil.cpp
+++ b/BaseLib/ConfigTreeUtil.cpp
@@ -60,7 +60,6 @@ ConfigTree makeConfigTreeFromFile(const std::string& filepath,
     {
         std::stringstream buffer;
         buffer << file.rdbuf();
-        file.close();
 
         return makeConfigTree(filepath, be_ruthless, toplevel_tag, buffer);
     }
diff --git a/BaseLib/ConfigTreeUtil.h b/BaseLib/ConfigTreeUtil.h
index 677847607f7..1026272d222 100644
--- a/BaseLib/ConfigTreeUtil.h
+++ b/BaseLib/ConfigTreeUtil.h
@@ -20,7 +20,7 @@ namespace BaseLib
  * \param be_ruthless  see ConfigTreeTopLevel::ConfigTreeTopLevel()
  * \param toplevel_tag name of the outermost tag in the XML file. The returned
  *                     ConfigTree is rooted one level below that tag.
- * \param patch_files  optional vector of strings with patch file paths.
+ * \param prj_stream   content of the (pre-processed) prj file.
  *
  * The parameter \c toplevel_tag is provided for compatibility with our existing
  * configuration files whose toplevel tags are written in camel case, which
diff --git a/BaseLib/PrjProcessing.cpp b/BaseLib/PrjProcessing.cpp
index 1f2105ddaf8..84702330f45 100644
--- a/BaseLib/PrjProcessing.cpp
+++ b/BaseLib/PrjProcessing.cpp
@@ -14,30 +14,26 @@
 #include <libxml/tree.h>
 #include <xml_patch.h>
 
+#include <filesystem>
+#include <fstream>
+
 #include "Error.h"
+#include "FileTools.h"
 #include "Logging.h"
 
 namespace BaseLib
 {
-bool isEqual(const unsigned char* a, std::string const& b)
-{
-    return std::string{reinterpret_cast<const char*>(a)} == b;
-}
-
 void traverseIncludes(xmlDoc* doc, xmlNode* node,
                       std::filesystem::path const& prj_dir)
 {
     xmlNode* cur_node = nullptr;
     for (cur_node = node; cur_node; cur_node = cur_node->next)
     {
-        if (cur_node->type != XML_ELEMENT_NODE ||
-            cur_node->type == XML_TEXT_NODE)
+        if (cur_node->type != XML_ELEMENT_NODE)
         {
             continue;
         }
-        if (isEqual(cur_node->name, "include"))
-        // if (!strcmp(reinterpret_cast<const char*>(cur_node->name),
-        // "include"))
+        if (xmlStrEqual(cur_node->name, xmlCharStrdup("include")))
         {
             auto include_file_char_pointer =
                 xmlGetProp(cur_node, xmlCharStrdup("file"));
@@ -48,8 +44,10 @@ void traverseIncludes(xmlDoc* doc, xmlNode* node,
                     "element '{:s}' on line {:d}: no file attribute given!",
                     cur_node->name, cur_node->line);
             }
+            auto filename_length = xmlStrlen(include_file_char_pointer);
             std::string filename(
-                reinterpret_cast<char*>(include_file_char_pointer));
+                reinterpret_cast<char*>(include_file_char_pointer),
+                filename_length);
             if (auto const filepath = std::filesystem::path(filename);
                 filepath.is_relative())
             {
@@ -157,8 +155,8 @@ void patchStream(std::string const& patch_file, std::stringstream& prj_stream,
             // Check for after_includes-attribute
             xmlChar* value =
                 xmlNodeListGetString(node->doc, attribute->children, 1);
-            if (isEqual(attribute->name, "after_includes") &&
-                isEqual(value, "true"))
+            if (xmlStrEqual(attribute->name, xmlCharStrdup("after_includes")) &&
+                xmlStrEqual(value, xmlCharStrdup("true")))
             {
                 node_after_includes = true;
             }
@@ -172,15 +170,15 @@ void patchStream(std::string const& patch_file, std::stringstream& prj_stream,
             continue;
         }
 
-        if (isEqual(node->name, "add"))
+        if (xmlStrEqual(node->name, xmlCharStrdup("add")))
         {
             rc = xml_patch_add(doc, node);
         }
-        else if (isEqual(node->name, "replace"))
+        else if (xmlStrEqual(node->name, xmlCharStrdup("replace")))
         {
             rc = xml_patch_replace(doc, node);
         }
-        else if (isEqual(node->name, "remove"))
+        else if (xmlStrEqual(node->name, xmlCharStrdup("remove")))
         {
             rc = xml_patch_remove(doc, node);
         }
@@ -261,12 +259,9 @@ void readAndPatchPrj(std::stringstream& prj_stream, std::string& prj_file,
     }
 
     // apply xml patches to stream
-    if (!patch_files.empty())
+    for (const auto& patch_file : patch_files)
     {
-        for (const auto& patch_file : patch_files)
-        {
-            patchStream(patch_file, prj_stream);
-        }
+        patchStream(patch_file, prj_stream);
     }
 }
 
@@ -279,15 +274,17 @@ void prepareProjectFile(std::stringstream& prj_stream,
 
     std::vector<std::string> patch_files_copy = patch_files;
     readAndPatchPrj(prj_stream, prj_file, patch_files_copy);
-    replaceIncludes(prj_stream, std::filesystem::path(prj_file).parent_path());
+    // LB TODO later: replace canonical with absolute when a mesh input dir
+    // ogs parameter is implemented.
+    replaceIncludes(prj_stream,
+                    std::filesystem::canonical(std::filesystem::path(prj_file))
+                        .parent_path());
     // re-apply xml patches to stream
-    if (!patch_files_copy.empty())
+    for (const auto& patch_file : patch_files_copy)
     {
-        for (const auto& patch_file : patch_files_copy)
-        {
-            patchStream(patch_file, prj_stream, true);
-        }
+        patchStream(patch_file, prj_stream, true);
     }
+
     if (write_prj)
     {
         // pretty-print
@@ -297,13 +294,15 @@ void prepareProjectFile(std::stringstream& prj_stream,
         // not work. 2 spaces are default.
         //
         // xmlThrDefIndentTreeOutput(1);
-        // xmlThrDefTreeIndentString("");
+        // xmlThrDefTreeIndentString("    "); // 4 spaces indent
         auto doc =
             xmlParseMemory(prj_stream.str().c_str(), prj_stream.str().size());
-        auto prj_out = std::string(std::filesystem::path(out_directory) /
-                                   std::filesystem::path(prj_file).stem()) +
+        auto prj_out = (std::filesystem::path(out_directory) /
+                        std::filesystem::path(filepath).stem())
+                           .string() +
                        "_processed.prj";
         xmlSaveFormatFileEnc(prj_out.c_str(), doc, "utf-8", 1);
+        INFO("Processed project file written to {:s}.", prj_out);
         xmlFreeDoc(doc);
     }
     xmlCleanupParser();
diff --git a/BaseLib/PrjProcessing.h b/BaseLib/PrjProcessing.h
index 267f81cd834..138ee7d0faa 100644
--- a/BaseLib/PrjProcessing.h
+++ b/BaseLib/PrjProcessing.h
@@ -16,11 +16,13 @@
 namespace BaseLib
 {
 /**
- * @brief Applies includes and patch files to project file.
+ * \brief Applies includes and patch files to project file.
  *
- * @param prj_stream The processed prj as a stringstream.
- * @param filepath    The prj file.
- * @param patch_files Optional patch files.
+ * \param prj_stream    The processed prj as a stringstream.
+ * \param filepath      The prj file.
+ * \param patch_files   Optional patch files.
+ * \param write_prj     Write the processed project file to disk?
+ * \param out_directory The directory to write the processed file to.
  */
 void prepareProjectFile(std::stringstream& prj_stream,
                         const std::string& filepath,
diff --git a/ProcessLib/SteadyStateDiffusion/Tests.cmake b/ProcessLib/SteadyStateDiffusion/Tests.cmake
index c7c7c6de2f6..3d183ba286f 100644
--- a/ProcessLib/SteadyStateDiffusion/Tests.cmake
+++ b/ProcessLib/SteadyStateDiffusion/Tests.cmake
@@ -4,7 +4,7 @@ foreach(mesh_size 1e0 1e1 1e2 1e3)
         NAME SteadyStateDiffusion_cube_1x1x1_${mesh_size}
         PATH Elliptic/cube_1x1x1_SteadyStateDiffusion
         EXECUTABLE ogs
-        EXECUTABLE_ARGS cube_${mesh_size}.xml
+        EXECUTABLE_ARGS cube_${mesh_size}.xml --write-prj
         TESTER vtkdiff
         REQUIREMENTS NOT OGS_USE_MPI
         DIFF_DATA
-- 
GitLab