Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: GDAL Algorithm driver
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 "cpl_json.h"
14 : #include "cpl_string.h"
15 :
16 : #include "gdalalgorithm.h"
17 : #include "gdal_proxy.h"
18 : #include "gdal_priv.h"
19 :
20 : /************************************************************************/
21 : /* GDALGDataset */
22 : /************************************************************************/
23 :
24 : class GDALGDataset final : public GDALProxyDataset
25 : {
26 : public:
27 : GDALGDataset(const std::string &filename,
28 : std::unique_ptr<GDALAlgorithm> poAlg, GDALDataset *poDS);
29 :
30 9 : char **GetFileList(void) override
31 : {
32 18 : CPLStringList aosList;
33 9 : if (!m_filename.empty())
34 8 : aosList.push_back(m_filename);
35 18 : return aosList.StealList();
36 : }
37 :
38 : static int Identify(GDALOpenInfo *poOpenInfo);
39 : static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
40 :
41 : protected:
42 31 : GDALDataset *RefUnderlyingDataset() const override
43 : {
44 31 : return m_poUnderlyingDS;
45 : }
46 :
47 31 : void UnrefUnderlyingDataset(GDALDataset *) const override
48 : {
49 31 : }
50 :
51 : private:
52 : const std::string m_filename;
53 : std::unique_ptr<GDALAlgorithm> m_poAlg{};
54 : GDALDataset *m_poUnderlyingDS = nullptr;
55 :
56 : CPL_DISALLOW_COPY_ASSIGN(GDALGDataset)
57 :
58 32 : GDALDriver *GetDriver() override
59 : {
60 32 : return poDriver;
61 : }
62 :
63 37 : int GetLayerCount() override
64 : {
65 37 : return m_poUnderlyingDS->GetLayerCount();
66 : }
67 :
68 19 : OGRLayer *GetLayer(int idx) override
69 : {
70 19 : return m_poUnderlyingDS->GetLayer(idx);
71 : }
72 :
73 7 : OGRLayer *GetLayerByName(const char *pszName) override
74 : {
75 7 : return m_poUnderlyingDS->GetLayerByName(pszName);
76 : }
77 :
78 37 : OGRLayer *ExecuteSQL(const char *pszStatement, OGRGeometry *poSpatialFilter,
79 : const char *pszDialect) override
80 : {
81 37 : return m_poUnderlyingDS->ExecuteSQL(pszStatement, poSpatialFilter,
82 37 : pszDialect);
83 : }
84 :
85 1 : void ResetReading() override
86 : {
87 1 : m_poUnderlyingDS->ResetReading();
88 1 : }
89 :
90 11 : OGRFeature *GetNextFeature(OGRLayer **ppoBelongingLayer,
91 : double *pdfProgressPct,
92 : GDALProgressFunc pfnProgress,
93 : void *pProgressData) override
94 : {
95 11 : return m_poUnderlyingDS->GetNextFeature(
96 11 : ppoBelongingLayer, pdfProgressPct, pfnProgress, pProgressData);
97 : }
98 :
99 48 : int TestCapability(const char *pszCap) override
100 : {
101 48 : return m_poUnderlyingDS->TestCapability(pszCap);
102 : }
103 : };
104 :
105 : /************************************************************************/
106 : /* GDALGRasterBand */
107 : /************************************************************************/
108 :
109 : class GDALGRasterBand final : public GDALProxyRasterBand
110 : {
111 : public:
112 : explicit GDALGRasterBand(GDALRasterBand *poUnderlyingBand);
113 :
114 : protected:
115 : GDALRasterBand *
116 777 : RefUnderlyingRasterBand(bool /* bForceOpen */) const override
117 : {
118 777 : return m_poUnderlyingBand;
119 : }
120 :
121 777 : void UnrefUnderlyingRasterBand(GDALRasterBand *) const override
122 : {
123 777 : }
124 :
125 : private:
126 : GDALRasterBand *m_poUnderlyingBand = nullptr;
127 :
128 : CPL_DISALLOW_COPY_ASSIGN(GDALGRasterBand)
129 : };
130 :
131 : /************************************************************************/
132 : /* GDALGDataset::GDALGDataset() */
133 : /************************************************************************/
134 :
135 31 : GDALGDataset::GDALGDataset(const std::string &filename,
136 : std::unique_ptr<GDALAlgorithm> poAlg,
137 31 : GDALDataset *poDS)
138 31 : : m_filename(filename), m_poAlg(std::move(poAlg)), m_poUnderlyingDS(poDS)
139 : {
140 31 : nRasterXSize = m_poUnderlyingDS->GetRasterXSize();
141 31 : nRasterYSize = m_poUnderlyingDS->GetRasterYSize();
142 51 : for (int i = 0; i < m_poUnderlyingDS->GetRasterCount(); ++i)
143 : {
144 20 : SetBand(i + 1, std::make_unique<GDALGRasterBand>(
145 40 : m_poUnderlyingDS->GetRasterBand(i + 1)));
146 : }
147 31 : }
148 :
149 : /************************************************************************/
150 : /* GDALGRasterBand::GDALGRasterBand() */
151 : /************************************************************************/
152 :
153 20 : GDALGRasterBand::GDALGRasterBand(GDALRasterBand *poUnderlyingBand)
154 20 : : m_poUnderlyingBand(poUnderlyingBand)
155 : {
156 20 : nBand = poUnderlyingBand->GetBand();
157 20 : eDataType = poUnderlyingBand->GetRasterDataType();
158 20 : nRasterXSize = poUnderlyingBand->GetXSize();
159 20 : nRasterYSize = poUnderlyingBand->GetYSize();
160 20 : poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
161 20 : }
162 :
163 : /************************************************************************/
164 : /* GDALGDataset::Identify() */
165 : /************************************************************************/
166 :
167 65817 : /* static */ int GDALGDataset::Identify(GDALOpenInfo *poOpenInfo)
168 : {
169 65817 : return poOpenInfo->IsSingleAllowedDriver("GDALG") ||
170 65815 : (poOpenInfo->pabyHeader &&
171 10768 : strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
172 131632 : "\"gdal_streamed_alg\"")) ||
173 131597 : (strstr(poOpenInfo->pszFilename, "\"gdal_streamed_alg\""));
174 : }
175 :
176 : /************************************************************************/
177 : /* GDALGDataset::Open() */
178 : /************************************************************************/
179 :
180 50 : /* static */ GDALDataset *GDALGDataset::Open(GDALOpenInfo *poOpenInfo)
181 : {
182 100 : CPLJSONDocument oDoc;
183 50 : if (poOpenInfo->pabyHeader)
184 : {
185 32 : if (!oDoc.Load(poOpenInfo->pszFilename))
186 : {
187 1 : return nullptr;
188 : }
189 : }
190 : else
191 : {
192 36 : if (!oDoc.LoadMemory(
193 18 : reinterpret_cast<const char *>(poOpenInfo->pszFilename)))
194 : {
195 1 : return nullptr;
196 : }
197 : }
198 48 : if (oDoc.GetRoot().GetString("type") != "gdal_streamed_alg")
199 : {
200 1 : CPLDebug("GDALG", "\"type\" = \"gdal_streamed_alg\" missing");
201 1 : return nullptr;
202 : }
203 :
204 47 : if (poOpenInfo->eAccess == GA_Update)
205 : {
206 1 : ReportUpdateNotSupportedByDriver("GDALG");
207 1 : return nullptr;
208 : }
209 :
210 138 : const std::string osCommandLine = oDoc.GetRoot().GetString("command_line");
211 46 : if (osCommandLine.empty())
212 : {
213 1 : CPLError(CE_Failure, CPLE_AppDefined, "command_line missing");
214 1 : return nullptr;
215 : }
216 :
217 11 : const auto CheckVersion = [&oDoc]()
218 : {
219 33 : const std::string osVersion = oDoc.GetRoot().GetString("gdal_version");
220 15 : if (!osVersion.empty() &&
221 4 : atoi(GDALVersionInfo("VERSION_NUM")) < atoi(osVersion.c_str()))
222 : {
223 1 : CPLError(CE_Failure, CPLE_AppDefined,
224 : "The failure might be due to the .gdalg.json file having "
225 : "been created with GDAL VERSION_NUM=%s which is newer "
226 : "than current GDAL VERSION_NUM=%s",
227 : osVersion.c_str(), GDALVersionInfo("VERSION_NUM"));
228 : }
229 11 : };
230 :
231 90 : const CPLStringList aosArgs(CSLTokenizeString(osCommandLine.c_str()));
232 :
233 45 : auto alg = GDALGlobalAlgorithmRegistry::GetSingleton().Instantiate(
234 135 : GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME);
235 :
236 75 : if (poOpenInfo->pabyHeader &&
237 75 : oDoc.GetRoot().GetBool("relative_paths_relative_to_this_file", true))
238 : {
239 54 : alg->SetReferencePathForRelativePaths(
240 36 : CPLGetPathSafe(poOpenInfo->pszFilename).c_str());
241 : }
242 :
243 45 : alg->SetExecutionForStreamedOutput();
244 :
245 90 : alg->SetCallPath(std::vector<std::string>{aosArgs[0]});
246 90 : std::vector<std::string> args;
247 329 : for (int i = 1; i < aosArgs.size(); ++i)
248 284 : args.push_back(aosArgs[i]);
249 45 : if (!alg->ParseCommandLineArguments(args))
250 : {
251 3 : CheckVersion();
252 3 : return nullptr;
253 : }
254 42 : if (!alg->GetActualAlgorithm().SupportsStreamedOutput())
255 : {
256 1 : CPLError(CE_Failure, CPLE_AppDefined,
257 : "Algorithm %s does not support a streamed output",
258 1 : alg->GetActualAlgorithm().GetName().c_str());
259 1 : return nullptr;
260 : }
261 :
262 41 : if (!alg->Run(nullptr, nullptr))
263 : {
264 8 : CheckVersion();
265 8 : return nullptr;
266 : }
267 :
268 33 : std::unique_ptr<GDALDataset> ret;
269 33 : const auto outputArg = alg->GetActualAlgorithm().GetArg("output");
270 33 : if (outputArg && outputArg->GetType() == GAAT_DATASET)
271 : {
272 33 : auto &val = outputArg->Get<GDALArgDatasetValue>();
273 33 : auto poUnderlyingDS = val.GetDatasetRef();
274 33 : if (poUnderlyingDS)
275 : {
276 33 : if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) &&
277 19 : !(poOpenInfo->nOpenFlags & GDAL_OF_VECTOR))
278 : {
279 : // Don't return if asked for a raster dataset but the
280 : // underlying one is not.
281 20 : if (poUnderlyingDS->GetRasterCount() == 0 &&
282 1 : !poUnderlyingDS->GetMetadata("SUBDATASETS"))
283 : {
284 2 : return nullptr;
285 : }
286 : }
287 14 : else if (!(poOpenInfo->nOpenFlags & GDAL_OF_RASTER) &&
288 14 : (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR))
289 : {
290 : // Don't return if asked for a vector dataset but the
291 : // underlying one is not.
292 14 : if (poUnderlyingDS->GetLayerCount() == 0)
293 : {
294 1 : return nullptr;
295 : }
296 : }
297 31 : ret = std::make_unique<GDALGDataset>(
298 62 : poOpenInfo->pabyHeader ? poOpenInfo->pszFilename : "",
299 62 : std::move(alg), poUnderlyingDS);
300 : }
301 : }
302 :
303 31 : return ret.release();
304 : }
305 :
306 : /************************************************************************/
307 : /* GDALRegister_GDALG() */
308 : /************************************************************************/
309 :
310 1889 : void GDALRegister_GDALG()
311 : {
312 1889 : if (GDALGetDriverByName("GDALG") != nullptr)
313 282 : return;
314 :
315 3214 : auto poDriver = std::make_unique<GDALDriver>();
316 :
317 1607 : poDriver->SetDescription("GDALG");
318 1607 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
319 1607 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
320 1607 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
321 1607 : "GDAL Streamed Algorithm driver");
322 1607 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "gdalg.json");
323 :
324 1607 : poDriver->SetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES, "YES");
325 1607 : poDriver->SetMetadataItem(GDAL_DCAP_CURVE_GEOMETRIES, "YES");
326 1607 : poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
327 :
328 1607 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
329 :
330 1607 : poDriver->pfnIdentify = GDALGDataset::Identify;
331 1607 : poDriver->pfnOpen = GDALGDataset::Open;
332 :
333 1607 : GetGDALDriverManager()->RegisterDriver(poDriver.release());
334 : }
|