Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: gdal "vector pipeline" 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_vector_pipeline.h"
14 : #include "gdalalg_materialize.h"
15 : #include "gdalalg_vector_read.h"
16 : #include "gdalalg_vector_buffer.h"
17 : #include "gdalalg_vector_check_coverage.h"
18 : #include "gdalalg_vector_check_geometry.h"
19 : #include "gdalalg_vector_clean_coverage.h"
20 : #include "gdalalg_vector_clip.h"
21 : #include "gdalalg_vector_concat.h"
22 : #include "gdalalg_vector_edit.h"
23 : #include "gdalalg_vector_explode_collections.h"
24 : #include "gdalalg_vector_filter.h"
25 : #include "gdalalg_vector_geom.h"
26 : #include "gdalalg_vector_info.h"
27 : #include "gdalalg_vector_limit.h"
28 : #include "gdalalg_vector_make_point.h"
29 : #include "gdalalg_vector_make_valid.h"
30 : #include "gdalalg_vector_partition.h"
31 : #include "gdalalg_vector_reproject.h"
32 : #include "gdalalg_vector_segmentize.h"
33 : #include "gdalalg_vector_select.h"
34 : #include "gdalalg_vector_set_field_type.h"
35 : #include "gdalalg_vector_set_geom_type.h"
36 : #include "gdalalg_vector_simplify.h"
37 : #include "gdalalg_vector_simplify_coverage.h"
38 : #include "gdalalg_vector_sql.h"
39 : #include "gdalalg_vector_swap_xy.h"
40 : #include "gdalalg_vector_write.h"
41 : #include "gdalalg_tee.h"
42 :
43 : #include "../frmts/mem/memdataset.h"
44 :
45 : #include "cpl_conv.h"
46 : #include "cpl_string.h"
47 :
48 : #include <algorithm>
49 : #include <cassert>
50 :
51 : //! @cond Doxygen_Suppress
52 :
53 : #ifndef _
54 : #define _(x) (x)
55 : #endif
56 :
57 : GDALVectorAlgorithmStepRegistry::~GDALVectorAlgorithmStepRegistry() = default;
58 :
59 : /************************************************************************/
60 : /* GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm() */
61 : /************************************************************************/
62 :
63 1859 : GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm(
64 : const std::string &name, const std::string &description,
65 1859 : const std::string &helpURL, bool standaloneStep)
66 : : GDALVectorPipelineStepAlgorithm(
67 : name, description, helpURL,
68 1859 : ConstructorOptions().SetStandaloneStep(standaloneStep))
69 : {
70 1859 : }
71 :
72 : /************************************************************************/
73 : /* GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm() */
74 : /************************************************************************/
75 :
76 2268 : GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm(
77 : const std::string &name, const std::string &description,
78 2268 : const std::string &helpURL, const ConstructorOptions &options)
79 2268 : : GDALPipelineStepAlgorithm(name, description, helpURL, options)
80 : {
81 2268 : if (m_standaloneStep)
82 : {
83 437 : m_supportsStreamedOutput = true;
84 :
85 437 : if (m_constructorOptions.addDefaultArguments)
86 : {
87 328 : AddVectorInputArgs(false);
88 328 : AddProgressArg();
89 328 : AddVectorOutputArgs(false, false);
90 : }
91 : }
92 2268 : }
93 :
94 : GDALVectorPipelineStepAlgorithm::~GDALVectorPipelineStepAlgorithm() = default;
95 :
96 : /************************************************************************/
97 : /* GDALVectorPipelineAlgorithm::GDALVectorPipelineAlgorithm() */
98 : /************************************************************************/
99 :
100 94 : GDALVectorPipelineAlgorithm::GDALVectorPipelineAlgorithm()
101 : : GDALAbstractPipelineAlgorithm(
102 : NAME, DESCRIPTION, HELP_URL,
103 94 : ConstructorOptions().SetInputDatasetMaxCount(INT_MAX))
104 : {
105 94 : m_supportsStreamedOutput = true;
106 :
107 94 : AddVectorInputArgs(/* hiddenForCLI = */ true);
108 94 : AddProgressArg();
109 188 : AddArg("pipeline", 0, _("Pipeline string"), &m_pipeline)
110 94 : .SetHiddenForCLI()
111 94 : .SetPositional();
112 94 : AddVectorOutputArgs(/* hiddenForCLI = */ true,
113 : /* shortNameOutputLayerAllowed=*/false);
114 :
115 94 : AddOutputStringArg(&m_output).SetHiddenForCLI();
116 94 : AddStdoutArg(&m_stdout);
117 :
118 94 : RegisterAlgorithms(m_stepRegistry, false);
119 94 : }
120 :
121 : /************************************************************************/
122 : /* GDALVectorPipelineAlgorithm::RegisterAlgorithms() */
123 : /************************************************************************/
124 :
125 : /* static */
126 285 : void GDALVectorPipelineAlgorithm::RegisterAlgorithms(
127 : GDALVectorAlgorithmStepRegistry ®istry, bool forMixedPipeline)
128 : {
129 285 : GDALAlgorithmRegistry::AlgInfo algInfo;
130 :
131 : const auto addSuffixIfNeeded =
132 2565 : [forMixedPipeline](const char *name) -> std::string
133 : {
134 4284 : return forMixedPipeline ? std::string(name).append(VECTOR_SUFFIX)
135 6849 : : std::string(name);
136 285 : };
137 :
138 285 : registry.Register<GDALVectorReadAlgorithm>(
139 570 : addSuffixIfNeeded(GDALVectorReadAlgorithm::NAME));
140 :
141 285 : registry.Register<GDALVectorWriteAlgorithm>(
142 570 : addSuffixIfNeeded(GDALVectorWriteAlgorithm::NAME));
143 :
144 285 : registry.Register<GDALVectorInfoAlgorithm>(
145 570 : addSuffixIfNeeded(GDALVectorInfoAlgorithm::NAME));
146 :
147 285 : registry.Register<GDALVectorBufferAlgorithm>();
148 285 : registry.Register<GDALVectorCheckCoverageAlgorithm>();
149 285 : registry.Register<GDALVectorCheckGeometryAlgorithm>();
150 285 : registry.Register<GDALVectorConcatAlgorithm>();
151 285 : registry.Register<GDALVectorCleanCoverageAlgorithm>();
152 :
153 285 : registry.Register<GDALVectorClipAlgorithm>(
154 570 : addSuffixIfNeeded(GDALVectorClipAlgorithm::NAME));
155 :
156 285 : registry.Register<GDALVectorEditAlgorithm>(
157 570 : addSuffixIfNeeded(GDALVectorEditAlgorithm::NAME));
158 :
159 285 : registry.Register<GDALVectorExplodeCollectionsAlgorithm>();
160 :
161 285 : registry.Register<GDALMaterializeVectorAlgorithm>(
162 570 : addSuffixIfNeeded(GDALMaterializeVectorAlgorithm::NAME));
163 :
164 285 : registry.Register<GDALVectorReprojectAlgorithm>(
165 570 : addSuffixIfNeeded(GDALVectorReprojectAlgorithm::NAME));
166 :
167 285 : registry.Register<GDALVectorFilterAlgorithm>();
168 285 : registry.Register<GDALVectorGeomAlgorithm>();
169 285 : registry.Register<GDALVectorLimitAlgorithm>();
170 285 : registry.Register<GDALVectorMakePointAlgorithm>();
171 285 : registry.Register<GDALVectorMakeValidAlgorithm>();
172 285 : registry.Register<GDALVectorPartitionAlgorithm>();
173 285 : registry.Register<GDALVectorSegmentizeAlgorithm>();
174 :
175 285 : registry.Register<GDALVectorSelectAlgorithm>(
176 570 : addSuffixIfNeeded(GDALVectorSelectAlgorithm::NAME));
177 :
178 285 : registry.Register<GDALVectorSetFieldTypeAlgorithm>();
179 285 : registry.Register<GDALVectorSetGeomTypeAlgorithm>();
180 285 : registry.Register<GDALVectorSimplifyAlgorithm>();
181 285 : registry.Register<GDALVectorSimplifyCoverageAlgorithm>();
182 285 : registry.Register<GDALVectorSQLAlgorithm>();
183 285 : registry.Register<GDALVectorSwapXYAlgorithm>();
184 :
185 285 : registry.Register<GDALTeeVectorAlgorithm>(
186 570 : addSuffixIfNeeded(GDALTeeVectorAlgorithm::NAME));
187 285 : }
188 :
189 : /************************************************************************/
190 : /* GDALVectorPipelineAlgorithm::GetUsageForCLI() */
191 : /************************************************************************/
192 :
193 8 : std::string GDALVectorPipelineAlgorithm::GetUsageForCLI(
194 : bool shortUsage, const UsageOptions &usageOptions) const
195 : {
196 8 : UsageOptions stepUsageOptions;
197 8 : stepUsageOptions.isPipelineStep = true;
198 :
199 8 : if (!m_helpDocCategory.empty() && m_helpDocCategory != "main")
200 : {
201 4 : auto alg = GetStepAlg(m_helpDocCategory);
202 2 : if (alg)
203 : {
204 2 : alg->SetCallPath({m_helpDocCategory});
205 1 : alg->GetArg("help-doc")->Set(true);
206 1 : return alg->GetUsageForCLI(shortUsage, stepUsageOptions);
207 : }
208 : else
209 : {
210 1 : fprintf(stderr, "ERROR: unknown pipeline step '%s'\n",
211 : m_helpDocCategory.c_str());
212 : return CPLSPrintf("ERROR: unknown pipeline step '%s'\n",
213 1 : m_helpDocCategory.c_str());
214 : }
215 : }
216 :
217 6 : UsageOptions usageOptionsMain(usageOptions);
218 6 : usageOptionsMain.isPipelineMain = true;
219 : std::string ret =
220 12 : GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptionsMain);
221 6 : if (shortUsage)
222 2 : return ret;
223 :
224 : ret += "\n<PIPELINE> is of the form: read|concat [READ-OPTIONS] "
225 4 : "( ! <STEP-NAME> [STEP-OPTIONS] )* ! write|info [WRITE-OPTIONS]\n";
226 :
227 4 : if (m_helpDocCategory == "main")
228 : {
229 1 : return ret;
230 : }
231 :
232 3 : ret += '\n';
233 3 : ret += "Example: 'gdal vector pipeline --progress ! read in.gpkg ! \\\n";
234 3 : ret += " reproject --dst-crs=EPSG:32632 ! ";
235 3 : ret += "write out.gpkg --overwrite'\n";
236 3 : ret += '\n';
237 3 : ret += "Potential steps are:\n";
238 :
239 87 : for (const std::string &name : m_stepRegistry.GetNames())
240 : {
241 168 : auto alg = GetStepAlg(name);
242 84 : assert(alg);
243 84 : auto [options, maxOptLen] = alg->GetArgNamesForCLI();
244 84 : stepUsageOptions.maxOptLen =
245 84 : std::max(stepUsageOptions.maxOptLen, maxOptLen);
246 : }
247 :
248 : {
249 3 : const auto name = GDALVectorReadAlgorithm::NAME;
250 3 : ret += '\n';
251 6 : auto alg = GetStepAlg(name);
252 6 : alg->SetCallPath({name});
253 3 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
254 : }
255 87 : for (const std::string &name : m_stepRegistry.GetNames())
256 : {
257 168 : auto alg = GetStepAlg(name);
258 84 : assert(alg);
259 90 : if (alg->CanBeFirstStep() && !alg->CanBeMiddleStep() &&
260 90 : !alg->IsHidden() && name != GDALVectorReadAlgorithm::NAME)
261 : {
262 3 : ret += '\n';
263 6 : alg->SetCallPath({name});
264 3 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
265 : }
266 : }
267 87 : for (const std::string &name : m_stepRegistry.GetNames())
268 : {
269 168 : auto alg = GetStepAlg(name);
270 84 : assert(alg);
271 84 : if (alg->CanBeMiddleStep() && !alg->IsHidden())
272 : {
273 66 : ret += '\n';
274 132 : alg->SetCallPath({name});
275 66 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
276 : }
277 : }
278 87 : for (const std::string &name : m_stepRegistry.GetNames())
279 : {
280 168 : auto alg = GetStepAlg(name);
281 84 : assert(alg);
282 96 : if (alg->CanBeLastStep() && !alg->CanBeMiddleStep() &&
283 96 : !alg->IsHidden() && name != GDALVectorWriteAlgorithm::NAME)
284 : {
285 6 : ret += '\n';
286 12 : alg->SetCallPath({name});
287 6 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
288 : }
289 : }
290 : {
291 3 : const auto name = GDALVectorWriteAlgorithm::NAME;
292 3 : ret += '\n';
293 6 : auto alg = GetStepAlg(name);
294 6 : alg->SetCallPath({name});
295 3 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
296 : }
297 :
298 3 : ret += GetUsageForCLIEnd();
299 :
300 3 : return ret;
301 : }
302 :
303 : /************************************************************************/
304 : /* GDALVectorPipelineOutputLayer */
305 : /************************************************************************/
306 :
307 : /************************************************************************/
308 : /* GDALVectorPipelineOutputLayer() */
309 : /************************************************************************/
310 :
311 180 : GDALVectorPipelineOutputLayer::GDALVectorPipelineOutputLayer(OGRLayer &srcLayer)
312 180 : : m_srcLayer(srcLayer)
313 : {
314 180 : }
315 :
316 : /************************************************************************/
317 : /* ~GDALVectorPipelineOutputLayer() */
318 : /************************************************************************/
319 :
320 : GDALVectorPipelineOutputLayer::~GDALVectorPipelineOutputLayer() = default;
321 :
322 : /************************************************************************/
323 : /* GDALVectorPipelineOutputLayer::ResetReading() */
324 : /************************************************************************/
325 :
326 578 : void GDALVectorPipelineOutputLayer::ResetReading()
327 : {
328 578 : m_srcLayer.ResetReading();
329 578 : m_pendingFeatures.clear();
330 578 : m_idxInPendingFeatures = 0;
331 578 : }
332 :
333 : /************************************************************************/
334 : /* GDALVectorPipelineOutputLayer::GetNextRawFeature() */
335 : /************************************************************************/
336 :
337 2334 : OGRFeature *GDALVectorPipelineOutputLayer::GetNextRawFeature()
338 : {
339 2334 : if (m_idxInPendingFeatures < m_pendingFeatures.size())
340 : {
341 : OGRFeature *poFeature =
342 14 : m_pendingFeatures[m_idxInPendingFeatures].release();
343 14 : ++m_idxInPendingFeatures;
344 14 : return poFeature;
345 : }
346 2320 : m_pendingFeatures.clear();
347 2320 : m_idxInPendingFeatures = 0;
348 : while (true)
349 : {
350 : auto poSrcFeature =
351 2329 : std::unique_ptr<OGRFeature>(m_srcLayer.GetNextFeature());
352 2329 : if (!poSrcFeature)
353 263 : return nullptr;
354 2066 : TranslateFeature(std::move(poSrcFeature), m_pendingFeatures);
355 2066 : if (m_translateError)
356 : {
357 7 : return nullptr;
358 : }
359 2059 : if (!m_pendingFeatures.empty())
360 2050 : break;
361 9 : }
362 2050 : OGRFeature *poFeature = m_pendingFeatures[0].release();
363 2050 : m_idxInPendingFeatures = 1;
364 2050 : return poFeature;
365 : }
366 :
367 : /************************************************************************/
368 : /* GDALVectorOutputDataset */
369 : /************************************************************************/
370 :
371 15 : int GDALVectorOutputDataset::TestCapability(const char *) const
372 : {
373 15 : return 0;
374 : }
375 :
376 : /************************************************************************/
377 : /* GDALVectorPipelineOutputDataset */
378 : /************************************************************************/
379 :
380 : /************************************************************************/
381 : /* GDALVectorPipelineOutputDataset() */
382 : /************************************************************************/
383 :
384 171 : GDALVectorPipelineOutputDataset::GDALVectorPipelineOutputDataset(
385 171 : GDALDataset &srcDS)
386 171 : : m_srcDS(srcDS)
387 : {
388 171 : SetDescription(m_srcDS.GetDescription());
389 171 : SetMetadata(m_srcDS.GetMetadata());
390 171 : }
391 :
392 : /************************************************************************/
393 : /* GDALVectorPipelineOutputDataset::AddLayer() */
394 : /************************************************************************/
395 :
396 182 : void GDALVectorPipelineOutputDataset::AddLayer(
397 : OGRLayer &oSrcLayer,
398 : std::unique_ptr<OGRLayerWithTranslateFeature> poNewLayer)
399 : {
400 182 : m_layersToDestroy.push_back(std::move(poNewLayer));
401 : OGRLayerWithTranslateFeature *poNewLayerRaw =
402 182 : m_layersToDestroy.back().get();
403 182 : m_layers.push_back(poNewLayerRaw);
404 182 : m_mapSrcLayerToNewLayer[&oSrcLayer] = poNewLayerRaw;
405 182 : }
406 :
407 : /************************************************************************/
408 : /* GDALVectorPipelineOutputDataset::GetLayerCount() */
409 : /************************************************************************/
410 :
411 569 : int GDALVectorPipelineOutputDataset::GetLayerCount() const
412 : {
413 569 : return static_cast<int>(m_layers.size());
414 : }
415 :
416 : /************************************************************************/
417 : /* GDALVectorPipelineOutputDataset::GetLayer() */
418 : /************************************************************************/
419 :
420 264 : OGRLayer *GDALVectorPipelineOutputDataset::GetLayer(int idx) const
421 : {
422 264 : return idx >= 0 && idx < GetLayerCount() ? m_layers[idx] : nullptr;
423 : }
424 :
425 : /************************************************************************/
426 : /* GDALVectorPipelineOutputDataset::TestCapability() */
427 : /************************************************************************/
428 :
429 125 : int GDALVectorPipelineOutputDataset::TestCapability(const char *pszCap) const
430 : {
431 125 : if (EQUAL(pszCap, ODsCRandomLayerRead) ||
432 31 : EQUAL(pszCap, ODsCMeasuredGeometries) || EQUAL(pszCap, ODsCZGeometries))
433 : {
434 109 : return m_srcDS.TestCapability(pszCap);
435 : }
436 16 : return false;
437 : }
438 :
439 : /************************************************************************/
440 : /* GDALVectorPipelineOutputDataset::ResetReading() */
441 : /************************************************************************/
442 :
443 3 : void GDALVectorPipelineOutputDataset::ResetReading()
444 : {
445 3 : m_srcDS.ResetReading();
446 3 : m_pendingFeatures.clear();
447 3 : m_idxInPendingFeatures = 0;
448 3 : }
449 :
450 : /************************************************************************/
451 : /* GDALVectorPipelineOutputDataset::GetNextFeature() */
452 : /************************************************************************/
453 :
454 23 : OGRFeature *GDALVectorPipelineOutputDataset::GetNextFeature(
455 : OGRLayer **ppoBelongingLayer, double *pdfProgressPct,
456 : GDALProgressFunc pfnProgress, void *pProgressData)
457 : {
458 23 : if (m_idxInPendingFeatures < m_pendingFeatures.size())
459 : {
460 : OGRFeature *poFeature =
461 3 : m_pendingFeatures[m_idxInPendingFeatures].release();
462 3 : if (ppoBelongingLayer)
463 3 : *ppoBelongingLayer = m_belongingLayer;
464 3 : ++m_idxInPendingFeatures;
465 3 : return poFeature;
466 : }
467 :
468 20 : m_pendingFeatures.clear();
469 20 : m_idxInPendingFeatures = 0;
470 :
471 : while (true)
472 : {
473 20 : OGRLayer *poSrcBelongingLayer = nullptr;
474 20 : auto poSrcFeature = std::unique_ptr<OGRFeature>(m_srcDS.GetNextFeature(
475 20 : &poSrcBelongingLayer, pdfProgressPct, pfnProgress, pProgressData));
476 20 : if (!poSrcFeature)
477 3 : return nullptr;
478 17 : auto iterToDstLayer = m_mapSrcLayerToNewLayer.find(poSrcBelongingLayer);
479 17 : if (iterToDstLayer != m_mapSrcLayerToNewLayer.end())
480 : {
481 17 : m_belongingLayer = iterToDstLayer->second;
482 17 : m_belongingLayer->TranslateFeature(std::move(poSrcFeature),
483 17 : m_pendingFeatures);
484 :
485 17 : if (!m_pendingFeatures.empty())
486 17 : break;
487 : }
488 0 : }
489 17 : OGRFeature *poFeature = m_pendingFeatures[0].release();
490 17 : if (ppoBelongingLayer)
491 17 : *ppoBelongingLayer = m_belongingLayer;
492 17 : m_idxInPendingFeatures = 1;
493 17 : return poFeature;
494 : }
495 :
496 : /************************************************************************/
497 : /* GDALVectorPipelinePassthroughLayer::GetLayerDefn() */
498 : /************************************************************************/
499 :
500 33 : const OGRFeatureDefn *GDALVectorPipelinePassthroughLayer::GetLayerDefn() const
501 : {
502 33 : return m_srcLayer.GetLayerDefn();
503 : }
504 :
505 : /************************************************************************/
506 : /* GDALVectorNonStreamingAlgorithmDataset() */
507 : /************************************************************************/
508 :
509 30 : GDALVectorNonStreamingAlgorithmDataset::GDALVectorNonStreamingAlgorithmDataset()
510 30 : : m_ds(MEMDataset::Create("", 0, 0, 0, GDT_Unknown, nullptr))
511 : {
512 30 : }
513 :
514 : /************************************************************************/
515 : /* ~GDALVectorNonStreamingAlgorithmDataset() */
516 : /************************************************************************/
517 :
518 : GDALVectorNonStreamingAlgorithmDataset::
519 : ~GDALVectorNonStreamingAlgorithmDataset() = default;
520 :
521 : /************************************************************************/
522 : /* GDALVectorNonStreamingAlgorithmDataset::AddProcessedLayer() */
523 : /************************************************************************/
524 :
525 26 : bool GDALVectorNonStreamingAlgorithmDataset::AddProcessedLayer(
526 : OGRLayer &srcLayer, OGRFeatureDefn &dstDefn)
527 : {
528 26 : CPLStringList aosOptions;
529 26 : if (srcLayer.TestCapability(OLCStringsAsUTF8))
530 : {
531 1 : aosOptions.AddNameValue("ADVERTIZE_UTF8", "TRUE");
532 : }
533 :
534 26 : OGRMemLayer *poDstLayer = m_ds->CreateLayer(dstDefn, aosOptions.List());
535 26 : m_layers.push_back(poDstLayer);
536 :
537 26 : const bool bRet = Process(srcLayer, *poDstLayer);
538 26 : poDstLayer->SetUpdatable(false);
539 52 : return bRet;
540 : }
541 :
542 20 : bool GDALVectorNonStreamingAlgorithmDataset::AddProcessedLayer(
543 : OGRLayer &srcLayer)
544 : {
545 20 : return AddProcessedLayer(srcLayer, *srcLayer.GetLayerDefn());
546 : }
547 :
548 : /************************************************************************/
549 : /* GDALVectorNonStreamingAlgorithmDataset::AddPassThroughLayer() */
550 : /************************************************************************/
551 :
552 6 : void GDALVectorNonStreamingAlgorithmDataset::AddPassThroughLayer(
553 : OGRLayer &oLayer)
554 : {
555 6 : m_passthrough_layers.push_back(
556 12 : std::make_unique<GDALVectorPipelinePassthroughLayer>(oLayer));
557 6 : m_layers.push_back(m_passthrough_layers.back().get());
558 6 : }
559 :
560 : /************************************************************************/
561 : /* GDALVectorNonStreamingAlgorithmDataset::GetLayerCount() */
562 : /************************************************************************/
563 :
564 74 : int GDALVectorNonStreamingAlgorithmDataset::GetLayerCount() const
565 : {
566 74 : return static_cast<int>(m_layers.size());
567 : }
568 :
569 : /************************************************************************/
570 : /* GDALVectorNonStreamingAlgorithmDataset::GetLayer() */
571 : /************************************************************************/
572 :
573 73 : OGRLayer *GDALVectorNonStreamingAlgorithmDataset::GetLayer(int idx) const
574 : {
575 73 : if (idx < 0 || idx >= static_cast<int>(m_layers.size()))
576 : {
577 4 : return nullptr;
578 : }
579 69 : return m_layers[idx];
580 : }
581 :
582 : /************************************************************************/
583 : /* GDALVectorNonStreamingAlgorithmDataset::TestCapability() */
584 : /************************************************************************/
585 :
586 18 : int GDALVectorNonStreamingAlgorithmDataset::TestCapability(
587 : const char *pszCap) const
588 : {
589 18 : if (EQUAL(pszCap, ODsCCreateLayer) || EQUAL(pszCap, ODsCDeleteLayer))
590 : {
591 4 : return false;
592 : }
593 :
594 14 : return m_ds->TestCapability(pszCap);
595 : }
596 :
597 : //! @endcond
|