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

Generated by: LCOV version 1.14