LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_output_abstract.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 78 90 86.7 %
Date: 2025-05-15 13:16:46 Functions: 5 5 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             : /************************************************************************/
      25             : /*      GDALVectorOutputAbstractAlgorithm::AddAllOutputArgs()           */
      26             : /************************************************************************/
      27             : 
      28          36 : void GDALVectorOutputAbstractAlgorithm::AddAllOutputArgs()
      29             : {
      30          36 :     AddOutputFormatArg(&m_outputFormat)
      31             :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
      32         108 :                          {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE});
      33          36 :     AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR)
      34          36 :         .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
      35          36 :     AddCreationOptionsArg(&m_creationOptions);
      36          36 :     AddLayerCreationOptionsArg(&m_layerCreationOptions);
      37          36 :     AddOverwriteArg(&m_overwrite).SetMutualExclusionGroup("overwrite-update");
      38          36 :     AddUpdateArg(&m_update).SetMutualExclusionGroup("overwrite-update");
      39             :     AddArg("overwrite-layer", 0,
      40             :            _("Whether overwriting existing layer is allowed"),
      41          72 :            &m_overwriteLayer)
      42          36 :         .SetDefault(false)
      43             :         .AddValidationAction(
      44           1 :             [this]
      45             :             {
      46           1 :                 GetArg(GDAL_ARG_NAME_UPDATE)->Set(true);
      47           1 :                 return true;
      48          36 :             });
      49             :     AddArg("append", 0, _("Whether appending to existing layer is allowed"),
      50          72 :            &m_appendLayer)
      51          36 :         .SetDefault(false)
      52             :         .AddValidationAction(
      53           2 :             [this]
      54             :             {
      55           2 :                 GetArg(GDAL_ARG_NAME_UPDATE)->Set(true);
      56           2 :                 return true;
      57          36 :             });
      58             :     {
      59          36 :         auto &arg = AddLayerNameArg(&m_outputLayerName)
      60          72 :                         .AddAlias("nln")
      61          36 :                         .SetMinCharCount(0);
      62          36 :         if (!m_outputLayerName.empty())
      63           0 :             arg.SetDefault(m_outputLayerName);
      64             :     }
      65          36 : }
      66             : 
      67             : /************************************************************************/
      68             : /*         GDALVectorOutputAbstractAlgorithm::SetupOutputDataset()      */
      69             : /************************************************************************/
      70             : 
      71             : GDALVectorOutputAbstractAlgorithm::SetupOutputDatasetRet
      72          17 : GDALVectorOutputAbstractAlgorithm::SetupOutputDataset()
      73             : {
      74          17 :     SetupOutputDatasetRet ret;
      75             : 
      76          17 :     GDALDataset *poDstDS = m_outputDataset.GetDatasetRef();
      77          17 :     std::unique_ptr<GDALDataset> poRetDS;
      78          17 :     if (!poDstDS)
      79             :     {
      80          13 :         if (m_outputFormat.empty())
      81             :         {
      82             :             const auto aosFormats =
      83             :                 CPLStringList(GDALGetOutputDriversForDatasetName(
      84           2 :                     m_outputDataset.GetName().c_str(), GDAL_OF_VECTOR,
      85             :                     /* bSingleMatch = */ true,
      86           2 :                     /* bWarn = */ true));
      87           2 :             if (aosFormats.size() != 1)
      88             :             {
      89           0 :                 ReportError(CE_Failure, CPLE_AppDefined,
      90             :                             "Cannot guess driver for %s",
      91           0 :                             m_outputDataset.GetName().c_str());
      92           0 :                 return ret;
      93             :             }
      94           2 :             m_outputFormat = aosFormats[0];
      95             :         }
      96             : 
      97             :         auto poDriver =
      98          13 :             GetGDALDriverManager()->GetDriverByName(m_outputFormat.c_str());
      99          13 :         if (!poDriver)
     100             :         {
     101             :             // shouldn't happen given checks done in GDALAlgorithm
     102           0 :             ReportError(CE_Failure, CPLE_AppDefined, "Cannot find driver %s",
     103             :                         m_outputFormat.c_str());
     104           0 :             return ret;
     105             :         }
     106             : 
     107          13 :         poRetDS.reset(poDriver->Create(
     108          13 :             m_outputDataset.GetName().c_str(), 0, 0, 0, GDT_Unknown,
     109          26 :             CPLStringList(m_creationOptions).List()));
     110          13 :         if (!poRetDS)
     111           0 :             return ret;
     112             : 
     113          13 :         poDstDS = poRetDS.get();
     114             :     }
     115             : 
     116          17 :     auto poDstDriver = poDstDS->GetDriver();
     117          17 :     if (poDstDriver && EQUAL(poDstDriver->GetDescription(), "ESRI Shapefile") &&
     118          40 :         EQUAL(CPLGetExtensionSafe(poDstDS->GetDescription()).c_str(), "shp") &&
     119           6 :         poDstDS->GetLayerCount() <= 1)
     120             :     {
     121           6 :         m_outputLayerName = CPLGetBasenameSafe(poDstDS->GetDescription());
     122             :     }
     123             : 
     124          17 :     auto poDstLayer = m_outputLayerName.empty()
     125          17 :                           ? nullptr
     126          16 :                           : poDstDS->GetLayerByName(m_outputLayerName.c_str());
     127          17 :     if (poDstLayer)
     128             :     {
     129           4 :         if (m_overwriteLayer)
     130             :         {
     131           1 :             int iLayer = -1;
     132           1 :             const int nLayerCount = poDstDS->GetLayerCount();
     133           1 :             for (iLayer = 0; iLayer < nLayerCount; iLayer++)
     134             :             {
     135           1 :                 if (poDstDS->GetLayer(iLayer) == poDstLayer)
     136           1 :                     break;
     137             :             }
     138             : 
     139           1 :             if (iLayer < nLayerCount)
     140             :             {
     141           1 :                 if (poDstDS->DeleteLayer(iLayer) != OGRERR_NONE)
     142             :                 {
     143           0 :                     ReportError(CE_Failure, CPLE_AppDefined,
     144             :                                 "Cannot delete layer '%s'",
     145             :                                 m_outputLayerName.c_str());
     146           0 :                     return ret;
     147             :                 }
     148             :             }
     149           1 :             poDstLayer = nullptr;
     150             :         }
     151           3 :         else if (!m_appendLayer)
     152             :         {
     153           1 :             ReportError(CE_Failure, CPLE_AppDefined,
     154             :                         "Layer '%s' already exists. Specify the "
     155             :                         "--overwrite-layer option to overwrite it, or --append "
     156             :                         "to append to it.",
     157             :                         m_outputLayerName.c_str());
     158           1 :             return ret;
     159             :         }
     160             :     }
     161          13 :     else if (m_appendLayer || m_overwriteLayer)
     162             :     {
     163           0 :         ReportError(CE_Failure, CPLE_AppDefined, "Cannot find layer '%s'",
     164             :                     m_outputLayerName.c_str());
     165           0 :         return ret;
     166             :     }
     167             : 
     168          16 :     ret.newDS = std::move(poRetDS);
     169          16 :     ret.outDS = poDstDS;
     170          16 :     ret.layer = poDstLayer;
     171          16 :     return ret;
     172             : }
     173             : 
     174             : /************************************************************************/
     175             : /* GDALVectorOutputAbstractAlgorithm::SetDefaultOutputLayerNameIfNeeded */
     176             : /************************************************************************/
     177             : 
     178          16 : bool GDALVectorOutputAbstractAlgorithm::SetDefaultOutputLayerNameIfNeeded(
     179             :     GDALDataset *poOutDS)
     180             : {
     181          16 :     if (m_outputLayerName.empty())
     182             :     {
     183             :         VSIStatBufL sStat;
     184           1 :         auto poDriver = poOutDS->GetDriver();
     185           2 :         if (VSIStatL(m_outputDataset.GetName().c_str(), &sStat) == 0 ||
     186           1 :             (poDriver && EQUAL(poDriver->GetDescription(), "ESRI Shapefile")))
     187             :         {
     188             :             m_outputLayerName =
     189           0 :                 CPLGetBasenameSafe(m_outputDataset.GetName().c_str());
     190             :         }
     191             :     }
     192          16 :     if (m_outputLayerName.empty())
     193             :     {
     194           1 :         ReportError(CE_Failure, CPLE_AppDefined,
     195             :                     "Argument 'layer' must be specified");
     196           1 :         return false;
     197             :     }
     198          15 :     return true;
     199             : }
     200             : 
     201             : //! @endcond

Generated by: LCOV version 1.14