LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/geojson - ogrgeojsondatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 584 670 87.2 %
Date: 2025-01-18 12:42:00 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         665 : 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         665 :       bUpdatable_(false)
      58             : {
      59         665 : }
      60             : 
      61             : /************************************************************************/
      62             : /*                           ~OGRGeoJSONDataSource()                    */
      63             : /************************************************************************/
      64             : 
      65        1330 : OGRGeoJSONDataSource::~OGRGeoJSONDataSource()
      66             : {
      67         665 :     OGRGeoJSONDataSource::Close();
      68        1330 : }
      69             : 
      70             : /************************************************************************/
      71             : /*                              Close()                                 */
      72             : /************************************************************************/
      73             : 
      74        1180 : CPLErr OGRGeoJSONDataSource::Close()
      75             : {
      76        1180 :     CPLErr eErr = CE_None;
      77        1180 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
      78             :     {
      79         665 :         if (OGRGeoJSONDataSource::FlushCache(true) != CE_None)
      80           0 :             eErr = CE_Failure;
      81             : 
      82         665 :         if (!OGRGeoJSONDataSource::Clear())
      83           0 :             eErr = CE_Failure;
      84             : 
      85         665 :         if (GDALDataset::Close() != CE_None)
      86           0 :             eErr = CE_Failure;
      87             :     }
      88        1180 :     return eErr;
      89             : }
      90             : 
      91             : /************************************************************************/
      92             : /*                 DealWithOgrSchemaOpenOption()                       */
      93             : /************************************************************************/
      94             : 
      95         480 : bool OGRGeoJSONDataSource::DealWithOgrSchemaOpenOption(
      96             :     const GDALOpenInfo *poOpenInfo)
      97             : {
      98             : 
      99             :     std::string osFieldsSchemaOverrideParam =
     100         960 :         CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "OGR_SCHEMA", "");
     101             : 
     102         480 :     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         477 :     return true;
     208             : }
     209             : 
     210             : /************************************************************************/
     211             : /*                           Open()                                     */
     212             : /************************************************************************/
     213             : 
     214         507 : int OGRGeoJSONDataSource::Open(GDALOpenInfo *poOpenInfo,
     215             :                                GeoJSONSourceType nSrcType,
     216             :                                const char *pszJSonFlavor)
     217             : {
     218         507 :     osJSonFlavor_ = pszJSonFlavor;
     219             : 
     220         507 :     const char *pszUnprefixed = poOpenInfo->pszFilename;
     221         507 :     if (STARTS_WITH_CI(pszUnprefixed, pszJSonFlavor) &&
     222           1 :         pszUnprefixed[strlen(pszJSonFlavor)] == ':')
     223             :     {
     224           1 :         pszUnprefixed += strlen(pszJSonFlavor) + 1;
     225             :     }
     226             : 
     227         507 :     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         484 :     else if (eGeoJSONSourceText == nSrcType)
     239             :     {
     240         139 :         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         138 :         pszGeoData_ = CPLStrdup(pszUnprefixed);
     247             :     }
     248         345 :     else if (eGeoJSONSourceFile == nSrcType)
     249             :     {
     250         344 :         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         344 :         pszName_ = CPLStrdup(pszUnprefixed);
     258         344 :         bUpdatable_ = (poOpenInfo->eAccess == GA_Update);
     259             : 
     260         344 :         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         343 :         else if (poOpenInfo->fpL == nullptr)
     269           6 :             return FALSE;
     270             :         else
     271             :         {
     272         337 :             pszGeoData_ = CPLStrdup(
     273         337 :                 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         480 :     if (nullptr == pszGeoData_ ||
     287         480 :         STARTS_WITH(pszGeoData_, "{\"couchdb\":\"Welcome\"") ||
     288         480 :         STARTS_WITH(pszGeoData_, "{\"db_name\":\"") ||
     289         480 :         STARTS_WITH(pszGeoData_, "{\"total_rows\":") ||
     290         480 :         STARTS_WITH(pszGeoData_, "{\"rows\":["))
     291             :     {
     292           0 :         Clear();
     293           0 :         return FALSE;
     294             :     }
     295             : 
     296         480 :     SetDescription(poOpenInfo->pszFilename);
     297         480 :     LoadLayers(poOpenInfo, nSrcType, pszUnprefixed, pszJSonFlavor);
     298             : 
     299         480 :     if (!DealWithOgrSchemaOpenOption(poOpenInfo))
     300             :     {
     301           3 :         Clear();
     302           3 :         return FALSE;
     303             :     }
     304             : 
     305         477 :     if (nLayers_ == 0)
     306             :     {
     307           4 :         bool bEmitError = true;
     308           4 :         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           4 :         Clear();
     321             : 
     322           4 :         if (bEmitError)
     323             :         {
     324           4 :             CPLError(CE_Failure, CPLE_OpenFailed, "Failed to read %s data",
     325             :                      pszJSonFlavor);
     326             :         }
     327           4 :         return FALSE;
     328             :     }
     329             : 
     330         473 :     return TRUE;
     331             : }
     332             : 
     333             : /************************************************************************/
     334             : /*                           GetLayerCount()                            */
     335             : /************************************************************************/
     336             : 
     337         444 : int OGRGeoJSONDataSource::GetLayerCount()
     338             : {
     339         444 :     return nLayers_;
     340             : }
     341             : 
     342             : /************************************************************************/
     343             : /*                           GetLayer()                                 */
     344             : /************************************************************************/
     345             : 
     346         576 : OGRLayer *OGRGeoJSONDataSource::GetLayer(int nLayer)
     347             : {
     348         576 :     if (0 <= nLayer && nLayer < nLayers_)
     349             :     {
     350         572 :         if (papoLayers_)
     351         571 :             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         178 : OGRGeoJSONDataSource::ICreateLayer(const char *pszNameIn,
     365             :                                    const OGRGeomFieldDefn *poSrcGeomFieldDefn,
     366             :                                    CSLConstList papszOptions)
     367             : {
     368         178 :     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         178 :     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         162 :         poSrcGeomFieldDefn ? poSrcGeomFieldDefn->GetType() : wkbNone;
     385             :     const auto poSRS =
     386         162 :         poSrcGeomFieldDefn ? poSrcGeomFieldDefn->GetSpatialRef() : nullptr;
     387             : 
     388             :     const char *pszForeignMembersCollection =
     389         162 :         CSLFetchNameValue(papszOptions, "FOREIGN_MEMBERS_COLLECTION");
     390         162 :     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         318 :         CSLFetchNameValueDef(papszOptions, "FOREIGN_MEMBERS_FEATURE", "");
     417         159 :     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         156 :     VSIFPrintfL(fpOut_, "{\n\"type\": \"FeatureCollection\",\n");
     442             : 
     443         156 :     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         156 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "WRITE_BBOX", "FALSE"));
     452             : 
     453             :     const bool bRFC7946 =
     454         156 :         CPLTestBool(CSLFetchNameValueDef(papszOptions, "RFC7946", "FALSE"));
     455             : 
     456         156 :     const char *pszNativeData = CSLFetchNameValue(papszOptions, "NATIVE_DATA");
     457             :     const char *pszNativeMediaType =
     458         156 :         CSLFetchNameValue(papszOptions, "NATIVE_MEDIA_TYPE");
     459         156 :     bool bWriteCRSIfWGS84 = true;
     460         156 :     bool bFoundNameInNativeData = false;
     461         156 :     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         156 :     const char *pszAtName = CSLFetchNameValue(papszOptions, "@NAME");
     539         156 :     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         448 :     else if (!bFoundNameInNativeData &&
     547         138 :              CPLFetchBool(papszOptions, "WRITE_NAME", true) &&
     548         403 :              !EQUAL(pszNameIn, OGRGeoJSONLayer::DefaultName) &&
     549         110 :              !EQUAL(pszNameIn, ""))
     550             :     {
     551         110 :         json_object *poName = json_object_new_string(pszNameIn);
     552         110 :         VSIFPrintfL(fpOut_, "\"name\": %s,\n",
     553             :                     json_object_to_json_string(poName));
     554         110 :         json_object_put(poName);
     555             :     }
     556             : 
     557         156 :     const char *pszDescription = CSLFetchNameValue(papszOptions, "DESCRIPTION");
     558         156 :     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         156 :     OGRCoordinateTransformation *poCT = nullptr;
     567         156 :     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         133 :     else if (poSRS)
     616             :     {
     617          55 :         char *pszOGCURN = poSRS->GetOGCURN();
     618          55 :         if (pszOGCURN != nullptr &&
     619          17 :             (bWriteCRSIfWGS84 ||
     620          17 :              !EQUAL(pszOGCURN, "urn:ogc:def:crs:EPSG::4326")))
     621             :         {
     622          39 :             json_object *poObjCRS = json_object_new_object();
     623          39 :             json_object_object_add(poObjCRS, "type",
     624             :                                    json_object_new_string("name"));
     625          39 :             json_object *poObjProperties = json_object_new_object();
     626          39 :             json_object_object_add(poObjCRS, "properties", poObjProperties);
     627             : 
     628          39 :             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          27 :                 json_object_object_add(poObjProperties, "name",
     637             :                                        json_object_new_string(pszOGCURN));
     638             :             }
     639             : 
     640          39 :             const char *pszCRS = json_object_to_json_string(poObjCRS);
     641          39 :             VSIFPrintfL(fpOut_, "\"crs\": %s,\n", pszCRS);
     642             : 
     643          39 :             json_object_put(poObjCRS);
     644             :         }
     645          55 :         CPLFree(pszOGCURN);
     646             :     }
     647             : 
     648         156 :     CPLStringList aosOptions(papszOptions);
     649             : 
     650         156 :     double dfXYResolution = OGRGeomCoordinatePrecision::UNKNOWN;
     651         156 :     double dfZResolution = OGRGeomCoordinatePrecision::UNKNOWN;
     652             : 
     653         156 :     if (const char *pszCoordPrecision =
     654         156 :             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         153 :     else if (poSrcGeomFieldDefn)
     667             :     {
     668         149 :         const auto &oCoordPrec = poSrcGeomFieldDefn->GetCoordinatePrecision();
     669         298 :         OGRSpatialReference oSRSWGS84;
     670         149 :         oSRSWGS84.SetWellKnownGeogCS("WGS84");
     671             :         const auto oCoordPrecWGS84 =
     672         298 :             oCoordPrec.ConvertToOtherSRS(poSRS, &oSRSWGS84);
     673             : 
     674         149 :         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         149 :         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         156 :     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         156 :     VSIFPrintfL(fpOut_, "\"features\": [\n");
     711             : 
     712             :     OGRGeoJSONWriteLayer *poLayer = new OGRGeoJSONWriteLayer(
     713         156 :         pszNameIn, eGType, aosOptions.List(), bWriteFC_BBOX, poCT, this);
     714             : 
     715         156 :     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         156 :     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         156 :     CPLAssert(papoLayers_ == nullptr);
     739         312 :     papoLayersWriter_ = static_cast<OGRGeoJSONWriteLayer **>(CPLRealloc(
     740         156 :         papoLayers_, sizeof(OGRGeoJSONWriteLayer *) * (nLayers_ + 1)));
     741             : 
     742         156 :     papoLayersWriter_[nLayers_++] = poLayer;
     743             : 
     744         156 :     return poLayer;
     745             : }
     746             : 
     747             : /************************************************************************/
     748             : /*                           TestCapability()                           */
     749             : /************************************************************************/
     750             : 
     751         341 : int OGRGeoJSONDataSource::TestCapability(const char *pszCap)
     752             : {
     753         341 :     if (EQUAL(pszCap, ODsCCreateLayer))
     754          99 :         return fpOut_ != nullptr && nLayers_ == 0;
     755         242 :     else if (EQUAL(pszCap, ODsCZGeometries) ||
     756         238 :              EQUAL(pszCap, ODsCMeasuredGeometries))
     757           8 :         return TRUE;
     758             : 
     759         234 :     return FALSE;
     760             : }
     761             : 
     762             : /************************************************************************/
     763             : /*                              Create()                                */
     764             : /************************************************************************/
     765             : 
     766         158 : int OGRGeoJSONDataSource::Create(const char *pszName,
     767             :                                  char ** /* papszOptions */)
     768             : {
     769         158 :     CPLAssert(nullptr == fpOut_);
     770             : 
     771         158 :     if (strcmp(pszName, "/dev/stdout") == 0)
     772           0 :         pszName = "/vsistdout/";
     773             : 
     774         315 :     bFpOutputIsSeekable_ = !(strcmp(pszName, "/vsistdout/") == 0 ||
     775         157 :                              STARTS_WITH(pszName, "/vsigzip/") ||
     776         151 :                              STARTS_WITH(pszName, "/vsizip/"));
     777             : 
     778             :     /* -------------------------------------------------------------------- */
     779             :     /*     File overwrite not supported.                                    */
     780             :     /* -------------------------------------------------------------------- */
     781             :     VSIStatBufL sStatBuf;
     782         158 :     if (0 == VSIStatL(pszName, &sStatBuf))
     783             :     {
     784           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     785             :                  "The GeoJSON driver does not overwrite existing files.");
     786           0 :         return FALSE;
     787             :     }
     788             : 
     789             :     /* -------------------------------------------------------------------- */
     790             :     /*      Create the output file.                                         */
     791             :     /* -------------------------------------------------------------------- */
     792         158 :     fpOut_ = VSIFOpenExL(pszName, "w", true);
     793         158 :     if (nullptr == fpOut_)
     794             :     {
     795           2 :         CPLError(CE_Failure, CPLE_OpenFailed,
     796             :                  "Failed to create GeoJSON datasource: %s: %s", pszName,
     797             :                  VSIGetLastErrorMsg());
     798           2 :         return FALSE;
     799             :     }
     800             : 
     801         156 :     pszName_ = CPLStrdup(pszName);
     802             : 
     803         156 :     return TRUE;
     804             : }
     805             : 
     806             : /************************************************************************/
     807             : /*                           SetGeometryTranslation()                   */
     808             : /************************************************************************/
     809             : 
     810         485 : void OGRGeoJSONDataSource::SetGeometryTranslation(GeometryTranslation type)
     811             : {
     812         485 :     flTransGeom_ = type;
     813         485 : }
     814             : 
     815             : /************************************************************************/
     816             : /*                           SetAttributesTranslation()                 */
     817             : /************************************************************************/
     818             : 
     819         485 : void OGRGeoJSONDataSource::SetAttributesTranslation(AttributesTranslation type)
     820             : {
     821         485 :     flTransAttrs_ = type;
     822         485 : }
     823             : 
     824             : /************************************************************************/
     825             : /*                  PRIVATE FUNCTIONS IMPLEMENTATION                    */
     826             : /************************************************************************/
     827             : 
     828         673 : bool OGRGeoJSONDataSource::Clear()
     829             : {
     830        1311 :     for (int i = 0; i < nLayers_; i++)
     831             :     {
     832         638 :         if (papoLayers_ != nullptr)
     833         482 :             delete papoLayers_[i];
     834             :         else
     835         156 :             delete papoLayersWriter_[i];
     836             :     }
     837             : 
     838         673 :     CPLFree(papoLayers_);
     839         673 :     papoLayers_ = nullptr;
     840         673 :     CPLFree(papoLayersWriter_);
     841         673 :     papoLayersWriter_ = nullptr;
     842         673 :     nLayers_ = 0;
     843             : 
     844         673 :     CPLFree(pszName_);
     845         673 :     pszName_ = nullptr;
     846             : 
     847         673 :     CPLFree(pszGeoData_);
     848         673 :     pszGeoData_ = nullptr;
     849         673 :     nGeoDataLen_ = 0;
     850             : 
     851         673 :     bool bRet = true;
     852         673 :     if (fpOut_)
     853             :     {
     854         156 :         if (VSIFCloseL(fpOut_) != 0)
     855           0 :             bRet = false;
     856         156 :         fpOut_ = nullptr;
     857             :     }
     858         673 :     return bRet;
     859             : }
     860             : 
     861             : /************************************************************************/
     862             : /*                           ReadFromFile()                             */
     863             : /************************************************************************/
     864             : 
     865          58 : int OGRGeoJSONDataSource::ReadFromFile(GDALOpenInfo *poOpenInfo,
     866             :                                        const char *pszUnprefixed)
     867             : {
     868          58 :     GByte *pabyOut = nullptr;
     869          58 :     if (!EQUAL(poOpenInfo->pszFilename, pszUnprefixed))
     870             :     {
     871           1 :         GDALOpenInfo oOpenInfo(pszUnprefixed, GA_ReadOnly);
     872           1 :         if (oOpenInfo.fpL == nullptr || oOpenInfo.pabyHeader == nullptr)
     873           0 :             return FALSE;
     874           1 :         VSIFSeekL(oOpenInfo.fpL, 0, SEEK_SET);
     875           1 :         if (!VSIIngestFile(oOpenInfo.fpL, pszUnprefixed, &pabyOut, nullptr, -1))
     876             :         {
     877           0 :             return FALSE;
     878             :         }
     879             :     }
     880             :     else
     881             :     {
     882          57 :         if (poOpenInfo->fpL == nullptr)
     883           0 :             return FALSE;
     884          57 :         VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET);
     885          57 :         if (!VSIIngestFile(poOpenInfo->fpL, poOpenInfo->pszFilename, &pabyOut,
     886             :                            nullptr, -1))
     887             :         {
     888           0 :             return FALSE;
     889             :         }
     890             : 
     891          57 :         VSIFCloseL(poOpenInfo->fpL);
     892          57 :         poOpenInfo->fpL = nullptr;
     893             :     }
     894             : 
     895          58 :     CPLFree(pszGeoData_);
     896          58 :     pszGeoData_ = reinterpret_cast<char *>(pabyOut);
     897             : 
     898          58 :     CPLAssert(nullptr != pszGeoData_);
     899             : 
     900          58 :     return TRUE;
     901             : }
     902             : 
     903             : /************************************************************************/
     904             : /*                           ReadFromService()                          */
     905             : /************************************************************************/
     906             : 
     907          23 : int OGRGeoJSONDataSource::ReadFromService(GDALOpenInfo *poOpenInfo,
     908             :                                           const char *pszSource)
     909             : {
     910          23 :     CPLAssert(nullptr == pszGeoData_);
     911          23 :     CPLAssert(nullptr != pszSource);
     912             : 
     913          23 :     CPLErrorReset();
     914             : 
     915             :     /* -------------------------------------------------------------------- */
     916             :     /*      Look if we already cached the content.                          */
     917             :     /* -------------------------------------------------------------------- */
     918          23 :     char *pszStoredContent = OGRGeoJSONDriverStealStoredContent(pszSource);
     919          23 :     if (pszStoredContent != nullptr)
     920             :     {
     921          16 :         if (!EQUAL(pszStoredContent, INVALID_CONTENT_FOR_JSON_LIKE) &&
     922           0 :             ((osJSonFlavor_ == "ESRIJSON" &&
     923           0 :               ESRIJSONIsObject(pszStoredContent, poOpenInfo)) ||
     924           0 :              (osJSonFlavor_ == "TopoJSON" &&
     925           0 :               TopoJSONIsObject(pszStoredContent, poOpenInfo))))
     926             :         {
     927           0 :             pszGeoData_ = pszStoredContent;
     928           0 :             nGeoDataLen_ = strlen(pszGeoData_);
     929             : 
     930           0 :             pszName_ = CPLStrdup(pszSource);
     931           0 :             return true;
     932             :         }
     933             : 
     934          16 :         OGRGeoJSONDriverStoreContent(pszSource, pszStoredContent);
     935          16 :         return false;
     936             :     }
     937             : 
     938             :     /* -------------------------------------------------------------------- */
     939             :     /*      Fetch the GeoJSON result.                                        */
     940             :     /* -------------------------------------------------------------------- */
     941           7 :     CPLHTTPResult *pResult = GeoJSONHTTPFetchWithContentTypeHeader(pszSource);
     942           7 :     if (!pResult)
     943             :     {
     944           0 :         return FALSE;
     945             :     }
     946             : 
     947             :     /* -------------------------------------------------------------------- */
     948             :     /*      Copy returned GeoJSON data to text buffer.                      */
     949             :     /* -------------------------------------------------------------------- */
     950           7 :     char *pszData = reinterpret_cast<char *>(pResult->pabyData);
     951             : 
     952             :     // Directly assign CPLHTTPResult::pabyData to pszGeoData_.
     953           7 :     pszGeoData_ = pszData;
     954           7 :     nGeoDataLen_ = pResult->nDataLen;
     955           7 :     pResult->pabyData = nullptr;
     956           7 :     pResult->nDataLen = 0;
     957             : 
     958           7 :     pszName_ = CPLStrdup(pszSource);
     959             : 
     960             :     /* -------------------------------------------------------------------- */
     961             :     /*      Cleanup HTTP resources.                                         */
     962             :     /* -------------------------------------------------------------------- */
     963           7 :     CPLHTTPDestroyResult(pResult);
     964             : 
     965           7 :     CPLAssert(nullptr != pszGeoData_);
     966             : 
     967             :     /* -------------------------------------------------------------------- */
     968             :     /*      Cache the content if it is not handled by this driver, but      */
     969             :     /*      another related one.                                            */
     970             :     /* -------------------------------------------------------------------- */
     971           7 :     if (EQUAL(pszSource, poOpenInfo->pszFilename) && osJSonFlavor_ == "GeoJSON")
     972             :     {
     973           7 :         if (!GeoJSONIsObject(pszGeoData_, poOpenInfo))
     974             :         {
     975           3 :             if (ESRIJSONIsObject(pszGeoData_, poOpenInfo) ||
     976           3 :                 TopoJSONIsObject(pszGeoData_, poOpenInfo) ||
     977           9 :                 GeoJSONSeqIsObject(pszGeoData_, poOpenInfo) ||
     978           3 :                 JSONFGIsObject(pszGeoData_, poOpenInfo))
     979             :             {
     980           0 :                 OGRGeoJSONDriverStoreContent(pszSource, pszGeoData_);
     981           0 :                 pszGeoData_ = nullptr;
     982           0 :                 nGeoDataLen_ = 0;
     983             :             }
     984             :             else
     985             :             {
     986           3 :                 OGRGeoJSONDriverStoreContent(
     987             :                     pszSource, CPLStrdup(INVALID_CONTENT_FOR_JSON_LIKE));
     988             :             }
     989           3 :             return false;
     990             :         }
     991             :     }
     992             : 
     993           4 :     return TRUE;
     994             : }
     995             : 
     996             : /************************************************************************/
     997             : /*                       RemoveJSonPStuff()                             */
     998             : /************************************************************************/
     999             : 
    1000         177 : void OGRGeoJSONDataSource::RemoveJSonPStuff()
    1001             : {
    1002         177 :     const char *const apszPrefix[] = {"loadGeoJSON(", "jsonp("};
    1003         531 :     for (size_t iP = 0; iP < CPL_ARRAYSIZE(apszPrefix); iP++)
    1004             :     {
    1005         354 :         if (strncmp(pszGeoData_, apszPrefix[iP], strlen(apszPrefix[iP])) == 0)
    1006             :         {
    1007           2 :             const size_t nDataLen = strlen(pszGeoData_);
    1008           2 :             memmove(pszGeoData_, pszGeoData_ + strlen(apszPrefix[iP]),
    1009           2 :                     nDataLen - strlen(apszPrefix[iP]));
    1010           2 :             size_t i = nDataLen - strlen(apszPrefix[iP]);
    1011           2 :             pszGeoData_[i] = '\0';
    1012           4 :             while (i > 0 && pszGeoData_[i] != ')')
    1013             :             {
    1014           2 :                 i--;
    1015             :             }
    1016           2 :             pszGeoData_[i] = '\0';
    1017             :         }
    1018             :     }
    1019         177 : }
    1020             : 
    1021             : /************************************************************************/
    1022             : /*                           LoadLayers()                               */
    1023             : /************************************************************************/
    1024             : 
    1025         480 : void OGRGeoJSONDataSource::LoadLayers(GDALOpenInfo *poOpenInfo,
    1026             :                                       GeoJSONSourceType nSrcType,
    1027             :                                       const char *pszUnprefixed,
    1028             :                                       const char *pszJSonFlavor)
    1029             : {
    1030         480 :     if (nullptr == pszGeoData_)
    1031             :     {
    1032           0 :         CPLError(CE_Failure, CPLE_ObjectNull, "%s data buffer empty",
    1033             :                  pszJSonFlavor);
    1034           0 :         return;
    1035             :     }
    1036             : 
    1037         480 :     if (nSrcType != eGeoJSONSourceFile)
    1038             :     {
    1039         142 :         RemoveJSonPStuff();
    1040             :     }
    1041             : 
    1042             :     /* -------------------------------------------------------------------- */
    1043             :     /*      Is it ESRI Feature Service data ?                               */
    1044             :     /* -------------------------------------------------------------------- */
    1045         480 :     if (EQUAL(pszJSonFlavor, "ESRIJSON"))
    1046             :     {
    1047          42 :         OGRESRIJSONReader reader;
    1048          21 :         if (nSrcType == eGeoJSONSourceFile)
    1049             :         {
    1050          19 :             if (!ReadFromFile(poOpenInfo, pszUnprefixed))
    1051           0 :                 return;
    1052             :         }
    1053          21 :         OGRErr err = reader.Parse(pszGeoData_);
    1054          21 :         if (OGRERR_NONE == err)
    1055             :         {
    1056          21 :             json_object *poObj = reader.GetJSonObject();
    1057          21 :             CheckExceededTransferLimit(poObj);
    1058          21 :             reader.ReadLayers(this, nSrcType);
    1059             :         }
    1060          21 :         return;
    1061             :     }
    1062             : 
    1063             :     /* -------------------------------------------------------------------- */
    1064             :     /*      Is it TopoJSON data ?                                           */
    1065             :     /* -------------------------------------------------------------------- */
    1066         459 :     if (EQUAL(pszJSonFlavor, "TOPOJSON"))
    1067             :     {
    1068           8 :         OGRTopoJSONReader reader;
    1069           4 :         if (nSrcType == eGeoJSONSourceFile)
    1070             :         {
    1071           4 :             if (!ReadFromFile(poOpenInfo, pszUnprefixed))
    1072           0 :                 return;
    1073             :         }
    1074           8 :         OGRErr err = reader.Parse(
    1075           4 :             pszGeoData_,
    1076           4 :             nSrcType == eGeoJSONSourceService &&
    1077           0 :                 !STARTS_WITH_CI(poOpenInfo->pszFilename, "TopoJSON:"));
    1078           4 :         if (OGRERR_NONE == err)
    1079             :         {
    1080           4 :             reader.ReadLayers(this);
    1081             :         }
    1082           4 :         return;
    1083             :     }
    1084             : 
    1085         455 :     VSILFILE *fp = nullptr;
    1086         455 :     if (nSrcType == eGeoJSONSourceFile &&
    1087         315 :         !EQUAL(poOpenInfo->pszFilename, pszUnprefixed))
    1088             :     {
    1089           0 :         GDALOpenInfo oOpenInfo(pszUnprefixed, GA_ReadOnly);
    1090           0 :         if (oOpenInfo.fpL == nullptr || oOpenInfo.pabyHeader == nullptr)
    1091           0 :             return;
    1092           0 :         CPL_IGNORE_RET_VAL(oOpenInfo.TryToIngest(6000));
    1093           0 :         CPLFree(pszGeoData_);
    1094           0 :         pszGeoData_ =
    1095           0 :             CPLStrdup(reinterpret_cast<const char *>(oOpenInfo.pabyHeader));
    1096           0 :         fp = oOpenInfo.fpL;
    1097           0 :         oOpenInfo.fpL = nullptr;
    1098             :     }
    1099             : 
    1100         455 :     if (!GeoJSONIsObject(pszGeoData_, poOpenInfo))
    1101             :     {
    1102           0 :         CPLDebug(pszJSonFlavor, "No valid %s data found in source '%s'",
    1103             :                  pszJSonFlavor, pszName_);
    1104           0 :         if (fp)
    1105           0 :             VSIFCloseL(fp);
    1106           0 :         return;
    1107             :     }
    1108             : 
    1109             :     /* -------------------------------------------------------------------- */
    1110             :     /*      Configure GeoJSON format translator.                            */
    1111             :     /* -------------------------------------------------------------------- */
    1112         455 :     OGRGeoJSONReader *poReader = new OGRGeoJSONReader();
    1113         455 :     SetOptionsOnReader(poOpenInfo, poReader);
    1114             : 
    1115             :     /* -------------------------------------------------------------------- */
    1116             :     /*      Parse GeoJSON and build valid OGRLayer instance.                */
    1117             :     /* -------------------------------------------------------------------- */
    1118         455 :     bool bUseStreamingInterface = false;
    1119         455 :     const GIntBig nMaxBytesFirstPass = CPLAtoGIntBig(
    1120             :         CPLGetConfigOption("OGR_GEOJSON_MAX_BYTES_FIRST_PASS", "0"));
    1121         455 :     if ((fp != nullptr || poOpenInfo->fpL != nullptr) &&
    1122         315 :         (!STARTS_WITH(pszUnprefixed, "/vsistdin/") ||
    1123           0 :          (nMaxBytesFirstPass > 0 && nMaxBytesFirstPass <= 1000000)))
    1124             :     {
    1125         315 :         const char *pszStr = strstr(pszGeoData_, "\"features\"");
    1126         315 :         if (pszStr)
    1127             :         {
    1128         281 :             pszStr += strlen("\"features\"");
    1129         304 :             while (*pszStr && isspace(static_cast<unsigned char>(*pszStr)))
    1130          23 :                 pszStr++;
    1131         281 :             if (*pszStr == ':')
    1132             :             {
    1133         281 :                 pszStr++;
    1134         637 :                 while (*pszStr && isspace(static_cast<unsigned char>(*pszStr)))
    1135         356 :                     pszStr++;
    1136         281 :                 if (*pszStr == '[')
    1137             :                 {
    1138         281 :                     bUseStreamingInterface = true;
    1139             :                 }
    1140             :             }
    1141             :         }
    1142             :     }
    1143             : 
    1144         455 :     if (bUseStreamingInterface)
    1145             :     {
    1146         281 :         bool bTryStandardReading = false;
    1147         281 :         if (poReader->FirstPassReadLayer(this, fp ? fp : poOpenInfo->fpL,
    1148             :                                          bTryStandardReading))
    1149             :         {
    1150         278 :             if (fp)
    1151           0 :                 fp = nullptr;
    1152             :             else
    1153         278 :                 poOpenInfo->fpL = nullptr;
    1154         278 :             CheckExceededTransferLimit(poReader->GetJSonObject());
    1155             :         }
    1156             :         else
    1157             :         {
    1158           3 :             delete poReader;
    1159             :         }
    1160         281 :         if (!bTryStandardReading)
    1161             :         {
    1162         280 :             if (fp)
    1163           0 :                 VSIFCloseL(fp);
    1164         280 :             return;
    1165             :         }
    1166             : 
    1167           1 :         poReader = new OGRGeoJSONReader();
    1168           1 :         SetOptionsOnReader(poOpenInfo, poReader);
    1169             :     }
    1170             : 
    1171         175 :     if (fp)
    1172           0 :         VSIFCloseL(fp);
    1173         175 :     if (nSrcType == eGeoJSONSourceFile)
    1174             :     {
    1175          35 :         if (!ReadFromFile(poOpenInfo, pszUnprefixed))
    1176             :         {
    1177           0 :             delete poReader;
    1178           0 :             return;
    1179             :         }
    1180          35 :         RemoveJSonPStuff();
    1181             :     }
    1182         175 :     const OGRErr err = poReader->Parse(pszGeoData_);
    1183         175 :     if (OGRERR_NONE == err)
    1184             :     {
    1185         175 :         CheckExceededTransferLimit(poReader->GetJSonObject());
    1186             :     }
    1187             : 
    1188         175 :     poReader->ReadLayers(this);
    1189         175 :     delete poReader;
    1190             : }
    1191             : 
    1192             : /************************************************************************/
    1193             : /*                          SetOptionsOnReader()                        */
    1194             : /************************************************************************/
    1195             : 
    1196         456 : void OGRGeoJSONDataSource::SetOptionsOnReader(GDALOpenInfo *poOpenInfo,
    1197             :                                               OGRGeoJSONReader *poReader)
    1198             : {
    1199         456 :     if (eGeometryAsCollection == flTransGeom_)
    1200             :     {
    1201           0 :         poReader->SetPreserveGeometryType(false);
    1202           0 :         CPLDebug("GeoJSON", "Geometry as OGRGeometryCollection type.");
    1203             :     }
    1204             : 
    1205         456 :     if (eAttributesSkip == flTransAttrs_)
    1206             :     {
    1207           0 :         poReader->SetSkipAttributes(true);
    1208           0 :         CPLDebug("GeoJSON", "Skip all attributes.");
    1209             :     }
    1210             : 
    1211        1368 :     poReader->SetFlattenNestedAttributes(
    1212         456 :         CPLFetchBool(poOpenInfo->papszOpenOptions, "FLATTEN_NESTED_ATTRIBUTES",
    1213             :                      false),
    1214         456 :         CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
    1215         456 :                              "NESTED_ATTRIBUTE_SEPARATOR", "_")[0]);
    1216             : 
    1217         456 :     const bool bDefaultNativeData = bUpdatable_;
    1218         456 :     poReader->SetStoreNativeData(CPLFetchBool(
    1219         456 :         poOpenInfo->papszOpenOptions, "NATIVE_DATA", bDefaultNativeData));
    1220             : 
    1221         912 :     poReader->SetArrayAsString(CPLTestBool(CSLFetchNameValueDef(
    1222         456 :         poOpenInfo->papszOpenOptions, "ARRAY_AS_STRING",
    1223             :         CPLGetConfigOption("OGR_GEOJSON_ARRAY_AS_STRING", "NO"))));
    1224             : 
    1225         912 :     poReader->SetDateAsString(CPLTestBool(CSLFetchNameValueDef(
    1226         456 :         poOpenInfo->papszOpenOptions, "DATE_AS_STRING",
    1227             :         CPLGetConfigOption("OGR_GEOJSON_DATE_AS_STRING", "NO"))));
    1228             : 
    1229         912 :     const char *pszForeignMembers = CSLFetchNameValueDef(
    1230         456 :         poOpenInfo->papszOpenOptions, "FOREIGN_MEMBERS", "AUTO");
    1231         456 :     if (EQUAL(pszForeignMembers, "AUTO"))
    1232             :     {
    1233         452 :         poReader->SetForeignMemberProcessing(
    1234             :             OGRGeoJSONBaseReader::ForeignMemberProcessing::AUTO);
    1235             :     }
    1236           4 :     else if (EQUAL(pszForeignMembers, "ALL"))
    1237             :     {
    1238           1 :         poReader->SetForeignMemberProcessing(
    1239             :             OGRGeoJSONBaseReader::ForeignMemberProcessing::ALL);
    1240             :     }
    1241           3 :     else if (EQUAL(pszForeignMembers, "NONE"))
    1242             :     {
    1243           2 :         poReader->SetForeignMemberProcessing(
    1244             :             OGRGeoJSONBaseReader::ForeignMemberProcessing::NONE);
    1245             :     }
    1246           1 :     else if (EQUAL(pszForeignMembers, "STAC"))
    1247             :     {
    1248           1 :         poReader->SetForeignMemberProcessing(
    1249             :             OGRGeoJSONBaseReader::ForeignMemberProcessing::STAC);
    1250             :     }
    1251         456 : }
    1252             : 
    1253             : /************************************************************************/
    1254             : /*                     CheckExceededTransferLimit()                     */
    1255             : /************************************************************************/
    1256             : 
    1257         474 : void OGRGeoJSONDataSource::CheckExceededTransferLimit(json_object *poObj)
    1258             : {
    1259        1404 :     for (int i = 0; i < 2; i++)
    1260             :     {
    1261         946 :         if (i == 1)
    1262             :         {
    1263         472 :             if (poObj && json_object_get_type(poObj) == json_type_object)
    1264             :             {
    1265         472 :                 poObj = CPL_json_object_object_get(poObj, "properties");
    1266             :             }
    1267             :         }
    1268         946 :         if (poObj && json_object_get_type(poObj) == json_type_object)
    1269             :         {
    1270             :             json_object *poExceededTransferLimit =
    1271         507 :                 CPL_json_object_object_get(poObj, "exceededTransferLimit");
    1272         523 :             if (poExceededTransferLimit &&
    1273          16 :                 json_object_get_type(poExceededTransferLimit) ==
    1274             :                     json_type_boolean)
    1275             :             {
    1276          16 :                 bOtherPages_ = CPL_TO_BOOL(
    1277             :                     json_object_get_boolean(poExceededTransferLimit));
    1278          16 :                 return;
    1279             :             }
    1280             :         }
    1281             :     }
    1282             : }
    1283             : 
    1284             : /************************************************************************/
    1285             : /*                            AddLayer()                                */
    1286             : /************************************************************************/
    1287             : 
    1288         482 : void OGRGeoJSONDataSource::AddLayer(OGRGeoJSONLayer *poLayer)
    1289             : {
    1290         482 :     CPLAssert(papoLayersWriter_ == nullptr);
    1291             : 
    1292             :     // Return layer in readable state.
    1293         482 :     poLayer->ResetReading();
    1294             : 
    1295         482 :     papoLayers_ = static_cast<OGRGeoJSONLayer **>(
    1296         482 :         CPLRealloc(papoLayers_, sizeof(OGRGeoJSONLayer *) * (nLayers_ + 1)));
    1297         482 :     papoLayers_[nLayers_] = poLayer;
    1298         482 :     nLayers_++;
    1299         482 : }
    1300             : 
    1301             : /************************************************************************/
    1302             : /*                            FlushCache()                              */
    1303             : /************************************************************************/
    1304             : 
    1305         746 : CPLErr OGRGeoJSONDataSource::FlushCache(bool /*bAtClosing*/)
    1306             : {
    1307         746 :     if (papoLayersWriter_ != nullptr)
    1308             :     {
    1309         234 :         return papoLayersWriter_[0]->SyncToDisk() == OGRERR_NONE ? CE_None
    1310         234 :                                                                  : CE_Failure;
    1311             :     }
    1312             : 
    1313         512 :     CPLErr eErr = CE_None;
    1314         994 :     for (int i = 0; i < nLayers_; i++)
    1315             :     {
    1316         482 :         if (papoLayers_[i]->HasBeenUpdated())
    1317             :         {
    1318          15 :             papoLayers_[i]->SetUpdated(false);
    1319             : 
    1320          15 :             bool bOK = false;
    1321             : 
    1322             :             // Disable all filters.
    1323          15 :             OGRFeatureQuery *poAttrQueryBak = papoLayers_[i]->m_poAttrQuery;
    1324          15 :             papoLayers_[i]->m_poAttrQuery = nullptr;
    1325          15 :             OGRGeometry *poFilterGeomBak = papoLayers_[i]->m_poFilterGeom;
    1326          15 :             papoLayers_[i]->m_poFilterGeom = nullptr;
    1327             : 
    1328             :             // If the source data only contained one single feature and
    1329             :             // that's still the case, then do not use a FeatureCollection
    1330             :             // on writing.
    1331          15 :             bool bAlreadyDone = false;
    1332          23 :             if (papoLayers_[i]->GetFeatureCount(TRUE) == 1 &&
    1333           8 :                 papoLayers_[i]->GetMetadata("NATIVE_DATA") == nullptr)
    1334             :             {
    1335           1 :                 papoLayers_[i]->ResetReading();
    1336           1 :                 OGRFeature *poFeature = papoLayers_[i]->GetNextFeature();
    1337           1 :                 if (poFeature != nullptr)
    1338             :                 {
    1339           1 :                     if (poFeature->GetNativeData() != nullptr)
    1340             :                     {
    1341           1 :                         bAlreadyDone = true;
    1342           2 :                         OGRGeoJSONWriteOptions oOptions;
    1343             :                         json_object *poObj =
    1344           1 :                             OGRGeoJSONWriteFeature(poFeature, oOptions);
    1345           1 :                         VSILFILE *fp = VSIFOpenL(pszName_, "wb");
    1346           1 :                         if (fp != nullptr)
    1347             :                         {
    1348           1 :                             bOK = VSIFPrintfL(
    1349             :                                       fp, "%s",
    1350             :                                       json_object_to_json_string(poObj)) > 0;
    1351           1 :                             VSIFCloseL(fp);
    1352             :                         }
    1353           1 :                         json_object_put(poObj);
    1354             :                     }
    1355           1 :                     delete poFeature;
    1356             :                 }
    1357             :             }
    1358             : 
    1359             :             // Otherwise do layer translation.
    1360          15 :             if (!bAlreadyDone)
    1361             :             {
    1362          14 :                 char **papszOptions = CSLAddString(nullptr, "-f");
    1363          14 :                 papszOptions = CSLAddString(papszOptions, "GeoJSON");
    1364             :                 GDALVectorTranslateOptions *psOptions =
    1365          14 :                     GDALVectorTranslateOptionsNew(papszOptions, nullptr);
    1366          14 :                 CSLDestroy(papszOptions);
    1367          14 :                 GDALDatasetH hSrcDS = this;
    1368          28 :                 CPLString osNewFilename(pszName_);
    1369          14 :                 osNewFilename += ".tmp";
    1370          14 :                 GDALDatasetH hOutDS = GDALVectorTranslate(
    1371             :                     osNewFilename, nullptr, 1, &hSrcDS, psOptions, nullptr);
    1372          14 :                 GDALVectorTranslateOptionsFree(psOptions);
    1373             : 
    1374          14 :                 if (hOutDS != nullptr)
    1375             :                 {
    1376          14 :                     CPLErrorReset();
    1377          14 :                     GDALClose(hOutDS);
    1378          14 :                     bOK = (CPLGetLastErrorType() == CE_None);
    1379             :                 }
    1380          14 :                 if (bOK)
    1381             :                 {
    1382          14 :                     const bool bOverwrite = CPLTestBool(
    1383             :                         CPLGetConfigOption("OGR_GEOJSON_REWRITE_IN_PLACE",
    1384             : #ifdef _WIN32
    1385             :                                            "YES"
    1386             : #else
    1387             :                                            "NO"
    1388             : #endif
    1389             :                                            ));
    1390          14 :                     if (bOverwrite)
    1391             :                     {
    1392           1 :                         VSILFILE *fpTarget = nullptr;
    1393           1 :                         for (int attempt = 0; attempt < 10; attempt++)
    1394             :                         {
    1395           1 :                             fpTarget = VSIFOpenL(pszName_, "rb+");
    1396           1 :                             if (fpTarget)
    1397           1 :                                 break;
    1398           0 :                             CPLSleep(0.1);
    1399             :                         }
    1400           1 :                         if (!fpTarget)
    1401             :                         {
    1402           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
    1403             :                                      "Cannot rewrite %s", pszName_);
    1404             :                         }
    1405             :                         else
    1406             :                         {
    1407           1 :                             bool bCopyOK = CPL_TO_BOOL(
    1408             :                                 VSIOverwriteFile(fpTarget, osNewFilename));
    1409           1 :                             if (VSIFCloseL(fpTarget) != 0)
    1410           0 :                                 bCopyOK = false;
    1411           1 :                             if (bCopyOK)
    1412             :                             {
    1413           1 :                                 VSIUnlink(osNewFilename);
    1414             :                             }
    1415             :                             else
    1416             :                             {
    1417           0 :                                 CPLError(CE_Failure, CPLE_AppDefined,
    1418             :                                          "Cannot rewrite %s with content of %s",
    1419             :                                          pszName_, osNewFilename.c_str());
    1420             :                             }
    1421             :                         }
    1422             :                     }
    1423             :                     else
    1424             :                     {
    1425          26 :                         CPLString osBackup(pszName_);
    1426          13 :                         osBackup += ".bak";
    1427          13 :                         if (VSIRename(pszName_, osBackup) < 0)
    1428             :                         {
    1429           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
    1430             :                                      "Cannot create backup copy");
    1431             :                         }
    1432          13 :                         else if (VSIRename(osNewFilename, pszName_) < 0)
    1433             :                         {
    1434           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
    1435             :                                      "Cannot rename %s to %s",
    1436             :                                      osNewFilename.c_str(), pszName_);
    1437             :                         }
    1438             :                         else
    1439             :                         {
    1440          13 :                             VSIUnlink(osBackup);
    1441             :                         }
    1442             :                     }
    1443             :                 }
    1444             :             }
    1445          15 :             if (!bOK)
    1446           0 :                 eErr = CE_Failure;
    1447             : 
    1448             :             // Restore filters.
    1449          15 :             papoLayers_[i]->m_poAttrQuery = poAttrQueryBak;
    1450          15 :             papoLayers_[i]->m_poFilterGeom = poFilterGeomBak;
    1451             :         }
    1452             :     }
    1453         512 :     return eErr;
    1454             : }

Generated by: LCOV version 1.14