Coverage Report

Created: 2026-02-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/apps/gdalalg_vector_edit.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  "edit" step of "vector pipeline"
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_edit.h"
14
15
#include "gdal_priv.h"
16
#include "gdal_utils.h"
17
18
//! @cond Doxygen_Suppress
19
20
#ifndef _
21
0
#define _(x) (x)
22
#endif
23
24
/************************************************************************/
25
/*          GDALVectorEditAlgorithm::GDALVectorEditAlgorithm()          */
26
/************************************************************************/
27
28
GDALVectorEditAlgorithm::GDALVectorEditAlgorithm(bool standaloneStep)
29
0
    : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
30
0
                                      standaloneStep)
31
0
{
32
0
    AddActiveLayerArg(&m_activeLayer);
33
0
    AddGeometryTypeArg(&m_geometryType, _("Layer geometry type"));
34
35
0
    AddArg("crs", 0, _("Override CRS (without reprojection)"), &m_overrideCrs)
36
0
        .AddHiddenAlias("a_srs")
37
0
        .SetIsCRSArg(/*noneAllowed=*/true);
38
39
0
    {
40
0
        auto &arg = AddArg("metadata", 0, _("Add/update dataset metadata item"),
41
0
                           &m_metadata)
42
0
                        .SetMetaVar("<KEY>=<VALUE>")
43
0
                        .SetPackedValuesAllowed(false);
44
0
        arg.AddValidationAction([this, &arg]()
45
0
                                { return ParseAndValidateKeyValue(arg); });
46
0
        arg.AddHiddenAlias("mo");
47
0
    }
48
49
0
    AddArg("unset-metadata", 0, _("Remove dataset metadata item"),
50
0
           &m_unsetMetadata)
51
0
        .SetMetaVar("<KEY>");
52
53
0
    {
54
0
        auto &arg =
55
0
            AddArg("layer-metadata", 0, _("Add/update layer metadata item"),
56
0
                   &m_layerMetadata)
57
0
                .SetMetaVar("<KEY>=<VALUE>")
58
0
                .SetPackedValuesAllowed(false);
59
0
        arg.AddValidationAction([this, &arg]()
60
0
                                { return ParseAndValidateKeyValue(arg); });
61
0
    }
62
63
0
    AddArg("unset-layer-metadata", 0, _("Remove layer metadata item"),
64
0
           &m_unsetLayerMetadata)
65
0
        .SetMetaVar("<KEY>");
66
67
0
    AddArg("unset-fid", 0,
68
0
           _("Unset the identifier of each feature and the FID column name"),
69
0
           &m_unsetFID);
70
0
}
71
72
/************************************************************************/
73
/*                     GDALVectorEditAlgorithmLayer                     */
74
/************************************************************************/
75
76
namespace
77
{
78
class GDALVectorEditAlgorithmLayer final : public GDALVectorPipelineOutputLayer
79
{
80
  public:
81
    GDALVectorEditAlgorithmLayer(
82
        OGRLayer &oSrcLayer, const std::string &activeLayer,
83
        bool bChangeGeomType, OGRwkbGeometryType eType,
84
        const std::string &overrideCrs,
85
        const std::vector<std::string> &layerMetadata,
86
        const std::vector<std::string> &unsetLayerMetadata, bool unsetFID)
87
0
        : GDALVectorPipelineOutputLayer(oSrcLayer),
88
0
          m_bOverrideCrs(!overrideCrs.empty()), m_unsetFID(unsetFID)
89
0
    {
90
0
        SetDescription(oSrcLayer.GetDescription());
91
0
        SetMetadata(oSrcLayer.GetMetadata());
92
93
0
        m_poFeatureDefn = oSrcLayer.GetLayerDefn()->Clone();
94
0
        m_poFeatureDefn->Reference();
95
96
0
        if (activeLayer.empty() || activeLayer == GetDescription())
97
0
        {
98
0
            const CPLStringList aosMD(layerMetadata);
99
0
            for (const auto &[key, value] : cpl::IterateNameValue(aosMD))
100
0
            {
101
0
                if (SetMetadataItem(key, value) != CE_None)
102
0
                {
103
0
                    CPLError(CE_Warning, CPLE_AppDefined,
104
0
                             "SetMetadataItem('%s', '%s') failed", key, value);
105
0
                }
106
0
            }
107
108
0
            for (const std::string &key : unsetLayerMetadata)
109
0
            {
110
0
                if (SetMetadataItem(key.c_str(), nullptr) != CE_None)
111
0
                {
112
0
                    CPLError(CE_Warning, CPLE_AppDefined,
113
0
                             "SetMetadataItem('%s', NULL) failed", key.c_str());
114
0
                }
115
0
            }
116
117
0
            if (bChangeGeomType)
118
0
            {
119
0
                for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); ++i)
120
0
                {
121
0
                    m_poFeatureDefn->GetGeomFieldDefn(i)->SetType(eType);
122
0
                }
123
0
            }
124
125
0
            if (!overrideCrs.empty())
126
0
            {
127
0
                if (!EQUAL(overrideCrs.c_str(), "null") &&
128
0
                    !EQUAL(overrideCrs.c_str(), "none"))
129
0
                {
130
0
                    m_poSRS = new OGRSpatialReference();
131
0
                    m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
132
0
                    m_poSRS->SetFromUserInput(overrideCrs.c_str());
133
0
                }
134
0
                for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); ++i)
135
0
                {
136
0
                    m_poFeatureDefn->GetGeomFieldDefn(i)->SetSpatialRef(
137
0
                        m_poSRS);
138
0
                }
139
0
            }
140
0
        }
141
0
    }
142
143
    ~GDALVectorEditAlgorithmLayer() override
144
0
    {
145
0
        m_poFeatureDefn->Release();
146
0
        if (m_poSRS)
147
0
            m_poSRS->Release();
148
0
    }
149
150
    const char *GetFIDColumn() const override
151
0
    {
152
0
        if (m_unsetFID)
153
0
            return "";
154
0
        return m_srcLayer.GetFIDColumn();
155
0
    }
156
157
    const OGRFeatureDefn *GetLayerDefn() const override
158
0
    {
159
0
        return m_poFeatureDefn;
160
0
    }
161
162
    void TranslateFeature(
163
        std::unique_ptr<OGRFeature> poSrcFeature,
164
        std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures) override
165
0
    {
166
0
        poSrcFeature->SetFDefnUnsafe(m_poFeatureDefn);
167
0
        if (m_bOverrideCrs)
168
0
        {
169
0
            for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); ++i)
170
0
            {
171
0
                auto poGeom = poSrcFeature->GetGeomFieldRef(i);
172
0
                if (poGeom)
173
0
                    poGeom->assignSpatialReference(m_poSRS);
174
0
            }
175
0
        }
176
0
        if (m_unsetFID)
177
0
            poSrcFeature->SetFID(OGRNullFID);
178
0
        apoOutFeatures.push_back(std::move(poSrcFeature));
179
0
    }
180
181
    int TestCapability(const char *pszCap) const override
182
0
    {
183
0
        if (EQUAL(pszCap, OLCStringsAsUTF8) ||
184
0
            EQUAL(pszCap, OLCCurveGeometries) || EQUAL(pszCap, OLCZGeometries))
185
0
            return m_srcLayer.TestCapability(pszCap);
186
0
        return false;
187
0
    }
188
189
  private:
190
    const bool m_bOverrideCrs;
191
    const bool m_unsetFID;
192
    OGRFeatureDefn *m_poFeatureDefn = nullptr;
193
    OGRSpatialReference *m_poSRS = nullptr;
194
195
    CPL_DISALLOW_COPY_ASSIGN(GDALVectorEditAlgorithmLayer)
196
};
197
198
}  // namespace
199
200
/************************************************************************/
201
/*                  GDALVectorEditAlgorithm::RunStep()                  */
202
/************************************************************************/
203
204
bool GDALVectorEditAlgorithm::RunStep(GDALPipelineStepRunContext &)
205
0
{
206
0
    auto poSrcDS = m_inputDataset[0].GetDatasetRef();
207
0
    CPLAssert(poSrcDS);
208
209
0
    CPLAssert(m_outputDataset.GetName().empty());
210
0
    CPLAssert(!m_outputDataset.GetDatasetRef());
211
212
0
    const int nLayerCount = poSrcDS->GetLayerCount();
213
214
0
    bool bChangeGeomType = false;
215
0
    OGRwkbGeometryType eType = wkbUnknown;
216
0
    if (!m_geometryType.empty())
217
0
    {
218
0
        eType = OGRFromOGCGeomType(m_geometryType.c_str());
219
0
        bChangeGeomType = true;
220
0
    }
221
222
0
    auto outDS = std::make_unique<GDALVectorPipelineOutputDataset>(*poSrcDS);
223
224
0
    const CPLStringList aosMD(m_metadata);
225
0
    for (const auto &[key, value] : cpl::IterateNameValue(aosMD))
226
0
    {
227
0
        if (outDS->SetMetadataItem(key, value) != CE_None)
228
0
        {
229
0
            ReportError(CE_Failure, CPLE_AppDefined,
230
0
                        "SetMetadataItem('%s', '%s') failed", key, value);
231
0
            return false;
232
0
        }
233
0
    }
234
235
0
    for (const std::string &key : m_unsetMetadata)
236
0
    {
237
0
        if (outDS->SetMetadataItem(key.c_str(), nullptr) != CE_None)
238
0
        {
239
0
            ReportError(CE_Failure, CPLE_AppDefined,
240
0
                        "SetMetadataItem('%s', NULL) failed", key.c_str());
241
0
            return false;
242
0
        }
243
0
    }
244
245
0
    bool ret = true;
246
0
    for (int i = 0; ret && i < nLayerCount; ++i)
247
0
    {
248
0
        auto poSrcLayer = poSrcDS->GetLayer(i);
249
0
        ret = (poSrcLayer != nullptr);
250
0
        if (ret)
251
0
        {
252
0
            outDS->AddLayer(*poSrcLayer,
253
0
                            std::make_unique<GDALVectorEditAlgorithmLayer>(
254
0
                                *poSrcLayer, m_activeLayer, bChangeGeomType,
255
0
                                eType, m_overrideCrs, m_layerMetadata,
256
0
                                m_unsetLayerMetadata, m_unsetFID));
257
0
        }
258
0
    }
259
260
0
    if (ret)
261
0
        m_outputDataset.Set(std::move(outDS));
262
263
0
    return ret;
264
0
}
265
266
0
GDALVectorEditAlgorithmStandalone::~GDALVectorEditAlgorithmStandalone() =
267
    default;
268
269
//! @endcond