LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_output_abstract.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 72 84 85.7 %
Date: 2025-06-19 12:30:01 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Class to abstract outputting to a vector layer
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdalalg_vector_output_abstract.h"
      14             : 
      15             : #include "cpl_vsi.h"
      16             : #include "ogrsf_frmts.h"
      17             : 
      18             : //! @cond Doxygen_Suppress
      19             : 
      20             : #ifndef _
      21             : #define _(x) (x)
      22             : #endif
      23             : 
      24             : GDALVectorOutputAbstractAlgorithm::~GDALVectorOutputAbstractAlgorithm() =
      25             :     default;
      26             : 
      27             : /************************************************************************/
      28             : /*      GDALVectorOutputAbstractAlgorithm::AddAllOutputArgs()           */
      29             : /************************************************************************/
      30             : 
      31          82 : void GDALVectorOutputAbstractAlgorithm::AddAllOutputArgs()
      32             : {
      33          82 :     AddOutputFormatArg(&m_outputFormat)
      34             :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
      35         246 :                          {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE});
      36          82 :     AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR)
      37          82 :         .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
      38          82 :     AddCreationOptionsArg(&m_creationOptions);
      39          82 :     AddLayerCreationOptionsArg(&m_layerCreationOptions);
      40          82 :     AddOverwriteArg(&m_overwrite).SetMutualExclusionGroup("overwrite-update");
      41             :     auto &updateArg =
      42          82 :         AddUpdateArg(&m_update).SetMutualExclusionGroup("overwrite-update");
      43          82 :     AddOverwriteLayerArg(&m_overwriteLayer);
      44             :     AddArg("append", 0, _("Whether appending to existing layer is allowed"),
      45         164 :            &m_appendLayer)
      46          82 :         .SetDefault(false)
      47          92 :         .AddAction([&updateArg] { updateArg.Set(true); });
      48             :     {
      49          82 :         auto &arg = AddLayerNameArg(&m_outputLayerName)
      50         164 :                         .AddAlias("nln")
      51          82 :                         .SetMinCharCount(0);
      52          82 :         if (!m_outputLayerName.empty())
      53           0 :             arg.SetDefault(m_outputLayerName);
      54             :     }
      55          82 : }
      56             : 
      57             : /************************************************************************/
      58             : /*         GDALVectorOutputAbstractAlgorithm::SetupOutputDataset()      */
      59             : /************************************************************************/
      60             : 
      61             : GDALVectorOutputAbstractAlgorithm::SetupOutputDatasetRet
      62          58 : GDALVectorOutputAbstractAlgorithm::SetupOutputDataset()
      63             : {
      64          58 :     SetupOutputDatasetRet ret;
      65             : 
      66          58 :     GDALDataset *poDstDS = m_outputDataset.GetDatasetRef();
      67          58 :     std::unique_ptr<GDALDataset> poRetDS;
      68          58 :     if (!poDstDS)
      69             :     {
      70          46 :         if (m_outputFormat.empty())
      71             :         {
      72             :             const auto aosFormats =
      73             :                 CPLStringList(GDALGetOutputDriversForDatasetName(
      74          15 :                     m_outputDataset.GetName().c_str(), GDAL_OF_VECTOR,
      75             :                     /* bSingleMatch = */ true,
      76          15 :                     /* bWarn = */ true));
      77          15 :             if (aosFormats.size() != 1)
      78             :             {
      79           0 :                 ReportError(CE_Failure, CPLE_AppDefined,
      80             :                             "Cannot guess driver for %s",
      81           0 :                             m_outputDataset.GetName().c_str());
      82           0 :                 return ret;
      83             :             }
      84          15 :             m_outputFormat = aosFormats[0];
      85             :         }
      86             : 
      87             :         auto poDriver =
      88          46 :             GetGDALDriverManager()->GetDriverByName(m_outputFormat.c_str());
      89          46 :         if (!poDriver)
      90             :         {
      91             :             // shouldn't happen given checks done in GDALAlgorithm
      92           0 :             ReportError(CE_Failure, CPLE_AppDefined, "Cannot find driver %s",
      93             :                         m_outputFormat.c_str());
      94           0 :             return ret;
      95             :         }
      96             : 
      97          46 :         poRetDS.reset(poDriver->Create(
      98          46 :             m_outputDataset.GetName().c_str(), 0, 0, 0, GDT_Unknown,
      99          92 :             CPLStringList(m_creationOptions).List()));
     100          46 :         if (!poRetDS)
     101           0 :             return ret;
     102             : 
     103          46 :         poDstDS = poRetDS.get();
     104             :     }
     105             : 
     106          58 :     auto poDstDriver = poDstDS->GetDriver();
     107          58 :     if (poDstDriver && EQUAL(poDstDriver->GetDescription(), "ESRI Shapefile") &&
     108         135 :         EQUAL(CPLGetExtensionSafe(poDstDS->GetDescription()).c_str(), "shp") &&
     109          19 :         poDstDS->GetLayerCount() <= 1)
     110             :     {
     111          19 :         m_outputLayerName = CPLGetBasenameSafe(poDstDS->GetDescription());
     112             :     }
     113          58 :     if (m_outputLayerName.empty() && poDstDS->GetLayerCount() == 1)
     114           6 :         m_outputLayerName = poDstDS->GetLayer(0)->GetDescription();
     115             : 
     116          58 :     auto poDstLayer = m_outputLayerName.empty()
     117          58 :                           ? nullptr
     118          35 :                           : poDstDS->GetLayerByName(m_outputLayerName.c_str());
     119          58 :     if (poDstLayer)
     120             :     {
     121          12 :         if (m_overwriteLayer)
     122             :         {
     123           1 :             int iLayer = -1;
     124           1 :             const int nLayerCount = poDstDS->GetLayerCount();
     125           1 :             for (iLayer = 0; iLayer < nLayerCount; iLayer++)
     126             :             {
     127           1 :                 if (poDstDS->GetLayer(iLayer) == poDstLayer)
     128           1 :                     break;
     129             :             }
     130             : 
     131           1 :             if (iLayer < nLayerCount)
     132             :             {
     133           1 :                 if (poDstDS->DeleteLayer(iLayer) != OGRERR_NONE)
     134             :                 {
     135           0 :                     ReportError(CE_Failure, CPLE_AppDefined,
     136             :                                 "Cannot delete layer '%s'",
     137             :                                 m_outputLayerName.c_str());
     138           0 :                     return ret;
     139             :                 }
     140             :             }
     141           1 :             poDstLayer = nullptr;
     142             :         }
     143          11 :         else if (!m_appendLayer)
     144             :         {
     145           1 :             ReportError(CE_Failure, CPLE_AppDefined,
     146             :                         "Layer '%s' already exists. Specify the "
     147             :                         "--%s option to overwrite it, or --%s "
     148             :                         "to append to it.",
     149             :                         m_outputLayerName.c_str(),
     150             :                         GDAL_ARG_NAME_OVERWRITE_LAYER, GDAL_ARG_NAME_APPEND);
     151           1 :             return ret;
     152             :         }
     153             :     }
     154          46 :     else if (m_appendLayer || m_overwriteLayer)
     155             :     {
     156           0 :         ReportError(CE_Failure, CPLE_AppDefined, "Cannot find layer '%s'",
     157             :                     m_outputLayerName.c_str());
     158           0 :         return ret;
     159             :     }
     160             : 
     161          57 :     ret.newDS = std::move(poRetDS);
     162          57 :     ret.outDS = poDstDS;
     163          57 :     ret.layer = poDstLayer;
     164          57 :     return ret;
     165             : }
     166             : 
     167             : /************************************************************************/
     168             : /* GDALVectorOutputAbstractAlgorithm::SetDefaultOutputLayerNameIfNeeded */
     169             : /************************************************************************/
     170             : 
     171          16 : bool GDALVectorOutputAbstractAlgorithm::SetDefaultOutputLayerNameIfNeeded(
     172             :     GDALDataset *poOutDS)
     173             : {
     174          16 :     if (m_outputLayerName.empty())
     175             :     {
     176             :         VSIStatBufL sStat;
     177           1 :         auto poDriver = poOutDS->GetDriver();
     178           2 :         if (VSIStatL(m_outputDataset.GetName().c_str(), &sStat) == 0 ||
     179           1 :             (poDriver && EQUAL(poDriver->GetDescription(), "ESRI Shapefile")))
     180             :         {
     181             :             m_outputLayerName =
     182           0 :                 CPLGetBasenameSafe(m_outputDataset.GetName().c_str());
     183             :         }
     184             :     }
     185          16 :     if (m_outputLayerName.empty())
     186             :     {
     187           1 :         ReportError(CE_Failure, CPLE_AppDefined,
     188             :                     "Argument 'layer' must be specified");
     189           1 :         return false;
     190             :     }
     191          15 :     return true;
     192             : }
     193             : 
     194             : //! @endcond

Generated by: LCOV version 1.14