Coverage Report

Created: 2025-11-15 08:43

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