From 10e1610430083894216eaa1f154902e81e2ffa13 Mon Sep 17 00:00:00 2001
From: Petros Koutsolampros <commits@pklampros.io>
Date: Wed, 15 Jul 2020 23:05:37 +0300
Subject: [PATCH 1/2] Test MapInfo .mif/.mid for null-filled columns

---
 salaTest/testmapinfodata.cpp | 49 ++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/salaTest/testmapinfodata.cpp b/salaTest/testmapinfodata.cpp
index 8fe2cfbd..95a87e57 100644
--- a/salaTest/testmapinfodata.cpp
+++ b/salaTest/testmapinfodata.cpp
@@ -82,6 +82,55 @@ TEST_CASE("MapInfo failing column attribute columns", "")
     REQUIRE_FALSE(mapinfodata.readcolumnheaders(mifstream, columnheads));
 }
 
+TEST_CASE("MapInfo MID file with empty column", "")
+{
+    const float EPSILON = 0.001;
+
+    // A typical MIF
+
+    std::string mifdata =
+            "Version 300\n" \
+            "Charset \"WindowsLatin1\"\n" \
+            "Delimiter \",\"\n" \
+            "Index 1,2,3,4\n" \
+            "CoordSys Earth Projection 8, 79, \"m\", -2, 49, 0.9996012717, 400000, -100000\n";
+
+    mifdata +=
+            "Columns 4\n" \
+            "  ID Integer\n" \
+            "  Length_m Float\n" \
+            "  Height_m Float\n" \
+            "  Width_m Float\n" \
+            "Data\n" \
+            "\n" \
+            "Line 534014.29 182533.33 535008.52 182764.11\n" \
+            "    Pen (1,2,0)\n" \
+            "Line 533798.68 183094.69 534365.48 183159.01\n" \
+            "    Pen (1,2,0)\n" \
+            "Point 534014.29 182533.33\n" \
+            "    Symbol (34,0,12)";
+
+
+    // A MID with empty columns
+
+    std::string middata =
+            "1,1017.81,,\n" \
+            "2,568.795,,\n" \
+            "3,216.026,,";
+
+    ShapeMap shapeMap("MapInfoTest");
+    MapInfoData mapinfodata;
+
+    std::stringstream mifstream(mifdata);
+    std::stringstream midstream(middata);
+    REQUIRE(mapinfodata.import(mifstream, midstream, shapeMap) == MINFO_OK);
+    REQUIRE(shapeMap.getAttributeTable().getNumColumns() == 4);
+    REQUIRE(shapeMap.getAttributeTable().getColumn(0).getName() == "Id");
+    REQUIRE(shapeMap.getAttributeTable().getColumn(1).getName() == "Length_M");
+    REQUIRE(shapeMap.getAttributeTable().getColumn(2).getName() == "Height_M");
+    REQUIRE(shapeMap.getAttributeTable().getColumn(3).getName() == "Width_M");
+}
+
 TEST_CASE("Complete proper MapInfo file", "")
 {
     const float EPSILON = 0.001;

From 924c1c2da5b2976f349882e5b178fed8c1ddd3c1 Mon Sep 17 00:00:00 2001
From: Petros Koutsolampros <commits@pklampros.io>
Date: Wed, 15 Jul 2020 23:14:01 +0300
Subject: [PATCH 2/2] Make sure null columns in .mid files get a value on
 import

---
 salaTest/testmapinfodata.cpp    | 37 ++++++++++++++++++++++++++++-----
 salalib/parsers/mapinfodata.cpp | 13 +++++++++---
 2 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/salaTest/testmapinfodata.cpp b/salaTest/testmapinfodata.cpp
index 95a87e57..4dddf9b2 100644
--- a/salaTest/testmapinfodata.cpp
+++ b/salaTest/testmapinfodata.cpp
@@ -124,11 +124,38 @@ TEST_CASE("MapInfo MID file with empty column", "")
     std::stringstream mifstream(mifdata);
     std::stringstream midstream(middata);
     REQUIRE(mapinfodata.import(mifstream, midstream, shapeMap) == MINFO_OK);
-    REQUIRE(shapeMap.getAttributeTable().getNumColumns() == 4);
-    REQUIRE(shapeMap.getAttributeTable().getColumn(0).getName() == "Id");
-    REQUIRE(shapeMap.getAttributeTable().getColumn(1).getName() == "Length_M");
-    REQUIRE(shapeMap.getAttributeTable().getColumn(2).getName() == "Height_M");
-    REQUIRE(shapeMap.getAttributeTable().getColumn(3).getName() == "Width_M");
+
+    AttributeTable& att = shapeMap.getAttributeTable();
+
+    REQUIRE(att.getNumColumns() == 4);
+    REQUIRE(att.getColumn(0).getName() == "Id");
+    REQUIRE(att.getColumn(1).getName() == "Length_M");
+    REQUIRE(att.getColumn(2).getName() == "Height_M");
+    REQUIRE(att.getColumn(3).getName() == "Width_M");
+
+    std::map<int, SalaShape> shapes = shapeMap.getAllShapes();
+    auto shapeRef0 = depthmapX::getMapAtIndex(shapes, 0);
+    auto shapeRef1 = depthmapX::getMapAtIndex(shapes, 1);
+    auto shapeRef2 = depthmapX::getMapAtIndex(shapes, 2);
+
+    REQUIRE(att.getNumRows() == 3);
+    auto &row0 = att.getRow(AttributeKey(shapeRef0->first));
+    auto &row1 = att.getRow(AttributeKey(shapeRef1->first));
+    auto &row2 = att.getRow(AttributeKey(shapeRef2->first));
+
+    REQUIRE(row0.getValue("Id") == 1);
+    REQUIRE(row1.getValue("Id") == 2);
+    REQUIRE(row2.getValue("Id") == 3);
+    REQUIRE(row0.getValue("Length_M") == Approx(1017.81).epsilon(EPSILON));
+    REQUIRE(row1.getValue("Length_M") == Approx(568.795).epsilon(EPSILON));
+    REQUIRE(row2.getValue("Length_M") == Approx(216.026).epsilon(EPSILON));
+    REQUIRE(row0.getValue("Height_M") == -1);
+    REQUIRE(row1.getValue("Height_M") == -1);
+    REQUIRE(row2.getValue("Height_M") == -1);
+    REQUIRE(row0.getValue("Width_M") == -1);
+    REQUIRE(row1.getValue("Width_M") == -1);
+    REQUIRE(row2.getValue("Width_M") == -1);
+
 }
 
 TEST_CASE("Complete proper MapInfo file", "")
diff --git a/salalib/parsers/mapinfodata.cpp b/salalib/parsers/mapinfodata.cpp
index f4b011eb..2ea43f5a 100644
--- a/salalib/parsers/mapinfodata.cpp
+++ b/salalib/parsers/mapinfodata.cpp
@@ -191,10 +191,17 @@ int MapInfoData::import(std::istream& miffile, std::istream& midfile, ShapeMap&
                   int length = (here < line.length()) ? here-first-1 : here-first;
                   std::string field = line.substr(first,length);
                   first = here;
-                  if (reading == readable[nextreadable]) {
-                     float val = stof(field);
+                  if (length == 1 && field[0] == m_delimiter) {
+                     // field is empty
+                     row.setValue(colindexes[nextreadable], -1);
+                     nextreadable++; // go to next column
+                  } else if (reading == readable[nextreadable]) {
+                     float val = -1;
+                     if(!field.empty()) {
+                         val = stof(field);
+                     }
                      row.setValue(colindexes[nextreadable],val);
-                     nextreadable++;
+                     nextreadable++; // go to next column
                   }
                   reading++;
                }