Coverage Report

Created: 2026-02-14 09:00

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
748k
{
48
748k
    if (nullptr == poObj)
49
0
        return GeoJSONObject::eUnknown;
50
51
748k
    json_object *poObjType = OGRGeoJSONFindMemberByName(poObj, "type");
52
748k
    if (nullptr == poObjType)
53
413k
        return GeoJSONObject::eUnknown;
54
55
334k
    const char *name = json_object_get_string(poObjType);
56
57
334k
#define ASSOC(x)                                                               \
58
4.68M
    {                                                                          \
59
4.68M
        #x, GeoJSONObject::e##x                                                \
60
4.68M
    }
61
62
334k
    static const struct
63
334k
    {
64
334k
        const char *pszName;
65
334k
        GeoJSONObject::Type eType;
66
334k
    } tabAssoc[] = {
67
334k
        ASSOC(Point),
68
334k
        ASSOC(LineString),
69
334k
        ASSOC(Polygon),
70
334k
        ASSOC(MultiPoint),
71
334k
        ASSOC(MultiLineString),
72
334k
        ASSOC(MultiPolygon),
73
334k
        ASSOC(GeometryCollection),
74
334k
        ASSOC(CircularString),
75
334k
        ASSOC(CompoundCurve),
76
334k
        ASSOC(CurvePolygon),
77
334k
        ASSOC(MultiCurve),
78
334k
        ASSOC(MultiSurface),
79
334k
        ASSOC(Feature),
80
334k
        ASSOC(FeatureCollection),
81
334k
    };
82
83
334k
#undef ASSOC
84
85
334k
    for (const auto &assoc : tabAssoc)
86
3.56M
    {
87
3.56M
        if (EQUAL(name, assoc.pszName))
88
287k
            return assoc.eType;
89
3.56M
    }
90
91
47.6k
    return GeoJSONObject::eUnknown;
92
334k
}
93
94
/************************************************************************/
95
/*                        OGRJSONFGHasMeasure()                         */
96
/************************************************************************/
97
98
bool OGRJSONFGHasMeasure(json_object *poObj, bool bUpperLevelMValue)
99
420k
{
100
420k
    bool bHasM = bUpperLevelMValue;
101
420k
    if (json_object *pojMeasures =
102
420k
            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
420k
    return bHasM;
109
420k
}
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
31.7k
{
144
31.7k
    if (nullptr == poObj)
145
551
        return wkbUnknown;
146
147
31.1k
    json_object *poObjType = CPL_json_object_object_get(poObj, "type");
148
31.1k
    if (nullptr == poObjType)
149
903
        return wkbUnknown;
150
151
30.2k
    const char *name = json_object_get_string(poObjType);
152
153
30.2k
    OGRwkbGeometryType eType = wkbNone;
154
30.2k
    for (const auto &assoc : asAssocGeometryTypes)
155
135k
    {
156
135k
        if (EQUAL(name, assoc.pszName))
157
28.0k
        {
158
28.0k
            eType = assoc.eType;
159
28.0k
            break;
160
28.0k
        }
161
135k
    }
162
30.2k
    if (eType == wkbNone)
163
2.25k
        return wkbUnknown;
164
165
28.0k
    bHasM = OGRJSONFGHasMeasure(poObj, bHasM);
166
167
28.0k
    json_object *poCoordinates;
168
28.0k
    if (eType == wkbGeometryCollection || eType == wkbMultiCurve ||
169
25.9k
        eType == wkbMultiSurface || eType == wkbCompoundCurve ||
170
25.9k
        eType == wkbCurvePolygon)
171
2.10k
    {
172
2.10k
        json_object *poGeometries =
173
2.10k
            CPL_json_object_object_get(poObj, "geometries");
174
2.10k
        if (poGeometries &&
175
714
            json_object_get_type(poGeometries) == json_type_array &&
176
713
            json_object_array_length(poGeometries) > 0)
177
675
        {
178
675
            const auto subGeomType = OGRGeoJSONGetOGRGeometryType(
179
675
                json_object_array_get_idx(poGeometries, 0), bHasM);
180
675
            if (OGR_GT_HasZ(subGeomType))
181
0
                eType = OGR_GT_SetZ(eType);
182
675
        }
183
2.10k
    }
184
25.9k
    else
185
25.9k
    {
186
25.9k
        poCoordinates = CPL_json_object_object_get(poObj, "coordinates");
187
25.9k
        if (poCoordinates &&
188
22.5k
            json_object_get_type(poCoordinates) == json_type_array &&
189
22.5k
            json_object_array_length(poCoordinates) > 0)
190
20.5k
        {
191
28.2k
            while (true)
192
28.2k
            {
193
28.2k
                auto poChild = json_object_array_get_idx(poCoordinates, 0);
194
28.2k
                if (!(poChild &&
195
18.3k
                      json_object_get_type(poChild) == json_type_array &&
196
11.8k
                      json_object_array_length(poChild) > 0))
197
20.5k
                {
198
20.5k
                    const auto nLength =
199
20.5k
                        json_object_array_length(poCoordinates);
200
20.5k
                    if ((bHasM && nLength == 4) || (!bHasM && nLength == 3))
201
2.55k
                        eType = OGR_GT_SetZ(eType);
202
20.5k
                    break;
203
20.5k
                }
204
7.72k
                poCoordinates = poChild;
205
7.72k
            }
206
20.5k
        }
207
25.9k
    }
208
28.0k
    if (bHasM)
209
0
        eType = OGR_GT_SetM(eType);
210
211
28.0k
    return eType;
212
30.2k
}
213
214
/************************************************************************/
215
/*                     OGRGeoJSONGetGeometryName()                      */
216
/************************************************************************/
217
218
const char *OGRGeoJSONGetGeometryName(OGRGeometry const *poGeometry)
219
640k
{
220
640k
    CPLAssert(nullptr != poGeometry);
221
222
640k
    const OGRwkbGeometryType eType = wkbFlatten(poGeometry->getGeometryType());
223
224
640k
    for (const auto &assoc : asAssocGeometryTypes)
225
1.94M
    {
226
1.94M
        if (eType == assoc.eType)
227
640k
        {
228
640k
            return assoc.pszName;
229
640k
        }
230
1.94M
    }
231
597
    return "Unknown";
232
640k
}
233
234
/************************************************************************/
235
/*                        OGRGeoJSONReadGeometry                        */
236
/************************************************************************/
237
238
std::unique_ptr<OGRGeometry>
239
OGRGeoJSONReadGeometry(json_object *poObj, bool bHasM,
240
                       const OGRSpatialReference *poParentSRS)
241
391k
{
242
243
391k
    std::unique_ptr<OGRGeometry> poGeometry;
244
391k
    OGRSpatialReference *poSRS = nullptr;
245
391k
    lh_entry *entry = OGRGeoJSONFindMemberEntryByName(poObj, "crs");
246
391k
    if (entry != nullptr)
247
307k
    {
248
307k
        json_object *poObjSrs =
249
307k
            static_cast<json_object *>(const_cast<void *>(entry->v));
250
307k
        if (poObjSrs != nullptr)
251
306k
        {
252
306k
            poSRS = OGRGeoJSONReadSpatialReference(poObj);
253
306k
        }
254
307k
    }
255
256
391k
    const OGRSpatialReference *poSRSToAssign = nullptr;
257
391k
    if (entry != nullptr)
258
307k
    {
259
307k
        poSRSToAssign = poSRS;
260
307k
    }
261
83.9k
    else if (poParentSRS)
262
41.7k
    {
263
41.7k
        poSRSToAssign = poParentSRS;
264
41.7k
    }
265
42.1k
    else
266
42.1k
    {
267
        // Assign WGS84 if no CRS defined on geometry.
268
42.1k
        poSRSToAssign = OGRSpatialReference::GetWGS84SRS();
269
42.1k
    }
270
271
391k
    bHasM = OGRJSONFGHasMeasure(poObj, bHasM);
272
273
391k
    const auto objType = OGRGeoJSONGetType(poObj);
274
391k
    switch (objType)
275
391k
    {
276
14.1k
        case GeoJSONObject::ePoint:
277
14.1k
            poGeometry = OGRGeoJSONReadPoint(poObj, bHasM);
278
14.1k
            break;
279
280
10.0k
        case GeoJSONObject::eLineString:
281
10.0k
            poGeometry = OGRGeoJSONReadLineString(poObj, bHasM,
282
10.0k
                                                  /* bRaw = */ false);
283
10.0k
            break;
284
285
7.49k
        case GeoJSONObject::ePolygon:
286
7.49k
            poGeometry =
287
7.49k
                OGRGeoJSONReadPolygon(poObj, bHasM, /* bRaw = */ false);
288
7.49k
            break;
289
290
6.13k
        case GeoJSONObject::eMultiPoint:
291
6.13k
            poGeometry = OGRGeoJSONReadMultiPoint(poObj, bHasM);
292
6.13k
            break;
293
294
5.39k
        case GeoJSONObject::eMultiLineString:
295
5.39k
            poGeometry = OGRGeoJSONReadMultiLineString(poObj, bHasM);
296
5.39k
            break;
297
298
13.2k
        case GeoJSONObject::eMultiPolygon:
299
13.2k
            poGeometry = OGRGeoJSONReadMultiPolygon(poObj, bHasM);
300
13.2k
            break;
301
302
3.61k
        case GeoJSONObject::eGeometryCollection:
303
3.61k
            poGeometry =
304
3.61k
                OGRGeoJSONReadGeometryCollection(poObj, bHasM, poSRSToAssign);
305
3.61k
            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
11
        case GeoJSONObject::eMultiCurve:
321
11
            poGeometry = OGRGeoJSONReadMultiCurve(poObj, bHasM, poSRSToAssign);
322
11
            break;
323
324
0
        case GeoJSONObject::eMultiSurface:
325
0
            poGeometry =
326
0
                OGRGeoJSONReadMultiSurface(poObj, bHasM, poSRSToAssign);
327
0
            break;
328
329
2.02k
        case GeoJSONObject::eFeature:
330
2.09k
        case GeoJSONObject::eFeatureCollection:
331
2.09k
            [[fallthrough]];
332
331k
        case GeoJSONObject::eUnknown:
333
331k
            CPLError(CE_Warning, CPLE_AppDefined,
334
331k
                     "Unsupported geometry type detected. "
335
331k
                     "Feature gets NULL geometry assigned.");
336
331k
            break;
337
391k
    }
338
339
391k
    if (poGeometry && GeoJSONObject::eGeometryCollection != objType)
340
17.0k
        poGeometry->assignSpatialReference(poSRSToAssign);
341
342
391k
    if (poSRS)
343
106k
        poSRS->Release();
344
345
391k
    return poGeometry;
346
391k
}
347
348
/************************************************************************/
349
/*                        GetJSONConstructName()                        */
350
/************************************************************************/
351
352
static const char *GetJSONConstructName(json_type eType)
353
18.0k
{
354
18.0k
    switch (eType)
355
18.0k
    {
356
5.38k
        case json_type_null:
357
5.38k
            break;
358
0
        case json_type_boolean:
359
0
            return "boolean";
360
0
        case json_type_double:
361
0
            return "double";
362
9.93k
        case json_type_int:
363
9.93k
            return "int";
364
30
        case json_type_object:
365
30
            return "object";
366
185
        case json_type_array:
367
185
            return "array";
368
2.56k
        case json_type_string:
369
2.56k
            return "string";
370
18.0k
    }
371
5.38k
    return "null";
372
18.0k
}
373
374
/************************************************************************/
375
/*                      OGRGeoJSONGetCoordinate()                       */
376
/************************************************************************/
377
378
static double OGRGeoJSONGetCoordinate(json_object *poObj,
379
                                      const char *pszCoordName, int nIndex,
380
                                      bool &bValid)
381
50.2k
{
382
50.2k
    json_object *poObjCoord = json_object_array_get_idx(poObj, nIndex);
383
50.2k
    if (nullptr == poObjCoord)
384
5.83k
    {
385
5.83k
        CPLDebug("GeoJSON", "Point: got null object for %s.", pszCoordName);
386
5.83k
        bValid = false;
387
5.83k
        return 0.0;
388
5.83k
    }
389
390
44.3k
    const json_type eType = json_object_get_type(poObjCoord);
391
44.3k
    if (json_type_double != eType && json_type_int != eType)
392
188
    {
393
188
        CPLError(CE_Failure, CPLE_AppDefined,
394
188
                 "OGRGeoJSONGetCoordinate(): invalid '%s' coordinate. "
395
188
                 "Unexpected type %s for '%s'. Expected double or integer.",
396
188
                 pszCoordName, GetJSONConstructName(eType),
397
188
                 json_object_to_json_string(poObjCoord));
398
188
        bValid = false;
399
188
        return 0.0;
400
188
    }
401
402
44.2k
    return json_object_get_double(poObjCoord);
403
44.3k
}
404
405
/************************************************************************/
406
/*                        OGRGeoJSONReadRawPoint                        */
407
/************************************************************************/
408
409
static bool OGRGeoJSONReadRawPoint(json_object *poObj, OGRPoint &point,
410
                                   bool bHasM)
411
40.2k
{
412
40.2k
    if (json_type_array == json_object_get_type(poObj))
413
26.9k
    {
414
26.9k
        const int nSize = static_cast<int>(json_object_array_length(poObj));
415
416
26.9k
        if (nSize < GeoJSONObject::eMinCoordinateDimension)
417
3.95k
        {
418
3.95k
            CPLError(CE_Warning, CPLE_AppDefined,
419
3.95k
                     "OGRGeoJSONReadRawPoint(): "
420
3.95k
                     "Invalid coord dimension for '%s'. "
421
3.95k
                     "At least 2 dimensions must be present.",
422
3.95k
                     json_object_to_json_string(poObj));
423
3.95k
            return false;
424
3.95k
        }
425
426
23.0k
        bool bValid = true;
427
23.0k
        const double dfX = OGRGeoJSONGetCoordinate(poObj, "x", 0, bValid);
428
23.0k
        const double dfY = OGRGeoJSONGetCoordinate(poObj, "y", 1, bValid);
429
23.0k
        point.setX(dfX);
430
23.0k
        point.setY(dfY);
431
432
        // Read Z and/or M coordinate.
433
23.0k
        if (nSize > GeoJSONObject::eMinCoordinateDimension)
434
4.18k
        {
435
4.18k
            const int nMaxDim =
436
4.18k
                bHasM ? GeoJSONObject::eMaxCoordinateDimensionJSONFG
437
4.18k
                      : GeoJSONObject::eMaxCoordinateDimensionGeoJSON;
438
4.18k
            if (nSize > nMaxDim)
439
30
            {
440
30
                CPLErrorOnce(CE_Warning, CPLE_AppDefined,
441
30
                             "OGRGeoJSONReadRawPoint(): too many members in "
442
30
                             "array '%s': %d. At most %d are handled. Ignoring "
443
30
                             "extra members.",
444
30
                             json_object_to_json_string(poObj), nSize, nMaxDim);
445
30
            }
446
            // Don't *expect* mixed-dimension geometries, although the
447
            // spec doesn't explicitly forbid this.
448
4.18k
            if (nSize == 4 || (nSize == 3 && !bHasM))
449
4.18k
            {
450
4.18k
                const double dfZ =
451
4.18k
                    OGRGeoJSONGetCoordinate(poObj, "z", 2, bValid);
452
4.18k
                point.setZ(dfZ);
453
4.18k
            }
454
455
4.18k
            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
4.18k
        }
462
18.8k
        else
463
18.8k
        {
464
18.8k
            point.flattenTo2D();
465
18.8k
        }
466
23.0k
        return bValid;
467
26.9k
    }
468
13.3k
    else
469
13.3k
    {
470
13.3k
        CPLError(CE_Failure, CPLE_AppDefined,
471
13.3k
                 "OGRGeoJSONReadRawPoint(): invalid Point. "
472
13.3k
                 "Unexpected type %s for '%s'. Expected array.",
473
13.3k
                 GetJSONConstructName(json_object_get_type(poObj)),
474
13.3k
                 json_object_to_json_string(poObj));
475
13.3k
    }
476
477
13.3k
    return false;
478
40.2k
}
479
480
/************************************************************************/
481
/*                         OGRGeoJSONReadPoint                          */
482
/************************************************************************/
483
484
std::unique_ptr<OGRPoint> OGRGeoJSONReadPoint(json_object *poObj, bool bHasM)
485
14.1k
{
486
14.1k
    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
14.1k
    json_object *poObjCoords = OGRGeoJSONFindMemberByName(poObj, "coordinates");
493
14.1k
    if (nullptr == poObjCoords)
494
4.67k
    {
495
4.67k
        CPLError(CE_Failure, CPLE_AppDefined,
496
4.67k
                 "OGRGeoJSONReadPoint(): invalid Point object. "
497
4.67k
                 "Missing \'coordinates\' member.");
498
4.67k
        return nullptr;
499
4.67k
    }
500
501
9.49k
    auto poPoint = std::make_unique<OGRPoint>();
502
9.49k
    if (!OGRGeoJSONReadRawPoint(poObjCoords, *poPoint, bHasM))
503
8.65k
    {
504
8.65k
        return nullptr;
505
8.65k
    }
506
507
839
    return poPoint;
508
9.49k
}
509
510
/************************************************************************/
511
/*                       OGRGeoJSONReadMultiPoint                       */
512
/************************************************************************/
513
514
std::unique_ptr<OGRMultiPoint> OGRGeoJSONReadMultiPoint(json_object *poObj,
515
                                                        bool bHasM)
516
6.13k
{
517
6.13k
    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
6.13k
    json_object *poObjPoints = OGRGeoJSONFindMemberByName(poObj, "coordinates");
525
6.13k
    if (nullptr == poObjPoints)
526
3.35k
    {
527
3.35k
        CPLError(CE_Failure, CPLE_AppDefined,
528
3.35k
                 "Invalid MultiPoint object. "
529
3.35k
                 "Missing \'coordinates\' member.");
530
3.35k
        return nullptr;
531
3.35k
    }
532
533
2.77k
    std::unique_ptr<OGRMultiPoint> poMultiPoint;
534
2.77k
    if (json_type_array == json_object_get_type(poObjPoints))
535
2.51k
    {
536
2.51k
        const auto nPoints = json_object_array_length(poObjPoints);
537
538
2.51k
        poMultiPoint = std::make_unique<OGRMultiPoint>();
539
540
3.77k
        for (auto i = decltype(nPoints){0}; i < nPoints; ++i)
541
2.79k
        {
542
2.79k
            json_object *poObjCoords =
543
2.79k
                json_object_array_get_idx(poObjPoints, i);
544
545
2.79k
            OGRPoint pt;
546
2.79k
            if (!OGRGeoJSONReadRawPoint(poObjCoords, pt, bHasM))
547
1.53k
            {
548
1.53k
                return nullptr;
549
1.53k
            }
550
1.25k
            poMultiPoint->addGeometry(&pt);
551
1.25k
        }
552
2.51k
    }
553
254
    else
554
254
    {
555
254
        CPLError(CE_Failure, CPLE_AppDefined,
556
254
                 "OGRGeoJSONReadMultiPoint(): invalid MultiPoint. "
557
254
                 "Unexpected type %s for '%s'. Expected array.",
558
254
                 GetJSONConstructName(json_object_get_type(poObjPoints)),
559
254
                 json_object_to_json_string(poObjPoints));
560
254
    }
561
562
1.23k
    return poMultiPoint;
563
2.77k
}
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
34.1k
{
574
34.1k
    if (!poObj)
575
900
    {
576
900
        CPLError(CE_Failure, CPLE_AppDefined,
577
900
                 "%s(): invalid LineString object. Got null.", pszFuncName);
578
900
        return nullptr;
579
900
    }
580
33.2k
    json_object *poObjPoints = nullptr;
581
582
33.2k
    if (!bRaw)
583
10.0k
    {
584
10.0k
        poObjPoints = OGRGeoJSONFindMemberByName(poObj, "coordinates");
585
10.0k
        if (nullptr == poObjPoints)
586
7.62k
        {
587
7.62k
            CPLError(CE_Failure, CPLE_AppDefined,
588
7.62k
                     "Invalid LineString object. "
589
7.62k
                     "Missing \'coordinates\' member.");
590
7.62k
            return nullptr;
591
7.62k
        }
592
10.0k
    }
593
23.1k
    else
594
23.1k
    {
595
23.1k
        poObjPoints = poObj;
596
23.1k
    }
597
598
25.5k
    std::unique_ptr<T> poLine;
599
600
25.5k
    if (json_type_array == json_object_get_type(poObjPoints))
601
22.5k
    {
602
22.5k
        const int nPoints =
603
22.5k
            static_cast<int>(json_object_array_length(poObjPoints));
604
605
22.5k
        poLine = std::make_unique<T>();
606
22.5k
        poLine->setNumPoints(nPoints);
607
608
39.1k
        for (int i = 0; i < nPoints; ++i)
609
28.0k
        {
610
28.0k
            json_object *poObjCoords =
611
28.0k
                json_object_array_get_idx(poObjPoints, i);
612
613
28.0k
            OGRPoint pt;
614
28.0k
            if (!OGRGeoJSONReadRawPoint(poObjCoords, pt, bHasM))
615
11.4k
            {
616
11.4k
                return nullptr;
617
11.4k
            }
618
16.6k
            if (pt.Is3D())
619
2.79k
                poLine->set3D(true);
620
16.6k
            if (pt.IsMeasured())
621
0
                poLine->setMeasured(true);
622
16.6k
            poLine->setPoint(i, &pt);
623
16.6k
        }
624
22.5k
    }
625
3.06k
    else
626
3.06k
    {
627
3.06k
        CPLError(CE_Failure, CPLE_AppDefined,
628
3.06k
                 "%s(): invalid geometry. "
629
3.06k
                 "Unexpected type %s for '%s'. Expected array.",
630
3.06k
                 pszFuncName,
631
3.06k
                 GetJSONConstructName(json_object_get_type(poObjPoints)),
632
3.06k
                 json_object_to_json_string(poObjPoints));
633
3.06k
    }
634
635
14.1k
    return poLine;
636
25.5k
}
ogrgeojsongeometry.cpp:std::__1::unique_ptr<OGRLineString, std::__1::default_delete<OGRLineString> > OGRGeoJSONReadSimpleCurve<OGRLineString>(char const*, json_object*, bool, bool)
Line
Count
Source
573
23.0k
{
574
23.0k
    if (!poObj)
575
900
    {
576
900
        CPLError(CE_Failure, CPLE_AppDefined,
577
900
                 "%s(): invalid LineString object. Got null.", pszFuncName);
578
900
        return nullptr;
579
900
    }
580
22.1k
    json_object *poObjPoints = nullptr;
581
582
22.1k
    if (!bRaw)
583
10.0k
    {
584
10.0k
        poObjPoints = OGRGeoJSONFindMemberByName(poObj, "coordinates");
585
10.0k
        if (nullptr == poObjPoints)
586
7.62k
        {
587
7.62k
            CPLError(CE_Failure, CPLE_AppDefined,
588
7.62k
                     "Invalid LineString object. "
589
7.62k
                     "Missing \'coordinates\' member.");
590
7.62k
            return nullptr;
591
7.62k
        }
592
10.0k
    }
593
12.0k
    else
594
12.0k
    {
595
12.0k
        poObjPoints = poObj;
596
12.0k
    }
597
598
14.4k
    std::unique_ptr<T> poLine;
599
600
14.4k
    if (json_type_array == json_object_get_type(poObjPoints))
601
14.2k
    {
602
14.2k
        const int nPoints =
603
14.2k
            static_cast<int>(json_object_array_length(poObjPoints));
604
605
14.2k
        poLine = std::make_unique<T>();
606
14.2k
        poLine->setNumPoints(nPoints);
607
608
20.4k
        for (int i = 0; i < nPoints; ++i)
609
15.5k
        {
610
15.5k
            json_object *poObjCoords =
611
15.5k
                json_object_array_get_idx(poObjPoints, i);
612
613
15.5k
            OGRPoint pt;
614
15.5k
            if (!OGRGeoJSONReadRawPoint(poObjCoords, pt, bHasM))
615
9.31k
            {
616
9.31k
                return nullptr;
617
9.31k
            }
618
6.20k
            if (pt.Is3D())
619
584
                poLine->set3D(true);
620
6.20k
            if (pt.IsMeasured())
621
0
                poLine->setMeasured(true);
622
6.20k
            poLine->setPoint(i, &pt);
623
6.20k
        }
624
14.2k
    }
625
207
    else
626
207
    {
627
207
        CPLError(CE_Failure, CPLE_AppDefined,
628
207
                 "%s(): invalid geometry. "
629
207
                 "Unexpected type %s for '%s'. Expected array.",
630
207
                 pszFuncName,
631
207
                 GetJSONConstructName(json_object_get_type(poObjPoints)),
632
207
                 json_object_to_json_string(poObjPoints));
633
207
    }
634
635
5.17k
    return poLine;
636
14.4k
}
Unexecuted instantiation: ogrgeojsongeometry.cpp:std::__1::unique_ptr<OGRCircularString, std::__1::default_delete<OGRCircularString> > OGRGeoJSONReadSimpleCurve<OGRCircularString>(char const*, json_object*, bool, bool)
ogrgeojsongeometry.cpp:std::__1::unique_ptr<OGRLinearRing, std::__1::default_delete<OGRLinearRing> > OGRGeoJSONReadSimpleCurve<OGRLinearRing>(char const*, json_object*, bool, bool)
Line
Count
Source
573
11.1k
{
574
11.1k
    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
11.1k
    json_object *poObjPoints = nullptr;
581
582
11.1k
    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
11.1k
    else
594
11.1k
    {
595
11.1k
        poObjPoints = poObj;
596
11.1k
    }
597
598
11.1k
    std::unique_ptr<T> poLine;
599
600
11.1k
    if (json_type_array == json_object_get_type(poObjPoints))
601
8.23k
    {
602
8.23k
        const int nPoints =
603
8.23k
            static_cast<int>(json_object_array_length(poObjPoints));
604
605
8.23k
        poLine = std::make_unique<T>();
606
8.23k
        poLine->setNumPoints(nPoints);
607
608
18.6k
        for (int i = 0; i < nPoints; ++i)
609
12.4k
        {
610
12.4k
            json_object *poObjCoords =
611
12.4k
                json_object_array_get_idx(poObjPoints, i);
612
613
12.4k
            OGRPoint pt;
614
12.4k
            if (!OGRGeoJSONReadRawPoint(poObjCoords, pt, bHasM))
615
2.08k
            {
616
2.08k
                return nullptr;
617
2.08k
            }
618
10.4k
            if (pt.Is3D())
619
2.21k
                poLine->set3D(true);
620
10.4k
            if (pt.IsMeasured())
621
0
                poLine->setMeasured(true);
622
10.4k
            poLine->setPoint(i, &pt);
623
10.4k
        }
624
8.23k
    }
625
2.86k
    else
626
2.86k
    {
627
2.86k
        CPLError(CE_Failure, CPLE_AppDefined,
628
2.86k
                 "%s(): invalid geometry. "
629
2.86k
                 "Unexpected type %s for '%s'. Expected array.",
630
2.86k
                 pszFuncName,
631
2.86k
                 GetJSONConstructName(json_object_get_type(poObjPoints)),
632
2.86k
                 json_object_to_json_string(poObjPoints));
633
2.86k
    }
634
635
9.01k
    return poLine;
636
11.1k
}
637
638
/************************************************************************/
639
/*                       OGRGeoJSONReadLineString                       */
640
/************************************************************************/
641
642
std::unique_ptr<OGRLineString> OGRGeoJSONReadLineString(json_object *poObj,
643
                                                        bool bHasM, bool bRaw)
644
23.0k
{
645
23.0k
    return OGRGeoJSONReadSimpleCurve<OGRLineString>(__func__, poObj, bHasM,
646
23.0k
                                                    bRaw);
647
23.0k
}
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
5.39k
{
667
5.39k
    CPLAssert(nullptr != poObj);
668
669
5.39k
    json_object *poObjLines = OGRGeoJSONFindMemberByName(poObj, "coordinates");
670
5.39k
    if (nullptr == poObjLines)
671
3.22k
    {
672
3.22k
        CPLError(CE_Failure, CPLE_AppDefined,
673
3.22k
                 "Invalid MultiLineString object. "
674
3.22k
                 "Missing \'coordinates\' member.");
675
3.22k
        return nullptr;
676
3.22k
    }
677
678
2.17k
    std::unique_ptr<OGRMultiLineString> poMultiLine;
679
680
2.17k
    if (json_type_array == json_object_get_type(poObjLines))
681
2.09k
    {
682
2.09k
        const auto nLines = json_object_array_length(poObjLines);
683
684
2.09k
        poMultiLine = std::make_unique<OGRMultiLineString>();
685
686
15.0k
        for (auto i = decltype(nLines){0}; i < nLines; ++i)
687
12.9k
        {
688
12.9k
            json_object *poObjLine = json_object_array_get_idx(poObjLines, i);
689
690
12.9k
            auto poLine =
691
12.9k
                OGRGeoJSONReadLineString(poObjLine, bHasM, /* bRaw = */ true);
692
12.9k
            if (poLine)
693
4.06k
            {
694
4.06k
                poMultiLine->addGeometry(std::move(poLine));
695
4.06k
            }
696
12.9k
        }
697
2.09k
    }
698
78
    else
699
78
    {
700
78
        CPLError(CE_Failure, CPLE_AppDefined,
701
78
                 "OGRGeoJSONReadLineString(): invalid LineString. "
702
78
                 "Unexpected type %s for '%s'. Expected array.",
703
78
                 GetJSONConstructName(json_object_get_type(poObjLines)),
704
78
                 json_object_to_json_string(poObjLines));
705
78
    }
706
707
2.17k
    return poMultiLine;
708
5.39k
}
709
710
/************************************************************************/
711
/*                       OGRGeoJSONReadLinearRing                       */
712
/************************************************************************/
713
714
std::unique_ptr<OGRLinearRing> OGRGeoJSONReadLinearRing(json_object *poObj,
715
                                                        bool bHasM)
716
11.1k
{
717
11.1k
    return OGRGeoJSONReadSimpleCurve<OGRLinearRing>(__func__, poObj, bHasM,
718
11.1k
                                                    /* bRaw = */ true);
719
11.1k
}
720
721
/************************************************************************/
722
/*                        OGRGeoJSONReadPolygon                         */
723
/************************************************************************/
724
725
std::unique_ptr<OGRPolygon> OGRGeoJSONReadPolygon(json_object *poObj,
726
                                                  bool bHasM, bool bRaw)
727
28.6k
{
728
28.6k
    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
28.6k
    json_object *poObjRings = nullptr;
735
736
28.6k
    if (!bRaw)
737
7.49k
    {
738
7.49k
        poObjRings = OGRGeoJSONFindMemberByName(poObj, "coordinates");
739
7.49k
        if (nullptr == poObjRings)
740
5.45k
        {
741
5.45k
            CPLError(CE_Failure, CPLE_AppDefined,
742
5.45k
                     "Invalid Polygon object. "
743
5.45k
                     "Missing \'coordinates\' member.");
744
5.45k
            return nullptr;
745
5.45k
        }
746
7.49k
    }
747
21.2k
    else
748
21.2k
    {
749
21.2k
        poObjRings = poObj;
750
21.2k
    }
751
752
23.2k
    std::unique_ptr<OGRPolygon> poPolygon;
753
754
23.2k
    if (json_type_array == json_object_get_type(poObjRings))
755
22.2k
    {
756
22.2k
        const auto nRings = json_object_array_length(poObjRings);
757
22.2k
        if (nRings > 0)
758
9.89k
        {
759
9.89k
            json_object *poObjPoints = json_object_array_get_idx(poObjRings, 0);
760
9.89k
            if (!poObjPoints)
761
3.13k
            {
762
3.13k
                poPolygon = std::make_unique<OGRPolygon>();
763
3.13k
            }
764
6.75k
            else
765
6.75k
            {
766
6.75k
                auto poRing = OGRGeoJSONReadLinearRing(poObjPoints, bHasM);
767
6.75k
                if (poRing)
768
3.80k
                {
769
3.80k
                    poPolygon = std::make_unique<OGRPolygon>();
770
3.80k
                    poPolygon->addRing(std::move(poRing));
771
3.80k
                }
772
6.75k
            }
773
774
9.89k
            for (auto i = decltype(nRings){1};
775
16.3k
                 i < nRings && nullptr != poPolygon; ++i)
776
6.40k
            {
777
6.40k
                poObjPoints = json_object_array_get_idx(poObjRings, i);
778
6.40k
                if (poObjPoints)
779
4.34k
                {
780
4.34k
                    auto poRing = OGRGeoJSONReadLinearRing(poObjPoints, bHasM);
781
4.34k
                    if (poRing)
782
2.34k
                    {
783
2.34k
                        poPolygon->addRing(std::move(poRing));
784
2.34k
                    }
785
4.34k
                }
786
6.40k
            }
787
9.89k
        }
788
12.3k
        else
789
12.3k
        {
790
12.3k
            poPolygon = std::make_unique<OGRPolygon>();
791
12.3k
        }
792
22.2k
    }
793
976
    else
794
976
    {
795
976
        CPLError(CE_Warning, CPLE_AppDefined,
796
976
                 "OGRGeoJSONReadPolygon(): unexpected type of JSON construct "
797
976
                 "%s for '%s'. Expected array.",
798
976
                 GetJSONConstructName(json_object_get_type(poObjRings)),
799
976
                 json_object_to_json_string(poObjRings));
800
976
    }
801
802
23.2k
    return poPolygon;
803
28.6k
}
804
805
/************************************************************************/
806
/*                      OGRGeoJSONReadMultiPolygon                      */
807
/************************************************************************/
808
809
std::unique_ptr<OGRMultiPolygon> OGRGeoJSONReadMultiPolygon(json_object *poObj,
810
                                                            bool bHasM)
811
13.2k
{
812
13.2k
    CPLAssert(nullptr != poObj);
813
814
13.2k
    json_object *poObjPolys = OGRGeoJSONFindMemberByName(poObj, "coordinates");
815
13.2k
    if (nullptr == poObjPolys)
816
2.82k
    {
817
2.82k
        CPLError(CE_Failure, CPLE_AppDefined,
818
2.82k
                 "Invalid MultiPolygon object. "
819
2.82k
                 "Missing \'coordinates\' member.");
820
2.82k
        return nullptr;
821
2.82k
    }
822
823
10.4k
    std::unique_ptr<OGRMultiPolygon> poMultiPoly;
824
825
10.4k
    if (json_type_array == json_object_get_type(poObjPolys))
826
10.4k
    {
827
10.4k
        const int nPolys =
828
10.4k
            static_cast<int>(json_object_array_length(poObjPolys));
829
830
10.4k
        poMultiPoly = std::make_unique<OGRMultiPolygon>();
831
832
41.8k
        for (int i = 0; i < nPolys; ++i)
833
31.3k
        {
834
31.3k
            json_object *poObjPoly = json_object_array_get_idx(poObjPolys, i);
835
31.3k
            if (!poObjPoly)
836
10.1k
            {
837
10.1k
                poMultiPoly->addGeometryDirectly(
838
10.1k
                    std::make_unique<OGRPolygon>().release());
839
10.1k
            }
840
21.2k
            else
841
21.2k
            {
842
21.2k
                auto poPoly =
843
21.2k
                    OGRGeoJSONReadPolygon(poObjPoly, bHasM, /* bRaw = */ true);
844
21.2k
                if (poPoly)
845
17.5k
                {
846
17.5k
                    poMultiPoly->addGeometry(std::move(poPoly));
847
17.5k
                }
848
21.2k
            }
849
31.3k
        }
850
10.4k
    }
851
5
    else
852
5
    {
853
5
        CPLError(CE_Warning, CPLE_AppDefined,
854
5
                 "OGRGeoJSONReadMultiPolygon(): unexpected type of JSON "
855
5
                 "construct %s for '%s'. Expected array.",
856
5
                 GetJSONConstructName(json_object_get_type(poObjPolys)),
857
5
                 json_object_to_json_string(poObjPolys));
858
5
    }
859
860
10.4k
    return poMultiPoly;
861
13.2k
}
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
3.62k
{
873
3.62k
    CPLAssert(nullptr != poObj);
874
875
3.62k
    json_object *poObjGeoms = OGRGeoJSONFindMemberByName(poObj, "geometries");
876
3.62k
    if (nullptr == poObjGeoms)
877
2.32k
    {
878
2.32k
        CPLError(CE_Failure, CPLE_AppDefined,
879
2.32k
                 "Invalid %s object. "
880
2.32k
                 "Missing \'geometries\' member.",
881
2.32k
                 pszGeomTypeName);
882
2.32k
        return nullptr;
883
2.32k
    }
884
885
1.30k
    std::unique_ptr<T> poCollection;
886
887
1.30k
    if (json_type_array == json_object_get_type(poObjGeoms))
888
1.09k
    {
889
1.09k
        poCollection = std::make_unique<T>();
890
1.09k
        poCollection->assignSpatialReference(poSRS);
891
892
1.09k
        const int nGeoms =
893
1.09k
            static_cast<int>(json_object_array_length(poObjGeoms));
894
3.30k
        for (int i = 0; i < nGeoms; ++i)
895
2.20k
        {
896
2.20k
            json_object *poObjGeom = json_object_array_get_idx(poObjGeoms, i);
897
2.20k
            if (!poObjGeom)
898
1.39k
            {
899
1.39k
                CPLError(CE_Warning, CPLE_AppDefined,
900
1.39k
                         "%s(): skipping null "
901
1.39k
                         "sub-geometry",
902
1.39k
                         pszFuncName);
903
1.39k
                continue;
904
1.39k
            }
905
906
808
            auto poGeometry = OGRGeoJSONReadGeometry(poObjGeom, bHasM, poSRS);
907
808
            if (poGeometry)
908
7
            {
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
7
                {
952
7
                    const auto eChildType = poGeometry->getGeometryType();
953
7
                    if (poCollection->addGeometry(std::move(poGeometry)) !=
954
7
                        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
7
                }
964
7
            }
965
808
        }
966
1.09k
    }
967
208
    else
968
208
    {
969
208
        CPLError(CE_Warning, CPLE_AppDefined,
970
208
                 "%s(): unexpected type of JSON "
971
208
                 "construct %s for '%s'. Expected array.",
972
208
                 pszFuncName,
973
208
                 GetJSONConstructName(json_object_get_type(poObjGeoms)),
974
208
                 json_object_to_json_string(poObjGeoms));
975
208
    }
976
977
1.30k
    return poCollection;
978
3.62k
}
ogrgeojsongeometry.cpp:std::__1::unique_ptr<OGRGeometryCollection, std::__1::default_delete<OGRGeometryCollection> > OGRGeoJSONReadCollection<OGRGeometryCollection>(char const*, char const*, json_object*, bool, OGRSpatialReference const*)
Line
Count
Source
872
3.61k
{
873
3.61k
    CPLAssert(nullptr != poObj);
874
875
3.61k
    json_object *poObjGeoms = OGRGeoJSONFindMemberByName(poObj, "geometries");
876
3.61k
    if (nullptr == poObjGeoms)
877
2.30k
    {
878
2.30k
        CPLError(CE_Failure, CPLE_AppDefined,
879
2.30k
                 "Invalid %s object. "
880
2.30k
                 "Missing \'geometries\' member.",
881
2.30k
                 pszGeomTypeName);
882
2.30k
        return nullptr;
883
2.30k
    }
884
885
1.30k
    std::unique_ptr<T> poCollection;
886
887
1.30k
    if (json_type_array == json_object_get_type(poObjGeoms))
888
1.09k
    {
889
1.09k
        poCollection = std::make_unique<T>();
890
1.09k
        poCollection->assignSpatialReference(poSRS);
891
892
1.09k
        const int nGeoms =
893
1.09k
            static_cast<int>(json_object_array_length(poObjGeoms));
894
3.30k
        for (int i = 0; i < nGeoms; ++i)
895
2.20k
        {
896
2.20k
            json_object *poObjGeom = json_object_array_get_idx(poObjGeoms, i);
897
2.20k
            if (!poObjGeom)
898
1.39k
            {
899
1.39k
                CPLError(CE_Warning, CPLE_AppDefined,
900
1.39k
                         "%s(): skipping null "
901
1.39k
                         "sub-geometry",
902
1.39k
                         pszFuncName);
903
1.39k
                continue;
904
1.39k
            }
905
906
808
            auto poGeometry = OGRGeoJSONReadGeometry(poObjGeom, bHasM, poSRS);
907
808
            if (poGeometry)
908
7
            {
909
                if constexpr (std::is_same_v<T, OGRCompoundCurve>)
910
                {
911
                    auto eFlatType = wkbFlatten(poGeometry->getGeometryType());
912
                    if (eFlatType == wkbLineString ||
913
                        eFlatType == wkbCircularString)
914
                    {
915
                        if (poCollection->addCurve(std::unique_ptr<OGRCurve>(
916
                                poGeometry.release()->toCurve())) !=
917
                            OGRERR_NONE)
918
                            return nullptr;
919
                    }
920
                    else
921
                    {
922
                        CPLError(CE_Warning, CPLE_AppDefined,
923
                                 "%s(): member of a CompoundCurve is not a "
924
                                 "LineString or CircularString.",
925
                                 pszFuncName);
926
                        return nullptr;
927
                    }
928
                }
929
                else if constexpr (std::is_same_v<T, OGRCurvePolygon>)
930
                {
931
                    auto eFlatType = wkbFlatten(poGeometry->getGeometryType());
932
                    if (eFlatType == wkbLineString ||
933
                        eFlatType == wkbCircularString ||
934
                        eFlatType == wkbCompoundCurve)
935
                    {
936
                        if (poCollection->addRing(std::unique_ptr<OGRCurve>(
937
                                poGeometry.release()->toCurve())) !=
938
                            OGRERR_NONE)
939
                            return nullptr;
940
                    }
941
                    else
942
                    {
943
                        CPLError(CE_Warning, CPLE_AppDefined,
944
                                 "%s(): member of a CurvePolygon is not a "
945
                                 "LineString, CircularString or CompoundCurve.",
946
                                 pszFuncName);
947
                        return nullptr;
948
                    }
949
                }
950
                else
951
7
                {
952
7
                    const auto eChildType = poGeometry->getGeometryType();
953
7
                    if (poCollection->addGeometry(std::move(poGeometry)) !=
954
7
                        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
7
                }
964
7
            }
965
808
        }
966
1.09k
    }
967
208
    else
968
208
    {
969
208
        CPLError(CE_Warning, CPLE_AppDefined,
970
208
                 "%s(): unexpected type of JSON "
971
208
                 "construct %s for '%s'. Expected array.",
972
208
                 pszFuncName,
973
208
                 GetJSONConstructName(json_object_get_type(poObjGeoms)),
974
208
                 json_object_to_json_string(poObjGeoms));
975
208
    }
976
977
1.30k
    return poCollection;
978
3.61k
}
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*)
ogrgeojsongeometry.cpp:std::__1::unique_ptr<OGRMultiCurve, std::__1::default_delete<OGRMultiCurve> > OGRGeoJSONReadCollection<OGRMultiCurve>(char const*, char const*, json_object*, bool, OGRSpatialReference const*)
Line
Count
Source
872
11
{
873
11
    CPLAssert(nullptr != poObj);
874
875
11
    json_object *poObjGeoms = OGRGeoJSONFindMemberByName(poObj, "geometries");
876
11
    if (nullptr == poObjGeoms)
877
11
    {
878
11
        CPLError(CE_Failure, CPLE_AppDefined,
879
11
                 "Invalid %s object. "
880
11
                 "Missing \'geometries\' member.",
881
11
                 pszGeomTypeName);
882
11
        return nullptr;
883
11
    }
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
                {
911
                    auto eFlatType = wkbFlatten(poGeometry->getGeometryType());
912
                    if (eFlatType == wkbLineString ||
913
                        eFlatType == wkbCircularString)
914
                    {
915
                        if (poCollection->addCurve(std::unique_ptr<OGRCurve>(
916
                                poGeometry.release()->toCurve())) !=
917
                            OGRERR_NONE)
918
                            return nullptr;
919
                    }
920
                    else
921
                    {
922
                        CPLError(CE_Warning, CPLE_AppDefined,
923
                                 "%s(): member of a CompoundCurve is not a "
924
                                 "LineString or CircularString.",
925
                                 pszFuncName);
926
                        return nullptr;
927
                    }
928
                }
929
                else if constexpr (std::is_same_v<T, OGRCurvePolygon>)
930
                {
931
                    auto eFlatType = wkbFlatten(poGeometry->getGeometryType());
932
                    if (eFlatType == wkbLineString ||
933
                        eFlatType == wkbCircularString ||
934
                        eFlatType == wkbCompoundCurve)
935
                    {
936
                        if (poCollection->addRing(std::unique_ptr<OGRCurve>(
937
                                poGeometry.release()->toCurve())) !=
938
                            OGRERR_NONE)
939
                            return nullptr;
940
                    }
941
                    else
942
                    {
943
                        CPLError(CE_Warning, CPLE_AppDefined,
944
                                 "%s(): member of a CurvePolygon is not a "
945
                                 "LineString, CircularString or CompoundCurve.",
946
                                 pszFuncName);
947
                        return nullptr;
948
                    }
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
11
}
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
3.61k
{
988
3.61k
    return OGRGeoJSONReadCollection<OGRGeometryCollection>(
989
3.61k
        __func__, "GeometryCollection", poObj, bHasM, poSRS);
990
3.61k
}
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
11
{
1023
11
    return OGRGeoJSONReadCollection<OGRMultiCurve>(__func__, "MultiCurve",
1024
11
                                                   poObj, bHasM, poSRS);
1025
11
}
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
307k
{
1045
1046
    /* -------------------------------------------------------------------- */
1047
    /*      Read spatial reference definition.                              */
1048
    /* -------------------------------------------------------------------- */
1049
307k
    OGRSpatialReference *poSRS = nullptr;
1050
1051
307k
    json_object *poObjSrs = OGRGeoJSONFindMemberByName(poObj, "crs");
1052
307k
    if (nullptr != poObjSrs)
1053
306k
    {
1054
306k
        json_object *poObjSrsType =
1055
306k
            OGRGeoJSONFindMemberByName(poObjSrs, "type");
1056
306k
        if (poObjSrsType == nullptr)
1057
8.75k
            return nullptr;
1058
1059
297k
        const char *pszSrsType = json_object_get_string(poObjSrsType);
1060
1061
        // TODO: Add URL and URN types support.
1062
297k
        if (STARTS_WITH_CI(pszSrsType, "NAME"))
1063
187k
        {
1064
187k
            json_object *poObjSrsProps =
1065
187k
                OGRGeoJSONFindMemberByName(poObjSrs, "properties");
1066
187k
            if (poObjSrsProps == nullptr)
1067
3.31k
                return nullptr;
1068
1069
184k
            json_object *poNameURL =
1070
184k
                OGRGeoJSONFindMemberByName(poObjSrsProps, "name");
1071
184k
            if (poNameURL == nullptr)
1072
3.71k
                return nullptr;
1073
1074
180k
            const char *pszName = json_object_get_string(poNameURL);
1075
1076
180k
            if (EQUAL(pszName, "urn:ogc:def:crs:OGC:1.3:CRS84"))
1077
91
                pszName = "EPSG:4326";
1078
1079
180k
            poSRS = new OGRSpatialReference();
1080
180k
            poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1081
180k
            if (OGRERR_NONE !=
1082
180k
                poSRS->SetFromUserInput(
1083
180k
                    pszName,
1084
180k
                    OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get()))
1085
102k
            {
1086
102k
                delete poSRS;
1087
102k
                poSRS = nullptr;
1088
102k
            }
1089
180k
        }
1090
1091
110k
        else if (STARTS_WITH_CI(pszSrsType, "EPSG"))
1092
909
        {
1093
909
            json_object *poObjSrsProps =
1094
909
                OGRGeoJSONFindMemberByName(poObjSrs, "properties");
1095
909
            if (poObjSrsProps == nullptr)
1096
89
                return nullptr;
1097
1098
820
            json_object *poObjCode =
1099
820
                OGRGeoJSONFindMemberByName(poObjSrsProps, "code");
1100
820
            if (poObjCode == nullptr)
1101
339
                return nullptr;
1102
1103
481
            int nEPSG = json_object_get_int(poObjCode);
1104
1105
481
            poSRS = new OGRSpatialReference();
1106
481
            poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1107
481
            if (OGRERR_NONE != poSRS->importFromEPSG(nEPSG))
1108
481
            {
1109
481
                delete poSRS;
1110
481
                poSRS = nullptr;
1111
481
            }
1112
481
        }
1113
1114
109k
        else if (STARTS_WITH_CI(pszSrsType, "URL") ||
1115
76.9k
                 STARTS_WITH_CI(pszSrsType, "LINK"))
1116
32.2k
        {
1117
32.2k
            json_object *poObjSrsProps =
1118
32.2k
                OGRGeoJSONFindMemberByName(poObjSrs, "properties");
1119
32.2k
            if (poObjSrsProps == nullptr)
1120
1.53k
                return nullptr;
1121
1122
30.7k
            json_object *poObjURL =
1123
30.7k
                OGRGeoJSONFindMemberByName(poObjSrsProps, "url");
1124
1125
30.7k
            if (nullptr == poObjURL)
1126
1.36k
            {
1127
1.36k
                poObjURL = OGRGeoJSONFindMemberByName(poObjSrsProps, "href");
1128
1.36k
            }
1129
30.7k
            if (poObjURL == nullptr)
1130
1.36k
                return nullptr;
1131
1132
29.3k
            const char *pszURL = json_object_get_string(poObjURL);
1133
1134
29.3k
            poSRS = new OGRSpatialReference();
1135
29.3k
            poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1136
29.3k
            if (OGRERR_NONE != poSRS->importFromUrl(pszURL))
1137
29.3k
            {
1138
29.3k
                delete poSRS;
1139
29.3k
                poSRS = nullptr;
1140
29.3k
            }
1141
29.3k
        }
1142
1143
76.8k
        else if (EQUAL(pszSrsType, "OGC"))
1144
73.2k
        {
1145
73.2k
            json_object *poObjSrsProps =
1146
73.2k
                OGRGeoJSONFindMemberByName(poObjSrs, "properties");
1147
73.2k
            if (poObjSrsProps == nullptr)
1148
2.25k
                return nullptr;
1149
1150
70.9k
            json_object *poObjURN =
1151
70.9k
                OGRGeoJSONFindMemberByName(poObjSrsProps, "urn");
1152
70.9k
            if (poObjURN == nullptr)
1153
2.16k
                return nullptr;
1154
1155
68.8k
            poSRS = new OGRSpatialReference();
1156
68.8k
            poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1157
68.8k
            if (OGRERR_NONE !=
1158
68.8k
                poSRS->importFromURN(json_object_get_string(poObjURN)))
1159
40.5k
            {
1160
40.5k
                delete poSRS;
1161
40.5k
                poSRS = nullptr;
1162
40.5k
            }
1163
68.8k
        }
1164
297k
    }
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
283k
    if (poSRS != nullptr)
1171
106k
    {
1172
106k
        OGR_SRSNode *poGEOGCS = poSRS->GetAttrNode("GEOGCS");
1173
106k
        if (poGEOGCS != nullptr)
1174
34.4k
            poGEOGCS->StripNodes("AXIS");
1175
106k
    }
1176
1177
283k
    return poSRS;
1178
307k
}
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
1.05M
{
1187
1.05M
    if (nullptr == pszJson)
1188
0
    {
1189
        // Translation failed.
1190
0
        return nullptr;
1191
0
    }
1192
1193
1.05M
    json_object *poObj = nullptr;
1194
1.05M
    if (!OGRJSonParse(pszJson, &poObj))
1195
706k
        return nullptr;
1196
1197
350k
    OGRGeometry *poGeometry =
1198
350k
        OGRGeoJSONReadGeometry(poObj, /* bHasM = */ false,
1199
350k
                               /* OGRSpatialReference* = */ nullptr)
1200
350k
            .release();
1201
1202
    // Release JSON tree.
1203
350k
    json_object_put(poObj);
1204
1205
350k
    return OGRGeometry::ToHandle(poGeometry);
1206
1.05M
}
1207
1208
/*! @endcond */