Coverage Report

Created: 2025-06-13 06:29

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