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

Generated by: LCOV version 1.14