Coverage Report

Created: 2025-12-03 08:24

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