Coverage Report

Created: 2025-11-16 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrgeojsongeometry.cpp
Line
Count
Source
1
// SPDX-License-Identifier: MIT
2
// Copyright 2007, Mateusz Loskot
3
// Copyright 2008-2024, Even Rouault <even.rouault at spatialys.com>
4
5
/*! @cond Doxygen_Suppress */
6
7
#include "ogrgeojsongeometry.h"
8
#include "ogrlibjsonutils.h"
9
10
#include "ogr_geometry.h"
11
#include "ogr_spatialref.h"
12
13
static std::unique_ptr<OGRPoint> OGRGeoJSONReadPoint(json_object *poObj,
14
                                                     bool bHasM);
15
static std::unique_ptr<OGRMultiPoint>
16
OGRGeoJSONReadMultiPoint(json_object *poObj, bool bHasM);
17
static std::unique_ptr<OGRLineString>
18
OGRGeoJSONReadLineString(json_object *poObj, bool bHasM, bool bRaw);
19
static std::unique_ptr<OGRMultiLineString>
20
OGRGeoJSONReadMultiLineString(json_object *poObj, bool bHasM);
21
static std::unique_ptr<OGRLinearRing>
22
OGRGeoJSONReadLinearRing(json_object *poObj, bool bHasM);
23
static std::unique_ptr<OGRMultiPolygon>
24
OGRGeoJSONReadMultiPolygon(json_object *poObj, bool bHasM);
25
static std::unique_ptr<OGRGeometryCollection>
26
OGRGeoJSONReadGeometryCollection(json_object *poObj, bool bHasM,
27
                                 const OGRSpatialReference *poSRS);
28
static std::unique_ptr<OGRCircularString>
29
OGRGeoJSONReadCircularString(json_object *poObj, bool bHasM);
30
static std::unique_ptr<OGRCompoundCurve>
31
OGRGeoJSONReadCompoundCurve(json_object *poObj, bool bHasM,
32
                            const OGRSpatialReference *poSRS);
33
static std::unique_ptr<OGRCurvePolygon>
34
OGRGeoJSONReadCurvePolygon(json_object *poObj, bool bHasM);
35
static std::unique_ptr<OGRMultiCurve>
36
OGRGeoJSONReadMultiCurve(json_object *poObj, bool bHasM,
37
                         const OGRSpatialReference *poSRS);
38
static std::unique_ptr<OGRMultiSurface>
39
OGRGeoJSONReadMultiSurface(json_object *poObj, bool bHasM,
40
                           const OGRSpatialReference *poSRS);
41
42
/************************************************************************/
43
/*                           OGRGeoJSONGetType                          */
44
/************************************************************************/
45
46
GeoJSONObject::Type OGRGeoJSONGetType(json_object *poObj)
47
0
{
48
0
    if (nullptr == poObj)
49
0
        return GeoJSONObject::eUnknown;
50
51
0
    json_object *poObjType = OGRGeoJSONFindMemberByName(poObj, "type");
52
0
    if (nullptr == poObjType)
53
0
        return GeoJSONObject::eUnknown;
54
55
0
    const char *name = json_object_get_string(poObjType);
56
57
0
#define ASSOC(x)                                                               \
58
0
    {                                                                          \
59
0
#x, GeoJSONObject::e##x                                                \
60
0
    }
61
62
0
    static const struct
63
0
    {
64
0
        const char *pszName;
65
0
        GeoJSONObject::Type eType;
66
0
    } tabAssoc[] = {
67
0
        ASSOC(Point),
68
0
        ASSOC(LineString),
69
0
        ASSOC(Polygon),
70
0
        ASSOC(MultiPoint),
71
0
        ASSOC(MultiLineString),
72
0
        ASSOC(MultiPolygon),
73
0
        ASSOC(GeometryCollection),
74
0
        ASSOC(CircularString),
75
0
        ASSOC(CompoundCurve),
76
0
        ASSOC(CurvePolygon),
77
0
        ASSOC(MultiCurve),
78
0
        ASSOC(MultiSurface),
79
0
        ASSOC(Feature),
80
0
        ASSOC(FeatureCollection),
81
0
    };
82
83
0
#undef ASSOC
84
85
0
    for (const auto &assoc : tabAssoc)
86
0
    {
87
0
        if (EQUAL(name, assoc.pszName))
88
0
            return assoc.eType;
89
0
    }
90
91
0
    return GeoJSONObject::eUnknown;
92
0
}
93
94
/************************************************************************/
95
/*                       OGRJSONFGHasMeasure()                          */
96
/************************************************************************/
97
98
bool OGRJSONFGHasMeasure(json_object *poObj, bool bUpperLevelMValue)
99
0
{
100
0
    bool bHasM = bUpperLevelMValue;
101
0
    if (json_object *pojMeasures =
102
0
            CPL_json_object_object_get(poObj, "measures"))
103
0
    {
104
0
        json_object *poEnabled =
105
0
            CPL_json_object_object_get(pojMeasures, "enabled");
106
0
        bHasM = json_object_get_boolean(poEnabled);
107
0
    }
108
0
    return bHasM;
109
0
}
110
111
/************************************************************************/
112
/*                          asAssocGeometryTypes[]                      */
113
/************************************************************************/
114
115
#define ASSOC(x)                                                               \
116
    {                                                                          \
117
#x, wkb##x                                                             \
118
    }
119
120
static const struct
121
{
122
    const char *pszName;
123
    OGRwkbGeometryType eType;
124
} asAssocGeometryTypes[] = {
125
    ASSOC(Point),
126
    ASSOC(LineString),
127
    ASSOC(Polygon),
128
    ASSOC(MultiPoint),
129
    ASSOC(MultiLineString),
130
    ASSOC(MultiPolygon),
131
    ASSOC(GeometryCollection),
132
    ASSOC(CircularString),
133
    ASSOC(CompoundCurve),
134
    ASSOC(CurvePolygon),
135
    ASSOC(MultiCurve),
136
    ASSOC(MultiSurface),
137
};
138
139
#undef ASSOC
140
141
/************************************************************************/
142
/*                   OGRGeoJSONGetOGRGeometryType()                     */
143
/************************************************************************/
144
145
OGRwkbGeometryType OGRGeoJSONGetOGRGeometryType(json_object *poObj, bool bHasM)
146
0
{
147
0
    if (nullptr == poObj)
148
0
        return wkbUnknown;
149
150
0
    json_object *poObjType = CPL_json_object_object_get(poObj, "type");
151
0
    if (nullptr == poObjType)
152
0
        return wkbUnknown;
153
154
0
    const char *name = json_object_get_string(poObjType);
155
156
0
    OGRwkbGeometryType eType = wkbNone;
157
0
    for (const auto &assoc : asAssocGeometryTypes)
158
0
    {
159
0
        if (EQUAL(name, assoc.pszName))
160
0
        {
161
0
            eType = assoc.eType;
162
0
            break;
163
0
        }
164
0
    }
165
0
    if (eType == wkbNone)
166
0
        return wkbUnknown;
167
168
0
    bHasM = OGRJSONFGHasMeasure(poObj, bHasM);
169
170
0
    json_object *poCoordinates;
171
0
    if (eType == wkbGeometryCollection || eType == wkbMultiCurve ||
172
0
        eType == wkbMultiSurface || eType == wkbCompoundCurve ||
173
0
        eType == wkbCurvePolygon)
174
0
    {
175
0
        json_object *poGeometries =
176
0
            CPL_json_object_object_get(poObj, "geometries");
177
0
        if (poGeometries &&
178
0
            json_object_get_type(poGeometries) == json_type_array &&
179
0
            json_object_array_length(poGeometries) > 0)
180
0
        {
181
0
            const auto subGeomType = OGRGeoJSONGetOGRGeometryType(
182
0
                json_object_array_get_idx(poGeometries, 0), bHasM);
183
0
            if (OGR_GT_HasZ(subGeomType))
184
0
                eType = OGR_GT_SetZ(eType);
185
0
        }
186
0
    }
187
0
    else
188
0
    {
189
0
        poCoordinates = CPL_json_object_object_get(poObj, "coordinates");
190
0
        if (poCoordinates &&
191
0
            json_object_get_type(poCoordinates) == json_type_array &&
192
0
            json_object_array_length(poCoordinates) > 0)
193
0
        {
194
0
            while (true)
195
0
            {
196
0
                auto poChild = json_object_array_get_idx(poCoordinates, 0);
197
0
                if (!(poChild &&
198
0
                      json_object_get_type(poChild) == json_type_array &&
199
0
                      json_object_array_length(poChild) > 0))
200
0
                {
201
0
                    const auto nLength =
202
0
                        json_object_array_length(poCoordinates);
203
0
                    if ((bHasM && nLength == 4) || (!bHasM && nLength == 3))
204
0
                        eType = OGR_GT_SetZ(eType);
205
0
                    break;
206
0
                }
207
0
                poCoordinates = poChild;
208
0
            }
209
0
        }
210
0
    }
211
0
    if (bHasM)
212
0
        eType = OGR_GT_SetM(eType);
213
214
0
    return eType;
215
0
}
216
217
/************************************************************************/
218
/*                           OGRGeoJSONGetGeometryName()                */
219
/************************************************************************/
220
221
const char *OGRGeoJSONGetGeometryName(OGRGeometry const *poGeometry)
222
0
{
223
0
    CPLAssert(nullptr != poGeometry);
224
225
0
    const OGRwkbGeometryType eType = wkbFlatten(poGeometry->getGeometryType());
226
227
0
    for (const auto &assoc : asAssocGeometryTypes)
228
0
    {
229
0
        if (eType == assoc.eType)
230
0
        {
231
0
            return assoc.pszName;
232
0
        }
233
0
    }
234
0
    return "Unknown";
235
0
}
236
237
/************************************************************************/
238
/*                           OGRGeoJSONReadGeometry                     */
239
/************************************************************************/
240
241
std::unique_ptr<OGRGeometry>
242
OGRGeoJSONReadGeometry(json_object *poObj, bool bHasM,
243
                       const OGRSpatialReference *poParentSRS)
244
0
{
245
246
0
    std::unique_ptr<OGRGeometry> poGeometry;
247
0
    OGRSpatialReference *poSRS = nullptr;
248
0
    lh_entry *entry = OGRGeoJSONFindMemberEntryByName(poObj, "crs");
249
0
    if (entry != nullptr)
250
0
    {
251
0
        json_object *poObjSrs =
252
0
            static_cast<json_object *>(const_cast<void *>(entry->v));
253
0
        if (poObjSrs != nullptr)
254
0
        {
255
0
            poSRS = OGRGeoJSONReadSpatialReference(poObj);
256
0
        }
257
0
    }
258
259
0
    const OGRSpatialReference *poSRSToAssign = nullptr;
260
0
    if (entry != nullptr)
261
0
    {
262
0
        poSRSToAssign = poSRS;
263
0
    }
264
0
    else if (poParentSRS)
265
0
    {
266
0
        poSRSToAssign = poParentSRS;
267
0
    }
268
0
    else
269
0
    {
270
        // Assign WGS84 if no CRS defined on geometry.
271
0
        poSRSToAssign = OGRSpatialReference::GetWGS84SRS();
272
0
    }
273
274
0
    bHasM = OGRJSONFGHasMeasure(poObj, bHasM);
275
276
0
    const auto objType = OGRGeoJSONGetType(poObj);
277
0
    switch (objType)
278
0
    {
279
0
        case GeoJSONObject::ePoint:
280
0
            poGeometry = OGRGeoJSONReadPoint(poObj, bHasM);
281
0
            break;
282
283
0
        case GeoJSONObject::eLineString:
284
0
            poGeometry = OGRGeoJSONReadLineString(poObj, bHasM,
285
0
                                                  /* bRaw = */ false);
286
0
            break;
287
288
0
        case GeoJSONObject::ePolygon:
289
0
            poGeometry =
290
0
                OGRGeoJSONReadPolygon(poObj, bHasM, /* bRaw = */ false);
291
0
            break;
292
293
0
        case GeoJSONObject::eMultiPoint:
294
0
            poGeometry = OGRGeoJSONReadMultiPoint(poObj, bHasM);
295
0
            break;
296
297
0
        case GeoJSONObject::eMultiLineString:
298
0
            poGeometry = OGRGeoJSONReadMultiLineString(poObj, bHasM);
299
0
            break;
300
301
0
        case GeoJSONObject::eMultiPolygon:
302
0
            poGeometry = OGRGeoJSONReadMultiPolygon(poObj, bHasM);
303
0
            break;
304
305
0
        case GeoJSONObject::eGeometryCollection:
306
0
            poGeometry =
307
0
                OGRGeoJSONReadGeometryCollection(poObj, bHasM, poSRSToAssign);
308
0
            break;
309
310
0
        case GeoJSONObject::eCircularString:
311
0
            poGeometry = OGRGeoJSONReadCircularString(poObj, bHasM);
312
0
            break;
313
314
0
        case GeoJSONObject::eCompoundCurve:
315
0
            poGeometry =
316
0
                OGRGeoJSONReadCompoundCurve(poObj, bHasM, poSRSToAssign);
317
0
            break;
318
319
0
        case GeoJSONObject::eCurvePolygon:
320
0
            poGeometry = OGRGeoJSONReadCurvePolygon(poObj, bHasM);
321
0
            break;
322
323
0
        case GeoJSONObject::eMultiCurve:
324
0
            poGeometry = OGRGeoJSONReadMultiCurve(poObj, bHasM, poSRSToAssign);
325
0
            break;
326
327
0
        case GeoJSONObject::eMultiSurface:
328
0
            poGeometry =
329
0
                OGRGeoJSONReadMultiSurface(poObj, bHasM, poSRSToAssign);
330
0
            break;
331
332
0
        case GeoJSONObject::eFeature:
333
0
        case GeoJSONObject::eFeatureCollection:
334
0
            [[fallthrough]];
335
0
        case GeoJSONObject::eUnknown:
336
0
            CPLError(CE_Warning, CPLE_AppDefined,
337
0
                     "Unsupported geometry type detected. "
338
0
                     "Feature gets NULL geometry assigned.");
339
0
            break;
340
0
    }
341
342
0
    if (poGeometry && GeoJSONObject::eGeometryCollection != objType)
343
0
        poGeometry->assignSpatialReference(poSRSToAssign);
344
345
0
    if (poSRS)
346
0
        poSRS->Release();
347
348
0
    return poGeometry;
349
0
}
350
351
/************************************************************************/
352
/*                       GetJSONConstructName()                         */
353
/************************************************************************/
354
355
static const char *GetJSONConstructName(json_type eType)
356
0
{
357
0
    switch (eType)
358
0
    {
359
0
        case json_type_null:
360
0
            break;
361
0
        case json_type_boolean:
362
0
            return "boolean";
363
0
        case json_type_double:
364
0
            return "double";
365
0
        case json_type_int:
366
0
            return "int";
367
0
        case json_type_object:
368
0
            return "object";
369
0
        case json_type_array:
370
0
            return "array";
371
0
        case json_type_string:
372
0
            return "string";
373
0
    }
374
0
    return "null";
375
0
}
376
377
/************************************************************************/
378
/*                        OGRGeoJSONGetCoordinate()                     */
379
/************************************************************************/
380
381
static double OGRGeoJSONGetCoordinate(json_object *poObj,
382
                                      const char *pszCoordName, int nIndex,
383
                                      bool &bValid)
384
0
{
385
0
    json_object *poObjCoord = json_object_array_get_idx(poObj, nIndex);
386
0
    if (nullptr == poObjCoord)
387
0
    {
388
0
        CPLDebug("GeoJSON", "Point: got null object for %s.", pszCoordName);
389
0
        bValid = false;
390
0
        return 0.0;
391
0
    }
392
393
0
    const json_type eType = json_object_get_type(poObjCoord);
394
0
    if (json_type_double != eType && json_type_int != eType)
395
0
    {
396
0
        CPLError(CE_Failure, CPLE_AppDefined,
397
0
                 "OGRGeoJSONGetCoordinate(): invalid '%s' coordinate. "
398
0
                 "Unexpected type %s for '%s'. Expected double or integer.",
399
0
                 pszCoordName, GetJSONConstructName(eType),
400
0
                 json_object_to_json_string(poObjCoord));
401
0
        bValid = false;
402
0
        return 0.0;
403
0
    }
404
405
0
    return json_object_get_double(poObjCoord);
406
0
}
407
408
/************************************************************************/
409
/*                           OGRGeoJSONReadRawPoint                     */
410
/************************************************************************/
411
412
static bool OGRGeoJSONReadRawPoint(json_object *poObj, OGRPoint &point,
413
                                   bool bHasM)
414
0
{
415
0
    if (json_type_array == json_object_get_type(poObj))
416
0
    {
417
0
        const int nSize = static_cast<int>(json_object_array_length(poObj));
418
419
0
        if (nSize < GeoJSONObject::eMinCoordinateDimension)
420
0
        {
421
0
            CPLError(CE_Warning, CPLE_AppDefined,
422
0
                     "OGRGeoJSONReadRawPoint(): "
423
0
                     "Invalid coord dimension for '%s'. "
424
0
                     "At least 2 dimensions must be present.",
425
0
                     json_object_to_json_string(poObj));
426
0
            return false;
427
0
        }
428
429
0
        bool bValid = true;
430
0
        const double dfX = OGRGeoJSONGetCoordinate(poObj, "x", 0, bValid);
431
0
        const double dfY = OGRGeoJSONGetCoordinate(poObj, "y", 1, bValid);
432
0
        point.setX(dfX);
433
0
        point.setY(dfY);
434
435
        // Read Z and/or M coordinate.
436
0
        if (nSize > GeoJSONObject::eMinCoordinateDimension)
437
0
        {
438
0
            const int nMaxDim =
439
0
                bHasM ? GeoJSONObject::eMaxCoordinateDimensionJSONFG
440
0
                      : GeoJSONObject::eMaxCoordinateDimensionGeoJSON;
441
0
            if (nSize > nMaxDim)
442
0
            {
443
0
                CPLErrorOnce(CE_Warning, CPLE_AppDefined,
444
0
                             "OGRGeoJSONReadRawPoint(): too many members in "
445
0
                             "array '%s': %d. At most %d are handled. Ignoring "
446
0
                             "extra members.",
447
0
                             json_object_to_json_string(poObj), nSize, nMaxDim);
448
0
            }
449
            // Don't *expect* mixed-dimension geometries, although the
450
            // spec doesn't explicitly forbid this.
451
0
            if (nSize == 4 || (nSize == 3 && !bHasM))
452
0
            {
453
0
                const double dfZ =
454
0
                    OGRGeoJSONGetCoordinate(poObj, "z", 2, bValid);
455
0
                point.setZ(dfZ);
456
0
            }
457
458
0
            if (bHasM)
459
0
            {
460
0
                const double dfM =
461
0
                    OGRGeoJSONGetCoordinate(poObj, "m", nSize - 1, bValid);
462
0
                point.setM(dfM);
463
0
            }
464
0
        }
465
0
        else
466
0
        {
467
0
            point.flattenTo2D();
468
0
        }
469
0
        return bValid;
470
0
    }
471
0
    else
472
0
    {
473
0
        CPLError(CE_Failure, CPLE_AppDefined,
474
0
                 "OGRGeoJSONReadRawPoint(): invalid Point. "
475
0
                 "Unexpected type %s for '%s'. Expected array.",
476
0
                 GetJSONConstructName(json_object_get_type(poObj)),
477
0
                 json_object_to_json_string(poObj));
478
0
    }
479
480
0
    return false;
481
0
}
482
483
/************************************************************************/
484
/*                           OGRGeoJSONReadPoint                        */
485
/************************************************************************/
486
487
std::unique_ptr<OGRPoint> OGRGeoJSONReadPoint(json_object *poObj, bool bHasM)
488
0
{
489
0
    if (!poObj)
490
0
    {
491
0
        CPLError(CE_Failure, CPLE_AppDefined,
492
0
                 "OGRGeoJSONReadPoint(): invalid Point object. Got null.");
493
0
        return nullptr;
494
0
    }
495
0
    json_object *poObjCoords = OGRGeoJSONFindMemberByName(poObj, "coordinates");
496
0
    if (nullptr == poObjCoords)
497
0
    {
498
0
        CPLError(CE_Failure, CPLE_AppDefined,
499
0
                 "OGRGeoJSONReadPoint(): invalid Point object. "
500
0
                 "Missing \'coordinates\' member.");
501
0
        return nullptr;
502
0
    }
503
504
0
    auto poPoint = std::make_unique<OGRPoint>();
505
0
    if (!OGRGeoJSONReadRawPoint(poObjCoords, *poPoint, bHasM))
506
0
    {
507
0
        return nullptr;
508
0
    }
509
510
0
    return poPoint;
511
0
}
512
513
/************************************************************************/
514
/*                           OGRGeoJSONReadMultiPoint                   */
515
/************************************************************************/
516
517
std::unique_ptr<OGRMultiPoint> OGRGeoJSONReadMultiPoint(json_object *poObj,
518
                                                        bool bHasM)
519
0
{
520
0
    if (!poObj)
521
0
    {
522
0
        CPLError(
523
0
            CE_Failure, CPLE_AppDefined,
524
0
            "OGRGeoJSONReadMultiPoint(): invalid MultiPoint object. Got null.");
525
0
        return nullptr;
526
0
    }
527
0
    json_object *poObjPoints = OGRGeoJSONFindMemberByName(poObj, "coordinates");
528
0
    if (nullptr == poObjPoints)
529
0
    {
530
0
        CPLError(CE_Failure, CPLE_AppDefined,
531
0
                 "Invalid MultiPoint object. "
532
0
                 "Missing \'coordinates\' member.");
533
0
        return nullptr;
534
0
    }
535
536
0
    std::unique_ptr<OGRMultiPoint> poMultiPoint;
537
0
    if (json_type_array == json_object_get_type(poObjPoints))
538
0
    {
539
0
        const auto nPoints = json_object_array_length(poObjPoints);
540
541
0
        poMultiPoint = std::make_unique<OGRMultiPoint>();
542
543
0
        for (auto i = decltype(nPoints){0}; i < nPoints; ++i)
544
0
        {
545
0
            json_object *poObjCoords =
546
0
                json_object_array_get_idx(poObjPoints, i);
547
548
0
            OGRPoint pt;
549
0
            if (!OGRGeoJSONReadRawPoint(poObjCoords, pt, bHasM))
550
0
            {
551
0
                return nullptr;
552
0
            }
553
0
            poMultiPoint->addGeometry(&pt);
554
0
        }
555
0
    }
556
0
    else
557
0
    {
558
0
        CPLError(CE_Failure, CPLE_AppDefined,
559
0
                 "OGRGeoJSONReadMultiPoint(): invalid MultiPoint. "
560
0
                 "Unexpected type %s for '%s'. Expected array.",
561
0
                 GetJSONConstructName(json_object_get_type(poObjPoints)),
562
0
                 json_object_to_json_string(poObjPoints));
563
0
    }
564
565
0
    return poMultiPoint;
566
0
}
567
568
/************************************************************************/
569
/*                         OGRGeoJSONReadSimpleCurve                    */
570
/************************************************************************/
571
572
template <class T>
573
static std::unique_ptr<T> OGRGeoJSONReadSimpleCurve(const char *pszFuncName,
574
                                                    json_object *poObj,
575
                                                    bool bHasM, bool bRaw)
576
0
{
577
0
    if (!poObj)
578
0
    {
579
0
        CPLError(CE_Failure, CPLE_AppDefined,
580
0
                 "%s(): invalid LineString object. Got null.", pszFuncName);
581
0
        return nullptr;
582
0
    }
583
0
    json_object *poObjPoints = nullptr;
584
585
0
    if (!bRaw)
586
0
    {
587
0
        poObjPoints = OGRGeoJSONFindMemberByName(poObj, "coordinates");
588
0
        if (nullptr == poObjPoints)
589
0
        {
590
0
            CPLError(CE_Failure, CPLE_AppDefined,
591
0
                     "Invalid LineString object. "
592
0
                     "Missing \'coordinates\' member.");
593
0
            return nullptr;
594
0
        }
595
0
    }
596
0
    else
597
0
    {
598
0
        poObjPoints = poObj;
599
0
    }
600
601
0
    std::unique_ptr<T> poLine;
602
603
0
    if (json_type_array == json_object_get_type(poObjPoints))
604
0
    {
605
0
        const int nPoints =
606
0
            static_cast<int>(json_object_array_length(poObjPoints));
607
608
0
        poLine = std::make_unique<T>();
609
0
        poLine->setNumPoints(nPoints);
610
611
0
        for (int i = 0; i < nPoints; ++i)
612
0
        {
613
0
            json_object *poObjCoords =
614
0
                json_object_array_get_idx(poObjPoints, i);
615
616
0
            OGRPoint pt;
617
0
            if (!OGRGeoJSONReadRawPoint(poObjCoords, pt, bHasM))
618
0
            {
619
0
                return nullptr;
620
0
            }
621
0
            if (pt.Is3D())
622
0
                poLine->set3D(true);
623
0
            if (pt.IsMeasured())
624
0
                poLine->setMeasured(true);
625
0
            poLine->setPoint(i, &pt);
626
0
        }
627
0
    }
628
0
    else
629
0
    {
630
0
        CPLError(CE_Failure, CPLE_AppDefined,
631
0
                 "%s(): invalid geometry. "
632
0
                 "Unexpected type %s for '%s'. Expected array.",
633
0
                 pszFuncName,
634
0
                 GetJSONConstructName(json_object_get_type(poObjPoints)),
635
0
                 json_object_to_json_string(poObjPoints));
636
0
    }
637
638
0
    return poLine;
639
0
}
Unexecuted instantiation: ogrgeojsongeometry.cpp:std::__1::unique_ptr<OGRLineString, std::__1::default_delete<OGRLineString> > OGRGeoJSONReadSimpleCurve<OGRLineString>(char const*, json_object*, bool, bool)
Unexecuted instantiation: ogrgeojsongeometry.cpp:std::__1::unique_ptr<OGRCircularString, std::__1::default_delete<OGRCircularString> > OGRGeoJSONReadSimpleCurve<OGRCircularString>(char const*, json_object*, bool, bool)
Unexecuted instantiation: ogrgeojsongeometry.cpp:std::__1::unique_ptr<OGRLinearRing, std::__1::default_delete<OGRLinearRing> > OGRGeoJSONReadSimpleCurve<OGRLinearRing>(char const*, json_object*, bool, bool)
640
641
/************************************************************************/
642
/*                           OGRGeoJSONReadLineString                   */
643
/************************************************************************/
644
645
std::unique_ptr<OGRLineString> OGRGeoJSONReadLineString(json_object *poObj,
646
                                                        bool bHasM, bool bRaw)
647
0
{
648
0
    return OGRGeoJSONReadSimpleCurve<OGRLineString>(__func__, poObj, bHasM,
649
0
                                                    bRaw);
650
0
}
651
652
/************************************************************************/
653
/*                        OGRGeoJSONReadCircularString                  */
654
/************************************************************************/
655
656
std::unique_ptr<OGRCircularString>
657
OGRGeoJSONReadCircularString(json_object *poObj, bool bHasM)
658
0
{
659
0
    return OGRGeoJSONReadSimpleCurve<OGRCircularString>(__func__, poObj, bHasM,
660
0
                                                        /* bRaw = */ false);
661
0
}
662
663
/************************************************************************/
664
/*                           OGRGeoJSONReadMultiLineString              */
665
/************************************************************************/
666
667
std::unique_ptr<OGRMultiLineString>
668
OGRGeoJSONReadMultiLineString(json_object *poObj, bool bHasM)
669
0
{
670
0
    CPLAssert(nullptr != poObj);
671
672
0
    json_object *poObjLines = OGRGeoJSONFindMemberByName(poObj, "coordinates");
673
0
    if (nullptr == poObjLines)
674
0
    {
675
0
        CPLError(CE_Failure, CPLE_AppDefined,
676
0
                 "Invalid MultiLineString object. "
677
0
                 "Missing \'coordinates\' member.");
678
0
        return nullptr;
679
0
    }
680
681
0
    std::unique_ptr<OGRMultiLineString> poMultiLine;
682
683
0
    if (json_type_array == json_object_get_type(poObjLines))
684
0
    {
685
0
        const auto nLines = json_object_array_length(poObjLines);
686
687
0
        poMultiLine = std::make_unique<OGRMultiLineString>();
688
689
0
        for (auto i = decltype(nLines){0}; i < nLines; ++i)
690
0
        {
691
0
            json_object *poObjLine = json_object_array_get_idx(poObjLines, i);
692
693
0
            auto poLine =
694
0
                OGRGeoJSONReadLineString(poObjLine, bHasM, /* bRaw = */ true);
695
0
            if (poLine)
696
0
            {
697
0
                poMultiLine->addGeometry(std::move(poLine));
698
0
            }
699
0
        }
700
0
    }
701
0
    else
702
0
    {
703
0
        CPLError(CE_Failure, CPLE_AppDefined,
704
0
                 "OGRGeoJSONReadLineString(): invalid LineString. "
705
0
                 "Unexpected type %s for '%s'. Expected array.",
706
0
                 GetJSONConstructName(json_object_get_type(poObjLines)),
707
0
                 json_object_to_json_string(poObjLines));
708
0
    }
709
710
0
    return poMultiLine;
711
0
}
712
713
/************************************************************************/
714
/*                           OGRGeoJSONReadLinearRing                   */
715
/************************************************************************/
716
717
std::unique_ptr<OGRLinearRing> OGRGeoJSONReadLinearRing(json_object *poObj,
718
                                                        bool bHasM)
719
0
{
720
0
    return OGRGeoJSONReadSimpleCurve<OGRLinearRing>(__func__, poObj, bHasM,
721
0
                                                    /* bRaw = */ true);
722
0
}
723
724
/************************************************************************/
725
/*                           OGRGeoJSONReadPolygon                      */
726
/************************************************************************/
727
728
std::unique_ptr<OGRPolygon> OGRGeoJSONReadPolygon(json_object *poObj,
729
                                                  bool bHasM, bool bRaw)
730
0
{
731
0
    if (!poObj)
732
0
    {
733
0
        CPLError(CE_Failure, CPLE_AppDefined,
734
0
                 "OGRGeoJSONReadPolygon(): invalid Polygon object. Got null.");
735
0
        return nullptr;
736
0
    }
737
0
    json_object *poObjRings = nullptr;
738
739
0
    if (!bRaw)
740
0
    {
741
0
        poObjRings = OGRGeoJSONFindMemberByName(poObj, "coordinates");
742
0
        if (nullptr == poObjRings)
743
0
        {
744
0
            CPLError(CE_Failure, CPLE_AppDefined,
745
0
                     "Invalid Polygon object. "
746
0
                     "Missing \'coordinates\' member.");
747
0
            return nullptr;
748
0
        }
749
0
    }
750
0
    else
751
0
    {
752
0
        poObjRings = poObj;
753
0
    }
754
755
0
    std::unique_ptr<OGRPolygon> poPolygon;
756
757
0
    if (json_type_array == json_object_get_type(poObjRings))
758
0
    {
759
0
        const auto nRings = json_object_array_length(poObjRings);
760
0
        if (nRings > 0)
761
0
        {
762
0
            json_object *poObjPoints = json_object_array_get_idx(poObjRings, 0);
763
0
            if (!poObjPoints)
764
0
            {
765
0
                poPolygon = std::make_unique<OGRPolygon>();
766
0
            }
767
0
            else
768
0
            {
769
0
                auto poRing = OGRGeoJSONReadLinearRing(poObjPoints, bHasM);
770
0
                if (poRing)
771
0
                {
772
0
                    poPolygon = std::make_unique<OGRPolygon>();
773
0
                    poPolygon->addRing(std::move(poRing));
774
0
                }
775
0
            }
776
777
0
            for (auto i = decltype(nRings){1};
778
0
                 i < nRings && nullptr != poPolygon; ++i)
779
0
            {
780
0
                poObjPoints = json_object_array_get_idx(poObjRings, i);
781
0
                if (poObjPoints)
782
0
                {
783
0
                    auto poRing = OGRGeoJSONReadLinearRing(poObjPoints, bHasM);
784
0
                    if (poRing)
785
0
                    {
786
0
                        poPolygon->addRing(std::move(poRing));
787
0
                    }
788
0
                }
789
0
            }
790
0
        }
791
0
        else
792
0
        {
793
0
            poPolygon = std::make_unique<OGRPolygon>();
794
0
        }
795
0
    }
796
0
    else
797
0
    {
798
0
        CPLError(CE_Warning, CPLE_AppDefined,
799
0
                 "OGRGeoJSONReadPolygon(): unexpected type of JSON construct "
800
0
                 "%s for '%s'. Expected array.",
801
0
                 GetJSONConstructName(json_object_get_type(poObjRings)),
802
0
                 json_object_to_json_string(poObjRings));
803
0
    }
804
805
0
    return poPolygon;
806
0
}
807
808
/************************************************************************/
809
/*                           OGRGeoJSONReadMultiPolygon                 */
810
/************************************************************************/
811
812
std::unique_ptr<OGRMultiPolygon> OGRGeoJSONReadMultiPolygon(json_object *poObj,
813
                                                            bool bHasM)
814
0
{
815
0
    CPLAssert(nullptr != poObj);
816
817
0
    json_object *poObjPolys = OGRGeoJSONFindMemberByName(poObj, "coordinates");
818
0
    if (nullptr == poObjPolys)
819
0
    {
820
0
        CPLError(CE_Failure, CPLE_AppDefined,
821
0
                 "Invalid MultiPolygon object. "
822
0
                 "Missing \'coordinates\' member.");
823
0
        return nullptr;
824
0
    }
825
826
0
    std::unique_ptr<OGRMultiPolygon> poMultiPoly;
827
828
0
    if (json_type_array == json_object_get_type(poObjPolys))
829
0
    {
830
0
        const int nPolys =
831
0
            static_cast<int>(json_object_array_length(poObjPolys));
832
833
0
        poMultiPoly = std::make_unique<OGRMultiPolygon>();
834
835
0
        for (int i = 0; i < nPolys; ++i)
836
0
        {
837
0
            json_object *poObjPoly = json_object_array_get_idx(poObjPolys, i);
838
0
            if (!poObjPoly)
839
0
            {
840
0
                poMultiPoly->addGeometryDirectly(
841
0
                    std::make_unique<OGRPolygon>().release());
842
0
            }
843
0
            else
844
0
            {
845
0
                auto poPoly =
846
0
                    OGRGeoJSONReadPolygon(poObjPoly, bHasM, /* bRaw = */ true);
847
0
                if (poPoly)
848
0
                {
849
0
                    poMultiPoly->addGeometry(std::move(poPoly));
850
0
                }
851
0
            }
852
0
        }
853
0
    }
854
0
    else
855
0
    {
856
0
        CPLError(CE_Warning, CPLE_AppDefined,
857
0
                 "OGRGeoJSONReadMultiPolygon(): unexpected type of JSON "
858
0
                 "construct %s for '%s'. Expected array.",
859
0
                 GetJSONConstructName(json_object_get_type(poObjPolys)),
860
0
                 json_object_to_json_string(poObjPolys));
861
0
    }
862
863
0
    return poMultiPoly;
864
0
}
865
866
/************************************************************************/
867
/*                      OGRGeoJSONReadCollection                        */
868
/************************************************************************/
869
870
template <class T>
871
static std::unique_ptr<T>
872
OGRGeoJSONReadCollection(const char *pszFuncName, const char *pszGeomTypeName,
873
                         json_object *poObj, bool bHasM,
874
                         const OGRSpatialReference *poSRS)
875
0
{
876
0
    CPLAssert(nullptr != poObj);
877
878
0
    json_object *poObjGeoms = OGRGeoJSONFindMemberByName(poObj, "geometries");
879
0
    if (nullptr == poObjGeoms)
880
0
    {
881
0
        CPLError(CE_Failure, CPLE_AppDefined,
882
0
                 "Invalid %s object. "
883
0
                 "Missing \'geometries\' member.",
884
0
                 pszGeomTypeName);
885
0
        return nullptr;
886
0
    }
887
888
0
    std::unique_ptr<T> poCollection;
889
890
0
    if (json_type_array == json_object_get_type(poObjGeoms))
891
0
    {
892
0
        poCollection = std::make_unique<T>();
893
0
        poCollection->assignSpatialReference(poSRS);
894
895
0
        const int nGeoms =
896
0
            static_cast<int>(json_object_array_length(poObjGeoms));
897
0
        for (int i = 0; i < nGeoms; ++i)
898
0
        {
899
0
            json_object *poObjGeom = json_object_array_get_idx(poObjGeoms, i);
900
0
            if (!poObjGeom)
901
0
            {
902
0
                CPLError(CE_Warning, CPLE_AppDefined,
903
0
                         "%s(): skipping null "
904
0
                         "sub-geometry",
905
0
                         pszFuncName);
906
0
                continue;
907
0
            }
908
909
0
            auto poGeometry = OGRGeoJSONReadGeometry(poObjGeom, bHasM, poSRS);
910
0
            if (poGeometry)
911
0
            {
912
                if constexpr (std::is_same_v<T, OGRCompoundCurve>)
913
0
                {
914
0
                    auto eFlatType = wkbFlatten(poGeometry->getGeometryType());
915
0
                    if (eFlatType == wkbLineString ||
916
0
                        eFlatType == wkbCircularString)
917
0
                    {
918
0
                        if (poCollection->addCurve(std::unique_ptr<OGRCurve>(
919
0
                                poGeometry.release()->toCurve())) !=
920
0
                            OGRERR_NONE)
921
0
                            return nullptr;
922
0
                    }
923
0
                    else
924
0
                    {
925
0
                        CPLError(CE_Warning, CPLE_AppDefined,
926
0
                                 "%s(): member of a CompoundCurve is not a "
927
0
                                 "LineString or CircularString.",
928
0
                                 pszFuncName);
929
0
                        return nullptr;
930
0
                    }
931
                }
932
                else if constexpr (std::is_same_v<T, OGRCurvePolygon>)
933
0
                {
934
0
                    auto eFlatType = wkbFlatten(poGeometry->getGeometryType());
935
0
                    if (eFlatType == wkbLineString ||
936
0
                        eFlatType == wkbCircularString ||
937
0
                        eFlatType == wkbCompoundCurve)
938
0
                    {
939
0
                        if (poCollection->addRing(std::unique_ptr<OGRCurve>(
940
0
                                poGeometry.release()->toCurve())) !=
941
0
                            OGRERR_NONE)
942
0
                            return nullptr;
943
0
                    }
944
0
                    else
945
0
                    {
946
0
                        CPLError(CE_Warning, CPLE_AppDefined,
947
0
                                 "%s(): member of a CurvePolygon is not a "
948
0
                                 "LineString, CircularString or CompoundCurve.",
949
0
                                 pszFuncName);
950
0
                        return nullptr;
951
0
                    }
952
                }
953
                else
954
0
                {
955
0
                    const auto eChildType = poGeometry->getGeometryType();
956
0
                    if (poCollection->addGeometry(std::move(poGeometry)) !=
957
0
                        OGRERR_NONE)
958
0
                    {
959
0
                        CPLError(
960
0
                            CE_Warning, CPLE_AppDefined,
961
0
                            "%s(): Invalid child geometry type (%s) for %s",
962
0
                            pszFuncName, OGRToOGCGeomType(eChildType),
963
0
                            pszGeomTypeName);
964
0
                        return nullptr;
965
0
                    }
966
0
                }
967
0
            }
968
0
        }
969
0
    }
970
0
    else
971
0
    {
972
0
        CPLError(CE_Warning, CPLE_AppDefined,
973
0
                 "%s(): unexpected type of JSON "
974
0
                 "construct %s for '%s'. Expected array.",
975
0
                 pszFuncName,
976
0
                 GetJSONConstructName(json_object_get_type(poObjGeoms)),
977
0
                 json_object_to_json_string(poObjGeoms));
978
0
    }
979
980
0
    return poCollection;
981
0
}
Unexecuted instantiation: ogrgeojsongeometry.cpp:std::__1::unique_ptr<OGRGeometryCollection, std::__1::default_delete<OGRGeometryCollection> > OGRGeoJSONReadCollection<OGRGeometryCollection>(char const*, char const*, json_object*, bool, OGRSpatialReference const*)
Unexecuted instantiation: ogrgeojsongeometry.cpp:std::__1::unique_ptr<OGRCompoundCurve, std::__1::default_delete<OGRCompoundCurve> > OGRGeoJSONReadCollection<OGRCompoundCurve>(char const*, char const*, json_object*, bool, OGRSpatialReference const*)
Unexecuted instantiation: ogrgeojsongeometry.cpp:std::__1::unique_ptr<OGRCurvePolygon, std::__1::default_delete<OGRCurvePolygon> > OGRGeoJSONReadCollection<OGRCurvePolygon>(char const*, char const*, json_object*, bool, OGRSpatialReference const*)
Unexecuted instantiation: ogrgeojsongeometry.cpp:std::__1::unique_ptr<OGRMultiCurve, std::__1::default_delete<OGRMultiCurve> > OGRGeoJSONReadCollection<OGRMultiCurve>(char const*, char const*, json_object*, bool, OGRSpatialReference const*)
Unexecuted instantiation: ogrgeojsongeometry.cpp:std::__1::unique_ptr<OGRMultiSurface, std::__1::default_delete<OGRMultiSurface> > OGRGeoJSONReadCollection<OGRMultiSurface>(char const*, char const*, json_object*, bool, OGRSpatialReference const*)
982
983
/************************************************************************/
984
/*                    OGRGeoJSONReadGeometryCollection                  */
985
/************************************************************************/
986
987
std::unique_ptr<OGRGeometryCollection>
988
OGRGeoJSONReadGeometryCollection(json_object *poObj, bool bHasM,
989
                                 const OGRSpatialReference *poSRS)
990
0
{
991
0
    return OGRGeoJSONReadCollection<OGRGeometryCollection>(
992
0
        __func__, "GeometryCollection", poObj, bHasM, poSRS);
993
0
}
994
995
/************************************************************************/
996
/*                    OGRGeoJSONReadCompoundCurve                       */
997
/************************************************************************/
998
999
std::unique_ptr<OGRCompoundCurve>
1000
OGRGeoJSONReadCompoundCurve(json_object *poObj, bool bHasM,
1001
                            const OGRSpatialReference *poSRS)
1002
0
{
1003
0
    return OGRGeoJSONReadCollection<OGRCompoundCurve>(__func__, "CompoundCurve",
1004
0
                                                      poObj, bHasM, poSRS);
1005
0
}
1006
1007
/************************************************************************/
1008
/*                     OGRGeoJSONReadCurvePolygon                       */
1009
/************************************************************************/
1010
1011
std::unique_ptr<OGRCurvePolygon> OGRGeoJSONReadCurvePolygon(json_object *poObj,
1012
                                                            bool bHasM)
1013
0
{
1014
0
    return OGRGeoJSONReadCollection<OGRCurvePolygon>(
1015
0
        __func__, "CurvePolygon", poObj, bHasM, /* poSRS = */ nullptr);
1016
0
}
1017
1018
/************************************************************************/
1019
/*                      OGRGeoJSONReadMultiCurve                        */
1020
/************************************************************************/
1021
1022
std::unique_ptr<OGRMultiCurve>
1023
OGRGeoJSONReadMultiCurve(json_object *poObj, bool bHasM,
1024
                         const OGRSpatialReference *poSRS)
1025
0
{
1026
0
    return OGRGeoJSONReadCollection<OGRMultiCurve>(__func__, "MultiCurve",
1027
0
                                                   poObj, bHasM, poSRS);
1028
0
}
1029
1030
/************************************************************************/
1031
/*                      OGRGeoJSONReadMultiSurface                      */
1032
/************************************************************************/
1033
1034
std::unique_ptr<OGRMultiSurface>
1035
OGRGeoJSONReadMultiSurface(json_object *poObj, bool bHasM,
1036
                           const OGRSpatialReference *poSRS)
1037
0
{
1038
0
    return OGRGeoJSONReadCollection<OGRMultiSurface>(__func__, "MultiSurface",
1039
0
                                                     poObj, bHasM, poSRS);
1040
0
}
1041
1042
/************************************************************************/
1043
/*                    OGRGeoJSONReadSpatialReference                    */
1044
/************************************************************************/
1045
1046
OGRSpatialReference *OGRGeoJSONReadSpatialReference(json_object *poObj)
1047
0
{
1048
1049
    /* -------------------------------------------------------------------- */
1050
    /*      Read spatial reference definition.                              */
1051
    /* -------------------------------------------------------------------- */
1052
0
    OGRSpatialReference *poSRS = nullptr;
1053
1054
0
    json_object *poObjSrs = OGRGeoJSONFindMemberByName(poObj, "crs");
1055
0
    if (nullptr != poObjSrs)
1056
0
    {
1057
0
        json_object *poObjSrsType =
1058
0
            OGRGeoJSONFindMemberByName(poObjSrs, "type");
1059
0
        if (poObjSrsType == nullptr)
1060
0
            return nullptr;
1061
1062
0
        const char *pszSrsType = json_object_get_string(poObjSrsType);
1063
1064
        // TODO: Add URL and URN types support.
1065
0
        if (STARTS_WITH_CI(pszSrsType, "NAME"))
1066
0
        {
1067
0
            json_object *poObjSrsProps =
1068
0
                OGRGeoJSONFindMemberByName(poObjSrs, "properties");
1069
0
            if (poObjSrsProps == nullptr)
1070
0
                return nullptr;
1071
1072
0
            json_object *poNameURL =
1073
0
                OGRGeoJSONFindMemberByName(poObjSrsProps, "name");
1074
0
            if (poNameURL == nullptr)
1075
0
                return nullptr;
1076
1077
0
            const char *pszName = json_object_get_string(poNameURL);
1078
1079
0
            if (EQUAL(pszName, "urn:ogc:def:crs:OGC:1.3:CRS84"))
1080
0
                pszName = "EPSG:4326";
1081
1082
0
            poSRS = new OGRSpatialReference();
1083
0
            poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1084
0
            if (OGRERR_NONE !=
1085
0
                poSRS->SetFromUserInput(
1086
0
                    pszName,
1087
0
                    OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get()))
1088
0
            {
1089
0
                delete poSRS;
1090
0
                poSRS = nullptr;
1091
0
            }
1092
0
        }
1093
1094
0
        else if (STARTS_WITH_CI(pszSrsType, "EPSG"))
1095
0
        {
1096
0
            json_object *poObjSrsProps =
1097
0
                OGRGeoJSONFindMemberByName(poObjSrs, "properties");
1098
0
            if (poObjSrsProps == nullptr)
1099
0
                return nullptr;
1100
1101
0
            json_object *poObjCode =
1102
0
                OGRGeoJSONFindMemberByName(poObjSrsProps, "code");
1103
0
            if (poObjCode == nullptr)
1104
0
                return nullptr;
1105
1106
0
            int nEPSG = json_object_get_int(poObjCode);
1107
1108
0
            poSRS = new OGRSpatialReference();
1109
0
            poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1110
0
            if (OGRERR_NONE != poSRS->importFromEPSG(nEPSG))
1111
0
            {
1112
0
                delete poSRS;
1113
0
                poSRS = nullptr;
1114
0
            }
1115
0
        }
1116
1117
0
        else if (STARTS_WITH_CI(pszSrsType, "URL") ||
1118
0
                 STARTS_WITH_CI(pszSrsType, "LINK"))
1119
0
        {
1120
0
            json_object *poObjSrsProps =
1121
0
                OGRGeoJSONFindMemberByName(poObjSrs, "properties");
1122
0
            if (poObjSrsProps == nullptr)
1123
0
                return nullptr;
1124
1125
0
            json_object *poObjURL =
1126
0
                OGRGeoJSONFindMemberByName(poObjSrsProps, "url");
1127
1128
0
            if (nullptr == poObjURL)
1129
0
            {
1130
0
                poObjURL = OGRGeoJSONFindMemberByName(poObjSrsProps, "href");
1131
0
            }
1132
0
            if (poObjURL == nullptr)
1133
0
                return nullptr;
1134
1135
0
            const char *pszURL = json_object_get_string(poObjURL);
1136
1137
0
            poSRS = new OGRSpatialReference();
1138
0
            poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1139
0
            if (OGRERR_NONE != poSRS->importFromUrl(pszURL))
1140
0
            {
1141
0
                delete poSRS;
1142
0
                poSRS = nullptr;
1143
0
            }
1144
0
        }
1145
1146
0
        else if (EQUAL(pszSrsType, "OGC"))
1147
0
        {
1148
0
            json_object *poObjSrsProps =
1149
0
                OGRGeoJSONFindMemberByName(poObjSrs, "properties");
1150
0
            if (poObjSrsProps == nullptr)
1151
0
                return nullptr;
1152
1153
0
            json_object *poObjURN =
1154
0
                OGRGeoJSONFindMemberByName(poObjSrsProps, "urn");
1155
0
            if (poObjURN == nullptr)
1156
0
                return nullptr;
1157
1158
0
            poSRS = new OGRSpatialReference();
1159
0
            poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1160
0
            if (OGRERR_NONE !=
1161
0
                poSRS->importFromURN(json_object_get_string(poObjURN)))
1162
0
            {
1163
0
                delete poSRS;
1164
0
                poSRS = nullptr;
1165
0
            }
1166
0
        }
1167
0
    }
1168
1169
    // Strip AXIS, since geojson has (easting, northing) / (longitude, latitude)
1170
    // order.  According to http://www.geojson.org/geojson-spec.html#id2 :
1171
    // "Point coordinates are in x, y order (easting, northing for projected
1172
    // coordinates, longitude, latitude for geographic coordinates)".
1173
0
    if (poSRS != nullptr)
1174
0
    {
1175
0
        OGR_SRSNode *poGEOGCS = poSRS->GetAttrNode("GEOGCS");
1176
0
        if (poGEOGCS != nullptr)
1177
0
            poGEOGCS->StripNodes("AXIS");
1178
0
    }
1179
1180
0
    return poSRS;
1181
0
}
1182
1183
/************************************************************************/
1184
/*                       OGR_G_CreateGeometryFromJson                   */
1185
/************************************************************************/
1186
1187
/** Create a OGR geometry from a GeoJSON geometry object */
1188
OGRGeometryH OGR_G_CreateGeometryFromJson(const char *pszJson)
1189
0
{
1190
0
    if (nullptr == pszJson)
1191
0
    {
1192
        // Translation failed.
1193
0
        return nullptr;
1194
0
    }
1195
1196
0
    json_object *poObj = nullptr;
1197
0
    if (!OGRJSonParse(pszJson, &poObj))
1198
0
        return nullptr;
1199
1200
0
    OGRGeometry *poGeometry =
1201
0
        OGRGeoJSONReadGeometry(poObj, /* bHasM = */ false,
1202
0
                               /* OGRSpatialReference* = */ nullptr)
1203
0
            .release();
1204
1205
    // Release JSON tree.
1206
0
    json_object_put(poObj);
1207
1208
0
    return OGRGeometry::ToHandle(poGeometry);
1209
0
}
1210
1211
/*! @endcond */