/*******************************************************************************
* Project: NextGIS Web Driver
* Purpose: Implements NextGIS Web Driver
* Author: Dmitry Baryshnikov, dmitry.baryshnikov@nextgis.com
* Language: C++
*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2018, NextGIS
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/
#include "ogr_ngw.h"
#include "cpl_http.h"
#include "gdal_proxy.h"
class NGWWrapperRasterBand : public GDALProxyRasterBand
{
GDALRasterBand *poBaseBand;
protected:
virtual GDALRasterBand *RefUnderlyingRasterBand() override { return poBaseBand; }
public:
explicit NGWWrapperRasterBand( GDALRasterBand* poBaseBandIn ) :
poBaseBand( poBaseBandIn )
{
eDataType = poBaseBand->GetRasterDataType();
poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
}
virtual ~NGWWrapperRasterBand() {}
};
/*
* OGRNGWDataset()
*/
OGRNGWDataset::OGRNGWDataset() :
bReadWrite(false),
nBatchSize(-1),
nPageSize(-1),
bFetchedPermissions(false),
bHasFeaturePaging(false),
bMetadataDerty(false),
papoLayers(nullptr),
nLayers(0),
poRasterDS(nullptr),
nRasters(0),
nCacheExpires(604800), // 7 days
nCacheMaxSize(67108864) // 64 MB
{}
/*
* ~OGRNGWDataset()
*/
OGRNGWDataset::~OGRNGWDataset()
{
// Last sync with server.
FlushCache();
if( poRasterDS != nullptr )
{
GDALClose( poRasterDS );
poRasterDS = nullptr;
}
for( int i = 0; i < nLayers; ++i )
{
delete papoLayers[i];
}
CPLFree( papoLayers );
}
/*
* FetchPermissions()
*/
void OGRNGWDataset::FetchPermissions()
{
if( bFetchedPermissions )
{
return;
}
if( bReadWrite )
{
// Check connection and is it read only.
char **papszHTTPOptions = GetHeaders();
stPermissions = NGWAPI::CheckPermissions( osUrl, osResourceId,
papszHTTPOptions, bReadWrite );
CSLDestroy( papszHTTPOptions );
}
else
{
stPermissions.bDataCanRead = true;
stPermissions.bResourceCanRead = true;
stPermissions.bDatastructCanRead = true;
stPermissions.bMetadataCanRead = true;
}
bFetchedPermissions = true;
}
/*
* TestCapability()
*/
int OGRNGWDataset::TestCapability( const char *pszCap )
{
FetchPermissions();
if( EQUAL(pszCap, ODsCCreateLayer) )
{
return stPermissions.bResourceCanCreate;
}
else if( EQUAL(pszCap, ODsCDeleteLayer) )
{
return stPermissions.bResourceCanDelete;
}
else if( EQUAL(pszCap, "RenameLayer") )
{
return stPermissions.bResourceCanUpdate;
}
else if( EQUAL(pszCap, ODsCRandomLayerWrite) )
{
return stPermissions.bDataCanWrite; // FIXME: Check on resource level is this permission set?
}
else if( EQUAL(pszCap, ODsCRandomLayerRead) )
{
return stPermissions.bDataCanRead;
}
else
{
return FALSE;
}
}
/*
* GetLayer()
*/
OGRLayer *OGRNGWDataset::GetLayer( int iLayer )
{
if( iLayer < 0 || iLayer >= nLayers )
{
return nullptr;
}
else
{
return papoLayers[iLayer];
}
}
/*
* Open()
*/
bool OGRNGWDataset::Open( const std::string &osUrlIn,
const std::string &osResourceIdIn, char **papszOpenOptionsIn,
bool bUpdateIn, int nOpenFlagsIn )
{
osUrl = osUrlIn;
osResourceId = osResourceIdIn;
bReadWrite = bUpdateIn;
osUserPwd = CSLFetchNameValueDef( papszOpenOptionsIn, "USERPWD",
CPLGetConfigOption("NGW_USERPWD", ""));
nBatchSize = atoi( CSLFetchNameValueDef( papszOpenOptionsIn,
"BATCH_SIZE", CPLGetConfigOption("NGW_BATCH_SIZE", "-1") ) );
nPageSize = atoi( CSLFetchNameValueDef(papszOpenOptionsIn, "PAGE_SIZE",
CPLGetConfigOption("NGW_PAGE_SIZE", "-1") ) );
if( nPageSize == 0 )
{
nPageSize = -1;
}
nCacheExpires = atoi( CSLFetchNameValueDef(papszOpenOptionsIn, "CACHE_EXPIRES",
CPLGetConfigOption("NGW_CACHE_EXPIRES", "604800") ) );
nCacheMaxSize = atoi( CSLFetchNameValueDef(papszOpenOptionsIn, "CACHE_MAX_SIZE",
CPLGetConfigOption("NGW_CACHE_MAX_SIZE", "67108864") ) );
return Init( nOpenFlagsIn );
}
/*
* Open()
*
* The pszFilename templates:
* - NGW:http://some.nextgis.com/resource/0
* - NGW:http://some.nextgis.com:8000/test/resource/0
*/
bool OGRNGWDataset::Open( const char *pszFilename, char **papszOpenOptionsIn,
bool bUpdateIn, int nOpenFlagsIn )
{
NGWAPI::Uri stUri = NGWAPI::ParseUri(pszFilename);
if( stUri.osPrefix != "NGW" )
{
CPLError(CE_Failure, CPLE_NotSupported,
"Unsupported name %s", pszFilename);
return false;
}
osUrl = stUri.osAddress;
osResourceId = stUri.osResourceId;
return Open( stUri.osAddress, stUri.osResourceId, papszOpenOptionsIn,
bUpdateIn, nOpenFlagsIn );
}
/*
* Init()
*/
bool OGRNGWDataset::Init(int nOpenFlagsIn)
{
// NOTE: Skip check API version at that moment. We expected API v3.
// Get resource details.
CPLJSONDocument oResourceDetailsReq;
char **papszHTTPOptions = GetHeaders();
bool bResult = oResourceDetailsReq.LoadUrl( NGWAPI::GetResource( osUrl,
osResourceId ), papszHTTPOptions );
if( bResult )
{
CPLJSONObject oRoot = oResourceDetailsReq.GetRoot();
if( oRoot.IsValid() )
{
std::string osResourceType = oRoot.GetString("resource/cls");
FillMetadata( oRoot );
if( osResourceType == "resource_group" )
{
// Check feature paging.
FillCapabilities( papszHTTPOptions );
if( oRoot.GetBool( "resource/children", false ) ) {
// Get child resources.
bResult = FillResources( papszHTTPOptions, nOpenFlagsIn );
}
}
else if( (osResourceType == "vector_layer" ||
osResourceType == "postgis_layer") )
{
// Cehck feature paging.
FillCapabilities( papszHTTPOptions );
// Add vector layer.
AddLayer( oRoot, papszHTTPOptions, nOpenFlagsIn );
}
else if( ( osResourceType == "mapserver_style" ||
osResourceType == "qgis_vector_style" ||
osResourceType == "raster_style" ||
osResourceType == "wmsclient_layer") &&
nOpenFlagsIn & GDAL_OF_RASTER )
{
// GetExtent from parent.
OGREnvelope stExtent;
std::string osParentId = oRoot.GetString("resource/parent/id");
bool bExtentResult = NGWAPI::GetExtent(osUrl, osParentId,
papszHTTPOptions, 3857, stExtent);
if( !bExtentResult )
{
// Set full extent for EPSG:3857.
stExtent.MinX = -20037508.34;
stExtent.MaxX = 20037508.34;
stExtent.MinY = -20037508.34;
stExtent.MaxY = 20037508.34;
}
CPLDebug("NGW", "Raster extent is: %f, %f, %f, %f",
stExtent.MinX, stExtent.MinY,
stExtent.MaxX, stExtent.MaxY);
int nEPSG = 3857;
// Get parent details. We can skip this as default SRS in NGW is 3857.
if( osResourceType == "wmsclient_layer" )
{
nEPSG = oRoot.GetInteger("wmsclient_layer/srs/id", nEPSG);
}
else
{
CPLJSONDocument oResourceReq;
bResult = oResourceReq.LoadUrl( NGWAPI::GetResource( osUrl,
osResourceId ), papszHTTPOptions );
if( bResult )
{
CPLJSONObject oParentRoot = oResourceReq.GetRoot();
if( osResourceType == "mapserver_style" ||
osResourceType == "qgis_vector_style" )
{
nEPSG = oParentRoot.GetInteger("vector_layer/srs/id", nEPSG);
}
else if( osResourceType == "raster_style")
{
nEPSG = oParentRoot.GetInteger("raster_layer/srs/id", nEPSG);
}
}
}
// Create raster dataset.
std::string osRasterUrl = NGWAPI::GetTMS(osUrl, osResourceId);
char* pszRasterUrl = CPLEscapeString(osRasterUrl.c_str(), -1, CPLES_XML);
const char *pszConnStr = CPLSPrintf(""
"%s"
"-20037508.3420037508.34"
"20037508.34-20037508.34"
"%d1"
"1top"
"EPSG:%d256"
"256%d"
"file%d%d"
"204,404",
pszRasterUrl,
22, // NOTE: We have no limit in zoom levels.
nEPSG, // NOTE: Default SRS is EPSG:3857.
4,
nCacheExpires,
nCacheMaxSize);
CPLFree( pszRasterUrl );
poRasterDS = reinterpret_cast(GDALOpenEx(pszConnStr,
GDAL_OF_READONLY | GDAL_OF_RASTER | GDAL_OF_INTERNAL, nullptr,
nullptr, nullptr));
if( poRasterDS )
{
bResult = true;
nRasterXSize = poRasterDS->GetRasterXSize();
nRasterYSize = poRasterDS->GetRasterYSize();
for( int iBand = 1; iBand <= poRasterDS->GetRasterCount();
iBand++ )
{
SetBand( iBand, new NGWWrapperRasterBand(
poRasterDS->GetRasterBand( iBand )) );
}
// Set pixel limits.
bool bHasTransform = false;
double geoTransform[6] = { 0.0 };
double invGeoTransform[6] = { 0.0 };
if(poRasterDS->GetGeoTransform(geoTransform) == CE_None)
{
bHasTransform = GDALInvGeoTransform(geoTransform,
invGeoTransform) == TRUE;
}
if(bHasTransform)
{
GDALApplyGeoTransform(invGeoTransform, stExtent.MinX,
stExtent.MinY, &stPixelExtent.MinX, &stPixelExtent.MaxY);
GDALApplyGeoTransform(invGeoTransform, stExtent.MaxX,
stExtent.MaxY, &stPixelExtent.MaxX, &stPixelExtent.MinY);
CPLDebug("NGW", "Raster extent in px is: %f, %f, %f, %f",
stPixelExtent.MinX, stPixelExtent.MinY,
stPixelExtent.MaxX, stPixelExtent.MaxY);
}
else
{
stPixelExtent.MinX = 0.0;
stPixelExtent.MinY = 0.0;
stPixelExtent.MaxX = std::numeric_limits::max();
stPixelExtent.MaxY = std::numeric_limits::max();
}
}
else
{
bResult = false;
}
}
else if( osResourceType == "raster_layer" &&
nOpenFlagsIn & GDAL_OF_RASTER )
{
AddRaster( oRoot, papszHTTPOptions );
}
else
{
bResult = false;
}
// TODO: Add support for baselayers, webmap, wfsserver_service, wmsserver_service.
}
}
CSLDestroy( papszHTTPOptions );
return bResult;
}
/*
* FillResources()
*/
bool OGRNGWDataset::FillResources( char **papszOptions, int nOpenFlagsIn )
{
CPLJSONDocument oResourceDetailsReq;
bool bResult = oResourceDetailsReq.LoadUrl( NGWAPI::GetChildren( osUrl,
osResourceId ), papszOptions );
if( bResult )
{
CPLJSONArray oChildren(oResourceDetailsReq.GetRoot());
for( int i = 0; i < oChildren.Size(); ++i )
{
CPLJSONObject oChild = oChildren[i];
std::string osResourceType = oChild.GetString("resource/cls");
if( (osResourceType == "vector_layer" ||
osResourceType == "postgis_layer") )
{
// Add vector layer. If failed, try next layer.
AddLayer( oChild, papszOptions, nOpenFlagsIn );
}
else if( (osResourceType == "raster_layer" ||
osResourceType == "wmsclient_layer") & nOpenFlagsIn & GDAL_OF_RASTER )
{
AddRaster( oChild, papszOptions );
}
// TODO: Add support for baselayers, webmap, wfsserver_service, wmsserver_service.
}
}
return bResult;
}
/*
* AddLayer()
*/
void OGRNGWDataset::AddLayer( const CPLJSONObject &oResourceJsonObject,
char **papszOptions, int nOpenFlagsIn )
{
std::string osLayerResourceId;
if( nOpenFlagsIn & GDAL_OF_VECTOR )
{
OGRNGWLayer *poLayer = new OGRNGWLayer( this, oResourceJsonObject );
papoLayers = (OGRNGWLayer**) CPLRealloc(papoLayers, (nLayers + 1) *
sizeof(OGRNGWLayer*));
papoLayers[nLayers++] = poLayer;
osLayerResourceId = poLayer->GetResourceId();
}
else
{
osLayerResourceId = oResourceJsonObject.GetString("resource/id");
}
// Check styles exist and add them as rasters.
if( nOpenFlagsIn & GDAL_OF_RASTER &&
oResourceJsonObject.GetBool( "resource/children", false ) )
{
CPLJSONDocument oResourceChildReq;
bool bResult = oResourceChildReq.LoadUrl( NGWAPI::GetChildren( osUrl,
osLayerResourceId ), papszOptions );
if( bResult )
{
CPLJSONArray oChildren( oResourceChildReq.GetRoot() );
for( int i = 0; i < oChildren.Size(); ++i )
{
AddRaster( oChildren[i], papszOptions );
}
}
}
}
/*
* AddRaster()
*/
void OGRNGWDataset::AddRaster( const CPLJSONObject &oRasterJsonObj,
char **papszOptions )
{
std::string osOutResourceId;
std::string osOutResourceName;
std::string osResourceType = oRasterJsonObj.GetString( "resource/cls" );
if( osResourceType == "mapserver_style" ||
osResourceType == "qgis_vector_style" ||
osResourceType == "raster_style" ||
osResourceType == "wmsclient_layer" )
{
osOutResourceId = oRasterJsonObj.GetString( "resource/id" );
osOutResourceName = oRasterJsonObj.GetString( "resource/display_name" );
}
else if( osResourceType == "raster_layer" )
{
std::string osRasterResourceId = oRasterJsonObj.GetString( "resource/id" );
CPLJSONDocument oResourceRequest;
bool bResult = oResourceRequest.LoadUrl( NGWAPI::GetChildren( osUrl,
osRasterResourceId ), papszOptions );
if( bResult )
{
CPLJSONArray oChildren(oResourceRequest.GetRoot());
for( int i = 0; i < oChildren.Size(); ++i )
{
CPLJSONObject oChild = oChildren[i];
osResourceType = oChild.GetString("resource/cls");
if( osResourceType == "raster_style" )
{
AddRaster( oChild, papszOptions );
}
}
}
}
if( !osOutResourceId.empty() )
{
if( osOutResourceName.empty() )
{
osOutResourceName = "raster_" + osOutResourceId;
}
GDALDataset::SetMetadataItem( CPLSPrintf("SUBDATASET_%d_NAME", nRasters),
CPLSPrintf("NGW:%s/resource/%s", osUrl.c_str(),
osOutResourceId.c_str()), "SUBDATASETS" );
GDALDataset::SetMetadataItem( CPLSPrintf("SUBDATASET_%d_DESC", nRasters),
osOutResourceName.c_str(), "SUBDATASETS" );
nRasters++;
}
}
/*
* ICreateLayer
*/
OGRLayer *OGRNGWDataset::ICreateLayer( const char *pszNameIn,
OGRSpatialReference *poSpatialRef,
OGRwkbGeometryType eGType,
char **papszOptions )
{
if( !bReadWrite )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Operation not available in read-only mode");
return nullptr;
}
// Check permissions as we create new layer in memory and will create in during SyncToDisk.
FetchPermissions();
if( !stPermissions.bResourceCanCreate )
{
CPLError(CE_Failure, CPLE_AppDefined, "Operation not permitted.");
return nullptr;
}
// Check input parameters.
if( eGType < wkbPoint || eGType > wkbMultiPolygon )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Unsupported geometry type: %s", OGRGeometryTypeToName(eGType));
return nullptr;
}
if( !poSpatialRef )
{
CPLError(CE_Failure, CPLE_AppDefined, "Undefined spatial reference");
return nullptr;
}
poSpatialRef->AutoIdentifyEPSG();
const char *pszEPSG = poSpatialRef->GetAuthorityCode( nullptr );
int nEPSG = -1;
if( pszEPSG != nullptr )
{
nEPSG = atoi( pszEPSG );
}
if( nEPSG != 3857 ) // TODO: Check NextGIS Web supported SRS.
{
CPLError(CE_Failure, CPLE_AppDefined,
"Unsupported spatial reference EPSG code: %d", nEPSG);
return nullptr;
}
// Do we already have this layer? If so, should we blow it away?
bool bOverwrite = CPLFetchBool(papszOptions, "OVERWRITE", "NO");
for( int iLayer = 0; iLayer < nLayers; ++iLayer )
{
if( EQUAL(pszNameIn, papoLayers[iLayer]->GetName()) )
{
if( bOverwrite )
{
DeleteLayer( iLayer );
break;
}
else
{
CPLError( CE_Failure, CPLE_AppDefined,
"Layer %s already exists, CreateLayer failed.\n"
"Use the layer creation option OVERWRITE=YES to "
"replace it.",
pszNameIn );
return nullptr;
}
}
}
// Create layer.
std::string osKey = CSLFetchNameValueDef( papszOptions, "KEY", "");
std::string osDesc = CSLFetchNameValueDef( papszOptions, "DESCRIPTION", "");
OGRNGWLayer *poLayer = new OGRNGWLayer( this, pszNameIn, poSpatialRef, eGType,
osKey, osDesc );
papoLayers = (OGRNGWLayer**) CPLRealloc(papoLayers, (nLayers + 1) *
sizeof(OGRNGWLayer*));
papoLayers[nLayers++] = poLayer;
return poLayer;
}
/*
* DeleteLayer()
*/
OGRErr OGRNGWDataset::DeleteLayer( int iLayer )
{
if( !bReadWrite )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Operation not available in read-only mode.");
return OGRERR_FAILURE;
}
if( iLayer < 0 || iLayer >= nLayers )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Layer %d not in legal range of 0 to %d.", iLayer, nLayers-1 );
return OGRERR_FAILURE;
}
OGRNGWLayer *poLayer = static_cast(papoLayers[iLayer]);
if( poLayer->GetResourceId() != "-1" )
{
// For layers from server we can check permissions.
// We can skip check permissions here as papoLayers[iLayer]->Delete() will
// return false if no delete permission available.
FetchPermissions();
if( !stPermissions.bResourceCanDelete )
{
CPLError(CE_Failure, CPLE_AppDefined, "Operation not permitted.");
return OGRERR_FAILURE;
}
}
if( poLayer->Delete() )
{
delete poLayer;
memmove( papoLayers + iLayer, papoLayers + iLayer + 1,
sizeof(void *) * (nLayers - iLayer - 1) );
nLayers--;
}
return OGRERR_NONE;
}
/*
* FillMetadata()
*/
void OGRNGWDataset::FillMetadata( const CPLJSONObject &oRootObject )
{
std::string osCreateDate = oRootObject.GetString("resource/creation_date");
if( !osCreateDate.empty() )
{
GDALDataset::SetMetadataItem( "creation_date", osCreateDate.c_str() );
}
osName = oRootObject.GetString("resource/display_name");
SetDescription( osName.c_str() );
GDALDataset::SetMetadataItem( "display_name", osName.c_str() );
std::string osDescription = oRootObject.GetString("resource/description");
if( !osDescription.empty() )
{
GDALDataset::SetMetadataItem( "description", osDescription.c_str() );
}
GDALDataset::SetMetadataItem( "id", osResourceId.c_str() );
std::vector items =
oRootObject.GetObj("resmeta/items").GetChildren();
for( const CPLJSONObject &item : items )
{
std::string osSuffix = NGWAPI::GetResmetaSuffix( item.GetType() );
GDALDataset::SetMetadataItem( (item.GetName() + osSuffix).c_str(),
item.ToString().c_str(), "NGW" );
}
}
/*
* FlushMetadata()
*/
bool OGRNGWDataset::FlushMetadata( char **papszMetadata )
{
if( !bMetadataDerty )
{
return true;
}
bool bResult = NGWAPI::FlushMetadata(osUrl, osResourceId, papszMetadata,
GetHeaders());
if( bResult )
{
bMetadataDerty = false;
}
return bResult;
}
/*
* SetMetadata()
*/
CPLErr OGRNGWDataset::SetMetadata( char **papszMetadata, const char *pszDomain)
{
FetchPermissions();
if( !stPermissions.bMetadataCanWrite )
{
CPLError(CE_Failure, CPLE_AppDefined, "Operation not permitted.");
return CE_Failure;
}
CPLErr eResult = GDALDataset::SetMetadata(papszMetadata, pszDomain);
if( eResult == CE_None && pszDomain != nullptr && EQUAL(pszDomain, "NGW") )
{
eResult = FlushMetadata( papszMetadata ) ? CE_None : CE_Failure;
}
return eResult;
}
/*
* SetMetadataItem()
*/
CPLErr OGRNGWDataset::SetMetadataItem( const char *pszName,
const char *pszValue, const char *pszDomain)
{
FetchPermissions();
if( !stPermissions.bMetadataCanWrite )
{
CPLError(CE_Failure, CPLE_AppDefined, "Operation not permitted.");
return CE_Failure;
}
if( pszDomain != nullptr && EQUAL(pszDomain, "NGW") )
{
bMetadataDerty = true;
}
return GDALDataset::SetMetadataItem(pszName, pszValue, pszDomain);
}
/*
* FlushCache()
*/
void OGRNGWDataset::FlushCache()
{
GDALDataset::FlushCache();
FlushMetadata( GetMetadata("NGW") );
}
/*
* GetHeaders()
*/
char **OGRNGWDataset::GetHeaders() const
{
char **papszOptions = nullptr;
papszOptions = CSLAddString(papszOptions, "HEADERS=Accept: */*");
if( !osUserPwd.empty() )
{
papszOptions = CSLAddString(papszOptions, "HTTPAUTH=BASIC");
std::string osUserPwdOption("USERPWD=");
osUserPwdOption += osUserPwd;
papszOptions = CSLAddString(papszOptions, osUserPwdOption.c_str());
}
return papszOptions;
}
/*
* ExecuteSQL()
*/
OGRLayer *OGRNGWDataset::ExecuteSQL( const char *pszStatement,
OGRGeometry *poSpatialFilter, const char *pszDialect )
{
// Clean statement string.
CPLString osStatement(pszStatement);
osStatement = osStatement.Trim().replaceAll(" ", " ");
if( STARTS_WITH_CI(osStatement.c_str(), "DELLAYER:") )
{
CPLString osLayerName = osStatement.substr(9);
if( osLayerName.endsWith(";") )
{
osLayerName = osLayerName.substr(0, osLayerName.size() - 1);
osLayerName.Trim();
}
CPLDebug("NGW", "Delete layer with name %s.", osLayerName.c_str());
for( int iLayer = 0; iLayer < nLayers; ++iLayer )
{
if( EQUAL(papoLayers[iLayer]->GetName(), osLayerName.c_str() ) )
{
DeleteLayer( iLayer );
break;
}
}
return nullptr;
}
if( STARTS_WITH_CI(osStatement.c_str(), "DELETE FROM") )
{
// Get layer name from pszStatement DELETE FROM layer;.
CPLString osLayerName = osStatement.substr(12);
if( osLayerName.endsWith(";") )
{
osLayerName = osLayerName.substr(0, osLayerName.size() - 1);
osLayerName.Trim();
}
CPLDebug("NGW", "Delete features from layer with name %s.", osLayerName.c_str());
OGRNGWLayer *poLayer = static_cast(GetLayerByName(osLayerName));
if( poLayer )
{
poLayer->DeleteAllFeatures();
}
else
{
CPLError(CE_Failure, CPLE_AppDefined, "Unknown layer : %s",
osLayerName.c_str());
}
return nullptr;
}
return GDALDataset::ExecuteSQL(pszStatement, poSpatialFilter, pszDialect);
}
/*
* GetProjectionRef()
*/
const char *OGRNGWDataset::GetProjectionRef(void)
{
if( poRasterDS != nullptr )
{
return poRasterDS->GetProjectionRef();
}
return GDALDataset::GetProjectionRef();
}
/*
* GetGeoTransform()
*/
CPLErr OGRNGWDataset::GetGeoTransform( double *padfTransform )
{
if( poRasterDS != nullptr )
{
return poRasterDS->GetGeoTransform( padfTransform );
}
return GDALDataset::GetGeoTransform( padfTransform );
}
/*
* IRasterIO()
*/
CPLErr OGRNGWDataset::IRasterIO( GDALRWFlag eRWFlag, int nXOff, int nYOff,
int nXSize, int nYSize, void *pData, int nBufXSize, int nBufYSize,
GDALDataType eBufType, int nBandCount, int *panBandMap,
GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
GDALRasterIOExtraArg* psExtraArg )
{
if( poRasterDS != nullptr )
{
if( stPixelExtent.IsInit() )
{
OGREnvelope stTestExtent;
stTestExtent.MinX = static_cast(nXOff);
stTestExtent.MinY = static_cast(nYOff);
stTestExtent.MaxX = static_cast(nXOff + nXSize);
stTestExtent.MaxY = static_cast(nYOff + nYSize);
if( !stPixelExtent.Intersects(stTestExtent) )
{
CPLDebug("NGW", "Raster extent in px is: %f, %f, %f, %f",
stPixelExtent.MinX, stPixelExtent.MinY,
stPixelExtent.MaxX, stPixelExtent.MaxY);
CPLDebug("NGW", "RasterIO extent is: %f, %f, %f, %f",
stTestExtent.MinX, stTestExtent.MinY,
stTestExtent.MaxX, stTestExtent.MaxY);
// Fill buffer transparent color.
memset( pData, 0, nBufXSize * nBufYSize * nBandCount *
GDALGetDataTypeSizeBytes(eBufType) );
return CE_None;
}
}
}
return GDALDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
nBufXSize, nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace,
nLineSpace, nBandSpace, psExtraArg);
}
/*
* FillCapabilities()
*/
void OGRNGWDataset::FillCapabilities( char **papszOptions )
{
CPLJSONDocument oRouteReq;
if( oRouteReq.LoadUrl( NGWAPI::GetRoute(osUrl), papszOptions ) )
{
CPLJSONObject oRoot = oRouteReq.GetRoot();
if( oRoot.IsValid() )
{
// TODO: check bHasFeaturePaging
}
}
}