LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/geojson - ogresrijsonreader.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 414 507 81.7 %
Date: 2024-05-03 15:49:35 Functions: 22 22 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implementation of OGRESRIJSONReader class (OGR ESRIJSON Driver)
       5             :  *           to read ESRI Feature Service REST data
       6             :  * Author:   Even Rouault, even dot rouault at spatialys.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  * Copyright (c) 2007, Mateusz Loskot
      11             :  * Copyright (c) 2013, Kyle Shannon <kyle at pobox dot com>
      12             :  *
      13             :  * Permission is hereby granted, free of charge, to any person obtaining a
      14             :  * copy of this software and associated documentation files (the "Software"),
      15             :  * to deal in the Software without restriction, including without limitation
      16             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      17             :  * and/or sell copies of the Software, and to permit persons to whom the
      18             :  * Software is furnished to do so, subject to the following conditions:
      19             :  *
      20             :  * The above copyright notice and this permission notice shall be included
      21             :  * in all copies or substantial portions of the Software.
      22             :  *
      23             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      24             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      25             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      26             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      27             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      28             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      29             :  * DEALINGS IN THE SOFTWARE.
      30             :  ****************************************************************************/
      31             : 
      32             : #include "cpl_port.h"
      33             : #include "ogrgeojsonreader.h"
      34             : 
      35             : #include <limits.h>
      36             : #include <stddef.h>
      37             : 
      38             : #include "cpl_conv.h"
      39             : #include "cpl_error.h"
      40             : #include "cpl_time.h"
      41             : #include "json.h"
      42             : // #include "json_object.h"
      43             : // #include "json_tokener.h"
      44             : #include "ogr_api.h"
      45             : #include "ogr_core.h"
      46             : #include "ogr_feature.h"
      47             : #include "ogr_geometry.h"
      48             : #include "ogr_spatialref.h"
      49             : #include "ogr_geojson.h"
      50             : #include "ogrgeojsonreader.h"
      51             : #include "ogrgeojsonutils.h"
      52             : 
      53             : // #include "symbol_renames.h"
      54             : 
      55             : /************************************************************************/
      56             : /*                          OGRESRIJSONReader()                         */
      57             : /************************************************************************/
      58             : 
      59          19 : OGRESRIJSONReader::OGRESRIJSONReader() : poGJObject_(nullptr), poLayer_(nullptr)
      60             : {
      61          19 : }
      62             : 
      63             : /************************************************************************/
      64             : /*                         ~OGRESRIJSONReader()                         */
      65             : /************************************************************************/
      66             : 
      67          38 : OGRESRIJSONReader::~OGRESRIJSONReader()
      68             : {
      69          19 :     if (nullptr != poGJObject_)
      70             :     {
      71          19 :         json_object_put(poGJObject_);
      72             :     }
      73             : 
      74          19 :     poGJObject_ = nullptr;
      75          19 :     poLayer_ = nullptr;
      76          19 : }
      77             : 
      78             : /************************************************************************/
      79             : /*                           Parse()                                    */
      80             : /************************************************************************/
      81             : 
      82          19 : OGRErr OGRESRIJSONReader::Parse(const char *pszText)
      83             : {
      84          19 :     json_object *jsobj = nullptr;
      85          19 :     if (nullptr != pszText && !OGRJSonParse(pszText, &jsobj, true))
      86             :     {
      87           0 :         return OGRERR_CORRUPT_DATA;
      88             :     }
      89             : 
      90             :     // JSON tree is shared for while lifetime of the reader object
      91             :     // and will be released in the destructor.
      92          19 :     poGJObject_ = jsobj;
      93          19 :     return OGRERR_NONE;
      94             : }
      95             : 
      96             : /************************************************************************/
      97             : /*                           ReadLayers()                               */
      98             : /************************************************************************/
      99             : 
     100          19 : void OGRESRIJSONReader::ReadLayers(OGRGeoJSONDataSource *poDS,
     101             :                                    GeoJSONSourceType eSourceType)
     102             : {
     103          19 :     CPLAssert(nullptr == poLayer_);
     104             : 
     105          19 :     if (nullptr == poGJObject_)
     106             :     {
     107           0 :         CPLDebug("ESRIJSON",
     108             :                  "Missing parsed ESRIJSON data. Forgot to call Parse()?");
     109           0 :         return;
     110             :     }
     111             : 
     112          19 :     OGRSpatialReference *poSRS = OGRESRIJSONReadSpatialReference(poGJObject_);
     113             : 
     114          19 :     const char *pszName = "ESRIJSON";
     115          19 :     if (eSourceType == eGeoJSONSourceFile)
     116             :     {
     117          17 :         pszName = poDS->GetDescription();
     118          17 :         if (STARTS_WITH_CI(pszName, "ESRIJSON:"))
     119           1 :             pszName += strlen("ESRIJSON:");
     120          17 :         pszName = CPLGetBasename(pszName);
     121             :     }
     122             : 
     123          19 :     auto eGeomType = OGRESRIJSONGetGeometryType(poGJObject_);
     124          19 :     if (eGeomType == wkbNone && poSRS != nullptr)
     125             :     {
     126           0 :         eGeomType = wkbUnknown;
     127             :     }
     128             : 
     129          19 :     poLayer_ = new OGRGeoJSONLayer(pszName, poSRS, eGeomType, poDS, nullptr);
     130          19 :     if (poSRS != nullptr)
     131           8 :         poSRS->Release();
     132             : 
     133          19 :     if (!GenerateLayerDefn())
     134             :     {
     135           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     136             :                  "Layer schema generation failed.");
     137             : 
     138           0 :         delete poLayer_;
     139           0 :         return;
     140             :     }
     141             : 
     142          19 :     OGRGeoJSONLayer *poThisLayer = ReadFeatureCollection(poGJObject_);
     143          19 :     if (poThisLayer == nullptr)
     144             :     {
     145           0 :         delete poLayer_;
     146           0 :         return;
     147             :     }
     148             : 
     149          19 :     CPLErrorReset();
     150             : 
     151          19 :     poLayer_->DetectGeometryType();
     152          19 :     poDS->AddLayer(poLayer_);
     153             : }
     154             : 
     155             : /************************************************************************/
     156             : /*                        GenerateFeatureDefn()                         */
     157             : /************************************************************************/
     158             : 
     159          19 : bool OGRESRIJSONReader::GenerateLayerDefn()
     160             : {
     161          19 :     CPLAssert(nullptr != poGJObject_);
     162             : 
     163          19 :     bool bSuccess = true;
     164             : 
     165          19 :     OGRFeatureDefn *poDefn = poLayer_->GetLayerDefn();
     166          19 :     CPLAssert(nullptr != poDefn);
     167          19 :     CPLAssert(0 == poDefn->GetFieldCount());
     168          19 :     auto oTemporaryUnsealer(poDefn->GetTemporaryUnsealer());
     169             : 
     170             :     /* -------------------------------------------------------------------- */
     171             :     /*      Scan all features and generate layer definition.                */
     172             :     /* -------------------------------------------------------------------- */
     173          19 :     json_object *poFields = OGRGeoJSONFindMemberByName(poGJObject_, "fields");
     174          38 :     if (nullptr != poFields &&
     175          19 :         json_type_array == json_object_get_type(poFields))
     176             :     {
     177          19 :         const auto nFeatures = json_object_array_length(poFields);
     178          54 :         for (auto i = decltype(nFeatures){0}; i < nFeatures; ++i)
     179             :         {
     180          35 :             json_object *poField = json_object_array_get_idx(poFields, i);
     181          35 :             if (!ParseField(poField))
     182             :             {
     183           0 :                 CPLDebug("GeoJSON", "Create feature schema failure.");
     184           0 :                 bSuccess = false;
     185             :             }
     186             :         }
     187             :     }
     188             :     else
     189             :     {
     190           0 :         poFields = OGRGeoJSONFindMemberByName(poGJObject_, "fieldAliases");
     191           0 :         if (nullptr != poFields &&
     192           0 :             json_object_get_type(poFields) == json_type_object)
     193             :         {
     194             :             json_object_iter it;
     195           0 :             it.key = nullptr;
     196           0 :             it.val = nullptr;
     197           0 :             it.entry = nullptr;
     198           0 :             json_object_object_foreachC(poFields, it)
     199             :             {
     200           0 :                 OGRFieldDefn fldDefn(it.key, OFTString);
     201           0 :                 poDefn->AddFieldDefn(&fldDefn);
     202             :             }
     203             :         }
     204             :         else
     205             :         {
     206           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     207             :                      "Invalid FeatureCollection object. "
     208             :                      "Missing \'fields\' member.");
     209           0 :             bSuccess = false;
     210             :         }
     211             :     }
     212             : 
     213          38 :     return bSuccess;
     214             : }
     215             : 
     216             : /************************************************************************/
     217             : /*                             ParseField()                             */
     218             : /************************************************************************/
     219             : 
     220          35 : bool OGRESRIJSONReader::ParseField(json_object *poObj)
     221             : {
     222          35 :     OGRFeatureDefn *poDefn = poLayer_->GetLayerDefn();
     223          35 :     CPLAssert(nullptr != poDefn);
     224             : 
     225          35 :     bool bSuccess = false;
     226             : 
     227             :     /* -------------------------------------------------------------------- */
     228             :     /*      Read collection of properties.                                  */
     229             :     /* -------------------------------------------------------------------- */
     230          35 :     json_object *poObjName = OGRGeoJSONFindMemberByName(poObj, "name");
     231          35 :     json_object *poObjType = OGRGeoJSONFindMemberByName(poObj, "type");
     232          35 :     if (nullptr != poObjName && nullptr != poObjType)
     233             :     {
     234          35 :         OGRFieldType eFieldType = OFTString;
     235          35 :         OGRFieldSubType eFieldSubType = OFSTNone;
     236          35 :         const char *pszObjName = json_object_get_string(poObjName);
     237          35 :         const char *pszObjType = json_object_get_string(poObjType);
     238          35 :         if (EQUAL(pszObjType, "esriFieldTypeOID"))
     239             :         {
     240          11 :             eFieldType = OFTInteger;
     241          11 :             poLayer_->SetFIDColumn(pszObjName);
     242             :         }
     243          24 :         else if (EQUAL(pszObjType, "esriFieldTypeSingle"))
     244             :         {
     245           1 :             eFieldType = OFTReal;
     246           1 :             eFieldSubType = OFSTFloat32;
     247             :         }
     248          23 :         else if (EQUAL(pszObjType, "esriFieldTypeDouble"))
     249             :         {
     250           7 :             eFieldType = OFTReal;
     251             :         }
     252          16 :         else if (EQUAL(pszObjType, "esriFieldTypeSmallInteger"))
     253             :         {
     254           1 :             eFieldType = OFTInteger;
     255           1 :             eFieldSubType = OFSTInt16;
     256             :         }
     257          15 :         else if (EQUAL(pszObjType, "esriFieldTypeInteger"))
     258             :         {
     259           7 :             eFieldType = OFTInteger;
     260             :         }
     261           8 :         else if (EQUAL(pszObjType, "esriFieldTypeDate"))
     262             :         {
     263           1 :             eFieldType = OFTDateTime;
     264             :         }
     265             :         else
     266             :         {
     267           7 :             CPLDebug("ESRIJSON",
     268             :                      "Unhandled fields[\"%s\"].type = %s. "
     269             :                      "Processing it as a String",
     270             :                      pszObjName, pszObjType);
     271             :         }
     272          35 :         OGRFieldDefn fldDefn(pszObjName, eFieldType);
     273          35 :         fldDefn.SetSubType(eFieldSubType);
     274             : 
     275             :         json_object *const poObjLength =
     276          35 :             OGRGeoJSONFindMemberByName(poObj, "length");
     277          51 :         if (poObjLength != nullptr &&
     278          16 :             json_object_get_type(poObjLength) == json_type_int)
     279             :         {
     280          16 :             const int nWidth = json_object_get_int(poObjLength);
     281             :             // A dummy width of 2147483647 seems to indicate no known field with
     282             :             // which in the OGR world is better modelled as 0 field width.
     283             :             // (#6529)
     284          16 :             if (nWidth != INT_MAX)
     285          16 :                 fldDefn.SetWidth(nWidth);
     286             :         }
     287             : 
     288          35 :         poDefn->AddFieldDefn(&fldDefn);
     289             : 
     290          35 :         bSuccess = true;
     291             :     }
     292          35 :     return bSuccess;
     293             : }
     294             : 
     295             : /************************************************************************/
     296             : /*                           AddFeature                                 */
     297             : /************************************************************************/
     298             : 
     299          18 : bool OGRESRIJSONReader::AddFeature(OGRFeature *poFeature)
     300             : {
     301          18 :     if (nullptr == poFeature)
     302           0 :         return false;
     303             : 
     304          18 :     poLayer_->AddFeature(poFeature);
     305          18 :     delete poFeature;
     306             : 
     307          18 :     return true;
     308             : }
     309             : 
     310             : /************************************************************************/
     311             : /*                       OGRESRIJSONReadGeometry()                      */
     312             : /************************************************************************/
     313             : 
     314          17 : OGRGeometry *OGRESRIJSONReadGeometry(json_object *poObj)
     315             : {
     316          17 :     OGRGeometry *poGeometry = nullptr;
     317             : 
     318          17 :     if (OGRGeoJSONFindMemberByName(poObj, "x"))
     319           5 :         poGeometry = OGRESRIJSONReadPoint(poObj);
     320          12 :     else if (OGRGeoJSONFindMemberByName(poObj, "paths"))
     321           3 :         poGeometry = OGRESRIJSONReadLineString(poObj);
     322           9 :     else if (OGRGeoJSONFindMemberByName(poObj, "rings"))
     323           4 :         poGeometry = OGRESRIJSONReadPolygon(poObj);
     324           5 :     else if (OGRGeoJSONFindMemberByName(poObj, "points"))
     325           5 :         poGeometry = OGRESRIJSONReadMultiPoint(poObj);
     326             : 
     327          17 :     return poGeometry;
     328             : }
     329             : 
     330             : /************************************************************************/
     331             : /*                     OGR_G_CreateGeometryFromEsriJson()               */
     332             : /************************************************************************/
     333             : 
     334             : /** Create a OGR geometry from a ESRIJson geometry object */
     335           2 : OGRGeometryH OGR_G_CreateGeometryFromEsriJson(const char *pszJson)
     336             : {
     337           2 :     if (nullptr == pszJson)
     338             :     {
     339             :         // Translation failed.
     340           0 :         return nullptr;
     341             :     }
     342             : 
     343           2 :     json_object *poObj = nullptr;
     344           2 :     if (!OGRJSonParse(pszJson, &poObj))
     345           1 :         return nullptr;
     346             : 
     347           1 :     OGRGeometry *poGeometry = OGRESRIJSONReadGeometry(poObj);
     348             : 
     349             :     // Release JSON tree.
     350           1 :     json_object_put(poObj);
     351             : 
     352           1 :     return OGRGeometry::ToHandle(poGeometry);
     353             : }
     354             : 
     355             : /************************************************************************/
     356             : /*                           EsriDateToOGRDate()                        */
     357             : /************************************************************************/
     358             : 
     359           1 : static void EsriDateToOGRDate(int64_t nVal, OGRField *psField)
     360             : {
     361           1 :     const auto nSeconds = nVal / 1000;
     362           1 :     const auto nMillisec = static_cast<int>(nVal % 1000);
     363             : 
     364             :     struct tm brokendowntime;
     365           1 :     CPLUnixTimeToYMDHMS(nSeconds, &brokendowntime);
     366             : 
     367           1 :     psField->Date.Year = static_cast<GInt16>(brokendowntime.tm_year + 1900);
     368           1 :     psField->Date.Month = static_cast<GByte>(brokendowntime.tm_mon + 1);
     369           1 :     psField->Date.Day = static_cast<GByte>(brokendowntime.tm_mday);
     370           1 :     psField->Date.Hour = static_cast<GByte>(brokendowntime.tm_hour);
     371           1 :     psField->Date.Minute = static_cast<GByte>(brokendowntime.tm_min);
     372           1 :     psField->Date.Second =
     373           1 :         static_cast<float>(brokendowntime.tm_sec + nMillisec / 1000.0);
     374           1 :     psField->Date.TZFlag = 100;
     375           1 :     psField->Date.Reserved = 0;
     376           1 : }
     377             : 
     378             : /************************************************************************/
     379             : /*                           ReadFeature()                              */
     380             : /************************************************************************/
     381             : 
     382          18 : OGRFeature *OGRESRIJSONReader::ReadFeature(json_object *poObj)
     383             : {
     384          18 :     CPLAssert(nullptr != poObj);
     385          18 :     CPLAssert(nullptr != poLayer_);
     386             : 
     387          18 :     OGRFeature *poFeature = new OGRFeature(poLayer_->GetLayerDefn());
     388             : 
     389             :     /* -------------------------------------------------------------------- */
     390             :     /*      Translate ESRIJSON "attributes" object to feature attributes.   */
     391             :     /* -------------------------------------------------------------------- */
     392          18 :     CPLAssert(nullptr != poFeature);
     393             : 
     394          18 :     json_object *poObjProps = OGRGeoJSONFindMemberByName(poObj, "attributes");
     395          35 :     if (nullptr != poObjProps &&
     396          17 :         json_object_get_type(poObjProps) == json_type_object)
     397             :     {
     398          17 :         OGRFieldDefn *poFieldDefn = nullptr;
     399             :         json_object_iter it;
     400          17 :         it.key = nullptr;
     401          17 :         it.val = nullptr;
     402          17 :         it.entry = nullptr;
     403          52 :         json_object_object_foreachC(poObjProps, it)
     404             :         {
     405          35 :             const int nField = poFeature->GetFieldIndex(it.key);
     406          35 :             if (nField >= 0)
     407             :             {
     408          35 :                 poFieldDefn = poFeature->GetFieldDefnRef(nField);
     409          35 :                 if (poFieldDefn && it.val != nullptr)
     410             :                 {
     411          35 :                     if (EQUAL(it.key, poLayer_->GetFIDColumn()))
     412          11 :                         poFeature->SetFID(json_object_get_int(it.val));
     413          35 :                     switch (poLayer_->GetLayerDefn()
     414          35 :                                 ->GetFieldDefn(nField)
     415          35 :                                 ->GetType())
     416             :                     {
     417          19 :                         case OFTInteger:
     418             :                         {
     419          19 :                             poFeature->SetField(nField,
     420          19 :                                                 json_object_get_int(it.val));
     421          19 :                             break;
     422             :                         }
     423           8 :                         case OFTReal:
     424             :                         {
     425           8 :                             poFeature->SetField(nField,
     426           8 :                                                 json_object_get_double(it.val));
     427           8 :                             break;
     428             :                         }
     429           1 :                         case OFTDateTime:
     430             :                         {
     431           1 :                             const auto nVal = json_object_get_int64(it.val);
     432           1 :                             EsriDateToOGRDate(
     433             :                                 nVal, poFeature->GetRawFieldRef(nField));
     434           1 :                             break;
     435             :                         }
     436           7 :                         default:
     437             :                         {
     438           7 :                             poFeature->SetField(nField,
     439             :                                                 json_object_get_string(it.val));
     440           7 :                             break;
     441             :                         }
     442             :                     }
     443             :                 }
     444             :             }
     445             :         }
     446             :     }
     447             : 
     448          18 :     const OGRwkbGeometryType eType = poLayer_->GetGeomType();
     449          18 :     if (eType == wkbNone)
     450           0 :         return poFeature;
     451             : 
     452             :     /* -------------------------------------------------------------------- */
     453             :     /*      Translate geometry sub-object of ESRIJSON Feature.               */
     454             :     /* -------------------------------------------------------------------- */
     455          18 :     json_object *poObjGeom = nullptr;
     456          18 :     json_object *poTmp = poObj;
     457             :     json_object_iter it;
     458          18 :     it.key = nullptr;
     459          18 :     it.val = nullptr;
     460          18 :     it.entry = nullptr;
     461          49 :     json_object_object_foreachC(poTmp, it)
     462             :     {
     463          33 :         if (EQUAL(it.key, "geometry"))
     464             :         {
     465          18 :             if (it.val != nullptr)
     466          16 :                 poObjGeom = it.val;
     467             :             // We're done.  They had 'geometry':null.
     468             :             else
     469           2 :                 return poFeature;
     470             :         }
     471             :     }
     472             : 
     473          16 :     if (nullptr != poObjGeom)
     474             :     {
     475          16 :         OGRGeometry *poGeometry = OGRESRIJSONReadGeometry(poObjGeom);
     476          16 :         if (nullptr != poGeometry)
     477             :         {
     478          16 :             poFeature->SetGeometryDirectly(poGeometry);
     479             :         }
     480             :     }
     481             : 
     482          16 :     return poFeature;
     483             : }
     484             : 
     485             : /************************************************************************/
     486             : /*                           ReadFeatureCollection()                    */
     487             : /************************************************************************/
     488             : 
     489          19 : OGRGeoJSONLayer *OGRESRIJSONReader::ReadFeatureCollection(json_object *poObj)
     490             : {
     491          19 :     CPLAssert(nullptr != poLayer_);
     492             : 
     493          19 :     json_object *poObjFeatures = OGRGeoJSONFindMemberByName(poObj, "features");
     494          19 :     if (nullptr == poObjFeatures)
     495             :     {
     496           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     497             :                  "Invalid FeatureCollection object. "
     498             :                  "Missing \'features\' member.");
     499           0 :         return nullptr;
     500             :     }
     501             : 
     502          19 :     if (json_type_array == json_object_get_type(poObjFeatures))
     503             :     {
     504          19 :         const auto nFeatures = json_object_array_length(poObjFeatures);
     505          37 :         for (auto i = decltype(nFeatures){0}; i < nFeatures; ++i)
     506             :         {
     507             :             json_object *poObjFeature =
     508          18 :                 json_object_array_get_idx(poObjFeatures, i);
     509          36 :             if (poObjFeature != nullptr &&
     510          18 :                 json_object_get_type(poObjFeature) == json_type_object)
     511             :             {
     512             :                 OGRFeature *poFeature =
     513          18 :                     OGRESRIJSONReader::ReadFeature(poObjFeature);
     514          18 :                 AddFeature(poFeature);
     515             :             }
     516             :         }
     517             :     }
     518             : 
     519             :     // We're returning class member to follow the same pattern of
     520             :     // Read* functions call convention.
     521          19 :     CPLAssert(nullptr != poLayer_);
     522          19 :     return poLayer_;
     523             : }
     524             : 
     525             : /************************************************************************/
     526             : /*                        OGRESRIJSONGetType()                          */
     527             : /************************************************************************/
     528             : 
     529          19 : OGRwkbGeometryType OGRESRIJSONGetGeometryType(json_object *poObj)
     530             : {
     531          19 :     if (nullptr == poObj)
     532           0 :         return wkbUnknown;
     533             : 
     534          19 :     json_object *poObjType = OGRGeoJSONFindMemberByName(poObj, "geometryType");
     535          19 :     if (nullptr == poObjType)
     536             :     {
     537           0 :         return wkbNone;
     538             :     }
     539             : 
     540          19 :     const char *name = json_object_get_string(poObjType);
     541          19 :     if (EQUAL(name, "esriGeometryPoint"))
     542           7 :         return wkbPoint;
     543          12 :     else if (EQUAL(name, "esriGeometryPolyline"))
     544           3 :         return wkbLineString;
     545           9 :     else if (EQUAL(name, "esriGeometryPolygon"))
     546           4 :         return wkbPolygon;
     547           5 :     else if (EQUAL(name, "esriGeometryMultiPoint"))
     548           5 :         return wkbMultiPoint;
     549             :     else
     550           0 :         return wkbUnknown;
     551             : }
     552             : 
     553             : /************************************************************************/
     554             : /*                     OGRESRIJSONGetCoordinateToDouble()               */
     555             : /************************************************************************/
     556             : 
     557         119 : static double OGRESRIJSONGetCoordinateToDouble(json_object *poObjCoord,
     558             :                                                const char *pszCoordName,
     559             :                                                bool &bValid)
     560             : {
     561         119 :     const int iType = json_object_get_type(poObjCoord);
     562         119 :     if (json_type_double != iType && json_type_int != iType)
     563             :     {
     564           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     565             :                  "Invalid '%s' coordinate. "
     566             :                  "Type is not double or integer for \'%s\'.",
     567             :                  pszCoordName, json_object_to_json_string(poObjCoord));
     568           0 :         bValid = false;
     569           0 :         return 0.0;
     570             :     }
     571             : 
     572         119 :     return json_object_get_double(poObjCoord);
     573             : }
     574             : 
     575             : /************************************************************************/
     576             : /*                       OGRESRIJSONGetCoordinate()                     */
     577             : /************************************************************************/
     578             : 
     579          10 : static double OGRESRIJSONGetCoordinate(json_object *poObj,
     580             :                                        const char *pszCoordName, bool &bValid)
     581             : {
     582          10 :     json_object *poObjCoord = OGRGeoJSONFindMemberByName(poObj, pszCoordName);
     583          10 :     if (nullptr == poObjCoord)
     584             :     {
     585           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     586             :                  "Invalid Point object. "
     587             :                  "Missing '%s' member.",
     588             :                  pszCoordName);
     589           0 :         bValid = false;
     590           0 :         return 0.0;
     591             :     }
     592             : 
     593          10 :     return OGRESRIJSONGetCoordinateToDouble(poObjCoord, pszCoordName, bValid);
     594             : }
     595             : 
     596             : /************************************************************************/
     597             : /*                          OGRESRIJSONReadPoint()                      */
     598             : /************************************************************************/
     599             : 
     600           5 : OGRPoint *OGRESRIJSONReadPoint(json_object *poObj)
     601             : {
     602           5 :     CPLAssert(nullptr != poObj);
     603             : 
     604           5 :     bool bValid = true;
     605           5 :     const double dfX = OGRESRIJSONGetCoordinate(poObj, "x", bValid);
     606           5 :     const double dfY = OGRESRIJSONGetCoordinate(poObj, "y", bValid);
     607           5 :     if (!bValid)
     608           0 :         return nullptr;
     609             : 
     610           5 :     json_object *poObjZ = OGRGeoJSONFindMemberByName(poObj, "z");
     611           5 :     if (nullptr == poObjZ)
     612           2 :         return new OGRPoint(dfX, dfY);
     613             : 
     614           3 :     const double dfZ = OGRESRIJSONGetCoordinateToDouble(poObjZ, "z", bValid);
     615           3 :     if (!bValid)
     616           0 :         return nullptr;
     617           3 :     return new OGRPoint(dfX, dfY, dfZ);
     618             : }
     619             : 
     620             : /************************************************************************/
     621             : /*                     OGRESRIJSONReaderParseZM()                      */
     622             : /************************************************************************/
     623             : 
     624          12 : static void OGRESRIJSONReaderParseZM(json_object *poObj, bool *bHasZ,
     625             :                                      bool *bHasM)
     626             : {
     627          12 :     CPLAssert(nullptr != poObj);
     628             :     // The ESRI geojson spec states that geometries other than point can
     629             :     // have the attributes hasZ and hasM.  A geometry that has a z value
     630             :     // implies the 3rd number in the tuple is z.  if hasM is true, but hasZ
     631             :     // is not, it is the M value.
     632          12 :     bool bZ = false;
     633          12 :     json_object *poObjHasZ = OGRGeoJSONFindMemberByName(poObj, "hasZ");
     634          12 :     if (poObjHasZ != nullptr)
     635             :     {
     636           2 :         if (json_object_get_type(poObjHasZ) == json_type_boolean)
     637             :         {
     638           2 :             bZ = CPL_TO_BOOL(json_object_get_boolean(poObjHasZ));
     639             :         }
     640             :     }
     641             : 
     642          12 :     bool bM = false;
     643          12 :     json_object *poObjHasM = OGRGeoJSONFindMemberByName(poObj, "hasM");
     644          12 :     if (poObjHasM != nullptr)
     645             :     {
     646           2 :         if (json_object_get_type(poObjHasM) == json_type_boolean)
     647             :         {
     648           2 :             bM = CPL_TO_BOOL(json_object_get_boolean(poObjHasM));
     649             :         }
     650             :     }
     651          12 :     if (bHasZ != nullptr)
     652          12 :         *bHasZ = bZ;
     653          12 :     if (bHasM != nullptr)
     654          12 :         *bHasM = bM;
     655          12 : }
     656             : 
     657             : /************************************************************************/
     658             : /*                     OGRESRIJSONReaderParseXYZMArray()                  */
     659             : /************************************************************************/
     660             : 
     661          43 : static bool OGRESRIJSONReaderParseXYZMArray(json_object *poObjCoords,
     662             :                                             bool /*bHasZ*/, bool bHasM,
     663             :                                             double *pdfX, double *pdfY,
     664             :                                             double *pdfZ, double *pdfM,
     665             :                                             int *pnNumCoords)
     666             : {
     667          43 :     if (poObjCoords == nullptr)
     668             :     {
     669           0 :         CPLDebug("ESRIJSON",
     670             :                  "OGRESRIJSONReaderParseXYZMArray: got null object.");
     671           0 :         return false;
     672             :     }
     673             : 
     674          43 :     if (json_type_array != json_object_get_type(poObjCoords))
     675             :     {
     676           0 :         CPLDebug("ESRIJSON",
     677             :                  "OGRESRIJSONReaderParseXYZMArray: got non-array object.");
     678           0 :         return false;
     679             :     }
     680             : 
     681          43 :     const auto coordDimension = json_object_array_length(poObjCoords);
     682             : 
     683             :     // Allow 4 coordinates if M is present, but it is eventually ignored.
     684          43 :     if (coordDimension < 2 || coordDimension > 4)
     685             :     {
     686           0 :         CPLDebug("ESRIJSON",
     687             :                  "OGRESRIJSONReaderParseXYZMArray: got an unexpected "
     688             :                  "array object.");
     689           0 :         return false;
     690             :     }
     691             : 
     692             :     // Read X coordinate.
     693          43 :     json_object *poObjCoord = json_object_array_get_idx(poObjCoords, 0);
     694          43 :     if (poObjCoord == nullptr)
     695             :     {
     696           0 :         CPLDebug("ESRIJSON",
     697             :                  "OGRESRIJSONReaderParseXYZMArray: got null object.");
     698           0 :         return false;
     699             :     }
     700             : 
     701          43 :     bool bValid = true;
     702             :     const double dfX =
     703          43 :         OGRESRIJSONGetCoordinateToDouble(poObjCoord, "x", bValid);
     704             : 
     705             :     // Read Y coordinate.
     706          43 :     poObjCoord = json_object_array_get_idx(poObjCoords, 1);
     707          43 :     if (poObjCoord == nullptr)
     708             :     {
     709           0 :         CPLDebug("ESRIJSON",
     710             :                  "OGRESRIJSONReaderParseXYZMArray: got null object.");
     711           0 :         return false;
     712             :     }
     713             : 
     714             :     const double dfY =
     715          43 :         OGRESRIJSONGetCoordinateToDouble(poObjCoord, "y", bValid);
     716          43 :     if (!bValid)
     717           0 :         return false;
     718             : 
     719             :     // Read Z or M or Z and M coordinates.
     720          43 :     if (coordDimension > 2)
     721             :     {
     722          18 :         poObjCoord = json_object_array_get_idx(poObjCoords, 2);
     723          18 :         if (poObjCoord == nullptr)
     724             :         {
     725           0 :             CPLDebug("ESRIJSON",
     726             :                      "OGRESRIJSONReaderParseXYZMArray: got null object.");
     727           0 :             return false;
     728             :         }
     729             : 
     730          34 :         const double dfZorM = OGRESRIJSONGetCoordinateToDouble(
     731          16 :             poObjCoord, (coordDimension > 3 || !bHasM) ? "z" : "m", bValid);
     732          18 :         if (!bValid)
     733           0 :             return false;
     734          18 :         if (pdfZ != nullptr)
     735             :         {
     736          18 :             if (coordDimension > 3 || !bHasM)
     737          16 :                 *pdfZ = dfZorM;
     738             :             else
     739           2 :                 *pdfZ = 0.0;
     740             :         }
     741          18 :         if (pdfM != nullptr && coordDimension == 3)
     742             :         {
     743          16 :             if (bHasM)
     744           2 :                 *pdfM = dfZorM;
     745             :             else
     746          14 :                 *pdfM = 0.0;
     747             :         }
     748          18 :         if (coordDimension == 4)
     749             :         {
     750           2 :             poObjCoord = json_object_array_get_idx(poObjCoords, 3);
     751           2 :             if (poObjCoord == nullptr)
     752             :             {
     753           0 :                 CPLDebug("ESRIJSON",
     754             :                          "OGRESRIJSONReaderParseXYZMArray: got null object.");
     755           0 :                 return false;
     756             :             }
     757             : 
     758             :             const double dfM =
     759           2 :                 OGRESRIJSONGetCoordinateToDouble(poObjCoord, "m", bValid);
     760           2 :             if (!bValid)
     761           0 :                 return false;
     762           2 :             if (pdfM != nullptr)
     763           2 :                 *pdfM = dfM;
     764             :         }
     765             :     }
     766             :     else
     767             :     {
     768          25 :         if (pdfZ != nullptr)
     769          25 :             *pdfZ = 0.0;
     770          25 :         if (pdfM != nullptr)
     771          25 :             *pdfM = 0.0;
     772             :     }
     773             : 
     774          43 :     if (pnNumCoords != nullptr)
     775          43 :         *pnNumCoords = static_cast<int>(coordDimension);
     776          43 :     if (pdfX != nullptr)
     777          43 :         *pdfX = dfX;
     778          43 :     if (pdfY != nullptr)
     779          43 :         *pdfY = dfY;
     780             : 
     781          43 :     return true;
     782             : }
     783             : 
     784             : /************************************************************************/
     785             : /*                        OGRESRIJSONReadLineString()                   */
     786             : /************************************************************************/
     787             : 
     788           3 : OGRGeometry *OGRESRIJSONReadLineString(json_object *poObj)
     789             : {
     790           3 :     CPLAssert(nullptr != poObj);
     791             : 
     792           3 :     bool bHasZ = false;
     793           3 :     bool bHasM = false;
     794             : 
     795           3 :     OGRESRIJSONReaderParseZM(poObj, &bHasZ, &bHasM);
     796             : 
     797           3 :     json_object *poObjPaths = OGRGeoJSONFindMemberByName(poObj, "paths");
     798           3 :     if (nullptr == poObjPaths)
     799             :     {
     800           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     801             :                  "Invalid LineString object. "
     802             :                  "Missing \'paths\' member.");
     803           0 :         return nullptr;
     804             :     }
     805             : 
     806           3 :     if (json_type_array != json_object_get_type(poObjPaths))
     807             :     {
     808           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     809             :                  "Invalid LineString object. "
     810             :                  "Invalid \'paths\' member.");
     811           0 :         return nullptr;
     812             :     }
     813             : 
     814           3 :     OGRMultiLineString *poMLS = nullptr;
     815           3 :     OGRGeometry *poRet = nullptr;
     816           3 :     const auto nPaths = json_object_array_length(poObjPaths);
     817           7 :     for (auto iPath = decltype(nPaths){0}; iPath < nPaths; iPath++)
     818             :     {
     819           4 :         json_object *poObjPath = json_object_array_get_idx(poObjPaths, iPath);
     820           8 :         if (poObjPath == nullptr ||
     821           4 :             json_type_array != json_object_get_type(poObjPath))
     822             :         {
     823           0 :             delete poRet;
     824           0 :             CPLDebug("ESRIJSON", "LineString: got non-array object.");
     825           0 :             return nullptr;
     826             :         }
     827             : 
     828           4 :         OGRLineString *poLine = new OGRLineString();
     829           4 :         if (nPaths > 1)
     830             :         {
     831           2 :             if (iPath == 0)
     832             :             {
     833           1 :                 poMLS = new OGRMultiLineString();
     834           1 :                 poRet = poMLS;
     835             :             }
     836           2 :             poMLS->addGeometryDirectly(poLine);
     837             :         }
     838             :         else
     839             :         {
     840           2 :             poRet = poLine;
     841             :         }
     842           4 :         const auto nPoints = json_object_array_length(poObjPath);
     843          12 :         for (auto i = decltype(nPoints){0}; i < nPoints; i++)
     844             :         {
     845           8 :             int nNumCoords = 2;
     846           8 :             json_object *poObjCoords = json_object_array_get_idx(poObjPath, i);
     847           8 :             double dfX = 0.0;
     848           8 :             double dfY = 0.0;
     849           8 :             double dfZ = 0.0;
     850           8 :             double dfM = 0.0;
     851           8 :             if (!OGRESRIJSONReaderParseXYZMArray(poObjCoords, bHasZ, bHasM,
     852             :                                                  &dfX, &dfY, &dfZ, &dfM,
     853             :                                                  &nNumCoords))
     854             :             {
     855           0 :                 delete poRet;
     856           0 :                 return nullptr;
     857             :             }
     858             : 
     859           8 :             if (nNumCoords == 3 && !bHasM)
     860             :             {
     861           2 :                 poLine->addPoint(dfX, dfY, dfZ);
     862             :             }
     863           6 :             else if (nNumCoords == 3)
     864             :             {
     865           0 :                 poLine->addPointM(dfX, dfY, dfM);
     866             :             }
     867           6 :             else if (nNumCoords == 4)
     868             :             {
     869           0 :                 poLine->addPoint(dfX, dfY, dfZ, dfM);
     870             :             }
     871             :             else
     872             :             {
     873           6 :                 poLine->addPoint(dfX, dfY);
     874             :             }
     875             :         }
     876             :     }
     877             : 
     878           3 :     if (poRet == nullptr)
     879           0 :         poRet = new OGRLineString();
     880             : 
     881           3 :     return poRet;
     882             : }
     883             : 
     884             : /************************************************************************/
     885             : /*                          OGRESRIJSONReadPolygon()                    */
     886             : /************************************************************************/
     887             : 
     888           4 : OGRGeometry *OGRESRIJSONReadPolygon(json_object *poObj)
     889             : {
     890           4 :     CPLAssert(nullptr != poObj);
     891             : 
     892           4 :     bool bHasZ = false;
     893           4 :     bool bHasM = false;
     894             : 
     895           4 :     OGRESRIJSONReaderParseZM(poObj, &bHasZ, &bHasM);
     896             : 
     897           4 :     json_object *poObjRings = OGRGeoJSONFindMemberByName(poObj, "rings");
     898           4 :     if (nullptr == poObjRings)
     899             :     {
     900           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     901             :                  "Invalid Polygon object. "
     902             :                  "Missing \'rings\' member.");
     903           0 :         return nullptr;
     904             :     }
     905             : 
     906           4 :     if (json_type_array != json_object_get_type(poObjRings))
     907             :     {
     908           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     909             :                  "Invalid Polygon object. "
     910             :                  "Invalid \'rings\' member.");
     911           0 :         return nullptr;
     912             :     }
     913             : 
     914           4 :     const auto nRings = json_object_array_length(poObjRings);
     915           4 :     OGRGeometry **papoGeoms = new OGRGeometry *[nRings];
     916           9 :     for (auto iRing = decltype(nRings){0}; iRing < nRings; iRing++)
     917             :     {
     918           5 :         json_object *poObjRing = json_object_array_get_idx(poObjRings, iRing);
     919          10 :         if (poObjRing == nullptr ||
     920           5 :             json_type_array != json_object_get_type(poObjRing))
     921             :         {
     922           0 :             for (auto j = decltype(iRing){0}; j < iRing; j++)
     923           0 :                 delete papoGeoms[j];
     924           0 :             delete[] papoGeoms;
     925           0 :             CPLDebug("ESRIJSON", "Polygon: got non-array object.");
     926           0 :             return nullptr;
     927             :         }
     928             : 
     929           5 :         OGRPolygon *poPoly = new OGRPolygon();
     930           5 :         auto poLine = std::make_unique<OGRLinearRing>();
     931           5 :         papoGeoms[iRing] = poPoly;
     932             : 
     933           5 :         const auto nPoints = json_object_array_length(poObjRing);
     934          30 :         for (auto i = decltype(nPoints){0}; i < nPoints; i++)
     935             :         {
     936          25 :             int nNumCoords = 2;
     937          25 :             json_object *poObjCoords = json_object_array_get_idx(poObjRing, i);
     938          25 :             double dfX = 0.0;
     939          25 :             double dfY = 0.0;
     940          25 :             double dfZ = 0.0;
     941          25 :             double dfM = 0.0;
     942          25 :             if (!OGRESRIJSONReaderParseXYZMArray(poObjCoords, bHasZ, bHasM,
     943             :                                                  &dfX, &dfY, &dfZ, &dfM,
     944             :                                                  &nNumCoords))
     945             :             {
     946           0 :                 for (auto j = decltype(iRing){0}; j <= iRing; j++)
     947           0 :                     delete papoGeoms[j];
     948           0 :                 delete[] papoGeoms;
     949           0 :                 return nullptr;
     950             :             }
     951             : 
     952          25 :             if (nNumCoords == 3 && !bHasM)
     953             :             {
     954          10 :                 poLine->addPoint(dfX, dfY, dfZ);
     955             :             }
     956          15 :             else if (nNumCoords == 3)
     957             :             {
     958           0 :                 poLine->addPointM(dfX, dfY, dfM);
     959             :             }
     960          15 :             else if (nNumCoords == 4)
     961             :             {
     962           0 :                 poLine->addPoint(dfX, dfY, dfZ, dfM);
     963             :             }
     964             :             else
     965             :             {
     966          15 :                 poLine->addPoint(dfX, dfY);
     967             :             }
     968             :         }
     969           5 :         poPoly->addRingDirectly(poLine.release());
     970             :     }
     971             : 
     972           4 :     OGRGeometry *poRet = OGRGeometryFactory::organizePolygons(
     973             :         papoGeoms, static_cast<int>(nRings), nullptr, nullptr);
     974           4 :     delete[] papoGeoms;
     975             : 
     976           4 :     return poRet;
     977             : }
     978             : 
     979             : /************************************************************************/
     980             : /*                        OGRESRIJSONReadMultiPoint()                   */
     981             : /************************************************************************/
     982             : 
     983           5 : OGRMultiPoint *OGRESRIJSONReadMultiPoint(json_object *poObj)
     984             : {
     985           5 :     CPLAssert(nullptr != poObj);
     986             : 
     987           5 :     bool bHasZ = false;
     988           5 :     bool bHasM = false;
     989             : 
     990           5 :     OGRESRIJSONReaderParseZM(poObj, &bHasZ, &bHasM);
     991             : 
     992           5 :     json_object *poObjPoints = OGRGeoJSONFindMemberByName(poObj, "points");
     993           5 :     if (nullptr == poObjPoints)
     994             :     {
     995           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     996             :                  "Invalid MultiPoint object. "
     997             :                  "Missing \'points\' member.");
     998           0 :         return nullptr;
     999             :     }
    1000             : 
    1001           5 :     if (json_type_array != json_object_get_type(poObjPoints))
    1002             :     {
    1003           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1004             :                  "Invalid MultiPoint object. "
    1005             :                  "Invalid \'points\' member.");
    1006           0 :         return nullptr;
    1007             :     }
    1008             : 
    1009           5 :     OGRMultiPoint *poMulti = new OGRMultiPoint();
    1010             : 
    1011           5 :     const auto nPoints = json_object_array_length(poObjPoints);
    1012          15 :     for (auto i = decltype(nPoints){0}; i < nPoints; i++)
    1013             :     {
    1014          10 :         int nNumCoords = 2;
    1015          10 :         json_object *poObjCoords = json_object_array_get_idx(poObjPoints, i);
    1016          10 :         double dfX = 0.0;
    1017          10 :         double dfY = 0.0;
    1018          10 :         double dfZ = 0.0;
    1019          10 :         double dfM = 0.0;
    1020          10 :         if (!OGRESRIJSONReaderParseXYZMArray(poObjCoords, bHasZ, bHasM, &dfX,
    1021             :                                              &dfY, &dfZ, &dfM, &nNumCoords))
    1022             :         {
    1023           0 :             delete poMulti;
    1024           0 :             return nullptr;
    1025             :         }
    1026             : 
    1027          10 :         if (nNumCoords == 3 && !bHasM)
    1028             :         {
    1029           2 :             poMulti->addGeometryDirectly(new OGRPoint(dfX, dfY, dfZ));
    1030             :         }
    1031           8 :         else if (nNumCoords == 3)
    1032             :         {
    1033           2 :             OGRPoint *poPoint = new OGRPoint(dfX, dfY);
    1034           2 :             poPoint->setM(dfM);
    1035           2 :             poMulti->addGeometryDirectly(poPoint);
    1036             :         }
    1037           6 :         else if (nNumCoords == 4)
    1038             :         {
    1039           2 :             poMulti->addGeometryDirectly(new OGRPoint(dfX, dfY, dfZ, dfM));
    1040             :         }
    1041             :         else
    1042             :         {
    1043           4 :             poMulti->addGeometryDirectly(new OGRPoint(dfX, dfY));
    1044             :         }
    1045             :     }
    1046             : 
    1047           5 :     return poMulti;
    1048             : }
    1049             : 
    1050             : /************************************************************************/
    1051             : /*                    OGRESRIJSONReadSpatialReference()                 */
    1052             : /************************************************************************/
    1053             : 
    1054          19 : OGRSpatialReference *OGRESRIJSONReadSpatialReference(json_object *poObj)
    1055             : {
    1056             :     /* -------------------------------------------------------------------- */
    1057             :     /*      Read spatial reference definition.                              */
    1058             :     /* -------------------------------------------------------------------- */
    1059          19 :     OGRSpatialReference *poSRS = nullptr;
    1060             : 
    1061             :     json_object *poObjSrs =
    1062          19 :         OGRGeoJSONFindMemberByName(poObj, "spatialReference");
    1063          19 :     if (nullptr != poObjSrs)
    1064             :     {
    1065             :         json_object *poObjWkid =
    1066           8 :             OGRGeoJSONFindMemberByName(poObjSrs, "latestWkid");
    1067           8 :         if (poObjWkid == nullptr)
    1068           8 :             poObjWkid = OGRGeoJSONFindMemberByName(poObjSrs, "wkid");
    1069           8 :         if (poObjWkid == nullptr)
    1070             :         {
    1071           1 :             json_object *poObjWkt = OGRGeoJSONFindMemberByName(poObjSrs, "wkt");
    1072           1 :             if (poObjWkt == nullptr)
    1073           0 :                 return nullptr;
    1074             : 
    1075           1 :             const char *pszWKT = json_object_get_string(poObjWkt);
    1076           1 :             poSRS = new OGRSpatialReference();
    1077           1 :             poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    1078           1 :             if (OGRERR_NONE != poSRS->importFromWkt(pszWKT))
    1079             :             {
    1080           0 :                 delete poSRS;
    1081           0 :                 poSRS = nullptr;
    1082             :             }
    1083             :             else
    1084             :             {
    1085           1 :                 auto poSRSMatch = poSRS->FindBestMatch(70);
    1086           1 :                 if (poSRSMatch)
    1087             :                 {
    1088           1 :                     poSRS->Release();
    1089           1 :                     poSRS = poSRSMatch;
    1090           1 :                     poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    1091             :                 }
    1092             :             }
    1093             : 
    1094           1 :             return poSRS;
    1095             :         }
    1096             : 
    1097           7 :         const int nEPSG = json_object_get_int(poObjWkid);
    1098             : 
    1099           7 :         poSRS = new OGRSpatialReference();
    1100           7 :         poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    1101           7 :         if (OGRERR_NONE != poSRS->importFromEPSG(nEPSG))
    1102             :         {
    1103           0 :             delete poSRS;
    1104           0 :             poSRS = nullptr;
    1105             :         }
    1106             :     }
    1107             : 
    1108          18 :     return poSRS;
    1109             : }

Generated by: LCOV version 1.14