Skip to content

Commit

Permalink
Merge pull request #9515 from rouault/shape_bool
Browse files Browse the repository at this point in the history
Shapefile: add read/write support for DBF Logical field type mapped to OGR OFSTBoolean
  • Loading branch information
rouault authored Mar 25, 2024
2 parents 1f2e264 + 5805d0a commit 07de246
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 23 deletions.
46 changes: 46 additions & 0 deletions autotest/ogr/ogr_shape.py
Original file line number Diff line number Diff line change
Expand Up @@ -6066,3 +6066,49 @@ def test_ogr_shape_arrow_stream_fid_optim(tmp_vsimem):
== "YES"
)
assert len(batches) == 0


###############################################################################
# Test DBF Logical field type


@gdaltest.enable_exceptions()
def test_ogr_shape_logical_field(tmp_vsimem):

filename = tmp_vsimem / "test_ogr_shape_logical_field.shp"
ds = gdal.GetDriverByName("ESRI Shapefile").Create(
filename, 0, 0, 0, gdal.GDT_Unknown
)
lyr = ds.CreateLayer("test")
fld_defn = ogr.FieldDefn("bool_field", ogr.OFTInteger)
fld_defn.SetSubType(ogr.OFSTBoolean)
lyr.CreateField(fld_defn)
lyr.CreateField(ogr.FieldDefn("int_field", ogr.OFTInteger))
f = ogr.Feature(lyr.GetLayerDefn())
f["bool_field"] = True
f["int_field"] = 1234
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f["bool_field"] = False
f["int_field"] = -1234
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f["bool_field"] = None
lyr.CreateFeature(f)
f = None
ds.Close()

ds = ogr.Open(filename)
lyr = ds.GetLayer(0)
fld_defn = lyr.GetLayerDefn().GetFieldDefn(0)
assert fld_defn.GetType() == ogr.OFTInteger
assert fld_defn.GetSubType() == ogr.OFSTBoolean
assert fld_defn.GetWidth() == 1
f = lyr.GetNextFeature()
assert f["bool_field"] == True
assert f["int_field"] == 1234
f = lyr.GetNextFeature()
assert f["bool_field"] == False
assert f["int_field"] == -1234
f = lyr.GetNextFeature()
assert f["bool_field"] is None
1 change: 1 addition & 0 deletions ogr/ogrsf_frmts/shape/ogrshapedriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ void RegisterOGRShape()

poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES,
"Integer Integer64 Real String Date");
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
16 changes: 12 additions & 4 deletions ogr/ogrsf_frmts/shape/ogrshapelayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2042,10 +2042,18 @@ OGRErr OGRShapeLayer::CreateField(const OGRFieldDefn *poFieldDefn,
switch (oModFieldDefn.GetType())
{
case OFTInteger:
chType = 'N';
nWidth = oModFieldDefn.GetWidth();
if (nWidth == 0)
nWidth = 9;
if (oModFieldDefn.GetSubType() == OFSTBoolean)
{
chType = 'L';
nWidth = 1;
}
else
{
chType = 'N';
nWidth = oModFieldDefn.GetWidth();
if (nWidth == 0)
nWidth = 9;
}
break;

case OFTInteger64:
Expand Down
66 changes: 47 additions & 19 deletions ogr/ogrsf_frmts/shape/shape2ogr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1172,6 +1172,11 @@ OGRFeatureDefn *SHPReadOGRFeatureDefn(const char *pszName, SHPHandle hSHP,
}
else if (eDBFType == FTInteger)
oField.SetType(OFTInteger);
else if (eDBFType == FTLogical)
{
oField.SetType(OFTInteger);
oField.SetSubType(OFSTBoolean);
}
else
oField.SetType(OFTString);

Expand Down Expand Up @@ -1431,8 +1436,22 @@ OGRFeature *SHPReadOGRFeature(SHPHandle hSHP, DBFHandle hDBF,
}
else
{
poFeature->SetField(
iField, DBFReadStringAttribute(hDBF, iShape, iField));
if (poFieldDefn->GetSubType() == OFSTBoolean)
{
const char *pszVal =
DBFReadLogicalAttribute(hDBF, iShape, iField);
poFeature->SetField(
iField, pszVal[0] == 'T' || pszVal[0] == 't' ||
pszVal[0] == 'Y' || pszVal[0] == 'y'
? 1
: 0);
}
else
{
const char *pszVal =
DBFReadStringAttribute(hDBF, iShape, iField);
poFeature->SetField(iField, pszVal);
}
}
break;
}
Expand Down Expand Up @@ -1682,27 +1701,36 @@ OGRErr SHPWriteOGRFeature(SHPHandle hSHP, DBFHandle hDBF,
case OFTInteger:
case OFTInteger64:
{
char szValue[32] = {};
const int nFieldWidth = poFieldDefn->GetWidth();
snprintf(szValue, sizeof(szValue),
"%*" CPL_FRMT_GB_WITHOUT_PREFIX "d",
std::min(nFieldWidth,
static_cast<int>(sizeof(szValue)) - 1),
poFeature->GetFieldAsInteger64(iField));

const int nStrLen = static_cast<int>(strlen(szValue));
if (nStrLen > nFieldWidth)
if (poFieldDefn->GetSubType() == OFSTBoolean)
{
if (GrowField(hDBF, iField, poFieldDefn, nStrLen) !=
OGRERR_NONE)
DBFWriteAttributeDirectly(
hDBF, static_cast<int>(poFeature->GetFID()), iField,
poFeature->GetFieldAsInteger(iField) ? "T" : "F");
}
else
{
char szValue[32] = {};
const int nFieldWidth = poFieldDefn->GetWidth();
snprintf(szValue, sizeof(szValue),
"%*" CPL_FRMT_GB_WITHOUT_PREFIX "d",
std::min(nFieldWidth,
static_cast<int>(sizeof(szValue)) - 1),
poFeature->GetFieldAsInteger64(iField));

const int nStrLen = static_cast<int>(strlen(szValue));
if (nStrLen > nFieldWidth)
{
return OGRERR_FAILURE;
if (GrowField(hDBF, iField, poFieldDefn, nStrLen) !=
OGRERR_NONE)
{
return OGRERR_FAILURE;
}
}
}

DBFWriteAttributeDirectly(hDBF,
static_cast<int>(poFeature->GetFID()),
iField, szValue);
DBFWriteAttributeDirectly(
hDBF, static_cast<int>(poFeature->GetFID()), iField,
szValue);
}

break;
}
Expand Down

0 comments on commit 07de246

Please sign in to comment.