LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/geoconcept - ogrgeoconceptdatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 145 230 63.0 %
Date: 2024-11-21 22:18:42 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Name:     ogrgeoconceptdatasource.h
       4             :  * Project:  OpenGIS Simple Features Reference Implementation
       5             :  * Purpose:  Implements OGRGeoconceptDataSource class.
       6             :  * Language: C++
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2007, Geoconcept and IGN
      10             :  * Copyright (c) 2008, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_conv.h"
      16             : #include "cpl_string.h"
      17             : #include "ogrgeoconceptdatasource.h"
      18             : #include "ogrgeoconceptlayer.h"
      19             : 
      20             : /************************************************************************/
      21             : /*                         OGRGeoconceptDataSource()                    */
      22             : /************************************************************************/
      23             : 
      24          34 : OGRGeoconceptDataSource::OGRGeoconceptDataSource()
      25             :     : _papoLayers(nullptr), _nLayers(0), _pszGCT(nullptr),
      26             :       _pszDirectory(nullptr), _pszExt(nullptr), _papszOptions(nullptr),
      27          34 :       _bSingleNewFile(false), _bUpdate(false), _hGXT(nullptr)
      28             : {
      29          34 : }
      30             : 
      31             : /************************************************************************/
      32             : /*                        ~OGRGeoconceptDataSource()                    */
      33             : /************************************************************************/
      34             : 
      35          68 : OGRGeoconceptDataSource::~OGRGeoconceptDataSource()
      36             : 
      37             : {
      38          43 :     for (int i = 0; i < _nLayers; i++)
      39             :     {
      40           9 :         delete _papoLayers[i];
      41             :     }
      42          34 :     CPLFree(_papoLayers);
      43          34 :     CPLFree(_pszGCT);
      44          34 :     CPLFree(_pszDirectory);
      45          34 :     CPLFree(_pszExt);
      46          34 :     CSLDestroy(_papszOptions);
      47             : 
      48          34 :     if (_hGXT)
      49             :     {
      50          25 :         Close_GCIO(&_hGXT);
      51             :     }
      52          68 : }
      53             : 
      54             : /************************************************************************/
      55             : /*                                Open()                                */
      56             : /*                                                                      */
      57             : /*      Open an existing file.                                          */
      58             : /************************************************************************/
      59             : 
      60          16 : int OGRGeoconceptDataSource::Open(const char *pszName, bool bTestOpen,
      61             :                                   bool bUpdate)
      62             : 
      63             : {
      64             :     /* -------------------------------------------------------------------- */
      65             :     /*      Is the given path a directory or a regular file?                */
      66             :     /* -------------------------------------------------------------------- */
      67             :     VSIStatBufL sStat;
      68             : 
      69          28 :     if (VSIStatL(pszName, &sStat) != 0 ||
      70          12 :         (!VSI_ISDIR(sStat.st_mode) && !VSI_ISREG(sStat.st_mode)))
      71             :     {
      72           4 :         if (!bTestOpen)
      73             :         {
      74           0 :             CPLError(CE_Failure, CPLE_AppDefined,
      75             :                      "%s is neither a file or directory, "
      76             :                      "Geoconcept access failed.",
      77             :                      pszName);
      78             :         }
      79             : 
      80           4 :         return FALSE;
      81             :     }
      82             : 
      83          12 :     if (VSI_ISDIR(sStat.st_mode))
      84             :     {
      85           0 :         CPLDebug("GEOCONCEPT",
      86             :                  "%s is a directory, Geoconcept access is not yet supported.",
      87             :                  pszName);
      88             : 
      89           0 :         return FALSE;
      90             :     }
      91             : 
      92          12 :     SetDescription(pszName);
      93             : 
      94          12 :     if (VSI_ISREG(sStat.st_mode))
      95             :     {
      96          12 :         _bSingleNewFile = false;
      97          12 :         _bUpdate = bUpdate;
      98          12 :         if (!LoadFile(_bUpdate ? "a+t" : "rt"))
      99             :         {
     100           4 :             CPLDebug("GEOCONCEPT",
     101             :                      "Failed to open Geoconcept %s."
     102             :                      " It may be corrupt.",
     103             :                      pszName);
     104             : 
     105           4 :             return FALSE;
     106             :         }
     107             : 
     108           8 :         return TRUE;
     109             :     }
     110             : 
     111           0 :     return _nLayers > 0;
     112             : }
     113             : 
     114             : /************************************************************************/
     115             : /*                              LoadFile()                              */
     116             : /************************************************************************/
     117             : 
     118          29 : int OGRGeoconceptDataSource::LoadFile(const char *pszMode)
     119             : 
     120             : {
     121          29 :     if (_pszExt == nullptr)
     122             :     {
     123          12 :         const char *pszExtension = CPLGetExtension(GetDescription());
     124          12 :         _pszExt = CPLStrdup(pszExtension);
     125             :     }
     126          29 :     CPLStrlwr(_pszExt);
     127             : 
     128          29 :     if (!_pszDirectory)
     129          12 :         _pszDirectory = CPLStrdup(CPLGetPath(GetDescription()));
     130             : 
     131          29 :     if ((_hGXT = Open_GCIO(GetDescription(), _pszExt, pszMode, _pszGCT)) ==
     132             :         nullptr)
     133             :     {
     134           4 :         return FALSE;
     135             :     }
     136             : 
     137             :     /* Collect layers : */
     138          25 :     GCExportFileMetadata *Meta = GetGCMeta_GCIO(_hGXT);
     139          25 :     if (Meta)
     140             :     {
     141           8 :         const int nC = CountMetaTypes_GCIO(Meta);
     142             : 
     143           8 :         if (nC > 0)
     144             :         {
     145          16 :             for (int iC = 0; iC < nC; iC++)
     146             :             {
     147           8 :                 GCType *aClass = GetMetaType_GCIO(Meta, iC);
     148           8 :                 if (aClass)
     149             :                 {
     150           8 :                     const int nS = CountTypeSubtypes_GCIO(aClass);
     151           8 :                     if (nS)
     152             :                     {
     153          16 :                         for (int iS = 0; iS < nS; iS++)
     154             :                         {
     155             :                             GCSubType *aSubclass =
     156           8 :                                 GetTypeSubtype_GCIO(aClass, iS);
     157           8 :                             if (aSubclass)
     158             :                             {
     159             :                                 OGRGeoconceptLayer *poFile =
     160           8 :                                     new OGRGeoconceptLayer;
     161           8 :                                 if (poFile->Open(aSubclass) != OGRERR_NONE)
     162             :                                 {
     163           0 :                                     delete poFile;
     164           0 :                                     return FALSE;
     165             :                                 }
     166             : 
     167             :                                 /* Add layer to data source layers list */
     168           8 :                                 _papoLayers =
     169             :                                     static_cast<OGRGeoconceptLayer **>(
     170          16 :                                         CPLRealloc(
     171           8 :                                             _papoLayers,
     172             :                                             sizeof(OGRGeoconceptLayer *) *
     173           8 :                                                 (_nLayers + 1)));
     174           8 :                                 _papoLayers[_nLayers++] = poFile;
     175             : 
     176           8 :                                 CPLDebug("GEOCONCEPT", "nLayers=%d - last=[%s]",
     177             :                                          _nLayers,
     178           8 :                                          poFile->GetLayerDefn()->GetName());
     179             :                             }
     180             :                         }
     181             :                     }
     182             :                 }
     183             :             }
     184             :         }
     185             :     }
     186             : 
     187          25 :     return TRUE;
     188             : }
     189             : 
     190             : /************************************************************************/
     191             : /*                               Create()                               */
     192             : /*                                                                      */
     193             : /*      Create a new dataset.                                           */
     194             : /*                                                                      */
     195             : /* Options (-dsco) :                                                    */
     196             : /*   EXTENSION : gxt|txt                                                */
     197             : /*   CONFIG : path to GCT file                                          */
     198             : /************************************************************************/
     199             : 
     200          18 : int OGRGeoconceptDataSource::Create(const char *pszName, char **papszOptions)
     201             : 
     202             : {
     203          18 :     _papszOptions = CSLDuplicate(papszOptions);
     204             : 
     205          18 :     const char *pszConf = CSLFetchNameValue(papszOptions, "CONFIG");
     206          18 :     if (pszConf != nullptr)
     207             :     {
     208           0 :         _pszGCT = CPLStrdup(pszConf);
     209             :     }
     210             : 
     211          18 :     _pszExt = (char *)CSLFetchNameValue(papszOptions, "EXTENSION");
     212          18 :     const char *pszExtension = CSLFetchNameValue(papszOptions, "EXTENSION");
     213          18 :     if (pszExtension == nullptr)
     214             :     {
     215          18 :         _pszExt = CPLStrdup(CPLGetExtension(pszName));
     216             :     }
     217             :     else
     218             :     {
     219           0 :         _pszExt = CPLStrdup(pszExtension);
     220             :     }
     221             : 
     222          18 :     if (strlen(_pszExt) == 0)
     223             :     {
     224          17 :         if (VSIMkdir(pszName, 0755) != 0)
     225             :         {
     226           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     227             :                      "Directory %s already exists"
     228             :                      " as geoconcept datastore or"
     229             :                      " is made up of a non existing list of directories.",
     230             :                      pszName);
     231             : 
     232           1 :             return FALSE;
     233             :         }
     234          16 :         _pszDirectory = CPLStrdup(pszName);
     235          16 :         CPLFree(_pszExt);
     236          16 :         _pszExt = CPLStrdup("gxt");
     237          16 :         char *pszbName = CPLStrdup(CPLGetBasename(pszName));
     238          16 :         if (strlen(pszbName) == 0)
     239             :         { /* pszName ends with '/' */
     240           0 :             CPLFree(pszbName);
     241           0 :             char *pszNameDup = CPLStrdup(pszName);
     242           0 :             pszNameDup[strlen(pszName) - 2] = '\0';
     243           0 :             pszbName = CPLStrdup(CPLGetBasename(pszNameDup));
     244           0 :             CPLFree(pszNameDup);
     245             :         }
     246          16 :         SetDescription(CPLFormFilename(_pszDirectory, pszbName, nullptr));
     247          16 :         CPLFree(pszbName);
     248             :     }
     249             :     else
     250             :     {
     251           1 :         _pszDirectory = CPLStrdup(CPLGetPath(pszName));
     252           1 :         SetDescription(pszName);
     253             :     }
     254             : 
     255             :     /* -------------------------------------------------------------------- */
     256             :     /*      Create a new single file.                                       */
     257             :     /*      OGRGeoconceptDriver::ICreateLayer() will do the job.             */
     258             :     /* -------------------------------------------------------------------- */
     259          17 :     _bSingleNewFile = true;
     260             : 
     261          17 :     if (!LoadFile("wt"))
     262             :     {
     263           0 :         CPLDebug("GEOCONCEPT", "Failed to create Geoconcept %s.", pszName);
     264             : 
     265           0 :         return FALSE;
     266             :     }
     267             : 
     268          17 :     return TRUE;
     269             : }
     270             : 
     271             : /************************************************************************/
     272             : /*                           ICreateLayer()                             */
     273             : /*                                                                      */
     274             : /* Options (-lco) :                                                     */
     275             : /*   FEATURETYPE : TYPE.SUBTYPE                                         */
     276             : /************************************************************************/
     277             : 
     278             : OGRLayer *
     279          17 : OGRGeoconceptDataSource::ICreateLayer(const char *pszLayerName,
     280             :                                       const OGRGeomFieldDefn *poGeomFieldDefn,
     281             :                                       CSLConstList papszOptions)
     282             : 
     283             : {
     284          17 :     if (_hGXT == nullptr)
     285             :     {
     286           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     287             :                  "Internal Error : null datasource handler.");
     288           0 :         return nullptr;
     289             :     }
     290             : 
     291             :     const auto poSRS =
     292          17 :         poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
     293          17 :     if (poSRS == nullptr && !_bUpdate)
     294             :     {
     295          16 :         CPLError(CE_Failure, CPLE_NotSupported,
     296             :                  "SRS is mandatory of creating a Geoconcept Layer.");
     297          16 :         return nullptr;
     298             :     }
     299             : 
     300             :     /*
     301             :      * pszLayerName Class.Subclass if -nln option used, otherwise file name
     302             :      */
     303           1 :     const char *pszFeatureType = nullptr;
     304             :     char pszln[512];
     305             : 
     306           1 :     if (!(pszFeatureType = CSLFetchNameValue(papszOptions, "FEATURETYPE")))
     307             :     {
     308           1 :         if (!pszLayerName || !strchr(pszLayerName, '.'))
     309             :         {
     310           1 :             snprintf(pszln, 511, "%s.%s",
     311             :                      pszLayerName ? pszLayerName : "ANONCLASS",
     312             :                      pszLayerName ? pszLayerName : "ANONSUBCLASS");
     313           1 :             pszln[511] = '\0';
     314           1 :             pszFeatureType = pszln;
     315             :         }
     316             :         else
     317           0 :             pszFeatureType = pszLayerName;
     318             :     }
     319             : 
     320           1 :     char **ft = CSLTokenizeString2(pszFeatureType, ".", 0);
     321           1 :     if (!ft || CSLCount(ft) != 2)
     322             :     {
     323           0 :         CSLDestroy(ft);
     324           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     325             :                  "Feature type name '%s' is incorrect."
     326             :                  "Correct syntax is : Class.Subclass.",
     327             :                  pszFeatureType);
     328           0 :         return nullptr;
     329             :     }
     330             : 
     331             :     /* -------------------------------------------------------------------- */
     332             :     /*      Figure out what type of layer we need.                          */
     333             :     /* -------------------------------------------------------------------- */
     334             :     GCTypeKind gcioFeaType;
     335           1 :     GCDim gcioDim = v2D_GCIO;
     336             : 
     337           1 :     const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
     338           1 :     if (eType == wkbUnknown)
     339           0 :         gcioFeaType = vUnknownItemType_GCIO;
     340           1 :     else if (eType == wkbPoint)
     341           1 :         gcioFeaType = vPoint_GCIO;
     342           0 :     else if (eType == wkbLineString)
     343           0 :         gcioFeaType = vLine_GCIO;
     344           0 :     else if (eType == wkbPolygon)
     345           0 :         gcioFeaType = vPoly_GCIO;
     346           0 :     else if (eType == wkbMultiPoint)
     347           0 :         gcioFeaType = vPoint_GCIO;
     348           0 :     else if (eType == wkbMultiLineString)
     349           0 :         gcioFeaType = vLine_GCIO;
     350           0 :     else if (eType == wkbMultiPolygon)
     351           0 :         gcioFeaType = vPoly_GCIO;
     352           0 :     else if (eType == wkbPoint25D)
     353             :     {
     354           0 :         gcioFeaType = vPoint_GCIO;
     355           0 :         gcioDim = v3DM_GCIO;
     356             :     }
     357           0 :     else if (eType == wkbLineString25D)
     358             :     {
     359           0 :         gcioFeaType = vLine_GCIO;
     360           0 :         gcioDim = v3DM_GCIO;
     361             :     }
     362           0 :     else if (eType == wkbPolygon25D)
     363             :     {
     364           0 :         gcioFeaType = vPoly_GCIO;
     365           0 :         gcioDim = v3DM_GCIO;
     366             :     }
     367           0 :     else if (eType == wkbMultiPoint25D)
     368             :     {
     369           0 :         gcioFeaType = vPoint_GCIO;
     370           0 :         gcioDim = v3DM_GCIO;
     371             :     }
     372           0 :     else if (eType == wkbMultiLineString25D)
     373             :     {
     374           0 :         gcioFeaType = vLine_GCIO;
     375           0 :         gcioDim = v3DM_GCIO;
     376             :     }
     377           0 :     else if (eType == wkbMultiPolygon25D)
     378             :     {
     379           0 :         gcioFeaType = vPoly_GCIO;
     380           0 :         gcioDim = v3DM_GCIO;
     381             :     }
     382             :     else
     383             :     {
     384           0 :         CSLDestroy(ft);
     385           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     386             :                  "Geometry type of '%s' not supported in Geoconcept files.",
     387             :                  OGRGeometryTypeToName(eType));
     388           0 :         return nullptr;
     389             :     }
     390             : 
     391             :     /*
     392             :      * As long as we use the CONFIG, creating a layer implies the
     393             :      * layer name to exist in the CONFIG as "Class.Subclass".
     394             :      * Removing the CONFIG, implies on-the-fly-creation of layers...
     395             :      */
     396           1 :     OGRGeoconceptLayer *poFile = nullptr;
     397             : 
     398           1 :     if (_nLayers > 0)
     399           0 :         for (int iLayer = 0; iLayer < _nLayers; iLayer++)
     400             :         {
     401           0 :             poFile = reinterpret_cast<OGRGeoconceptLayer *>(GetLayer(iLayer));
     402           0 :             if (poFile != nullptr &&
     403           0 :                 EQUAL(poFile->GetLayerDefn()->GetName(), pszFeatureType))
     404             :             {
     405           0 :                 break;
     406             :             }
     407           0 :             poFile = nullptr;
     408             :         }
     409           1 :     if (!poFile)
     410             :     {
     411           1 :         GCSubType *aSubclass = nullptr;
     412           1 :         GCExportFileMetadata *m = GetGCMeta_GCIO(_hGXT);
     413             : 
     414           1 :         if (!m)
     415             :         {
     416           1 :             if (!(m = CreateHeader_GCIO()))
     417             :             {
     418           0 :                 CSLDestroy(ft);
     419           0 :                 return nullptr;
     420             :             }
     421           1 :             SetMetaExtent_GCIO(
     422             :                 m, CreateExtent_GCIO(HUGE_VAL, HUGE_VAL, -HUGE_VAL, -HUGE_VAL));
     423           1 :             SetGCMeta_GCIO(_hGXT, m);
     424             :         }
     425           1 :         if (FindFeature_GCIO(_hGXT, pszFeatureType))
     426             :         {
     427           0 :             CSLDestroy(ft);
     428           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Layer '%s' already exists.",
     429             :                      pszFeatureType);
     430           0 :             return nullptr;
     431             :         }
     432           1 :         if (!AddType_GCIO(_hGXT, ft[0], -1L))
     433             :         {
     434           0 :             CSLDestroy(ft);
     435           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Failed to add layer '%s'.",
     436             :                      pszFeatureType);
     437           0 :             return nullptr;
     438             :         }
     439           1 :         if (!(aSubclass = AddSubType_GCIO(_hGXT, ft[0], ft[1], -1L, gcioFeaType,
     440             :                                           gcioDim)))
     441             :         {
     442           0 :             CSLDestroy(ft);
     443           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Failed to add layer '%s'.",
     444             :                      pszFeatureType);
     445           0 :             return nullptr;
     446             :         }
     447             :         /* complete feature type with private fields : */
     448           1 :         AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kIdentifier_GCIO, -100,
     449             :                              vIntFld_GCIO, nullptr, nullptr);
     450           1 :         AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kClass_GCIO, -101,
     451             :                              vMemoFld_GCIO, nullptr, nullptr);
     452           1 :         AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kSubclass_GCIO, -102,
     453             :                              vMemoFld_GCIO, nullptr, nullptr);
     454           1 :         AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kName_GCIO, -103,
     455             :                              vMemoFld_GCIO, nullptr, nullptr);
     456           1 :         AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kNbFields_GCIO, -104,
     457             :                              vIntFld_GCIO, nullptr, nullptr);
     458           1 :         AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kX_GCIO, -105,
     459             :                              vRealFld_GCIO, nullptr, nullptr);
     460           1 :         AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kY_GCIO, -106,
     461             :                              vRealFld_GCIO, nullptr, nullptr);
     462             :         /* user's fields will be added with Layer->CreateField() method ... */
     463           1 :         switch (gcioFeaType)
     464             :         {
     465           1 :             case vPoint_GCIO:
     466           1 :                 break;
     467           0 :             case vLine_GCIO:
     468           0 :                 AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kXP_GCIO, -107,
     469             :                                      vRealFld_GCIO, nullptr, nullptr);
     470           0 :                 AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kYP_GCIO, -108,
     471             :                                      vRealFld_GCIO, nullptr, nullptr);
     472           0 :                 AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kGraphics_GCIO,
     473             :                                      -109, vUnknownItemType_GCIO, nullptr,
     474             :                                      nullptr);
     475           0 :                 break;
     476           0 :             default:
     477           0 :                 AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kGraphics_GCIO,
     478             :                                      -109, vUnknownItemType_GCIO, nullptr,
     479             :                                      nullptr);
     480           0 :                 break;
     481             :         }
     482           1 :         SetSubTypeGCHandle_GCIO(aSubclass, _hGXT);
     483             : 
     484             :         /* Add layer to data source layers list */
     485           1 :         poFile = new OGRGeoconceptLayer;
     486           1 :         if (poFile->Open(aSubclass) != OGRERR_NONE)
     487             :         {
     488           0 :             CSLDestroy(ft);
     489           0 :             delete poFile;
     490           0 :             return nullptr;
     491             :         }
     492             : 
     493           2 :         _papoLayers = static_cast<OGRGeoconceptLayer **>(CPLRealloc(
     494           1 :             _papoLayers, sizeof(OGRGeoconceptLayer *) * (_nLayers + 1)));
     495           1 :         _papoLayers[_nLayers++] = poFile;
     496             : 
     497           1 :         CPLDebug("GEOCONCEPT", "nLayers=%d - last=[%s]", _nLayers,
     498           1 :                  poFile->GetLayerDefn()->GetName());
     499             :     }
     500           1 :     CSLDestroy(ft);
     501             : 
     502             :     /* -------------------------------------------------------------------- */
     503             :     /*      Assign the coordinate system (if provided)                      */
     504             :     /* -------------------------------------------------------------------- */
     505           1 :     if (poSRS != nullptr)
     506             :     {
     507           1 :         auto poSRSClone = poSRS->Clone();
     508           1 :         poFile->SetSpatialRef(poSRSClone);
     509           1 :         poSRSClone->Release();
     510             :     }
     511             : 
     512           1 :     return poFile;
     513             : }
     514             : 
     515             : /************************************************************************/
     516             : /*                           TestCapability()                           */
     517             : /************************************************************************/
     518             : 
     519          16 : int OGRGeoconceptDataSource::TestCapability(const char *pszCap)
     520             : 
     521             : {
     522          16 :     if (EQUAL(pszCap, ODsCCreateLayer))
     523          16 :         return TRUE;
     524           0 :     else if (EQUAL(pszCap, ODsCZGeometries))
     525           0 :         return TRUE;
     526             : 
     527           0 :     return FALSE;
     528             : }
     529             : 
     530             : /************************************************************************/
     531             : /*                              GetLayer()                              */
     532             : /************************************************************************/
     533             : 
     534           8 : OGRLayer *OGRGeoconceptDataSource::GetLayer(int iLayer)
     535             : 
     536             : {
     537           8 :     if (iLayer < 0 || iLayer >= GetLayerCount())
     538           0 :         return nullptr;
     539             : 
     540           8 :     OGRLayer *poFile = _papoLayers[iLayer];
     541           8 :     return poFile;
     542             : }

Generated by: LCOV version 1.14