LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/geojson - ogrgeojsonwritelayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 187 221 84.6 %
Date: 2024-05-03 15:49:35 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implementation of OGRGeoJSONWriteLayer class (OGR GeoJSON Driver).
       5             :  * Author:   Mateusz Loskot, mateusz@loskot.net
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2011, Even Rouault <even dot rouault at spatialys.com>
       9             :  * Copyright (c) 2007, Mateusz Loskot
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "ogr_geojson.h"
      31             : #include "ogrgeojsonwriter.h"
      32             : 
      33             : #include "cpl_vsi_virtual.h"
      34             : 
      35             : #include <algorithm>
      36             : 
      37             : /************************************************************************/
      38             : /*                         OGRGeoJSONWriteLayer()                       */
      39             : /************************************************************************/
      40             : 
      41         146 : OGRGeoJSONWriteLayer::OGRGeoJSONWriteLayer(const char *pszName,
      42             :                                            OGRwkbGeometryType eGType,
      43             :                                            CSLConstList papszOptions,
      44             :                                            bool bWriteFC_BBOXIn,
      45             :                                            OGRCoordinateTransformation *poCT,
      46         146 :                                            OGRGeoJSONDataSource *poDS)
      47         146 :     : poDS_(poDS), poFeatureDefn_(new OGRFeatureDefn(pszName)), nOutCounter_(0),
      48         146 :       bWriteBBOX(CPLTestBool(
      49             :           CSLFetchNameValueDef(papszOptions, "WRITE_BBOX", "FALSE"))),
      50             :       bBBOX3D(false), bWriteFC_BBOX(bWriteFC_BBOXIn),
      51         146 :       nSignificantFigures_(atoi(
      52             :           CSLFetchNameValueDef(papszOptions, "SIGNIFICANT_FIGURES", "-1"))),
      53             :       bRFC7946_(
      54         146 :           CPLTestBool(CSLFetchNameValueDef(papszOptions, "RFC7946", "FALSE"))),
      55         146 :       bWrapDateLine_(CPLTestBool(
      56             :           CSLFetchNameValueDef(papszOptions, "WRAPDATELINE", "YES"))),
      57             :       osForeignMembers_(
      58             :           CSLFetchNameValueDef(papszOptions, "FOREIGN_MEMBERS_FEATURE", "")),
      59         876 :       poCT_(poCT)
      60             : {
      61         146 :     if (!osForeignMembers_.empty())
      62             :     {
      63             :         // Already checked in OGRGeoJSONDataSource::ICreateLayer()
      64           1 :         CPLAssert(osForeignMembers_.front() == '{');
      65           1 :         CPLAssert(osForeignMembers_.back() == '}');
      66             :         osForeignMembers_ =
      67           1 :             osForeignMembers_.substr(1, osForeignMembers_.size() - 2);
      68             :     }
      69         146 :     poFeatureDefn_->Reference();
      70         146 :     poFeatureDefn_->SetGeomType(eGType);
      71         146 :     SetDescription(poFeatureDefn_->GetName());
      72             :     const char *pszCoordPrecision =
      73         146 :         CSLFetchNameValue(papszOptions, "COORDINATE_PRECISION");
      74         146 :     if (pszCoordPrecision)
      75             :     {
      76           3 :         oWriteOptions_.nXYCoordPrecision = atoi(pszCoordPrecision);
      77           3 :         oWriteOptions_.nZCoordPrecision = atoi(pszCoordPrecision);
      78             :     }
      79             :     else
      80             :     {
      81         143 :         oWriteOptions_.nXYCoordPrecision = atoi(CSLFetchNameValueDef(
      82         143 :             papszOptions, "XY_COORD_PRECISION", bRFC7946_ ? "7" : "-1"));
      83         143 :         oWriteOptions_.nZCoordPrecision = atoi(CSLFetchNameValueDef(
      84         143 :             papszOptions, "Z_COORD_PRECISION", bRFC7946_ ? "3" : "-1"));
      85             :     }
      86         146 :     oWriteOptions_.bWriteBBOX = bWriteBBOX;
      87         146 :     oWriteOptions_.nSignificantFigures = nSignificantFigures_;
      88         146 :     if (bRFC7946_)
      89             :     {
      90          23 :         oWriteOptions_.SetRFC7946Settings();
      91             :     }
      92         146 :     oWriteOptions_.SetIDOptions(papszOptions);
      93         146 :     oWriteOptions_.bAllowNonFiniteValues = CPLTestBool(
      94             :         CSLFetchNameValueDef(papszOptions, "WRITE_NON_FINITE_VALUES", "FALSE"));
      95         146 :     oWriteOptions_.bAutodetectJsonStrings = CPLTestBool(
      96             :         CSLFetchNameValueDef(papszOptions, "AUTODETECT_JSON_STRINGS", "TRUE"));
      97         146 : }
      98             : 
      99             : /************************************************************************/
     100             : /*                        ~OGRGeoJSONWriteLayer()                       */
     101             : /************************************************************************/
     102             : 
     103         292 : OGRGeoJSONWriteLayer::~OGRGeoJSONWriteLayer()
     104             : {
     105         146 :     FinishWriting();
     106             : 
     107         146 :     if (nullptr != poFeatureDefn_)
     108             :     {
     109         146 :         poFeatureDefn_->Release();
     110             :     }
     111             : 
     112         146 :     delete poCT_;
     113         292 : }
     114             : 
     115             : /************************************************************************/
     116             : /*                           FinishWriting()                            */
     117             : /************************************************************************/
     118             : 
     119         286 : void OGRGeoJSONWriteLayer::FinishWriting()
     120             : {
     121         286 :     if (m_nPositionBeforeFCClosed == 0)
     122             :     {
     123         147 :         VSILFILE *fp = poDS_->GetOutputFile();
     124             : 
     125         147 :         m_nPositionBeforeFCClosed = fp->Tell();
     126             : 
     127         147 :         VSIFPrintfL(fp, "\n]");
     128             : 
     129         147 :         if (bWriteFC_BBOX && sEnvelopeLayer.IsInit())
     130             :         {
     131          46 :             CPLString osBBOX = "[ ";
     132             :             char szFormat[32];
     133          23 :             if (oWriteOptions_.nXYCoordPrecision >= 0)
     134          20 :                 snprintf(szFormat, sizeof(szFormat), "%%.%df",
     135             :                          oWriteOptions_.nXYCoordPrecision);
     136             :             else
     137           3 :                 snprintf(szFormat, sizeof(szFormat), "%s", "%.15g");
     138             : 
     139          23 :             osBBOX += CPLSPrintf(szFormat, sEnvelopeLayer.MinX);
     140          23 :             osBBOX += ", ";
     141          23 :             osBBOX += CPLSPrintf(szFormat, sEnvelopeLayer.MinY);
     142          23 :             osBBOX += ", ";
     143          23 :             if (bBBOX3D)
     144             :             {
     145           1 :                 osBBOX += CPLSPrintf(szFormat, sEnvelopeLayer.MinZ);
     146           1 :                 osBBOX += ", ";
     147             :             }
     148          23 :             osBBOX += CPLSPrintf(szFormat, sEnvelopeLayer.MaxX);
     149          23 :             osBBOX += ", ";
     150          23 :             osBBOX += CPLSPrintf(szFormat, sEnvelopeLayer.MaxY);
     151          23 :             if (bBBOX3D)
     152             :             {
     153           1 :                 osBBOX += ", ";
     154           1 :                 osBBOX += CPLSPrintf(szFormat, sEnvelopeLayer.MaxZ);
     155             :             }
     156          23 :             osBBOX += " ]";
     157             : 
     158          46 :             if (poDS_->GetFpOutputIsSeekable() &&
     159          23 :                 osBBOX.size() + 9 < OGRGeoJSONDataSource::SPACE_FOR_BBOX)
     160             :             {
     161          23 :                 VSIFSeekL(fp, poDS_->GetBBOXInsertLocation(), SEEK_SET);
     162          23 :                 VSIFPrintfL(fp, "\"bbox\": %s,", osBBOX.c_str());
     163          23 :                 VSIFSeekL(fp, 0, SEEK_END);
     164             :             }
     165             :             else
     166             :             {
     167           0 :                 VSIFPrintfL(fp, ",\n\"bbox\": %s", osBBOX.c_str());
     168             :             }
     169             :         }
     170             : 
     171         147 :         VSIFPrintfL(fp, "\n}\n");
     172         147 :         fp->Flush();
     173             :     }
     174         286 : }
     175             : 
     176             : /************************************************************************/
     177             : /*                           SyncToDisk()                               */
     178             : /************************************************************************/
     179             : 
     180         218 : OGRErr OGRGeoJSONWriteLayer::SyncToDisk()
     181             : {
     182         218 :     if (m_nPositionBeforeFCClosed == 0 && poDS_->GetFpOutputIsSeekable())
     183             :     {
     184         140 :         FinishWriting();
     185             :     }
     186             : 
     187         218 :     return OGRERR_NONE;
     188             : }
     189             : 
     190             : /************************************************************************/
     191             : /*                           ICreateFeature()                            */
     192             : /************************************************************************/
     193             : 
     194        1055 : OGRErr OGRGeoJSONWriteLayer::ICreateFeature(OGRFeature *poFeature)
     195             : {
     196        1055 :     VSILFILE *fp = poDS_->GetOutputFile();
     197             : 
     198             :     OGRFeature *poFeatureToWrite;
     199        1055 :     if (poCT_ != nullptr || bRFC7946_)
     200             :     {
     201          42 :         poFeatureToWrite = new OGRFeature(poFeatureDefn_);
     202          42 :         poFeatureToWrite->SetFrom(poFeature);
     203          42 :         poFeatureToWrite->SetFID(poFeature->GetFID());
     204          42 :         OGRGeometry *poGeometry = poFeatureToWrite->GetGeometryRef();
     205          42 :         if (poGeometry)
     206             :         {
     207          42 :             const char *const apszOptions[] = {
     208          42 :                 bWrapDateLine_ ? "WRAPDATELINE=YES" : nullptr, nullptr};
     209          84 :             OGRGeometry *poNewGeom = OGRGeometryFactory::transformWithOptions(
     210             :                 poGeometry, poCT_, const_cast<char **>(apszOptions),
     211          42 :                 oTransformCache_);
     212          42 :             if (poNewGeom == nullptr)
     213             :             {
     214           0 :                 delete poFeatureToWrite;
     215           0 :                 return OGRERR_FAILURE;
     216             :             }
     217             : 
     218          42 :             OGREnvelope sEnvelope;
     219          42 :             poNewGeom->getEnvelope(&sEnvelope);
     220          42 :             if (sEnvelope.MinX < -180.0 || sEnvelope.MaxX > 180.0 ||
     221          42 :                 sEnvelope.MinY < -90.0 || sEnvelope.MaxY > 90.0)
     222             :             {
     223           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     224             :                          "Geometry extent outside of "
     225             :                          "[-180.0,180.0]x[-90.0,90.0] bounds");
     226           0 :                 delete poFeatureToWrite;
     227           0 :                 return OGRERR_FAILURE;
     228             :             }
     229             : 
     230          42 :             poFeatureToWrite->SetGeometryDirectly(poNewGeom);
     231          42 :         }
     232             :     }
     233             :     else
     234             :     {
     235        1013 :         poFeatureToWrite = poFeature;
     236             :     }
     237             : 
     238          71 :     const auto IsValid = [](const OGRGeometry *poGeom)
     239             :     {
     240         142 :         CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
     241         142 :         return poGeom->IsValid();
     242             :     };
     243             : 
     244             :     // Special processing to detect and repair invalid geometries due to
     245             :     // coordinate precision.
     246             :     // Normally drivers shouldn't do that as similar code is triggered by
     247             :     // setting the OGR_APPLY_GEOM_SET_PRECISION=YES configuration option by
     248             :     // the generic OGRLayer::CreateFeature() code path. But this code predates
     249             :     // its introduction and RFC99, and can be useful in RFC7946 mode due to
     250             :     // coordinate reprojection.
     251        1055 :     OGRGeometry *poOrigGeom = poFeature->GetGeometryRef();
     252        1055 :     if (OGRGeometryFactory::haveGEOS() &&
     253        1055 :         oWriteOptions_.nXYCoordPrecision >= 0 && poOrigGeom &&
     254        2147 :         wkbFlatten(poOrigGeom->getGeometryType()) != wkbPoint &&
     255          37 :         IsValid(poOrigGeom))
     256             :     {
     257             :         const double dfXYResolution =
     258          34 :             std::pow(10.0, double(-oWriteOptions_.nXYCoordPrecision));
     259             :         auto poNewGeom = poFeature == poFeatureToWrite
     260          34 :                              ? poOrigGeom->clone()
     261          33 :                              : poFeatureToWrite->GetGeometryRef();
     262          34 :         bool bDeleteNewGeom = (poFeature == poFeatureToWrite);
     263          68 :         OGRGeomCoordinatePrecision sPrecision;
     264          34 :         sPrecision.dfXYResolution = dfXYResolution;
     265          34 :         poNewGeom->roundCoordinates(sPrecision);
     266          34 :         if (!IsValid(poNewGeom))
     267             :         {
     268           2 :             CPLDebug("GeoJSON", "Running SetPrecision() to correct an invalid "
     269             :                                 "geometry due to reduced precision output");
     270             :             auto poValidGeom =
     271           2 :                 poOrigGeom->SetPrecision(dfXYResolution, /* nFlags = */ 0);
     272           2 :             if (poValidGeom)
     273             :             {
     274           2 :                 if (poFeature == poFeatureToWrite)
     275             :                 {
     276           1 :                     poFeatureToWrite = new OGRFeature(poFeatureDefn_);
     277           1 :                     poFeatureToWrite->SetFrom(poFeature);
     278           1 :                     poFeatureToWrite->SetFID(poFeature->GetFID());
     279             :                 }
     280             : 
     281           2 :                 poFeatureToWrite->SetGeometryDirectly(poValidGeom);
     282             :             }
     283             :         }
     284          34 :         if (bDeleteNewGeom)
     285           1 :             delete poNewGeom;
     286             :     }
     287             : 
     288        1055 :     if (oWriteOptions_.bGenerateID && poFeatureToWrite->GetFID() == OGRNullFID)
     289             :     {
     290           3 :         poFeatureToWrite->SetFID(nOutCounter_);
     291             :     }
     292             :     json_object *poObj =
     293        1055 :         OGRGeoJSONWriteFeature(poFeatureToWrite, oWriteOptions_);
     294        1055 :     CPLAssert(nullptr != poObj);
     295             : 
     296        1055 :     if (m_nPositionBeforeFCClosed)
     297             :     {
     298             :         // If we had called SyncToDisk() previously, undo its effects
     299           1 :         fp->Seek(m_nPositionBeforeFCClosed, SEEK_SET);
     300           1 :         m_nPositionBeforeFCClosed = 0;
     301             :     }
     302             : 
     303        1055 :     if (nOutCounter_ > 0)
     304             :     {
     305             :         /* Separate "Feature" entries in "FeatureCollection" object. */
     306         930 :         VSIFPrintfL(fp, ",\n");
     307             :     }
     308        1055 :     const char *pszJson = json_object_to_json_string_ext(
     309             :         poObj, JSON_C_TO_STRING_SPACED
     310             : #ifdef JSON_C_TO_STRING_NOSLASHESCAPE
     311             :                    | JSON_C_TO_STRING_NOSLASHESCAPE
     312             : #endif
     313             :     );
     314             : 
     315        1055 :     OGRErr eErr = OGRERR_NONE;
     316        1055 :     size_t nLen = strlen(pszJson);
     317        1055 :     if (!osForeignMembers_.empty())
     318             :     {
     319           1 :         if (nLen > 2 && pszJson[nLen - 2] == ' ' && pszJson[nLen - 1] == '}')
     320             :         {
     321           1 :             nLen -= 2;
     322             :         }
     323             :         else
     324             :         {
     325             :             // should not happen
     326           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     327             :                      "Unexpected JSON output for feature. Cannot write foreign "
     328             :                      "member");
     329           0 :             osForeignMembers_.clear();
     330             :         }
     331             :     }
     332        1055 :     if (VSIFWriteL(pszJson, nLen, 1, fp) != 1)
     333             :     {
     334           0 :         CPLError(CE_Failure, CPLE_FileIO, "Cannot write feature");
     335           0 :         eErr = OGRERR_FAILURE;
     336             :     }
     337        1056 :     else if (!osForeignMembers_.empty() &&
     338           1 :              (VSIFWriteL(", ", 2, 1, fp) != 1 ||
     339           1 :               VSIFWriteL(osForeignMembers_.c_str(), osForeignMembers_.size(), 1,
     340           1 :                          fp) != 1 ||
     341           1 :               VSIFWriteL("}", 1, 1, fp) != 1))
     342             :     {
     343           0 :         CPLError(CE_Failure, CPLE_FileIO, "Cannot write feature");
     344           0 :         eErr = OGRERR_FAILURE;
     345             :     }
     346             : 
     347        1055 :     json_object_put(poObj);
     348             : 
     349        1055 :     ++nOutCounter_;
     350             : 
     351        1055 :     OGRGeometry *poGeometry = poFeatureToWrite->GetGeometryRef();
     352        1055 :     if (poGeometry != nullptr && !poGeometry->IsEmpty())
     353             :     {
     354         963 :         OGREnvelope3D sEnvelope = OGRGeoJSONGetBBox(poGeometry, oWriteOptions_);
     355         963 :         if (poGeometry->getCoordinateDimension() == 3)
     356          21 :             bBBOX3D = true;
     357             : 
     358         963 :         if (!sEnvelopeLayer.IsInit())
     359             :         {
     360          96 :             sEnvelopeLayer = sEnvelope;
     361             :         }
     362         867 :         else if (oWriteOptions_.bBBOXRFC7946)
     363             :         {
     364          20 :             const bool bEnvelopeCrossAM = (sEnvelope.MinX > sEnvelope.MaxX);
     365          20 :             const bool bEnvelopeLayerCrossAM =
     366          20 :                 (sEnvelopeLayer.MinX > sEnvelopeLayer.MaxX);
     367          20 :             if (bEnvelopeCrossAM)
     368             :             {
     369           8 :                 if (bEnvelopeLayerCrossAM)
     370             :                 {
     371           8 :                     sEnvelopeLayer.MinX =
     372           8 :                         std::min(sEnvelopeLayer.MinX, sEnvelope.MinX);
     373           8 :                     sEnvelopeLayer.MaxX =
     374           8 :                         std::max(sEnvelopeLayer.MaxX, sEnvelope.MaxX);
     375             :                 }
     376             :                 else
     377             :                 {
     378           0 :                     if (sEnvelopeLayer.MinX > 0)
     379             :                     {
     380           0 :                         sEnvelopeLayer.MinX =
     381           0 :                             std::min(sEnvelopeLayer.MinX, sEnvelope.MinX);
     382           0 :                         sEnvelopeLayer.MaxX = sEnvelope.MaxX;
     383             :                     }
     384           0 :                     else if (sEnvelopeLayer.MaxX < 0)
     385             :                     {
     386           0 :                         sEnvelopeLayer.MaxX =
     387           0 :                             std::max(sEnvelopeLayer.MaxX, sEnvelope.MaxX);
     388           0 :                         sEnvelopeLayer.MinX = sEnvelope.MinX;
     389             :                     }
     390             :                     else
     391             :                     {
     392           0 :                         sEnvelopeLayer.MinX = -180.0;
     393           0 :                         sEnvelopeLayer.MaxX = 180.0;
     394             :                     }
     395             :                 }
     396             :             }
     397          12 :             else if (bEnvelopeLayerCrossAM)
     398             :             {
     399           0 :                 if (sEnvelope.MinX > 0)
     400             :                 {
     401           0 :                     sEnvelopeLayer.MinX =
     402           0 :                         std::min(sEnvelopeLayer.MinX, sEnvelope.MinX);
     403             :                 }
     404           0 :                 else if (sEnvelope.MaxX < 0)
     405             :                 {
     406           0 :                     sEnvelopeLayer.MaxX =
     407           0 :                         std::max(sEnvelopeLayer.MaxX, sEnvelope.MaxX);
     408             :                 }
     409             :                 else
     410             :                 {
     411           0 :                     sEnvelopeLayer.MinX = -180.0;
     412           0 :                     sEnvelopeLayer.MaxX = 180.0;
     413             :                 }
     414             :             }
     415             :             else
     416             :             {
     417          12 :                 sEnvelopeLayer.MinX =
     418          12 :                     std::min(sEnvelopeLayer.MinX, sEnvelope.MinX);
     419          12 :                 sEnvelopeLayer.MaxX =
     420          12 :                     std::max(sEnvelopeLayer.MaxX, sEnvelope.MaxX);
     421             :             }
     422             : 
     423          20 :             sEnvelopeLayer.MinY = std::min(sEnvelopeLayer.MinY, sEnvelope.MinY);
     424          20 :             sEnvelopeLayer.MaxY = std::max(sEnvelopeLayer.MaxY, sEnvelope.MaxY);
     425             :         }
     426             :         else
     427             :         {
     428         847 :             sEnvelopeLayer.Merge(sEnvelope);
     429             :         }
     430             :     }
     431             : 
     432        1055 :     if (poFeatureToWrite != poFeature)
     433          43 :         delete poFeatureToWrite;
     434             : 
     435        1055 :     return eErr;
     436             : }
     437             : 
     438             : /************************************************************************/
     439             : /*                           CreateField()                              */
     440             : /************************************************************************/
     441             : 
     442         209 : OGRErr OGRGeoJSONWriteLayer::CreateField(const OGRFieldDefn *poField,
     443             :                                          int /* bApproxOK */)
     444             : {
     445         209 :     if (poFeatureDefn_->GetFieldIndexCaseSensitive(poField->GetNameRef()) >= 0)
     446             :     {
     447           0 :         CPLDebug("GeoJSON", "Field '%s' already present in schema",
     448             :                  poField->GetNameRef());
     449             : 
     450             :         // TODO - mloskot: Is this return code correct?
     451           0 :         return OGRERR_NONE;
     452             :     }
     453             : 
     454         209 :     poFeatureDefn_->AddFieldDefn(poField);
     455             : 
     456         209 :     return OGRERR_NONE;
     457             : }
     458             : 
     459             : /************************************************************************/
     460             : /*                           TestCapability()                           */
     461             : /************************************************************************/
     462             : 
     463         345 : int OGRGeoJSONWriteLayer::TestCapability(const char *pszCap)
     464             : {
     465         345 :     if (EQUAL(pszCap, OLCCreateField))
     466          16 :         return TRUE;
     467         329 :     else if (EQUAL(pszCap, OLCSequentialWrite))
     468          20 :         return TRUE;
     469         309 :     else if (EQUAL(pszCap, OLCStringsAsUTF8))
     470           0 :         return TRUE;
     471         309 :     return FALSE;
     472             : }
     473             : 
     474             : /************************************************************************/
     475             : /*                            GetExtent()                               */
     476             : /************************************************************************/
     477             : 
     478           2 : OGRErr OGRGeoJSONWriteLayer::GetExtent(OGREnvelope *psExtent, int)
     479             : {
     480           2 :     if (sEnvelopeLayer.IsInit())
     481             :     {
     482           2 :         *psExtent = sEnvelopeLayer;
     483           2 :         return OGRERR_NONE;
     484             :     }
     485           0 :     return OGRERR_FAILURE;
     486             : }
     487             : 
     488             : /************************************************************************/
     489             : /*                             GetDataset()                             */
     490             : /************************************************************************/
     491             : 
     492          34 : GDALDataset *OGRGeoJSONWriteLayer::GetDataset()
     493             : {
     494          34 :     return poDS_;
     495             : }

Generated by: LCOV version 1.14