LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/geojson - ogrgeojsondriver.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 265 286 92.7 %
Date: 2025-02-20 10:14:44 Functions: 26 27 96.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implementation of OGRGeoJSONDriver class (OGR GeoJSON Driver).
       5             :  * Author:   Mateusz Loskot, mateusz@loskot.net
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2007, Mateusz Loskot
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_port.h"
      14             : #include "ogr_geojson.h"
      15             : 
      16             : #include <stdlib.h>
      17             : #include <string.h>
      18             : #include <limits>
      19             : 
      20             : #include "cpl_conv.h"
      21             : #include "cpl_error.h"
      22             : #include "cpl_http.h"
      23             : #include "cpl_multiproc.h"
      24             : #include "cpl_string.h"
      25             : #include "cpl_vsi.h"
      26             : // #include "json_object.h"
      27             : #include "gdal.h"
      28             : #include "gdal_priv.h"
      29             : #include "ogr_core.h"
      30             : #include "ogr_feature.h"
      31             : #include "ogrgeojsonutils.h"
      32             : #include "ogrsf_frmts.h"
      33             : 
      34             : static CPLMutex *ghMutex = nullptr;
      35             : static char *gpszSource = nullptr;
      36             : static char *gpszText = nullptr;
      37             : 
      38             : class OGRESRIFeatureServiceDataset;
      39             : 
      40             : /************************************************************************/
      41             : /*                      OGRESRIFeatureServiceLayer                      */
      42             : /************************************************************************/
      43             : 
      44             : class OGRESRIFeatureServiceLayer final : public OGRLayer
      45             : {
      46             :     OGRESRIFeatureServiceDataset *poDS;
      47             :     OGRFeatureDefn *poFeatureDefn;
      48             :     GIntBig nFeaturesRead;
      49             :     GIntBig nFirstFID;
      50             :     GIntBig nLastFID;
      51             :     bool bOtherPage;
      52             :     bool bUseSequentialFID;
      53             : 
      54             :   public:
      55             :     explicit OGRESRIFeatureServiceLayer(OGRESRIFeatureServiceDataset *poDS);
      56             :     virtual ~OGRESRIFeatureServiceLayer();
      57             : 
      58             :     void ResetReading() override;
      59             :     OGRFeature *GetNextFeature() override;
      60             :     GIntBig GetFeatureCount(int bForce = TRUE) override;
      61             :     OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent,
      62             :                       bool bForce = true) override;
      63             : 
      64             :     int TestCapability(const char *pszCap) override;
      65             : 
      66           8 :     OGRFeatureDefn *GetLayerDefn() override
      67             :     {
      68           8 :         return poFeatureDefn;
      69             :     }
      70             : };
      71             : 
      72             : /************************************************************************/
      73             : /*                       OGRESRIFeatureServiceDataset                   */
      74             : /************************************************************************/
      75             : 
      76             : class OGRESRIFeatureServiceDataset final : public GDALDataset
      77             : {
      78             :     CPLString m_osURL{};
      79             :     GIntBig m_nFirstOffset = 0;
      80             :     GIntBig m_nLastOffset = 0;
      81             :     std::unique_ptr<OGRGeoJSONDataSource> m_poCurrent{};
      82             :     std::unique_ptr<OGRESRIFeatureServiceLayer> m_poLayer{};
      83             :     GeoJSONSourceType m_nSrcType = eGeoJSONSourceUnknown;
      84             : 
      85             :     bool LoadPage();
      86             : 
      87             :   public:
      88             :     OGRESRIFeatureServiceDataset(
      89             :         const std::string &osURL,
      90             :         std::unique_ptr<OGRGeoJSONDataSource> &&poFirst,
      91             :         GeoJSONSourceType nSrcType);
      92             : 
      93           0 :     int GetLayerCount() override
      94             :     {
      95           0 :         return 1;
      96             :     }
      97             : 
      98           8 :     OGRLayer *GetLayer(int nLayer) override
      99             :     {
     100           8 :         return (nLayer == 0) ? m_poLayer.get() : nullptr;
     101             :     }
     102             : 
     103          52 :     OGRLayer *GetUnderlyingLayer()
     104             :     {
     105          52 :         return m_poCurrent->GetLayer(0);
     106             :     }
     107             : 
     108             :     bool MyResetReading();
     109             :     bool LoadNextPage();
     110             : 
     111           8 :     const CPLString &GetURL() const
     112             :     {
     113           8 :         return m_osURL;
     114             :     }
     115             : };
     116             : 
     117             : /************************************************************************/
     118             : /*                       OGRESRIFeatureServiceLayer()                   */
     119             : /************************************************************************/
     120             : 
     121           8 : OGRESRIFeatureServiceLayer::OGRESRIFeatureServiceLayer(
     122           8 :     OGRESRIFeatureServiceDataset *poDSIn)
     123             :     : poDS(poDSIn), nFeaturesRead(0), nFirstFID(0), nLastFID(0),
     124           8 :       bOtherPage(false), bUseSequentialFID(false)
     125             : {
     126           8 :     OGRFeatureDefn *poSrcFeatDefn = poDS->GetUnderlyingLayer()->GetLayerDefn();
     127           8 :     poFeatureDefn = new OGRFeatureDefn(poSrcFeatDefn->GetName());
     128           8 :     SetDescription(poFeatureDefn->GetName());
     129           8 :     poFeatureDefn->Reference();
     130           8 :     poFeatureDefn->SetGeomType(wkbNone);
     131             : 
     132          22 :     for (int i = 0; i < poSrcFeatDefn->GetFieldCount(); i++)
     133          14 :         poFeatureDefn->AddFieldDefn(poSrcFeatDefn->GetFieldDefn(i));
     134             : 
     135          16 :     for (int i = 0; i < poSrcFeatDefn->GetGeomFieldCount(); i++)
     136           8 :         poFeatureDefn->AddGeomFieldDefn(poSrcFeatDefn->GetGeomFieldDefn(i));
     137           8 : }
     138             : 
     139             : /************************************************************************/
     140             : /*                      ~OGRESRIFeatureServiceLayer()                   */
     141             : /************************************************************************/
     142             : 
     143          16 : OGRESRIFeatureServiceLayer::~OGRESRIFeatureServiceLayer()
     144             : {
     145           8 :     poFeatureDefn->Release();
     146          16 : }
     147             : 
     148             : /************************************************************************/
     149             : /*                            ResetReading()                            */
     150             : /************************************************************************/
     151             : 
     152          10 : void OGRESRIFeatureServiceLayer::ResetReading()
     153             : {
     154          10 :     poDS->MyResetReading();
     155          10 :     nFeaturesRead = 0;
     156          10 :     nLastFID = 0;
     157          10 :     bOtherPage = false;
     158          10 :     bUseSequentialFID = false;
     159          10 : }
     160             : 
     161             : /************************************************************************/
     162             : /*                            GetNextFeature()                          */
     163             : /************************************************************************/
     164             : 
     165          34 : OGRFeature *OGRESRIFeatureServiceLayer::GetNextFeature()
     166             : {
     167             :     while (true)
     168             :     {
     169          34 :         const bool bWasInFirstPage = !bOtherPage;
     170             : #if defined(__GNUC__)
     171             : #pragma GCC diagnostic push
     172             : #pragma GCC diagnostic ignored "-Wnull-dereference"
     173             : #endif
     174          34 :         OGRFeature *poSrcFeat = poDS->GetUnderlyingLayer()->GetNextFeature();
     175             : #if defined(__GNUC__)
     176             : #pragma GCC diagnostic pop
     177             : #endif
     178          34 :         if (poSrcFeat == nullptr)
     179             :         {
     180          20 :             if (!poDS->LoadNextPage())
     181          12 :                 return nullptr;
     182             : #if defined(__GNUC__)
     183             : #pragma GCC diagnostic push
     184             : #pragma GCC diagnostic ignored "-Wnull-dereference"
     185             : #endif
     186           8 :             poSrcFeat = poDS->GetUnderlyingLayer()->GetNextFeature();
     187             : #if defined(__GNUC__)
     188             : #pragma GCC diagnostic pop
     189             : #endif
     190           8 :             if (poSrcFeat == nullptr)
     191           0 :                 return nullptr;
     192           8 :             bOtherPage = true;
     193          16 :             if (bWasInFirstPage && poSrcFeat->GetFID() != 0 &&
     194           8 :                 poSrcFeat->GetFID() == nFirstFID)
     195             :             {
     196             :                 // End-less looping
     197           0 :                 CPLDebug("ESRIJSON", "Scrolling not working. Stopping");
     198           0 :                 delete poSrcFeat;
     199           0 :                 return nullptr;
     200             :             }
     201           8 :             if (bWasInFirstPage && poSrcFeat->GetFID() == 0 &&
     202           0 :                 nLastFID == nFeaturesRead - 1)
     203             :             {
     204           0 :                 bUseSequentialFID = true;
     205             :             }
     206             :         }
     207          22 :         if (nFeaturesRead == 0)
     208          14 :             nFirstFID = poSrcFeat->GetFID();
     209             : 
     210          22 :         OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
     211          22 :         poFeature->SetFrom(poSrcFeat);
     212          22 :         if (bUseSequentialFID)
     213           0 :             poFeature->SetFID(nFeaturesRead);
     214             :         else
     215          22 :             poFeature->SetFID(poSrcFeat->GetFID());
     216          22 :         nLastFID = poFeature->GetFID();
     217          22 :         nFeaturesRead++;
     218          22 :         delete poSrcFeat;
     219             : 
     220          44 :         if ((m_poFilterGeom == nullptr ||
     221          44 :              FilterGeometry(poFeature->GetGeometryRef())) &&
     222          22 :             (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
     223             :         {
     224          22 :             return poFeature;
     225             :         }
     226           0 :         delete poFeature;
     227           0 :     }
     228             : }
     229             : 
     230             : /************************************************************************/
     231             : /*                          TestCapability()                            */
     232             : /************************************************************************/
     233             : 
     234           6 : int OGRESRIFeatureServiceLayer::TestCapability(const char *pszCap)
     235             : {
     236           6 :     if (EQUAL(pszCap, OLCFastFeatureCount))
     237           2 :         return m_poAttrQuery == nullptr && m_poFilterGeom == nullptr;
     238           4 :     if (EQUAL(pszCap, OLCFastGetExtent))
     239           2 :         return FALSE;
     240             : #if defined(__GNUC__)
     241             : #pragma GCC diagnostic push
     242             : #pragma GCC diagnostic ignored "-Wnull-dereference"
     243             : #endif
     244           2 :     auto poUnderlyingLayer = poDS->GetUnderlyingLayer();
     245           2 :     return poUnderlyingLayer->TestCapability(pszCap);
     246             : #if defined(__GNUC__)
     247             : #pragma GCC diagnostic pop
     248             : #endif
     249             : }
     250             : 
     251             : /************************************************************************/
     252             : /*                          GetFeatureCount()                           */
     253             : /************************************************************************/
     254             : 
     255           4 : GIntBig OGRESRIFeatureServiceLayer::GetFeatureCount(int bForce)
     256             : {
     257           4 :     GIntBig nFeatureCount = -1;
     258           4 :     if (m_poAttrQuery == nullptr && m_poFilterGeom == nullptr)
     259             :     {
     260             :         CPLString osNewURL =
     261           8 :             CPLURLAddKVP(poDS->GetURL(), "returnCountOnly", "true");
     262           4 :         osNewURL = CPLURLAddKVP(osNewURL, "resultRecordCount", nullptr);
     263           4 :         CPLErrorReset();
     264           4 :         CPLHTTPResult *pResult = CPLHTTPFetch(osNewURL, nullptr);
     265           4 :         if (pResult != nullptr && pResult->nDataLen != 0 &&
     266           8 :             CPLGetLastErrorNo() == 0 && pResult->nStatus == 0)
     267             :         {
     268             :             const char *pszCount =
     269           2 :                 strstr((const char *)pResult->pabyData, "\"count\"");
     270           2 :             if (pszCount)
     271             :             {
     272           2 :                 pszCount = strchr(pszCount, ':');
     273           2 :                 if (pszCount)
     274             :                 {
     275           2 :                     pszCount++;
     276           2 :                     nFeatureCount = CPLAtoGIntBig(pszCount);
     277             :                 }
     278             :             }
     279             :         }
     280           4 :         CPLHTTPDestroyResult(pResult);
     281             :     }
     282           4 :     if (nFeatureCount < 0)
     283           2 :         nFeatureCount = OGRLayer::GetFeatureCount(bForce);
     284           4 :     return nFeatureCount;
     285             : }
     286             : 
     287             : /************************************************************************/
     288             : /*                              IGetExtent()                            */
     289             : /************************************************************************/
     290             : 
     291           4 : OGRErr OGRESRIFeatureServiceLayer::IGetExtent(int iGeomField,
     292             :                                               OGREnvelope *psExtent,
     293             :                                               bool bForce)
     294             : {
     295           4 :     OGRErr eErr = OGRERR_FAILURE;
     296             :     CPLString osNewURL =
     297           4 :         CPLURLAddKVP(poDS->GetURL(), "returnExtentOnly", "true");
     298           4 :     osNewURL = CPLURLAddKVP(osNewURL, "resultRecordCount", nullptr);
     299           4 :     osNewURL = CPLURLAddKVP(osNewURL, "f", "geojson");
     300           4 :     CPLErrorReset();
     301           4 :     CPLHTTPResult *pResult = CPLHTTPFetch(osNewURL, nullptr);
     302           4 :     if (pResult != nullptr && pResult->nDataLen != 0 &&
     303           8 :         CPLGetLastErrorNo() == 0 && pResult->nStatus == 0)
     304             :     {
     305             :         const char *pszBBox =
     306           2 :             strstr((const char *)pResult->pabyData, "\"bbox\"");
     307           2 :         if (pszBBox)
     308             :         {
     309           2 :             pszBBox = strstr(pszBBox, ":[");
     310           2 :             if (pszBBox)
     311             :             {
     312           2 :                 pszBBox += 2;
     313           2 :                 char **papszTokens = CSLTokenizeString2(pszBBox, ",", 0);
     314           2 :                 if (CSLCount(papszTokens) >= 4)
     315             :                 {
     316           2 :                     psExtent->MinX = CPLAtof(papszTokens[0]);
     317           2 :                     psExtent->MinY = CPLAtof(papszTokens[1]);
     318           2 :                     psExtent->MaxX = CPLAtof(papszTokens[2]);
     319           2 :                     psExtent->MaxY = CPLAtof(papszTokens[3]);
     320           2 :                     eErr = OGRERR_NONE;
     321             :                 }
     322           2 :                 CSLDestroy(papszTokens);
     323             :             }
     324             :         }
     325             :     }
     326           4 :     CPLHTTPDestroyResult(pResult);
     327           4 :     if (eErr == OGRERR_FAILURE)
     328           2 :         eErr = OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
     329           8 :     return eErr;
     330             : }
     331             : 
     332             : /************************************************************************/
     333             : /*                      OGRESRIFeatureServiceDataset()                  */
     334             : /************************************************************************/
     335             : 
     336           8 : OGRESRIFeatureServiceDataset::OGRESRIFeatureServiceDataset(
     337             :     const std::string &osURL, std::unique_ptr<OGRGeoJSONDataSource> &&poFirst,
     338           8 :     GeoJSONSourceType nSrcType)
     339           8 :     : m_osURL(osURL), m_poCurrent(std::move(poFirst)), m_nSrcType(nSrcType)
     340             : {
     341           8 :     m_poLayer = std::make_unique<OGRESRIFeatureServiceLayer>(this);
     342           8 :     if (CPLURLGetValue(m_osURL, "resultRecordCount").empty())
     343             :     {
     344             :         // We assume that if the server sets the exceededTransferLimit, the
     345             :         // and resultRecordCount is not set, the number of features returned
     346             :         // in our first request is the maximum allowed by the server
     347             :         // So set it for following requests.
     348           4 :         m_osURL = CPLURLAddKVP(
     349             :             m_osURL, "resultRecordCount",
     350             :             CPLSPrintf("%d", static_cast<int>(
     351           4 :                                  m_poCurrent->GetLayer(0)->GetFeatureCount())));
     352             :     }
     353             :     else
     354             :     {
     355             :         const int nUserSetRecordCount =
     356           6 :             atoi(CPLURLGetValue(m_osURL, "resultRecordCount"));
     357           6 :         if (nUserSetRecordCount > m_poCurrent->GetLayer(0)->GetFeatureCount())
     358             :         {
     359           2 :             CPLError(
     360             :                 CE_Warning, CPLE_AppDefined,
     361             :                 "Specified resultRecordCount=%d is greater than "
     362             :                 "the maximum %d supported by the server",
     363             :                 nUserSetRecordCount,
     364           2 :                 static_cast<int>(m_poCurrent->GetLayer(0)->GetFeatureCount()));
     365             :         }
     366             :     }
     367           8 :     m_nFirstOffset = CPLAtoGIntBig(CPLURLGetValue(m_osURL, "resultOffset"));
     368           8 :     m_nLastOffset = m_nFirstOffset;
     369           8 : }
     370             : 
     371             : /************************************************************************/
     372             : /*                           MyResetReading()                           */
     373             : /************************************************************************/
     374             : 
     375          10 : bool OGRESRIFeatureServiceDataset::MyResetReading()
     376             : {
     377          10 :     if (m_nLastOffset > m_nFirstOffset)
     378             :     {
     379           8 :         m_nLastOffset = m_nFirstOffset;
     380           8 :         return LoadPage();
     381             :     }
     382             : 
     383             : #if defined(__GNUC__)
     384             : #pragma GCC diagnostic push
     385             : #pragma GCC diagnostic ignored "-Wnull-dereference"
     386             : #endif
     387           2 :     m_poCurrent->GetLayer(0)->ResetReading();
     388             : #if defined(__GNUC__)
     389             : #pragma GCC diagnostic pop
     390             : #endif
     391           2 :     return true;
     392             : }
     393             : 
     394             : /************************************************************************/
     395             : /*                             LoadNextPage()                           */
     396             : /************************************************************************/
     397             : 
     398          20 : bool OGRESRIFeatureServiceDataset::LoadNextPage()
     399             : {
     400          20 :     if (!m_poCurrent->HasOtherPages())
     401           6 :         return false;
     402             : #if defined(__GNUC__)
     403             : #pragma GCC diagnostic push
     404             : #pragma GCC diagnostic ignored "-Wnull-dereference"
     405             : #endif
     406          14 :     const auto nCurPageFC = m_poCurrent->GetLayer(0)->GetFeatureCount();
     407             : #if defined(__GNUC__)
     408             : #pragma GCC diagnostic pop
     409             : #endif
     410          14 :     if (m_nLastOffset > std::numeric_limits<GIntBig>::max() - nCurPageFC)
     411           0 :         return false;
     412          14 :     m_nLastOffset += nCurPageFC;
     413          14 :     return LoadPage();
     414             : }
     415             : 
     416             : /************************************************************************/
     417             : /*                                 LoadPage()                           */
     418             : /************************************************************************/
     419             : 
     420          22 : bool OGRESRIFeatureServiceDataset::LoadPage()
     421             : {
     422             :     CPLString osNewURL = CPLURLAddKVP(m_osURL, "resultOffset",
     423          44 :                                       CPLSPrintf(CPL_FRMT_GIB, m_nLastOffset));
     424          44 :     auto poDS = std::make_unique<OGRGeoJSONDataSource>();
     425          44 :     GDALOpenInfo oOpenInfo(osNewURL, GA_ReadOnly);
     426          38 :     if (!poDS->Open(&oOpenInfo, m_nSrcType, m_poCurrent->GetJSonFlavor()) ||
     427          16 :         poDS->GetLayerCount() == 0)
     428             :     {
     429           6 :         return false;
     430             :     }
     431          16 :     m_poCurrent = std::move(poDS);
     432          16 :     return true;
     433             : }
     434             : 
     435             : /************************************************************************/
     436             : /*                        OGRGeoJSONDriverIdentify()                    */
     437             : /************************************************************************/
     438             : 
     439       49396 : static int OGRGeoJSONDriverIdentifyInternal(GDALOpenInfo *poOpenInfo,
     440             :                                             GeoJSONSourceType &nSrcType)
     441             : {
     442             :     /* -------------------------------------------------------------------- */
     443             :     /*      Determine type of data source: text file (.geojson, .json),     */
     444             :     /*      Web Service or text passed directly and load data.              */
     445             :     /* -------------------------------------------------------------------- */
     446             : 
     447       49396 :     nSrcType = GeoJSONGetSourceType(poOpenInfo);
     448       49396 :     if (nSrcType == eGeoJSONSourceUnknown)
     449             :     {
     450       48466 :         const char *pszHeader =
     451             :             reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
     452       48466 :         if (pszHeader && STARTS_WITH(pszHeader, "{\"properties\":{"))
     453           3 :             return GDAL_IDENTIFY_UNKNOWN;
     454             : 
     455       48463 :         return FALSE;
     456             :     }
     457             : 
     458         930 :     if (nSrcType == eGeoJSONSourceService)
     459             :     {
     460          37 :         if (poOpenInfo->IsSingleAllowedDriver("GeoJSON"))
     461           1 :             return TRUE;
     462          36 :         if (!STARTS_WITH_CI(poOpenInfo->pszFilename, "GeoJSON:"))
     463             :         {
     464          36 :             return -1;
     465             :         }
     466             :     }
     467             : 
     468             :     // If this looks like a file that can be handled by the STACTA driver,
     469             :     // and that one is available, then don't identify the file.
     470         893 :     const char *pszHeader =
     471             :         reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
     472        1512 :     if (pszHeader != nullptr &&
     473         619 :         strstr(pszHeader, "\"stac_extensions\"") != nullptr &&
     474        1514 :         strstr(pszHeader, "\"tiled-assets\"") != nullptr &&
     475           2 :         GDALGetDriverByName("STACTA") != nullptr)
     476             :     {
     477           2 :         if (poOpenInfo->IsSingleAllowedDriver("GeoJSON"))
     478           2 :             return TRUE;
     479           0 :         return FALSE;
     480             :     }
     481             : 
     482         891 :     return TRUE;
     483             : }
     484             : 
     485             : /************************************************************************/
     486             : /*                        OGRGeoJSONDriverIdentify()                    */
     487             : /************************************************************************/
     488             : 
     489       48942 : static int OGRGeoJSONDriverIdentify(GDALOpenInfo *poOpenInfo)
     490             : {
     491             :     GeoJSONSourceType nSrcType;
     492       97884 :     return OGRGeoJSONDriverIdentifyInternal(poOpenInfo, nSrcType);
     493             : }
     494             : 
     495             : /************************************************************************/
     496             : /*                           Open()                                     */
     497             : /************************************************************************/
     498             : 
     499         454 : static GDALDataset *OGRGeoJSONDriverOpen(GDALOpenInfo *poOpenInfo)
     500             : {
     501             :     GeoJSONSourceType nSrcType;
     502         454 :     if (OGRGeoJSONDriverIdentifyInternal(poOpenInfo, nSrcType) == FALSE)
     503             :     {
     504           0 :         return nullptr;
     505             :     }
     506         454 :     return OGRGeoJSONDriverOpenInternal(poOpenInfo, nSrcType, "GeoJSON");
     507             : }
     508             : 
     509             : /************************************************************************/
     510             : /*                     OGRGeoJSONDriverOpenInternal()                   */
     511             : /************************************************************************/
     512             : 
     513         486 : GDALDataset *OGRGeoJSONDriverOpenInternal(GDALOpenInfo *poOpenInfo,
     514             :                                           GeoJSONSourceType nSrcType,
     515             :                                           const char *pszJSonFlavor)
     516             : {
     517         972 :     auto poDS = std::make_unique<OGRGeoJSONDataSource>();
     518             : 
     519             :     /* -------------------------------------------------------------------- */
     520             :     /*      Processing configuration options.                               */
     521             :     /* -------------------------------------------------------------------- */
     522             : 
     523             :     // TODO: Currently, options are based on environment variables.
     524             :     //       This is workaround for not yet implemented Andrey's concept
     525             :     //       described in document 'RFC 10: OGR Open Parameters'.
     526             : 
     527         486 :     poDS->SetGeometryTranslation(OGRGeoJSONDataSource::eGeometryPreserve);
     528         486 :     const char *pszOpt = CPLGetConfigOption("GEOMETRY_AS_COLLECTION", nullptr);
     529         486 :     if (nullptr != pszOpt && STARTS_WITH_CI(pszOpt, "YES"))
     530             :     {
     531           0 :         poDS->SetGeometryTranslation(
     532             :             OGRGeoJSONDataSource::eGeometryAsCollection);
     533             :     }
     534             : 
     535         486 :     poDS->SetAttributesTranslation(OGRGeoJSONDataSource::eAttributesPreserve);
     536         486 :     pszOpt = CPLGetConfigOption("ATTRIBUTES_SKIP", nullptr);
     537         486 :     if (nullptr != pszOpt && STARTS_WITH_CI(pszOpt, "YES"))
     538             :     {
     539           0 :         poDS->SetAttributesTranslation(OGRGeoJSONDataSource::eAttributesSkip);
     540             :     }
     541             : 
     542             :     /* -------------------------------------------------------------------- */
     543             :     /*      Open and start processing GeoJSON datasource to OGR objects.    */
     544             :     /* -------------------------------------------------------------------- */
     545         486 :     if (!poDS->Open(poOpenInfo, nSrcType, pszJSonFlavor))
     546             :     {
     547          28 :         poDS.reset();
     548             :     }
     549             : 
     550         486 :     if (poDS != nullptr && poDS->HasOtherPages())
     551             :     {
     552           8 :         const char *pszFilename = poOpenInfo->pszFilename;
     553           8 :         if (STARTS_WITH_CI(pszFilename, "ESRIJSON:"))
     554           1 :             pszFilename += strlen("ESRIJSON:");
     555           8 :         if (STARTS_WITH(pszFilename, "http") ||
     556           8 :             STARTS_WITH(pszFilename, "/vsimem/"))
     557             :         {
     558           8 :             const char *pszFSP = CSLFetchNameValue(poOpenInfo->papszOpenOptions,
     559             :                                                    "FEATURE_SERVER_PAGING");
     560             :             const bool bHasResultOffset =
     561           8 :                 !CPLURLGetValue(pszFilename, "resultOffset").empty();
     562           8 :             if ((!bHasResultOffset &&
     563          16 :                  (pszFSP == nullptr || CPLTestBool(pszFSP))) ||
     564           0 :                 (bHasResultOffset && pszFSP != nullptr && CPLTestBool(pszFSP)))
     565             :             {
     566             :                 return new OGRESRIFeatureServiceDataset(
     567           8 :                     pszFilename, std::move(poDS), nSrcType);
     568             :             }
     569             :         }
     570             :     }
     571             : 
     572         478 :     return poDS.release();
     573             : }
     574             : 
     575             : /************************************************************************/
     576             : /*                               Create()                               */
     577             : /************************************************************************/
     578             : 
     579         158 : static GDALDataset *OGRGeoJSONDriverCreate(const char *pszName,
     580             :                                            int /* nBands */, int /* nXSize */,
     581             :                                            int /* nYSize */,
     582             :                                            GDALDataType /* eDT */,
     583             :                                            char **papszOptions)
     584             : {
     585         158 :     OGRGeoJSONDataSource *poDS = new OGRGeoJSONDataSource();
     586             : 
     587         158 :     if (!poDS->Create(pszName, papszOptions))
     588             :     {
     589           2 :         delete poDS;
     590           2 :         poDS = nullptr;
     591             :     }
     592             : 
     593         158 :     return poDS;
     594             : }
     595             : 
     596             : /************************************************************************/
     597             : /*                               Delete()                               */
     598             : /************************************************************************/
     599             : 
     600          38 : static CPLErr OGRGeoJSONDriverDelete(const char *pszFilename)
     601             : {
     602          38 :     if (VSIUnlink(pszFilename) == 0)
     603             :     {
     604          38 :         return CE_None;
     605             :     }
     606             : 
     607           0 :     CPLDebug("GeoJSON", "Failed to delete \'%s\'", pszFilename);
     608             : 
     609           0 :     return CE_Failure;
     610             : }
     611             : 
     612             : /************************************************************************/
     613             : /*                      OGRGeoJSONDriverStoreContent()                  */
     614             : /************************************************************************/
     615             : 
     616          37 : void OGRGeoJSONDriverStoreContent(const char *pszSource, char *pszText)
     617             : {
     618          37 :     CPLMutexHolderD(&ghMutex);
     619          37 :     CPLAssert(pszSource);
     620          37 :     CPLAssert(pszText);
     621             : 
     622          37 :     CPLFree(gpszSource);
     623          37 :     CPLFree(gpszText);
     624          37 :     gpszSource = CPLStrdup(pszSource);
     625          37 :     gpszText = pszText;
     626          37 : }
     627             : 
     628             : /************************************************************************/
     629             : /*                    OGRGeoJSONDriverStealStoredContent()              */
     630             : /************************************************************************/
     631             : 
     632          41 : char *OGRGeoJSONDriverStealStoredContent(const char *pszSource)
     633             : {
     634          82 :     CPLMutexHolderD(&ghMutex);
     635          41 :     if (gpszSource && EQUAL(pszSource, gpszSource))
     636             :     {
     637          34 :         char *pszRet = gpszText;
     638          34 :         CPLFree(gpszSource);
     639          34 :         gpszSource = nullptr;
     640          34 :         gpszText = nullptr;
     641          34 :         return pszRet;
     642             :     }
     643           7 :     return nullptr;
     644             : }
     645             : 
     646             : /************************************************************************/
     647             : /*                        OGRGeoJSONDriverUnload()                      */
     648             : /************************************************************************/
     649             : 
     650         943 : static void OGRGeoJSONDriverUnload(GDALDriver *)
     651             : {
     652         943 :     if (ghMutex)
     653           0 :         CPLDestroyMutex(ghMutex);
     654         943 :     ghMutex = nullptr;
     655         943 :     CPLFree(gpszSource);
     656         943 :     CPLFree(gpszText);
     657         943 :     gpszSource = nullptr;
     658         943 :     gpszText = nullptr;
     659         943 : }
     660             : 
     661             : /************************************************************************/
     662             : /*                           RegisterOGRGeoJSON()                       */
     663             : /************************************************************************/
     664             : 
     665        1686 : void RegisterOGRGeoJSON()
     666             : {
     667        1686 :     if (!GDAL_CHECK_VERSION("OGR/GeoJSON driver"))
     668           0 :         return;
     669             : 
     670        1686 :     if (GDALGetDriverByName("GeoJSON") != nullptr)
     671         302 :         return;
     672             : 
     673        1384 :     GDALDriver *poDriver = new GDALDriver();
     674             : 
     675        1384 :     poDriver->SetDescription("GeoJSON");
     676        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
     677        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
     678        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
     679        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_DELETE_FIELD, "YES");
     680        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_REORDER_FIELDS, "YES");
     681        1384 :     poDriver->SetMetadataItem(GDAL_DMD_ALTER_FIELD_DEFN_FLAGS, "Name Type");
     682        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
     683        1384 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "GeoJSON");
     684        1384 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "json geojson");
     685        1384 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
     686        1384 :                               "drivers/vector/geojson.html");
     687             : 
     688        1384 :     poDriver->SetMetadataItem(
     689             :         GDAL_DMD_OPENOPTIONLIST,
     690             :         "<OpenOptionList>"
     691             :         "  <Option name='FLATTEN_NESTED_ATTRIBUTES' type='boolean' "
     692             :         "description='Whether to recursively explore nested objects and "
     693             :         "produce flatten OGR attributes' default='NO'/>"
     694             :         "  <Option name='NESTED_ATTRIBUTE_SEPARATOR' type='string' "
     695             :         "description='Separator between components of nested attributes' "
     696             :         "default='_'/>"
     697             :         "  <Option name='FEATURE_SERVER_PAGING' type='boolean' "
     698             :         "description='Whether to automatically scroll through results with a "
     699             :         "ArcGIS Feature Service endpoint'/>"
     700             :         "  <Option name='NATIVE_DATA' type='boolean' description='Whether to "
     701             :         "store the native JSon representation at FeatureCollection and Feature "
     702             :         "level' default='NO'/>"
     703             :         "  <Option name='ARRAY_AS_STRING' type='boolean' description='Whether "
     704             :         "to expose JSon arrays of strings, integers or reals as a OGR String' "
     705             :         "default='NO'/>"
     706             :         "  <Option name='DATE_AS_STRING' type='boolean' description='Whether "
     707             :         "to expose date/time/date-time content using dedicated OGR "
     708             :         "date/time/date-time types or as a OGR String' default='NO'/>"
     709             :         "  <Option name='FOREIGN_MEMBERS' type='string-select' "
     710             :         "description='Whether and how foreign members at the feature level "
     711             :         "should be processed as OGR fields' default='AUTO'>"
     712             :         "    <Value>AUTO</Value>"
     713             :         "    <Value>ALL</Value>"
     714             :         "    <Value>NONE</Value>"
     715             :         "    <Value>STAC</Value>"
     716             :         "  </Option>"
     717             :         "  <Option name='OGR_SCHEMA' type='string' description='"
     718             :         "Partially or totally overrides the auto-detected schema to use for "
     719             :         "creating the layer. "
     720             :         "The overrides are defined as a JSON list of field definitions. "
     721             :         "This can be a filename or a JSON string or a URL.'/>"
     722        1384 :         "</OpenOptionList>");
     723             : 
     724        1384 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST,
     725        1384 :                               "<CreationOptionList/>");
     726             : 
     727        1384 :     poDriver->SetMetadataItem(
     728             :         GDAL_DS_LAYER_CREATIONOPTIONLIST,
     729             :         "<LayerCreationOptionList>"
     730             :         "  <Option name='WRITE_BBOX' type='boolean' description='whether to "
     731             :         "write a bbox property with the bounding box of the geometries at the "
     732             :         "feature and feature collection level' default='NO'/>"
     733             :         "  <Option name='COORDINATE_PRECISION' type='int' description='Number "
     734             :         "of decimal for coordinates. Default is 15 for GJ2008 and 7 for "
     735             :         "RFC7946'/>"
     736             :         "  <Option name='SIGNIFICANT_FIGURES' type='int' description='Number "
     737             :         "of significant figures for floating-point values' default='17'/>"
     738             :         "  <Option name='NATIVE_DATA' type='string' "
     739             :         "description='FeatureCollection level elements.'/>"
     740             :         "  <Option name='NATIVE_MEDIA_TYPE' type='string' description='Format "
     741             :         "of NATIVE_DATA. Must be \"application/vnd.geo+json\", otherwise "
     742             :         "NATIVE_DATA will be ignored.'/>"
     743             :         "  <Option name='RFC7946' type='boolean' description='Whether to use "
     744             :         "RFC 7946 standard. Otherwise GeoJSON 2008 initial version will be "
     745             :         "used' default='NO'/>"
     746             :         "  <Option name='WRAPDATELINE' type='boolean' description='Whether to "
     747             :         "apply heuristics to split geometries that cross dateline.' "
     748             :         "default='YES'/>"
     749             :         "  <Option name='WRITE_NAME' type='boolean' description='Whether to "
     750             :         "write a &quot;name&quot; property at feature collection level with "
     751             :         "layer name' default='YES'/>"
     752             :         "  <Option name='DESCRIPTION' type='string' description='(Long) "
     753             :         "description to write in a &quot;description&quot; property at feature "
     754             :         "collection level'/>"
     755             :         "  <Option name='ID_FIELD' type='string' description='Name of the "
     756             :         "source field that must be used as the id member of Feature features'/>"
     757             :         "  <Option name='ID_TYPE' type='string-select' description='Type of "
     758             :         "the id member of Feature features'>"
     759             :         "    <Value>AUTO</Value>"
     760             :         "    <Value>String</Value>"
     761             :         "    <Value>Integer</Value>"
     762             :         "  </Option>"
     763             :         "  <Option name='ID_GENERATE' type='boolean' "
     764             :         "description='Auto-generate feature ids' />"
     765             :         "  <Option name='WRITE_NON_FINITE_VALUES' type='boolean' "
     766             :         "description='Whether to write NaN / Infinity values' default='NO'/>"
     767             :         "  <Option name='AUTODETECT_JSON_STRINGS' type='boolean' "
     768             :         "description='Whether to try to interpret string fields as JSON "
     769             :         "arrays or objects' default='YES'/>"
     770             :         "  <Option name='FOREIGN_MEMBERS_FEATURE' type='string' "
     771             :         "description='Extra JSON content to add in each feature as a foreign "
     772             :         "members'/>"
     773             :         "  <Option name='FOREIGN_MEMBERS_COLLECTION' type='string' "
     774             :         "description='Extra JSON content to add to the feature collection as "
     775             :         "a foreign members'/>"
     776        1384 :         "</LayerCreationOptionList>");
     777             : 
     778        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     779        1384 :     poDriver->SetMetadataItem(
     780             :         GDAL_DMD_CREATIONFIELDDATATYPES,
     781             :         "Integer Integer64 Real String IntegerList "
     782        1384 :         "Integer64List RealList StringList Date DateTime");
     783        1384 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, "Boolean");
     784        1384 :     poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
     785        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES, "YES");
     786        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_FLUSHCACHE_CONSISTENT_STATE, "YES");
     787        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION, "YES");
     788             : 
     789        1384 :     poDriver->SetMetadataItem(GDAL_DCAP_UPDATE, "YES");
     790        1384 :     poDriver->SetMetadataItem(GDAL_DMD_UPDATE_ITEMS, "Features");
     791             : 
     792        1384 :     poDriver->pfnOpen = OGRGeoJSONDriverOpen;
     793        1384 :     poDriver->pfnIdentify = OGRGeoJSONDriverIdentify;
     794        1384 :     poDriver->pfnCreate = OGRGeoJSONDriverCreate;
     795        1384 :     poDriver->pfnDelete = OGRGeoJSONDriverDelete;
     796        1384 :     poDriver->pfnUnloadDriver = OGRGeoJSONDriverUnload;
     797             : 
     798        1384 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     799             : 
     800             : #ifdef BUILT_AS_PLUGIN
     801             :     RegisterOGRTopoJSON();
     802             :     RegisterOGRESRIJSON();
     803             :     RegisterOGRGeoJSONSeq();
     804             : #endif
     805             : }

Generated by: LCOV version 1.14