LCOV - code coverage report
Current view: top level - ogr - ogrgeojsongeometry.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 425 452 94.0 %
Date: 2025-10-21 22:35:35 Functions: 31 31 100.0 %

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

Generated by: LCOV version 1.14