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

Generated by: LCOV version 1.14