LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/nas - ogrnaslayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 76 146 52.1 %
Date: 2026-02-07 18:19:04 Functions: 6 8 75.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OGR
       4             :  * Purpose:  Implements OGRNASLayer class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_conv.h"
      15             : #include "cpl_port.h"
      16             : #include "cpl_string.h"
      17             : #include "ogr_nas.h"
      18             : 
      19             : /************************************************************************/
      20             : /*                            OGRNASLayer()                             */
      21             : /************************************************************************/
      22             : 
      23           5 : OGRNASLayer::OGRNASLayer(const char *pszName, OGRNASDataSource *poDSIn)
      24             :     : poFeatureDefn(new OGRFeatureDefn(
      25           5 :           pszName + (STARTS_WITH_CI(pszName, "ogr:") ? 4 : 0))),
      26             :       iNextNASId(0), poDS(poDSIn),
      27             :       // Readers should get the corresponding GMLFeatureClass and cache it.
      28          10 :       poFClass(poDS->GetReader()->GetClass(pszName))
      29             : {
      30           5 :     SetDescription(poFeatureDefn->GetName());
      31           5 :     poFeatureDefn->Reference();
      32           5 :     poFeatureDefn->SetGeomType(wkbNone);
      33           5 : }
      34             : 
      35             : /************************************************************************/
      36             : /*                            ~OGRNASLayer()                            */
      37             : /************************************************************************/
      38             : 
      39          10 : OGRNASLayer::~OGRNASLayer()
      40             : 
      41             : {
      42           5 :     if (poFeatureDefn)
      43           5 :         poFeatureDefn->Release();
      44          10 : }
      45             : 
      46             : /************************************************************************/
      47             : /*                            ResetReading()                            */
      48             : /************************************************************************/
      49             : 
      50           6 : void OGRNASLayer::ResetReading()
      51             : 
      52             : {
      53           6 :     iNextNASId = 0;
      54           6 :     poDS->GetReader()->ResetReading();
      55           6 :     if (poFClass)
      56           6 :         poDS->GetReader()->SetFilteredClassName(poFClass->GetElementName());
      57           6 : }
      58             : 
      59             : /************************************************************************/
      60             : /*                           GetNextFeature()                           */
      61             : /************************************************************************/
      62             : 
      63           3 : OGRFeature *OGRNASLayer::GetNextFeature()
      64             : 
      65             : {
      66           3 :     GMLFeature *poNASFeature = nullptr;
      67             : 
      68           3 :     if (iNextNASId == 0)
      69           3 :         ResetReading();
      70             : 
      71             :     /* ==================================================================== */
      72             :     /*      Loop till we find and translate a feature meeting all our       */
      73             :     /*      requirements.                                                   */
      74             :     /* ==================================================================== */
      75             :     while (true)
      76             :     {
      77             :         /* --------------------------------------------------------------------
      78             :          */
      79             :         /*      Cleanup last feature, and get a new raw nas feature. */
      80             :         /* --------------------------------------------------------------------
      81             :          */
      82           3 :         delete poNASFeature;
      83           3 :         poNASFeature = poDS->GetReader()->NextFeature();
      84           3 :         if (poNASFeature == nullptr)
      85           3 :             return nullptr;
      86             : 
      87             :         /* --------------------------------------------------------------------
      88             :          */
      89             :         /*      Is it of the proper feature class? */
      90             :         /* --------------------------------------------------------------------
      91             :          */
      92             : 
      93             :         // We count reading low level NAS features as a feature read for
      94             :         // work checking purposes, though at least we didn't necessary
      95             :         // have to turn it into an OGRFeature.
      96           3 :         m_nFeaturesRead++;
      97             : 
      98           3 :         if (poNASFeature->GetClass() != poFClass)
      99           0 :             continue;
     100             : 
     101           3 :         iNextNASId++;
     102             : 
     103             :         /* --------------------------------------------------------------------
     104             :          */
     105             :         /*      Does it satisfy the spatial query, if there is one? */
     106             :         /* --------------------------------------------------------------------
     107             :          */
     108           3 :         const CPLXMLNode *const *papsGeometry = poNASFeature->GetGeometryList();
     109             : 
     110             :         std::vector<std::unique_ptr<OGRGeometry>> apoGeom(
     111           3 :             poNASFeature->GetGeometryCount());
     112             : 
     113           3 :         bool bErrored = false, bFiltered = false;
     114           3 :         CPLString osLastErrorMsg;
     115           4 :         for (int iGeom = 0; iGeom < poNASFeature->GetGeometryCount(); ++iGeom)
     116             :         {
     117           1 :             if (papsGeometry[iGeom])
     118             :             {
     119           1 :                 CPLPushErrorHandler(CPLQuietErrorHandler);
     120             : 
     121           2 :                 apoGeom[iGeom].reset(OGRGeometry::FromHandle(
     122           1 :                     OGR_G_CreateFromGMLTree(papsGeometry[iGeom])));
     123           1 :                 CPLPopErrorHandler();
     124           1 :                 if (apoGeom[iGeom] == nullptr)
     125           0 :                     osLastErrorMsg = CPLGetLastErrorMsg();
     126           1 :                 apoGeom[iGeom] =
     127           2 :                     NASReader::ConvertGeometry(std::move(apoGeom[iGeom]));
     128           2 :                 apoGeom[iGeom] = OGRGeometryFactory::forceTo(
     129           2 :                     std::move(apoGeom[iGeom]), GetGeomType());
     130             : 
     131           1 :                 if (apoGeom[iGeom] == nullptr)
     132           0 :                     bErrored = true;
     133             :             }
     134             : 
     135           1 :             bFiltered = m_poFilterGeom != nullptr &&
     136           0 :                         !FilterGeometry(apoGeom[iGeom].get());
     137           1 :             if (bErrored || bFiltered)
     138             :             {
     139             :                 break;
     140             :             }
     141             :         }
     142             : 
     143           3 :         if (bErrored)
     144             :         {
     145             : 
     146           0 :             CPLString osGMLId;
     147           0 :             if (poFClass->GetPropertyIndex("gml_id") == 0)
     148             :             {
     149           0 :                 const GMLProperty *psGMLProperty = poNASFeature->GetProperty(0);
     150           0 :                 if (psGMLProperty && psGMLProperty->nSubProperties == 1)
     151             :                 {
     152             :                     osGMLId.Printf("(gml_id=%s) ",
     153           0 :                                    psGMLProperty->papszSubProperties[0]);
     154             :                 }
     155             :             }
     156             : 
     157           0 :             delete poNASFeature;
     158           0 :             poNASFeature = nullptr;
     159             : 
     160           0 :             const bool bGoOn = CPLTestBool(
     161             :                 CPLGetConfigOption("NAS_SKIP_CORRUPTED_FEATURES", "NO"));
     162           0 :             CPLError(bGoOn ? CE_Warning : CE_Failure, CPLE_AppDefined,
     163             :                      "Geometry of feature %d %scannot be parsed: %s%s",
     164             :                      iNextNASId, osGMLId.c_str(), osLastErrorMsg.c_str(),
     165             :                      bGoOn ? ". Skipping to next feature."
     166             :                            : ". You may set the NAS_SKIP_CORRUPTED_FEATURES "
     167             :                              "configuration option to YES to skip to the next "
     168             :                              "feature");
     169           0 :             if (bGoOn)
     170           0 :                 continue;
     171             : 
     172           0 :             return nullptr;
     173             :         }
     174             : 
     175           3 :         if (bFiltered)
     176           0 :             continue;
     177             : 
     178             :         /* --------------------------------------------------------------------
     179             :          */
     180             :         /*      Convert the whole feature into an OGRFeature. */
     181             :         /* --------------------------------------------------------------------
     182             :          */
     183           3 :         OGRFeature *poOGRFeature = new OGRFeature(GetLayerDefn());
     184             : 
     185           3 :         poOGRFeature->SetFID(iNextNASId);
     186             : 
     187          45 :         for (int iField = 0; iField < poFClass->GetPropertyCount(); iField++)
     188             :         {
     189             :             const GMLProperty *psGMLProperty =
     190          42 :                 poNASFeature->GetProperty(iField);
     191          42 :             if (psGMLProperty == nullptr || psGMLProperty->nSubProperties == 0)
     192           8 :                 continue;
     193             : 
     194          34 :             switch (poFClass->GetProperty(iField)->GetType())
     195             :             {
     196           1 :                 case GMLPT_Real:
     197             :                 {
     198           1 :                     poOGRFeature->SetField(
     199           1 :                         iField, CPLAtof(psGMLProperty->papszSubProperties[0]));
     200             :                 }
     201           1 :                 break;
     202             : 
     203           0 :                 case GMLPT_IntegerList:
     204             :                 {
     205           0 :                     int nCount = psGMLProperty->nSubProperties;
     206             :                     int *panIntList =
     207           0 :                         static_cast<int *>(CPLMalloc(sizeof(int) * nCount));
     208             : 
     209           0 :                     for (int i = 0; i < nCount; i++)
     210           0 :                         panIntList[i] =
     211           0 :                             atoi(psGMLProperty->papszSubProperties[i]);
     212             : 
     213           0 :                     poOGRFeature->SetField(iField, nCount, panIntList);
     214           0 :                     CPLFree(panIntList);
     215             :                 }
     216           0 :                 break;
     217             : 
     218           0 :                 case GMLPT_RealList:
     219             :                 {
     220           0 :                     int nCount = psGMLProperty->nSubProperties;
     221             :                     double *padfList = static_cast<double *>(
     222           0 :                         CPLMalloc(sizeof(double) * nCount));
     223             : 
     224           0 :                     for (int i = 0; i < nCount; i++)
     225           0 :                         padfList[i] =
     226           0 :                             CPLAtof(psGMLProperty->papszSubProperties[i]);
     227             : 
     228           0 :                     poOGRFeature->SetField(iField, nCount, padfList);
     229           0 :                     CPLFree(padfList);
     230             :                 }
     231           0 :                 break;
     232             : 
     233           2 :                 case GMLPT_StringList:
     234             :                 {
     235           2 :                     poOGRFeature->SetField(iField,
     236           2 :                                            psGMLProperty->papszSubProperties);
     237             :                 }
     238           2 :                 break;
     239             : 
     240          31 :                 default:
     241          31 :                     poOGRFeature->SetField(
     242          31 :                         iField, psGMLProperty->papszSubProperties[0]);
     243          31 :                     break;
     244             :             }
     245             :         }
     246             : 
     247           4 :         for (int iGeom = 0; iGeom < poNASFeature->GetGeometryCount(); ++iGeom)
     248             :         {
     249           1 :             poOGRFeature->SetGeomField(iGeom, std::move(apoGeom[iGeom]));
     250             :         }
     251             : 
     252             :         /* --------------------------------------------------------------------
     253             :          */
     254             :         /*      Test against the attribute query. */
     255             :         /* --------------------------------------------------------------------
     256             :          */
     257           3 :         if (m_poAttrQuery != nullptr && !m_poAttrQuery->Evaluate(poOGRFeature))
     258             :         {
     259           0 :             delete poOGRFeature;
     260           0 :             continue;
     261             :         }
     262             : 
     263             :         /* --------------------------------------------------------------------
     264             :          */
     265             :         /*      Wow, we got our desired feature. Return it. */
     266             :         /* --------------------------------------------------------------------
     267             :          */
     268           3 :         delete poNASFeature;
     269             : 
     270           3 :         return poOGRFeature;
     271           0 :     }
     272             : }
     273             : 
     274             : /************************************************************************/
     275             : /*                          GetFeatureCount()                           */
     276             : /************************************************************************/
     277             : 
     278           3 : GIntBig OGRNASLayer::GetFeatureCount(int bForce)
     279             : 
     280             : {
     281           3 :     if (poFClass == nullptr)
     282           0 :         return 0;
     283             : 
     284           3 :     if (m_poFilterGeom != nullptr || m_poAttrQuery != nullptr)
     285           0 :         return OGRLayer::GetFeatureCount(bForce);
     286             : 
     287           3 :     return poFClass->GetFeatureCount();
     288             : }
     289             : 
     290             : /************************************************************************/
     291             : /*                             IGetExtent()                             */
     292             : /************************************************************************/
     293             : 
     294           0 : OGRErr OGRNASLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
     295             :                                bool bForce)
     296             : 
     297             : {
     298           0 :     double dfXMin = 0.0;
     299           0 :     double dfXMax = 0.0;
     300           0 :     double dfYMin = 0.0;
     301           0 :     double dfYMax = 0.0;
     302             : 
     303           0 :     if (poFClass != nullptr &&
     304           0 :         poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax))
     305             :     {
     306           0 :         psExtent->MinX = dfXMin;
     307           0 :         psExtent->MaxX = dfXMax;
     308           0 :         psExtent->MinY = dfYMin;
     309           0 :         psExtent->MaxY = dfYMax;
     310             : 
     311           0 :         return OGRERR_NONE;
     312             :     }
     313             : 
     314           0 :     return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
     315             : }
     316             : 
     317             : /************************************************************************/
     318             : /*                           TestCapability()                           */
     319             : /************************************************************************/
     320             : 
     321           0 : int OGRNASLayer::TestCapability(const char *pszCap) const
     322             : 
     323             : {
     324           0 :     if (EQUAL(pszCap, OLCFastGetExtent))
     325             :     {
     326           0 :         if (poFClass == nullptr)
     327           0 :             return FALSE;
     328             : 
     329           0 :         double dfXMin = 0.0;
     330           0 :         double dfXMax = 0.0;
     331           0 :         double dfYMin = 0.0;
     332           0 :         double dfYMax = 0.0;
     333             : 
     334           0 :         return poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax);
     335             :     }
     336             : 
     337           0 :     if (EQUAL(pszCap, OLCFastFeatureCount))
     338             :     {
     339           0 :         if (poFClass == nullptr || m_poFilterGeom != nullptr ||
     340           0 :             m_poAttrQuery != nullptr)
     341           0 :             return FALSE;
     342             : 
     343           0 :         return poFClass->GetFeatureCount() != -1;
     344             :     }
     345             : 
     346           0 :     if (EQUAL(pszCap, OLCStringsAsUTF8))
     347           0 :         return TRUE;
     348             : 
     349           0 :     return FALSE;
     350             : }

Generated by: LCOV version 1.14