Coverage Report

Created: 2026-07-25 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/apps/gdalalg_mdim_convert.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  gdal "mdim convert" subcommand
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_mdim_convert.h"
14
15
#include "cpl_conv.h"
16
#include "gdal_priv.h"
17
#include "gdal_utils.h"
18
19
//! @cond Doxygen_Suppress
20
21
#ifndef _
22
0
#define _(x) (x)
23
#endif
24
25
/************************************************************************/
26
/*         GDALMdimConvertAlgorithm::GDALMdimConvertAlgorithm()         */
27
/************************************************************************/
28
29
GDALMdimConvertAlgorithm::GDALMdimConvertAlgorithm()
30
0
    : GDALMdimPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
31
0
                                    ConstructorOptions()
32
0
                                        .SetStandaloneStep(true)
33
0
                                        .SetInputDatasetMaxCount(1)
34
0
                                        .SetAddDefaultArguments(false))
35
0
{
36
0
    AddMdimInputArgs(false, false, /* acceptRaster = */ true);
37
0
    AddProgressArg();
38
0
    AddMdimOutputArgs(false);
39
40
0
    {
41
0
        auto &arg = AddArg("array", 0,
42
0
                           _("Select a single array instead of converting the "
43
0
                             "whole dataset."),
44
0
                           &m_arrays)
45
0
                        .SetMetaVar("<ARRAY-SPEC>")
46
0
                        .SetPackedValuesAllowed(false);
47
48
0
        arg.SetAutoCompleteFunction(
49
0
            [this](const std::string &)
50
0
            {
51
0
                std::vector<std::string> ret;
52
0
                if (m_inputDataset.size() == 1)
53
0
                {
54
0
                    if (auto poDS =
55
0
                            std::unique_ptr<GDALDataset>(GDALDataset::Open(
56
0
                                m_inputDataset[0].GetName().c_str(),
57
0
                                GDAL_OF_MULTIDIM_RASTER, nullptr, nullptr,
58
0
                                nullptr)))
59
0
                    {
60
0
                        if (auto poRG = poDS->GetRootGroup())
61
0
                        {
62
0
                            ret = poRG->GetMDArrayFullNamesRecursive();
63
0
                        }
64
0
                    }
65
0
                }
66
67
0
                return ret;
68
0
            });
69
0
    }
70
71
0
    {
72
0
        auto &arg = AddArg("array-option", 0,
73
0
                           _("Option passed to GDALGroup::GetMDArrayNames() to "
74
0
                             "filter arrays."),
75
0
                           &m_arrayOptions)
76
0
                        .SetMetaVar("<KEY>=<VALUE>")
77
0
                        .SetPackedValuesAllowed(false);
78
0
        arg.AddValidationAction([this, &arg]()
79
0
                                { return ParseAndValidateKeyValue(arg); });
80
81
0
        arg.SetAutoCompleteFunction(
82
0
            [this](const std::string &currentValue)
83
0
            {
84
0
                std::vector<std::string> ret;
85
0
                if (m_inputDataset.size() == 1)
86
0
                {
87
0
                    if (auto poDS =
88
0
                            std::unique_ptr<GDALDataset>(GDALDataset::Open(
89
0
                                m_inputDataset[0].GetName().c_str(),
90
0
                                GDAL_OF_MULTIDIM_RASTER, nullptr, nullptr,
91
0
                                nullptr)))
92
0
                    {
93
0
                        if (auto poDriver = poDS->GetDriver())
94
0
                        {
95
0
                            if (const char *pszXML = poDriver->GetMetadataItem(
96
0
                                    GDAL_DMD_MULTIDIM_ARRAY_OPENOPTIONLIST))
97
0
                            {
98
0
                                AddOptionsSuggestions(pszXML, 0, currentValue,
99
0
                                                      ret);
100
0
                            }
101
0
                        }
102
0
                    }
103
0
                }
104
105
0
                return ret;
106
0
            });
107
0
    }
108
109
0
    AddArg("group", 0,
110
0
           _("Select a single group instead of converting the whole dataset."),
111
0
           &m_groups)
112
0
        .SetMetaVar("<GROUP-SPEC>")
113
0
        .SetPackedValuesAllowed(false);
114
115
0
    AddArg("subset", 0, _("Select a subset of the data."), &m_subsets)
116
0
        .SetMetaVar("<SUBSET-SPEC>")
117
0
        .SetPackedValuesAllowed(false);
118
119
0
    AddArg("scale-axes", 0,
120
0
           _("Applies a integral scale factor to one or several dimensions"),
121
0
           &m_scaleAxes)
122
0
        .SetMetaVar("<SCALEAXES-SPEC>")
123
0
        .SetPackedValuesAllowed(false);
124
125
0
    AddArg("strict", 0, _("Turn warnings into failures."), &m_strict);
126
0
}
127
128
/************************************************************************/
129
/*                 GDALMdimConvertAlgorithm::RunImpl()                  */
130
/************************************************************************/
131
132
bool GDALMdimConvertAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
133
                                       void *pProgressData)
134
0
{
135
0
    GDALPipelineStepRunContext stepCtxt;
136
0
    stepCtxt.m_pfnProgress = pfnProgress;
137
0
    stepCtxt.m_pProgressData = pProgressData;
138
0
    return RunPreStepPipelineValidations() && RunStep(stepCtxt);
139
0
}
140
141
/************************************************************************/
142
/*                 GDALMdimConvertAlgorithm::RunStep()                  */
143
/************************************************************************/
144
145
bool GDALMdimConvertAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
146
0
{
147
0
    auto poSrcDS = m_inputDataset[0].GetDatasetRef();
148
0
    CPLAssert(poSrcDS);
149
150
0
    CPLAssert(!m_outputDataset.GetDatasetRef());
151
152
0
    CPLStringList aosOptions;
153
0
    if (!m_format.empty())
154
0
    {
155
0
        aosOptions.AddString("-of");
156
0
        aosOptions.AddString(m_format.c_str());
157
0
    }
158
0
    if (m_overwrite)
159
0
    {
160
0
        aosOptions.AddString("--overwrite");
161
0
    }
162
0
    else
163
0
    {
164
0
        aosOptions.AddString("--no-overwrite");
165
0
    }
166
0
    if (m_strict)
167
0
    {
168
0
        aosOptions.AddString("-strict");
169
0
    }
170
0
    for (const auto &array : m_arrays)
171
0
    {
172
0
        aosOptions.AddString("-array");
173
0
        aosOptions.AddString(array.c_str());
174
0
    }
175
0
    for (const auto &opt : m_arrayOptions)
176
0
    {
177
0
        aosOptions.AddString("-arrayoption");
178
0
        aosOptions.AddString(opt.c_str());
179
0
    }
180
0
    for (const auto &group : m_groups)
181
0
    {
182
0
        aosOptions.AddString("-group");
183
0
        aosOptions.AddString(group.c_str());
184
0
    }
185
0
    for (const auto &subset : m_subsets)
186
0
    {
187
0
        aosOptions.AddString("-subset");
188
0
        aosOptions.AddString(subset.c_str());
189
0
    }
190
191
0
    std::string scaleAxes;
192
0
    for (const auto &scaleAxis : m_scaleAxes)
193
0
    {
194
0
        if (!scaleAxes.empty())
195
0
            scaleAxes += ',';
196
0
        scaleAxes += scaleAxis;
197
0
    }
198
0
    if (!scaleAxes.empty())
199
0
    {
200
0
        aosOptions.AddString("-scaleaxes");
201
0
        aosOptions.AddString(scaleAxes.c_str());
202
0
    }
203
204
0
    for (const auto &co : m_creationOptions)
205
0
    {
206
0
        aosOptions.AddString("-co");
207
0
        aosOptions.AddString(co.c_str());
208
0
    }
209
210
0
    GDALMultiDimTranslateOptions *psOptions =
211
0
        GDALMultiDimTranslateOptionsNew(aosOptions.List(), nullptr);
212
0
    auto pfnProgress = ctxt.m_pfnProgress;
213
0
    auto pProgressData = ctxt.m_pProgressData;
214
0
    GDALMultiDimTranslateOptionsSetProgress(psOptions, pfnProgress,
215
0
                                            pProgressData);
216
217
0
    auto hSrcDS = GDALDataset::ToHandle(poSrcDS);
218
0
    auto poOutDS = std::unique_ptr<GDALDataset>(GDALDataset::FromHandle(
219
0
        GDALMultiDimTranslate(m_outputDataset.GetName().c_str(), nullptr, 1,
220
0
                              &hSrcDS, psOptions, nullptr)));
221
0
    GDALMultiDimTranslateOptionsFree(psOptions);
222
0
    if (!poOutDS)
223
0
        return false;
224
225
0
    m_outputDataset.Set(std::move(poOutDS));
226
227
0
    return true;
228
0
}
229
230
//! @endcond