LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/geojson - ogrgeojsonreader.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1055 1137 92.8 %
Date: 2024-11-21 22:18:42 Functions: 44 46 95.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implementation of OGRGeoJSONReader class (OGR GeoJSON Driver).
       5             :  * Author:   Mateusz Loskot, mateusz@loskot.net
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2007, Mateusz Loskot
       9             :  * Copyright (c) 2008-2017, Even Rouault <even dot rouault at spatialys dot com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "ogrgeojsonreader.h"
      15             : #include "ogrgeojsonutils.h"
      16             : #include "ogrgeojsongeometry.h"
      17             : #include "ogr_geojson.h"
      18             : #include "ogrlibjsonutils.h"
      19             : #include "ogrjsoncollectionstreamingparser.h"
      20             : #include "ogr_api.h"
      21             : 
      22             : #include <cmath>
      23             : #include <limits>
      24             : #include <set>
      25             : #include <functional>
      26             : 
      27             : /************************************************************************/
      28             : /*                      OGRGeoJSONReaderStreamingParser                 */
      29             : /************************************************************************/
      30             : 
      31             : class OGRGeoJSONReaderStreamingParser final
      32             :     : public OGRJSONCollectionStreamingParser
      33             : {
      34             :     OGRGeoJSONReader &m_oReader;
      35             :     OGRGeoJSONLayer *m_poLayer = nullptr;
      36             : 
      37             :     std::vector<OGRFeature *> m_apoFeatures{};
      38             :     size_t m_nCurFeatureIdx = 0;
      39             :     bool m_bOriginalIdModifiedEmitted = false;
      40             :     std::set<GIntBig> m_oSetUsedFIDs{};
      41             : 
      42             :     std::map<std::string, int> m_oMapFieldNameToIdx{};
      43             :     std::vector<std::unique_ptr<OGRFieldDefn>> m_apoFieldDefn{};
      44             :     gdal::DirectedAcyclicGraph<int, std::string> m_dag{};
      45             : 
      46             :     void AnalyzeFeature();
      47             : 
      48             :     CPL_DISALLOW_COPY_ASSIGN(OGRGeoJSONReaderStreamingParser)
      49             : 
      50             :   protected:
      51             :     void GotFeature(json_object *poObj, bool bFirstPass,
      52             :                     const std::string &osJson) override;
      53             :     void TooComplex() override;
      54             : 
      55             :   public:
      56             :     OGRGeoJSONReaderStreamingParser(OGRGeoJSONReader &oReader,
      57             :                                     OGRGeoJSONLayer *poLayer, bool bFirstPass,
      58             :                                     bool bStoreNativeData);
      59             :     ~OGRGeoJSONReaderStreamingParser();
      60             : 
      61             :     void FinalizeLayerDefn();
      62             : 
      63             :     OGRFeature *GetNextFeature();
      64             : 
      65         123 :     inline bool GetOriginalIdModifiedEmitted() const
      66             :     {
      67         123 :         return m_bOriginalIdModifiedEmitted;
      68             :     }
      69             : 
      70         290 :     inline void SetOriginalIdModifiedEmitted(bool b)
      71             :     {
      72         290 :         m_bOriginalIdModifiedEmitted = b;
      73         290 :     }
      74             : };
      75             : 
      76             : /************************************************************************/
      77             : /*                        OGRGeoJSONBaseReader()                        */
      78             : /************************************************************************/
      79             : 
      80             : OGRGeoJSONBaseReader::OGRGeoJSONBaseReader() = default;
      81             : 
      82             : /************************************************************************/
      83             : /*                           SetPreserveGeometryType                    */
      84             : /************************************************************************/
      85             : 
      86           0 : void OGRGeoJSONBaseReader::SetPreserveGeometryType(bool bPreserve)
      87             : {
      88           0 :     bGeometryPreserve_ = bPreserve;
      89           0 : }
      90             : 
      91             : /************************************************************************/
      92             : /*                           SetSkipAttributes                          */
      93             : /************************************************************************/
      94             : 
      95           0 : void OGRGeoJSONBaseReader::SetSkipAttributes(bool bSkip)
      96             : {
      97           0 :     bAttributesSkip_ = bSkip;
      98           0 : }
      99             : 
     100             : /************************************************************************/
     101             : /*                         SetFlattenNestedAttributes                   */
     102             : /************************************************************************/
     103             : 
     104         434 : void OGRGeoJSONBaseReader::SetFlattenNestedAttributes(bool bFlatten,
     105             :                                                       char chSeparator)
     106             : {
     107         434 :     bFlattenNestedAttributes_ = bFlatten;
     108         434 :     chNestedAttributeSeparator_ = chSeparator;
     109         434 : }
     110             : 
     111             : /************************************************************************/
     112             : /*                           SetStoreNativeData                         */
     113             : /************************************************************************/
     114             : 
     115         434 : void OGRGeoJSONBaseReader::SetStoreNativeData(bool bStoreNativeData)
     116             : {
     117         434 :     bStoreNativeData_ = bStoreNativeData;
     118         434 : }
     119             : 
     120             : /************************************************************************/
     121             : /*                           SetArrayAsString                           */
     122             : /************************************************************************/
     123             : 
     124         434 : void OGRGeoJSONBaseReader::SetArrayAsString(bool bArrayAsString)
     125             : {
     126         434 :     bArrayAsString_ = bArrayAsString;
     127         434 : }
     128             : 
     129             : /************************************************************************/
     130             : /*                           SetDateAsString                           */
     131             : /************************************************************************/
     132             : 
     133         434 : void OGRGeoJSONBaseReader::SetDateAsString(bool bDateAsString)
     134             : {
     135         434 :     bDateAsString_ = bDateAsString;
     136         434 : }
     137             : 
     138             : /************************************************************************/
     139             : /*                           OGRGeoJSONReader                           */
     140             : /************************************************************************/
     141             : 
     142         434 : OGRGeoJSONReader::OGRGeoJSONReader()
     143             :     : poGJObject_(nullptr), poStreamingParser_(nullptr), bFirstSeg_(false),
     144             :       bJSonPLikeWrapper_(false), fp_(nullptr), bCanEasilyAppend_(false),
     145             :       bFCHasBBOX_(false), nBufferSize_(0), pabyBuffer_(nullptr),
     146         434 :       nTotalFeatureCount_(0), nTotalOGRFeatureMemEstimate_(0)
     147             : {
     148         434 : }
     149             : 
     150             : /************************************************************************/
     151             : /*                          ~OGRGeoJSONReader                           */
     152             : /************************************************************************/
     153             : 
     154         434 : OGRGeoJSONReader::~OGRGeoJSONReader()
     155             : {
     156         434 :     if (nullptr != poGJObject_)
     157             :     {
     158         431 :         json_object_put(poGJObject_);
     159             :     }
     160         434 :     if (fp_ != nullptr)
     161             :     {
     162         265 :         VSIFCloseL(fp_);
     163             :     }
     164         434 :     delete poStreamingParser_;
     165         434 :     CPLFree(pabyBuffer_);
     166             : 
     167         434 :     poGJObject_ = nullptr;
     168         434 : }
     169             : 
     170             : /************************************************************************/
     171             : /*                           Parse                                      */
     172             : /************************************************************************/
     173             : 
     174         166 : OGRErr OGRGeoJSONReader::Parse(const char *pszText)
     175             : {
     176         166 :     if (nullptr != pszText)
     177             :     {
     178             :         // Skip UTF-8 BOM (#5630).
     179         166 :         const GByte *pabyData = (const GByte *)pszText;
     180         166 :         if (pabyData[0] == 0xEF && pabyData[1] == 0xBB && pabyData[2] == 0xBF)
     181             :         {
     182           1 :             CPLDebug("GeoJSON", "Skip UTF-8 BOM");
     183           1 :             pszText += 3;
     184             :         }
     185             : 
     186         166 :         if (poGJObject_ != nullptr)
     187             :         {
     188           0 :             json_object_put(poGJObject_);
     189           0 :             poGJObject_ = nullptr;
     190             :         }
     191             : 
     192             :         // JSON tree is shared for while lifetime of the reader object
     193             :         // and will be released in the destructor.
     194         166 :         if (!OGRJSonParse(pszText, &poGJObject_))
     195           0 :             return OGRERR_CORRUPT_DATA;
     196             :     }
     197             : 
     198         166 :     return OGRERR_NONE;
     199             : }
     200             : 
     201             : /************************************************************************/
     202             : /*                           ReadLayers                                 */
     203             : /************************************************************************/
     204             : 
     205         166 : void OGRGeoJSONReader::ReadLayers(OGRGeoJSONDataSource *poDS)
     206             : {
     207         166 :     if (nullptr == poGJObject_)
     208             :     {
     209           0 :         CPLDebug("GeoJSON",
     210             :                  "Missing parsed GeoJSON data. Forgot to call Parse()?");
     211           0 :         return;
     212             :     }
     213             : 
     214         166 :     ReadLayer(poDS, nullptr, poGJObject_);
     215             : }
     216             : 
     217             : /************************************************************************/
     218             : /*           OGRGeoJSONReaderStreamingParserGetMaxObjectSize()          */
     219             : /************************************************************************/
     220             : 
     221         558 : static size_t OGRGeoJSONReaderStreamingParserGetMaxObjectSize()
     222             : {
     223             :     const double dfTmp =
     224         558 :         CPLAtof(CPLGetConfigOption("OGR_GEOJSON_MAX_OBJ_SIZE", "200"));
     225         558 :     return dfTmp > 0 ? static_cast<size_t>(dfTmp * 1024 * 1024) : 0;
     226             : }
     227             : 
     228             : /************************************************************************/
     229             : /*                     OGRGeoJSONReaderStreamingParser()                */
     230             : /************************************************************************/
     231             : 
     232         558 : OGRGeoJSONReaderStreamingParser::OGRGeoJSONReaderStreamingParser(
     233             :     OGRGeoJSONReader &oReader, OGRGeoJSONLayer *poLayer, bool bFirstPass,
     234         558 :     bool bStoreNativeData)
     235             :     : OGRJSONCollectionStreamingParser(
     236             :           bFirstPass, bStoreNativeData,
     237             :           OGRGeoJSONReaderStreamingParserGetMaxObjectSize()),
     238         558 :       m_oReader(oReader), m_poLayer(poLayer)
     239             : {
     240         558 : }
     241             : 
     242             : /************************************************************************/
     243             : /*                   ~OGRGeoJSONReaderStreamingParser()                 */
     244             : /************************************************************************/
     245             : 
     246         843 : OGRGeoJSONReaderStreamingParser::~OGRGeoJSONReaderStreamingParser()
     247             : {
     248         911 :     for (size_t i = 0; i < m_apoFeatures.size(); i++)
     249         353 :         delete m_apoFeatures[i];
     250         843 : }
     251             : 
     252             : /************************************************************************/
     253             : /*                          GetNextFeature()                            */
     254             : /************************************************************************/
     255             : 
     256        1821 : OGRFeature *OGRGeoJSONReaderStreamingParser::GetNextFeature()
     257             : {
     258        1821 :     if (m_nCurFeatureIdx < m_apoFeatures.size())
     259             :     {
     260        1092 :         OGRFeature *poFeat = m_apoFeatures[m_nCurFeatureIdx];
     261        1092 :         m_apoFeatures[m_nCurFeatureIdx] = nullptr;
     262        1092 :         m_nCurFeatureIdx++;
     263        1092 :         return poFeat;
     264             :     }
     265         729 :     m_nCurFeatureIdx = 0;
     266         729 :     m_apoFeatures.clear();
     267         729 :     return nullptr;
     268             : }
     269             : 
     270             : /************************************************************************/
     271             : /*                          GotFeature()                                */
     272             : /************************************************************************/
     273             : 
     274        5687 : void OGRGeoJSONReaderStreamingParser::GotFeature(json_object *poObj,
     275             :                                                  bool bFirstPass,
     276             :                                                  const std::string &osJson)
     277             : {
     278        5687 :     if (bFirstPass)
     279             :     {
     280        4412 :         if (!m_oReader.GenerateFeatureDefn(m_oMapFieldNameToIdx, m_apoFieldDefn,
     281        4412 :                                            m_dag, m_poLayer, poObj))
     282             :         {
     283             :         }
     284        4412 :         m_poLayer->IncFeatureCount();
     285             :     }
     286             :     else
     287             :     {
     288             :         OGRFeature *poFeat =
     289        1275 :             m_oReader.ReadFeature(m_poLayer, poObj, osJson.c_str());
     290        1275 :         if (poFeat)
     291             :         {
     292        1275 :             GIntBig nFID = poFeat->GetFID();
     293        1275 :             if (nFID == OGRNullFID)
     294             :             {
     295        1101 :                 nFID = static_cast<GIntBig>(m_oSetUsedFIDs.size());
     296        1101 :                 while (cpl::contains(m_oSetUsedFIDs, nFID))
     297             :                 {
     298           0 :                     ++nFID;
     299             :                 }
     300             :             }
     301         174 :             else if (cpl::contains(m_oSetUsedFIDs, nFID))
     302             :             {
     303          33 :                 if (!m_bOriginalIdModifiedEmitted)
     304             :                 {
     305           2 :                     CPLError(CE_Warning, CPLE_AppDefined,
     306             :                              "Several features with id = " CPL_FRMT_GIB " have "
     307             :                              "been found. Altering it to be unique. "
     308             :                              "This warning will not be emitted anymore for "
     309             :                              "this layer",
     310             :                              nFID);
     311           2 :                     m_bOriginalIdModifiedEmitted = true;
     312             :                 }
     313          33 :                 nFID = static_cast<GIntBig>(m_oSetUsedFIDs.size());
     314          33 :                 while (cpl::contains(m_oSetUsedFIDs, nFID))
     315             :                 {
     316           0 :                     ++nFID;
     317             :                 }
     318             :             }
     319        1275 :             m_oSetUsedFIDs.insert(nFID);
     320        1275 :             poFeat->SetFID(nFID);
     321             : 
     322        1275 :             m_apoFeatures.push_back(poFeat);
     323             :         }
     324             :     }
     325        5687 : }
     326             : 
     327             : /************************************************************************/
     328             : /*                         FinalizeLayerDefn()                          */
     329             : /************************************************************************/
     330             : 
     331         265 : void OGRGeoJSONReaderStreamingParser::FinalizeLayerDefn()
     332             : {
     333         265 :     OGRFeatureDefn *poDefn = m_poLayer->GetLayerDefn();
     334         530 :     auto oTemporaryUnsealer(poDefn->GetTemporaryUnsealer());
     335         530 :     const auto sortedFields = m_dag.getTopologicalOrdering();
     336         265 :     CPLAssert(sortedFields.size() == m_apoFieldDefn.size());
     337         961 :     for (int idx : sortedFields)
     338             :     {
     339         696 :         poDefn->AddFieldDefn(m_apoFieldDefn[idx].get());
     340             :     }
     341         265 :     m_dag = gdal::DirectedAcyclicGraph<int, std::string>();
     342         265 :     m_oMapFieldNameToIdx.clear();
     343         265 :     m_apoFieldDefn.clear();
     344         265 : }
     345             : 
     346             : /************************************************************************/
     347             : /*                            TooComplex()                              */
     348             : /************************************************************************/
     349             : 
     350           1 : void OGRGeoJSONReaderStreamingParser::TooComplex()
     351             : {
     352           1 :     if (!ExceptionOccurred())
     353           1 :         EmitException("GeoJSON object too complex/large. You may define the "
     354             :                       "OGR_GEOJSON_MAX_OBJ_SIZE configuration option to "
     355             :                       "a value in megabytes to allow "
     356             :                       "for larger features, or 0 to remove any size limit.");
     357           1 : }
     358             : 
     359             : /************************************************************************/
     360             : /*                       SetCoordinatePrecision()                       */
     361             : /************************************************************************/
     362             : 
     363         357 : static void SetCoordinatePrecision(json_object *poRootObj,
     364             :                                    OGRGeoJSONLayer *poLayer)
     365             : {
     366         357 :     if (poLayer->GetLayerDefn()->GetGeomType() != wkbNone)
     367             :     {
     368         714 :         OGRGeoJSONWriteOptions options;
     369             : 
     370             :         json_object *poXYRes =
     371         357 :             CPL_json_object_object_get(poRootObj, "xy_coordinate_resolution");
     372         357 :         if (poXYRes && (json_object_get_type(poXYRes) == json_type_double ||
     373           0 :                         json_object_get_type(poXYRes) == json_type_int))
     374             :         {
     375           8 :             auto poGeomFieldDefn = poLayer->GetLayerDefn()->GetGeomFieldDefn(0);
     376             :             OGRGeomCoordinatePrecision oCoordPrec(
     377           8 :                 poGeomFieldDefn->GetCoordinatePrecision());
     378           8 :             oCoordPrec.dfXYResolution = json_object_get_double(poXYRes);
     379           8 :             whileUnsealing(poGeomFieldDefn)->SetCoordinatePrecision(oCoordPrec);
     380             : 
     381           8 :             options.nXYCoordPrecision =
     382           8 :                 OGRGeomCoordinatePrecision::ResolutionToPrecision(
     383             :                     oCoordPrec.dfXYResolution);
     384             :         }
     385             : 
     386             :         json_object *poZRes =
     387         357 :             CPL_json_object_object_get(poRootObj, "z_coordinate_resolution");
     388         357 :         if (poZRes && (json_object_get_type(poZRes) == json_type_double ||
     389           0 :                        json_object_get_type(poZRes) == json_type_int))
     390             :         {
     391           6 :             auto poGeomFieldDefn = poLayer->GetLayerDefn()->GetGeomFieldDefn(0);
     392             :             OGRGeomCoordinatePrecision oCoordPrec(
     393           6 :                 poGeomFieldDefn->GetCoordinatePrecision());
     394           6 :             oCoordPrec.dfZResolution = json_object_get_double(poZRes);
     395           6 :             whileUnsealing(poGeomFieldDefn)->SetCoordinatePrecision(oCoordPrec);
     396             : 
     397           6 :             options.nZCoordPrecision =
     398           6 :                 OGRGeomCoordinatePrecision::ResolutionToPrecision(
     399             :                     oCoordPrec.dfZResolution);
     400             :         }
     401             : 
     402         357 :         poLayer->SetWriteOptions(options);
     403             :     }
     404         357 : }
     405             : 
     406             : /************************************************************************/
     407             : /*                       FirstPassReadLayer()                           */
     408             : /************************************************************************/
     409             : 
     410         268 : bool OGRGeoJSONReader::FirstPassReadLayer(OGRGeoJSONDataSource *poDS,
     411             :                                           VSILFILE *fp,
     412             :                                           bool &bTryStandardReading)
     413             : {
     414         268 :     bTryStandardReading = false;
     415         268 :     VSIFSeekL(fp, 0, SEEK_SET);
     416         268 :     bFirstSeg_ = true;
     417             : 
     418         268 :     const char *pszName = poDS->GetDescription();
     419         268 :     if (STARTS_WITH_CI(pszName, "GeoJSON:"))
     420           0 :         pszName += strlen("GeoJSON:");
     421         268 :     pszName = CPLGetBasename(pszName);
     422             : 
     423             :     OGRGeoJSONLayer *poLayer = new OGRGeoJSONLayer(
     424         268 :         pszName, nullptr, OGRGeoJSONLayer::DefaultGeometryType, poDS, this);
     425             :     OGRGeoJSONReaderStreamingParser oParser(*this, poLayer, true,
     426         536 :                                             bStoreNativeData_);
     427             : 
     428         268 :     vsi_l_offset nFileSize = 0;
     429         343 :     if (STARTS_WITH(poDS->GetDescription(), "/vsimem/") ||
     430          75 :         !STARTS_WITH(poDS->GetDescription(), "/vsi"))
     431             :     {
     432             :         VSIStatBufL sStatBuf;
     433         262 :         if (VSIStatL(poDS->GetDescription(), &sStatBuf) == 0)
     434             :         {
     435         262 :             nFileSize = sStatBuf.st_size;
     436             :         }
     437             :     }
     438             : 
     439         268 :     nBufferSize_ = 4096 * 10;
     440         268 :     pabyBuffer_ = static_cast<GByte *>(CPLMalloc(nBufferSize_));
     441         268 :     int nIter = 0;
     442         268 :     bool bThresholdReached = false;
     443         268 :     const GIntBig nMaxBytesFirstPass = CPLAtoGIntBig(
     444             :         CPLGetConfigOption("OGR_GEOJSON_MAX_BYTES_FIRST_PASS", "0"));
     445         268 :     const GIntBig nLimitFeaturesFirstPass = CPLAtoGIntBig(
     446             :         CPLGetConfigOption("OGR_GEOJSON_MAX_FEATURES_FIRST_PASS", "0"));
     447             :     while (true)
     448             :     {
     449         413 :         nIter++;
     450             : 
     451         413 :         if (nMaxBytesFirstPass > 0 &&
     452           0 :             static_cast<GIntBig>(nIter) * static_cast<GIntBig>(nBufferSize_) >=
     453             :                 nMaxBytesFirstPass)
     454             :         {
     455           0 :             CPLDebug("GeoJSON", "First pass: early exit since above "
     456             :                                 "OGR_GEOJSON_MAX_BYTES_FIRST_PASS");
     457           0 :             bThresholdReached = true;
     458           0 :             break;
     459             :         }
     460             : 
     461         413 :         size_t nRead = VSIFReadL(pabyBuffer_, 1, nBufferSize_, fp);
     462         413 :         const bool bFinished = nRead < nBufferSize_;
     463         413 :         size_t nSkip = 0;
     464         413 :         if (bFirstSeg_)
     465             :         {
     466         268 :             bFirstSeg_ = false;
     467         268 :             nSkip = SkipPrologEpilogAndUpdateJSonPLikeWrapper(nRead);
     468             :         }
     469         413 :         if (bFinished && bJSonPLikeWrapper_ && nRead > nSkip)
     470           1 :             nRead--;
     471         413 :         if (!oParser.Parse(reinterpret_cast<const char *>(pabyBuffer_ + nSkip),
     472         824 :                            nRead - nSkip, bFinished) ||
     473         411 :             oParser.ExceptionOccurred())
     474             :         {
     475             :             // to avoid killing ourselves during layer deletion
     476           2 :             poLayer->UnsetReader();
     477           2 :             delete poLayer;
     478           2 :             return false;
     479             :         }
     480         411 :         if (bFinished || (nIter % 100) == 0)
     481             :         {
     482         266 :             if (nFileSize == 0)
     483             :             {
     484           6 :                 if (bFinished)
     485             :                 {
     486           6 :                     CPLDebug("GeoJSON", "First pass: 100.00 %%");
     487             :                 }
     488             :                 else
     489             :                 {
     490           0 :                     CPLDebug("GeoJSON",
     491             :                              "First pass: " CPL_FRMT_GUIB " bytes read",
     492           0 :                              static_cast<GUIntBig>(nIter) *
     493           0 :                                      static_cast<GUIntBig>(nBufferSize_) +
     494             :                                  nRead);
     495             :                 }
     496             :             }
     497             :             else
     498             :             {
     499         260 :                 CPLDebug("GeoJSON", "First pass: %.2f %%",
     500         260 :                          100.0 * VSIFTellL(fp) / nFileSize);
     501             :             }
     502             :         }
     503         411 :         if (nLimitFeaturesFirstPass > 0 &&
     504           0 :             poLayer->GetFeatureCount(FALSE) >= nLimitFeaturesFirstPass)
     505             :         {
     506           0 :             CPLDebug("GeoJSON", "First pass: early exit since above "
     507             :                                 "OGR_GEOJSON_MAX_FEATURES_FIRST_PASS");
     508           0 :             bThresholdReached = true;
     509           0 :             break;
     510             :         }
     511         411 :         if (oParser.IsTypeKnown() && !oParser.IsFeatureCollection())
     512           0 :             break;
     513         411 :         if (bFinished)
     514         266 :             break;
     515         145 :     }
     516             : 
     517         266 :     if (bThresholdReached)
     518             :     {
     519           0 :         poLayer->InvalidateFeatureCount();
     520             :     }
     521         266 :     else if (!oParser.IsTypeKnown() || !oParser.IsFeatureCollection())
     522             :     {
     523             :         // to avoid killing ourselves during layer deletion
     524           1 :         poLayer->UnsetReader();
     525           1 :         delete poLayer;
     526             :         const vsi_l_offset nRAM =
     527           1 :             static_cast<vsi_l_offset>(CPLGetUsablePhysicalRAM());
     528           1 :         if (nFileSize == 0 || nRAM == 0 || nRAM > nFileSize * 20)
     529             :         {
     530             :             // Only try full ingestion if we have 20x more RAM than the file
     531             :             // size
     532           1 :             bTryStandardReading = true;
     533             :         }
     534           1 :         return false;
     535             :     }
     536             : 
     537         265 :     oParser.FinalizeLayerDefn();
     538             : 
     539         265 :     CPLString osFIDColumn;
     540         265 :     FinalizeLayerDefn(poLayer, osFIDColumn);
     541         265 :     if (!osFIDColumn.empty())
     542          26 :         poLayer->SetFIDColumn(osFIDColumn);
     543             : 
     544         265 :     bCanEasilyAppend_ = oParser.CanEasilyAppend();
     545         265 :     nTotalFeatureCount_ = poLayer->GetFeatureCount(FALSE);
     546         265 :     nTotalOGRFeatureMemEstimate_ = oParser.GetTotalOGRFeatureMemEstimate();
     547             : 
     548         265 :     json_object *poRootObj = oParser.StealRootObject();
     549         265 :     if (poRootObj)
     550             :     {
     551         265 :         bFCHasBBOX_ = CPL_json_object_object_get(poRootObj, "bbox") != nullptr;
     552             : 
     553             :         // CPLDebug("GeoJSON", "%s", json_object_get_string(poRootObj));
     554             : 
     555         265 :         json_object *poName = CPL_json_object_object_get(poRootObj, "name");
     556         265 :         if (poName && json_object_get_type(poName) == json_type_string)
     557             :         {
     558         116 :             const char *pszValue = json_object_get_string(poName);
     559         116 :             whileUnsealing(poLayer->GetLayerDefn())->SetName(pszValue);
     560         116 :             poLayer->SetDescription(pszValue);
     561             :         }
     562             : 
     563             :         json_object *poDescription =
     564         265 :             CPL_json_object_object_get(poRootObj, "description");
     565         266 :         if (poDescription &&
     566           1 :             json_object_get_type(poDescription) == json_type_string)
     567             :         {
     568           1 :             const char *pszValue = json_object_get_string(poDescription);
     569           1 :             poLayer->SetMetadataItem("DESCRIPTION", pszValue);
     570             :         }
     571             : 
     572         265 :         OGRSpatialReference *poSRS = OGRGeoJSONReadSpatialReference(poRootObj);
     573         265 :         const auto eGeomType = poLayer->GetLayerDefn()->GetGeomType();
     574         265 :         if (eGeomType != wkbNone && poSRS == nullptr)
     575             :         {
     576             :             // If there is none defined, we use 4326 / 4979.
     577         230 :             poSRS = new OGRSpatialReference();
     578         230 :             if (OGR_GT_HasZ(eGeomType))
     579          17 :                 poSRS->importFromEPSG(4979);
     580             :             else
     581         213 :                 poSRS->SetFromUserInput(SRS_WKT_WGS84_LAT_LONG);
     582         230 :             poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     583             :         }
     584         265 :         CPLErrorReset();
     585             : 
     586         265 :         if (eGeomType != wkbNone && poSRS != nullptr)
     587             :         {
     588         265 :             auto poGeomFieldDefn = poLayer->GetLayerDefn()->GetGeomFieldDefn(0);
     589         265 :             whileUnsealing(poGeomFieldDefn)->SetSpatialRef(poSRS);
     590             :         }
     591         265 :         if (poSRS)
     592         265 :             poSRS->Release();
     593             : 
     594         265 :         SetCoordinatePrecision(poRootObj, poLayer);
     595             : 
     596         265 :         if (bStoreNativeData_)
     597             :         {
     598          58 :             CPLString osNativeData("NATIVE_DATA=");
     599          29 :             osNativeData += json_object_get_string(poRootObj);
     600             : 
     601          29 :             char *apszMetadata[3] = {
     602          29 :                 const_cast<char *>(osNativeData.c_str()),
     603             :                 const_cast<char *>(
     604             :                     "NATIVE_MEDIA_TYPE=application/vnd.geo+json"),
     605          29 :                 nullptr};
     606             : 
     607          29 :             poLayer->SetMetadata(apszMetadata, "NATIVE_DATA");
     608             :         }
     609             : 
     610         265 :         poGJObject_ = poRootObj;
     611             :     }
     612             : 
     613         265 :     fp_ = fp;
     614         265 :     poDS->AddLayer(poLayer);
     615         265 :     return true;
     616             : }
     617             : 
     618             : /************************************************************************/
     619             : /*               SkipPrologEpilogAndUpdateJSonPLikeWrapper()            */
     620             : /************************************************************************/
     621             : 
     622         558 : size_t OGRGeoJSONReader::SkipPrologEpilogAndUpdateJSonPLikeWrapper(size_t nRead)
     623             : {
     624         558 :     size_t nSkip = 0;
     625         558 :     if (nRead >= 3 && pabyBuffer_[0] == 0xEF && pabyBuffer_[1] == 0xBB &&
     626           0 :         pabyBuffer_[2] == 0xBF)
     627             :     {
     628           0 :         CPLDebug("GeoJSON", "Skip UTF-8 BOM");
     629           0 :         nSkip += 3;
     630             :     }
     631             : 
     632         558 :     const char *const apszPrefix[] = {"loadGeoJSON(", "jsonp("};
     633        1672 :     for (size_t i = 0; i < CPL_ARRAYSIZE(apszPrefix); i++)
     634             :     {
     635        1115 :         if (nRead >= nSkip + strlen(apszPrefix[i]) &&
     636        1115 :             memcmp(pabyBuffer_ + nSkip, apszPrefix[i], strlen(apszPrefix[i])) ==
     637             :                 0)
     638             :         {
     639           1 :             nSkip += strlen(apszPrefix[i]);
     640           1 :             bJSonPLikeWrapper_ = true;
     641           1 :             break;
     642             :         }
     643             :     }
     644             : 
     645         558 :     return nSkip;
     646             : }
     647             : 
     648             : /************************************************************************/
     649             : /*                            ResetReading()                            */
     650             : /************************************************************************/
     651             : 
     652         538 : void OGRGeoJSONReader::ResetReading()
     653             : {
     654         538 :     CPLAssert(fp_);
     655         538 :     if (poStreamingParser_)
     656         114 :         bOriginalIdModifiedEmitted_ =
     657         114 :             poStreamingParser_->GetOriginalIdModifiedEmitted();
     658         538 :     delete poStreamingParser_;
     659         538 :     poStreamingParser_ = nullptr;
     660         538 : }
     661             : 
     662             : /************************************************************************/
     663             : /*                           GetNextFeature()                           */
     664             : /************************************************************************/
     665             : 
     666        1261 : OGRFeature *OGRGeoJSONReader::GetNextFeature(OGRGeoJSONLayer *poLayer)
     667             : {
     668        1261 :     CPLAssert(fp_);
     669        1261 :     if (poStreamingParser_ == nullptr)
     670             :     {
     671         285 :         poStreamingParser_ = new OGRGeoJSONReaderStreamingParser(
     672         285 :             *this, poLayer, false, bStoreNativeData_);
     673         285 :         poStreamingParser_->SetOriginalIdModifiedEmitted(
     674         285 :             bOriginalIdModifiedEmitted_);
     675         285 :         VSIFSeekL(fp_, 0, SEEK_SET);
     676         285 :         bFirstSeg_ = true;
     677         285 :         bJSonPLikeWrapper_ = false;
     678             :     }
     679             : 
     680        1261 :     OGRFeature *poFeat = poStreamingParser_->GetNextFeature();
     681        1261 :     if (poFeat)
     682         719 :         return poFeat;
     683             : 
     684             :     while (true)
     685             :     {
     686         542 :         size_t nRead = VSIFReadL(pabyBuffer_, 1, nBufferSize_, fp_);
     687         542 :         const bool bFinished = nRead < nBufferSize_;
     688         542 :         size_t nSkip = 0;
     689         542 :         if (bFirstSeg_)
     690             :         {
     691         285 :             bFirstSeg_ = false;
     692         285 :             nSkip = SkipPrologEpilogAndUpdateJSonPLikeWrapper(nRead);
     693             :         }
     694         542 :         if (bFinished && bJSonPLikeWrapper_ && nRead > nSkip)
     695           0 :             nRead--;
     696        1626 :         if (!poStreamingParser_->Parse(
     697         542 :                 reinterpret_cast<const char *>(pabyBuffer_ + nSkip),
     698        1084 :                 nRead - nSkip, bFinished) ||
     699         542 :             poStreamingParser_->ExceptionOccurred())
     700             :         {
     701           0 :             break;
     702             :         }
     703             : 
     704         542 :         poFeat = poStreamingParser_->GetNextFeature();
     705         542 :         if (poFeat)
     706         355 :             return poFeat;
     707             : 
     708         187 :         if (bFinished)
     709         187 :             break;
     710           0 :     }
     711             : 
     712         187 :     return nullptr;
     713             : }
     714             : 
     715             : /************************************************************************/
     716             : /*                             GetFeature()                             */
     717             : /************************************************************************/
     718             : 
     719          22 : OGRFeature *OGRGeoJSONReader::GetFeature(OGRGeoJSONLayer *poLayer, GIntBig nFID)
     720             : {
     721          22 :     CPLAssert(fp_);
     722             : 
     723          22 :     if (oMapFIDToOffsetSize_.empty())
     724             :     {
     725           5 :         CPLDebug("GeoJSON",
     726             :                  "Establishing index to features for first GetFeature() call");
     727             : 
     728           5 :         if (poStreamingParser_)
     729           4 :             bOriginalIdModifiedEmitted_ =
     730           4 :                 poStreamingParser_->GetOriginalIdModifiedEmitted();
     731           5 :         delete poStreamingParser_;
     732           5 :         poStreamingParser_ = nullptr;
     733             : 
     734             :         OGRGeoJSONReaderStreamingParser oParser(*this, poLayer, false,
     735           5 :                                                 bStoreNativeData_);
     736           5 :         oParser.SetOriginalIdModifiedEmitted(bOriginalIdModifiedEmitted_);
     737           5 :         VSIFSeekL(fp_, 0, SEEK_SET);
     738           5 :         bFirstSeg_ = true;
     739           5 :         bJSonPLikeWrapper_ = false;
     740           5 :         vsi_l_offset nCurOffset = 0;
     741           5 :         vsi_l_offset nFeatureOffset = 0;
     742             :         while (true)
     743             :         {
     744           5 :             size_t nRead = VSIFReadL(pabyBuffer_, 1, nBufferSize_, fp_);
     745           5 :             const bool bFinished = nRead < nBufferSize_;
     746           5 :             size_t nSkip = 0;
     747           5 :             if (bFirstSeg_)
     748             :             {
     749           5 :                 bFirstSeg_ = false;
     750           5 :                 nSkip = SkipPrologEpilogAndUpdateJSonPLikeWrapper(nRead);
     751             :             }
     752           5 :             if (bFinished && bJSonPLikeWrapper_ && nRead > nSkip)
     753           0 :                 nRead--;
     754           5 :             auto pszPtr = reinterpret_cast<const char *>(pabyBuffer_ + nSkip);
     755        1673 :             for (size_t i = 0; i < nRead - nSkip; i++)
     756             :             {
     757        1668 :                 oParser.ResetFeatureDetectionState();
     758        1668 :                 if (!oParser.Parse(pszPtr + i, 1,
     759        5004 :                                    bFinished && (i + 1 == nRead - nSkip)) ||
     760        1668 :                     oParser.ExceptionOccurred())
     761             :                 {
     762           0 :                     return nullptr;
     763             :                 }
     764        1668 :                 if (oParser.IsStartFeature())
     765             :                 {
     766          18 :                     nFeatureOffset = nCurOffset + i;
     767             :                 }
     768        1650 :                 else if (oParser.IsEndFeature())
     769             :                 {
     770          18 :                     vsi_l_offset nFeatureSize =
     771          18 :                         (nCurOffset + i) - nFeatureOffset + 1;
     772          18 :                     auto poFeat = oParser.GetNextFeature();
     773          18 :                     if (poFeat)
     774             :                     {
     775          18 :                         const GIntBig nThisFID = poFeat->GetFID();
     776          18 :                         if (!cpl::contains(oMapFIDToOffsetSize_, nThisFID))
     777             :                         {
     778          18 :                             oMapFIDToOffsetSize_[nThisFID] =
     779          36 :                                 std::pair<vsi_l_offset, vsi_l_offset>(
     780          18 :                                     nFeatureOffset, nFeatureSize);
     781             :                         }
     782          18 :                         delete poFeat;
     783             :                     }
     784             :                 }
     785             :             }
     786             : 
     787           5 :             if (bFinished)
     788           5 :                 break;
     789           0 :             nCurOffset += nRead;
     790           0 :         }
     791             : 
     792           5 :         bOriginalIdModifiedEmitted_ = oParser.GetOriginalIdModifiedEmitted();
     793             :     }
     794             : 
     795          22 :     const auto oIter = oMapFIDToOffsetSize_.find(nFID);
     796          22 :     if (oIter == oMapFIDToOffsetSize_.end())
     797             :     {
     798           5 :         return nullptr;
     799             :     }
     800             : 
     801          17 :     VSIFSeekL(fp_, oIter->second.first, SEEK_SET);
     802          17 :     if (oIter->second.second > 1000 * 1000 * 1000)
     803             :     {
     804           0 :         return nullptr;
     805             :     }
     806          17 :     size_t nSize = static_cast<size_t>(oIter->second.second);
     807          17 :     char *pszBuffer = static_cast<char *>(VSIMalloc(nSize + 1));
     808          17 :     if (!pszBuffer)
     809             :     {
     810           0 :         return nullptr;
     811             :     }
     812          17 :     if (VSIFReadL(pszBuffer, 1, nSize, fp_) != nSize)
     813             :     {
     814           0 :         VSIFree(pszBuffer);
     815           0 :         return nullptr;
     816             :     }
     817          17 :     pszBuffer[nSize] = 0;
     818          17 :     json_object *poObj = nullptr;
     819          17 :     if (!OGRJSonParse(pszBuffer, &poObj))
     820             :     {
     821           0 :         VSIFree(pszBuffer);
     822           0 :         return nullptr;
     823             :     }
     824             : 
     825          17 :     OGRFeature *poFeat = ReadFeature(poLayer, poObj, pszBuffer);
     826          17 :     json_object_put(poObj);
     827          17 :     VSIFree(pszBuffer);
     828          17 :     if (!poFeat)
     829             :     {
     830           0 :         return nullptr;
     831             :     }
     832          17 :     poFeat->SetFID(nFID);
     833          17 :     return poFeat;
     834             : }
     835             : 
     836             : /************************************************************************/
     837             : /*                           IngestAll()                                */
     838             : /************************************************************************/
     839             : 
     840          14 : bool OGRGeoJSONReader::IngestAll(OGRGeoJSONLayer *poLayer)
     841             : {
     842             :     const vsi_l_offset nRAM =
     843          14 :         static_cast<vsi_l_offset>(CPLGetUsablePhysicalRAM()) / 3 * 4;
     844          14 :     if (nRAM && nTotalOGRFeatureMemEstimate_ > nRAM)
     845             :     {
     846           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     847             :                  "Not enough memory to ingest all the layer: " CPL_FRMT_GUIB
     848             :                  " available, " CPL_FRMT_GUIB " needed",
     849             :                  nRAM, nTotalOGRFeatureMemEstimate_);
     850           0 :         return false;
     851             :     }
     852             : 
     853          14 :     CPLDebug("GeoJSON",
     854             :              "Total memory estimated for ingestion: " CPL_FRMT_GUIB " bytes",
     855             :              nTotalOGRFeatureMemEstimate_);
     856             : 
     857          14 :     ResetReading();
     858          14 :     GIntBig nCounter = 0;
     859             :     while (true)
     860             :     {
     861          42 :         OGRFeature *poFeature = GetNextFeature(poLayer);
     862          42 :         if (poFeature == nullptr)
     863          14 :             break;
     864          28 :         poLayer->AddFeature(poFeature);
     865          28 :         delete poFeature;
     866          28 :         nCounter++;
     867          28 :         if (((nCounter % 10000) == 0 || nCounter == nTotalFeatureCount_) &&
     868          12 :             nTotalFeatureCount_ > 0)
     869             :         {
     870          12 :             CPLDebug("GeoJSON", "Ingestion at %.02f %%",
     871          12 :                      100.0 * nCounter / nTotalFeatureCount_);
     872             :         }
     873          28 :     }
     874          14 :     return true;
     875             : }
     876             : 
     877             : /************************************************************************/
     878             : /*                           ReadLayer                                  */
     879             : /************************************************************************/
     880             : 
     881         170 : void OGRGeoJSONReader::ReadLayer(OGRGeoJSONDataSource *poDS,
     882             :                                  const char *pszName, json_object *poObj)
     883             : {
     884         170 :     GeoJSONObject::Type objType = OGRGeoJSONGetType(poObj);
     885         170 :     if (objType == GeoJSONObject::eUnknown)
     886             :     {
     887             :         // Check if the object contains key:value pairs where value
     888             :         // is a standard GeoJSON object. In which case, use key as the layer
     889             :         // name.
     890           2 :         if (json_type_object == json_object_get_type(poObj))
     891             :         {
     892             :             json_object_iter it;
     893           2 :             it.key = nullptr;
     894           2 :             it.val = nullptr;
     895           2 :             it.entry = nullptr;
     896           6 :             json_object_object_foreachC(poObj, it)
     897             :             {
     898           4 :                 objType = OGRGeoJSONGetType(it.val);
     899           4 :                 if (objType != GeoJSONObject::eUnknown)
     900           4 :                     ReadLayer(poDS, it.key, it.val);
     901             :             }
     902             :         }
     903             : 
     904             :         // CPLError(CE_Failure, CPLE_AppDefined,
     905             :         //          "Unrecognized GeoJSON structure.");
     906             : 
     907           2 :         return;
     908             :     }
     909             : 
     910         168 :     CPLErrorReset();
     911             : 
     912             :     // Figure out layer name
     913         168 :     if (pszName == nullptr)
     914             :     {
     915         164 :         if (GeoJSONObject::eFeatureCollection == objType)
     916             :         {
     917          91 :             json_object *poName = CPL_json_object_object_get(poObj, "name");
     918          94 :             if (poName != nullptr &&
     919           3 :                 json_object_get_type(poName) == json_type_string)
     920             :             {
     921           3 :                 pszName = json_object_get_string(poName);
     922             :             }
     923             :         }
     924         164 :         if (pszName == nullptr)
     925             :         {
     926         161 :             const char *pszDesc = poDS->GetDescription();
     927         161 :             if (strchr(pszDesc, '?') == nullptr &&
     928         161 :                 strchr(pszDesc, '{') == nullptr)
     929             :             {
     930          30 :                 pszName = CPLGetBasename(pszDesc);
     931             :             }
     932             :         }
     933         164 :         if (pszName == nullptr)
     934         131 :             pszName = OGRGeoJSONLayer::DefaultName;
     935             :     }
     936             : 
     937             :     OGRGeoJSONLayer *poLayer = new OGRGeoJSONLayer(
     938         168 :         pszName, nullptr, OGRGeoJSONLayer::DefaultGeometryType, poDS, nullptr);
     939             : 
     940         168 :     OGRSpatialReference *poSRS = OGRGeoJSONReadSpatialReference(poObj);
     941         168 :     bool bDefaultSRS = false;
     942         168 :     if (poSRS == nullptr)
     943             :     {
     944             :         // If there is none defined, we use 4326 / 4979.
     945         161 :         poSRS = new OGRSpatialReference();
     946         161 :         bDefaultSRS = true;
     947             :     }
     948             :     {
     949         168 :         auto poGeomFieldDefn = poLayer->GetLayerDefn()->GetGeomFieldDefn(0);
     950         168 :         whileUnsealing(poGeomFieldDefn)->SetSpatialRef(poSRS);
     951             :     }
     952             : 
     953         168 :     if (!GenerateLayerDefn(poLayer, poObj))
     954             :     {
     955           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     956             :                  "Layer schema generation failed.");
     957             : 
     958           1 :         delete poLayer;
     959           1 :         poSRS->Release();
     960           1 :         return;
     961             :     }
     962             : 
     963         167 :     if (GeoJSONObject::eFeatureCollection == objType)
     964             :     {
     965             :         json_object *poDescription =
     966          92 :             CPL_json_object_object_get(poObj, "description");
     967          93 :         if (poDescription != nullptr &&
     968           1 :             json_object_get_type(poDescription) == json_type_string)
     969             :         {
     970           1 :             poLayer->SetMetadataItem("DESCRIPTION",
     971           1 :                                      json_object_get_string(poDescription));
     972             :         }
     973             : 
     974          92 :         SetCoordinatePrecision(poObj, poLayer);
     975             :     }
     976             : 
     977             :     /* -------------------------------------------------------------------- */
     978             :     /*      Translate single geometry-only Feature object.                  */
     979             :     /* -------------------------------------------------------------------- */
     980             : 
     981         167 :     if (GeoJSONObject::ePoint == objType ||
     982         121 :         GeoJSONObject::eMultiPoint == objType ||
     983         119 :         GeoJSONObject::eLineString == objType ||
     984         118 :         GeoJSONObject::eMultiLineString == objType ||
     985         116 :         GeoJSONObject::ePolygon == objType ||
     986         111 :         GeoJSONObject::eMultiPolygon == objType ||
     987             :         GeoJSONObject::eGeometryCollection == objType)
     988             :     {
     989          58 :         OGRGeometry *poGeometry = ReadGeometry(poObj, poLayer->GetSpatialRef());
     990          58 :         if (!AddFeature(poLayer, poGeometry))
     991             :         {
     992           1 :             CPLDebug("GeoJSON", "Translation of single geometry failed.");
     993           1 :             delete poLayer;
     994           1 :             poSRS->Release();
     995           1 :             return;
     996          57 :         }
     997             :     }
     998             :     /* -------------------------------------------------------------------- */
     999             :     /*      Translate single but complete Feature object.                   */
    1000             :     /* -------------------------------------------------------------------- */
    1001         109 :     else if (GeoJSONObject::eFeature == objType)
    1002             :     {
    1003          17 :         OGRFeature *poFeature = ReadFeature(poLayer, poObj, nullptr);
    1004          17 :         AddFeature(poLayer, poFeature);
    1005             :     }
    1006             :     /* -------------------------------------------------------------------- */
    1007             :     /*      Translate multi-feature FeatureCollection object.               */
    1008             :     /* -------------------------------------------------------------------- */
    1009          92 :     else if (GeoJSONObject::eFeatureCollection == objType)
    1010             :     {
    1011          92 :         ReadFeatureCollection(poLayer, poObj);
    1012             :     }
    1013             : 
    1014         166 :     if (CPLGetLastErrorType() != CE_Warning)
    1015         163 :         CPLErrorReset();
    1016             : 
    1017         166 :     poLayer->DetectGeometryType();
    1018             : 
    1019         166 :     if (bDefaultSRS && poLayer->GetGeomType() != wkbNone)
    1020             :     {
    1021         159 :         if (OGR_GT_HasZ(poLayer->GetGeomType()))
    1022          46 :             poSRS->importFromEPSG(4979);
    1023             :         else
    1024         113 :             poSRS->SetFromUserInput(SRS_WKT_WGS84_LAT_LONG);
    1025         159 :         poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    1026             :     }
    1027         166 :     poSRS->Release();
    1028             : 
    1029         166 :     poDS->AddLayer(poLayer);
    1030             : }
    1031             : 
    1032             : /************************************************************************/
    1033             : /*                         GenerateLayerDefn()                          */
    1034             : /************************************************************************/
    1035             : 
    1036         168 : bool OGRGeoJSONReader::GenerateLayerDefn(OGRGeoJSONLayer *poLayer,
    1037             :                                          json_object *poGJObject)
    1038             : {
    1039         168 :     CPLAssert(nullptr != poGJObject);
    1040         168 :     CPLAssert(nullptr != poLayer->GetLayerDefn());
    1041         168 :     CPLAssert(0 == poLayer->GetLayerDefn()->GetFieldCount());
    1042             : 
    1043         168 :     if (bAttributesSkip_)
    1044           0 :         return true;
    1045             : 
    1046             :     /* -------------------------------------------------------------------- */
    1047             :     /*      Scan all features and generate layer definition.                */
    1048             :     /* -------------------------------------------------------------------- */
    1049         168 :     bool bSuccess = true;
    1050             : 
    1051         336 :     std::map<std::string, int> oMapFieldNameToIdx;
    1052         336 :     std::vector<std::unique_ptr<OGRFieldDefn>> apoFieldDefn;
    1053         336 :     gdal::DirectedAcyclicGraph<int, std::string> dag;
    1054             : 
    1055         168 :     GeoJSONObject::Type objType = OGRGeoJSONGetType(poGJObject);
    1056         168 :     if (GeoJSONObject::eFeature == objType)
    1057             :     {
    1058          17 :         bSuccess = GenerateFeatureDefn(oMapFieldNameToIdx, apoFieldDefn, dag,
    1059             :                                        poLayer, poGJObject);
    1060             :     }
    1061         151 :     else if (GeoJSONObject::eFeatureCollection == objType)
    1062             :     {
    1063             :         json_object *poObjFeatures =
    1064          93 :             OGRGeoJSONFindMemberByName(poGJObject, "features");
    1065         186 :         if (nullptr != poObjFeatures &&
    1066          93 :             json_type_array == json_object_get_type(poObjFeatures))
    1067             :         {
    1068          93 :             const auto nFeatures = json_object_array_length(poObjFeatures);
    1069         208 :             for (auto i = decltype(nFeatures){0}; i < nFeatures; ++i)
    1070             :             {
    1071             :                 json_object *poObjFeature =
    1072         115 :                     json_object_array_get_idx(poObjFeatures, i);
    1073         115 :                 if (!GenerateFeatureDefn(oMapFieldNameToIdx, apoFieldDefn, dag,
    1074             :                                          poLayer, poObjFeature))
    1075             :                 {
    1076           1 :                     CPLDebug("GeoJSON", "Create feature schema failure.");
    1077           1 :                     bSuccess = false;
    1078             :                 }
    1079             :             }
    1080             :         }
    1081             :         else
    1082             :         {
    1083           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1084             :                      "Invalid FeatureCollection object. "
    1085             :                      "Missing \'features\' member.");
    1086           0 :             bSuccess = false;
    1087             :         }
    1088             :     }
    1089             : 
    1090             :     // Note: the current strategy will not produce stable output, depending
    1091             :     // on the order of features, if there are conflicting order / cycles.
    1092             :     // See https://github.com/OSGeo/gdal/pull/4552 for a number of potential
    1093             :     // resolutions if that has to be solved in the future.
    1094         168 :     OGRFeatureDefn *poDefn = poLayer->GetLayerDefn();
    1095         336 :     const auto sortedFields = dag.getTopologicalOrdering();
    1096         168 :     CPLAssert(sortedFields.size() == apoFieldDefn.size());
    1097             :     {
    1098         336 :         auto oTemporaryUnsealer(poDefn->GetTemporaryUnsealer());
    1099         287 :         for (int idx : sortedFields)
    1100             :         {
    1101         119 :             poDefn->AddFieldDefn(apoFieldDefn[idx].get());
    1102             :         }
    1103             :     }
    1104             : 
    1105         168 :     CPLString osFIDColumn;
    1106         168 :     FinalizeLayerDefn(poLayer, osFIDColumn);
    1107         168 :     if (!osFIDColumn.empty())
    1108           8 :         poLayer->SetFIDColumn(osFIDColumn);
    1109             : 
    1110         168 :     return bSuccess;
    1111             : }
    1112             : 
    1113             : /************************************************************************/
    1114             : /*                          FinalizeLayerDefn()                         */
    1115             : /************************************************************************/
    1116             : 
    1117         476 : void OGRGeoJSONBaseReader::FinalizeLayerDefn(OGRLayer *poLayer,
    1118             :                                              CPLString &osFIDColumn)
    1119             : {
    1120             :     /* -------------------------------------------------------------------- */
    1121             :     /*      Validate and add FID column if necessary.                       */
    1122             :     /* -------------------------------------------------------------------- */
    1123         476 :     osFIDColumn.clear();
    1124         476 :     OGRFeatureDefn *poLayerDefn = poLayer->GetLayerDefn();
    1125         476 :     CPLAssert(nullptr != poLayerDefn);
    1126             : 
    1127         476 :     whileUnsealing(poLayerDefn)->SetGeomType(m_eLayerGeomType);
    1128             : 
    1129         476 :     if (m_bNeedFID64)
    1130             :     {
    1131           4 :         poLayer->SetMetadataItem(OLMD_FID64, "YES");
    1132             :     }
    1133             : 
    1134         476 :     if (!bFeatureLevelIdAsFID_)
    1135             :     {
    1136         453 :         const int idx = poLayerDefn->GetFieldIndexCaseSensitive("id");
    1137         453 :         if (idx >= 0)
    1138             :         {
    1139          67 :             OGRFieldDefn *poFDefn = poLayerDefn->GetFieldDefn(idx);
    1140         102 :             if (poFDefn->GetType() == OFTInteger ||
    1141          35 :                 poFDefn->GetType() == OFTInteger64)
    1142             :             {
    1143          34 :                 osFIDColumn = poLayerDefn->GetFieldDefn(idx)->GetNameRef();
    1144             :             }
    1145             :         }
    1146             :     }
    1147         476 : }
    1148             : 
    1149             : /************************************************************************/
    1150             : /*                     OGRGeoJSONReaderAddOrUpdateField()               */
    1151             : /************************************************************************/
    1152             : 
    1153       20073 : void OGRGeoJSONReaderAddOrUpdateField(
    1154             :     std::vector<int> &retIndices,
    1155             :     std::map<std::string, int> &oMapFieldNameToIdx,
    1156             :     std::vector<std::unique_ptr<OGRFieldDefn>> &apoFieldDefn,
    1157             :     const char *pszKey, json_object *poVal, bool bFlattenNestedAttributes,
    1158             :     char chNestedAttributeSeparator, bool bArrayAsString, bool bDateAsString,
    1159             :     std::set<int> &aoSetUndeterminedTypeFields)
    1160             : {
    1161       20073 :     const auto jType = json_object_get_type(poVal);
    1162       20073 :     if (bFlattenNestedAttributes && poVal != nullptr &&
    1163             :         jType == json_type_object)
    1164             :     {
    1165             :         json_object_iter it;
    1166           2 :         it.key = nullptr;
    1167           2 :         it.val = nullptr;
    1168           2 :         it.entry = nullptr;
    1169           6 :         json_object_object_foreachC(poVal, it)
    1170             :         {
    1171           4 :             char szSeparator[2] = {chNestedAttributeSeparator, '\0'};
    1172             : 
    1173             :             CPLString osAttrName(
    1174           8 :                 CPLSPrintf("%s%s%s", pszKey, szSeparator, it.key));
    1175           8 :             if (it.val != nullptr &&
    1176           4 :                 json_object_get_type(it.val) == json_type_object)
    1177             :             {
    1178           0 :                 OGRGeoJSONReaderAddOrUpdateField(
    1179             :                     retIndices, oMapFieldNameToIdx, apoFieldDefn, osAttrName,
    1180             :                     it.val, true, chNestedAttributeSeparator, bArrayAsString,
    1181             :                     bDateAsString, aoSetUndeterminedTypeFields);
    1182             :             }
    1183             :             else
    1184             :             {
    1185           4 :                 OGRGeoJSONReaderAddOrUpdateField(
    1186             :                     retIndices, oMapFieldNameToIdx, apoFieldDefn, osAttrName,
    1187             :                     it.val, false, 0, bArrayAsString, bDateAsString,
    1188             :                     aoSetUndeterminedTypeFields);
    1189             :             }
    1190             :         }
    1191           2 :         return;
    1192             :     }
    1193             : 
    1194       20071 :     const auto oMapFieldNameToIdxIter = oMapFieldNameToIdx.find(pszKey);
    1195       20071 :     if (oMapFieldNameToIdxIter == oMapFieldNameToIdx.end())
    1196             :     {
    1197             :         OGRFieldSubType eSubType;
    1198             :         const OGRFieldType eType =
    1199        1021 :             GeoJSONPropertyToFieldType(poVal, eSubType, bArrayAsString);
    1200        2042 :         auto poFieldDefn = std::make_unique<OGRFieldDefn>(pszKey, eType);
    1201        1021 :         poFieldDefn->SetSubType(eSubType);
    1202        1021 :         if (eSubType == OFSTBoolean)
    1203          34 :             poFieldDefn->SetWidth(1);
    1204        1021 :         if (poFieldDefn->GetType() == OFTString && !bDateAsString)
    1205             :         {
    1206         500 :             int nTZFlag = 0;
    1207         500 :             poFieldDefn->SetType(
    1208             :                 GeoJSONStringPropertyToFieldType(poVal, nTZFlag));
    1209         500 :             poFieldDefn->SetTZFlag(nTZFlag);
    1210             :         }
    1211        1021 :         apoFieldDefn.emplace_back(std::move(poFieldDefn));
    1212        1021 :         const int nIndex = static_cast<int>(apoFieldDefn.size()) - 1;
    1213        1021 :         retIndices.emplace_back(nIndex);
    1214        1021 :         oMapFieldNameToIdx[pszKey] = nIndex;
    1215        1021 :         if (poVal == nullptr)
    1216           8 :             aoSetUndeterminedTypeFields.insert(nIndex);
    1217             :     }
    1218       19050 :     else if (poVal)
    1219             :     {
    1220       19035 :         const int nIndex = oMapFieldNameToIdxIter->second;
    1221       19035 :         retIndices.emplace_back(nIndex);
    1222             :         // If there is a null value: do not update field definition.
    1223       19035 :         OGRFieldDefn *poFDefn = apoFieldDefn[nIndex].get();
    1224       19035 :         const OGRFieldType eType = poFDefn->GetType();
    1225       19035 :         const OGRFieldSubType eSubType = poFDefn->GetSubType();
    1226             :         OGRFieldSubType eNewSubType;
    1227             :         OGRFieldType eNewType =
    1228       19035 :             GeoJSONPropertyToFieldType(poVal, eNewSubType, bArrayAsString);
    1229             :         const bool bNewIsEmptyArray =
    1230       19035 :             (jType == json_type_array && json_object_array_length(poVal) == 0);
    1231       19035 :         if (cpl::contains(aoSetUndeterminedTypeFields, nIndex))
    1232             :         {
    1233           7 :             poFDefn->SetSubType(OFSTNone);
    1234           7 :             poFDefn->SetType(eNewType);
    1235           7 :             if (poFDefn->GetType() == OFTString && !bDateAsString)
    1236             :             {
    1237           2 :                 int nTZFlag = 0;
    1238           2 :                 poFDefn->SetType(
    1239             :                     GeoJSONStringPropertyToFieldType(poVal, nTZFlag));
    1240           2 :                 poFDefn->SetTZFlag(nTZFlag);
    1241             :             }
    1242           7 :             poFDefn->SetSubType(eNewSubType);
    1243           7 :             aoSetUndeterminedTypeFields.erase(nIndex);
    1244             :         }
    1245       19028 :         else if (eType == OFTInteger)
    1246             :         {
    1247       12971 :             if (eNewType == OFTInteger && eSubType == OFSTBoolean &&
    1248           5 :                 eNewSubType != OFSTBoolean)
    1249             :             {
    1250           2 :                 poFDefn->SetSubType(OFSTNone);
    1251             :             }
    1252       12969 :             else if (eNewType == OFTInteger64 || eNewType == OFTReal ||
    1253       12955 :                      eNewType == OFTInteger64List || eNewType == OFTRealList ||
    1254             :                      eNewType == OFTStringList)
    1255             :             {
    1256          18 :                 poFDefn->SetSubType(OFSTNone);
    1257          18 :                 poFDefn->SetType(eNewType);
    1258             :             }
    1259       12951 :             else if (eNewType == OFTIntegerList)
    1260             :             {
    1261           4 :                 if (eSubType == OFSTBoolean && eNewSubType != OFSTBoolean)
    1262             :                 {
    1263           1 :                     poFDefn->SetSubType(OFSTNone);
    1264             :                 }
    1265           4 :                 poFDefn->SetType(eNewType);
    1266             :             }
    1267       12947 :             else if (eNewType != OFTInteger)
    1268             :             {
    1269          15 :                 poFDefn->SetSubType(OFSTNone);
    1270          15 :                 poFDefn->SetType(OFTString);
    1271          15 :                 poFDefn->SetSubType(OFSTJSON);
    1272             :             }
    1273             :         }
    1274        6057 :         else if (eType == OFTInteger64)
    1275             :         {
    1276          15 :             if (eNewType == OFTReal)
    1277             :             {
    1278           2 :                 poFDefn->SetSubType(OFSTNone);
    1279           2 :                 poFDefn->SetType(eNewType);
    1280             :             }
    1281          13 :             else if (eNewType == OFTIntegerList || eNewType == OFTInteger64List)
    1282             :             {
    1283           3 :                 poFDefn->SetSubType(OFSTNone);
    1284           3 :                 poFDefn->SetType(OFTInteger64List);
    1285             :             }
    1286          10 :             else if (eNewType == OFTRealList || eNewType == OFTStringList)
    1287             :             {
    1288           2 :                 poFDefn->SetSubType(OFSTNone);
    1289           2 :                 poFDefn->SetType(eNewType);
    1290             :             }
    1291           8 :             else if (eNewType != OFTInteger && eNewType != OFTInteger64)
    1292             :             {
    1293           2 :                 poFDefn->SetSubType(OFSTNone);
    1294           2 :                 poFDefn->SetType(OFTString);
    1295           2 :                 poFDefn->SetSubType(OFSTJSON);
    1296             :             }
    1297             :         }
    1298        6042 :         else if (eType == OFTReal)
    1299             :         {
    1300         413 :             if (eNewType == OFTIntegerList || eNewType == OFTInteger64List ||
    1301             :                 eNewType == OFTRealList)
    1302             :             {
    1303           4 :                 poFDefn->SetSubType(OFSTNone);
    1304           4 :                 poFDefn->SetType(OFTRealList);
    1305             :             }
    1306         409 :             else if (eNewType == OFTStringList)
    1307             :             {
    1308           1 :                 poFDefn->SetSubType(OFSTNone);
    1309           1 :                 poFDefn->SetType(OFTStringList);
    1310             :             }
    1311         408 :             else if (eNewType != OFTInteger && eNewType != OFTInteger64 &&
    1312             :                      eNewType != OFTReal)
    1313             :             {
    1314           2 :                 poFDefn->SetSubType(OFSTNone);
    1315           2 :                 poFDefn->SetType(OFTString);
    1316           2 :                 poFDefn->SetSubType(OFSTJSON);
    1317             :             }
    1318             :         }
    1319        5629 :         else if (eType == OFTString)
    1320             :         {
    1321        5353 :             if (eSubType == OFSTNone)
    1322             :             {
    1323        5317 :                 if (eNewType == OFTStringList)
    1324             :                 {
    1325           1 :                     poFDefn->SetType(OFTStringList);
    1326             :                 }
    1327        5316 :                 else if (eNewType != OFTString)
    1328             :                 {
    1329          15 :                     poFDefn->SetSubType(OFSTJSON);
    1330             :                 }
    1331             :             }
    1332             :         }
    1333         276 :         else if (eType == OFTIntegerList)
    1334             :         {
    1335          50 :             if (eNewType == OFTString)
    1336             :             {
    1337           6 :                 if (!bNewIsEmptyArray)
    1338             :                 {
    1339           6 :                     poFDefn->SetSubType(OFSTNone);
    1340           6 :                     poFDefn->SetType(eNewType);
    1341           6 :                     poFDefn->SetSubType(OFSTJSON);
    1342             :                 }
    1343             :             }
    1344          44 :             else if (eNewType == OFTInteger64List || eNewType == OFTRealList ||
    1345             :                      eNewType == OFTStringList)
    1346             :             {
    1347          19 :                 poFDefn->SetSubType(OFSTNone);
    1348          19 :                 poFDefn->SetType(eNewType);
    1349             :             }
    1350          25 :             else if (eNewType == OFTInteger64)
    1351             :             {
    1352           2 :                 poFDefn->SetSubType(OFSTNone);
    1353           2 :                 poFDefn->SetType(OFTInteger64List);
    1354             :             }
    1355          23 :             else if (eNewType == OFTReal)
    1356             :             {
    1357           2 :                 poFDefn->SetSubType(OFSTNone);
    1358           2 :                 poFDefn->SetType(OFTRealList);
    1359             :             }
    1360          21 :             else if (eNewType == OFTInteger || eNewType == OFTIntegerList)
    1361             :             {
    1362          21 :                 if (eSubType == OFSTBoolean && eNewSubType != OFSTBoolean)
    1363             :                 {
    1364           2 :                     poFDefn->SetSubType(OFSTNone);
    1365             :                 }
    1366             :             }
    1367             :             else
    1368             :             {
    1369           0 :                 poFDefn->SetSubType(OFSTNone);
    1370           0 :                 poFDefn->SetType(OFTString);
    1371           0 :                 poFDefn->SetSubType(OFSTJSON);
    1372             :             }
    1373             :         }
    1374         226 :         else if (eType == OFTInteger64List)
    1375             :         {
    1376          24 :             if (eNewType == OFTString)
    1377             :             {
    1378           3 :                 if (!bNewIsEmptyArray)
    1379             :                 {
    1380           3 :                     poFDefn->SetSubType(OFSTNone);
    1381           3 :                     poFDefn->SetType(eNewType);
    1382           3 :                     poFDefn->SetSubType(OFSTJSON);
    1383             :                 }
    1384             :             }
    1385          21 :             else if (eNewType == OFTInteger64List || eNewType == OFTRealList ||
    1386             :                      eNewType == OFTStringList)
    1387             :             {
    1388           9 :                 poFDefn->SetSubType(OFSTNone);
    1389           9 :                 poFDefn->SetType(eNewType);
    1390             :             }
    1391          12 :             else if (eNewType == OFTReal)
    1392             :             {
    1393           1 :                 poFDefn->SetSubType(OFSTNone);
    1394           1 :                 poFDefn->SetType(OFTRealList);
    1395             :             }
    1396          11 :             else if (eNewType != OFTInteger && eNewType != OFTInteger64 &&
    1397             :                      eNewType != OFTIntegerList)
    1398             :             {
    1399           0 :                 poFDefn->SetSubType(OFSTNone);
    1400           0 :                 poFDefn->SetType(OFTString);
    1401           0 :                 poFDefn->SetSubType(OFSTJSON);
    1402             :             }
    1403             :         }
    1404         202 :         else if (eType == OFTRealList)
    1405             :         {
    1406          24 :             if (eNewType == OFTString)
    1407             :             {
    1408           3 :                 if (!bNewIsEmptyArray)
    1409             :                 {
    1410           3 :                     poFDefn->SetSubType(OFSTNone);
    1411           3 :                     poFDefn->SetType(eNewType);
    1412           3 :                     poFDefn->SetSubType(OFSTJSON);
    1413             :                 }
    1414             :             }
    1415          21 :             else if (eNewType == OFTStringList)
    1416             :             {
    1417           1 :                 poFDefn->SetSubType(OFSTNone);
    1418           1 :                 poFDefn->SetType(eNewType);
    1419             :             }
    1420          20 :             else if (eNewType != OFTInteger && eNewType != OFTInteger64 &&
    1421          16 :                      eNewType != OFTReal && eNewType != OFTIntegerList &&
    1422           4 :                      eNewType != OFTInteger64List && eNewType != OFTRealList)
    1423             :             {
    1424           0 :                 poFDefn->SetSubType(OFSTNone);
    1425           0 :                 poFDefn->SetType(OFTString);
    1426           0 :                 poFDefn->SetSubType(OFSTJSON);
    1427             :             }
    1428             :         }
    1429         178 :         else if (eType == OFTStringList)
    1430             :         {
    1431          30 :             if (eNewType == OFTString && eNewSubType == OFSTJSON)
    1432             :             {
    1433           1 :                 if (!bNewIsEmptyArray)
    1434             :                 {
    1435           1 :                     poFDefn->SetSubType(OFSTNone);
    1436           1 :                     poFDefn->SetType(eNewType);
    1437           1 :                     poFDefn->SetSubType(OFSTJSON);
    1438             :                 }
    1439             :             }
    1440             :         }
    1441         148 :         else if (eType == OFTDate || eType == OFTTime || eType == OFTDateTime)
    1442             :         {
    1443         148 :             if (eNewType == OFTString && !bDateAsString &&
    1444         147 :                 eNewSubType == OFSTNone)
    1445             :             {
    1446         146 :                 int nTZFlag = 0;
    1447         146 :                 eNewType = GeoJSONStringPropertyToFieldType(poVal, nTZFlag);
    1448         156 :                 if (poFDefn->GetTZFlag() > OGR_TZFLAG_UNKNOWN &&
    1449          10 :                     nTZFlag != poFDefn->GetTZFlag())
    1450             :                 {
    1451           6 :                     if (nTZFlag == OGR_TZFLAG_UNKNOWN)
    1452           4 :                         poFDefn->SetTZFlag(OGR_TZFLAG_UNKNOWN);
    1453             :                     else
    1454           2 :                         poFDefn->SetTZFlag(OGR_TZFLAG_MIXED_TZ);
    1455             :                 }
    1456             :             }
    1457         148 :             if (eType != eNewType)
    1458             :             {
    1459           8 :                 poFDefn->SetSubType(OFSTNone);
    1460           8 :                 if (eNewType == OFTString)
    1461             :                 {
    1462           5 :                     poFDefn->SetType(eNewType);
    1463           5 :                     poFDefn->SetSubType(eNewSubType);
    1464             :                 }
    1465           3 :                 else if (eType == OFTDate && eNewType == OFTDateTime)
    1466             :                 {
    1467           1 :                     poFDefn->SetType(OFTDateTime);
    1468             :                 }
    1469           2 :                 else if (!(eType == OFTDateTime && eNewType == OFTDate))
    1470             :                 {
    1471           1 :                     poFDefn->SetType(OFTString);
    1472           1 :                     poFDefn->SetSubType(OFSTJSON);
    1473             :                 }
    1474             :             }
    1475             :         }
    1476             : 
    1477       19035 :         poFDefn->SetWidth(poFDefn->GetSubType() == OFSTBoolean ? 1 : 0);
    1478             :     }
    1479             :     else
    1480             :     {
    1481          15 :         const int nIndex = oMapFieldNameToIdxIter->second;
    1482          15 :         retIndices.emplace_back(nIndex);
    1483             :     }
    1484             : }
    1485             : 
    1486             : /************************************************************************/
    1487             : /*             OGRGeoJSONGenerateFeatureDefnDealWithID()                */
    1488             : /************************************************************************/
    1489             : 
    1490        4916 : void OGRGeoJSONGenerateFeatureDefnDealWithID(
    1491             :     json_object *poObj, json_object *poObjProps, int &nPrevFieldIdx,
    1492             :     std::map<std::string, int> &oMapFieldNameToIdx,
    1493             :     std::vector<std::unique_ptr<OGRFieldDefn>> &apoFieldDefn,
    1494             :     gdal::DirectedAcyclicGraph<int, std::string> &dag,
    1495             :     bool &bFeatureLevelIdAsFID, bool &bFeatureLevelIdAsAttribute,
    1496             :     bool &bNeedFID64)
    1497             : {
    1498        4916 :     json_object *poObjId = OGRGeoJSONFindMemberByName(poObj, "id");
    1499        4916 :     if (poObjId)
    1500             :     {
    1501        1697 :         const auto iterIdxId = oMapFieldNameToIdx.find("id");
    1502        1697 :         if (iterIdxId == oMapFieldNameToIdx.end())
    1503             :         {
    1504         107 :             if (json_object_get_type(poObjId) == json_type_int)
    1505             :             {
    1506             :                 // If the value is negative, we cannot use it as the FID
    1507             :                 // as OGRMemLayer doesn't support negative FID. And we would
    1508             :                 // have an ambiguity with -1 that can mean OGRNullFID
    1509             :                 // so in that case create a regular attribute and let OGR
    1510             :                 // attribute sequential OGR FIDs.
    1511          71 :                 if (json_object_get_int64(poObjId) < 0)
    1512             :                 {
    1513           5 :                     bFeatureLevelIdAsFID = false;
    1514             :                 }
    1515             :                 else
    1516             :                 {
    1517          66 :                     bFeatureLevelIdAsFID = true;
    1518             :                 }
    1519             :             }
    1520         107 :             if (!bFeatureLevelIdAsFID)
    1521             :             {
    1522             :                 // If there's a top-level id of type string or negative int,
    1523             :                 // and no properties.id, then declare a id field.
    1524          41 :                 bool bHasRegularIdProp = false;
    1525          80 :                 if (nullptr != poObjProps &&
    1526          39 :                     json_object_get_type(poObjProps) == json_type_object)
    1527             :                 {
    1528          39 :                     bHasRegularIdProp =
    1529          39 :                         CPL_json_object_object_get(poObjProps, "id") != nullptr;
    1530             :                 }
    1531          41 :                 if (!bHasRegularIdProp)
    1532             :                 {
    1533          38 :                     OGRFieldType eType = OFTString;
    1534          38 :                     if (json_object_get_type(poObjId) == json_type_int)
    1535             :                     {
    1536           5 :                         if (CPL_INT64_FITS_ON_INT32(
    1537             :                                 json_object_get_int64(poObjId)))
    1538           4 :                             eType = OFTInteger;
    1539             :                         else
    1540           1 :                             eType = OFTInteger64;
    1541             :                     }
    1542             :                     apoFieldDefn.emplace_back(
    1543          38 :                         std::make_unique<OGRFieldDefn>("id", eType));
    1544          38 :                     const int nIdx = static_cast<int>(apoFieldDefn.size()) - 1;
    1545          38 :                     oMapFieldNameToIdx["id"] = nIdx;
    1546          38 :                     nPrevFieldIdx = nIdx;
    1547          38 :                     dag.addNode(nIdx, "id");
    1548          38 :                     bFeatureLevelIdAsAttribute = true;
    1549             :                 }
    1550             :             }
    1551             :         }
    1552             :         else
    1553             :         {
    1554        1590 :             const int nIdx = iterIdxId->second;
    1555        1590 :             nPrevFieldIdx = nIdx;
    1556        1607 :             if (bFeatureLevelIdAsAttribute &&
    1557          17 :                 json_object_get_type(poObjId) == json_type_int)
    1558             :             {
    1559           3 :                 if (apoFieldDefn[nIdx]->GetType() == OFTInteger)
    1560             :                 {
    1561           1 :                     if (!CPL_INT64_FITS_ON_INT32(
    1562             :                             json_object_get_int64(poObjId)))
    1563           1 :                         apoFieldDefn[nIdx]->SetType(OFTInteger64);
    1564             :                 }
    1565             :             }
    1566        1587 :             else if (bFeatureLevelIdAsAttribute)
    1567             :             {
    1568          14 :                 apoFieldDefn[nIdx]->SetType(OFTString);
    1569             :             }
    1570             :         }
    1571             :     }
    1572             : 
    1573        4916 :     if (!bNeedFID64)
    1574             :     {
    1575        4915 :         json_object *poId = CPL_json_object_object_get(poObj, "id");
    1576        4915 :         if (poId == nullptr)
    1577             :         {
    1578        6392 :             if (poObjProps &&
    1579        3173 :                 json_object_get_type(poObjProps) == json_type_object)
    1580             :             {
    1581        3172 :                 poId = CPL_json_object_object_get(poObjProps, "id");
    1582             :             }
    1583             :         }
    1584        4915 :         if (poId != nullptr && json_object_get_type(poId) == json_type_int)
    1585             :         {
    1586        1689 :             GIntBig nFID = json_object_get_int64(poId);
    1587        1689 :             if (!CPL_INT64_FITS_ON_INT32(nFID))
    1588             :             {
    1589           4 :                 bNeedFID64 = true;
    1590             :             }
    1591             :         }
    1592             :     }
    1593        4916 : }
    1594             : 
    1595             : /************************************************************************/
    1596             : /*                        GenerateFeatureDefn()                         */
    1597             : /************************************************************************/
    1598        4697 : bool OGRGeoJSONBaseReader::GenerateFeatureDefn(
    1599             :     std::map<std::string, int> &oMapFieldNameToIdx,
    1600             :     std::vector<std::unique_ptr<OGRFieldDefn>> &apoFieldDefn,
    1601             :     gdal::DirectedAcyclicGraph<int, std::string> &dag, OGRLayer *poLayer,
    1602             :     json_object *poObj)
    1603             : {
    1604             :     /* -------------------------------------------------------------------- */
    1605             :     /*      Read collection of properties.                                  */
    1606             :     /* -------------------------------------------------------------------- */
    1607             :     lh_entry *poObjPropsEntry =
    1608        4697 :         OGRGeoJSONFindMemberEntryByName(poObj, "properties");
    1609        4697 :     json_object *poObjProps =
    1610        4697 :         const_cast<json_object *>(static_cast<const json_object *>(
    1611             :             poObjPropsEntry ? poObjPropsEntry->v : nullptr));
    1612             : 
    1613        9394 :     std::vector<int> anCurFieldIndices;
    1614        4697 :     int nPrevFieldIdx = -1;
    1615             : 
    1616        4697 :     OGRGeoJSONGenerateFeatureDefnDealWithID(
    1617             :         poObj, poObjProps, nPrevFieldIdx, oMapFieldNameToIdx, apoFieldDefn, dag,
    1618        4697 :         bFeatureLevelIdAsFID_, bFeatureLevelIdAsAttribute_, m_bNeedFID64);
    1619             : 
    1620        4697 :     json_object *poGeomObj = CPL_json_object_object_get(poObj, "geometry");
    1621        4697 :     if (poGeomObj && json_object_get_type(poGeomObj) == json_type_object)
    1622             :     {
    1623        4451 :         const auto eType = OGRGeoJSONGetOGRGeometryType(poGeomObj);
    1624             : 
    1625        4451 :         OGRGeoJSONUpdateLayerGeomType(m_bFirstGeometry, eType,
    1626        4451 :                                       m_eLayerGeomType);
    1627             : 
    1628        4451 :         if (eType != wkbNone && eType != wkbUnknown)
    1629             :         {
    1630             :             // This is maybe too optimistic: it assumes that the geometry
    1631             :             // coordinates array is in the correct format
    1632        4451 :             m_bExtentRead |= OGRGeoJSONGetExtent3D(poGeomObj, &m_oEnvelope3D);
    1633             :         }
    1634             :     }
    1635             : 
    1636        4697 :     bool bSuccess = false;
    1637             : 
    1638        9349 :     if (nullptr != poObjProps &&
    1639        4652 :         json_object_get_type(poObjProps) == json_type_object)
    1640             :     {
    1641        4651 :         if (bIsGeocouchSpatiallistFormat)
    1642             :         {
    1643           3 :             poObjProps = CPL_json_object_object_get(poObjProps, "properties");
    1644           6 :             if (nullptr == poObjProps ||
    1645           3 :                 json_object_get_type(poObjProps) != json_type_object)
    1646             :             {
    1647           2 :                 return true;
    1648             :             }
    1649             :         }
    1650             : 
    1651             :         json_object_iter it;
    1652        4651 :         it.key = nullptr;
    1653        4651 :         it.val = nullptr;
    1654        4651 :         it.entry = nullptr;
    1655       24367 :         json_object_object_foreachC(poObjProps, it)
    1656             :         {
    1657       39427 :             if (!bIsGeocouchSpatiallistFormat &&
    1658       19709 :                 !cpl::contains(oMapFieldNameToIdx, it.key))
    1659             :             {
    1660             :                 // Detect the special kind of GeoJSON output by a spatiallist of
    1661             :                 // GeoCouch such as:
    1662             :                 // http://gd.iriscouch.com/cphosm/_design/geo/_rewrite/data?bbox=12.53%2C55.73%2C12.54%2C55.73
    1663         886 :                 if (strcmp(it.key, "_id") == 0)
    1664             :                 {
    1665           2 :                     bFoundGeocouchId = true;
    1666             :                 }
    1667         884 :                 else if (bFoundGeocouchId && strcmp(it.key, "_rev") == 0)
    1668             :                 {
    1669           2 :                     bFoundRev = true;
    1670             :                 }
    1671           4 :                 else if (bFoundRev && strcmp(it.key, "type") == 0 &&
    1672           2 :                          it.val != nullptr &&
    1673         888 :                          json_object_get_type(it.val) == json_type_string &&
    1674           2 :                          strcmp(json_object_get_string(it.val), "Feature") == 0)
    1675             :                 {
    1676           2 :                     bFoundTypeFeature = true;
    1677             :                 }
    1678        1762 :                 else if (bFoundTypeFeature &&
    1679           2 :                          strcmp(it.key, "properties") == 0 &&
    1680         884 :                          it.val != nullptr &&
    1681           2 :                          json_object_get_type(it.val) == json_type_object)
    1682             :                 {
    1683           2 :                     if (bFlattenGeocouchSpatiallistFormat < 0)
    1684           2 :                         bFlattenGeocouchSpatiallistFormat =
    1685           2 :                             CPLTestBool(CPLGetConfigOption(
    1686             :                                 "GEOJSON_FLATTEN_GEOCOUCH", "TRUE"));
    1687           2 :                     if (bFlattenGeocouchSpatiallistFormat)
    1688             :                     {
    1689           2 :                         const auto typeIter = oMapFieldNameToIdx.find("type");
    1690           2 :                         if (typeIter != oMapFieldNameToIdx.end())
    1691             :                         {
    1692           2 :                             const int nIdx = typeIter->second;
    1693           2 :                             apoFieldDefn.erase(apoFieldDefn.begin() + nIdx);
    1694           2 :                             oMapFieldNameToIdx.erase(typeIter);
    1695           2 :                             dag.removeNode(nIdx);
    1696             :                         }
    1697             : 
    1698           2 :                         bIsGeocouchSpatiallistFormat = true;
    1699           2 :                         return GenerateFeatureDefn(oMapFieldNameToIdx,
    1700             :                                                    apoFieldDefn, dag, poLayer,
    1701           2 :                                                    poObj);
    1702             :                     }
    1703             :                 }
    1704             :             }
    1705             : 
    1706       19716 :             anCurFieldIndices.clear();
    1707       19716 :             OGRGeoJSONReaderAddOrUpdateField(
    1708       19716 :                 anCurFieldIndices, oMapFieldNameToIdx, apoFieldDefn, it.key,
    1709       19716 :                 it.val, bFlattenNestedAttributes_, chNestedAttributeSeparator_,
    1710       19716 :                 bArrayAsString_, bDateAsString_, aoSetUndeterminedTypeFields_);
    1711       39434 :             for (int idx : anCurFieldIndices)
    1712             :             {
    1713       19718 :                 dag.addNode(idx, apoFieldDefn[idx]->GetNameRef());
    1714       19718 :                 if (nPrevFieldIdx != -1)
    1715             :                 {
    1716       17392 :                     dag.addEdge(nPrevFieldIdx, idx);
    1717             :                 }
    1718       19718 :                 nPrevFieldIdx = idx;
    1719             :             }
    1720             :         }
    1721             : 
    1722        4649 :         bSuccess = true;  // SUCCESS
    1723             :     }
    1724          47 :     else if (nullptr != poObjPropsEntry &&
    1725           1 :              (poObjProps == nullptr ||
    1726           1 :               (json_object_get_type(poObjProps) == json_type_array &&
    1727           1 :                json_object_array_length(poObjProps) == 0)))
    1728             :     {
    1729             :         // Ignore "properties": null and "properties": []
    1730          13 :         bSuccess = true;
    1731             :     }
    1732          65 :     else if (poObj != nullptr &&
    1733          32 :              json_object_get_type(poObj) == json_type_object)
    1734             :     {
    1735             :         json_object_iter it;
    1736          32 :         it.key = nullptr;
    1737          32 :         it.val = nullptr;
    1738          32 :         it.entry = nullptr;
    1739         100 :         json_object_object_foreachC(poObj, it)
    1740             :         {
    1741          68 :             if (strcmp(it.key, "type") != 0 &&
    1742          36 :                 strcmp(it.key, "geometry") != 0 &&
    1743           4 :                 strcmp(it.key, "centroid") != 0 &&
    1744           4 :                 strcmp(it.key, "bbox") != 0 && strcmp(it.key, "center") != 0)
    1745             :             {
    1746           4 :                 if (!cpl::contains(oMapFieldNameToIdx, it.key))
    1747             :                 {
    1748           4 :                     anCurFieldIndices.clear();
    1749           4 :                     OGRGeoJSONReaderAddOrUpdateField(
    1750             :                         anCurFieldIndices, oMapFieldNameToIdx, apoFieldDefn,
    1751           4 :                         it.key, it.val, bFlattenNestedAttributes_,
    1752           4 :                         chNestedAttributeSeparator_, bArrayAsString_,
    1753           4 :                         bDateAsString_, aoSetUndeterminedTypeFields_);
    1754           8 :                     for (int idx : anCurFieldIndices)
    1755             :                     {
    1756           4 :                         dag.addNode(idx, apoFieldDefn[idx]->GetNameRef());
    1757           4 :                         if (nPrevFieldIdx != -1)
    1758             :                         {
    1759           0 :                             dag.addEdge(nPrevFieldIdx, idx);
    1760             :                         }
    1761           4 :                         nPrevFieldIdx = idx;
    1762             :                     }
    1763             :                 }
    1764             :             }
    1765             :         }
    1766             : 
    1767          32 :         bSuccess = true;  // SUCCESS
    1768             :         // CPLError(CE_Failure, CPLE_AppDefined,
    1769             :         //          "Invalid Feature object. "
    1770             :         //          "Missing \'properties\' member." );
    1771             :     }
    1772             : 
    1773        4695 :     return bSuccess;
    1774             : }
    1775             : 
    1776             : /************************************************************************/
    1777             : /*                   OGRGeoJSONUpdateLayerGeomType()                    */
    1778             : /************************************************************************/
    1779             : 
    1780        4666 : bool OGRGeoJSONUpdateLayerGeomType(bool &bFirstGeom,
    1781             :                                    OGRwkbGeometryType eGeomType,
    1782             :                                    OGRwkbGeometryType &eLayerGeomType)
    1783             : {
    1784        4666 :     if (bFirstGeom)
    1785             :     {
    1786         415 :         eLayerGeomType = eGeomType;
    1787         415 :         bFirstGeom = false;
    1788             :     }
    1789        4262 :     else if (OGR_GT_HasZ(eGeomType) && !OGR_GT_HasZ(eLayerGeomType) &&
    1790          11 :              wkbFlatten(eGeomType) == wkbFlatten(eLayerGeomType))
    1791             :     {
    1792           2 :         eLayerGeomType = eGeomType;
    1793             :     }
    1794        4252 :     else if (!OGR_GT_HasZ(eGeomType) && OGR_GT_HasZ(eLayerGeomType) &&
    1795           3 :              wkbFlatten(eGeomType) == wkbFlatten(eLayerGeomType))
    1796             :     {
    1797             :         // ok
    1798             :     }
    1799        4247 :     else if (eGeomType != eLayerGeomType && eLayerGeomType != wkbUnknown)
    1800             :     {
    1801          45 :         CPLDebug("GeoJSON", "Detected layer of mixed-geometry type features.");
    1802          45 :         eLayerGeomType = wkbUnknown;
    1803          45 :         return false;
    1804             :     }
    1805        4621 :     return true;
    1806             : }
    1807             : 
    1808             : /************************************************************************/
    1809             : /*                           AddFeature                                 */
    1810             : /************************************************************************/
    1811             : 
    1812          58 : bool OGRGeoJSONReader::AddFeature(OGRGeoJSONLayer *poLayer,
    1813             :                                   OGRGeometry *poGeometry)
    1814             : {
    1815          58 :     bool bAdded = false;
    1816             : 
    1817             :     // TODO: Should we check if geometry is of type of wkbGeometryCollection?
    1818             : 
    1819          58 :     if (nullptr != poGeometry)
    1820             :     {
    1821          57 :         OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
    1822          57 :         poFeature->SetGeometryDirectly(poGeometry);
    1823             : 
    1824          57 :         bAdded = AddFeature(poLayer, poFeature);
    1825             :     }
    1826             : 
    1827          58 :     return bAdded;
    1828             : }
    1829             : 
    1830             : /************************************************************************/
    1831             : /*                           AddFeature                                 */
    1832             : /************************************************************************/
    1833             : 
    1834         188 : bool OGRGeoJSONReader::AddFeature(OGRGeoJSONLayer *poLayer,
    1835             :                                   OGRFeature *poFeature)
    1836             : {
    1837         188 :     if (poFeature == nullptr)
    1838           0 :         return false;
    1839             : 
    1840         188 :     poLayer->AddFeature(poFeature);
    1841         188 :     delete poFeature;
    1842             : 
    1843         188 :     return true;
    1844             : }
    1845             : 
    1846             : /************************************************************************/
    1847             : /*                           ReadGeometry                               */
    1848             : /************************************************************************/
    1849             : 
    1850        1250 : OGRGeometry *OGRGeoJSONBaseReader::ReadGeometry(json_object *poObj,
    1851             :                                                 OGRSpatialReference *poLayerSRS)
    1852             : {
    1853        1250 :     OGRGeometry *poGeometry = OGRGeoJSONReadGeometry(poObj, poLayerSRS);
    1854             : 
    1855             :     /* -------------------------------------------------------------------- */
    1856             :     /*      Wrap geometry with GeometryCollection as a common denominator.  */
    1857             :     /*      Sometimes a GeoJSON text may consist of objects of different    */
    1858             :     /*      geometry types. Users may request wrapping all geometries with  */
    1859             :     /*      OGRGeometryCollection type by using option                      */
    1860             :     /*      GEOMETRY_AS_COLLECTION=NO|YES (NO is default).                  */
    1861             :     /* -------------------------------------------------------------------- */
    1862        1250 :     if (nullptr != poGeometry)
    1863             :     {
    1864        1235 :         if (!bGeometryPreserve_ &&
    1865           0 :             wkbGeometryCollection != poGeometry->getGeometryType())
    1866             :         {
    1867           0 :             OGRGeometryCollection *poMetaGeometry = new OGRGeometryCollection();
    1868           0 :             poMetaGeometry->addGeometryDirectly(poGeometry);
    1869           0 :             return poMetaGeometry;
    1870             :         }
    1871             :     }
    1872             : 
    1873        1250 :     return poGeometry;
    1874             : }
    1875             : 
    1876             : /************************************************************************/
    1877             : /*                OGRGeoJSONReaderSetFieldNestedAttribute()             */
    1878             : /************************************************************************/
    1879             : 
    1880           2 : static void OGRGeoJSONReaderSetFieldNestedAttribute(OGRLayer *poLayer,
    1881             :                                                     OGRFeature *poFeature,
    1882             :                                                     const char *pszAttrPrefix,
    1883             :                                                     char chSeparator,
    1884             :                                                     json_object *poVal)
    1885             : {
    1886             :     json_object_iter it;
    1887           2 :     it.key = nullptr;
    1888           2 :     it.val = nullptr;
    1889           2 :     it.entry = nullptr;
    1890           6 :     json_object_object_foreachC(poVal, it)
    1891             :     {
    1892           4 :         const char szSeparator[2] = {chSeparator, '\0'};
    1893             :         const CPLString osAttrName(
    1894           8 :             CPLSPrintf("%s%s%s", pszAttrPrefix, szSeparator, it.key));
    1895           8 :         if (it.val != nullptr &&
    1896           4 :             json_object_get_type(it.val) == json_type_object)
    1897             :         {
    1898           0 :             OGRGeoJSONReaderSetFieldNestedAttribute(
    1899             :                 poLayer, poFeature, osAttrName, chSeparator, it.val);
    1900             :         }
    1901             :         else
    1902             :         {
    1903             :             const int nField =
    1904           4 :                 poFeature->GetDefnRef()->GetFieldIndexCaseSensitive(osAttrName);
    1905           4 :             OGRGeoJSONReaderSetField(poLayer, poFeature, nField, osAttrName,
    1906             :                                      it.val, false, 0);
    1907             :         }
    1908             :     }
    1909           2 : }
    1910             : 
    1911             : /************************************************************************/
    1912             : /*                   OGRGeoJSONReaderSetField()                         */
    1913             : /************************************************************************/
    1914             : 
    1915        5987 : void OGRGeoJSONReaderSetField(OGRLayer *poLayer, OGRFeature *poFeature,
    1916             :                               int nField, const char *pszAttrPrefix,
    1917             :                               json_object *poVal, bool bFlattenNestedAttributes,
    1918             :                               char chNestedAttributeSeparator)
    1919             : {
    1920        5991 :     if (bFlattenNestedAttributes && poVal != nullptr &&
    1921           4 :         json_object_get_type(poVal) == json_type_object)
    1922             :     {
    1923           2 :         OGRGeoJSONReaderSetFieldNestedAttribute(
    1924             :             poLayer, poFeature, pszAttrPrefix, chNestedAttributeSeparator,
    1925             :             poVal);
    1926           2 :         return;
    1927             :     }
    1928        5985 :     if (nField < 0)
    1929           0 :         return;
    1930             : 
    1931        5985 :     OGRFieldDefn *poFieldDefn = poFeature->GetFieldDefnRef(nField);
    1932        5985 :     CPLAssert(nullptr != poFieldDefn);
    1933        5985 :     OGRFieldType eType = poFieldDefn->GetType();
    1934             : 
    1935        5985 :     if (poVal == nullptr)
    1936             :     {
    1937          86 :         poFeature->SetFieldNull(nField);
    1938             :     }
    1939        5899 :     else if (OFTInteger == eType)
    1940             :     {
    1941        1701 :         poFeature->SetField(nField, json_object_get_int(poVal));
    1942             : 
    1943             :         // Check if FID available and set correct value.
    1944        1701 :         if (EQUAL(poFieldDefn->GetNameRef(), poLayer->GetFIDColumn()))
    1945         145 :             poFeature->SetFID(json_object_get_int(poVal));
    1946             :     }
    1947        4198 :     else if (OFTInteger64 == eType)
    1948             :     {
    1949          26 :         poFeature->SetField(nField, (GIntBig)json_object_get_int64(poVal));
    1950             : 
    1951             :         // Check if FID available and set correct value.
    1952          26 :         if (EQUAL(poFieldDefn->GetNameRef(), poLayer->GetFIDColumn()))
    1953           0 :             poFeature->SetFID(
    1954           0 :                 static_cast<GIntBig>(json_object_get_int64(poVal)));
    1955             :     }
    1956        4172 :     else if (OFTReal == eType)
    1957             :     {
    1958        1521 :         poFeature->SetField(nField, json_object_get_double(poVal));
    1959             :     }
    1960        2651 :     else if (OFTIntegerList == eType)
    1961             :     {
    1962          59 :         const enum json_type eJSonType(json_object_get_type(poVal));
    1963          59 :         if (eJSonType == json_type_array)
    1964             :         {
    1965          51 :             const auto nLength = json_object_array_length(poVal);
    1966          51 :             int *panVal = static_cast<int *>(CPLMalloc(sizeof(int) * nLength));
    1967         108 :             for (auto i = decltype(nLength){0}; i < nLength; i++)
    1968             :             {
    1969          57 :                 json_object *poRow = json_object_array_get_idx(poVal, i);
    1970          57 :                 panVal[i] = json_object_get_int(poRow);
    1971             :             }
    1972          51 :             poFeature->SetField(nField, static_cast<int>(nLength), panVal);
    1973          51 :             CPLFree(panVal);
    1974             :         }
    1975           8 :         else if (eJSonType == json_type_boolean || eJSonType == json_type_int)
    1976             :         {
    1977           8 :             poFeature->SetField(nField, json_object_get_int(poVal));
    1978             :         }
    1979             :     }
    1980        2592 :     else if (OFTInteger64List == eType)
    1981             :     {
    1982          77 :         const enum json_type eJSonType(json_object_get_type(poVal));
    1983          77 :         if (eJSonType == json_type_array)
    1984             :         {
    1985          67 :             const auto nLength = json_object_array_length(poVal);
    1986             :             GIntBig *panVal =
    1987          67 :                 static_cast<GIntBig *>(CPLMalloc(sizeof(GIntBig) * nLength));
    1988         149 :             for (auto i = decltype(nLength){0}; i < nLength; i++)
    1989             :             {
    1990          82 :                 json_object *poRow = json_object_array_get_idx(poVal, i);
    1991          82 :                 panVal[i] = static_cast<GIntBig>(json_object_get_int64(poRow));
    1992             :             }
    1993          67 :             poFeature->SetField(nField, static_cast<int>(nLength), panVal);
    1994          67 :             CPLFree(panVal);
    1995             :         }
    1996          10 :         else if (eJSonType == json_type_boolean || eJSonType == json_type_int)
    1997             :         {
    1998          10 :             poFeature->SetField(
    1999          10 :                 nField, static_cast<GIntBig>(json_object_get_int64(poVal)));
    2000             :         }
    2001             :     }
    2002        2515 :     else if (OFTRealList == eType)
    2003             :     {
    2004          96 :         const enum json_type eJSonType(json_object_get_type(poVal));
    2005          96 :         if (eJSonType == json_type_array)
    2006             :         {
    2007          82 :             const auto nLength = json_object_array_length(poVal);
    2008             :             double *padfVal =
    2009          82 :                 static_cast<double *>(CPLMalloc(sizeof(double) * nLength));
    2010         179 :             for (auto i = decltype(nLength){0}; i < nLength; i++)
    2011             :             {
    2012          97 :                 json_object *poRow = json_object_array_get_idx(poVal, i);
    2013          97 :                 padfVal[i] = json_object_get_double(poRow);
    2014             :             }
    2015          82 :             poFeature->SetField(nField, static_cast<int>(nLength), padfVal);
    2016          82 :             CPLFree(padfVal);
    2017             :         }
    2018          14 :         else if (eJSonType == json_type_boolean || eJSonType == json_type_int ||
    2019             :                  eJSonType == json_type_double)
    2020             :         {
    2021          14 :             poFeature->SetField(nField, json_object_get_double(poVal));
    2022             :         }
    2023             :     }
    2024        2419 :     else if (OFTStringList == eType)
    2025             :     {
    2026          80 :         const enum json_type eJSonType(json_object_get_type(poVal));
    2027          80 :         if (eJSonType == json_type_array)
    2028             :         {
    2029          70 :             auto nLength = json_object_array_length(poVal);
    2030             :             char **papszVal =
    2031          70 :                 (char **)CPLMalloc(sizeof(char *) * (nLength + 1));
    2032          70 :             decltype(nLength) i = 0;  // Used after for.
    2033         143 :             for (; i < nLength; i++)
    2034             :             {
    2035          73 :                 json_object *poRow = json_object_array_get_idx(poVal, i);
    2036          73 :                 const char *pszVal = json_object_get_string(poRow);
    2037          73 :                 if (pszVal == nullptr)
    2038           0 :                     break;
    2039          73 :                 papszVal[i] = CPLStrdup(pszVal);
    2040             :             }
    2041          70 :             papszVal[i] = nullptr;
    2042          70 :             poFeature->SetField(nField, papszVal);
    2043          70 :             CSLDestroy(papszVal);
    2044             :         }
    2045             :         else
    2046             :         {
    2047          10 :             poFeature->SetField(nField, json_object_get_string(poVal));
    2048             :         }
    2049             :     }
    2050             :     else
    2051             :     {
    2052        2339 :         poFeature->SetField(nField, json_object_get_string(poVal));
    2053             :     }
    2054             : }
    2055             : 
    2056             : /************************************************************************/
    2057             : /*                           ReadFeature()                              */
    2058             : /************************************************************************/
    2059             : 
    2060        1558 : OGRFeature *OGRGeoJSONBaseReader::ReadFeature(OGRLayer *poLayer,
    2061             :                                               json_object *poObj,
    2062             :                                               const char *pszSerializedObj)
    2063             : {
    2064        1558 :     CPLAssert(nullptr != poObj);
    2065             : 
    2066        1558 :     OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
    2067        1558 :     OGRFeature *poFeature = new OGRFeature(poFDefn);
    2068             : 
    2069        1558 :     if (bStoreNativeData_)
    2070             :     {
    2071         430 :         poFeature->SetNativeData(pszSerializedObj
    2072             :                                      ? pszSerializedObj
    2073          10 :                                      : json_object_to_json_string(poObj));
    2074         420 :         poFeature->SetNativeMediaType("application/vnd.geo+json");
    2075             :     }
    2076             : 
    2077             :     /* -------------------------------------------------------------------- */
    2078             :     /*      Translate GeoJSON "properties" object to feature attributes.    */
    2079             :     /* -------------------------------------------------------------------- */
    2080        1558 :     CPLAssert(nullptr != poFeature);
    2081             : 
    2082        1558 :     json_object *poObjProps = OGRGeoJSONFindMemberByName(poObj, "properties");
    2083        3075 :     if (!bAttributesSkip_ && nullptr != poObjProps &&
    2084        1517 :         json_object_get_type(poObjProps) == json_type_object)
    2085             :     {
    2086        1516 :         if (bIsGeocouchSpatiallistFormat)
    2087             :         {
    2088           3 :             json_object *poId = CPL_json_object_object_get(poObjProps, "_id");
    2089           6 :             if (poId != nullptr &&
    2090           3 :                 json_object_get_type(poId) == json_type_string)
    2091           3 :                 poFeature->SetField("_id", json_object_get_string(poId));
    2092             : 
    2093           3 :             json_object *poRev = CPL_json_object_object_get(poObjProps, "_rev");
    2094           6 :             if (poRev != nullptr &&
    2095           3 :                 json_object_get_type(poRev) == json_type_string)
    2096             :             {
    2097           3 :                 poFeature->SetField("_rev", json_object_get_string(poRev));
    2098             :             }
    2099             : 
    2100           3 :             poObjProps = CPL_json_object_object_get(poObjProps, "properties");
    2101           6 :             if (nullptr == poObjProps ||
    2102           3 :                 json_object_get_type(poObjProps) != json_type_object)
    2103             :             {
    2104           0 :                 return poFeature;
    2105             :             }
    2106             :         }
    2107             : 
    2108             :         json_object_iter it;
    2109        1516 :         it.key = nullptr;
    2110        1516 :         it.val = nullptr;
    2111        1516 :         it.entry = nullptr;
    2112        5985 :         json_object_object_foreachC(poObjProps, it)
    2113             :         {
    2114        4469 :             const int nField = poFDefn->GetFieldIndexCaseSensitive(it.key);
    2115        4471 :             if (nField < 0 &&
    2116           2 :                 !(bFlattenNestedAttributes_ && it.val != nullptr &&
    2117           2 :                   json_object_get_type(it.val) == json_type_object))
    2118             :             {
    2119           0 :                 CPLDebug("GeoJSON", "Cannot find field %s", it.key);
    2120             :             }
    2121             :             else
    2122             :             {
    2123        4469 :                 OGRGeoJSONReaderSetField(poLayer, poFeature, nField, it.key,
    2124        4469 :                                          it.val, bFlattenNestedAttributes_,
    2125        4469 :                                          chNestedAttributeSeparator_);
    2126             :             }
    2127             :         }
    2128             :     }
    2129             : 
    2130        1558 :     if (!bAttributesSkip_ && nullptr == poObjProps)
    2131             :     {
    2132             :         json_object_iter it;
    2133          41 :         it.key = nullptr;
    2134          41 :         it.val = nullptr;
    2135          41 :         it.entry = nullptr;
    2136         137 :         json_object_object_foreachC(poObj, it)
    2137             :         {
    2138          96 :             const int nFldIndex = poFDefn->GetFieldIndexCaseSensitive(it.key);
    2139          96 :             if (nFldIndex >= 0)
    2140             :             {
    2141           4 :                 if (it.val)
    2142           4 :                     poFeature->SetField(nFldIndex,
    2143             :                                         json_object_get_string(it.val));
    2144             :                 else
    2145           0 :                     poFeature->SetFieldNull(nFldIndex);
    2146             :             }
    2147             :         }
    2148             :     }
    2149             : 
    2150             :     /* -------------------------------------------------------------------- */
    2151             :     /*      Try to use feature-level ID if available                        */
    2152             :     /*      and of integral type. Otherwise, leave unset (-1) then index    */
    2153             :     /*      in features sequence will be used as FID.                       */
    2154             :     /* -------------------------------------------------------------------- */
    2155        1558 :     json_object *poObjId = OGRGeoJSONFindMemberByName(poObj, "id");
    2156        1558 :     if (nullptr != poObjId && bFeatureLevelIdAsFID_)
    2157             :     {
    2158          57 :         poFeature->SetFID(static_cast<GIntBig>(json_object_get_int64(poObjId)));
    2159             :     }
    2160             : 
    2161             :     /* -------------------------------------------------------------------- */
    2162             :     /*      Handle the case where the special id is in a regular field.     */
    2163             :     /* -------------------------------------------------------------------- */
    2164        1501 :     else if (nullptr != poObjId)
    2165             :     {
    2166          45 :         const int nIdx = poFDefn->GetFieldIndexCaseSensitive("id");
    2167          45 :         if (nIdx >= 0 && !poFeature->IsFieldSet(nIdx))
    2168             :         {
    2169          41 :             poFeature->SetField(nIdx, json_object_get_string(poObjId));
    2170             :         }
    2171             :     }
    2172             : 
    2173             :     /* -------------------------------------------------------------------- */
    2174             :     /*      Translate geometry sub-object of GeoJSON Feature.               */
    2175             :     /* -------------------------------------------------------------------- */
    2176        1558 :     json_object *poObjGeom = nullptr;
    2177        1558 :     json_object *poTmp = poObj;
    2178             :     json_object_iter it;
    2179        1558 :     it.key = nullptr;
    2180        1558 :     it.val = nullptr;
    2181        1558 :     it.entry = nullptr;
    2182        5956 :     json_object_object_foreachC(poTmp, it)
    2183             :     {
    2184        4741 :         if (EQUAL(it.key, "geometry"))
    2185             :         {
    2186        1531 :             if (it.val != nullptr)
    2187        1188 :                 poObjGeom = it.val;
    2188             :             // Done.  They had 'geometry':null.
    2189             :             else
    2190         343 :                 return poFeature;
    2191             :         }
    2192             :     }
    2193             : 
    2194        1215 :     if (nullptr != poObjGeom)
    2195             :     {
    2196             :         // NOTE: If geometry can not be parsed or read correctly
    2197             :         //       then NULL geometry is assigned to a feature and
    2198             :         //       geometry type for layer is classified as wkbUnknown.
    2199             :         OGRGeometry *poGeometry =
    2200        1188 :             ReadGeometry(poObjGeom, poLayer->GetSpatialRef());
    2201        1188 :         if (nullptr != poGeometry)
    2202             :         {
    2203        1174 :             poFeature->SetGeometryDirectly(poGeometry);
    2204             :         }
    2205             :     }
    2206             :     else
    2207             :     {
    2208             :         static bool bWarned = false;
    2209          27 :         if (!bWarned)
    2210             :         {
    2211           1 :             bWarned = true;
    2212           1 :             CPLDebug(
    2213             :                 "GeoJSON",
    2214             :                 "Non conformant Feature object. Missing \'geometry\' member.");
    2215             :         }
    2216             :     }
    2217             : 
    2218        1215 :     return poFeature;
    2219             : }
    2220             : 
    2221             : /************************************************************************/
    2222             : /*                           Extent getters                             */
    2223             : /************************************************************************/
    2224             : 
    2225          30 : bool OGRGeoJSONBaseReader::ExtentRead() const
    2226             : {
    2227          30 :     return m_bExtentRead;
    2228             : }
    2229             : 
    2230          24 : OGREnvelope3D OGRGeoJSONBaseReader::GetExtent3D() const
    2231             : {
    2232          24 :     return m_oEnvelope3D;
    2233             : }
    2234             : 
    2235             : /************************************************************************/
    2236             : /*                           ReadFeatureCollection()                    */
    2237             : /************************************************************************/
    2238             : 
    2239          92 : void OGRGeoJSONReader::ReadFeatureCollection(OGRGeoJSONLayer *poLayer,
    2240             :                                              json_object *poObj)
    2241             : {
    2242          92 :     json_object *poObjFeatures = OGRGeoJSONFindMemberByName(poObj, "features");
    2243          92 :     if (nullptr == poObjFeatures)
    2244             :     {
    2245           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2246             :                  "Invalid FeatureCollection object. "
    2247             :                  "Missing \'features\' member.");
    2248           0 :         return;
    2249             :     }
    2250             : 
    2251          92 :     if (json_type_array == json_object_get_type(poObjFeatures))
    2252             :     {
    2253          92 :         const auto nFeatures = json_object_array_length(poObjFeatures);
    2254         206 :         for (auto i = decltype(nFeatures){0}; i < nFeatures; ++i)
    2255             :         {
    2256             :             json_object *poObjFeature =
    2257         114 :                 json_object_array_get_idx(poObjFeatures, i);
    2258         114 :             OGRFeature *poFeature = ReadFeature(poLayer, poObjFeature, nullptr);
    2259         114 :             AddFeature(poLayer, poFeature);
    2260             :         }
    2261             :     }
    2262             : 
    2263             :     // Collect top objects except 'type' and the 'features' array.
    2264          92 :     if (bStoreNativeData_)
    2265             :     {
    2266             :         json_object_iter it;
    2267           5 :         it.key = nullptr;
    2268           5 :         it.val = nullptr;
    2269           5 :         it.entry = nullptr;
    2270          10 :         CPLString osNativeData;
    2271          25 :         json_object_object_foreachC(poObj, it)
    2272             :         {
    2273          20 :             if (strcmp(it.key, "type") == 0 || strcmp(it.key, "features") == 0)
    2274             :             {
    2275          10 :                 continue;
    2276             :             }
    2277          10 :             if (osNativeData.empty())
    2278           3 :                 osNativeData = "{ ";
    2279             :             else
    2280           7 :                 osNativeData += ", ";
    2281          10 :             json_object *poKey = json_object_new_string(it.key);
    2282          10 :             osNativeData += json_object_to_json_string(poKey);
    2283          10 :             json_object_put(poKey);
    2284          10 :             osNativeData += ": ";
    2285          10 :             osNativeData += json_object_to_json_string(it.val);
    2286             :         }
    2287           5 :         if (osNativeData.empty())
    2288             :         {
    2289           2 :             osNativeData = "{ ";
    2290             :         }
    2291           5 :         osNativeData += " }";
    2292             : 
    2293           5 :         osNativeData = "NATIVE_DATA=" + osNativeData;
    2294             : 
    2295           5 :         char *apszMetadata[3] = {
    2296           5 :             const_cast<char *>(osNativeData.c_str()),
    2297             :             const_cast<char *>("NATIVE_MEDIA_TYPE=application/vnd.geo+json"),
    2298           5 :             nullptr};
    2299             : 
    2300           5 :         poLayer->SetMetadata(apszMetadata, "NATIVE_DATA");
    2301             :     }
    2302             : }
    2303             : 
    2304             : /************************************************************************/
    2305             : /*                          OGRGeoJSONGetExtent3D()                     */
    2306             : /************************************************************************/
    2307             : 
    2308        4451 : bool OGRGeoJSONGetExtent3D(json_object *poObj, OGREnvelope3D *poEnvelope)
    2309             : {
    2310        4451 :     if (!poEnvelope || !poObj)
    2311             :     {
    2312           0 :         return false;
    2313             :     }
    2314             : 
    2315             :     // poObjCoords can be an array of arrays, this lambda function will
    2316             :     // recursively parse the array
    2317        8902 :     std::function<bool(json_object *, OGREnvelope3D *)> fParseCoords;
    2318      194494 :     fParseCoords = [&fParseCoords](json_object *poObjCoordsIn,
    2319      190039 :                                    OGREnvelope3D *poEnvelopeIn) -> bool
    2320             :     {
    2321      194494 :         if (json_type_array == json_object_get_type(poObjCoordsIn))
    2322             :         {
    2323      194494 :             const auto nItems = json_object_array_length(poObjCoordsIn);
    2324             : 
    2325      194494 :             double dXVal = std::numeric_limits<double>::quiet_NaN();
    2326      194494 :             double dYVal = std::numeric_limits<double>::quiet_NaN();
    2327      194494 :             double dZVal = std::numeric_limits<double>::quiet_NaN();
    2328             : 
    2329      756072 :             for (auto i = decltype(nItems){0}; i < nItems; ++i)
    2330             :             {
    2331             : 
    2332             :                 // Get the i element
    2333             :                 json_object *poObjCoordsElement =
    2334      561595 :                     json_object_array_get_idx(poObjCoordsIn, i);
    2335             : 
    2336      561595 :                 const json_type eType{json_object_get_type(poObjCoordsElement)};
    2337             : 
    2338             :                 // if it is an array, recurse
    2339      561595 :                 if (json_type_array == eType)
    2340             :                 {
    2341      190039 :                     if (!fParseCoords(poObjCoordsElement, poEnvelopeIn))
    2342             :                     {
    2343           1 :                         return false;
    2344             :                     }
    2345             :                 }
    2346      371556 :                 else if (json_type_double == eType || json_type_int == eType)
    2347             :                 {
    2348      371540 :                     switch (i)
    2349             :                     {
    2350      185650 :                         case 0:
    2351             :                         {
    2352      185650 :                             dXVal = json_object_get_double(poObjCoordsElement);
    2353      185650 :                             break;
    2354             :                         }
    2355      185649 :                         case 1:
    2356             :                         {
    2357      185649 :                             dYVal = json_object_get_double(poObjCoordsElement);
    2358      185649 :                             break;
    2359             :                         }
    2360         241 :                         case 2:
    2361             :                         {
    2362         241 :                             dZVal = json_object_get_double(poObjCoordsElement);
    2363         241 :                             break;
    2364             :                         }
    2365           0 :                         default:
    2366           0 :                             return false;
    2367             :                     }
    2368             :                 }
    2369             :                 else
    2370             :                 {
    2371          16 :                     return false;
    2372             :                 }
    2373             :             }
    2374             : 
    2375      194477 :             if (!std::isnan(dXVal) && !std::isnan(dYVal))
    2376             :             {
    2377      185648 :                 if (std::isnan(dZVal))
    2378             :                 {
    2379             :                     static_cast<OGREnvelope *>(poEnvelopeIn)
    2380      185407 :                         ->Merge(dXVal, dYVal);
    2381             :                 }
    2382             :                 else
    2383             :                 {
    2384         241 :                     poEnvelopeIn->Merge(dXVal, dYVal, dZVal);
    2385             :                 }
    2386             :             }
    2387             : 
    2388      194477 :             return true;
    2389             :         }
    2390             :         else
    2391             :         {
    2392           0 :             return false;
    2393             :         }
    2394        4451 :     };
    2395             : 
    2396             :     // This function looks for "coordinates" and for "geometries" to handle
    2397             :     // geometry collections.  It will recurse on itself to handle nested geometry.
    2398        8902 :     std::function<bool(json_object *, OGREnvelope3D *)> fParseGeometry;
    2399        4473 :     fParseGeometry = [&fParseGeometry,
    2400             :                       &fParseCoords](json_object *poObjIn,
    2401        4477 :                                      OGREnvelope3D *poEnvelopeIn) -> bool
    2402             :     {
    2403             :         // Get the "coordinates" array from the JSON object
    2404             :         json_object *poObjCoords =
    2405        4473 :             OGRGeoJSONFindMemberByName(poObjIn, "coordinates");
    2406             : 
    2407             :         // Return if found and not an array
    2408        4473 :         if (poObjCoords && json_object_get_type(poObjCoords) != json_type_array)
    2409             :         {
    2410           0 :             return false;
    2411             :         }
    2412        4473 :         else if (poObjCoords)
    2413             :         {
    2414        4455 :             return fParseCoords(poObjCoords, poEnvelopeIn);
    2415             :         }
    2416             : 
    2417             :         // Try "geometries"
    2418          18 :         if (!poObjCoords)
    2419             :         {
    2420          18 :             poObjCoords = OGRGeoJSONFindMemberByName(poObjIn, "geometries");
    2421             :         }
    2422             : 
    2423             :         // Return if not found or not an array
    2424          28 :         if (!poObjCoords ||
    2425          10 :             json_object_get_type(poObjCoords) != json_type_array)
    2426             :         {
    2427           8 :             return false;
    2428             :         }
    2429             :         else
    2430             :         {
    2431             :             // Loop thgrough the geometries
    2432          10 :             const auto nItems = json_object_array_length(poObjCoords);
    2433          30 :             for (auto i = decltype(nItems){0}; i < nItems; ++i)
    2434             :             {
    2435             :                 json_object *poObjGeometry =
    2436          22 :                     json_object_array_get_idx(poObjCoords, i);
    2437             : 
    2438             :                 // Recurse
    2439          22 :                 if (!fParseGeometry(poObjGeometry, poEnvelopeIn))
    2440             :                 {
    2441           2 :                     return false;
    2442             :                 }
    2443             :             }
    2444           8 :             return true;
    2445             :         }
    2446        4451 :     };
    2447             : 
    2448        4451 :     return fParseGeometry(poObj, poEnvelope);
    2449             : }

Generated by: LCOV version 1.14