LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/ngw - ogrngwdriver.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 60 245 24.5 %
Date: 2025-02-18 14:19:29 Functions: 4 8 50.0 %

          Line data    Source code
       1             : /*******************************************************************************
       2             :  *  Project: NextGIS Web Driver
       3             :  *  Purpose: Implements NextGIS Web Driver
       4             :  *  Author: Dmitry Baryshnikov, dmitry.baryshnikov@nextgis.com
       5             :  *  Language: C++
       6             :  *******************************************************************************
       7             :  *  The MIT License (MIT)
       8             :  *
       9             :  *  Copyright (c) 2018-2025, NextGIS <info@nextgis.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  *******************************************************************************/
      13             : 
      14             : #include "ogr_ngw.h"
      15             : 
      16             : // #include <gdalsubdatasetinfo.h>
      17             : 
      18             : /*
      19             :  * GetHeaders()
      20             :  */
      21           0 : static CPLStringList GetHeaders(const std::string &osUserPwdIn = "",
      22             :                                 const std::string &osConnectTimeout = "",
      23             :                                 const std::string &osTimeout = "",
      24             :                                 const std::string &osRetryCount = "",
      25             :                                 const std::string &osRetryDelay = "")
      26             : {
      27           0 :     CPLStringList aosHTTPOptions;
      28           0 :     aosHTTPOptions.AddString("HEADERS=Accept: */*");
      29           0 :     if (!osUserPwdIn.empty())
      30             :     {
      31           0 :         aosHTTPOptions.AddString("HTTPAUTH=BASIC");
      32           0 :         std::string osUserPwdOption("USERPWD=");
      33           0 :         osUserPwdOption += osUserPwdIn;
      34           0 :         aosHTTPOptions.AddString(osUserPwdOption.c_str());
      35             :     }
      36             : 
      37           0 :     if (!osConnectTimeout.empty())
      38             :     {
      39           0 :         aosHTTPOptions.AddNameValue("CONNECTTIMEOUT", osConnectTimeout.c_str());
      40             :     }
      41             : 
      42           0 :     if (!osTimeout.empty())
      43             :     {
      44           0 :         aosHTTPOptions.AddNameValue("TIMEOUT", osTimeout.c_str());
      45             :     }
      46             : 
      47           0 :     if (!osRetryCount.empty())
      48             :     {
      49           0 :         aosHTTPOptions.AddNameValue("MAX_RETRY", osRetryCount.c_str());
      50             :     }
      51           0 :     if (!osRetryDelay.empty())
      52             :     {
      53           0 :         aosHTTPOptions.AddNameValue("RETRY_DELAY", osRetryDelay.c_str());
      54             :     }
      55           0 :     return aosHTTPOptions;
      56             : }
      57             : 
      58             : /*
      59             :  * OGRNGWDriverIdentify()
      60             :  */
      61             : 
      62       52357 : static int OGRNGWDriverIdentify(GDALOpenInfo *poOpenInfo)
      63             : {
      64       52357 :     return STARTS_WITH_CI(poOpenInfo->pszFilename, "NGW:");
      65             : }
      66             : 
      67             : /*
      68             :  * OGRNGWDriverOpen()
      69             :  */
      70             : 
      71           0 : static GDALDataset *OGRNGWDriverOpen(GDALOpenInfo *poOpenInfo)
      72             : {
      73           0 :     if (OGRNGWDriverIdentify(poOpenInfo) == 0)
      74             :     {
      75           0 :         return nullptr;
      76             :     }
      77             : 
      78           0 :     OGRNGWDataset *poDS = new OGRNGWDataset();
      79           0 :     if (!poDS->Open(poOpenInfo->pszFilename, poOpenInfo->papszOpenOptions,
      80           0 :                     poOpenInfo->eAccess == GA_Update, poOpenInfo->nOpenFlags))
      81             :     {
      82           0 :         delete poDS;
      83           0 :         poDS = nullptr;
      84             :     }
      85             : 
      86           0 :     return poDS;
      87             : }
      88             : 
      89             : /*
      90             :  * OGRNGWDriverCreate()
      91             :  *
      92             :  * Add new datasource name at the end of URL:
      93             :  * NGW:http://some.nextgis.com/resource/0/new_name
      94             :  * NGW:http://some.nextgis.com:8000/test/resource/0/new_name
      95             :  */
      96             : 
      97             : static GDALDataset *
      98          32 : OGRNGWDriverCreate(const char *pszName, CPL_UNUSED int nBands,
      99             :                    CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
     100             :                    CPL_UNUSED GDALDataType eDT, char **papszOptions)
     101             : 
     102             : {
     103          96 :     NGWAPI::Uri stUri = NGWAPI::ParseUri(pszName);
     104          32 :     CPLErrorReset();
     105          32 :     if (stUri.osPrefix != "NGW")
     106             :     {
     107          32 :         CPLError(CE_Failure, CPLE_NotSupported, "Unsupported name %s", pszName);
     108          32 :         return nullptr;
     109             :     }
     110             : 
     111           0 :     CPLDebug("NGW", "Parse uri result. URL: %s, ID: %s, New name: %s",
     112             :              stUri.osAddress.c_str(), stUri.osResourceId.c_str(),
     113             :              stUri.osNewResourceName.c_str());
     114             : 
     115           0 :     std::string osKey = CSLFetchNameValueDef(papszOptions, "KEY", "");
     116           0 :     std::string osDesc = CSLFetchNameValueDef(papszOptions, "DESCRIPTION", "");
     117             :     std::string osUserPwd = CSLFetchNameValueDef(
     118           0 :         papszOptions, "USERPWD", CPLGetConfigOption("NGW_USERPWD", ""));
     119             : 
     120           0 :     CPLJSONObject oPayload;
     121           0 :     CPLJSONObject oResource("resource", oPayload);
     122           0 :     oResource.Add("cls", "resource_group");
     123           0 :     oResource.Add("display_name", stUri.osNewResourceName);
     124           0 :     if (!osKey.empty())
     125             :     {
     126           0 :         oResource.Add("keyname", osKey);
     127             :     }
     128             : 
     129           0 :     if (!osDesc.empty())
     130             :     {
     131           0 :         oResource.Add("description", osDesc);
     132             :     }
     133             : 
     134           0 :     CPLJSONObject oParent("parent", oResource);
     135           0 :     oParent.Add("id", atoi(stUri.osResourceId.c_str()));
     136             : 
     137             :     std::string osConnectTimeout =
     138             :         CSLFetchNameValueDef(papszOptions, "CONNECTTIMEOUT",
     139           0 :                              CPLGetConfigOption("NGW_CONNECTTIMEOUT", ""));
     140             :     std::string osTimeout = CSLFetchNameValueDef(
     141           0 :         papszOptions, "TIMEOUT", CPLGetConfigOption("NGW_TIMEOUT", ""));
     142             : 
     143             :     std::string osNewResourceId = NGWAPI::CreateResource(
     144           0 :         stUri.osAddress, oPayload.Format(CPLJSONObject::PrettyFormat::Plain),
     145           0 :         GetHeaders(osUserPwd, osConnectTimeout, osTimeout));
     146           0 :     if (osNewResourceId == "-1")
     147             :     {
     148           0 :         return nullptr;
     149             :     }
     150             : 
     151           0 :     OGRNGWDataset *poDS = new OGRNGWDataset();
     152             : 
     153           0 :     if (!poDS->Open(stUri.osAddress, osNewResourceId, papszOptions, true,
     154             :                     GDAL_OF_RASTER | GDAL_OF_VECTOR))  // TODO: GDAL_OF_GNM
     155             :     {
     156           0 :         delete poDS;
     157           0 :         poDS = nullptr;
     158             :     }
     159             : 
     160           0 :     return poDS;
     161             : }
     162             : 
     163             : /*
     164             :  * OGRNGWDriverDelete()
     165             :  */
     166           0 : static CPLErr OGRNGWDriverDelete(const char *pszName)
     167             : {
     168           0 :     NGWAPI::Uri stUri = NGWAPI::ParseUri(pszName);
     169           0 :     CPLErrorReset();
     170             : 
     171           0 :     if (stUri.osPrefix != "NGW")
     172             :     {
     173           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Unsupported name %s", pszName);
     174           0 :         return CE_Failure;
     175             :     }
     176             : 
     177           0 :     if (!stUri.osNewResourceName.empty())
     178             :     {
     179           0 :         CPLError(CE_Warning, CPLE_NotSupported,
     180             :                  "Cannot delete new resource with name %s", pszName);
     181           0 :         return CE_Failure;
     182             :     }
     183             : 
     184           0 :     if (stUri.osResourceId == "0")
     185             :     {
     186           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Cannot delete resource 0");
     187           0 :         return CE_Failure;
     188             :     }
     189             : 
     190           0 :     std::string osUserPwd = CPLGetConfigOption("NGW_USERPWD", "");
     191           0 :     std::string osConnectTimeout = CPLGetConfigOption("NGW_CONNECTTIMEOUT", "");
     192           0 :     std::string osTimeout = CPLGetConfigOption("NGW_TIMEOUT", "");
     193           0 :     std::string osRetryCount = CPLGetConfigOption("NGW_MAX_RETRY", "");
     194           0 :     std::string osRetryDelay = CPLGetConfigOption("NGW_RETRY_DELAY", "");
     195             : 
     196             :     auto aosHTTPOptions = GetHeaders(osUserPwd, osConnectTimeout, osTimeout,
     197           0 :                                      osRetryCount, osRetryDelay);
     198             : 
     199           0 :     return NGWAPI::DeleteResource(stUri.osAddress, stUri.osResourceId,
     200             :                                   aosHTTPOptions)
     201           0 :                ? CE_None
     202           0 :                : CE_Failure;
     203             : }
     204             : 
     205             : /*
     206             :  * OGRNGWDriverRename()
     207             :  */
     208           0 : static CPLErr OGRNGWDriverRename(const char *pszNewName, const char *pszOldName)
     209             : {
     210           0 :     NGWAPI::Uri stUri = NGWAPI::ParseUri(pszOldName);
     211           0 :     CPLErrorReset();
     212           0 :     if (stUri.osPrefix != "NGW")
     213             :     {
     214           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Unsupported name %s",
     215             :                  pszOldName);
     216           0 :         return CE_Failure;
     217             :     }
     218           0 :     CPLDebug("NGW", "Parse uri result. URL: %s, ID: %s, New name: %s",
     219             :              stUri.osAddress.c_str(), stUri.osResourceId.c_str(), pszNewName);
     220             : 
     221           0 :     std::string osUserPwd = CPLGetConfigOption("NGW_USERPWD", "");
     222           0 :     std::string osConnectTimeout = CPLGetConfigOption("NGW_CONNECTTIMEOUT", "");
     223           0 :     std::string osTimeout = CPLGetConfigOption("NGW_TIMEOUT", "");
     224           0 :     std::string osRetryCount = CPLGetConfigOption("NGW_MAX_RETRY", "");
     225           0 :     std::string osRetryDelay = CPLGetConfigOption("NGW_RETRY_DELAY", "");
     226             : 
     227             :     auto aosHTTPOptions = GetHeaders(osUserPwd, osConnectTimeout, osTimeout,
     228           0 :                                      osRetryCount, osRetryDelay);
     229             : 
     230           0 :     return NGWAPI::RenameResource(stUri.osAddress, stUri.osResourceId,
     231             :                                   pszNewName, aosHTTPOptions)
     232           0 :                ? CE_None
     233           0 :                : CE_Failure;
     234             : }
     235             : 
     236             : /*
     237             :  * OGRNGWDriverCreateCopy()
     238             :  */
     239          18 : static GDALDataset *OGRNGWDriverCreateCopy(const char *pszFilename,
     240             :                                            GDALDataset *poSrcDS, int bStrict,
     241             :                                            char **papszOptions,
     242             :                                            GDALProgressFunc pfnProgress,
     243             :                                            void *pProgressData)
     244             : {
     245             :     // Check destination dataset,
     246          54 :     NGWAPI::Uri stUri = NGWAPI::ParseUri(pszFilename);
     247          18 :     CPLErrorReset();
     248          18 :     if (stUri.osPrefix != "NGW")
     249             :     {
     250          18 :         CPLError(CE_Failure, CPLE_NotSupported, "Unsupported name %s",
     251             :                  pszFilename);
     252          18 :         return nullptr;
     253             :     }
     254             : 
     255           0 :     bool bCloseDS = false;
     256           0 :     std::string osFilename;
     257             : 
     258             :     // Check if source GDALDataset is tiff.
     259           0 :     if (EQUAL(poSrcDS->GetDriverName(), "GTiff") == FALSE)
     260             :     {
     261           0 :         GDALDriver *poDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
     262             :         // Compress to minimize network transfer.
     263           0 :         const char *apszOptions[] = {"COMPRESS=LZW", "NUM_THREADS=ALL_CPUS",
     264             :                                      nullptr};
     265           0 :         std::string osTempFilename = CPLGenerateTempFilenameSafe("ngw_tmp");
     266           0 :         osTempFilename += ".tif";
     267           0 :         GDALDataset *poTmpDS = poDriver->CreateCopy(
     268             :             osTempFilename.c_str(), poSrcDS, bStrict,
     269             :             const_cast<char **>(apszOptions), pfnProgress, pProgressData);
     270             : 
     271           0 :         if (poTmpDS != nullptr)
     272             :         {
     273           0 :             bCloseDS = true;
     274           0 :             osFilename = std::move(osTempFilename);
     275           0 :             poSrcDS = poTmpDS;
     276             :         }
     277             :         else
     278             :         {
     279           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     280             :                      "NGW driver doesn't support %s source raster.",
     281           0 :                      poSrcDS->GetDriverName());
     282           0 :             return nullptr;
     283             :         }
     284             :     }
     285             : 
     286           0 :     if (osFilename.empty())
     287             :     {
     288             :         // Check if source tiff is local file.
     289           0 :         CPLStringList oaFiles(poSrcDS->GetFileList());
     290           0 :         for (int i = 0; i < oaFiles.size(); ++i)
     291             :         {
     292             :             // Check extension tif
     293           0 :             const std::string osExt = CPLGetExtensionSafe(oaFiles[i]);
     294           0 :             if (EQUALN(osExt.c_str(), "tif", 3))
     295             :             {
     296           0 :                 osFilename = oaFiles[i];
     297           0 :                 break;
     298             :             }
     299             :         }
     300             :     }
     301             : 
     302             :     // Check bands count.
     303           0 :     auto nBands = poSrcDS->GetRasterCount();
     304           0 :     auto nDataType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
     305             : 
     306           0 :     if (bCloseDS)
     307             :     {
     308           0 :         GDALClose((GDALDatasetH)poSrcDS);
     309             :     }
     310             : 
     311           0 :     std::string osKey = CSLFetchNameValueDef(papszOptions, "KEY", "");
     312           0 :     std::string osDesc = CSLFetchNameValueDef(papszOptions, "DESCRIPTION", "");
     313             :     std::string osUserPwd = CSLFetchNameValueDef(
     314           0 :         papszOptions, "USERPWD", CPLGetConfigOption("NGW_USERPWD", ""));
     315             :     std::string osStyleName =
     316           0 :         CSLFetchNameValueDef(papszOptions, "RASTER_STYLE_NAME", "");
     317             : 
     318             :     std::string osConnectTimeout =
     319             :         CSLFetchNameValueDef(papszOptions, "CONNECTTIMEOUT",
     320           0 :                              CPLGetConfigOption("NGW_CONNECTTIMEOUT", ""));
     321             :     std::string osTimeout = CSLFetchNameValueDef(
     322           0 :         papszOptions, "TIMEOUT", CPLGetConfigOption("NGW_TIMEOUT", ""));
     323             :     std::string osRetryCount = CSLFetchNameValueDef(
     324           0 :         papszOptions, "MAX_RETRY", CPLGetConfigOption("NGW_MAX_RETRY", ""));
     325             :     std::string osRetryDelay = CSLFetchNameValueDef(
     326           0 :         papszOptions, "RETRY_DELAY", CPLGetConfigOption("NGW_RETRY_DELAY", ""));
     327             : 
     328             :     // Send file
     329             :     auto aosHTTPOptions = GetHeaders(osUserPwd, osConnectTimeout, osTimeout,
     330           0 :                                      osRetryCount, osRetryDelay);
     331             :     CPLJSONObject oFileJson =
     332             :         NGWAPI::UploadFile(stUri.osAddress, osFilename, aosHTTPOptions,
     333           0 :                            pfnProgress, pProgressData);
     334             : 
     335           0 :     if (bCloseDS)  // Delete temp tiff file.
     336             :     {
     337           0 :         VSIUnlink(osFilename.c_str());
     338             :     }
     339             : 
     340           0 :     if (!oFileJson.IsValid())
     341             :     {
     342           0 :         return nullptr;
     343             :     }
     344             : 
     345           0 :     CPLJSONArray oUploadMeta = oFileJson.GetArray("upload_meta");
     346           0 :     if (!oUploadMeta.IsValid() || oUploadMeta.Size() == 0)
     347             :     {
     348           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Get unexpected response: %s.",
     349           0 :                  oFileJson.Format(CPLJSONObject::PrettyFormat::Plain).c_str());
     350           0 :         return nullptr;
     351             :     }
     352             : 
     353             :     // Create raster layer
     354             :     // Create payload
     355           0 :     CPLJSONObject oPayloadRaster;
     356           0 :     CPLJSONObject oResource("resource", oPayloadRaster);
     357           0 :     oResource.Add("cls", "raster_layer");
     358           0 :     oResource.Add("display_name", stUri.osNewResourceName);
     359           0 :     if (!osKey.empty())
     360             :     {
     361           0 :         oResource.Add("keyname", osKey);
     362             :     }
     363             : 
     364           0 :     if (!osDesc.empty())
     365             :     {
     366           0 :         oResource.Add("description", osDesc);
     367             :     }
     368             : 
     369           0 :     CPLJSONObject oParent("parent", oResource);
     370           0 :     oParent.Add("id", atoi(stUri.osResourceId.c_str()));
     371             : 
     372           0 :     CPLJSONObject oRasterLayer("raster_layer", oPayloadRaster);
     373           0 :     oRasterLayer.Add("source", oUploadMeta[0]);
     374             : 
     375           0 :     CPLJSONObject oSrs("srs", oRasterLayer);
     376           0 :     oSrs.Add("id", 3857);  // Now only Web Mercator supported.
     377             : 
     378             :     auto osRasterResourceId = NGWAPI::CreateResource(
     379             :         stUri.osAddress,
     380           0 :         oPayloadRaster.Format(CPLJSONObject::PrettyFormat::Plain),
     381           0 :         aosHTTPOptions);
     382           0 :     if (osRasterResourceId == "-1")
     383             :     {
     384           0 :         return nullptr;
     385             :     }
     386             : 
     387             :     // Create raster style
     388           0 :     CPLJSONObject oPayloadRasterStyle;
     389           0 :     CPLJSONObject oResourceStyle("resource", oPayloadRasterStyle);
     390             : 
     391             :     // NGW v3.1 supported different raster types: 1 band and 16/32 bit, RGB/RGBA
     392             :     // rasters and etc.
     393             :     // For RGB/RGBA rasters we can create default raster_style.
     394             :     // For other types - qml style file path is mandatory.
     395             :     std::string osQMLPath =
     396           0 :         CSLFetchNameValueDef(papszOptions, "RASTER_QML_PATH", "");
     397             : 
     398           0 :     bool bCreateStyle = true;
     399           0 :     if (osQMLPath.empty())
     400             :     {
     401           0 :         if ((nBands == 3 || nBands == 4) && nDataType == GDT_Byte)
     402             :         {
     403           0 :             oResourceStyle.Add("cls", "raster_style");
     404             :         }
     405             :         else
     406             :         {
     407           0 :             CPLError(CE_Warning, CPLE_NotSupported,
     408             :                      "Default NGW raster style supports only 3 (RGB) or 4 "
     409             :                      "(RGBA) and 8 "
     410             :                      "bit byte bands. Raster has %d bands and data type %s",
     411             :                      nBands, GDALGetDataTypeName(nDataType));
     412           0 :             bCreateStyle = false;
     413             :         }
     414             :     }
     415             :     else
     416             :     {
     417           0 :         oResourceStyle.Add("cls", "qgis_raster_style");
     418             : 
     419             :         // Upload QML file
     420             :         oFileJson =
     421           0 :             NGWAPI::UploadFile(stUri.osAddress, osQMLPath, aosHTTPOptions,
     422           0 :                                pfnProgress, pProgressData);
     423           0 :         oUploadMeta = oFileJson.GetArray("upload_meta");
     424           0 :         if (!oUploadMeta.IsValid() || oUploadMeta.Size() == 0)
     425             :         {
     426           0 :             CPLError(
     427             :                 CE_Failure, CPLE_AppDefined, "Get unexpected response: %s.",
     428           0 :                 oFileJson.Format(CPLJSONObject::PrettyFormat::Plain).c_str());
     429           0 :             return nullptr;
     430             :         }
     431             :         CPLJSONObject oQGISRasterStyle("qgis_raster_style",
     432           0 :                                        oPayloadRasterStyle);
     433           0 :         oQGISRasterStyle.Add("file_upload", oUploadMeta[0]);
     434             :     }
     435             : 
     436           0 :     if (bCreateStyle)
     437             :     {
     438           0 :         if (osStyleName.empty())
     439             :         {
     440           0 :             osStyleName = stUri.osNewResourceName;
     441             :         }
     442           0 :         oResourceStyle.Add("display_name", osStyleName);
     443           0 :         CPLJSONObject oParentRaster("parent", oResourceStyle);
     444           0 :         oParentRaster.Add("id", atoi(osRasterResourceId.c_str()));
     445             : 
     446             :         auto osStyleResourceId = NGWAPI::CreateResource(
     447             :             stUri.osAddress,
     448           0 :             oPayloadRasterStyle.Format(CPLJSONObject::PrettyFormat::Plain),
     449           0 :             aosHTTPOptions);
     450           0 :         if (osStyleResourceId == "-1")
     451             :         {
     452           0 :             return nullptr;
     453             :         }
     454             :     }
     455             : 
     456           0 :     OGRNGWDataset *poDS = new OGRNGWDataset();
     457             : 
     458           0 :     if (!poDS->Open(stUri.osAddress, osRasterResourceId, papszOptions, true,
     459             :                     GDAL_OF_RASTER))
     460             :     {
     461           0 :         delete poDS;
     462           0 :         poDS = nullptr;
     463             :     }
     464             : 
     465           0 :     return poDS;
     466             : }
     467             : 
     468             : /*
     469             :  * RegisterOGRNGW()
     470             :  */
     471             : 
     472        1686 : void RegisterOGRNGW()
     473             : {
     474        1686 :     if (GDALGetDriverByName("NGW") != nullptr)
     475             :     {
     476         302 :         return;
     477             :     }
     478             : 
     479        1384 :     GDALDriver *poDriver = new GDALDriver();
     480             : 
     481        1384 :     poDriver->SetDescription("NGW");
     482        1384 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "NextGIS Web");
     483        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     484        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
     485        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
     486        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_DELETE_LAYER, "YES");
     487        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
     488        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_DELETE_FIELD, "YES");
     489        1384 :     poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
     490        1384 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/ngw.html");
     491        1384 :     poDriver->SetMetadataItem(GDAL_DMD_CONNECTION_PREFIX, "NGW:");
     492        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
     493        1384 :     poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS,
     494        1384 :                               "NATIVE OGRSQL SQLITE");
     495             : 
     496        1384 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte");
     497        1384 :     poDriver->SetMetadataItem(GDAL_DMD_ALTER_FIELD_DEFN_FLAGS,
     498        1384 :                               "Name AlternativeName Domain");
     499        1384 :     poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS,
     500        1384 :                               "AlternativeName Domain");
     501        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
     502        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_FIELD_DOMAINS, "YES");
     503             : 
     504        1384 :     poDriver->SetMetadataItem(
     505             :         GDAL_DMD_OPENOPTIONLIST,
     506             :         "<OpenOptionList>"
     507             :         "   <Option name='USERPWD' scope='raster,vector' type='string' "
     508             :         "description='Username and password, separated by colon'/>"
     509             :         "   <Option name='PAGE_SIZE' scope='vector' type='integer' "
     510             :         "description='Limit feature count while fetching from server. Default "
     511             :         "value is -1 - no limit' default='-1'/>"
     512             :         "   <Option name='BATCH_SIZE' scope='vector' type='integer' "
     513             :         "description='Size of feature insert and update operations cache "
     514             :         "before send to server. If batch size is -1 batch mode is disabled' "
     515             :         "default='-1'/>"
     516             :         "   <Option name='NATIVE_DATA' scope='vector' type='boolean' "
     517             :         "description='Whether to store the native Json representation of "
     518             :         "extensions key. If EXTENSIONS not set or empty, NATIVE_DATA defaults "
     519             :         "to NO' default='NO'/>"
     520             :         "   <Option name='CACHE_EXPIRES' scope='raster' type='integer' "
     521             :         "description='Time in seconds cached files will stay valid. If cached "
     522             :         "file expires it is deleted when maximum size of cache is reached. "
     523             :         "Also expired file can be overwritten by the new one from web' "
     524             :         "default='604800'/>"
     525             :         "   <Option name='CACHE_MAX_SIZE' scope='raster' type='integer' "
     526             :         "description='The cache maximum size in bytes. If cache reached "
     527             :         "maximum size, expired cached files will be deleted' "
     528             :         "default='67108864'/>"
     529             :         "   <Option name='JSON_DEPTH' scope='raster,vector' type='integer' "
     530             :         "description='The depth of json response that can be parsed. If depth "
     531             :         "is greater than this value, parse error occurs' default='32'/>"
     532             :         "   <Option name='EXTENSIONS' scope='vector' type='string' "
     533             :         "description='Comma separated extensions list. Available are "
     534             :         "description and attachment' default=''/>"
     535             :         "   <Option name='CONNECTTIMEOUT' scope='raster,vector' type='integer' "
     536             :         "description='Maximum delay for the connection to be established "
     537             :         "before "
     538             :         "being aborted in seconds'/>"
     539             :         "   <Option name='TIMEOUT' scope='raster,vector' type='integer' "
     540             :         "description='Maximum delay for the whole request to complete before "
     541             :         "being aborted in seconds'/>"
     542             :         "   <Option name='MAX_RETRY' scope='raster,vector' type='integer' "
     543             :         "description='Maximum number of retry attempts if a 429, 502, 503 or "
     544             :         "504 "
     545             :         "HTTP error occurs'/>"
     546             :         "   <Option name='RETRY_DELAY' scope='raster,vector' type='integer' "
     547             :         "description='Number of seconds between retry attempts'/>"
     548        1384 :         "</OpenOptionList>");
     549             : 
     550        1384 :     poDriver->SetMetadataItem(
     551             :         GDAL_DMD_CREATIONOPTIONLIST,
     552             :         "<CreationOptionList>"
     553             :         "   <Option name='KEY' scope='raster,vector' type='string' "
     554             :         "description='Key value. Must be unique in whole NextGIS Web "
     555             :         "instance'/>"
     556             :         "   <Option name='DESCRIPTION' scope='raster,vector' type='string' "
     557             :         "description='Resource description'/>"
     558             :         "   <Option name='RASTER_STYLE_NAME' scope='raster' type='string' "
     559             :         "description='Raster layer style name'/>"
     560             :         "   <Option name='USERPWD' scope='raster,vector' type='string' "
     561             :         "description='Username and password, separated by colon'/>"
     562             :         "   <Option name='PAGE_SIZE' scope='vector' type='integer' "
     563             :         "description='Limit feature count while fetching from server. Default "
     564             :         "value is -1 - no limit' default='-1'/>"
     565             :         "   <Option name='BATCH_SIZE' scope='vector' type='integer' "
     566             :         "description='Size of feature insert and update operations cache "
     567             :         "before send to server. If batch size is -1 batch mode is disabled' "
     568             :         "default='-1'/>"
     569             :         "   <Option name='NATIVE_DATA' scope='vector' type='boolean' "
     570             :         "description='Whether to store the native Json representation of "
     571             :         "extensions key. If EXTENSIONS not set or empty, NATIVE_DATA defaults "
     572             :         "to NO' default='NO'/>"
     573             :         "   <Option name='CACHE_EXPIRES' scope='raster' type='integer' "
     574             :         "description='Time in seconds cached files will stay valid. If cached "
     575             :         "file expires it is deleted when maximum size of cache is reached. "
     576             :         "Also expired file can be overwritten by the new one from web' "
     577             :         "default='604800'/>"
     578             :         "   <Option name='CACHE_MAX_SIZE' scope='raster' type='integer' "
     579             :         "description='The cache maximum size in bytes. If cache reached "
     580             :         "maximum size, expired cached files will be deleted' "
     581             :         "default='67108864'/>"
     582             :         "   <Option name='JSON_DEPTH' scope='raster,vector' type='integer' "
     583             :         "description='The depth of json response that can be parsed. If depth "
     584             :         "is greater than this value, parse error occurs' default='32'/>"
     585             :         "   <Option name='RASTER_QML_PATH' scope='raster' type='string' "
     586             :         "description='Raster QMS style path'/>"
     587             :         "   <Option name='EXTENSIONS' scope='vector' type='string' "
     588             :         "description='Comma separated extensions list. Available are "
     589             :         "description and attachment' default=''/>"
     590             :         "   <Option name='CONNECTTIMEOUT' scope='raster,vector' type='integer' "
     591             :         "description='Maximum delay for the connection to be established "
     592             :         "before "
     593             :         "being aborted in seconds'/>"
     594             :         "   <Option name='TIMEOUT' scope='raster,vector' type='integer' "
     595             :         "description='Maximum delay for the whole request to complete before "
     596             :         "being aborted in seconds'/>"
     597             :         "   <Option name='MAX_RETRY' scope='raster,vector' type='integer' "
     598             :         "description='Maximum number of retry attempts if a 429, 502, 503 or "
     599             :         "504 "
     600             :         "HTTP error occurs'/>"
     601             :         "   <Option name='RETRY_DELAY' scope='raster,vector' type='integer' "
     602             :         "description='Number of seconds between retry attempts'/>"
     603        1384 :         "</CreationOptionList>");
     604             : 
     605        1384 :     poDriver->SetMetadataItem(
     606             :         GDAL_DS_LAYER_CREATIONOPTIONLIST,
     607             :         "<LayerCreationOptionList>"
     608             :         "   <Option name='OVERWRITE' type='boolean' description='Whether to "
     609             :         "overwrite an existing table with the layer name to be created' "
     610             :         "default='NO'/>"
     611             :         "   <Option name='KEY' type='string' description='Key value. Must be "
     612             :         "unique in whole NextGIS Web instance'/>"
     613             :         "   <Option name='DESCRIPTION' type='string' description='Resource "
     614             :         "description'/>"
     615        1384 :         "</LayerCreationOptionList>");
     616             : 
     617        1384 :     poDriver->SetMetadataItem(
     618             :         GDAL_DMD_CREATIONFIELDDATATYPES,
     619        1384 :         "Integer Integer64 Real String Date DateTime Time");
     620        1384 :     poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS,
     621        1384 :                               "AlternativeName");
     622        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_NOTNULL_GEOMFIELDS, "YES");
     623        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES");
     624        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_RENAME_LAYERS, "YES");
     625        1384 :     poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DOMAIN_TYPES, "Coded");
     626             : 
     627        1384 :     poDriver->pfnOpen = OGRNGWDriverOpen;
     628        1384 :     poDriver->pfnIdentify = OGRNGWDriverIdentify;
     629        1384 :     poDriver->pfnCreate = OGRNGWDriverCreate;
     630        1384 :     poDriver->pfnCreateCopy = OGRNGWDriverCreateCopy;
     631        1384 :     poDriver->pfnDelete = OGRNGWDriverDelete;
     632        1384 :     poDriver->pfnRename = OGRNGWDriverRename;
     633             : 
     634        1384 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     635             : }

Generated by: LCOV version 1.14