LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/geojson - ogrgeojsondatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 585 671 87.2 %
Date: 2025-05-31 00:00:17 Functions: 22 22 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implementation of OGRGeoJSONDataSource class (OGR GeoJSON Driver).
       5             :  * Author:   Mateusz Loskot, mateusz@loskot.net
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2007, Mateusz Loskot
       9             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "ogr_geojson.h"
      16             : 
      17             : #include <cmath>
      18             : #include <cstddef>
      19             : #include <cstdlib>
      20             : #include <cstring>
      21             : #include <string>
      22             : 
      23             : #include "cpl_conv.h"
      24             : #include "cpl_error.h"
      25             : #include "cpl_http.h"
      26             : #include "cpl_string.h"
      27             : #include "cpl_vsi.h"
      28             : #include "cpl_vsi_error.h"
      29             : #include "json.h"
      30             : // #include "json_object.h"
      31             : #include "gdal_utils.h"
      32             : #include "gdal.h"
      33             : #include "gdal_priv.h"
      34             : #include "ogr_core.h"
      35             : #include "ogr_feature.h"
      36             : #include "ogr_geometry.h"
      37             : #include "ogr_spatialref.h"
      38             : #include "ogrlibjsonutils.h"
      39             : #include "ogrgeojsonreader.h"
      40             : #include "ogrgeojsonutils.h"
      41             : #include "ogrgeojsonwriter.h"
      42             : #include "ogrsf_frmts.h"
      43             : #include "ogr_schema_override.h"
      44             : 
      45             : // #include "symbol_renames.h"
      46             : 
      47             : /************************************************************************/
      48             : /*                           OGRGeoJSONDataSource()                     */
      49             : /************************************************************************/
      50             : 
      51         719 : OGRGeoJSONDataSource::OGRGeoJSONDataSource()
      52             :     : pszName_(nullptr), pszGeoData_(nullptr), nGeoDataLen_(0),
      53             :       papoLayers_(nullptr), papoLayersWriter_(nullptr), nLayers_(0),
      54             :       fpOut_(nullptr), flTransGeom_(OGRGeoJSONDataSource::eGeometryPreserve),
      55             :       flTransAttrs_(OGRGeoJSONDataSource::eAttributesPreserve),
      56             :       bOtherPages_(false), bFpOutputIsSeekable_(false), nBBOXInsertLocation_(0),
      57         719 :       bUpdatable_(false)
      58             : {
      59         719 : }
      60             : 
      61             : /************************************************************************/
      62             : /*                           ~OGRGeoJSONDataSource()                    */
      63             : /************************************************************************/
      64             : 
      65        1438 : OGRGeoJSONDataSource::~OGRGeoJSONDataSource()
      66             : {
      67         719 :     OGRGeoJSONDataSource::Close();
      68        1438 : }
      69             : 
      70             : /************************************************************************/
      71             : /*                              Close()                                 */
      72             : /************************************************************************/
      73             : 
      74        1252 : CPLErr OGRGeoJSONDataSource::Close()
      75             : {
      76        1252 :     CPLErr eErr = CE_None;
      77        1252 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
      78             :     {
      79         719 :         if (OGRGeoJSONDataSource::FlushCache(true) != CE_None)
      80           0 :             eErr = CE_Failure;
      81             : 
      82         719 :         if (!OGRGeoJSONDataSource::Clear())
      83           0 :             eErr = CE_Failure;
      84             : 
      85         719 :         if (GDALDataset::Close() != CE_None)
      86           0 :             eErr = CE_Failure;
      87             :     }
      88        1252 :     return eErr;
      89             : }
      90             : 
      91             : /************************************************************************/
      92             : /*                 DealWithOgrSchemaOpenOption()                       */
      93             : /************************************************************************/
      94             : 
      95         533 : bool OGRGeoJSONDataSource::DealWithOgrSchemaOpenOption(
      96             :     const GDALOpenInfo *poOpenInfo)
      97             : {
      98             : 
      99             :     std::string osFieldsSchemaOverrideParam =
     100        1066 :         CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "OGR_SCHEMA", "");
     101             : 
     102         533 :     if (!osFieldsSchemaOverrideParam.empty())
     103             :     {
     104             : 
     105           8 :         if (poOpenInfo->eAccess == GA_Update)
     106             :         {
     107           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     108             :                      "OGR_SCHEMA open option is not supported in update mode.");
     109           3 :             return false;
     110             :         }
     111             : 
     112           8 :         OGRSchemaOverride osSchemaOverride;
     113          15 :         if (!osSchemaOverride.LoadFromJSON(osFieldsSchemaOverrideParam) ||
     114           7 :             !osSchemaOverride.IsValid())
     115             :         {
     116           1 :             return false;
     117             :         }
     118             : 
     119           7 :         const auto &oLayerOverrides = osSchemaOverride.GetLayerOverrides();
     120          12 :         for (const auto &oLayer : oLayerOverrides)
     121             :         {
     122           7 :             const auto &oLayerName = oLayer.first;
     123           7 :             const auto &oLayerFieldOverride = oLayer.second;
     124           7 :             const bool bIsFullOverride{oLayerFieldOverride.IsFullOverride()};
     125           7 :             auto oFieldOverrides = oLayerFieldOverride.GetFieldOverrides();
     126           7 :             std::vector<OGRFieldDefn *> aoFields;
     127             : 
     128           7 :             CPLDebug("GeoJSON", "Applying schema override for layer %s",
     129             :                      oLayerName.c_str());
     130             : 
     131             :             // Fail if the layer name does not exist
     132           7 :             auto poLayer = GetLayerByName(oLayerName.c_str());
     133           7 :             if (poLayer == nullptr)
     134             :             {
     135           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
     136             :                          "Layer %s not found in GeoJSON file",
     137             :                          oLayerName.c_str());
     138           1 :                 return false;
     139             :             }
     140             : 
     141             :             // Patch field definitions
     142           6 :             auto poLayerDefn = poLayer->GetLayerDefn();
     143          54 :             for (int i = 0; i < poLayerDefn->GetFieldCount(); i++)
     144             :             {
     145          48 :                 auto poFieldDefn = poLayerDefn->GetFieldDefn(i);
     146             :                 auto oFieldOverride =
     147          48 :                     oFieldOverrides.find(poFieldDefn->GetNameRef());
     148          48 :                 if (oFieldOverride != oFieldOverrides.cend())
     149             :                 {
     150           8 :                     if (oFieldOverride->second.GetFieldType().has_value())
     151           8 :                         whileUnsealing(poFieldDefn)
     152           4 :                             ->SetType(
     153           4 :                                 oFieldOverride->second.GetFieldType().value());
     154           8 :                     if (oFieldOverride->second.GetFieldWidth().has_value())
     155           2 :                         whileUnsealing(poFieldDefn)
     156           1 :                             ->SetWidth(
     157           1 :                                 oFieldOverride->second.GetFieldWidth().value());
     158           8 :                     if (oFieldOverride->second.GetFieldPrecision().has_value())
     159           2 :                         whileUnsealing(poFieldDefn)
     160           1 :                             ->SetPrecision(
     161           2 :                                 oFieldOverride->second.GetFieldPrecision()
     162           1 :                                     .value());
     163           8 :                     if (oFieldOverride->second.GetFieldSubType().has_value())
     164           8 :                         whileUnsealing(poFieldDefn)
     165           4 :                             ->SetSubType(
     166           8 :                                 oFieldOverride->second.GetFieldSubType()
     167           4 :                                     .value());
     168           8 :                     if (oFieldOverride->second.GetFieldName().has_value())
     169           0 :                         whileUnsealing(poFieldDefn)
     170           0 :                             ->SetName(oFieldOverride->second.GetFieldName()
     171           0 :                                           .value()
     172             :                                           .c_str());
     173             : 
     174           8 :                     if (bIsFullOverride)
     175             :                     {
     176           2 :                         aoFields.push_back(poFieldDefn);
     177             :                     }
     178           8 :                     oFieldOverrides.erase(oFieldOverride);
     179             :                 }
     180             :             }
     181             : 
     182             :             // Error if any field override is not found
     183           6 :             if (!oFieldOverrides.empty())
     184             :             {
     185           2 :                 CPLError(CE_Failure, CPLE_AppDefined,
     186             :                          "Field %s not found in layer %s",
     187           1 :                          oFieldOverrides.cbegin()->first.c_str(),
     188             :                          oLayerName.c_str());
     189           1 :                 return false;
     190             :             }
     191             : 
     192             :             // Remove fields not in the override
     193           5 :             if (bIsFullOverride)
     194             :             {
     195           9 :                 for (int i = poLayerDefn->GetFieldCount() - 1; i >= 0; i--)
     196             :                 {
     197           8 :                     auto poFieldDefn = poLayerDefn->GetFieldDefn(i);
     198           8 :                     if (std::find(aoFields.begin(), aoFields.end(),
     199           8 :                                   poFieldDefn) == aoFields.end())
     200             :                     {
     201           6 :                         whileUnsealing(poLayerDefn)->DeleteFieldDefn(i);
     202             :                     }
     203             :                 }
     204             :             }
     205             :         }
     206             :     }
     207         530 :     return true;
     208             : }
     209             : 
     210             : /************************************************************************/
     211             : /*                           Open()                                     */
     212             : /************************************************************************/
     213             : 
     214         560 : int OGRGeoJSONDataSource::Open(GDALOpenInfo *poOpenInfo,
     215             :                                GeoJSONSourceType nSrcType,
     216             :                                const char *pszJSonFlavor)
     217             : {
     218         560 :     osJSonFlavor_ = pszJSonFlavor;
     219             : 
     220         560 :     const char *pszUnprefixed = poOpenInfo->pszFilename;
     221         560 :     if (STARTS_WITH_CI(pszUnprefixed, pszJSonFlavor) &&
     222           1 :         pszUnprefixed[strlen(pszJSonFlavor)] == ':')
     223             :     {
     224           1 :         pszUnprefixed += strlen(pszJSonFlavor) + 1;
     225             :     }
     226             : 
     227         560 :     if (eGeoJSONSourceService == nSrcType)
     228             :     {
     229          23 :         if (!ReadFromService(poOpenInfo, pszUnprefixed))
     230          19 :             return FALSE;
     231           4 :         if (poOpenInfo->eAccess == GA_Update)
     232             :         {
     233           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     234             :                      "Update from remote service not supported");
     235           0 :             return FALSE;
     236             :         }
     237             :     }
     238         537 :     else if (eGeoJSONSourceText == nSrcType)
     239             :     {
     240         182 :         if (poOpenInfo->eAccess == GA_Update)
     241             :         {
     242           1 :             CPLError(CE_Failure, CPLE_NotSupported,
     243             :                      "Update from inline definition not supported");
     244           1 :             return FALSE;
     245             :         }
     246         181 :         pszGeoData_ = CPLStrdup(pszUnprefixed);
     247             :     }
     248         355 :     else if (eGeoJSONSourceFile == nSrcType)
     249             :     {
     250         354 :         if (poOpenInfo->eAccess == GA_Update &&
     251          22 :             !EQUAL(pszJSonFlavor, "GeoJSON"))
     252             :         {
     253           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     254             :                      "Update of %s not supported", pszJSonFlavor);
     255           0 :             return FALSE;
     256             :         }
     257         354 :         pszName_ = CPLStrdup(pszUnprefixed);
     258         354 :         bUpdatable_ = (poOpenInfo->eAccess == GA_Update);
     259             : 
     260         354 :         if (!EQUAL(pszUnprefixed, poOpenInfo->pszFilename))
     261             :         {
     262           1 :             GDALOpenInfo oOpenInfo(pszUnprefixed, GA_ReadOnly);
     263           1 :             if (oOpenInfo.fpL == nullptr || oOpenInfo.pabyHeader == nullptr)
     264           0 :                 return FALSE;
     265           1 :             pszGeoData_ =
     266           1 :                 CPLStrdup(reinterpret_cast<const char *>(oOpenInfo.pabyHeader));
     267             :         }
     268         353 :         else if (poOpenInfo->fpL == nullptr)
     269           6 :             return FALSE;
     270             :         else
     271             :         {
     272         347 :             pszGeoData_ = CPLStrdup(
     273         347 :                 reinterpret_cast<const char *>(poOpenInfo->pabyHeader));
     274             :         }
     275             :     }
     276             :     else
     277             :     {
     278           1 :         Clear();
     279           1 :         return FALSE;
     280             :     }
     281             : 
     282             :     /* -------------------------------------------------------------------- */
     283             :     /*      Construct OGR layer and feature objects from                    */
     284             :     /*      GeoJSON text tree.                                              */
     285             :     /* -------------------------------------------------------------------- */
     286         533 :     if (nullptr == pszGeoData_ ||
     287         533 :         STARTS_WITH(pszGeoData_, "{\"couchdb\":\"Welcome\"") ||
     288         533 :         STARTS_WITH(pszGeoData_, "{\"db_name\":\"") ||
     289         533 :         STARTS_WITH(pszGeoData_, "{\"total_rows\":") ||
     290         533 :         STARTS_WITH(pszGeoData_, "{\"rows\":["))
     291             :     {
     292           0 :         Clear();
     293           0 :         return FALSE;
     294             :     }
     295             : 
     296         533 :     SetDescription(poOpenInfo->pszFilename);
     297         533 :     LoadLayers(poOpenInfo, nSrcType, pszUnprefixed, pszJSonFlavor);
     298             : 
     299         533 :     if (!DealWithOgrSchemaOpenOption(poOpenInfo))
     300             :     {
     301           3 :         Clear();
     302           3 :         return FALSE;
     303             :     }
     304             : 
     305         530 :     if (nLayers_ == 0)
     306             :     {
     307          33 :         bool bEmitError = true;
     308          33 :         if (eGeoJSONSourceService == nSrcType)
     309             :         {
     310             :             const CPLString osTmpFilename =
     311             :                 VSIMemGenerateHiddenFilename(CPLSPrintf(
     312           0 :                     "geojson_%s", CPLGetFilename(poOpenInfo->pszFilename)));
     313           0 :             VSIFCloseL(VSIFileFromMemBuffer(osTmpFilename, (GByte *)pszGeoData_,
     314             :                                             nGeoDataLen_, TRUE));
     315           0 :             pszGeoData_ = nullptr;
     316           0 :             if (GDALIdentifyDriver(osTmpFilename, nullptr))
     317           0 :                 bEmitError = false;
     318           0 :             VSIUnlink(osTmpFilename);
     319             :         }
     320          33 :         Clear();
     321             : 
     322          33 :         if (bEmitError)
     323             :         {
     324          33 :             CPLError(CE_Failure, CPLE_OpenFailed, "Failed to read %s data",
     325             :                      pszJSonFlavor);
     326             :         }
     327          33 :         return FALSE;
     328             :     }
     329             : 
     330         497 :     return TRUE;
     331             : }
     332             : 
     333             : /************************************************************************/
     334             : /*                           GetLayerCount()                            */
     335             : /************************************************************************/
     336             : 
     337         449 : int OGRGeoJSONDataSource::GetLayerCount()
     338             : {
     339         449 :     return nLayers_;
     340             : }
     341             : 
     342             : /************************************************************************/
     343             : /*                           GetLayer()                                 */
     344             : /************************************************************************/
     345             : 
     346         592 : OGRLayer *OGRGeoJSONDataSource::GetLayer(int nLayer)
     347             : {
     348         592 :     if (0 <= nLayer && nLayer < nLayers_)
     349             :     {
     350         588 :         if (papoLayers_)
     351         587 :             return papoLayers_[nLayer];
     352             :         else
     353           1 :             return papoLayersWriter_[nLayer];
     354             :     }
     355             : 
     356           4 :     return nullptr;
     357             : }
     358             : 
     359             : /************************************************************************/
     360             : /*                           ICreateLayer()                             */
     361             : /************************************************************************/
     362             : 
     363             : OGRLayer *
     364         179 : OGRGeoJSONDataSource::ICreateLayer(const char *pszNameIn,
     365             :                                    const OGRGeomFieldDefn *poSrcGeomFieldDefn,
     366             :                                    CSLConstList papszOptions)
     367             : {
     368         179 :     if (nullptr == fpOut_)
     369             :     {
     370           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     371             :                  "GeoJSON driver doesn't support creating a layer "
     372             :                  "on a read-only datasource");
     373           0 :         return nullptr;
     374             :     }
     375             : 
     376         179 :     if (nLayers_ != 0)
     377             :     {
     378          16 :         CPLError(CE_Failure, CPLE_NotSupported,
     379             :                  "GeoJSON driver doesn't support creating more than one layer");
     380          16 :         return nullptr;
     381             :     }
     382             : 
     383             :     const auto eGType =
     384         163 :         poSrcGeomFieldDefn ? poSrcGeomFieldDefn->GetType() : wkbNone;
     385             :     const auto poSRS =
     386         163 :         poSrcGeomFieldDefn ? poSrcGeomFieldDefn->GetSpatialRef() : nullptr;
     387             : 
     388             :     const char *pszForeignMembersCollection =
     389         163 :         CSLFetchNameValue(papszOptions, "FOREIGN_MEMBERS_COLLECTION");
     390         163 :     if (pszForeignMembersCollection)
     391             :     {
     392           4 :         if (pszForeignMembersCollection[0] != '{' ||
     393           3 :             pszForeignMembersCollection[strlen(pszForeignMembersCollection) -
     394           3 :                                         1] != '}')
     395             :         {
     396           2 :             CPLError(CE_Failure, CPLE_AppDefined,
     397             :                      "Value of FOREIGN_MEMBERS_COLLECTION should start with { "
     398             :                      "and end with }");
     399           3 :             return nullptr;
     400             :         }
     401           2 :         json_object *poTmp = nullptr;
     402           2 :         if (!OGRJSonParse(pszForeignMembersCollection, &poTmp, false))
     403             :         {
     404           1 :             pszForeignMembersCollection = nullptr;
     405             :         }
     406           2 :         json_object_put(poTmp);
     407           2 :         if (!pszForeignMembersCollection)
     408             :         {
     409           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     410             :                      "Value of FOREIGN_MEMBERS_COLLECTION is invalid JSON");
     411           1 :             return nullptr;
     412             :         }
     413             :     }
     414             : 
     415             :     std::string osForeignMembersFeature =
     416         320 :         CSLFetchNameValueDef(papszOptions, "FOREIGN_MEMBERS_FEATURE", "");
     417         160 :     if (!osForeignMembersFeature.empty())
     418             :     {
     419           7 :         if (osForeignMembersFeature.front() != '{' ||
     420           3 :             osForeignMembersFeature.back() != '}')
     421             :         {
     422           2 :             CPLError(CE_Failure, CPLE_AppDefined,
     423             :                      "Value of FOREIGN_MEMBERS_FEATURE should start with { and "
     424             :                      "end with }");
     425           3 :             return nullptr;
     426             :         }
     427           2 :         json_object *poTmp = nullptr;
     428           2 :         if (!OGRJSonParse(osForeignMembersFeature.c_str(), &poTmp, false))
     429             :         {
     430           1 :             osForeignMembersFeature.clear();
     431             :         }
     432           2 :         json_object_put(poTmp);
     433           2 :         if (osForeignMembersFeature.empty())
     434             :         {
     435           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     436             :                      "Value of FOREIGN_MEMBERS_FEATURE is invalid JSON");
     437           1 :             return nullptr;
     438             :         }
     439             :     }
     440             : 
     441         157 :     VSIFPrintfL(fpOut_, "{\n\"type\": \"FeatureCollection\",\n");
     442             : 
     443         157 :     if (pszForeignMembersCollection)
     444             :     {
     445           1 :         VSIFWriteL(pszForeignMembersCollection + 1, 1,
     446           1 :                    strlen(pszForeignMembersCollection) - 2, fpOut_);
     447           1 :         VSIFWriteL(",\n", 2, 1, fpOut_);
     448             :     }
     449             : 
     450             :     bool bWriteFC_BBOX =
     451         157 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "WRITE_BBOX", "FALSE"));
     452             : 
     453             :     const bool bRFC7946 =
     454         157 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "RFC7946", "FALSE"));
     455             : 
     456         157 :     const char *pszNativeData = CSLFetchNameValue(papszOptions, "NATIVE_DATA");
     457             :     const char *pszNativeMediaType =
     458         157 :         CSLFetchNameValue(papszOptions, "NATIVE_MEDIA_TYPE");
     459         157 :     bool bWriteCRSIfWGS84 = true;
     460         157 :     bool bFoundNameInNativeData = false;
     461         157 :     if (pszNativeData && pszNativeMediaType &&
     462          26 :         EQUAL(pszNativeMediaType, "application/vnd.geo+json"))
     463             :     {
     464          26 :         json_object *poObj = nullptr;
     465          52 :         if (OGRJSonParse(pszNativeData, &poObj) &&
     466          26 :             json_object_get_type(poObj) == json_type_object)
     467             :         {
     468             :             json_object_iter it;
     469          26 :             it.key = nullptr;
     470          26 :             it.val = nullptr;
     471          26 :             it.entry = nullptr;
     472          52 :             CPLString osNativeData;
     473          26 :             bWriteCRSIfWGS84 = false;
     474          69 :             json_object_object_foreachC(poObj, it)
     475             :             {
     476          43 :                 if (strcmp(it.key, "type") == 0 ||
     477          42 :                     strcmp(it.key, "features") == 0)
     478             :                 {
     479           2 :                     continue;
     480             :                 }
     481          41 :                 if (strcmp(it.key, "bbox") == 0)
     482             :                 {
     483           3 :                     if (CSLFetchNameValue(papszOptions, "WRITE_BBOX") ==
     484             :                         nullptr)
     485           3 :                         bWriteFC_BBOX = true;
     486           3 :                     continue;
     487             :                 }
     488          38 :                 if (strcmp(it.key, "crs") == 0)
     489             :                 {
     490           8 :                     if (!bRFC7946)
     491           7 :                         bWriteCRSIfWGS84 = true;
     492           8 :                     continue;
     493             :                 }
     494             :                 // See https://tools.ietf.org/html/rfc7946#section-7.1
     495          30 :                 if (bRFC7946 && (strcmp(it.key, "coordinates") == 0 ||
     496           4 :                                  strcmp(it.key, "geometries") == 0 ||
     497           3 :                                  strcmp(it.key, "geometry") == 0 ||
     498           2 :                                  strcmp(it.key, "properties") == 0))
     499             :                 {
     500           4 :                     continue;
     501             :                 }
     502             : 
     503          26 :                 if (strcmp(it.key, "name") == 0)
     504             :                 {
     505          17 :                     bFoundNameInNativeData = true;
     506          34 :                     if (!CPLFetchBool(papszOptions, "WRITE_NAME", true) ||
     507          17 :                         CSLFetchNameValue(papszOptions, "@NAME") != nullptr)
     508             :                     {
     509           0 :                         continue;
     510             :                     }
     511             :                 }
     512             : 
     513             :                 // If a native description exists, ignore it if an explicit
     514             :                 // DESCRIPTION option has been provided.
     515          26 :                 if (strcmp(it.key, "description") == 0 &&
     516           0 :                     CSLFetchNameValue(papszOptions, "DESCRIPTION"))
     517             :                 {
     518           0 :                     continue;
     519             :                 }
     520             : 
     521          26 :                 if (strcmp(it.key, "xy_coordinate_resolution") == 0 ||
     522          25 :                     strcmp(it.key, "z_coordinate_resolution") == 0)
     523             :                 {
     524           2 :                     continue;
     525             :                 }
     526             : 
     527          24 :                 json_object *poKey = json_object_new_string(it.key);
     528          24 :                 VSIFPrintfL(fpOut_, "%s: ", json_object_to_json_string(poKey));
     529          24 :                 json_object_put(poKey);
     530          24 :                 VSIFPrintfL(fpOut_, "%s,\n",
     531             :                             json_object_to_json_string(it.val));
     532             :             }
     533          26 :             json_object_put(poObj);
     534             :         }
     535             :     }
     536             : 
     537             :     // Used by ogr2ogr in -nln mode
     538         157 :     const char *pszAtName = CSLFetchNameValue(papszOptions, "@NAME");
     539         157 :     if (pszAtName && CPLFetchBool(papszOptions, "WRITE_NAME", true))
     540             :     {
     541           1 :         json_object *poName = json_object_new_string(pszAtName);
     542           1 :         VSIFPrintfL(fpOut_, "\"name\": %s,\n",
     543             :                     json_object_to_json_string(poName));
     544           1 :         json_object_put(poName);
     545             :     }
     546         451 :     else if (!bFoundNameInNativeData &&
     547         139 :              CPLFetchBool(papszOptions, "WRITE_NAME", true) &&
     548         406 :              !EQUAL(pszNameIn, OGRGeoJSONLayer::DefaultName) &&
     549         111 :              !EQUAL(pszNameIn, ""))
     550             :     {
     551         111 :         json_object *poName = json_object_new_string(pszNameIn);
     552         111 :         VSIFPrintfL(fpOut_, "\"name\": %s,\n",
     553             :                     json_object_to_json_string(poName));
     554         111 :         json_object_put(poName);
     555             :     }
     556             : 
     557         157 :     const char *pszDescription = CSLFetchNameValue(papszOptions, "DESCRIPTION");
     558         157 :     if (pszDescription)
     559             :     {
     560           1 :         json_object *poDesc = json_object_new_string(pszDescription);
     561           1 :         VSIFPrintfL(fpOut_, "\"description\": %s,\n",
     562             :                     json_object_to_json_string(poDesc));
     563           1 :         json_object_put(poDesc);
     564             :     }
     565             : 
     566         157 :     OGRCoordinateTransformation *poCT = nullptr;
     567         157 :     if (bRFC7946)
     568             :     {
     569          23 :         if (poSRS == nullptr)
     570             :         {
     571           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     572             :                      "No SRS set on layer. Assuming it is long/lat on WGS84 "
     573             :                      "ellipsoid");
     574             :         }
     575          23 :         else if (poSRS->GetAxesCount() == 3)
     576             :         {
     577           2 :             OGRSpatialReference oSRS_EPSG_4979;
     578           2 :             oSRS_EPSG_4979.importFromEPSG(4979);
     579           2 :             oSRS_EPSG_4979.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     580           2 :             if (!poSRS->IsSame(&oSRS_EPSG_4979))
     581             :             {
     582             :                 poCT =
     583           2 :                     OGRCreateCoordinateTransformation(poSRS, &oSRS_EPSG_4979);
     584           2 :                 if (poCT == nullptr)
     585             :                 {
     586           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     587             :                              "Failed to create coordinate transformation "
     588             :                              "between the "
     589             :                              "input coordinate system and WGS84.");
     590             : 
     591           0 :                     return nullptr;
     592             :                 }
     593             :             }
     594             :         }
     595             :         else
     596             :         {
     597          21 :             OGRSpatialReference oSRSWGS84;
     598          21 :             oSRSWGS84.SetWellKnownGeogCS("WGS84");
     599          21 :             oSRSWGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     600          21 :             if (!poSRS->IsSame(&oSRSWGS84))
     601             :             {
     602           9 :                 poCT = OGRCreateCoordinateTransformation(poSRS, &oSRSWGS84);
     603           9 :                 if (poCT == nullptr)
     604             :                 {
     605           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     606             :                              "Failed to create coordinate transformation "
     607             :                              "between the "
     608             :                              "input coordinate system and WGS84.");
     609             : 
     610           0 :                     return nullptr;
     611             :                 }
     612             :             }
     613             :         }
     614             :     }
     615         134 :     else if (poSRS)
     616             :     {
     617          56 :         char *pszOGCURN = poSRS->GetOGCURN();
     618          56 :         if (pszOGCURN != nullptr &&
     619          17 :             (bWriteCRSIfWGS84 ||
     620          17 :              !EQUAL(pszOGCURN, "urn:ogc:def:crs:EPSG::4326")))
     621             :         {
     622          40 :             json_object *poObjCRS = json_object_new_object();
     623          40 :             json_object_object_add(poObjCRS, "type",
     624             :                                    json_object_new_string("name"));
     625          40 :             json_object *poObjProperties = json_object_new_object();
     626          40 :             json_object_object_add(poObjCRS, "properties", poObjProperties);
     627             : 
     628          40 :             if (EQUAL(pszOGCURN, "urn:ogc:def:crs:EPSG::4326"))
     629             :             {
     630          12 :                 json_object_object_add(
     631             :                     poObjProperties, "name",
     632             :                     json_object_new_string("urn:ogc:def:crs:OGC:1.3:CRS84"));
     633             :             }
     634             :             else
     635             :             {
     636          28 :                 json_object_object_add(poObjProperties, "name",
     637             :                                        json_object_new_string(pszOGCURN));
     638             :             }
     639             : 
     640          40 :             const char *pszCRS = json_object_to_json_string(poObjCRS);
     641          40 :             VSIFPrintfL(fpOut_, "\"crs\": %s,\n", pszCRS);
     642             : 
     643          40 :             json_object_put(poObjCRS);
     644             :         }
     645          56 :         CPLFree(pszOGCURN);
     646             :     }
     647             : 
     648         157 :     CPLStringList aosOptions(papszOptions);
     649             : 
     650         157 :     double dfXYResolution = OGRGeomCoordinatePrecision::UNKNOWN;
     651         157 :     double dfZResolution = OGRGeomCoordinatePrecision::UNKNOWN;
     652             : 
     653         157 :     if (const char *pszCoordPrecision =
     654         157 :             CSLFetchNameValue(papszOptions, "COORDINATE_PRECISION"))
     655             :     {
     656           3 :         dfXYResolution = std::pow(10.0, -CPLAtof(pszCoordPrecision));
     657           3 :         dfZResolution = dfXYResolution;
     658           3 :         VSIFPrintfL(fpOut_, "\"xy_coordinate_resolution\": %g,\n",
     659             :                     dfXYResolution);
     660           3 :         if (poSRS && poSRS->GetAxesCount() == 3)
     661             :         {
     662           0 :             VSIFPrintfL(fpOut_, "\"z_coordinate_resolution\": %g,\n",
     663             :                         dfZResolution);
     664             :         }
     665             :     }
     666         154 :     else if (poSrcGeomFieldDefn)
     667             :     {
     668         150 :         const auto &oCoordPrec = poSrcGeomFieldDefn->GetCoordinatePrecision();
     669         300 :         OGRSpatialReference oSRSWGS84;
     670         150 :         oSRSWGS84.SetWellKnownGeogCS("WGS84");
     671             :         const auto oCoordPrecWGS84 =
     672         300 :             oCoordPrec.ConvertToOtherSRS(poSRS, &oSRSWGS84);
     673             : 
     674         150 :         if (oCoordPrec.dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN)
     675             :         {
     676           3 :             dfXYResolution = poSRS && bRFC7946 ? oCoordPrecWGS84.dfXYResolution
     677             :                                                : oCoordPrec.dfXYResolution;
     678             : 
     679             :             aosOptions.SetNameValue(
     680             :                 "XY_COORD_PRECISION",
     681             :                 CPLSPrintf("%d",
     682             :                            OGRGeomCoordinatePrecision::ResolutionToPrecision(
     683           3 :                                dfXYResolution)));
     684           3 :             VSIFPrintfL(fpOut_, "\"xy_coordinate_resolution\": %g,\n",
     685             :                         dfXYResolution);
     686             :         }
     687         150 :         if (oCoordPrec.dfZResolution != OGRGeomCoordinatePrecision::UNKNOWN)
     688             :         {
     689           3 :             dfZResolution = poSRS && bRFC7946 ? oCoordPrecWGS84.dfZResolution
     690             :                                               : oCoordPrec.dfZResolution;
     691             : 
     692             :             aosOptions.SetNameValue(
     693             :                 "Z_COORD_PRECISION",
     694             :                 CPLSPrintf("%d",
     695             :                            OGRGeomCoordinatePrecision::ResolutionToPrecision(
     696           3 :                                dfZResolution)));
     697           3 :             VSIFPrintfL(fpOut_, "\"z_coordinate_resolution\": %g,\n",
     698             :                         dfZResolution);
     699             :         }
     700             :     }
     701             : 
     702         157 :     if (bFpOutputIsSeekable_ && bWriteFC_BBOX)
     703             :     {
     704          23 :         nBBOXInsertLocation_ = static_cast<int>(VSIFTellL(fpOut_));
     705             : 
     706          46 :         const std::string osSpaceForBBOX(SPACE_FOR_BBOX + 1, ' ');
     707          23 :         VSIFPrintfL(fpOut_, "%s\n", osSpaceForBBOX.c_str());
     708             :     }
     709             : 
     710         157 :     VSIFPrintfL(fpOut_, "\"features\": [\n");
     711             : 
     712             :     OGRGeoJSONWriteLayer *poLayer = new OGRGeoJSONWriteLayer(
     713         157 :         pszNameIn, eGType, aosOptions.List(), bWriteFC_BBOX, poCT, this);
     714             : 
     715         157 :     if (eGType != wkbNone &&
     716             :         dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN)
     717             :     {
     718           6 :         auto poGeomFieldDefn = poLayer->GetLayerDefn()->GetGeomFieldDefn(0);
     719             :         OGRGeomCoordinatePrecision oCoordPrec(
     720          12 :             poGeomFieldDefn->GetCoordinatePrecision());
     721           6 :         oCoordPrec.dfXYResolution = dfXYResolution;
     722           6 :         poGeomFieldDefn->SetCoordinatePrecision(oCoordPrec);
     723             :     }
     724             : 
     725         157 :     if (eGType != wkbNone &&
     726             :         dfZResolution != OGRGeomCoordinatePrecision::UNKNOWN)
     727             :     {
     728           6 :         auto poGeomFieldDefn = poLayer->GetLayerDefn()->GetGeomFieldDefn(0);
     729             :         OGRGeomCoordinatePrecision oCoordPrec(
     730          12 :             poGeomFieldDefn->GetCoordinatePrecision());
     731           6 :         oCoordPrec.dfZResolution = dfZResolution;
     732           6 :         poGeomFieldDefn->SetCoordinatePrecision(oCoordPrec);
     733             :     }
     734             : 
     735             :     /* -------------------------------------------------------------------- */
     736             :     /*      Add layer to data source layer list.                            */
     737             :     /* -------------------------------------------------------------------- */
     738         157 :     CPLAssert(papoLayers_ == nullptr);
     739         314 :     papoLayersWriter_ = static_cast<OGRGeoJSONWriteLayer **>(CPLRealloc(
     740         157 :         papoLayers_, sizeof(OGRGeoJSONWriteLayer *) * (nLayers_ + 1)));
     741             : 
     742         157 :     papoLayersWriter_[nLayers_++] = poLayer;
     743             : 
     744         157 :     return poLayer;
     745             : }
     746             : 
     747             : /************************************************************************/
     748             : /*                           TestCapability()                           */
     749             : /************************************************************************/
     750             : 
     751         342 : int OGRGeoJSONDataSource::TestCapability(const char *pszCap)
     752             : {
     753         342 :     if (EQUAL(pszCap, ODsCCreateLayer))
     754         100 :         return fpOut_ != nullptr && nLayers_ == 0;
     755         242 :     else if (EQUAL(pszCap, ODsCMeasuredGeometries))
     756           2 :         return m_bSupportsMGeometries;
     757         240 :     else if (EQUAL(pszCap, ODsCZGeometries))
     758           4 :         return m_bSupportsZGeometries;
     759             : 
     760         236 :     return FALSE;
     761             : }
     762             : 
     763             : /************************************************************************/
     764             : /*                              Create()                                */
     765             : /************************************************************************/
     766             : 
     767         159 : int OGRGeoJSONDataSource::Create(const char *pszName,
     768             :                                  char ** /* papszOptions */)
     769             : {
     770         159 :     CPLAssert(nullptr == fpOut_);
     771             : 
     772         159 :     if (strcmp(pszName, "/dev/stdout") == 0)
     773           0 :         pszName = "/vsistdout/";
     774             : 
     775         317 :     bFpOutputIsSeekable_ = !(strcmp(pszName, "/vsistdout/") == 0 ||
     776         158 :                              STARTS_WITH(pszName, "/vsigzip/") ||
     777         152 :                              STARTS_WITH(pszName, "/vsizip/"));
     778             : 
     779             :     /* -------------------------------------------------------------------- */
     780             :     /*     File overwrite not supported.                                    */
     781             :     /* -------------------------------------------------------------------- */
     782             :     VSIStatBufL sStatBuf;
     783         159 :     if (0 == VSIStatL(pszName, &sStatBuf))
     784             :     {
     785           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     786             :                  "The GeoJSON driver does not overwrite existing files.");
     787           0 :         return FALSE;
     788             :     }
     789             : 
     790             :     /* -------------------------------------------------------------------- */
     791             :     /*      Create the output file.                                         */
     792             :     /* -------------------------------------------------------------------- */
     793         159 :     fpOut_ = VSIFOpenExL(pszName, "w", true);
     794         159 :     if (nullptr == fpOut_)
     795             :     {
     796           2 :         CPLError(CE_Failure, CPLE_OpenFailed,
     797             :                  "Failed to create GeoJSON datasource: %s: %s", pszName,
     798             :                  VSIGetLastErrorMsg());
     799           2 :         return FALSE;
     800             :     }
     801             : 
     802         157 :     pszName_ = CPLStrdup(pszName);
     803             : 
     804         157 :     return TRUE;
     805             : }
     806             : 
     807             : /************************************************************************/
     808             : /*                           SetGeometryTranslation()                   */
     809             : /************************************************************************/
     810             : 
     811         538 : void OGRGeoJSONDataSource::SetGeometryTranslation(GeometryTranslation type)
     812             : {
     813         538 :     flTransGeom_ = type;
     814         538 : }
     815             : 
     816             : /************************************************************************/
     817             : /*                           SetAttributesTranslation()                 */
     818             : /************************************************************************/
     819             : 
     820         538 : void OGRGeoJSONDataSource::SetAttributesTranslation(AttributesTranslation type)
     821             : {
     822         538 :     flTransAttrs_ = type;
     823         538 : }
     824             : 
     825             : /************************************************************************/
     826             : /*                  PRIVATE FUNCTIONS IMPLEMENTATION                    */
     827             : /************************************************************************/
     828             : 
     829         756 : bool OGRGeoJSONDataSource::Clear()
     830             : {
     831        1420 :     for (int i = 0; i < nLayers_; i++)
     832             :     {
     833         664 :         if (papoLayers_ != nullptr)
     834         507 :             delete papoLayers_[i];
     835             :         else
     836         157 :             delete papoLayersWriter_[i];
     837             :     }
     838             : 
     839         756 :     CPLFree(papoLayers_);
     840         756 :     papoLayers_ = nullptr;
     841         756 :     CPLFree(papoLayersWriter_);
     842         756 :     papoLayersWriter_ = nullptr;
     843         756 :     nLayers_ = 0;
     844             : 
     845         756 :     CPLFree(pszName_);
     846         756 :     pszName_ = nullptr;
     847             : 
     848         756 :     CPLFree(pszGeoData_);
     849         756 :     pszGeoData_ = nullptr;
     850         756 :     nGeoDataLen_ = 0;
     851             : 
     852         756 :     bool bRet = true;
     853         756 :     if (fpOut_)
     854             :     {
     855         157 :         if (VSIFCloseL(fpOut_) != 0)
     856           0 :             bRet = false;
     857         157 :         fpOut_ = nullptr;
     858             :     }
     859         756 :     return bRet;
     860             : }
     861             : 
     862             : /************************************************************************/
     863             : /*                           ReadFromFile()                             */
     864             : /************************************************************************/
     865             : 
     866          66 : int OGRGeoJSONDataSource::ReadFromFile(GDALOpenInfo *poOpenInfo,
     867             :                                        const char *pszUnprefixed)
     868             : {
     869          66 :     GByte *pabyOut = nullptr;
     870          66 :     if (!EQUAL(poOpenInfo->pszFilename, pszUnprefixed))
     871             :     {
     872           1 :         GDALOpenInfo oOpenInfo(pszUnprefixed, GA_ReadOnly);
     873           1 :         if (oOpenInfo.fpL == nullptr || oOpenInfo.pabyHeader == nullptr)
     874           0 :             return FALSE;
     875           1 :         VSIFSeekL(oOpenInfo.fpL, 0, SEEK_SET);
     876           1 :         if (!VSIIngestFile(oOpenInfo.fpL, pszUnprefixed, &pabyOut, nullptr, -1))
     877             :         {
     878           0 :             return FALSE;
     879             :         }
     880             :     }
     881             :     else
     882             :     {
     883          65 :         if (poOpenInfo->fpL == nullptr)
     884           0 :             return FALSE;
     885          65 :         VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET);
     886          65 :         if (!VSIIngestFile(poOpenInfo->fpL, poOpenInfo->pszFilename, &pabyOut,
     887             :                            nullptr, -1))
     888             :         {
     889           0 :             return FALSE;
     890             :         }
     891             : 
     892          65 :         VSIFCloseL(poOpenInfo->fpL);
     893          65 :         poOpenInfo->fpL = nullptr;
     894             :     }
     895             : 
     896          66 :     CPLFree(pszGeoData_);
     897          66 :     pszGeoData_ = reinterpret_cast<char *>(pabyOut);
     898             : 
     899          66 :     CPLAssert(nullptr != pszGeoData_);
     900             : 
     901          66 :     return TRUE;
     902             : }
     903             : 
     904             : /************************************************************************/
     905             : /*                           ReadFromService()                          */
     906             : /************************************************************************/
     907             : 
     908          23 : int OGRGeoJSONDataSource::ReadFromService(GDALOpenInfo *poOpenInfo,
     909             :                                           const char *pszSource)
     910             : {
     911          23 :     CPLAssert(nullptr == pszGeoData_);
     912          23 :     CPLAssert(nullptr != pszSource);
     913             : 
     914          23 :     CPLErrorReset();
     915             : 
     916             :     /* -------------------------------------------------------------------- */
     917             :     /*      Look if we already cached the content.                          */
     918             :     /* -------------------------------------------------------------------- */
     919          23 :     char *pszStoredContent = OGRGeoJSONDriverStealStoredContent(pszSource);
     920          23 :     if (pszStoredContent != nullptr)
     921             :     {
     922          16 :         if (!EQUAL(pszStoredContent, INVALID_CONTENT_FOR_JSON_LIKE) &&
     923           0 :             ((osJSonFlavor_ == "ESRIJSON" &&
     924           0 :               ESRIJSONIsObject(pszStoredContent, poOpenInfo)) ||
     925           0 :              (osJSonFlavor_ == "TopoJSON" &&
     926           0 :               TopoJSONIsObject(pszStoredContent, poOpenInfo))))
     927             :         {
     928           0 :             pszGeoData_ = pszStoredContent;
     929           0 :             nGeoDataLen_ = strlen(pszGeoData_);
     930             : 
     931           0 :             pszName_ = CPLStrdup(pszSource);
     932           0 :             return true;
     933             :         }
     934             : 
     935          16 :         OGRGeoJSONDriverStoreContent(pszSource, pszStoredContent);
     936          16 :         return false;
     937             :     }
     938             : 
     939             :     /* -------------------------------------------------------------------- */
     940             :     /*      Fetch the GeoJSON result.                                        */
     941             :     /* -------------------------------------------------------------------- */
     942           7 :     CPLHTTPResult *pResult = GeoJSONHTTPFetchWithContentTypeHeader(pszSource);
     943           7 :     if (!pResult)
     944             :     {
     945           0 :         return FALSE;
     946             :     }
     947             : 
     948             :     /* -------------------------------------------------------------------- */
     949             :     /*      Copy returned GeoJSON data to text buffer.                      */
     950             :     /* -------------------------------------------------------------------- */
     951           7 :     char *pszData = reinterpret_cast<char *>(pResult->pabyData);
     952             : 
     953             :     // Directly assign CPLHTTPResult::pabyData to pszGeoData_.
     954           7 :     pszGeoData_ = pszData;
     955           7 :     nGeoDataLen_ = pResult->nDataLen;
     956           7 :     pResult->pabyData = nullptr;
     957           7 :     pResult->nDataLen = 0;
     958             : 
     959           7 :     pszName_ = CPLStrdup(pszSource);
     960             : 
     961             :     /* -------------------------------------------------------------------- */
     962             :     /*      Cleanup HTTP resources.                                         */
     963             :     /* -------------------------------------------------------------------- */
     964           7 :     CPLHTTPDestroyResult(pResult);
     965             : 
     966           7 :     CPLAssert(nullptr != pszGeoData_);
     967             : 
     968             :     /* -------------------------------------------------------------------- */
     969             :     /*      Cache the content if it is not handled by this driver, but      */
     970             :     /*      another related one.                                            */
     971             :     /* -------------------------------------------------------------------- */
     972           7 :     if (EQUAL(pszSource, poOpenInfo->pszFilename) && osJSonFlavor_ == "GeoJSON")
     973             :     {
     974           7 :         if (!GeoJSONIsObject(pszGeoData_, poOpenInfo))
     975             :         {
     976           3 :             if (ESRIJSONIsObject(pszGeoData_, poOpenInfo) ||
     977           3 :                 TopoJSONIsObject(pszGeoData_, poOpenInfo) ||
     978           9 :                 GeoJSONSeqIsObject(pszGeoData_, poOpenInfo) ||
     979           3 :                 JSONFGIsObject(pszGeoData_, poOpenInfo))
     980             :             {
     981           0 :                 OGRGeoJSONDriverStoreContent(pszSource, pszGeoData_);
     982           0 :                 pszGeoData_ = nullptr;
     983           0 :                 nGeoDataLen_ = 0;
     984             :             }
     985             :             else
     986             :             {
     987           3 :                 OGRGeoJSONDriverStoreContent(
     988             :                     pszSource, CPLStrdup(INVALID_CONTENT_FOR_JSON_LIKE));
     989             :             }
     990           3 :             return false;
     991             :         }
     992             :     }
     993             : 
     994           4 :     return TRUE;
     995             : }
     996             : 
     997             : /************************************************************************/
     998             : /*                       RemoveJSonPStuff()                             */
     999             : /************************************************************************/
    1000             : 
    1001         227 : void OGRGeoJSONDataSource::RemoveJSonPStuff()
    1002             : {
    1003         227 :     const char *const apszPrefix[] = {"loadGeoJSON(", "jsonp("};
    1004         681 :     for (size_t iP = 0; iP < CPL_ARRAYSIZE(apszPrefix); iP++)
    1005             :     {
    1006         454 :         if (strncmp(pszGeoData_, apszPrefix[iP], strlen(apszPrefix[iP])) == 0)
    1007             :         {
    1008           2 :             const size_t nDataLen = strlen(pszGeoData_);
    1009           2 :             memmove(pszGeoData_, pszGeoData_ + strlen(apszPrefix[iP]),
    1010           2 :                     nDataLen - strlen(apszPrefix[iP]));
    1011           2 :             size_t i = nDataLen - strlen(apszPrefix[iP]);
    1012           2 :             pszGeoData_[i] = '\0';
    1013           4 :             while (i > 0 && pszGeoData_[i] != ')')
    1014             :             {
    1015           2 :                 i--;
    1016             :             }
    1017           2 :             pszGeoData_[i] = '\0';
    1018             :         }
    1019             :     }
    1020         227 : }
    1021             : 
    1022             : /************************************************************************/
    1023             : /*                           LoadLayers()                               */
    1024             : /************************************************************************/
    1025             : 
    1026         533 : void OGRGeoJSONDataSource::LoadLayers(GDALOpenInfo *poOpenInfo,
    1027             :                                       GeoJSONSourceType nSrcType,
    1028             :                                       const char *pszUnprefixed,
    1029             :                                       const char *pszJSonFlavor)
    1030             : {
    1031         533 :     if (nullptr == pszGeoData_)
    1032             :     {
    1033           0 :         CPLError(CE_Failure, CPLE_ObjectNull, "%s data buffer empty",
    1034             :                  pszJSonFlavor);
    1035           0 :         return;
    1036             :     }
    1037             : 
    1038         533 :     if (nSrcType != eGeoJSONSourceFile)
    1039             :     {
    1040         185 :         RemoveJSonPStuff();
    1041             :     }
    1042             : 
    1043             :     /* -------------------------------------------------------------------- */
    1044             :     /*      Is it ESRI Feature Service data ?                               */
    1045             :     /* -------------------------------------------------------------------- */
    1046         533 :     if (EQUAL(pszJSonFlavor, "ESRIJSON"))
    1047             :     {
    1048          42 :         OGRESRIJSONReader reader;
    1049          21 :         if (nSrcType == eGeoJSONSourceFile)
    1050             :         {
    1051          19 :             if (!ReadFromFile(poOpenInfo, pszUnprefixed))
    1052           0 :                 return;
    1053             :         }
    1054          21 :         OGRErr err = reader.Parse(pszGeoData_);
    1055          21 :         if (OGRERR_NONE == err)
    1056             :         {
    1057          21 :             json_object *poObj = reader.GetJSonObject();
    1058          21 :             CheckExceededTransferLimit(poObj);
    1059          21 :             reader.ReadLayers(this, nSrcType);
    1060             :         }
    1061          21 :         return;
    1062             :     }
    1063             : 
    1064             :     /* -------------------------------------------------------------------- */
    1065             :     /*      Is it TopoJSON data ?                                           */
    1066             :     /* -------------------------------------------------------------------- */
    1067         512 :     if (EQUAL(pszJSonFlavor, "TOPOJSON"))
    1068             :     {
    1069          10 :         OGRTopoJSONReader reader;
    1070           5 :         if (nSrcType == eGeoJSONSourceFile)
    1071             :         {
    1072           5 :             if (!ReadFromFile(poOpenInfo, pszUnprefixed))
    1073           0 :                 return;
    1074             :         }
    1075          10 :         OGRErr err = reader.Parse(
    1076           5 :             pszGeoData_,
    1077           5 :             nSrcType == eGeoJSONSourceService &&
    1078           0 :                 !STARTS_WITH_CI(poOpenInfo->pszFilename, "TopoJSON:"));
    1079           5 :         if (OGRERR_NONE == err)
    1080             :         {
    1081           5 :             reader.ReadLayers(this);
    1082             :         }
    1083           5 :         return;
    1084             :     }
    1085             : 
    1086         507 :     VSILFILE *fp = nullptr;
    1087         507 :     if (nSrcType == eGeoJSONSourceFile &&
    1088         324 :         !EQUAL(poOpenInfo->pszFilename, pszUnprefixed))
    1089             :     {
    1090           0 :         GDALOpenInfo oOpenInfo(pszUnprefixed, GA_ReadOnly);
    1091           0 :         if (oOpenInfo.fpL == nullptr || oOpenInfo.pabyHeader == nullptr)
    1092           0 :             return;
    1093           0 :         CPL_IGNORE_RET_VAL(oOpenInfo.TryToIngest(6000));
    1094           0 :         CPLFree(pszGeoData_);
    1095           0 :         pszGeoData_ =
    1096           0 :             CPLStrdup(reinterpret_cast<const char *>(oOpenInfo.pabyHeader));
    1097           0 :         fp = oOpenInfo.fpL;
    1098           0 :         oOpenInfo.fpL = nullptr;
    1099             :     }
    1100             : 
    1101         507 :     if (!GeoJSONIsObject(pszGeoData_, poOpenInfo))
    1102             :     {
    1103           0 :         CPLDebug(pszJSonFlavor, "No valid %s data found in source '%s'",
    1104             :                  pszJSonFlavor, pszName_);
    1105           0 :         if (fp)
    1106           0 :             VSIFCloseL(fp);
    1107           0 :         return;
    1108             :     }
    1109             : 
    1110             :     /* -------------------------------------------------------------------- */
    1111             :     /*      Configure GeoJSON format translator.                            */
    1112             :     /* -------------------------------------------------------------------- */
    1113         507 :     OGRGeoJSONReader *poReader = new OGRGeoJSONReader();
    1114         507 :     SetOptionsOnReader(poOpenInfo, poReader);
    1115             : 
    1116             :     /* -------------------------------------------------------------------- */
    1117             :     /*      Parse GeoJSON and build valid OGRLayer instance.                */
    1118             :     /* -------------------------------------------------------------------- */
    1119         507 :     bool bUseStreamingInterface = false;
    1120         507 :     const GIntBig nMaxBytesFirstPass = CPLAtoGIntBig(
    1121             :         CPLGetConfigOption("OGR_GEOJSON_MAX_BYTES_FIRST_PASS", "0"));
    1122         507 :     if ((fp != nullptr || poOpenInfo->fpL != nullptr) &&
    1123         324 :         (!STARTS_WITH(pszUnprefixed, "/vsistdin/") ||
    1124           0 :          (nMaxBytesFirstPass > 0 && nMaxBytesFirstPass <= 1000000)))
    1125             :     {
    1126         324 :         const char *pszStr = strstr(pszGeoData_, "\"features\"");
    1127         324 :         if (pszStr)
    1128             :         {
    1129         283 :             pszStr += strlen("\"features\"");
    1130         306 :             while (*pszStr && isspace(static_cast<unsigned char>(*pszStr)))
    1131          23 :                 pszStr++;
    1132         283 :             if (*pszStr == ':')
    1133             :             {
    1134         283 :                 pszStr++;
    1135         640 :                 while (*pszStr && isspace(static_cast<unsigned char>(*pszStr)))
    1136         357 :                     pszStr++;
    1137         283 :                 if (*pszStr == '[')
    1138             :                 {
    1139         283 :                     bUseStreamingInterface = true;
    1140             :                 }
    1141             :             }
    1142             :         }
    1143             :     }
    1144             : 
    1145         507 :     if (bUseStreamingInterface)
    1146             :     {
    1147         283 :         bool bTryStandardReading = false;
    1148         283 :         if (poReader->FirstPassReadLayer(this, fp ? fp : poOpenInfo->fpL,
    1149             :                                          bTryStandardReading))
    1150             :         {
    1151         280 :             if (fp)
    1152           0 :                 fp = nullptr;
    1153             :             else
    1154         280 :                 poOpenInfo->fpL = nullptr;
    1155         280 :             CheckExceededTransferLimit(poReader->GetJSonObject());
    1156             :         }
    1157             :         else
    1158             :         {
    1159           3 :             delete poReader;
    1160             :         }
    1161         283 :         if (!bTryStandardReading)
    1162             :         {
    1163         282 :             if (fp)
    1164           0 :                 VSIFCloseL(fp);
    1165         282 :             return;
    1166             :         }
    1167             : 
    1168           1 :         poReader = new OGRGeoJSONReader();
    1169           1 :         SetOptionsOnReader(poOpenInfo, poReader);
    1170             :     }
    1171             : 
    1172         225 :     if (fp)
    1173           0 :         VSIFCloseL(fp);
    1174         225 :     if (nSrcType == eGeoJSONSourceFile)
    1175             :     {
    1176          42 :         if (!ReadFromFile(poOpenInfo, pszUnprefixed))
    1177             :         {
    1178           0 :             delete poReader;
    1179           0 :             return;
    1180             :         }
    1181          42 :         RemoveJSonPStuff();
    1182             :     }
    1183         225 :     const OGRErr err = poReader->Parse(pszGeoData_);
    1184         225 :     if (OGRERR_NONE == err)
    1185             :     {
    1186         225 :         CheckExceededTransferLimit(poReader->GetJSonObject());
    1187             :     }
    1188             : 
    1189         225 :     poReader->ReadLayers(this);
    1190         225 :     delete poReader;
    1191             : }
    1192             : 
    1193             : /************************************************************************/
    1194             : /*                          SetOptionsOnReader()                        */
    1195             : /************************************************************************/
    1196             : 
    1197         508 : void OGRGeoJSONDataSource::SetOptionsOnReader(GDALOpenInfo *poOpenInfo,
    1198             :                                               OGRGeoJSONReader *poReader)
    1199             : {
    1200         508 :     if (eGeometryAsCollection == flTransGeom_)
    1201             :     {
    1202           0 :         poReader->SetPreserveGeometryType(false);
    1203           0 :         CPLDebug("GeoJSON", "Geometry as OGRGeometryCollection type.");
    1204             :     }
    1205             : 
    1206         508 :     if (eAttributesSkip == flTransAttrs_)
    1207             :     {
    1208           0 :         poReader->SetSkipAttributes(true);
    1209           0 :         CPLDebug("GeoJSON", "Skip all attributes.");
    1210             :     }
    1211             : 
    1212        1524 :     poReader->SetFlattenNestedAttributes(
    1213         508 :         CPLFetchBool(poOpenInfo->papszOpenOptions, "FLATTEN_NESTED_ATTRIBUTES",
    1214             :                      false),
    1215         508 :         CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
    1216         508 :                              "NESTED_ATTRIBUTE_SEPARATOR", "_")[0]);
    1217             : 
    1218         508 :     const bool bDefaultNativeData = bUpdatable_;
    1219         508 :     poReader->SetStoreNativeData(CPLFetchBool(
    1220         508 :         poOpenInfo->papszOpenOptions, "NATIVE_DATA", bDefaultNativeData));
    1221             : 
    1222        1016 :     poReader->SetArrayAsString(CPLTestBool(CSLFetchNameValueDef(
    1223         508 :         poOpenInfo->papszOpenOptions, "ARRAY_AS_STRING",
    1224             :         CPLGetConfigOption("OGR_GEOJSON_ARRAY_AS_STRING", "NO"))));
    1225             : 
    1226        1016 :     poReader->SetDateAsString(CPLTestBool(CSLFetchNameValueDef(
    1227         508 :         poOpenInfo->papszOpenOptions, "DATE_AS_STRING",
    1228             :         CPLGetConfigOption("OGR_GEOJSON_DATE_AS_STRING", "NO"))));
    1229             : 
    1230        1016 :     const char *pszForeignMembers = CSLFetchNameValueDef(
    1231         508 :         poOpenInfo->papszOpenOptions, "FOREIGN_MEMBERS", "AUTO");
    1232         508 :     if (EQUAL(pszForeignMembers, "AUTO"))
    1233             :     {
    1234         504 :         poReader->SetForeignMemberProcessing(
    1235             :             OGRGeoJSONBaseReader::ForeignMemberProcessing::AUTO);
    1236             :     }
    1237           4 :     else if (EQUAL(pszForeignMembers, "ALL"))
    1238             :     {
    1239           1 :         poReader->SetForeignMemberProcessing(
    1240             :             OGRGeoJSONBaseReader::ForeignMemberProcessing::ALL);
    1241             :     }
    1242           3 :     else if (EQUAL(pszForeignMembers, "NONE"))
    1243             :     {
    1244           2 :         poReader->SetForeignMemberProcessing(
    1245             :             OGRGeoJSONBaseReader::ForeignMemberProcessing::NONE);
    1246             :     }
    1247           1 :     else if (EQUAL(pszForeignMembers, "STAC"))
    1248             :     {
    1249           1 :         poReader->SetForeignMemberProcessing(
    1250             :             OGRGeoJSONBaseReader::ForeignMemberProcessing::STAC);
    1251             :     }
    1252         508 : }
    1253             : 
    1254             : /************************************************************************/
    1255             : /*                     CheckExceededTransferLimit()                     */
    1256             : /************************************************************************/
    1257             : 
    1258         526 : void OGRGeoJSONDataSource::CheckExceededTransferLimit(json_object *poObj)
    1259             : {
    1260        1560 :     for (int i = 0; i < 2; i++)
    1261             :     {
    1262        1050 :         if (i == 1)
    1263             :         {
    1264         524 :             if (poObj && json_object_get_type(poObj) == json_type_object)
    1265             :             {
    1266         524 :                 poObj = CPL_json_object_object_get(poObj, "properties");
    1267             :             }
    1268             :         }
    1269        1050 :         if (poObj && json_object_get_type(poObj) == json_type_object)
    1270             :         {
    1271             :             json_object *poExceededTransferLimit =
    1272         566 :                 CPL_json_object_object_get(poObj, "exceededTransferLimit");
    1273         582 :             if (poExceededTransferLimit &&
    1274          16 :                 json_object_get_type(poExceededTransferLimit) ==
    1275             :                     json_type_boolean)
    1276             :             {
    1277          16 :                 bOtherPages_ = CPL_TO_BOOL(
    1278             :                     json_object_get_boolean(poExceededTransferLimit));
    1279          16 :                 return;
    1280             :             }
    1281             :         }
    1282             :     }
    1283             : }
    1284             : 
    1285             : /************************************************************************/
    1286             : /*                            AddLayer()                                */
    1287             : /************************************************************************/
    1288             : 
    1289         507 : void OGRGeoJSONDataSource::AddLayer(OGRGeoJSONLayer *poLayer)
    1290             : {
    1291         507 :     CPLAssert(papoLayersWriter_ == nullptr);
    1292             : 
    1293             :     // Return layer in readable state.
    1294         507 :     poLayer->ResetReading();
    1295             : 
    1296         507 :     papoLayers_ = static_cast<OGRGeoJSONLayer **>(
    1297         507 :         CPLRealloc(papoLayers_, sizeof(OGRGeoJSONLayer *) * (nLayers_ + 1)));
    1298         507 :     papoLayers_[nLayers_] = poLayer;
    1299         507 :     nLayers_++;
    1300         507 : }
    1301             : 
    1302             : /************************************************************************/
    1303             : /*                            FlushCache()                              */
    1304             : /************************************************************************/
    1305             : 
    1306         801 : CPLErr OGRGeoJSONDataSource::FlushCache(bool /*bAtClosing*/)
    1307             : {
    1308         801 :     if (papoLayersWriter_ != nullptr)
    1309             :     {
    1310         236 :         return papoLayersWriter_[0]->SyncToDisk() == OGRERR_NONE ? CE_None
    1311         236 :                                                                  : CE_Failure;
    1312             :     }
    1313             : 
    1314         565 :     CPLErr eErr = CE_None;
    1315        1072 :     for (int i = 0; i < nLayers_; i++)
    1316             :     {
    1317         507 :         if (papoLayers_[i]->HasBeenUpdated())
    1318             :         {
    1319          15 :             papoLayers_[i]->SetUpdated(false);
    1320             : 
    1321          15 :             bool bOK = false;
    1322             : 
    1323             :             // Disable all filters.
    1324          15 :             OGRFeatureQuery *poAttrQueryBak = papoLayers_[i]->m_poAttrQuery;
    1325          15 :             papoLayers_[i]->m_poAttrQuery = nullptr;
    1326          15 :             OGRGeometry *poFilterGeomBak = papoLayers_[i]->m_poFilterGeom;
    1327          15 :             papoLayers_[i]->m_poFilterGeom = nullptr;
    1328             : 
    1329             :             // If the source data only contained one single feature and
    1330             :             // that's still the case, then do not use a FeatureCollection
    1331             :             // on writing.
    1332          15 :             bool bAlreadyDone = false;
    1333          23 :             if (papoLayers_[i]->GetFeatureCount(TRUE) == 1 &&
    1334           8 :                 papoLayers_[i]->GetMetadata("NATIVE_DATA") == nullptr)
    1335             :             {
    1336           1 :                 papoLayers_[i]->ResetReading();
    1337           1 :                 OGRFeature *poFeature = papoLayers_[i]->GetNextFeature();
    1338           1 :                 if (poFeature != nullptr)
    1339             :                 {
    1340           1 :                     if (poFeature->GetNativeData() != nullptr)
    1341             :                     {
    1342           1 :                         bAlreadyDone = true;
    1343           2 :                         OGRGeoJSONWriteOptions oOptions;
    1344             :                         json_object *poObj =
    1345           1 :                             OGRGeoJSONWriteFeature(poFeature, oOptions);
    1346           1 :                         VSILFILE *fp = VSIFOpenL(pszName_, "wb");
    1347           1 :                         if (fp != nullptr)
    1348             :                         {
    1349           1 :                             bOK = VSIFPrintfL(
    1350             :                                       fp, "%s",
    1351             :                                       json_object_to_json_string(poObj)) > 0;
    1352           1 :                             VSIFCloseL(fp);
    1353             :                         }
    1354           1 :                         json_object_put(poObj);
    1355             :                     }
    1356           1 :                     delete poFeature;
    1357             :                 }
    1358             :             }
    1359             : 
    1360             :             // Otherwise do layer translation.
    1361          15 :             if (!bAlreadyDone)
    1362             :             {
    1363          14 :                 char **papszOptions = CSLAddString(nullptr, "-f");
    1364          14 :                 papszOptions = CSLAddString(papszOptions, "GeoJSON");
    1365             :                 GDALVectorTranslateOptions *psOptions =
    1366          14 :                     GDALVectorTranslateOptionsNew(papszOptions, nullptr);
    1367          14 :                 CSLDestroy(papszOptions);
    1368          14 :                 GDALDatasetH hSrcDS = this;
    1369          28 :                 CPLString osNewFilename(pszName_);
    1370          14 :                 osNewFilename += ".tmp";
    1371          14 :                 GDALDatasetH hOutDS = GDALVectorTranslate(
    1372             :                     osNewFilename, nullptr, 1, &hSrcDS, psOptions, nullptr);
    1373          14 :                 GDALVectorTranslateOptionsFree(psOptions);
    1374             : 
    1375          14 :                 if (hOutDS != nullptr)
    1376             :                 {
    1377          14 :                     CPLErrorReset();
    1378          14 :                     GDALClose(hOutDS);
    1379          14 :                     bOK = (CPLGetLastErrorType() == CE_None);
    1380             :                 }
    1381          14 :                 if (bOK)
    1382             :                 {
    1383          14 :                     const bool bOverwrite = CPLTestBool(
    1384             :                         CPLGetConfigOption("OGR_GEOJSON_REWRITE_IN_PLACE",
    1385             : #ifdef _WIN32
    1386             :                                            "YES"
    1387             : #else
    1388             :                                            "NO"
    1389             : #endif
    1390             :                                            ));
    1391          14 :                     if (bOverwrite)
    1392             :                     {
    1393           1 :                         VSILFILE *fpTarget = nullptr;
    1394           1 :                         for (int attempt = 0; attempt < 10; attempt++)
    1395             :                         {
    1396           1 :                             fpTarget = VSIFOpenL(pszName_, "rb+");
    1397           1 :                             if (fpTarget)
    1398           1 :                                 break;
    1399           0 :                             CPLSleep(0.1);
    1400             :                         }
    1401           1 :                         if (!fpTarget)
    1402             :                         {
    1403           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
    1404             :                                      "Cannot rewrite %s", pszName_);
    1405             :                         }
    1406             :                         else
    1407             :                         {
    1408           1 :                             bool bCopyOK = CPL_TO_BOOL(
    1409             :                                 VSIOverwriteFile(fpTarget, osNewFilename));
    1410           1 :                             if (VSIFCloseL(fpTarget) != 0)
    1411           0 :                                 bCopyOK = false;
    1412           1 :                             if (bCopyOK)
    1413             :                             {
    1414           1 :                                 VSIUnlink(osNewFilename);
    1415             :                             }
    1416             :                             else
    1417             :                             {
    1418           0 :                                 CPLError(CE_Failure, CPLE_AppDefined,
    1419             :                                          "Cannot rewrite %s with content of %s",
    1420             :                                          pszName_, osNewFilename.c_str());
    1421             :                             }
    1422             :                         }
    1423             :                     }
    1424             :                     else
    1425             :                     {
    1426          26 :                         CPLString osBackup(pszName_);
    1427          13 :                         osBackup += ".bak";
    1428          13 :                         if (VSIRename(pszName_, osBackup) < 0)
    1429             :                         {
    1430           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
    1431             :                                      "Cannot create backup copy");
    1432             :                         }
    1433          13 :                         else if (VSIRename(osNewFilename, pszName_) < 0)
    1434             :                         {
    1435           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
    1436             :                                      "Cannot rename %s to %s",
    1437             :                                      osNewFilename.c_str(), pszName_);
    1438             :                         }
    1439             :                         else
    1440             :                         {
    1441          13 :                             VSIUnlink(osBackup);
    1442             :                         }
    1443             :                     }
    1444             :                 }
    1445             :             }
    1446          15 :             if (!bOK)
    1447           0 :                 eErr = CE_Failure;
    1448             : 
    1449             :             // Restore filters.
    1450          15 :             papoLayers_[i]->m_poAttrQuery = poAttrQueryBak;
    1451          15 :             papoLayers_[i]->m_poFilterGeom = poFilterGeomBak;
    1452             :         }
    1453             :     }
    1454         565 :     return eErr;
    1455             : }

Generated by: LCOV version 1.14