Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: gdal "dataset identify" 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_dataset_identify.h"
14 :
15 : #include "cpl_string.h"
16 :
17 : //! @cond Doxygen_Suppress
18 :
19 : #ifndef _
20 : #define _(x) (x)
21 : #endif
22 :
23 : /************************************************************************/
24 : /* GDALDatasetIdentifyAlgorithm() */
25 : /************************************************************************/
26 :
27 10 : GDALDatasetIdentifyAlgorithm::GDALDatasetIdentifyAlgorithm()
28 10 : : GDALAlgorithm(NAME, DESCRIPTION, HELP_URL), m_oWriter(JSONPrint, this)
29 : {
30 10 : AddProgressArg();
31 :
32 20 : auto &arg = AddArg("filename", 0, _("File or directory name"), &m_filename)
33 10 : .SetPositional()
34 10 : .SetRequired();
35 10 : SetAutoCompleteFunctionForFilename(arg, 0);
36 :
37 10 : AddOutputFormatArg(&m_format).SetDefault("json").SetChoices("json", "text");
38 :
39 : AddArg("recursive", 'r', _("Recursively scan files/folders for datasets"),
40 10 : &m_recursive);
41 :
42 : AddArg("force-recursive", 0,
43 : _("Recursively scan folders for datasets, forcing "
44 : "recursion in folders recognized as valid formats"),
45 10 : &m_forceRecursive);
46 :
47 : AddArg("report-failures", 0,
48 : _("Report failures if file type is unidentified"),
49 10 : &m_reportFailures);
50 :
51 10 : AddOutputStringArg(&m_output);
52 : AddArg(
53 : "stdout", 0,
54 : _("Directly output on stdout. If enabled, output-string will be empty"),
55 20 : &m_stdout)
56 10 : .SetHiddenForCLI();
57 10 : }
58 :
59 : /************************************************************************/
60 : /* GDALDatasetIdentifyAlgorithm::Print() */
61 : /************************************************************************/
62 :
63 956 : void GDALDatasetIdentifyAlgorithm::Print(const char *str)
64 : {
65 956 : if (m_stdout)
66 21 : fwrite(str, 1, strlen(str), stdout);
67 : else
68 935 : m_output += str;
69 956 : }
70 :
71 : /************************************************************************/
72 : /* GDALDatasetIdentifyAlgorithm::JSONPrint() */
73 : /************************************************************************/
74 :
75 954 : /* static */ void GDALDatasetIdentifyAlgorithm::JSONPrint(const char *pszTxt,
76 : void *pUserData)
77 : {
78 954 : static_cast<GDALDatasetIdentifyAlgorithm *>(pUserData)->Print(pszTxt);
79 954 : }
80 :
81 : /************************************************************************/
82 : /* Process() */
83 : /************************************************************************/
84 :
85 70 : bool GDALDatasetIdentifyAlgorithm::Process(const char *pszTarget,
86 : CSLConstList papszSiblingList,
87 : GDALProgressFunc pfnProgress,
88 : void *pProgressData)
89 :
90 : {
91 70 : GDALDriverH hDriver = nullptr;
92 : {
93 70 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
94 70 : hDriver = GDALIdentifyDriver(pszTarget, papszSiblingList);
95 : }
96 :
97 70 : if (m_format == "json")
98 : {
99 68 : if (hDriver)
100 : {
101 51 : m_oWriter.StartObj();
102 51 : m_oWriter.AddObjKey("name");
103 51 : m_oWriter.Add(pszTarget);
104 51 : m_oWriter.AddObjKey("driver");
105 51 : m_oWriter.Add(GDALGetDriverShortName(hDriver));
106 51 : m_oWriter.EndObj();
107 : }
108 17 : else if (m_reportFailures)
109 : {
110 1 : m_oWriter.StartObj();
111 1 : m_oWriter.AddObjKey("name");
112 1 : m_oWriter.Add(pszTarget);
113 1 : m_oWriter.AddObjKey("driver");
114 1 : m_oWriter.AddNull();
115 1 : m_oWriter.EndObj();
116 : }
117 : }
118 : else
119 : {
120 2 : if (hDriver)
121 1 : Print(CPLSPrintf("%s: %s\n", pszTarget,
122 : GDALGetDriverShortName(hDriver)));
123 1 : else if (m_reportFailures)
124 1 : Print(CPLSPrintf("%s: unrecognized\n", pszTarget));
125 : }
126 :
127 70 : bool ret = true;
128 : VSIStatBufL sStatBuf;
129 8 : if ((m_forceRecursive || (m_recursive && hDriver == nullptr)) &&
130 78 : VSIStatL(pszTarget, &sStatBuf) == 0 && VSI_ISDIR(sStatBuf.st_mode))
131 : {
132 2 : const CPLStringList aosSiblingList(VSIReadDir(pszTarget));
133 1 : int i = 0;
134 64 : for (const char *pszSubTarget : cpl::Iterate(aosSiblingList))
135 : {
136 63 : if (!(EQUAL(pszSubTarget, "..") || EQUAL(pszSubTarget, ".")))
137 : {
138 : const std::string osSubTarget =
139 122 : CPLFormFilenameSafe(pszTarget, pszSubTarget, nullptr);
140 :
141 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
142 : pScaledProgress(
143 : GDALCreateScaledProgress(
144 122 : static_cast<double>(i) / aosSiblingList.size(),
145 122 : static_cast<double>(i + 1) / aosSiblingList.size(),
146 : pfnProgress, pProgressData),
147 61 : GDALDestroyScaledProgress);
148 122 : ret = ret &&
149 122 : Process(osSubTarget.c_str(), aosSiblingList.List(),
150 61 : pScaledProgress ? GDALScaledProgress : nullptr,
151 : pScaledProgress.get());
152 : }
153 63 : ++i;
154 : }
155 : }
156 :
157 70 : return ret && (!pfnProgress || pfnProgress(1.0, "", pProgressData));
158 : }
159 :
160 : /************************************************************************/
161 : /* GDALDatasetIdentifyAlgorithm::RunImpl() */
162 : /************************************************************************/
163 :
164 8 : bool GDALDatasetIdentifyAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
165 : void *pProgressData)
166 : {
167 8 : if (m_format == "json")
168 6 : m_oWriter.StartArray();
169 8 : int i = 0;
170 8 : bool ret = true;
171 17 : for (const std::string &osPath : m_filename)
172 : {
173 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
174 : pScaledProgress(GDALCreateScaledProgress(
175 9 : static_cast<double>(i) /
176 9 : static_cast<int>(m_filename.size()),
177 9 : static_cast<double>(i + 1) /
178 9 : static_cast<int>(m_filename.size()),
179 : pfnProgress, pProgressData),
180 9 : GDALDestroyScaledProgress);
181 18 : ret = ret && Process(osPath.c_str(), nullptr,
182 9 : pScaledProgress ? GDALScaledProgress : nullptr,
183 : pScaledProgress.get());
184 9 : ++i;
185 : }
186 8 : if (m_format == "json")
187 6 : m_oWriter.EndArray();
188 :
189 8 : return ret;
190 : }
191 :
192 : //! @endcond
|