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

Generated by: LCOV version 1.14