OGRShapeLayer::OGRShapeLayer( OGRShapeDataSource* poDSIn,
const char * pszFullNameIn,
SHPHandle hSHPIn, DBFHandle hDBFIn,
OGRSpatialReference *poSRSIn, bool bSRSSetIn,
bool bUpdate,
OGRwkbGeometryType eReqType,
char ** papszCreateOptions ) :
OGRAbstractProxiedLayer(poDSIn->GetPool()),
poDS(poDSIn),
iNextShapeId(0),
nTotalShapeCount(0),
pszFullName(CPLStrdup(pszFullNameIn)),
hSHP(hSHPIn),
hDBF(hDBFIn),
bUpdateAccess(bUpdate),
eRequestedGeomType(eReqType),
panMatchingFIDs(nullptr),
iMatchingFID(0),
m_poFilterGeomLastValid(nullptr),
nSpatialFIDCount(0),
panSpatialFIDs(nullptr),
bHeaderDirty(false),
bSHPNeedsRepack(false),
bCheckedForQIX(false),
hQIX(nullptr),
bCheckedForSBN(false),
hSBN(nullptr),
bSbnSbxDeleted(false),
bTruncationWarningEmitted(false),
bHSHPWasNonNULL(hSHPIn != nullptr),
bHDBFWasNonNULL(hDBFIn != nullptr),
eFileDescriptorsState(FD_OPENED),
bResizeAtClose(false),
bCreateSpatialIndexAtClose(false),
bRewindOnWrite(false),
m_bAutoRepack(false),
m_eNeedRepack(MAYBE)
{
if( hSHP != nullptr )
{
nTotalShapeCount = hSHP->nRecords;
if( hDBF != nullptr && hDBF->nRecords != nTotalShapeCount )
{
CPLDebug(
"Shape",
"Inconsistent record number in .shp (%d) and in .dbf (%d)",
hSHP->nRecords, hDBF->nRecords);
}
}
else if( hDBF != nullptr )
{
nTotalShapeCount = hDBF->nRecords;
}
#ifdef DEBUG
else
{
CPLError(CE_Fatal, CPLE_AssertionFailed,
"Should not happen: Both hSHP and hDBF are nullptrs");
}
#endif
if( !TouchLayer() )
{
CPLDebug("Shape", "TouchLayer in shape ctor failed. ");
}
if( hDBF != nullptr && hDBF->pszCodePage != nullptr )
{
CPLDebug( "Shape", "DBF Codepage = %s for %s",
hDBF->pszCodePage, pszFullName );
// Not too sure about this, but it seems like better than nothing.
osEncoding = ConvertCodePage( hDBF->pszCodePage );
}
if( hDBF != nullptr )
{
if( !(hDBF->nUpdateYearSince1900 == 95 &&
hDBF->nUpdateMonth == 7 &&
hDBF->nUpdateDay == 26) )
{
SetMetadataItem(
"DBF_DATE_LAST_UPDATE",
CPLSPrintf("%04d-%02d-%02d",
hDBF->nUpdateYearSince1900 + 1900,
hDBF->nUpdateMonth, hDBF->nUpdateDay) );
}
struct tm tm;
CPLUnixTimeToYMDHMS(time(nullptr), &tm);
DBFSetLastModifiedDate( hDBF, tm.tm_year,
tm.tm_mon + 1, tm.tm_mday );
}
const char* pszShapeEncoding =
CSLFetchNameValue(poDS->GetOpenOptions(), "ENCODING");
if( pszShapeEncoding == nullptr && osEncoding == "")
pszShapeEncoding = CSLFetchNameValue( papszCreateOptions, "ENCODING" );
if( pszShapeEncoding == nullptr )
pszShapeEncoding = CPLGetConfigOption( "SHAPE_ENCODING", nullptr );
if( pszShapeEncoding != nullptr )
osEncoding = pszShapeEncoding;
if( osEncoding != "" )
{
CPLDebug( "Shape", "Treating as encoding '%s'.", osEncoding.c_str() );
if( !OGRShapeLayer::TestCapability(OLCStringsAsUTF8) )
{
CPLDebug( "Shape", "Cannot recode from '%s'. Disabling recoding",
osEncoding.c_str() );
osEncoding = "";
}
}
poFeatureDefn = SHPReadOGRFeatureDefn(
CPLGetBasename(pszFullName),
hSHP, hDBF, osEncoding,
CPLFetchBool(poDS->GetOpenOptions(), "ADJUST_TYPE", false) );
// To make sure that
// GetLayerDefn()->GetGeomFieldDefn(0)->GetSpatialRef() == GetSpatialRef()
OGRwkbGeometryType eGeomType = poFeatureDefn->GetGeomType();
if( eGeomType != wkbNone )
{
OGRwkbGeometryType eType = wkbUnknown;
if( eRequestedGeomType == wkbNone )
{
eType = eGeomType;
const char* pszAdjustGeomType = CSLFetchNameValueDef(
poDS->GetOpenOptions(), "ADJUST_GEOM_TYPE", "FIRST_SHAPE");
const bool bFirstShape = EQUAL(pszAdjustGeomType, "FIRST_SHAPE");
const bool bAllShapes = EQUAL(pszAdjustGeomType, "ALL_SHAPES");
if( (hSHP != nullptr) && (hSHP->nRecords > 0) && wkbHasM(eType) &&
(bFirstShape || bAllShapes) )
{
bool bMIsUsed = false;
for( int iShape=0; iShape < hSHP->nRecords; iShape++ )
{
SHPObject *psShape = SHPReadObject( hSHP, iShape );
if( psShape )
{
if( psShape->bMeasureIsUsed &&
psShape->nVertices > 0 &&
psShape->padfM != nullptr )
{
for( int i = 0; i < psShape->nVertices; i++ )
{
// Per the spec, if the M value is smaller than
// -1e38, it is a nodata value.
if( psShape->padfM[i] > -1e38 )
{
bMIsUsed = true;
break;
}
}
}
SHPDestroyObject(psShape);
}
if( bFirstShape || bMIsUsed )
break;
}
if( !bMIsUsed )
eType = OGR_GT_SetModifier(eType, wkbHasZ(eType), FALSE);
}
}
else
{
eType = eRequestedGeomType;
}
OGRShapeGeomFieldDefn* poGeomFieldDefn =
new OGRShapeGeomFieldDefn(pszFullName, eType, bSRSSetIn, poSRSIn);
poFeatureDefn->SetGeomType(wkbNone);
poFeatureDefn->AddGeomFieldDefn(poGeomFieldDefn, FALSE);
}
else if( bSRSSetIn && poSRSIn != nullptr )
{
poSRSIn->Release();
}
SetDescription( poFeatureDefn->GetName() );
bRewindOnWrite =
CPLTestBool(CPLGetConfigOption( "SHAPE_REWIND_ON_WRITE", "YES" ));
}