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

Generated by: LCOV version 1.14