Coverage Report

Created: 2026-02-14 06:52

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