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