Coverage Report

Created: 2026-09-26 08:22

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