Coverage Report

Created: 2026-07-25 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/apps/gdalalg_raster_info.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  gdal "raster info" subcommand
5
 * Author:   Even Rouault <even dot rouault at spatialys.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#include "gdalalg_raster_info.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
/*          GDALRasterInfoAlgorithm::GDALRasterInfoAlgorithm()          */
27
/************************************************************************/
28
29
GDALRasterInfoAlgorithm::GDALRasterInfoAlgorithm(bool standaloneStep,
30
                                                 bool openForMixedRasterVector)
31
0
    : GDALRasterPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
32
0
                                      ConstructorOptions()
33
0
                                          .SetStandaloneStep(standaloneStep)
34
0
                                          .SetInputDatasetMaxCount(1)
35
0
                                          .SetAddDefaultArguments(false)
36
0
                                          .SetInputDatasetAlias("dataset"))
37
0
{
38
0
    if (standaloneStep)
39
0
    {
40
0
        AddProgressArg(/* hidden = */ true);
41
0
        AddRasterInputArgs(openForMixedRasterVector,
42
0
                           /* hiddenForCLI = */ false);
43
0
    }
44
0
    else
45
0
    {
46
0
        AddRasterHiddenInputDatasetArg();
47
0
    }
48
49
0
    AddOutputFormatArg(&m_format).SetChoices("json", "text");
50
0
    AddArg("min-max", 0, _("Compute minimum and maximum value"), &m_minMax)
51
0
        .AddAlias("mm");
52
0
    AddArg("stats", 0, _("Retrieve or compute statistics, using all pixels"),
53
0
           &m_stats)
54
0
        .SetMutualExclusionGroup("stats");
55
0
    AddArg("approx-stats", 0,
56
0
           _("Retrieve or compute statistics, using a subset of pixels"),
57
0
           &m_approxStats)
58
0
        .SetMutualExclusionGroup("stats");
59
0
    AddArg("hist", 0, _("Retrieve or compute histogram"), &m_hist);
60
61
0
    AddArg("no-gcp", 0, _("Suppress ground control points list printing"),
62
0
           &m_noGCP)
63
0
        .SetCategory(GAAC_ADVANCED);
64
0
    AddArg("no-md", 0, _("Suppress metadata printing"), &m_noMD)
65
0
        .SetCategory(GAAC_ADVANCED);
66
0
    AddArg("no-ct", 0, _("Suppress color table printing"), &m_noCT)
67
0
        .SetCategory(GAAC_ADVANCED);
68
0
    AddArg("no-fl", 0, _("Suppress file list printing"), &m_noFL)
69
0
        .SetCategory(GAAC_ADVANCED);
70
0
    AddArg("checksum", 0, _("Compute pixel checksum"), &m_checksum)
71
0
        .SetCategory(GAAC_ADVANCED);
72
0
    AddArg("list-mdd", 0,
73
0
           _("List all metadata domains available for the dataset"), &m_listMDD)
74
0
        .AddAlias("list-metadata-domains")
75
0
        .SetCategory(GAAC_ADVANCED);
76
0
    AddArg("metadata-domain", 0,
77
0
           _("Report metadata for the specified domain. 'all' can be used to "
78
0
             "report metadata in all domains"),
79
0
           &m_mdd)
80
0
        .AddAlias("mdd")
81
0
        .SetCategory(GAAC_ADVANCED);
82
83
0
    AddArg("no-nodata", 0, _("Suppress retrieving nodata value"), &m_noNodata)
84
0
        .SetCategory(GAAC_ESOTERIC);
85
0
    AddArg("no-mask", 0, _("Suppress mask band information"), &m_noMask)
86
0
        .SetCategory(GAAC_ESOTERIC);
87
0
    AddArg("subdataset", 0,
88
0
           _("Use subdataset of specified index (starting at 1), instead of "
89
0
             "the source dataset itself"),
90
0
           &m_subDS)
91
0
        .SetCategory(GAAC_ESOTERIC)
92
0
        .SetMinValueIncluded(1);
93
0
    AddArg("crs-format", 0, _("Which format to use to report CRS"),
94
0
           &m_crsFormat)
95
0
        .SetChoices("AUTO", "WKT2", "PROJJSON")
96
0
        .SetDefault(m_crsFormat)
97
0
        .SetCategory(GAAC_ESOTERIC);
98
99
0
    AddOutputStringArg(&m_output);
100
0
    AddStdoutArg(&m_stdout);
101
102
0
    AddValidationAction(
103
0
        [this]()
104
0
        {
105
0
            if (m_crsFormat != "AUTO" && m_format == "json")
106
0
            {
107
0
                ReportError(CE_Failure, CPLE_AppDefined,
108
0
                            "'crs-format' cannot be set when 'format' is set "
109
0
                            "to 'json'");
110
0
                return false;
111
0
            }
112
0
            return true;
113
0
        });
114
0
}
115
116
/************************************************************************/
117
/*                  GDALRasterInfoAlgorithm::RunStep()                  */
118
/************************************************************************/
119
120
bool GDALRasterInfoAlgorithm::RunStep(GDALPipelineStepRunContext &)
121
0
{
122
0
    CPLAssert(m_inputDataset.size() == 1);
123
0
    auto poSrcDS = m_inputDataset[0].GetDatasetRef();
124
0
    CPLAssert(poSrcDS);
125
126
0
    if (m_format.empty())
127
0
        m_format = IsCalledFromCommandLine() ? "text" : "json";
128
129
0
    CPLStringList aosOptions;
130
0
    aosOptions.AddString("--invoked-from=gdal-raster-info");
131
0
    aosOptions.AddString("--crs-format=" + m_crsFormat);
132
0
    if (m_format == "json")
133
0
        aosOptions.AddString("-json");
134
0
    if (m_minMax)
135
0
        aosOptions.AddString("-mm");
136
0
    if (m_stats)
137
0
        aosOptions.AddString("-stats");
138
0
    if (m_approxStats)
139
0
        aosOptions.AddString("-approx_stats");
140
0
    if (m_hist)
141
0
        aosOptions.AddString("-hist");
142
0
    if (m_noGCP)
143
0
        aosOptions.AddString("-nogcp");
144
0
    if (m_noMD)
145
0
        aosOptions.AddString("-nomd");
146
0
    if (m_noCT)
147
0
        aosOptions.AddString("-noct");
148
0
    if (m_noFL)
149
0
        aosOptions.AddString("-nofl");
150
0
    if (m_noMask)
151
0
        aosOptions.AddString("-nomask");
152
0
    if (m_noNodata)
153
0
        aosOptions.AddString("-nonodata");
154
0
    if (m_checksum)
155
0
        aosOptions.AddString("-checksum");
156
0
    if (m_listMDD)
157
0
        aosOptions.AddString("-listmdd");
158
0
    if (!m_mdd.empty())
159
0
    {
160
0
        aosOptions.AddString("-mdd");
161
0
        aosOptions.AddString(m_mdd.c_str());
162
0
    }
163
164
0
    GDALDatasetH hDS = GDALDataset::ToHandle(poSrcDS);
165
0
    std::unique_ptr<GDALDataset> poSubDataset;
166
167
0
    if (m_subDS > 0)
168
0
    {
169
0
        CSLConstList papszSubdatasets =
170
0
            GDALGetMetadata(hDS, GDAL_MDD_SUBDATASETS);
171
0
        const int nSubdatasets = CSLCount(papszSubdatasets) / 2;
172
0
        if (m_subDS > nSubdatasets)
173
0
        {
174
0
            CPLError(CE_Failure, CPLE_AppDefined,
175
0
                     "Invalid value for 'subdataset' argument. Should be "
176
0
                     "between 1 and %d",
177
0
                     nSubdatasets);
178
0
            return false;
179
0
        }
180
181
0
        char szKeyName[64];
182
0
        snprintf(szKeyName, sizeof(szKeyName), "SUBDATASET_%d_NAME", m_subDS);
183
0
        const std::string osSubDSName =
184
0
            CSLFetchNameValueDef(papszSubdatasets, szKeyName, "");
185
186
0
        poSubDataset.reset(GDALDataset::Open(
187
0
            osSubDSName.c_str(), GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
188
0
            nullptr, nullptr, nullptr));
189
0
        if (!poSubDataset)
190
0
            return false;
191
0
        hDS = GDALDataset::ToHandle(poSubDataset.get());
192
0
    }
193
194
0
    if (m_stdout)
195
0
    {
196
0
        aosOptions.AddString("-stdout");
197
0
    }
198
199
0
    GDALInfoOptions *psOptions = GDALInfoOptionsNew(aosOptions.List(), nullptr);
200
0
    char *ret = GDALInfo(hDS, psOptions);
201
0
    GDALInfoOptionsFree(psOptions);
202
0
    const bool bOK = ret != nullptr;
203
0
    if (ret)
204
0
    {
205
0
        m_output = ret;
206
0
    }
207
0
    CPLFree(ret);
208
209
0
    return bOK;
210
0
}
211
212
0
GDALRasterInfoAlgorithmStandalone::~GDALRasterInfoAlgorithmStandalone() =
213
    default;
214
215
//! @endcond