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: 2024-11-21 22:18:42 Functions: 27 28 96.4 %

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

Generated by: LCOV version 1.14