From 6eb7135e1b1cd9f429e76ff49d8d758719cb3034 Mon Sep 17 00:00:00 2001
From: rinkk <karsten.rink@ufz.de>
Date: Thu, 5 Sep 2019 15:17:25 +0200
Subject: [PATCH] updated netcdf cli to netcdf4-cxx

---
 .../Utils/FileConverter/CMakeLists.txt        |  50 +---
 .../Utils/FileConverter/NetCdfConverter.cpp   | 274 +++++++++---------
 2 files changed, 142 insertions(+), 182 deletions(-)

diff --git a/Applications/Utils/FileConverter/CMakeLists.txt b/Applications/Utils/FileConverter/CMakeLists.txt
index 230b4833461..4f326101ae1 100644
--- a/Applications/Utils/FileConverter/CMakeLists.txt
+++ b/Applications/Utils/FileConverter/CMakeLists.txt
@@ -9,7 +9,8 @@ set(TOOLS
     TecPlotTools
     GocadSGridReader
     GocadTSurfaceReader
-    Mesh2Raster)
+    Mesh2Raster
+    NetCdfConverter)
 
 if(OGS_BUILD_GUI)
     if(Shapelib_FOUND)
@@ -33,43 +34,14 @@ if(TARGET ConvertSHPToGLI)
     target_link_libraries(ConvertSHPToGLI GeoLib Qt5::Xml ${Shapelib_LIBRARIES})
 endif()
 
-add_executable(OGS2VTK OGS2VTK.cpp)
-set_target_properties(OGS2VTK PROPERTIES FOLDER Utilities)
-target_link_libraries(OGS2VTK MeshLib)
-ADD_VTK_DEPENDENCY(OGS2VTK)
-
-add_executable(VTK2OGS VTK2OGS.cpp)
-set_target_properties(VTK2OGS PROPERTIES FOLDER Utilities)
-target_link_libraries(VTK2OGS MeshLib)
-ADD_VTK_DEPENDENCY(VTK2OGS)
-
-add_executable(VTK2TIN VTK2TIN.cpp)
-set_target_properties(VTK2TIN PROPERTIES FOLDER Utilities)
-target_link_libraries(VTK2TIN MeshLib)
-ADD_VTK_DEPENDENCY(VTK2TIN)
-
-add_executable(TIN2VTK TIN2VTK.cpp)
-set_target_properties(TIN2VTK PROPERTIES FOLDER Utilities)
-target_link_libraries(TIN2VTK MeshLib)
-ADD_VTK_DEPENDENCY(TIN2VTK)
-
-add_executable(NetCdfConverter NetCdfConverter.cpp)
-set_target_properties(NetCdfConverter PROPERTIES FOLDER Utilities)
-target_link_libraries(NetCdfConverter MeshLib)
-ADD_VTK_DEPENDENCY(NetCdfConverter)
-
-####################
-### Installation ###
-####################
-install(TARGETS generateMatPropsFromMatID GMSH2OGS OGS2VTK VTK2OGS VTK2TIN
-    RUNTIME DESTINATION bin COMPONENT ogs_converter)
-
-if(Qt5XmlPatterns_FOUND)
-    if(Shapelib_FOUND)
-        install(TARGETS ConvertSHPToGLI
-            RUNTIME DESTINATION bin COMPONENT ogs_converter)
-    endif()
-    install(TARGETS  FEFLOW2OGS convertGEO
-        RUNTIME DESTINATION bin COMPONENT ogs_converter)
+if(TARGET Mesh2Shape)
+    target_link_libraries(Mesh2Shape ${Shapelib_LIBRARIES})
 endif()
 
+if(TARGET NetCdfConverter)
+    target_link_libraries(NetCdfConverter
+                          ${NETCDF_LIBRARIES_C}
+                          ${NETCDF_LIBRARIES_CXX}
+                          ${HDF5_LIBRARIES}
+                          ${HDF5_HL_LIBRARIES})
+endif()
diff --git a/Applications/Utils/FileConverter/NetCdfConverter.cpp b/Applications/Utils/FileConverter/NetCdfConverter.cpp
index f68447b56eb..986cc6874cf 100644
--- a/Applications/Utils/FileConverter/NetCdfConverter.cpp
+++ b/Applications/Utils/FileConverter/NetCdfConverter.cpp
@@ -19,12 +19,12 @@
 
 #include "Applications/ApplicationsLib/LogogSetup.h"
 
-#include <netcdfcpp.h>
+#include <netcdf>
 
 // BaseLib
-#include "BaseLib/BuildInfo.h"
-#include "BaseLib/LogogSimpleFormatter.h"
 #include "BaseLib/FileTools.h"
+#include "BaseLib/LogogSimpleFormatter.h"
+#include "InfoLib/GitInfo.h"
 
 // GeoLib
 #include "GeoLib/Raster.h"
@@ -35,10 +35,11 @@
 
 #include "MeshLib/IO/VtkIO/VtuInterface.h"
 
+using namespace netCDF;
 
 void checkExit(std::string const& str)
 {
-    if (str == "exit")
+    if (str == "x" || str == "exit")
         exit(0);
 }
 
@@ -87,60 +88,63 @@ std::size_t parseInput(std::string const& request_str, std::size_t max_val, bool
     return std::numeric_limits<std::size_t>::max();
 }
 
-void showArrays(NcFile const& dataset)
+NcVar getDimVar(NcFile const& dataset, NcVar const& var, std::size_t const dim)
 {
-    std::size_t const n_vars (dataset.num_vars());
+    NcDim const& dim_obj = var.getDim(dim);
+    return dataset.getVar(dim_obj.getName());
+}
+
+std::vector<std::string> showArrays(NcFile const& dataset)
+{
+    std::size_t const n_vars(dataset.getDimCount());
     std::cout << "The NetCDF file contains the following " << n_vars << " arrays:\n\n";
     std::cout << "\tIndex\tArray Name\t#Dimensions\n";
     std::cout << "-------------------------------------------\n";
-    for (std::size_t i=0; i<n_vars; ++i)
+    auto const& names = dataset.getVars();
+    std::vector<std::string> var_names;
+    for (auto [name, var] : names)
     {
-        NcVar const& var = *dataset.get_var(i);
-        std::cout << "\t" << i << "\t" << var.name() << "\t(" << var.num_dims() << "D array)\n";
+        std::cout << "\t" << var_names.size() << "\t" << name << "\t(" << var.getDimCount() << "D array)\n";
+        var_names.push_back(name);
     }
     std::cout << "\n";
+    return var_names;
 }
 
 bool showArraysDims(NcVar const& var)
 {
-    std::cout << "Data array \"" << var.name() << "\" contains the following dimensions:\n";
-    std::size_t const n_dims (var.num_dims());
+    std::cout << "Data array \"" << var.getName()
+              << "\" contains the following dimensions:\n";
+    std::size_t const n_dims (var.getDimCount());
     for (std::size_t i=0; i<n_dims; ++i)
-        std::cout << "\t" << i << "\t" << var.get_dim(i)->name() << "\t(" << var.get_dim(i)->size() << " values)\n";
+        std::cout << "\t" << i << "\t" << var.getDim(i).getName() << "\t(" << var.getDim(i).getSize() << " values)\n";
     std::cout << "\n";
     return true;
 }
 
-std::size_t getDimensionBoundaries(NcFile const& dataset, NcVar const& var, std::size_t dim, double &start, double &end)
+std::pair<double, double> getBoundaries(NcVar const& var)
 {
-    NcVar& dim_var = *dataset.get_var(var.get_dim(dim)->name());
-    if ((dim_var.num_dims()) == 1)
+    if ((var.getDimCount()) == 1)
     {
-        std::size_t size = dim_var.get_dim(0)->size();
-
-        std::size_t length[1] = {1};
-        long idx[1] = {0};
-        dim_var.set_cur(idx);
-        double val_at_idx[1] = {0};
-        dim_var.get(val_at_idx, length);
-        start = val_at_idx[0];
-
-        idx[0] = size-1;
-        dim_var.set_cur(idx);
-        dim_var.get(val_at_idx, length);
-        end = val_at_idx[0];
-        return size;
+        double start, end;
+        std::size_t size = var.getDim(0).getSize();
+        var.getVar({0}, {1}, &start);
+        var.getVar({size - 1}, {1}, &end);
+        return std::make_pair(start, end);
     }
-    return 0;
+    return std::make_pair(0, 0);
 }
 
-MathLib::Point3d getOrigin(std::array<std::pair<double, double>,3> bounds, std::size_t n_dims)
+MathLib::Point3d getOrigin(NcFile const& dataset, NcVar const& var)
 {
     MathLib::Point3d origin(std::array<double, 3>{ {0, 0, 0}});
-    for (std::size_t i=0; i<n_dims; ++i)
-        origin[i] = (bounds[i].first < bounds[i].second) ? bounds[i].first : bounds[i].second;
-    if (n_dims > 1)
-        std::swap(origin[0], origin[1]);
+    std::size_t const n_dims = var.getDimCount();
+    for (std::size_t i=1; i<n_dims; ++i)
+    {
+        NcVar const& dim = getDimVar(dataset, var, var.getDimCount() - i);
+        auto const bounds = getBoundaries(dim);
+        origin[n_dims - i] = (bounds.first < bounds.second) ? bounds.first : bounds.second;
+    }
     return origin;
 }
 
@@ -165,21 +169,29 @@ void reverseNorthSouth(double* data, std::size_t width, std::size_t height)
     delete[] cp_array;
 }
 
-std::size_t arraySelectionLoop(NcFile const& dataset)
+bool canConvert(NcVar const& var)
+{
+    bool ret (true);
+    if (ret = (var.getDimCount() < 2))
+        ERR ("Only 2+ dimensional variables can be converted into OGS Meshes.\n");
+    return !ret;
+}
+
+std::string arraySelectionLoop(NcFile const& dataset)
 {
-    showArrays(dataset);
-    std::size_t idx = parseInput("Enter data array index: ", dataset.num_vars(), true);
+    std::vector<std::string> const& names = showArrays(dataset);
+    std::size_t idx = parseInput("Enter data array index: ", dataset.getVarCount(), true);
 
-    if (idx == dataset.num_vars())
+    if (idx == dataset.getVarCount() || !canConvert(dataset.getVar(names[idx])))
         return arraySelectionLoop(dataset);
 
-    return idx;
+    return names[idx];
 }
 
 bool dimensionSelectionLoop(NcVar const& var, std::array<std::size_t,4> &dim_idx_map)
 {
     showArraysDims(var);
-    std::size_t const n_dims (var.num_dims());
+    std::size_t const n_dims(var.getDimCount());
     dim_idx_map[0] = std::numeric_limits<std::size_t>::max();
     bool is_time_dep (true);
 
@@ -195,16 +207,17 @@ bool dimensionSelectionLoop(NcVar const& var, std::array<std::size_t,4> &dim_idx
             std::stringstream str_stream(temp_str);
             if (str_stream.str() == "c" || str_stream.str() == "continue")
                 is_time_dep = false;
-            else 
+            else
             {
                 if (!(str_stream >> dim_idx_map[0]))
                 {
                     showErrorMessage(0);
+                    dim_idx_map[0] = std::numeric_limits<std::size_t>::max();
                     continue;
                 }
                 if (dim_idx_map[0] > n_dims-1)
                 {
-                    showErrorMessage(1, var.num_dims()-1);
+                    showErrorMessage(1, var.getDimCount() - 1);
                     dim_idx_map[0] = std::numeric_limits<std::size_t>::max();
                 }
             }
@@ -220,9 +233,9 @@ bool dimensionSelectionLoop(NcVar const& var, std::array<std::size_t,4> &dim_idx
         dim_idx_map[i] = std::numeric_limits<std::size_t>::max();
 
         std::string request_str ("Enter ID for dimension " + std::to_string(i) + ": ");
-        std::size_t idx = parseInput(request_str, var.num_dims(), true);
+        std::size_t idx = parseInput(request_str, var.getDimCount(), true);
 
-        if (idx == var.num_dims())
+        if (idx == var.getDimCount())
         {
             showArraysDims(var);
             i--;
@@ -234,15 +247,16 @@ bool dimensionSelectionLoop(NcVar const& var, std::array<std::size_t,4> &dim_idx
     return is_time_dep;
 }
 
-std::pair<std::size_t, std::size_t> timestepSelectionLoop(NcFile const& dataset, NcVar const& var, std::size_t dim)
+std::pair<std::size_t, std::size_t> timestepSelectionLoop(NcFile const& dataset, NcVar const& var, std::size_t dim_idx)
 {
-    double start, end;
-    std::string str("");
-    std::pair<std::size_t, std::size_t> bounds(0,std::numeric_limits<std::size_t>::max());
-    std::size_t n_time_steps = getDimensionBoundaries(dataset, var, dim, start, end);
+    NcVar const& dim_var = getDimVar(dataset, var, dim_idx);
+    std::size_t const n_time_steps = var.getDim(dim_idx).getSize();
+    std::pair<std::size_t, std::size_t> bounds(
+        std::numeric_limits<std::size_t>::max(),
+        std::numeric_limits<std::size_t>::max());
     std::cout << "\nThe dataset contains " << n_time_steps << " time steps.\n";
     bounds.first = parseInput("Specify first time step to export: ", n_time_steps, false);
-    while (bounds.first > bounds.second || bounds.second == std::numeric_limits<std::size_t>::max())
+    while (bounds.first > bounds.second || bounds.second > n_time_steps)
         bounds.second = parseInput("Specify last time step to export: ", n_time_steps, false);
     return bounds;
 }
@@ -256,7 +270,7 @@ MeshLib::MeshElemType elemSelectionLoop(std::size_t const dim)
     while (t == MeshLib::MeshElemType::INVALID)
     {
         std::cout << "\nSelect element type for result, choose ";
-    
+
         if (dim==2) std::cout << "(t)riangle or (q)uadliteral: ";
         if (dim==3) std::cout << "(p)rism or (h)exahedron: ";
         std::string type ("");
@@ -291,7 +305,7 @@ MeshLib::MeshElemType elemSelectionLoop(std::size_t const dim)
 
 bool multFilesSelectionLoop(std::pair<std::size_t, std::size_t> const& time_bounds)
 {
-    std::size_t n_time_steps(time_bounds.second - time_bounds.first);
+    std::size_t n_time_steps(time_bounds.second - time_bounds.first + 1);
     std::cout << "\nThe selection includes " << n_time_steps << " time steps.\n";
     std::cout << "0. Save data in " << n_time_steps << " mesh files with one scalar array each.\n";
     std::cout << "1. Save data in one mesh file with " << n_time_steps << " scalar arrays.\n";
@@ -299,16 +313,6 @@ bool multFilesSelectionLoop(std::pair<std::size_t, std::size_t> const& time_boun
     return (ret == 0) ? true : false;
 }
 
-void setTimeStep(NcVar &var, std::size_t time_step)
-{
-    long* newOrigin = new long[var.num_dims()];
-    for (int i=0; i < var.num_dims(); ++i) 
-        newOrigin[i]=0;
-    newOrigin[0] = time_step;
-    var.set_cur(newOrigin);
-    delete [] newOrigin;
-}
-
 std::string getIterationString(std::size_t i, std::size_t max)
 {
     std::size_t const max_length (std::to_string(max).length());
@@ -316,11 +320,39 @@ std::string getIterationString(std::size_t i, std::size_t max)
     return std::string(max_length - current_str.length(), '0') + current_str;
 }
 
+double getResolution(NcFile const& dataset, NcVar const& var)
+{
+    std::size_t dim_idx = var.getDimCount() - 1;
+    auto const bounds = getBoundaries(getDimVar(dataset, var, dim_idx));
+    return fabs(bounds.second - bounds.first) / static_cast<double>(var.getDim(dim_idx).getSize());
+}
+
+GeoLib::RasterHeader createRasterHeader(
+    NcFile const& dataset, NcVar const& var,
+    std::array<std::size_t, 4> const& dim_idx_map,
+    std::vector<std::size_t> const& length, bool is_time_dep)
+{
+    MathLib::Point3d origin = getOrigin(dataset, var);
+    double const res = getResolution(dataset, var);
+    std::size_t n_dims = var.getDimCount();
+    std::size_t temp_offset = (is_time_dep) ? 1 : 0;
+    std::size_t z_length = (n_dims - temp_offset == 3) ? length[dim_idx_map.back()] : 1;
+    return {length[dim_idx_map[0 + temp_offset]], length[dim_idx_map[1 + temp_offset]], z_length, origin, res, -9999};
+}
+
 int main (int argc, char* argv[])
 {
     ApplicationsLib::LogogSetup logog_setup;
 
-    TCLAP::CmdLine cmd("Converts NetCDF into mesh file.", ' ', BaseLib::BuildInfo::git_describe);
+    TCLAP::CmdLine cmd(
+        "Converts NetCDF into mesh file(s).\n\n "
+        "OpenGeoSys-6 software, version " +
+            GitInfoLib::GitInfo::ogs_version +
+            ".\n"
+            "Copyright (c) 2012-2019, OpenGeoSys Community "
+            "(http://www.opengeosys.org)",
+        ' ', GitInfoLib::GitInfo::ogs_version);
+
     TCLAP::ValueArg<std::string> input("i", "input-file",
                                        "the NetCDF input file", true,
                                        "", "the NetCDF input file");
@@ -331,9 +363,9 @@ int main (int argc, char* argv[])
     cmd.add(output);
     cmd.parse(argc, argv);
 
-    NcFile dataset(input.getValue().c_str(), NcFile::ReadOnly);
+    NcFile dataset(input.getValue().c_str(), NcFile::read);
 
-    if (!dataset.is_valid())
+    if (dataset.isNull())
     {
         ERR("Error opening file.");
         return -1;
@@ -344,34 +376,25 @@ int main (int argc, char* argv[])
     std::cin.ignore();
     std::string output_name (output.getValue());
 
-    std::size_t const var_idx = arraySelectionLoop(dataset);
-    NcVar& var = *dataset.get_var(var_idx);
+    std::string const& var_name = arraySelectionLoop(dataset);
+    NcVar& var = dataset.getVar(var_name);
 
     std::array<std::size_t, 4> dim_idx_map;
     bool const is_time_dep = dimensionSelectionLoop(var, dim_idx_map);
 
-    std::size_t temp_offset = (is_time_dep) ? 1 : 0;
-    std::size_t const n_dims = (var.num_dims());
-    std::size_t* length = new std::size_t[n_dims];
-    for(int i=0; i < n_dims; i++) 
-        length[i]=1;
-    std::array<std::size_t, 3> spatial_size = {0,0,0};
-    std::array<std::pair<double, double>,3> spatial_bounds;
-    for (std::size_t i=0; i<3; ++i)
-        spatial_bounds[i] = std::pair<double, double>(0, 0);
+    std::size_t const temp_offset = (is_time_dep) ? 1 : 0;
+    std::size_t const n_dims = (var.getDimCount());
+    std::vector<std::size_t> offset(n_dims, 0);
+    std::vector<std::size_t> length(n_dims, 1);
     std::size_t array_length = 1;
     for (std::size_t i=temp_offset; i<n_dims; ++i)
     {
-        length[dim_idx_map[i]] = getDimensionBoundaries(dataset, var, dim_idx_map[i], spatial_bounds[i-temp_offset].first, spatial_bounds[i-temp_offset].second);
-        spatial_size[i-temp_offset] = length[dim_idx_map[i]];
-        array_length *= length[dim_idx_map[i]];
+        length[i] = var.getDim(i).getSize();
+        array_length *= length[i];
     }
 
-    MathLib::Point3d origin = getOrigin(spatial_bounds, n_dims);
-    double const resolution = fabs(spatial_bounds[0].second - spatial_bounds[0].first) / (spatial_size[0] - 1);
-    GeoLib::RasterHeader header = { spatial_size[1], spatial_size[0], origin, resolution, -9999 };
-    MeshLib::MeshElemType meshElemType = elemSelectionLoop(n_dims - temp_offset);
-    MeshLib::UseIntensityAs useIntensity = MeshLib::UseIntensityAs::DATAVECTOR;
+    GeoLib::RasterHeader header =
+        createRasterHeader(dataset, var, dim_idx_map, length, is_time_dep);
 
     std::pair<std::size_t, std::size_t> time_bounds(0,0);
     if (is_time_dep)
@@ -381,42 +404,45 @@ int main (int argc, char* argv[])
     if (is_time_dep && time_bounds.first != time_bounds.second)
         mult_files = multFilesSelectionLoop(time_bounds);
 
-    double* data_array = nullptr;
     std::unique_ptr<MeshLib::Mesh> mesh;
+    MeshLib::MeshElemType const meshElemType = elemSelectionLoop(n_dims - temp_offset);
     for (std::size_t i=time_bounds.first; i<=time_bounds.second; ++i)
     {
-        if (is_time_dep)
-            setTimeStep(var, i);
-
-        data_array = new double[array_length];
-        for (std::size_t i = 0; i < array_length; i++)
-            data_array[i] = 0;
-        var.get(data_array, length);
-
-        for (std::size_t i=0; i < array_length; i++)
-            if (data_array[i] < -9999 ) data_array[i] = -9999; // all values < -10000, set to "no-value"
+        std::cout << "Converting time step " << i << "...\n";
+        offset[0] = i;
+        std::vector<double> data_array(array_length,0);
+        var.getVar(offset, length, data_array.data());
+        std::replace_if(data_array.begin(), data_array.end(),
+                        [](double& x) { return x <= -9999; }, -9999);
 
         // reverse lines in vertical direction if the original file has its origin in the northwest corner
-        if (spatial_bounds[0].first > spatial_bounds[0].second)
-            reverseNorthSouth(data_array, spatial_size[1], spatial_size[0]);
+        NcVar const& dim_var = getDimVar(dataset, var, n_dims - 1);
+        auto const bounds = getBoundaries(dim_var);
+        if (bounds.first > bounds.second)
+            reverseNorthSouth(data_array.data(), length[n_dims-2], length[n_dims-1]);
 
+        MeshLib::UseIntensityAs const useIntensity = MeshLib::UseIntensityAs::DATAVECTOR;
         if (mult_files)
         {
-            mesh.reset(MeshLib::RasterToMesh::convert(data_array, header, meshElemType, useIntensity, var.name()));
+            mesh.reset(MeshLib::RasterToMesh::convert(data_array.data(), header, meshElemType, useIntensity, var.getName()));
             std::string const output_file_name (BaseLib::dropFileExtension(output_name) + getIterationString(i, time_bounds.second) + ".vtu");
             MeshLib::IO::VtuInterface vtu(mesh.get());
             vtu.writeToFile(output_file_name);
         }
         else
         {
-            std::string array_name (var.name());
+            std::string array_name (var.getName());
             if (time_bounds.first != time_bounds.second)
                 array_name.append(getIterationString(i, time_bounds.second));
             if (i==time_bounds.first) // create persistent mesh
-                mesh.reset(MeshLib::RasterToMesh::convert(data_array, header, meshElemType, useIntensity, array_name));
-            else
+                mesh.reset(MeshLib::RasterToMesh::convert(data_array.data(), header, meshElemType, useIntensity, array_name));
+            else // copy array to mesh
             {
-                //copy array to mesh
+                std::unique_ptr<MeshLib::Mesh> temp (MeshLib::RasterToMesh::convert(data_array.data(), header, meshElemType, useIntensity, array_name));
+                MeshLib::PropertyVector<double> const*const vec = temp->getProperties().getPropertyVector<double>(array_name);
+                if (vec == nullptr)
+                    return EXIT_FAILURE;
+                MeshLib::addPropertyToMesh<double>(*mesh, array_name, MeshLib::MeshItemType::Cell, 1, *vec);
             }
             if (i==time_bounds.second)
             {
@@ -426,44 +452,6 @@ int main (int argc, char* argv[])
         }
     }
 
-
-    /***********************
-    for (std::size_t j = time_bounds.first; j <= time_bounds.second; ++j)
-    {
-            boost::optional< MeshLib::PropertyVector<double>& > tmp_vec = tmp_mesh->getProperties().getPropertyVector<double>(var.name());
-            if (!tmp_vec)
-            {
-                ERR("Vector not found");
-                continue;
-            }
-
-            if (tmp_vec->size() != mesh->getNumberOfElements())
-            {
-                ERR("Vector size doesn't fit.");
-                continue;
-            }
-
-            MeshLib::Properties& props (mesh->getProperties());
-
-            std::string iter_str (getIterationString(j, time_bounds.second);
-
-            boost::optional< MeshLib::PropertyVector<double>& > vec = 
-                props.createNewPropertyVector<double>(std::string(var.name() + iter_str), MeshLib::MeshItemType::Cell, 1);
-
-            if (!vec)
-            {
-                ERR ("Error creating vector");
-                continue;
-            }
-            vec->reserve(tmp_vec->size());
-            for (std::size_t i=0; i<tmp_vec->size(); ++i)
-                vec->push_back((*tmp_vec)[i]);
-
-            std::cout << "time step " << j << " written.\n";
-    }
-    /***********************/
-
-    delete[] length;
-    delete[] data_array;
-    return 0;
+    std::cout << "Conversion finished successfully.\n";
+    return EXIT_SUCCESS;
 }
-- 
GitLab