Coverage Report

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