Coverage Report

Created: 2026-07-25 06:50

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