Skip to content

Commit

Permalink
MapInfo .mif/.tab: implement read/write support for MapInfo logical t…
Browse files Browse the repository at this point in the history
…ype to OGR OFSTBoolean

Fixes qgis/QGIS#57359
  • Loading branch information
rouault committed May 8, 2024
1 parent c27a689 commit 49d741f
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 53 deletions.
Binary file modified autotest/ogr/data/mitab/all_possible_fields.dat
Binary file not shown.
3 changes: 2 additions & 1 deletion autotest/ogr/data/mitab/all_possible_fields.mid
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
"test",120,12345,123456789012345,12.34,12.34,20221231,235900000,20220323145600000,T
"test",120,12345,123456789012345,12.34,12.34,20221231,235900000,20220323145600000,T
"test",120,12345,123456789012345,12.34,12.34,20221231,235900000,20220323145600000,F
35 changes: 18 additions & 17 deletions autotest/ogr/data/mitab/all_possible_fields.mif
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
Version 900
Charset "WindowsLatin1"
Delimiter ","
Columns 10
field1 Char(10)
Field2 Integer
Field3 Smallint
Field4 LargeInt
Field5 Float
Field6 Decimal(10, 2)
Field7 Date
Field8 Time
Field9 DateTime
Field10 Logical
Data

none
Version 900
Charset "WindowsLatin1"
Delimiter ","
Columns 10
field1 Char(10)
Field2 Integer
Field3 Smallint
Field4 LargeInt
Field5 Float
Field6 Decimal(10, 2)
Field7 Date
Field8 Time
Field9 DateTime
Field10 Logical
Data

none
none
56 changes: 33 additions & 23 deletions autotest/ogr/ogr_mitab.py
Original file line number Diff line number Diff line change
Expand Up @@ -2507,11 +2507,11 @@ def test_ogr_mitab_read_multi_line_mid():
f = lyr.GetNextFeature()
assert f["Name"] == "NAME1"
assert f["Notes"] == "MULTI\n\nLINE"
assert f["Awesome"] == "F"
assert f["Awesome"] is False
f = lyr.GetNextFeature()
assert f["Name"] == "NAME2"
assert f["Notes"] == "MULTI\nLINE2"
assert f["Awesome"] == "F"
assert f["Awesome"] is False


###############################################################################
Expand All @@ -2536,38 +2536,48 @@ def test_ogr_mitab_read_single_field_mid():

@pytest.mark.parametrize("ext", ["mif", "tab"])
def test_ogr_mitab_read_write_all_data_types(tmp_vsimem, ext):
def check_features(lyr):
f = lyr.GetNextFeature()
assert f["field1"] == "test"
assert f["Field2"] == 120
assert f["Field3"] == 12345
assert (
lyr.GetLayerDefn()
.GetFieldDefn(lyr.GetLayerDefn().GetFieldIndex("Field4"))
.GetType()
== ogr.OFTInteger64
)
assert f["Field4"] == 123456789012345
assert f["Field5"] == 12.34
assert f["Field6"] == 12.34
assert f["Field7"] == "2022/12/31"
assert f["Field8"] == "23:59:00"
assert f["Field9"] == "2022/03/23 14:56:00"
assert f["Field10"] is True

f = lyr.GetNextFeature()
assert f["Field10"] is False

ds = ogr.Open("data/mitab/all_possible_fields." + ext)
lyr = ds.GetLayer(0)
f = lyr.GetNextFeature()
assert f["field1"] == "test"
assert f["Field2"] == 120
assert f["Field3"] == 12345
assert (
lyr.GetLayerDefn()
.GetFieldDefn(lyr.GetLayerDefn().GetFieldIndex("Field4"))
.GetType()
== ogr.OFTInteger64
)
assert f["Field4"] == 123456789012345
assert f["Field5"] == 12.34
assert f["Field6"] == 12.34
assert f["Field7"] == "2022/12/31"
assert f["Field8"] == "23:59:00"
assert f["Field9"] == "2022/03/23 14:56:00"
assert f["Field10"] == "T"
check_features(lyr)

filename = tmp_vsimem / f"test_ogr_mitab_read_write_all_data_types.{ext}"
out_ds = ogr.GetDriverByName("MapInfo File").CreateDataSource(filename)
out_lyr = out_ds.CreateLayer("test", geom_type=ogr.wkbNone)
for i in range(lyr.GetLayerDefn().GetFieldCount()):
out_lyr.CreateField(lyr.GetLayerDefn().GetFieldDefn(i))
out_f = ogr.Feature(out_lyr.GetLayerDefn())
out_f.SetFrom(f)
assert out_lyr.CreateFeature(out_f) == ogr.OGRERR_NONE
out_f = None
for f in lyr:
out_f = ogr.Feature(out_lyr.GetLayerDefn())
out_f.SetFrom(f)
assert out_lyr.CreateFeature(out_f) == ogr.OGRERR_NONE
out_f = None
out_ds = None

ds = ogr.Open(filename)
lyr = ds.GetLayer(0)
check_features(lyr)


###############################################################################

Expand Down
9 changes: 7 additions & 2 deletions ogr/ogrsf_frmts/mitab/mitab_feature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,11 @@ int TABFeature::ReadRecordFromDATFile(TABDATFile *poDATFile)
{
const char *pszValue = poDATFile->ReadLogicalField(
poDATFile->GetFieldWidth(iField));
SetField(iField, pszValue);
char ch = pszValue[0];
SetField(iField, (ch == 'T' || ch == 't' || ch == 'Y' ||
ch == 'y' || ch == '1')
? 1
: 0);
break;
}
case TABFDate:
Expand Down Expand Up @@ -558,7 +562,8 @@ int TABFeature::WriteRecordToDATFile(TABDATFile *poDATFile,
break;
case TABFLogical:
nStatus = poDATFile->WriteLogicalField(
GetFieldAsString(iField), poINDFile, panIndexNo[iField]);
GetFieldAsInteger(iField) ? "T" : "F", poINDFile,
panIndexNo[iField]);
break;
case TABFDate:
#ifdef MITAB_USE_OFTDATETIME
Expand Down
31 changes: 29 additions & 2 deletions ogr/ogrsf_frmts/mitab/mitab_feature_mif.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,9 @@ int TABFeature::ReadRecordFromMIDFile(MIDDATAFile *fp)
return -1;
}

OGRFieldDefn *poFDefn = nullptr;
for (int i = 0; i < nFields; i++)
{
poFDefn = GetFieldDefnRef(i);
const auto poFDefn = GetFieldDefnRef(i);
switch (poFDefn->GetType())
{
#ifdef MITAB_USE_OFTDATETIME
Expand Down Expand Up @@ -141,6 +140,22 @@ int TABFeature::ReadRecordFromMIDFile(MIDDATAFile *fp)
break;
}
#endif
case OFTInteger:
{
if (poFDefn->GetSubType() == OFSTBoolean)
{
char ch = papszToken[i][0];
SetField(i, (ch == 'T' || ch == 't' || ch == 'Y' ||
ch == 'y' || ch == '1')
? 1
: 0);
}
else
{
SetField(i, papszToken[i]);
}
break;
}
case OFTString:
{
CPLString osValue(papszToken[i]);
Expand Down Expand Up @@ -289,6 +304,18 @@ int TABFeature::WriteRecordToMIDFile(MIDDATAFile *fp)
break;
}
#endif
case OFTInteger:
{
if (poFDefn->GetSubType() == OFSTBoolean)
{
fp->WriteLine("%c", GetFieldAsInteger(iField) ? 'T' : 'F');
}
else
{
fp->WriteLine("%s", GetFieldAsString(iField));
}
break;
}
default:
fp->WriteLine("%s", GetFieldAsString(iField));
}
Expand Down
14 changes: 11 additions & 3 deletions ogr/ogrsf_frmts/mitab/mitab_imapinfofile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,9 +445,17 @@ int IMapInfoFile::GetTABType(const OGRFieldDefn *poField,

if (poField->GetType() == OFTInteger)
{
eTABType = TABFInteger;
if (nWidth == 0)
nWidth = 12;
if (poField->GetSubType() == OFSTBoolean)
{
eTABType = TABFLogical;
nWidth = 1;
}
else
{
eTABType = TABFInteger;
if (nWidth == 0)
nWidth = 12;
}
}
else if (poField->GetType() == OFTInteger64)
{
Expand Down
7 changes: 5 additions & 2 deletions ogr/ogrsf_frmts/mitab/mitab_miffile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1576,7 +1576,9 @@ int MIFFile::SetFeatureDefn(
switch (poFieldDefn->GetType())
{
case OFTInteger:
eMapInfoType = TABFInteger;
eMapInfoType = poFieldDefn->GetSubType() == OFSTBoolean
? TABFLogical
: TABFInteger;
break;
case OFTReal:
eMapInfoType = TABFFloat;
Expand Down Expand Up @@ -1764,7 +1766,8 @@ int MIFFile::AddFieldNative(const char *pszName, TABFieldType eMapInfoType,
/*-------------------------------------------------
* LOGICAL type (value "T" or "F")
*------------------------------------------------*/
poFieldDefn = new OGRFieldDefn(osName.c_str(), OFTString);
poFieldDefn = new OGRFieldDefn(osName.c_str(), OFTInteger);
poFieldDefn->SetSubType(OFSTBoolean);
poFieldDefn->SetWidth(1);
break;
default:
Expand Down
1 change: 1 addition & 0 deletions ogr/ogrsf_frmts/mitab/mitab_ogr_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ void RegisterOGRTAB()
poDriver->SetMetadataItem(
GDAL_DMD_CREATIONFIELDDATATYPES,
"Integer Integer64 Real String Date DateTime Time");
poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, "Boolean");
poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS,
"WidthPrecision");
poDriver->SetMetadataItem(GDAL_DMD_ALTER_FIELD_DEFN_FLAGS,
Expand Down
10 changes: 7 additions & 3 deletions ogr/ogrsf_frmts/mitab/mitab_tabfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,8 @@ int TABFile::ParseTABFileFields()
*------------------------------------------------*/
nStatus = m_poDATFile->ValidateFieldInfoFromTAB(
iField, osFieldName, TABFLogical, 0, 0);
poFieldDefn = new OGRFieldDefn(osFieldName, OFTString);
poFieldDefn = new OGRFieldDefn(osFieldName, OFTInteger);
poFieldDefn->SetSubType(OFSTBoolean);
poFieldDefn->SetWidth(1);
}
else
Expand Down Expand Up @@ -2044,7 +2045,9 @@ int TABFile::SetFeatureDefn(
switch (poFieldDefn->GetType())
{
case OFTInteger:
eMapInfoType = TABFInteger;
eMapInfoType = poFieldDefn->GetSubType() == OFSTBoolean
? TABFLogical
: TABFInteger;
break;
case OFTReal:
if (poFieldDefn->GetWidth() > 0 ||
Expand Down Expand Up @@ -2226,7 +2229,8 @@ int TABFile::AddFieldNative(const char *pszName, TABFieldType eMapInfoType,
/*-------------------------------------------------
* LOGICAL type (value "T" or "F")
*------------------------------------------------*/
poFieldDefn = new OGRFieldDefn(osName.c_str(), OFTString);
poFieldDefn = new OGRFieldDefn(osName.c_str(), OFTInteger);
poFieldDefn->SetSubType(OFSTBoolean);
poFieldDefn->SetWidth(1);
break;
default:
Expand Down

0 comments on commit 49d741f

Please sign in to comment.