LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/vrt - ogrvrtdatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 329 385 85.5 %
Date: 2026-01-20 17:06:23 Functions: 17 17 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRVRTDataSource class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2009-2014, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "ogr_vrt.h"
      16             : 
      17             : #include <stdlib.h>
      18             : #include <string.h>
      19             : #include <algorithm>
      20             : #include <set>
      21             : #include <string>
      22             : 
      23             : #include "cpl_conv.h"
      24             : #include "cpl_error.h"
      25             : #include "cpl_minixml.h"
      26             : #include "cpl_string.h"
      27             : #include "gdal_priv.h"
      28             : #include "ogr_core.h"
      29             : #include "ogr_feature.h"
      30             : #include "ogr_spatialref.h"
      31             : #include "ogrlayerpool.h"
      32             : #include "ogrunionlayer.h"
      33             : #include "ogrwarpedlayer.h"
      34             : #include "ogrsf_frmts.h"
      35             : #include "ogrvrtgeometrytypes.h"
      36             : 
      37             : /************************************************************************/
      38             : /*                          OGRVRTDataSource()                          */
      39             : /************************************************************************/
      40             : 
      41         403 : OGRVRTDataSource::OGRVRTDataSource(GDALDriver *poDriverIn)
      42             : {
      43         403 :     poDriver = poDriverIn;
      44         403 : }
      45             : 
      46             : /************************************************************************/
      47             : /*                         ~OGRVRTDataSource()                         */
      48             : /************************************************************************/
      49             : 
      50         806 : OGRVRTDataSource::~OGRVRTDataSource()
      51             : 
      52             : {
      53         403 :     OGRVRTDataSource::CloseDependentDatasets();
      54             : 
      55         403 :     CPLFree(paeLayerType);
      56             : 
      57         403 :     if (psTree != nullptr)
      58         403 :         CPLDestroyXMLNode(psTree);
      59         806 : }
      60             : 
      61             : /************************************************************************/
      62             : /*                        CloseDependentDatasets()                      */
      63             : /************************************************************************/
      64             : 
      65         403 : int OGRVRTDataSource::CloseDependentDatasets()
      66             : {
      67         403 :     const int bHasClosedDependentDatasets = nLayers > 0;
      68        1112 :     for (int i = 0; i < nLayers; i++)
      69             :     {
      70         709 :         delete papoLayers[i];
      71             :     }
      72         403 :     CPLFree(papoLayers);
      73         403 :     nLayers = 0;
      74         403 :     papoLayers = nullptr;
      75         403 :     return bHasClosedDependentDatasets;
      76             : }
      77             : 
      78             : /************************************************************************/
      79             : /*                        InstantiateWarpedLayer()                      */
      80             : /************************************************************************/
      81             : 
      82          21 : OGRLayer *OGRVRTDataSource::InstantiateWarpedLayer(CPLXMLNode *psLTree,
      83             :                                                    const char *pszVRTDirectory,
      84             :                                                    int bUpdate, int nRecLevel)
      85             : {
      86          21 :     if (!EQUAL(psLTree->pszValue, "OGRVRTWarpedLayer"))
      87           0 :         return nullptr;
      88             : 
      89          21 :     std::unique_ptr<OGRLayer> poSrcLayer;
      90             : 
      91          21 :     for (CPLXMLNode *psSubNode = psLTree->psChild; psSubNode != nullptr;
      92           0 :          psSubNode = psSubNode->psNext)
      93             :     {
      94          21 :         if (psSubNode->eType != CXT_Element)
      95           0 :             continue;
      96             : 
      97          21 :         poSrcLayer.reset(InstantiateLayer(psSubNode, pszVRTDirectory, bUpdate,
      98             :                                           nRecLevel + 1));
      99          21 :         if (poSrcLayer != nullptr)
     100          21 :             break;
     101             :     }
     102             : 
     103          21 :     if (poSrcLayer == nullptr)
     104             :     {
     105           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     106             :                  "Cannot instantiate source layer");
     107           0 :         return nullptr;
     108             :     }
     109             : 
     110          21 :     const char *pszTargetSRS = CPLGetXMLValue(psLTree, "TargetSRS", nullptr);
     111          21 :     if (pszTargetSRS == nullptr)
     112             :     {
     113           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     114             :                  "Missing TargetSRS element within OGRVRTWarpedLayer");
     115           1 :         return nullptr;
     116             :     }
     117             : 
     118             :     const char *pszGeomFieldName =
     119          20 :         CPLGetXMLValue(psLTree, "WarpedGeomFieldName", nullptr);
     120          20 :     int iGeomField = 0;
     121          20 :     if (pszGeomFieldName != nullptr)
     122             :     {
     123           3 :         iGeomField =
     124           3 :             poSrcLayer->GetLayerDefn()->GetGeomFieldIndex(pszGeomFieldName);
     125           3 :         if (iGeomField < 0)
     126             :         {
     127           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     128             :                      "Cannot find source geometry field '%s'",
     129             :                      pszGeomFieldName);
     130           1 :             return nullptr;
     131             :         }
     132             :     }
     133             : 
     134          19 :     std::unique_ptr<OGRSpatialReference> poSrcSRS;
     135          19 :     const char *pszSourceSRS = CPLGetXMLValue(psLTree, "SrcSRS", nullptr);
     136             : 
     137          19 :     if (pszSourceSRS == nullptr)
     138             :     {
     139          16 :         if (iGeomField < poSrcLayer->GetLayerDefn()->GetGeomFieldCount())
     140             :         {
     141          13 :             const auto *poSrcLayerSRS = poSrcLayer->GetLayerDefn()
     142          13 :                                             ->GetGeomFieldDefn(iGeomField)
     143          13 :                                             ->GetSpatialRef();
     144          13 :             if (poSrcLayerSRS)
     145          13 :                 poSrcSRS.reset(poSrcLayerSRS->Clone());
     146             :         }
     147             :     }
     148             :     else
     149             :     {
     150           3 :         poSrcSRS = std::make_unique<OGRSpatialReference>();
     151           3 :         poSrcSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     152           3 :         if (poSrcSRS->SetFromUserInput(
     153             :                 pszSourceSRS,
     154           3 :                 OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get()) !=
     155             :             OGRERR_NONE)
     156             :         {
     157           1 :             poSrcSRS.reset();
     158             :         }
     159             :     }
     160             : 
     161          19 :     if (poSrcSRS == nullptr)
     162             :     {
     163           4 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to import source SRS");
     164           4 :         return nullptr;
     165             :     }
     166             : 
     167          30 :     auto poTargetSRS = std::make_unique<OGRSpatialReference>();
     168          15 :     poTargetSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     169          15 :     if (poTargetSRS->SetFromUserInput(
     170             :             pszTargetSRS,
     171          15 :             OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get()) !=
     172             :         OGRERR_NONE)
     173             :     {
     174           1 :         poTargetSRS.reset();
     175             :     }
     176             : 
     177          15 :     if (poTargetSRS == nullptr)
     178             :     {
     179           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to import target SRS");
     180           1 :         return nullptr;
     181             :     }
     182             : 
     183          14 :     if (pszSourceSRS == nullptr && poSrcSRS->IsSame(poTargetSRS.get()))
     184             :     {
     185           1 :         return poSrcLayer.release();
     186             :     }
     187             : 
     188             :     std::unique_ptr<OGRCoordinateTransformation> poCT(
     189          26 :         OGRCreateCoordinateTransformation(poSrcSRS.get(), poTargetSRS.get()));
     190             :     std::unique_ptr<OGRCoordinateTransformation> poReversedCT(
     191          26 :         poCT != nullptr ? OGRCreateCoordinateTransformation(poTargetSRS.get(),
     192          13 :                                                             poSrcSRS.get())
     193          39 :                         : nullptr);
     194             : 
     195          13 :     if (poCT == nullptr)
     196             :     {
     197           0 :         return nullptr;
     198             :     }
     199             : 
     200             :     // Build the OGRWarpedLayer.
     201             :     auto poLayer = std::make_unique<OGRWarpedLayer>(
     202          13 :         poSrcLayer.release(), iGeomField, TRUE, std::move(poCT),
     203          26 :         std::move(poReversedCT));
     204             : 
     205             :     // Set Extent if provided.
     206          13 :     const char *pszExtentXMin = CPLGetXMLValue(psLTree, "ExtentXMin", nullptr);
     207          13 :     const char *pszExtentYMin = CPLGetXMLValue(psLTree, "ExtentYMin", nullptr);
     208          13 :     const char *pszExtentXMax = CPLGetXMLValue(psLTree, "ExtentXMax", nullptr);
     209          13 :     const char *pszExtentYMax = CPLGetXMLValue(psLTree, "ExtentYMax", nullptr);
     210          13 :     if (pszExtentXMin != nullptr && pszExtentYMin != nullptr &&
     211           1 :         pszExtentXMax != nullptr && pszExtentYMax != nullptr)
     212             :     {
     213           1 :         poLayer->SetExtent(CPLAtof(pszExtentXMin), CPLAtof(pszExtentYMin),
     214             :                            CPLAtof(pszExtentXMax), CPLAtof(pszExtentYMax));
     215             :     }
     216             : 
     217          13 :     return poLayer.release();
     218             : }
     219             : 
     220             : /************************************************************************/
     221             : /*                        InstantiateUnionLayer()                       */
     222             : /************************************************************************/
     223             : 
     224          85 : OGRLayer *OGRVRTDataSource::InstantiateUnionLayer(CPLXMLNode *psLTree,
     225             :                                                   const char *pszVRTDirectory,
     226             :                                                   int bUpdate, int nRecLevel)
     227             : {
     228          85 :     if (!EQUAL(psLTree->pszValue, "OGRVRTUnionLayer"))
     229           0 :         return nullptr;
     230             : 
     231             :     // Get layer name.
     232          85 :     const char *pszLayerName = CPLGetXMLValue(psLTree, "name", nullptr);
     233             : 
     234          85 :     if (pszLayerName == nullptr)
     235             :     {
     236           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     237             :                  "Missing name attribute on OGRVRTUnionLayer");
     238           0 :         return nullptr;
     239             :     }
     240             : 
     241             :     // Do we have a fixed geometry type?  If not derive from the
     242             :     // source layer.
     243          85 :     const char *pszGType = CPLGetXMLValue(psLTree, "GeometryType", nullptr);
     244          85 :     bool bGlobalGeomTypeSet = false;
     245          85 :     OGRwkbGeometryType eGlobalGeomType = wkbUnknown;
     246          85 :     if (pszGType != nullptr)
     247             :     {
     248          12 :         bGlobalGeomTypeSet = true;
     249          12 :         int bError = FALSE;
     250          12 :         eGlobalGeomType = OGRVRTGetGeometryType(pszGType, &bError);
     251          12 :         if (bError)
     252             :         {
     253           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     254             :                      "GeometryType %s not recognised.", pszGType);
     255           0 :             return nullptr;
     256             :         }
     257             :     }
     258             : 
     259             :     // Apply a spatial reference system if provided.
     260          85 :     const char *pszLayerSRS = CPLGetXMLValue(psLTree, "LayerSRS", nullptr);
     261          85 :     OGRSpatialReference *poGlobalSRS = nullptr;
     262          85 :     bool bGlobalSRSSet = false;
     263          85 :     if (pszLayerSRS != nullptr)
     264             :     {
     265           9 :         bGlobalSRSSet = true;
     266           9 :         if (!EQUAL(pszLayerSRS, "NULL"))
     267             :         {
     268           9 :             OGRSpatialReference oSRS;
     269           9 :             oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     270             : 
     271           9 :             if (oSRS.SetFromUserInput(
     272             :                     pszLayerSRS,
     273             :                     OGRSpatialReference::
     274           9 :                         SET_FROM_USER_INPUT_LIMITATIONS_get()) != OGRERR_NONE)
     275             :             {
     276           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     277             :                          "Failed to import LayerSRS `%s'.", pszLayerSRS);
     278           0 :                 return nullptr;
     279             :             }
     280           9 :             poGlobalSRS = oSRS.Clone();
     281             :         }
     282             :     }
     283             : 
     284             :     // Find field declarations.
     285         170 :     std::vector<OGRFieldDefn> aoFields;
     286         170 :     std::vector<OGRUnionLayerGeomFieldDefn> aoGeomFields;
     287             : 
     288         448 :     for (CPLXMLNode *psSubNode = psLTree->psChild; psSubNode != nullptr;
     289         363 :          psSubNode = psSubNode->psNext)
     290             :     {
     291         363 :         if (psSubNode->eType != CXT_Element)
     292          85 :             continue;
     293             : 
     294         278 :         if (EQUAL(psSubNode->pszValue, "Field"))
     295             :         {
     296             :             // Field name.
     297           0 :             const char *l_pszName = CPLGetXMLValue(psSubNode, "name", nullptr);
     298           0 :             if (l_pszName == nullptr)
     299             :             {
     300           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     301             :                          "Unable to identify Field name.");
     302           0 :                 break;
     303             :             }
     304             : 
     305           0 :             OGRFieldDefn oFieldDefn(l_pszName, OFTString);
     306             : 
     307             :             // Type.
     308           0 :             const char *pszArg = CPLGetXMLValue(psSubNode, "type", nullptr);
     309             : 
     310           0 :             if (pszArg != nullptr)
     311             :             {
     312           0 :                 int iType = 0;  // Used after for.
     313             : 
     314           0 :                 for (; iType <= static_cast<int>(OFTMaxType); iType++)
     315             :                 {
     316           0 :                     if (EQUAL(pszArg, OGRFieldDefn::GetFieldTypeName(
     317             :                                           static_cast<OGRFieldType>(iType))))
     318             :                     {
     319           0 :                         oFieldDefn.SetType(static_cast<OGRFieldType>(iType));
     320           0 :                         break;
     321             :                     }
     322             :                 }
     323             : 
     324           0 :                 if (iType > static_cast<int>(OFTMaxType))
     325             :                 {
     326           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     327             :                              "Unable to identify Field type '%s'.", pszArg);
     328           0 :                     break;
     329             :                 }
     330             :             }
     331             : 
     332             :             // Width and precision.
     333           0 :             const int nWidth = atoi(CPLGetXMLValue(psSubNode, "width", "0"));
     334           0 :             if (nWidth < 0)
     335             :             {
     336           0 :                 CPLError(CE_Failure, CPLE_IllegalArg,
     337             :                          "Invalid width for field %s.", l_pszName);
     338           0 :                 break;
     339             :             }
     340           0 :             oFieldDefn.SetWidth(nWidth);
     341             : 
     342             :             const int nPrecision =
     343           0 :                 atoi(CPLGetXMLValue(psSubNode, "precision", "0"));
     344           0 :             if (nPrecision < 0 || nPrecision > 1024)
     345             :             {
     346           0 :                 CPLError(CE_Failure, CPLE_IllegalArg,
     347             :                          "Invalid precision for field %s.", l_pszName);
     348           0 :                 break;
     349             :             }
     350           0 :             oFieldDefn.SetPrecision(nPrecision);
     351             : 
     352           0 :             aoFields.emplace_back(&oFieldDefn);
     353             :         }
     354         278 :         else if (EQUAL(psSubNode->pszValue, "GeometryField"))
     355             :         {
     356          12 :             const char *l_pszName = CPLGetXMLValue(psSubNode, "name", nullptr);
     357          12 :             if (l_pszName == nullptr)
     358             :             {
     359           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     360             :                          "Unable to identify GeometryField name.");
     361           0 :                 break;
     362             :             }
     363             : 
     364          12 :             pszGType = CPLGetXMLValue(psSubNode, "GeometryType", nullptr);
     365          12 :             if (pszGType == nullptr && aoGeomFields.empty())
     366           3 :                 pszGType = CPLGetXMLValue(psLTree, "GeometryType", nullptr);
     367          12 :             OGRwkbGeometryType eGeomType = wkbUnknown;
     368          12 :             bool bGeomTypeSet = false;
     369          12 :             if (pszGType != nullptr)
     370             :             {
     371           3 :                 int bError = FALSE;
     372           3 :                 eGeomType = OGRVRTGetGeometryType(pszGType, &bError);
     373           3 :                 bGeomTypeSet = true;
     374           3 :                 if (bError || eGeomType == wkbNone)
     375             :                 {
     376           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     377             :                              "GeometryType %s not recognised.", pszGType);
     378           0 :                     break;
     379             :                 }
     380             :             }
     381             : 
     382          12 :             const char *pszSRS = CPLGetXMLValue(psSubNode, "SRS", nullptr);
     383          12 :             if (pszSRS == nullptr && aoGeomFields.empty())
     384           6 :                 pszSRS = CPLGetXMLValue(psLTree, "LayerSRS", nullptr);
     385          12 :             OGRSpatialReference *poSRS = nullptr;
     386          12 :             bool bSRSSet = false;
     387          12 :             if (pszSRS != nullptr)
     388             :             {
     389           3 :                 bSRSSet = true;
     390           3 :                 if (!EQUAL(pszSRS, "NULL"))
     391             :                 {
     392           3 :                     OGRSpatialReference oSRS;
     393           3 :                     oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     394             : 
     395           3 :                     if (oSRS.SetFromUserInput(
     396             :                             pszSRS,
     397             :                             OGRSpatialReference::
     398           3 :                                 SET_FROM_USER_INPUT_LIMITATIONS_get()) !=
     399             :                         OGRERR_NONE)
     400             :                     {
     401           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     402             :                                  "Failed to import SRS `%s'.", pszSRS);
     403           0 :                         break;
     404             :                     }
     405           3 :                     poSRS = oSRS.Clone();
     406             :                 }
     407             :             }
     408             : 
     409          12 :             aoGeomFields.emplace_back(l_pszName, eGeomType);
     410          12 :             OGRUnionLayerGeomFieldDefn &oFieldDefn = aoGeomFields.back();
     411          12 :             if (poSRS != nullptr)
     412             :             {
     413           3 :                 oFieldDefn.SetSpatialRef(poSRS);
     414           3 :                 poSRS->Dereference();
     415             :             }
     416          12 :             oFieldDefn.bGeomTypeSet = bGeomTypeSet;
     417          12 :             oFieldDefn.bSRSSet = bSRSSet;
     418             : 
     419             :             const char *pszExtentXMin =
     420          12 :                 CPLGetXMLValue(psSubNode, "ExtentXMin", nullptr);
     421             :             const char *pszExtentYMin =
     422          12 :                 CPLGetXMLValue(psSubNode, "ExtentYMin", nullptr);
     423             :             const char *pszExtentXMax =
     424          12 :                 CPLGetXMLValue(psSubNode, "ExtentXMax", nullptr);
     425             :             const char *pszExtentYMax =
     426          12 :                 CPLGetXMLValue(psSubNode, "ExtentYMax", nullptr);
     427          12 :             if (pszExtentXMin != nullptr && pszExtentYMin != nullptr &&
     428           3 :                 pszExtentXMax != nullptr && pszExtentYMax != nullptr)
     429             :             {
     430           3 :                 oFieldDefn.sStaticEnvelope.MinX = CPLAtof(pszExtentXMin);
     431           3 :                 oFieldDefn.sStaticEnvelope.MinY = CPLAtof(pszExtentYMin);
     432           3 :                 oFieldDefn.sStaticEnvelope.MaxX = CPLAtof(pszExtentXMax);
     433           3 :                 oFieldDefn.sStaticEnvelope.MaxY = CPLAtof(pszExtentYMax);
     434             :             }
     435             :         }
     436             :     }
     437             : 
     438             :     // Set Extent if provided.
     439          85 :     const char *pszExtentXMin = CPLGetXMLValue(psLTree, "ExtentXMin", nullptr);
     440          85 :     const char *pszExtentYMin = CPLGetXMLValue(psLTree, "ExtentYMin", nullptr);
     441          85 :     const char *pszExtentXMax = CPLGetXMLValue(psLTree, "ExtentXMax", nullptr);
     442          85 :     const char *pszExtentYMax = CPLGetXMLValue(psLTree, "ExtentYMax", nullptr);
     443             : 
     444         152 :     if (eGlobalGeomType != wkbNone && aoGeomFields.empty() &&
     445          67 :         (bGlobalGeomTypeSet || bGlobalSRSSet ||
     446           0 :          (pszExtentXMin != nullptr && pszExtentYMin != nullptr &&
     447           0 :           pszExtentXMax != nullptr && pszExtentYMax != nullptr)))
     448             :     {
     449           9 :         aoGeomFields.emplace_back("", eGlobalGeomType);
     450           9 :         auto &oFieldDefn = aoGeomFields.back();
     451           9 :         if (poGlobalSRS != nullptr)
     452             :         {
     453           9 :             oFieldDefn.SetSpatialRef(poGlobalSRS);
     454           9 :             poGlobalSRS->Dereference();
     455           9 :             poGlobalSRS = nullptr;
     456             :         }
     457           9 :         oFieldDefn.bGeomTypeSet = bGlobalGeomTypeSet;
     458           9 :         oFieldDefn.bSRSSet = bGlobalSRSSet;
     459           9 :         if (pszExtentXMin != nullptr && pszExtentYMin != nullptr &&
     460           9 :             pszExtentXMax != nullptr && pszExtentYMax != nullptr)
     461             :         {
     462           9 :             oFieldDefn.sStaticEnvelope.MinX = CPLAtof(pszExtentXMin);
     463           9 :             oFieldDefn.sStaticEnvelope.MinY = CPLAtof(pszExtentYMin);
     464           9 :             oFieldDefn.sStaticEnvelope.MaxX = CPLAtof(pszExtentXMax);
     465           9 :             oFieldDefn.sStaticEnvelope.MaxY = CPLAtof(pszExtentYMax);
     466             :         }
     467             :     }
     468             :     else
     469             :     {
     470          76 :         delete poGlobalSRS;
     471          76 :         poGlobalSRS = nullptr;
     472             :     }
     473             : 
     474             :     // Find source layers.
     475          85 :     int nSrcLayers = 0;
     476          85 :     OGRLayer **papoSrcLayers = nullptr;
     477             : 
     478         448 :     for (CPLXMLNode *psSubNode = psLTree->psChild; psSubNode != nullptr;
     479         363 :          psSubNode = psSubNode->psNext)
     480             :     {
     481         363 :         if (psSubNode->eType != CXT_Element)
     482          85 :             continue;
     483             : 
     484         278 :         OGRLayer *poSrcLayer = InstantiateLayer(psSubNode, pszVRTDirectory,
     485             :                                                 bUpdate, nRecLevel + 1);
     486         278 :         if (poSrcLayer != nullptr)
     487             :         {
     488         332 :             papoSrcLayers = static_cast<OGRLayer **>(CPLRealloc(
     489         166 :                 papoSrcLayers, sizeof(OGRLayer *) * (nSrcLayers + 1)));
     490         166 :             papoSrcLayers[nSrcLayers] = poSrcLayer;
     491         166 :             nSrcLayers++;
     492             :         }
     493             :     }
     494             : 
     495          85 :     if (nSrcLayers == 0)
     496             :     {
     497           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find source layers");
     498           0 :         return nullptr;
     499             :     }
     500             : 
     501             :     // Build the OGRUnionLayer.
     502             :     OGRUnionLayer *poLayer =
     503          85 :         new OGRUnionLayer(pszLayerName, nSrcLayers, papoSrcLayers, TRUE);
     504             : 
     505             :     // Set the source layer field name attribute.
     506             :     const char *pszSourceLayerFieldName =
     507          85 :         CPLGetXMLValue(psLTree, "SourceLayerFieldName", nullptr);
     508          85 :     poLayer->SetSourceLayerFieldName(pszSourceLayerFieldName);
     509             : 
     510             :     // Set the PreserveSrcFID attribute.
     511          85 :     bool bPreserveSrcFID = false;
     512             :     const char *pszPreserveFID =
     513          85 :         CPLGetXMLValue(psLTree, "PreserveSrcFID", nullptr);
     514          85 :     if (pszPreserveFID != nullptr)
     515           9 :         bPreserveSrcFID = CPLTestBool(pszPreserveFID);
     516          85 :     poLayer->SetPreserveSrcFID(bPreserveSrcFID);
     517             : 
     518             :     // Set fields.
     519          85 :     FieldUnionStrategy eFieldStrategy = FIELD_UNION_ALL_LAYERS;
     520             :     const char *pszFieldStrategy =
     521          85 :         CPLGetXMLValue(psLTree, "FieldStrategy", nullptr);
     522          85 :     if (pszFieldStrategy != nullptr)
     523             :     {
     524          15 :         if (EQUAL(pszFieldStrategy, "FirstLayer"))
     525           3 :             eFieldStrategy = FIELD_FROM_FIRST_LAYER;
     526          12 :         else if (EQUAL(pszFieldStrategy, "Union"))
     527           0 :             eFieldStrategy = FIELD_UNION_ALL_LAYERS;
     528          12 :         else if (EQUAL(pszFieldStrategy, "Intersection"))
     529          12 :             eFieldStrategy = FIELD_INTERSECTION_ALL_LAYERS;
     530             :         else
     531             :         {
     532           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     533             :                      "Unhandled value for FieldStrategy `%s'.",
     534             :                      pszFieldStrategy);
     535             :         }
     536             :     }
     537          85 :     if (!aoFields.empty() || aoGeomFields.size() > 1)
     538             :     {
     539           6 :         if (pszFieldStrategy != nullptr)
     540           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     541             :                      "Ignoring FieldStrategy value, "
     542             :                      "because explicit Field or GeometryField is provided");
     543           6 :         eFieldStrategy = FIELD_SPECIFIED;
     544             :     }
     545             : 
     546         170 :     poLayer->SetFields(eFieldStrategy, static_cast<int>(aoFields.size()),
     547          85 :                        aoFields.data(),
     548          85 :                        (aoGeomFields.empty() && eGlobalGeomType == wkbNone)
     549             :                            ? -1
     550          82 :                            : static_cast<int>(aoGeomFields.size()),
     551          85 :                        aoGeomFields.data());
     552             : 
     553             :     // Set FeatureCount if provided.
     554             :     const char *pszFeatureCount =
     555          85 :         CPLGetXMLValue(psLTree, "FeatureCount", nullptr);
     556          85 :     if (pszFeatureCount != nullptr)
     557             :     {
     558           9 :         poLayer->SetFeatureCount(atoi(pszFeatureCount));
     559             :     }
     560             : 
     561          85 :     return poLayer;
     562             : }
     563             : 
     564             : /************************************************************************/
     565             : /*                     InstantiateLayerInternal()                       */
     566             : /************************************************************************/
     567             : 
     568             : OGRLayer *
     569        1134 : OGRVRTDataSource::InstantiateLayerInternal(CPLXMLNode *psLTree,
     570             :                                            const char *pszVRTDirectory,
     571             :                                            int bUpdate, int nRecLevel)
     572             : {
     573             :     // Create the layer object.
     574        1134 :     if (EQUAL(psLTree->pszValue, "OGRVRTLayer"))
     575             :     {
     576         910 :         OGRVRTLayer *poVRTLayer = new OGRVRTLayer(this);
     577             : 
     578         910 :         if (!poVRTLayer->FastInitialize(psLTree, pszVRTDirectory, bUpdate))
     579             :         {
     580           3 :             delete poVRTLayer;
     581           3 :             return nullptr;
     582             :         }
     583             : 
     584         907 :         return poVRTLayer;
     585             :     }
     586         224 :     else if (EQUAL(psLTree->pszValue, "OGRVRTWarpedLayer") && nRecLevel < 30)
     587             :     {
     588          21 :         return InstantiateWarpedLayer(psLTree, pszVRTDirectory, bUpdate,
     589          21 :                                       nRecLevel + 1);
     590             :     }
     591         203 :     else if (EQUAL(psLTree->pszValue, "OGRVRTUnionLayer") && nRecLevel < 30)
     592             :     {
     593          85 :         return InstantiateUnionLayer(psLTree, pszVRTDirectory, bUpdate,
     594          85 :                                      nRecLevel + 1);
     595             :     }
     596             : 
     597         118 :     return nullptr;
     598             : }
     599             : 
     600             : /************************************************************************/
     601             : /*                        OGRVRTOpenProxiedLayer()                      */
     602             : /************************************************************************/
     603             : 
     604             : struct PooledInitData
     605             : {
     606             :     OGRVRTDataSource *poDS = nullptr;
     607             :     CPLXMLNode *psNode = nullptr;
     608             :     std::string osVRTDirectory{};
     609             :     bool bUpdate = false;
     610             : };
     611             : 
     612         114 : static OGRLayer *OGRVRTOpenProxiedLayer(void *pUserData)
     613             : {
     614         114 :     const PooledInitData *pData =
     615             :         static_cast<const PooledInitData *>(pUserData);
     616         342 :     return pData->poDS->InstantiateLayerInternal(
     617         114 :         pData->psNode, pData->osVRTDirectory.c_str(), pData->bUpdate, 0);
     618             : }
     619             : 
     620             : /************************************************************************/
     621             : /*                     OGRVRTFreeProxiedLayerUserData()                 */
     622             : /************************************************************************/
     623             : 
     624           4 : static void OGRVRTFreeProxiedLayerUserData(void *pUserData)
     625             : {
     626           4 :     delete static_cast<PooledInitData *>(pUserData);
     627           4 : }
     628             : 
     629             : /************************************************************************/
     630             : /*                          InstantiateLayer()                          */
     631             : /************************************************************************/
     632             : 
     633        1024 : OGRLayer *OGRVRTDataSource::InstantiateLayer(CPLXMLNode *psLTree,
     634             :                                              const char *pszVRTDirectory,
     635             :                                              int bUpdate, int nRecLevel)
     636             : {
     637        1024 :     if (poLayerPool != nullptr && EQUAL(psLTree->pszValue, "OGRVRTLayer"))
     638             :     {
     639           4 :         auto pData = std::make_unique<PooledInitData>();
     640           4 :         pData->poDS = this;
     641           4 :         pData->psNode = psLTree;
     642           4 :         pData->osVRTDirectory = pszVRTDirectory ? pszVRTDirectory : "";
     643           4 :         pData->bUpdate = CPL_TO_BOOL(bUpdate);
     644           4 :         return new OGRProxiedLayer(poLayerPool.get(), OGRVRTOpenProxiedLayer,
     645             :                                    OGRVRTFreeProxiedLayerUserData,
     646           4 :                                    pData.release());
     647             :     }
     648             : 
     649        1020 :     return InstantiateLayerInternal(psLTree, pszVRTDirectory, bUpdate,
     650        1020 :                                     nRecLevel);
     651             : }
     652             : 
     653             : /************************************************************************/
     654             : /*                           CountOGRVRTLayers()                        */
     655             : /************************************************************************/
     656             : 
     657        9239 : static int CountOGRVRTLayers(const CPLXMLNode *psTree)
     658             : {
     659        9239 :     if (psTree->eType != CXT_Element)
     660        5088 :         return 0;
     661             : 
     662        4151 :     int nCount = 0;
     663        4151 :     if (EQUAL(psTree->pszValue, "OGRVRTLayer"))
     664         800 :         ++nCount;
     665             : 
     666       12988 :     for (const CPLXMLNode *psNode = psTree->psChild; psNode != nullptr;
     667        8837 :          psNode = psNode->psNext)
     668             :     {
     669        8837 :         nCount += CountOGRVRTLayers(psNode);
     670             :     }
     671             : 
     672        4151 :     return nCount;
     673             : }
     674             : 
     675             : /************************************************************************/
     676             : /*                             Initialize()                             */
     677             : /************************************************************************/
     678             : 
     679         403 : bool OGRVRTDataSource::Initialize(CPLXMLNode *psTreeIn, const char *pszNewName,
     680             :                                   int bUpdate)
     681             : 
     682             : {
     683         403 :     CPLAssert(nLayers == 0);
     684             : 
     685         403 :     AddForbiddenNames(pszNewName);
     686             : 
     687         403 :     psTree = psTreeIn;
     688             : 
     689             :     // Set name, and capture the directory path so we can use it
     690             :     // for relative datasources.
     691         806 :     CPLString osVRTDirectory = CPLGetPathSafe(pszNewName);
     692             : 
     693             :     // Look for the OGRVRTDataSource node, it might be after an <xml> node.
     694         403 :     CPLXMLNode *psVRTDSXML = CPLGetXMLNode(psTree, "=OGRVRTDataSource");
     695         403 :     if (psVRTDSXML == nullptr)
     696             :     {
     697           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     698             :                  "Did not find the <OGRVRTDataSource> node in the root of the "
     699             :                  "document, this is not really an OGR VRT.");
     700           1 :         return false;
     701             :     }
     702             : 
     703             :     // Determine if we must proxy layers.
     704         402 :     const int nOGRVRTLayerCount = CountOGRVRTLayers(psVRTDSXML);
     705             : 
     706             :     const int nMaxSimultaneouslyOpened =
     707         402 :         std::max(atoi(CPLGetConfigOption("OGR_VRT_MAX_OPENED", "100")), 1);
     708         402 :     if (nOGRVRTLayerCount > nMaxSimultaneouslyOpened)
     709           2 :         poLayerPool = std::make_unique<OGRLayerPool>(nMaxSimultaneouslyOpened);
     710             : 
     711             :     // Apply any dataset level metadata.
     712         402 :     oMDMD.XMLInit(psVRTDSXML, TRUE);
     713             : 
     714             :     // Look for layers.
     715        1128 :     for (CPLXMLNode *psLTree = psVRTDSXML->psChild; psLTree != nullptr;
     716         726 :          psLTree = psLTree->psNext)
     717             :     {
     718         726 :         if (psLTree->eType != CXT_Element)
     719           1 :             continue;
     720             : 
     721             :         // Create the layer object.
     722         725 :         OGRLayer *poLayer = InstantiateLayer(psLTree, osVRTDirectory, bUpdate);
     723         725 :         if (poLayer == nullptr)
     724          16 :             continue;
     725             : 
     726             :         // Add layer to data source layer list.
     727         709 :         nLayers++;
     728         709 :         papoLayers = static_cast<OGRLayer **>(
     729         709 :             CPLRealloc(papoLayers, sizeof(OGRLayer *) * nLayers));
     730         709 :         papoLayers[nLayers - 1] = poLayer;
     731             : 
     732         709 :         paeLayerType = static_cast<OGRLayerType *>(
     733         709 :             CPLRealloc(paeLayerType, sizeof(int) * nLayers));
     734         709 :         if (poLayerPool != nullptr && EQUAL(psLTree->pszValue, "OGRVRTLayer"))
     735             :         {
     736           0 :             paeLayerType[nLayers - 1] = OGR_VRT_PROXIED_LAYER;
     737             :         }
     738         709 :         else if (EQUAL(psLTree->pszValue, "OGRVRTLayer"))
     739             :         {
     740         611 :             paeLayerType[nLayers - 1] = OGR_VRT_LAYER;
     741             :         }
     742             :         else
     743             :         {
     744          98 :             paeLayerType[nLayers - 1] = OGR_VRT_OTHER_LAYER;
     745             :         }
     746             :     }
     747             : 
     748         402 :     return true;
     749             : }
     750             : 
     751             : /************************************************************************/
     752             : /*                           TestCapability()                           */
     753             : /************************************************************************/
     754             : 
     755         139 : int OGRVRTDataSource::TestCapability(const char *pszCap) const
     756             : {
     757         139 :     if (EQUAL(pszCap, ODsCCurveGeometries))
     758          29 :         return true;
     759         110 :     else if (EQUAL(pszCap, ODsCZGeometries))
     760          24 :         return true;
     761          86 :     else if (EQUAL(pszCap, ODsCMeasuredGeometries))
     762          24 :         return true;
     763             : 
     764          62 :     return false;
     765             : }
     766             : 
     767             : /************************************************************************/
     768             : /*                              GetLayer()                              */
     769             : /************************************************************************/
     770             : 
     771         897 : const OGRLayer *OGRVRTDataSource::GetLayer(int iLayer) const
     772             : 
     773             : {
     774         897 :     if (iLayer < 0 || iLayer >= nLayers)
     775          32 :         return nullptr;
     776             : 
     777         865 :     return papoLayers[iLayer];
     778             : }
     779             : 
     780             : /************************************************************************/
     781             : /*                         AddForbiddenNames()                          */
     782             : /************************************************************************/
     783             : 
     784         406 : void OGRVRTDataSource::AddForbiddenNames(const char *pszOtherDSName)
     785             : {
     786         406 :     aosOtherDSNameSet.insert(pszOtherDSName);
     787         406 : }
     788             : 
     789             : /************************************************************************/
     790             : /*                         IsInForbiddenNames()                         */
     791             : /************************************************************************/
     792             : 
     793          78 : bool OGRVRTDataSource::IsInForbiddenNames(const char *pszOtherDSName) const
     794             : {
     795          78 :     return aosOtherDSNameSet.find(pszOtherDSName) != aosOtherDSNameSet.end();
     796             : }
     797             : 
     798             : /************************************************************************/
     799             : /*                             GetFileList()                             */
     800             : /************************************************************************/
     801             : 
     802          16 : char **OGRVRTDataSource::GetFileList()
     803             : {
     804          32 :     CPLStringList oList;
     805          16 :     oList.AddString(GetDescription());
     806          32 :     for (int i = 0; i < nLayers; i++)
     807             :     {
     808          16 :         OGRLayer *poLayer = papoLayers[i];
     809          16 :         OGRVRTLayer *poVRTLayer = nullptr;
     810          16 :         switch (paeLayerType[nLayers - 1])
     811             :         {
     812           0 :             case OGR_VRT_PROXIED_LAYER:
     813           0 :                 poVRTLayer = cpl::down_cast<OGRVRTLayer *>(
     814             :                     cpl::down_cast<OGRProxiedLayer *>(poLayer)
     815             :                         ->GetUnderlyingLayer());
     816           0 :                 break;
     817           7 :             case OGR_VRT_LAYER:
     818           7 :                 poVRTLayer = cpl::down_cast<OGRVRTLayer *>(poLayer);
     819           7 :                 break;
     820           9 :             default:
     821           9 :                 break;
     822             :         }
     823          16 :         if (poVRTLayer != nullptr)
     824             :         {
     825           7 :             GDALDataset *poSrcDS = poVRTLayer->GetSrcDataset();
     826           7 :             if (poSrcDS != nullptr)
     827             :             {
     828           7 :                 char **papszFileList = poSrcDS->GetFileList();
     829           7 :                 char **papszIter = papszFileList;
     830          35 :                 for (; papszIter != nullptr && *papszIter != nullptr;
     831             :                      papszIter++)
     832             :                 {
     833          28 :                     if (oList.FindString(*papszIter) < 0)
     834          28 :                         oList.AddString(*papszIter);
     835             :                 }
     836           7 :                 CSLDestroy(papszFileList);
     837             :             }
     838             :         }
     839             :     }
     840          32 :     return oList.StealList();
     841             : }

Generated by: LCOV version 1.14