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).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 954 : void GDALDatasetIdentifyAlgorithm::Print(const char *str)
64 : {
65 954 : if (m_stdout)
66 1 : fwrite(str, 1, strlen(str), stdout);
67 : else
68 953 : m_output += str;
69 954 : }
70 :
71 : /************************************************************************/
72 : /* GDALDatasetIdentifyAlgorithm::JSONPrint() */
73 : /************************************************************************/
74 :
75 951 : /* static */ void GDALDatasetIdentifyAlgorithm::JSONPrint(const char *pszTxt,
76 : void *pUserData)
77 : {
78 951 : static_cast<GDALDatasetIdentifyAlgorithm *>(pUserData)->Print(pszTxt);
79 951 : }
80 :
81 : /************************************************************************/
82 : /* Process() */
83 : /************************************************************************/
84 :
85 71 : bool GDALDatasetIdentifyAlgorithm::Process(const char *pszTarget,
86 : CSLConstList papszSiblingList,
87 : GDALProgressFunc pfnProgress,
88 : void *pProgressData)
89 :
90 : {
91 71 : if (IsCalledFromCommandLine())
92 1 : pfnProgress = nullptr;
93 :
94 71 : if (m_format.empty())
95 0 : m_format = IsCalledFromCommandLine() ? "text" : "json";
96 :
97 71 : GDALDriverH hDriver = nullptr;
98 : {
99 71 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
100 71 : hDriver = GDALIdentifyDriver(pszTarget, papszSiblingList);
101 : }
102 :
103 71 : if (m_format == "json")
104 : {
105 68 : if (hDriver)
106 : {
107 51 : m_oWriter.StartObj();
108 51 : m_oWriter.AddObjKey("name");
109 51 : m_oWriter.Add(pszTarget);
110 51 : m_oWriter.AddObjKey("driver");
111 51 : m_oWriter.Add(GDALGetDriverShortName(hDriver));
112 51 : m_oWriter.EndObj();
113 : }
114 17 : else if (m_reportFailures)
115 : {
116 1 : m_oWriter.StartObj();
117 1 : m_oWriter.AddObjKey("name");
118 1 : m_oWriter.Add(pszTarget);
119 1 : m_oWriter.AddObjKey("driver");
120 1 : m_oWriter.AddNull();
121 1 : m_oWriter.EndObj();
122 : }
123 : }
124 : else
125 : {
126 3 : if (hDriver)
127 2 : Print(CPLSPrintf("%s: %s\n", pszTarget,
128 : GDALGetDriverShortName(hDriver)));
129 1 : else if (m_reportFailures)
130 1 : Print(CPLSPrintf("%s: unrecognized\n", pszTarget));
131 : }
132 :
133 71 : bool ret = true;
134 : VSIStatBufL sStatBuf;
135 8 : if ((m_forceRecursive || (m_recursive && hDriver == nullptr)) &&
136 79 : VSIStatL(pszTarget, &sStatBuf) == 0 && VSI_ISDIR(sStatBuf.st_mode))
137 : {
138 2 : const CPLStringList aosSiblingList(VSIReadDir(pszTarget));
139 1 : const int nListSize = aosSiblingList.size();
140 65 : for (int i = 0; i < nListSize; ++i)
141 : {
142 64 : const char *pszSubTarget = aosSiblingList[i];
143 64 : if (!(EQUAL(pszSubTarget, "..") || EQUAL(pszSubTarget, ".")))
144 : {
145 : const std::string osSubTarget =
146 124 : CPLFormFilenameSafe(pszTarget, pszSubTarget, nullptr);
147 :
148 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
149 : pScaledProgress(GDALCreateScaledProgress(
150 62 : static_cast<double>(i) / nListSize,
151 62 : static_cast<double>(i + 1) / nListSize,
152 : pfnProgress, pProgressData),
153 62 : GDALDestroyScaledProgress);
154 124 : ret = ret &&
155 124 : Process(osSubTarget.c_str(), aosSiblingList.List(),
156 62 : pScaledProgress ? GDALScaledProgress : nullptr,
157 : pScaledProgress.get());
158 : }
159 : }
160 : }
161 :
162 71 : return ret && (!pfnProgress || pfnProgress(1.0, "", pProgressData));
163 : }
164 :
165 : /************************************************************************/
166 : /* GDALDatasetIdentifyAlgorithm::RunImpl() */
167 : /************************************************************************/
168 :
169 8 : bool GDALDatasetIdentifyAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
170 : void *pProgressData)
171 : {
172 8 : if (m_format.empty())
173 6 : m_format = IsCalledFromCommandLine() ? "text" : "json";
174 :
175 8 : if (m_format == "json")
176 5 : m_oWriter.StartArray();
177 8 : int i = 0;
178 8 : bool ret = true;
179 17 : for (const std::string &osPath : m_filename)
180 : {
181 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
182 : pScaledProgress(GDALCreateScaledProgress(
183 9 : static_cast<double>(i) /
184 9 : static_cast<int>(m_filename.size()),
185 9 : static_cast<double>(i + 1) /
186 9 : static_cast<int>(m_filename.size()),
187 : pfnProgress, pProgressData),
188 9 : GDALDestroyScaledProgress);
189 18 : ret = ret && Process(osPath.c_str(), nullptr,
190 9 : pScaledProgress ? GDALScaledProgress : nullptr,
191 : pScaledProgress.get());
192 9 : ++i;
193 : }
194 8 : if (m_format == "json")
195 5 : m_oWriter.EndArray();
196 :
197 8 : return ret;
198 : }
199 :
200 : //! @endcond
|