Coverage Report

Created: 2026-08-14 09:29

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
959k
{
48
959k
    if (nullptr == poObj)
49
0
        return GeoJSONObject::eUnknown;
50
51
959k
    json_object *poObjType = OGRGeoJSONFindMemberByName(poObj, "type");
52
959k
    if (nullptr == poObjType)
53
467k
        return GeoJSONObject::eUnknown;
54
55
492k
    const char *name = json_object_get_string(poObjType);
56
57
492k
#define ASSOC(x)                                                               \
58
6.89M
    {                                                                          \
59
6.89M
        #x, GeoJSONObject::e##x                                                \
60
6.89M
    }
61
62
492k
    static const struct
63
492k
    {
64
492k
        const char *pszName;
65
492k
        GeoJSONObject::Type eType;
66
492k
    } tabAssoc[] = {
67
492k
        ASSOC(Point),
68
492k
        ASSOC(LineString),
69
492k
        ASSOC(Polygon),
70
492k
        ASSOC(MultiPoint),
71
492k
        ASSOC(MultiLineString),
72
492k
        ASSOC(MultiPolygon),
73
492k
        ASSOC(GeometryCollection),
74
492k
        ASSOC(CircularString),
75
492k
        ASSOC(CompoundCurve),
76
492k
        ASSOC(CurvePolygon),
77
492k
        ASSOC(MultiCurve),
78
492k
        ASSOC(MultiSurface),
79
492k
        ASSOC(Feature),
80
492k
        ASSOC(FeatureCollection),
81
492k
    };
82
83
492k
#undef ASSOC
84
85
492k
    for (const auto &assoc : tabAssoc)
86
5.28M
    {
87
5.28M
        if (EQUAL(name, assoc.pszName))
88
424k
            return assoc.eType;
89
5.28M
    }
90
91
67.4k
    return GeoJSONObject::eUnknown;
92
492k
}
93
94
/************************************************************************/
95
/*                        OGRJSONFGHasMeasure()                         */
96
/************************************************************************/
97
98
bool OGRJSONFGHasMeasure(json_object *poObj, bool bUpperLevelMValue)
99
508k
{
100
508k
    bool bHasM = bUpperLevelMValue;
101
508k
    if (json_object *pojMeasures =
102
508k
            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 = CPL_TO_BOOL(json_object_get_boolean(poEnabled));
107
0
    }
108
508k
    return bHasM;
109
508k
}
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
53.5k
{
144
53.5k
    if (nullptr == poObj)
145
903
        return wkbUnknown;
146
147
52.6k
    json_object *poObjType = CPL_json_object_object_get(poObj, "type");
148
52.6k
    if (nullptr == poObjType)
149
1.32k
        return wkbUnknown;
150
151
51.3k
    const char *name = json_object_get_string(poObjType);
152
153
51.3k
    OGRwkbGeometryType eType = wkbNone;
154
51.3k
    for (const auto &assoc : asAssocGeometryTypes)
155
219k
    {
156
219k
        if (EQUAL(name, assoc.pszName))
157
47.8k
        {
158
47.8k
            eType = assoc.eType;
159
47.8k
            break;
160
47.8k
        }
161
219k
    }
162
51.3k
    if (eType == wkbNone)
163
3.49k
        return wkbUnknown;
164
165
47.8k
    bHasM = OGRJSONFGHasMeasure(poObj, bHasM);
166
167
47.8k
    json_object *poCoordinates;
168
47.8k
    if (eType == wkbGeometryCollection || eType == wkbMultiCurve ||
169
44.3k
        eType == wkbMultiSurface || eType == wkbCompoundCurve ||
170
44.3k
        eType == wkbCurvePolygon)
171
3.44k
    {
172
3.44k
        json_object *poGeometries =
173
3.44k
            CPL_json_object_object_get(poObj, "geometries");
174
3.44k
        if (poGeometries &&
175
1.29k
            json_object_get_type(poGeometries) == json_type_array &&
176
1.28k
            json_object_array_length(poGeometries) > 0)
177
1.19k
        {
178
1.19k
            const auto subGeomType = OGRGeoJSONGetOGRGeometryType(
179
1.19k
                json_object_array_get_idx(poGeometries, 0), bHasM);
180
1.19k
            if (OGR_GT_HasZ(subGeomType))
181
8
                eType = OGR_GT_SetZ(eType);
182
1.19k
        }
183
3.44k
    }
184
44.3k
    else
185
44.3k
    {
186
44.3k
        poCoordinates = CPL_json_object_object_get(poObj, "coordinates");
187
44.3k
        if (poCoordinates &&
188
38.3k
            json_object_get_type(poCoordinates) == json_type_array &&
189
38.3k
            json_object_array_length(poCoordinates) > 0)
190
33.6k
        {
191
47.2k
            while (true)
192
47.2k
            {
193
47.2k
                auto poChild = json_object_array_get_idx(poCoordinates, 0);
194
47.2k
                if (!(poChild &&
195
32.6k
                      json_object_get_type(poChild) == json_type_array &&
196
19.4k
                      json_object_array_length(poChild) > 0))
197
33.6k
                {
198
33.6k
                    const auto nLength =
199
33.6k
                        json_object_array_length(poCoordinates);
200
33.6k
                    if ((bHasM && nLength == 4) || (!bHasM && nLength == 3))
201
5.31k
                        eType = OGR_GT_SetZ(eType);
202
33.6k
                    break;
203
33.6k
                }
204
13.5k
                poCoordinates = poChild;
205
13.5k
            }
206
33.6k
        }
207
44.3k
    }
208
47.8k
    if (bHasM)
209
0
        eType = OGR_GT_SetM(eType);
210
211
47.8k
    return eType;
212
51.3k
}
213
214
/************************************************************************/
215
/*                     OGRGeoJSONGetGeometryName()                      */
216
/************************************************************************/
217
218
const char *OGRGeoJSONGetGeometryName(OGRGeometry const *poGeometry)
219
680k
{
220
680k
    CPLAssert(nullptr != poGeometry);
221
222
680k
    const OGRwkbGeometryType eType = wkbFlatten(poGeometry->getGeometryType());
223
224
680k
    for (const auto &assoc : asAssocGeometryTypes)
225
2.00M
    {
226
2.00M
        if (eType == assoc.eType)
227
679k
        {
228
679k
            return assoc.pszName;
229
679k
        }
230
2.00M
    }
231
638
    return "Unknown";
232
680k
}
233
234
/************************************************************************/
235
/*                        OGRGeoJSONReadGeometry                        */
236
/************************************************************************/
237
238
std::unique_ptr<OGRGeometry>
239
OGRGeoJSONReadGeometry(json_object *poObj, bool bHasM,
240
                       const OGRSpatialReference *poParentSRS)
241
460k
{
242
243
460k
    std::unique_ptr<OGRGeometry> poGeometry;
244
460k
    OGRSpatialReference *poSRS = nullptr;
245
460k
    lh_entry *entry = OGRGeoJSONFindMemberEntryByName(poObj, "crs");
246
460k
    if (entry != nullptr)
247
337k
    {
248
337k
        json_object *poObjSrs =
249
337k
            static_cast<json_object *>(const_cast<void *>(entry->v));
250
337k
        if (poObjSrs != nullptr)
251
336k
        {
252
336k
            poSRS = OGRGeoJSONReadSpatialReference(poObj);
253
336k
        }
254
337k
    }
255
256
460k
    const OGRSpatialReference *poSRSToAssign = nullptr;
257
460k
    if (entry != nullptr)
258
337k
    {
259
337k
        poSRSToAssign = poSRS;
260
337k
    }
261
122k
    else if (poParentSRS)
262
62.2k
    {
263
62.2k
        poSRSToAssign = poParentSRS;
264
62.2k
    }
265
60.4k
    else
266
60.4k
    {
267
        // Assign WGS84 if no CRS defined on geometry.
268
60.4k
        poSRSToAssign = OGRSpatialReference::GetWGS84SRS();
269
60.4k
    }
270
271
460k
    bHasM = OGRJSONFGHasMeasure(poObj, bHasM);
272
273
460k
    const auto objType = OGRGeoJSONGetType(poObj);
274
460k
    switch (objType)
275
460k
    {
276
23.1k
        case GeoJSONObject::ePoint:
277
23.1k
            poGeometry = OGRGeoJSONReadPoint(poObj, bHasM);
278
23.1k
            break;
279
280
15.1k
        case GeoJSONObject::eLineString:
281
15.1k
            poGeometry = OGRGeoJSONReadLineString(poObj, bHasM,
282
15.1k
                                                  /* bRaw = */ false);
283
15.1k
            break;
284
285
9.55k
        case GeoJSONObject::ePolygon:
286
9.55k
            poGeometry =
287
9.55k
                OGRGeoJSONReadPolygon(poObj, bHasM, /* bRaw = */ false);
288
9.55k
            break;
289
290
10.6k
        case GeoJSONObject::eMultiPoint:
291
10.6k
            poGeometry = OGRGeoJSONReadMultiPoint(poObj, bHasM);
292
10.6k
            break;
293
294
7.21k
        case GeoJSONObject::eMultiLineString:
295
7.21k
            poGeometry = OGRGeoJSONReadMultiLineString(poObj, bHasM);
296
7.21k
            break;
297
298
20.2k
        case GeoJSONObject::eMultiPolygon:
299
20.2k
            poGeometry = OGRGeoJSONReadMultiPolygon(poObj, bHasM);
300
20.2k
            break;
301
302
5.36k
        case GeoJSONObject::eGeometryCollection:
303
5.36k
            poGeometry =
304
5.36k
                OGRGeoJSONReadGeometryCollection(poObj, bHasM, poSRSToAssign);
305
5.36k
            break;
306
307
9
        case GeoJSONObject::eCircularString:
308
9
            poGeometry = OGRGeoJSONReadCircularString(poObj, bHasM);
309
9
            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
59
        case GeoJSONObject::eMultiCurve:
321
59
            poGeometry = OGRGeoJSONReadMultiCurve(poObj, bHasM, poSRSToAssign);
322
59
            break;
323
324
0
        case GeoJSONObject::eMultiSurface:
325
0
            poGeometry =
326
0
                OGRGeoJSONReadMultiSurface(poObj, bHasM, poSRSToAssign);
327
0
            break;
328
329
3.54k
        case GeoJSONObject::eFeature:
330
3.64k
        case GeoJSONObject::eFeatureCollection:
331
3.64k
            [[fallthrough]];
332
369k
        case GeoJSONObject::eUnknown:
333
369k
            CPLError(CE_Warning, CPLE_AppDefined,
334
369k
                     "Unsupported geometry type detected. "
335
369k
                     "Feature gets NULL geometry assigned.");
336
369k
            break;
337
460k
    }
338
339
460k
    if (poGeometry && GeoJSONObject::eGeometryCollection != objType)
340
25.9k
        poGeometry->assignSpatialReference(poSRSToAssign);
341
342
460k
    if (poSRS)
343
116k
        poSRS->Release();
344
345
460k
    return poGeometry;
346
460k
}
347
348
/************************************************************************/
349
/*                        GetJSONConstructName()                        */
350
/************************************************************************/
351
352
static const char *GetJSONConstructName(json_type eType)
353
22.7k
{
354
22.7k
    switch (eType)
355
22.7k
    {
356
8.00k
        case json_type_null:
357
8.00k
            break;
358
0
        case json_type_boolean:
359
0
            return "boolean";
360
18
        case json_type_double:
361
18
            return "double";
362
10.8k
        case json_type_int:
363
10.8k
            return "int";
364
70
        case json_type_object:
365
70
            return "object";
366
206
        case json_type_array:
367
206
            return "array";
368
3.60k
        case json_type_string:
369
3.60k
            return "string";
370
22.7k
    }
371
8.00k
    return "null";
372
22.7k
}
373
374
/************************************************************************/
375
/*                      OGRGeoJSONGetCoordinate()                       */
376
/************************************************************************/
377
378
static double OGRGeoJSONGetCoordinate(json_object *poObj,
379
                                      const char *pszCoordName, int nIndex,
380
                                      bool &bValid)
381
102k
{
382
102k
    json_object *poObjCoord = json_object_array_get_idx(poObj, nIndex);
383
102k
    if (nullptr == poObjCoord)
384
10.7k
    {
385
10.7k
        CPLDebug("GeoJSON", "Point: got null object for %s.", pszCoordName);
386
10.7k
        bValid = false;
387
10.7k
        return 0.0;
388
10.7k
    }
389
390
91.7k
    const json_type eType = json_object_get_type(poObjCoord);
391
91.7k
    if (json_type_double != eType && json_type_int != eType)
392
213
    {
393
213
        CPLError(CE_Failure, CPLE_AppDefined,
394
213
                 "OGRGeoJSONGetCoordinate(): invalid '%s' coordinate. "
395
213
                 "Unexpected type %s for '%s'. Expected double or integer.",
396
213
                 pszCoordName, GetJSONConstructName(eType),
397
213
                 json_object_to_json_string(poObjCoord));
398
213
        bValid = false;
399
213
        return 0.0;
400
213
    }
401
402
91.5k
    return json_object_get_double(poObjCoord);
403
91.7k
}
404
405
/************************************************************************/
406
/*                        OGRGeoJSONReadRawPoint                        */
407
/************************************************************************/
408
409
static bool OGRGeoJSONReadRawPoint(json_object *poObj, OGRPoint &point,
410
                                   bool bHasM)
411
70.1k
{
412
70.1k
    if (json_type_array == json_object_get_type(poObj))
413
53.2k
    {
414
53.2k
        const int nSize = static_cast<int>(json_object_array_length(poObj));
415
416
53.2k
        if (nSize < GeoJSONObject::eMinCoordinateDimension)
417
5.60k
        {
418
5.60k
            CPLError(CE_Warning, CPLE_AppDefined,
419
5.60k
                     "OGRGeoJSONReadRawPoint(): "
420
5.60k
                     "Invalid coord dimension for '%s'. "
421
5.60k
                     "At least 2 dimensions must be present.",
422
5.60k
                     json_object_to_json_string(poObj));
423
5.60k
            return false;
424
5.60k
        }
425
426
47.6k
        bool bValid = true;
427
47.6k
        const double dfX = OGRGeoJSONGetCoordinate(poObj, "x", 0, bValid);
428
47.6k
        const double dfY = OGRGeoJSONGetCoordinate(poObj, "y", 1, bValid);
429
47.6k
        point.setX(dfX);
430
47.6k
        point.setY(dfY);
431
432
        // Read Z and/or M coordinate.
433
47.6k
        if (nSize > GeoJSONObject::eMinCoordinateDimension)
434
7.20k
        {
435
7.20k
            const int nMaxDim =
436
7.20k
                bHasM ? GeoJSONObject::eMaxCoordinateDimensionJSONFG
437
7.20k
                      : GeoJSONObject::eMaxCoordinateDimensionGeoJSON;
438
7.20k
            if (nSize > nMaxDim)
439
180
            {
440
180
                CPLErrorOnce(CE_Warning, CPLE_AppDefined,
441
180
                             "OGRGeoJSONReadRawPoint(): too many members in "
442
180
                             "array '%s': %d. At most %d are handled. Ignoring "
443
180
                             "extra members.",
444
180
                             json_object_to_json_string(poObj), nSize, nMaxDim);
445
180
            }
446
            // Don't *expect* mixed-dimension geometries, although the
447
            // spec doesn't explicitly forbid this.
448
7.20k
            if (nSize == 4 || (nSize == 3 && !bHasM))
449
7.20k
            {
450
7.20k
                const double dfZ =
451
7.20k
                    OGRGeoJSONGetCoordinate(poObj, "z", 2, bValid);
452
7.20k
                point.setZ(dfZ);
453
7.20k
            }
454
455
7.20k
            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
7.20k
        }
462
40.4k
        else
463
40.4k
        {
464
40.4k
            point.flattenTo2D();
465
40.4k
        }
466
47.6k
        return bValid;
467
53.2k
    }
468
16.8k
    else
469
16.8k
    {
470
16.8k
        CPLError(CE_Failure, CPLE_AppDefined,
471
16.8k
                 "OGRGeoJSONReadRawPoint(): invalid Point. "
472
16.8k
                 "Unexpected type %s for '%s'. Expected array.",
473
16.8k
                 GetJSONConstructName(json_object_get_type(poObj)),
474
16.8k
                 json_object_to_json_string(poObj));
475
16.8k
    }
476
477
16.8k
    return false;
478
70.1k
}
479
480
/************************************************************************/
481
/*                         OGRGeoJSONReadPoint                          */
482
/************************************************************************/
483
484
std::unique_ptr<OGRPoint> OGRGeoJSONReadPoint(json_object *poObj, bool bHasM)
485
23.1k
{
486
23.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
23.1k
    json_object *poObjCoords = OGRGeoJSONFindMemberByName(poObj, "coordinates");
493
23.1k
    if (nullptr == poObjCoords)
494
6.90k
    {
495
6.90k
        CPLError(CE_Failure, CPLE_AppDefined,
496
6.90k
                 "OGRGeoJSONReadPoint(): invalid Point object. "
497
6.90k
                 "Missing \'coordinates\' member.");
498
6.90k
        return nullptr;
499
6.90k
    }
500
501
16.2k
    auto poPoint = std::make_unique<OGRPoint>();
502
16.2k
    if (!OGRGeoJSONReadRawPoint(poObjCoords, *poPoint, bHasM))
503
14.6k
    {
504
14.6k
        return nullptr;
505
14.6k
    }
506
507
1.61k
    return poPoint;
508
16.2k
}
509
510
/************************************************************************/
511
/*                       OGRGeoJSONReadMultiPoint                       */
512
/************************************************************************/
513
514
std::unique_ptr<OGRMultiPoint> OGRGeoJSONReadMultiPoint(json_object *poObj,
515
                                                        bool bHasM)
516
10.6k
{
517
10.6k
    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
10.6k
    json_object *poObjPoints = OGRGeoJSONFindMemberByName(poObj, "coordinates");
525
10.6k
    if (nullptr == poObjPoints)
526
5.04k
    {
527
5.04k
        CPLError(CE_Failure, CPLE_AppDefined,
528
5.04k
                 "Invalid MultiPoint object. "
529
5.04k
                 "Missing \'coordinates\' member.");
530
5.04k
        return nullptr;
531
5.04k
    }
532
533
5.62k
    std::unique_ptr<OGRMultiPoint> poMultiPoint;
534
5.62k
    if (json_type_array == json_object_get_type(poObjPoints))
535
5.13k
    {
536
5.13k
        const auto nPoints = json_object_array_length(poObjPoints);
537
538
5.13k
        poMultiPoint = std::make_unique<OGRMultiPoint>();
539
540
8.96k
        for (auto i = decltype(nPoints){0}; i < nPoints; ++i)
541
6.56k
        {
542
6.56k
            json_object *poObjCoords =
543
6.56k
                json_object_array_get_idx(poObjPoints, i);
544
545
6.56k
            OGRPoint pt;
546
6.56k
            if (!OGRGeoJSONReadRawPoint(poObjCoords, pt, bHasM))
547
2.72k
            {
548
2.72k
                return nullptr;
549
2.72k
            }
550
3.83k
            poMultiPoint->addGeometry(&pt);
551
3.83k
        }
552
5.13k
    }
553
490
    else
554
490
    {
555
490
        CPLError(CE_Failure, CPLE_AppDefined,
556
490
                 "OGRGeoJSONReadMultiPoint(): invalid MultiPoint. "
557
490
                 "Unexpected type %s for '%s'. Expected array.",
558
490
                 GetJSONConstructName(json_object_get_type(poObjPoints)),
559
490
                 json_object_to_json_string(poObjPoints));
560
490
    }
561
562
2.89k
    return poMultiPoint;
563
5.62k
}
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
43.5k
{
574
43.5k
    if (!poObj)
575
801
    {
576
801
        CPLError(CE_Failure, CPLE_AppDefined,
577
801
                 "%s(): invalid LineString object. Got null.", pszFuncName);
578
801
        return nullptr;
579
801
    }
580
42.7k
    json_object *poObjPoints = nullptr;
581
582
42.7k
    if (!bRaw)
583
15.1k
    {
584
15.1k
        poObjPoints = OGRGeoJSONFindMemberByName(poObj, "coordinates");
585
15.1k
        if (nullptr == poObjPoints)
586
11.1k
        {
587
11.1k
            CPLError(CE_Failure, CPLE_AppDefined,
588
11.1k
                     "Invalid LineString object. "
589
11.1k
                     "Missing \'coordinates\' member.");
590
11.1k
            return nullptr;
591
11.1k
        }
592
15.1k
    }
593
27.5k
    else
594
27.5k
    {
595
27.5k
        poObjPoints = poObj;
596
27.5k
    }
597
598
31.5k
    std::unique_ptr<T> poLine;
599
600
31.5k
    if (json_type_array == json_object_get_type(poObjPoints))
601
28.1k
    {
602
28.1k
        const int nPoints =
603
28.1k
            static_cast<int>(json_object_array_length(poObjPoints));
604
605
28.1k
        poLine = std::make_unique<T>();
606
28.1k
        poLine->setNumPoints(nPoints);
607
608
62.1k
        for (int i = 0; i < nPoints; ++i)
609
47.3k
        {
610
47.3k
            json_object *poObjCoords =
611
47.3k
                json_object_array_get_idx(poObjPoints, i);
612
613
47.3k
            OGRPoint pt;
614
47.3k
            if (!OGRGeoJSONReadRawPoint(poObjCoords, pt, bHasM))
615
13.3k
            {
616
13.3k
                return nullptr;
617
13.3k
            }
618
34.0k
            if (pt.Is3D())
619
3.78k
                poLine->set3D(true);
620
34.0k
            if (pt.IsMeasured())
621
0
                poLine->setMeasured(true);
622
34.0k
            poLine->setPoint(i, &pt);
623
34.0k
        }
624
28.1k
    }
625
3.33k
    else
626
3.33k
    {
627
3.33k
        CPLError(CE_Failure, CPLE_AppDefined,
628
3.33k
                 "%s(): invalid geometry. "
629
3.33k
                 "Unexpected type %s for '%s'. Expected array.",
630
3.33k
                 pszFuncName,
631
3.33k
                 GetJSONConstructName(json_object_get_type(poObjPoints)),
632
3.33k
                 json_object_to_json_string(poObjPoints));
633
3.33k
    }
634
635
18.2k
    return poLine;
636
31.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
28.6k
{
574
28.6k
    if (!poObj)
575
801
    {
576
801
        CPLError(CE_Failure, CPLE_AppDefined,
577
801
                 "%s(): invalid LineString object. Got null.", pszFuncName);
578
801
        return nullptr;
579
801
    }
580
27.8k
    json_object *poObjPoints = nullptr;
581
582
27.8k
    if (!bRaw)
583
15.1k
    {
584
15.1k
        poObjPoints = OGRGeoJSONFindMemberByName(poObj, "coordinates");
585
15.1k
        if (nullptr == poObjPoints)
586
11.1k
        {
587
11.1k
            CPLError(CE_Failure, CPLE_AppDefined,
588
11.1k
                     "Invalid LineString object. "
589
11.1k
                     "Missing \'coordinates\' member.");
590
11.1k
            return nullptr;
591
11.1k
        }
592
15.1k
    }
593
12.6k
    else
594
12.6k
    {
595
12.6k
        poObjPoints = poObj;
596
12.6k
    }
597
598
16.6k
    std::unique_ptr<T> poLine;
599
600
16.6k
    if (json_type_array == json_object_get_type(poObjPoints))
601
16.3k
    {
602
16.3k
        const int nPoints =
603
16.3k
            static_cast<int>(json_object_array_length(poObjPoints));
604
605
16.3k
        poLine = std::make_unique<T>();
606
16.3k
        poLine->setNumPoints(nPoints);
607
608
25.9k
        for (int i = 0; i < nPoints; ++i)
609
20.3k
        {
610
20.3k
            json_object *poObjCoords =
611
20.3k
                json_object_array_get_idx(poObjPoints, i);
612
613
20.3k
            OGRPoint pt;
614
20.3k
            if (!OGRGeoJSONReadRawPoint(poObjCoords, pt, bHasM))
615
10.7k
            {
616
10.7k
                return nullptr;
617
10.7k
            }
618
9.59k
            if (pt.Is3D())
619
630
                poLine->set3D(true);
620
9.59k
            if (pt.IsMeasured())
621
0
                poLine->setMeasured(true);
622
9.59k
            poLine->setPoint(i, &pt);
623
9.59k
        }
624
16.3k
    }
625
291
    else
626
291
    {
627
291
        CPLError(CE_Failure, CPLE_AppDefined,
628
291
                 "%s(): invalid geometry. "
629
291
                 "Unexpected type %s for '%s'. Expected array.",
630
291
                 pszFuncName,
631
291
                 GetJSONConstructName(json_object_get_type(poObjPoints)),
632
291
                 json_object_to_json_string(poObjPoints));
633
291
    }
634
635
5.89k
    return poLine;
636
16.6k
}
ogrgeojsongeometry.cpp:std::__1::unique_ptr<OGRCircularString, std::__1::default_delete<OGRCircularString> > OGRGeoJSONReadSimpleCurve<OGRCircularString>(char const*, json_object*, bool, bool)
Line
Count
Source
573
9
{
574
9
    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
9
    json_object *poObjPoints = nullptr;
581
582
9
    if (!bRaw)
583
9
    {
584
9
        poObjPoints = OGRGeoJSONFindMemberByName(poObj, "coordinates");
585
9
        if (nullptr == poObjPoints)
586
9
        {
587
9
            CPLError(CE_Failure, CPLE_AppDefined,
588
9
                     "Invalid LineString object. "
589
9
                     "Missing \'coordinates\' member.");
590
9
            return nullptr;
591
9
        }
592
9
    }
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
}
ogrgeojsongeometry.cpp:std::__1::unique_ptr<OGRLinearRing, std::__1::default_delete<OGRLinearRing> > OGRGeoJSONReadSimpleCurve<OGRLinearRing>(char const*, json_object*, bool, bool)
Line
Count
Source
573
14.9k
{
574
14.9k
    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
14.9k
    json_object *poObjPoints = nullptr;
581
582
14.9k
    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
14.9k
    else
594
14.9k
    {
595
14.9k
        poObjPoints = poObj;
596
14.9k
    }
597
598
14.9k
    std::unique_ptr<T> poLine;
599
600
14.9k
    if (json_type_array == json_object_get_type(poObjPoints))
601
11.8k
    {
602
11.8k
        const int nPoints =
603
11.8k
            static_cast<int>(json_object_array_length(poObjPoints));
604
605
11.8k
        poLine = std::make_unique<T>();
606
11.8k
        poLine->setNumPoints(nPoints);
607
608
36.2k
        for (int i = 0; i < nPoints; ++i)
609
26.9k
        {
610
26.9k
            json_object *poObjCoords =
611
26.9k
                json_object_array_get_idx(poObjPoints, i);
612
613
26.9k
            OGRPoint pt;
614
26.9k
            if (!OGRGeoJSONReadRawPoint(poObjCoords, pt, bHasM))
615
2.58k
            {
616
2.58k
                return nullptr;
617
2.58k
            }
618
24.4k
            if (pt.Is3D())
619
3.15k
                poLine->set3D(true);
620
24.4k
            if (pt.IsMeasured())
621
0
                poLine->setMeasured(true);
622
24.4k
            poLine->setPoint(i, &pt);
623
24.4k
        }
624
11.8k
    }
625
3.04k
    else
626
3.04k
    {
627
3.04k
        CPLError(CE_Failure, CPLE_AppDefined,
628
3.04k
                 "%s(): invalid geometry. "
629
3.04k
                 "Unexpected type %s for '%s'. Expected array.",
630
3.04k
                 pszFuncName,
631
3.04k
                 GetJSONConstructName(json_object_get_type(poObjPoints)),
632
3.04k
                 json_object_to_json_string(poObjPoints));
633
3.04k
    }
634
635
12.3k
    return poLine;
636
14.9k
}
637
638
/************************************************************************/
639
/*                       OGRGeoJSONReadLineString                       */
640
/************************************************************************/
641
642
std::unique_ptr<OGRLineString> OGRGeoJSONReadLineString(json_object *poObj,
643
                                                        bool bHasM, bool bRaw)
644
28.6k
{
645
28.6k
    return OGRGeoJSONReadSimpleCurve<OGRLineString>(__func__, poObj, bHasM,
646
28.6k
                                                    bRaw);
647
28.6k
}
648
649
/************************************************************************/
650
/*                     OGRGeoJSONReadCircularString                     */
651
/************************************************************************/
652
653
std::unique_ptr<OGRCircularString>
654
OGRGeoJSONReadCircularString(json_object *poObj, bool bHasM)
655
9
{
656
9
    return OGRGeoJSONReadSimpleCurve<OGRCircularString>(__func__, poObj, bHasM,
657
9
                                                        /* bRaw = */ false);
658
9
}
659
660
/************************************************************************/
661
/*                    OGRGeoJSONReadMultiLineString                     */
662
/************************************************************************/
663
664
std::unique_ptr<OGRMultiLineString>
665
OGRGeoJSONReadMultiLineString(json_object *poObj, bool bHasM)
666
7.21k
{
667
7.21k
    CPLAssert(nullptr != poObj);
668
669
7.21k
    json_object *poObjLines = OGRGeoJSONFindMemberByName(poObj, "coordinates");
670
7.21k
    if (nullptr == poObjLines)
671
4.36k
    {
672
4.36k
        CPLError(CE_Failure, CPLE_AppDefined,
673
4.36k
                 "Invalid MultiLineString object. "
674
4.36k
                 "Missing \'coordinates\' member.");
675
4.36k
        return nullptr;
676
4.36k
    }
677
678
2.85k
    std::unique_ptr<OGRMultiLineString> poMultiLine;
679
680
2.85k
    if (json_type_array == json_object_get_type(poObjLines))
681
2.77k
    {
682
2.77k
        const auto nLines = json_object_array_length(poObjLines);
683
684
2.77k
        poMultiLine = std::make_unique<OGRMultiLineString>();
685
686
16.2k
        for (auto i = decltype(nLines){0}; i < nLines; ++i)
687
13.4k
        {
688
13.4k
            json_object *poObjLine = json_object_array_get_idx(poObjLines, i);
689
690
13.4k
            auto poLine =
691
13.4k
                OGRGeoJSONReadLineString(poObjLine, bHasM, /* bRaw = */ true);
692
13.4k
            if (poLine)
693
4.22k
            {
694
4.22k
                poMultiLine->addGeometry(std::move(poLine));
695
4.22k
            }
696
13.4k
        }
697
2.77k
    }
698
83
    else
699
83
    {
700
83
        CPLError(CE_Failure, CPLE_AppDefined,
701
83
                 "OGRGeoJSONReadLineString(): invalid LineString. "
702
83
                 "Unexpected type %s for '%s'. Expected array.",
703
83
                 GetJSONConstructName(json_object_get_type(poObjLines)),
704
83
                 json_object_to_json_string(poObjLines));
705
83
    }
706
707
2.85k
    return poMultiLine;
708
7.21k
}
709
710
/************************************************************************/
711
/*                       OGRGeoJSONReadLinearRing                       */
712
/************************************************************************/
713
714
std::unique_ptr<OGRLinearRing> OGRGeoJSONReadLinearRing(json_object *poObj,
715
                                                        bool bHasM)
716
14.9k
{
717
14.9k
    return OGRGeoJSONReadSimpleCurve<OGRLinearRing>(__func__, poObj, bHasM,
718
14.9k
                                                    /* bRaw = */ true);
719
14.9k
}
720
721
/************************************************************************/
722
/*                        OGRGeoJSONReadPolygon                         */
723
/************************************************************************/
724
725
std::unique_ptr<OGRPolygon> OGRGeoJSONReadPolygon(json_object *poObj,
726
                                                  bool bHasM, bool bRaw)
727
36.2k
{
728
36.2k
    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
36.2k
    json_object *poObjRings = nullptr;
735
736
36.2k
    if (!bRaw)
737
9.55k
    {
738
9.55k
        poObjRings = OGRGeoJSONFindMemberByName(poObj, "coordinates");
739
9.55k
        if (nullptr == poObjRings)
740
6.60k
        {
741
6.60k
            CPLError(CE_Failure, CPLE_AppDefined,
742
6.60k
                     "Invalid Polygon object. "
743
6.60k
                     "Missing \'coordinates\' member.");
744
6.60k
            return nullptr;
745
6.60k
        }
746
9.55k
    }
747
26.6k
    else
748
26.6k
    {
749
26.6k
        poObjRings = poObj;
750
26.6k
    }
751
752
29.6k
    std::unique_ptr<OGRPolygon> poPolygon;
753
754
29.6k
    if (json_type_array == json_object_get_type(poObjRings))
755
28.1k
    {
756
28.1k
        const auto nRings = json_object_array_length(poObjRings);
757
28.1k
        if (nRings > 0)
758
12.5k
        {
759
12.5k
            json_object *poObjPoints = json_object_array_get_idx(poObjRings, 0);
760
12.5k
            if (!poObjPoints)
761
3.49k
            {
762
3.49k
                poPolygon = std::make_unique<OGRPolygon>();
763
3.49k
            }
764
9.05k
            else
765
9.05k
            {
766
9.05k
                auto poRing = OGRGeoJSONReadLinearRing(poObjPoints, bHasM);
767
9.05k
                if (poRing)
768
5.72k
                {
769
5.72k
                    poPolygon = std::make_unique<OGRPolygon>();
770
5.72k
                    poPolygon->addRing(std::move(poRing));
771
5.72k
                }
772
9.05k
            }
773
774
12.5k
            for (auto i = decltype(nRings){1};
775
20.9k
                 i < nRings && nullptr != poPolygon; ++i)
776
8.42k
            {
777
8.42k
                poObjPoints = json_object_array_get_idx(poObjRings, i);
778
8.42k
                if (poObjPoints)
779
5.84k
                {
780
5.84k
                    auto poRing = OGRGeoJSONReadLinearRing(poObjPoints, bHasM);
781
5.84k
                    if (poRing)
782
3.54k
                    {
783
3.54k
                        poPolygon->addRing(std::move(poRing));
784
3.54k
                    }
785
5.84k
                }
786
8.42k
            }
787
12.5k
        }
788
15.6k
        else
789
15.6k
        {
790
15.6k
            poPolygon = std::make_unique<OGRPolygon>();
791
15.6k
        }
792
28.1k
    }
793
1.46k
    else
794
1.46k
    {
795
1.46k
        CPLError(CE_Warning, CPLE_AppDefined,
796
1.46k
                 "OGRGeoJSONReadPolygon(): unexpected type of JSON construct "
797
1.46k
                 "%s for '%s'. Expected array.",
798
1.46k
                 GetJSONConstructName(json_object_get_type(poObjRings)),
799
1.46k
                 json_object_to_json_string(poObjRings));
800
1.46k
    }
801
802
29.6k
    return poPolygon;
803
36.2k
}
804
805
/************************************************************************/
806
/*                      OGRGeoJSONReadMultiPolygon                      */
807
/************************************************************************/
808
809
std::unique_ptr<OGRMultiPolygon> OGRGeoJSONReadMultiPolygon(json_object *poObj,
810
                                                            bool bHasM)
811
20.2k
{
812
20.2k
    CPLAssert(nullptr != poObj);
813
814
20.2k
    json_object *poObjPolys = OGRGeoJSONFindMemberByName(poObj, "coordinates");
815
20.2k
    if (nullptr == poObjPolys)
816
4.97k
    {
817
4.97k
        CPLError(CE_Failure, CPLE_AppDefined,
818
4.97k
                 "Invalid MultiPolygon object. "
819
4.97k
                 "Missing \'coordinates\' member.");
820
4.97k
        return nullptr;
821
4.97k
    }
822
823
15.3k
    std::unique_ptr<OGRMultiPolygon> poMultiPoly;
824
825
15.3k
    if (json_type_array == json_object_get_type(poObjPolys))
826
15.2k
    {
827
15.2k
        const int nPolys =
828
15.2k
            static_cast<int>(json_object_array_length(poObjPolys));
829
830
15.2k
        poMultiPoly = std::make_unique<OGRMultiPolygon>();
831
832
55.7k
        for (int i = 0; i < nPolys; ++i)
833
40.4k
        {
834
40.4k
            json_object *poObjPoly = json_object_array_get_idx(poObjPolys, i);
835
40.4k
            if (!poObjPoly)
836
13.8k
            {
837
13.8k
                poMultiPoly->addGeometryDirectly(
838
13.8k
                    std::make_unique<OGRPolygon>().release());
839
13.8k
            }
840
26.6k
            else
841
26.6k
            {
842
26.6k
                auto poPoly =
843
26.6k
                    OGRGeoJSONReadPolygon(poObjPoly, bHasM, /* bRaw = */ true);
844
26.6k
                if (poPoly)
845
22.3k
                {
846
22.3k
                    poMultiPoly->addGeometry(std::move(poPoly));
847
22.3k
                }
848
26.6k
            }
849
40.4k
        }
850
15.2k
    }
851
94
    else
852
94
    {
853
94
        CPLError(CE_Warning, CPLE_AppDefined,
854
94
                 "OGRGeoJSONReadMultiPolygon(): unexpected type of JSON "
855
94
                 "construct %s for '%s'. Expected array.",
856
94
                 GetJSONConstructName(json_object_get_type(poObjPolys)),
857
94
                 json_object_to_json_string(poObjPolys));
858
94
    }
859
860
15.3k
    return poMultiPoly;
861
20.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
5.42k
{
873
5.42k
    CPLAssert(nullptr != poObj);
874
875
5.42k
    json_object *poObjGeoms = OGRGeoJSONFindMemberByName(poObj, "geometries");
876
5.42k
    if (nullptr == poObjGeoms)
877
3.54k
    {
878
3.54k
        CPLError(CE_Failure, CPLE_AppDefined,
879
3.54k
                 "Invalid %s object. "
880
3.54k
                 "Missing \'geometries\' member.",
881
3.54k
                 pszGeomTypeName);
882
3.54k
        return nullptr;
883
3.54k
    }
884
885
1.87k
    std::unique_ptr<T> poCollection;
886
887
1.87k
    if (json_type_array == json_object_get_type(poObjGeoms))
888
1.71k
    {
889
1.71k
        poCollection = std::make_unique<T>();
890
1.71k
        poCollection->assignSpatialReference(poSRS);
891
892
1.71k
        const int nGeoms =
893
1.71k
            static_cast<int>(json_object_array_length(poObjGeoms));
894
4.86k
        for (int i = 0; i < nGeoms; ++i)
895
3.14k
        {
896
3.14k
            json_object *poObjGeom = json_object_array_get_idx(poObjGeoms, i);
897
3.14k
            if (!poObjGeom)
898
2.11k
            {
899
2.11k
                CPLError(CE_Warning, CPLE_AppDefined,
900
2.11k
                         "%s(): skipping null "
901
2.11k
                         "sub-geometry",
902
2.11k
                         pszFuncName);
903
2.11k
                continue;
904
2.11k
            }
905
906
1.03k
            auto poGeometry = OGRGeoJSONReadGeometry(poObjGeom, bHasM, poSRS);
907
1.03k
            if (poGeometry)
908
10
            {
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
10
                {
952
10
                    const auto eChildType = poGeometry->getGeometryType();
953
10
                    if (poCollection->addGeometry(std::move(poGeometry)) !=
954
10
                        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
10
                }
964
10
            }
965
1.03k
        }
966
1.71k
    }
967
165
    else
968
165
    {
969
165
        CPLError(CE_Warning, CPLE_AppDefined,
970
165
                 "%s(): unexpected type of JSON "
971
165
                 "construct %s for '%s'. Expected array.",
972
165
                 pszFuncName,
973
165
                 GetJSONConstructName(json_object_get_type(poObjGeoms)),
974
165
                 json_object_to_json_string(poObjGeoms));
975
165
    }
976
977
1.87k
    return poCollection;
978
5.42k
}
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
5.36k
{
873
5.36k
    CPLAssert(nullptr != poObj);
874
875
5.36k
    json_object *poObjGeoms = OGRGeoJSONFindMemberByName(poObj, "geometries");
876
5.36k
    if (nullptr == poObjGeoms)
877
3.48k
    {
878
3.48k
        CPLError(CE_Failure, CPLE_AppDefined,
879
3.48k
                 "Invalid %s object. "
880
3.48k
                 "Missing \'geometries\' member.",
881
3.48k
                 pszGeomTypeName);
882
3.48k
        return nullptr;
883
3.48k
    }
884
885
1.87k
    std::unique_ptr<T> poCollection;
886
887
1.87k
    if (json_type_array == json_object_get_type(poObjGeoms))
888
1.71k
    {
889
1.71k
        poCollection = std::make_unique<T>();
890
1.71k
        poCollection->assignSpatialReference(poSRS);
891
892
1.71k
        const int nGeoms =
893
1.71k
            static_cast<int>(json_object_array_length(poObjGeoms));
894
4.86k
        for (int i = 0; i < nGeoms; ++i)
895
3.14k
        {
896
3.14k
            json_object *poObjGeom = json_object_array_get_idx(poObjGeoms, i);
897
3.14k
            if (!poObjGeom)
898
2.11k
            {
899
2.11k
                CPLError(CE_Warning, CPLE_AppDefined,
900
2.11k
                         "%s(): skipping null "
901
2.11k
                         "sub-geometry",
902
2.11k
                         pszFuncName);
903
2.11k
                continue;
904
2.11k
            }
905
906
1.03k
            auto poGeometry = OGRGeoJSONReadGeometry(poObjGeom, bHasM, poSRS);
907
1.03k
            if (poGeometry)
908
10
            {
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
10
                {
952
10
                    const auto eChildType = poGeometry->getGeometryType();
953
10
                    if (poCollection->addGeometry(std::move(poGeometry)) !=
954
10
                        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
10
                }
964
10
            }
965
1.03k
        }
966
1.71k
    }
967
165
    else
968
165
    {
969
165
        CPLError(CE_Warning, CPLE_AppDefined,
970
165
                 "%s(): unexpected type of JSON "
971
165
                 "construct %s for '%s'. Expected array.",
972
165
                 pszFuncName,
973
165
                 GetJSONConstructName(json_object_get_type(poObjGeoms)),
974
165
                 json_object_to_json_string(poObjGeoms));
975
165
    }
976
977
1.87k
    return poCollection;
978
5.36k
}
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
59
{
873
59
    CPLAssert(nullptr != poObj);
874
875
59
    json_object *poObjGeoms = OGRGeoJSONFindMemberByName(poObj, "geometries");
876
59
    if (nullptr == poObjGeoms)
877
59
    {
878
59
        CPLError(CE_Failure, CPLE_AppDefined,
879
59
                 "Invalid %s object. "
880
59
                 "Missing \'geometries\' member.",
881
59
                 pszGeomTypeName);
882
59
        return nullptr;
883
59
    }
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
59
}
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
5.36k
{
988
5.36k
    return OGRGeoJSONReadCollection<OGRGeometryCollection>(
989
5.36k
        __func__, "GeometryCollection", poObj, bHasM, poSRS);
990
5.36k
}
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
59
{
1023
59
    return OGRGeoJSONReadCollection<OGRMultiCurve>(__func__, "MultiCurve",
1024
59
                                                   poObj, bHasM, poSRS);
1025
59
}
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
338k
{
1045
1046
    /* -------------------------------------------------------------------- */
1047
    /*      Read spatial reference definition.                              */
1048
    /* -------------------------------------------------------------------- */
1049
338k
    OGRSpatialReference *poSRS = nullptr;
1050
1051
338k
    json_object *poObjSrs = OGRGeoJSONFindMemberByName(poObj, "crs");
1052
338k
    if (nullptr != poObjSrs)
1053
336k
    {
1054
336k
        json_object *poObjSrsType =
1055
336k
            OGRGeoJSONFindMemberByName(poObjSrs, "type");
1056
336k
        if (poObjSrsType == nullptr)
1057
9.24k
            return nullptr;
1058
1059
327k
        const char *pszSrsType = json_object_get_string(poObjSrsType);
1060
1061
        // TODO: Add URL and URN types support.
1062
327k
        if (STARTS_WITH_CI(pszSrsType, "NAME"))
1063
205k
        {
1064
205k
            json_object *poObjSrsProps =
1065
205k
                OGRGeoJSONFindMemberByName(poObjSrs, "properties");
1066
205k
            if (poObjSrsProps == nullptr)
1067
3.75k
                return nullptr;
1068
1069
202k
            json_object *poNameURL =
1070
202k
                OGRGeoJSONFindMemberByName(poObjSrsProps, "name");
1071
202k
            if (poNameURL == nullptr)
1072
3.80k
                return nullptr;
1073
1074
198k
            const char *pszName = json_object_get_string(poNameURL);
1075
1076
198k
            poSRS = new OGRSpatialReference();
1077
198k
            poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1078
198k
            if (EQUAL(pszName, "urn:ogc:def:crs:OGC:1.3:CRS84"))
1079
110
            {
1080
110
                CPL_IGNORE_RET_VAL(poSRS->importFromEPSG(4326));
1081
110
            }
1082
198k
            else if (OGRERR_NONE !=
1083
198k
                     poSRS->SetFromUserInput(
1084
198k
                         pszName, OGRSpatialReference::
1085
198k
                                      SET_FROM_USER_INPUT_LIMITATIONS_get()))
1086
112k
            {
1087
112k
                delete poSRS;
1088
112k
                poSRS = nullptr;
1089
112k
            }
1090
198k
        }
1091
1092
121k
        else if (STARTS_WITH_CI(pszSrsType, "EPSG"))
1093
1.33k
        {
1094
1.33k
            json_object *poObjSrsProps =
1095
1.33k
                OGRGeoJSONFindMemberByName(poObjSrs, "properties");
1096
1.33k
            if (poObjSrsProps == nullptr)
1097
114
                return nullptr;
1098
1099
1.21k
            json_object *poObjCode =
1100
1.21k
                OGRGeoJSONFindMemberByName(poObjSrsProps, "code");
1101
1.21k
            if (poObjCode == nullptr)
1102
387
                return nullptr;
1103
1104
830
            int nEPSG = json_object_get_int(poObjCode);
1105
1106
830
            poSRS = new OGRSpatialReference();
1107
830
            poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1108
830
            if (OGRERR_NONE != poSRS->importFromEPSG(nEPSG))
1109
830
            {
1110
830
                delete poSRS;
1111
830
                poSRS = nullptr;
1112
830
            }
1113
830
        }
1114
1115
120k
        else if (STARTS_WITH_CI(pszSrsType, "URL") ||
1116
86.4k
                 STARTS_WITH_CI(pszSrsType, "LINK"))
1117
33.8k
        {
1118
33.8k
            json_object *poObjSrsProps =
1119
33.8k
                OGRGeoJSONFindMemberByName(poObjSrs, "properties");
1120
33.8k
            if (poObjSrsProps == nullptr)
1121
1.64k
                return nullptr;
1122
1123
32.1k
            json_object *poObjURL =
1124
32.1k
                OGRGeoJSONFindMemberByName(poObjSrsProps, "url");
1125
1126
32.1k
            if (nullptr == poObjURL)
1127
1.34k
            {
1128
1.34k
                poObjURL = OGRGeoJSONFindMemberByName(poObjSrsProps, "href");
1129
1.34k
            }
1130
32.1k
            if (poObjURL == nullptr)
1131
1.34k
                return nullptr;
1132
1133
30.8k
            const char *pszURL = json_object_get_string(poObjURL);
1134
1135
30.8k
            poSRS = new OGRSpatialReference();
1136
30.8k
            poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1137
30.8k
            if (OGRERR_NONE != poSRS->importFromUrl(pszURL))
1138
30.8k
            {
1139
30.8k
                delete poSRS;
1140
30.8k
                poSRS = nullptr;
1141
30.8k
            }
1142
30.8k
        }
1143
1144
86.2k
        else if (EQUAL(pszSrsType, "OGC"))
1145
82.4k
        {
1146
82.4k
            json_object *poObjSrsProps =
1147
82.4k
                OGRGeoJSONFindMemberByName(poObjSrs, "properties");
1148
82.4k
            if (poObjSrsProps == nullptr)
1149
2.33k
                return nullptr;
1150
1151
80.1k
            json_object *poObjURN =
1152
80.1k
                OGRGeoJSONFindMemberByName(poObjSrsProps, "urn");
1153
80.1k
            if (poObjURN == nullptr)
1154
2.18k
                return nullptr;
1155
1156
77.9k
            poSRS = new OGRSpatialReference();
1157
77.9k
            poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1158
77.9k
            if (OGRERR_NONE !=
1159
77.9k
                poSRS->importFromURN(json_object_get_string(poObjURN)))
1160
47.9k
            {
1161
47.9k
                delete poSRS;
1162
47.9k
                poSRS = nullptr;
1163
47.9k
            }
1164
77.9k
        }
1165
327k
    }
1166
1167
    // Strip AXIS, since geojson has (easting, northing) / (longitude, latitude)
1168
    // order.  According to http://www.geojson.org/geojson-spec.html#id2 :
1169
    // "Point coordinates are in x, y order (easting, northing for projected
1170
    // coordinates, longitude, latitude for geographic coordinates)".
1171
313k
    if (poSRS != nullptr)
1172
116k
    {
1173
116k
        OGR_SRSNode *poGEOGCS = poSRS->GetAttrNode("GEOGCS");
1174
116k
        if (poGEOGCS != nullptr)
1175
38.3k
            poGEOGCS->StripNodes("AXIS");
1176
116k
    }
1177
1178
313k
    return poSRS;
1179
338k
}
1180
1181
/************************************************************************/
1182
/*                     OGR_G_CreateGeometryFromJson                     */
1183
/************************************************************************/
1184
1185
/** Create a OGR geometry from a GeoJSON geometry object */
1186
OGRGeometryH OGR_G_CreateGeometryFromJson(const char *pszJson)
1187
1.19M
{
1188
1.19M
    if (nullptr == pszJson)
1189
0
    {
1190
        // Translation failed.
1191
0
        return nullptr;
1192
0
    }
1193
1194
1.19M
    json_object *poObj = nullptr;
1195
1.19M
    if (!OGRJSonParse(pszJson, &poObj))
1196
795k
        return nullptr;
1197
1198
398k
    OGRGeometry *poGeometry =
1199
398k
        OGRGeoJSONReadGeometry(poObj, /* bHasM = */ false,
1200
398k
                               /* OGRSpatialReference* = */ nullptr)
1201
398k
            .release();
1202
1203
    // Release JSON tree.
1204
398k
    json_object_put(poObj);
1205
1206
398k
    return OGRGeometry::ToHandle(poGeometry);
1207
1.19M
}
1208
1209
/*! @endcond */