Coverage Report

Created: 2025-11-16 06:25

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