Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Implementation of GDALDriver class (and C wrappers)
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1998, 2000, Frank Warmerdam
9 : * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "gdal.h"
16 : #include "gdal_priv.h"
17 : #include "gdal_rat.h"
18 : #include "gdalalgorithm.h"
19 : #include "gdal_known_connection_prefixes.h"
20 :
21 : #include <algorithm>
22 : #include <cerrno>
23 : #include <cstdlib>
24 : #include <cstring>
25 : #include <set>
26 : #include <sys/stat.h>
27 :
28 : #include "cpl_conv.h"
29 : #include "cpl_error.h"
30 : #include "cpl_minixml.h"
31 : #include "cpl_multiproc.h"
32 : #include "cpl_progress.h"
33 : #include "cpl_string.h"
34 : #include "cpl_vsi.h"
35 : #include "ograpispy.h"
36 : #include "ogr_core.h"
37 : #include "ogrsf_frmts.h"
38 :
39 : /************************************************************************/
40 : /* GDALDriver() */
41 : /************************************************************************/
42 :
43 : GDALDriver::GDALDriver() = default;
44 :
45 : /************************************************************************/
46 : /* ~GDALDriver() */
47 : /************************************************************************/
48 :
49 456530 : GDALDriver::~GDALDriver()
50 :
51 : {
52 257489 : if (pfnUnloadDriver != nullptr)
53 9397 : pfnUnloadDriver(this);
54 456530 : }
55 :
56 : /************************************************************************/
57 : /* GDALCreateDriver() */
58 : /************************************************************************/
59 :
60 : /**
61 : * \brief Create a GDALDriver.
62 : *
63 : * Creates a driver in the GDAL heap.
64 : */
65 :
66 225 : GDALDriverH CPL_STDCALL GDALCreateDriver()
67 : {
68 225 : return new GDALDriver();
69 : }
70 :
71 : /************************************************************************/
72 : /* GDALDestroyDriver() */
73 : /************************************************************************/
74 :
75 : /**
76 : * \brief Destroy a GDALDriver.
77 : *
78 : * This is roughly equivalent to deleting the driver, but is guaranteed
79 : * to take place in the GDAL heap. It is important this that function
80 : * not be called on a driver that is registered with the GDALDriverManager.
81 : *
82 : * @param hDriver the driver to destroy.
83 : */
84 :
85 0 : void CPL_STDCALL GDALDestroyDriver(GDALDriverH hDriver)
86 :
87 : {
88 0 : if (hDriver != nullptr)
89 0 : delete GDALDriver::FromHandle(hDriver);
90 0 : }
91 :
92 : /************************************************************************/
93 : /* Open() */
94 : /************************************************************************/
95 :
96 : //! @cond Doxygen_Suppress
97 :
98 453829 : GDALDataset *GDALDriver::Open(GDALOpenInfo *poOpenInfo, bool bSetOpenOptions)
99 : {
100 :
101 453829 : GDALDataset *poDS = nullptr;
102 453829 : pfnOpen = GetOpenCallback();
103 453513 : if (pfnOpen != nullptr)
104 : {
105 453706 : poDS = pfnOpen(poOpenInfo);
106 : }
107 0 : else if (pfnOpenWithDriverArg != nullptr)
108 : {
109 3 : poDS = pfnOpenWithDriverArg(this, poOpenInfo);
110 : }
111 :
112 454281 : if (poDS)
113 : {
114 : // Only set GDAL_OF_THREAD_SAFE if the driver itself has set it in
115 : // poDS->nOpenFlags
116 56582 : int nOpenFlags = poOpenInfo->nOpenFlags &
117 : ~(GDAL_OF_FROM_GDALOPEN | GDAL_OF_THREAD_SAFE);
118 56582 : if (poDS->nOpenFlags & GDAL_OF_THREAD_SAFE)
119 911 : nOpenFlags |= GDAL_OF_THREAD_SAFE;
120 56582 : poDS->nOpenFlags = nOpenFlags;
121 :
122 56582 : if (strlen(poDS->GetDescription()) == 0)
123 11832 : poDS->SetDescription(poOpenInfo->pszFilename);
124 :
125 56549 : if (poDS->poDriver == nullptr)
126 52624 : poDS->poDriver = this;
127 :
128 56549 : if (poDS->papszOpenOptions == nullptr && bSetOpenOptions)
129 : {
130 29 : poDS->papszOpenOptions = CSLDuplicate(poOpenInfo->papszOpenOptions);
131 : }
132 :
133 56549 : if (!(poOpenInfo->nOpenFlags & GDAL_OF_INTERNAL))
134 : {
135 46302 : if (CPLGetPID() != GDALGetResponsiblePIDForCurrentThread())
136 6 : CPLDebug(
137 : "GDAL",
138 : "GDALOpen(%s, this=%p) succeeds as "
139 : "%s (pid=%d, responsiblePID=%d).",
140 6 : poOpenInfo->pszFilename, poDS, GetDescription(),
141 6 : static_cast<int>(CPLGetPID()),
142 6 : static_cast<int>(GDALGetResponsiblePIDForCurrentThread()));
143 : else
144 46299 : CPLDebug("GDAL", "GDALOpen(%s, this=%p) succeeds as %s.",
145 46291 : poOpenInfo->pszFilename, poDS, GetDescription());
146 :
147 46468 : poDS->AddToDatasetOpenList();
148 : }
149 : }
150 :
151 454607 : return poDS;
152 : }
153 :
154 : //! @endcond
155 :
156 : /************************************************************************/
157 : /* Create() */
158 : /************************************************************************/
159 :
160 : /**
161 : * \brief Create a new dataset with this driver.
162 : *
163 : * What argument values are legal for particular drivers is driver specific,
164 : * and there is no way to query in advance to establish legal values.
165 : *
166 : * That function will try to validate the creation option list passed to the
167 : * driver with the GDALValidateCreationOptions() method. This check can be
168 : * disabled by defining the configuration option
169 : * GDAL_VALIDATE_CREATION_OPTIONS=NO.
170 : *
171 : * After you have finished working with the returned dataset, it is
172 : * <b>required</b> to close it with GDALClose(). This does not only close the
173 : * file handle, but also ensures that all the data and metadata has been written
174 : * to the dataset (GDALFlushCache() is not sufficient for that purpose).
175 : *
176 : * The arguments nXSize, nYSize and nBands can be passed to 0 when
177 : * creating a vector-only dataset for a compatible driver.
178 : *
179 : * Equivalent of the C function GDALCreate().
180 : *
181 : * @param pszFilename the name of the dataset to create. UTF-8 encoded.
182 : * @param nXSize width of created raster in pixels.
183 : * @param nYSize height of created raster in pixels.
184 : * @param nBands number of bands.
185 : * @param eType type of raster.
186 : * @param papszOptions list of driver specific control parameters.
187 : * The APPEND_SUBDATASET=YES option can be
188 : * specified to avoid prior destruction of existing dataset.
189 : *
190 : * @return NULL on failure, or a new GDALDataset.
191 : */
192 :
193 23851 : GDALDataset *GDALDriver::Create(const char *pszFilename, int nXSize, int nYSize,
194 : int nBands, GDALDataType eType,
195 : CSLConstList papszOptions)
196 :
197 : {
198 : /* -------------------------------------------------------------------- */
199 : /* Does this format support creation. */
200 : /* -------------------------------------------------------------------- */
201 23851 : pfnCreate = GetCreateCallback();
202 23851 : if (CPL_UNLIKELY(pfnCreate == nullptr && pfnCreateEx == nullptr &&
203 : pfnCreateVectorOnly == nullptr))
204 : {
205 1 : CPLError(CE_Failure, CPLE_NotSupported,
206 : "GDALDriver::Create() ... no create method implemented"
207 : " for this format.");
208 :
209 1 : return nullptr;
210 : }
211 : /* -------------------------------------------------------------------- */
212 : /* Do some rudimentary argument checking. */
213 : /* -------------------------------------------------------------------- */
214 23850 : if (CPL_UNLIKELY(nBands < 0))
215 : {
216 1 : CPLError(CE_Failure, CPLE_AppDefined,
217 : "Attempt to create dataset with %d bands is illegal,"
218 : "Must be >= 0.",
219 : nBands);
220 1 : return nullptr;
221 : }
222 :
223 23849 : if (CPL_UNLIKELY(GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
224 : GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr &&
225 23849 : (nXSize < 1 || nYSize < 1)))
226 : {
227 1 : CPLError(CE_Failure, CPLE_AppDefined,
228 : "Attempt to create %dx%d dataset is illegal,"
229 : "sizes must be larger than zero.",
230 : nXSize, nYSize);
231 1 : return nullptr;
232 : }
233 :
234 23848 : if (CPL_UNLIKELY(nBands != 0 &&
235 : (eType == GDT_Unknown || eType == GDT_TypeCount)))
236 : {
237 1 : CPLError(CE_Failure, CPLE_IllegalArg,
238 : "Illegal GDT_Unknown/GDT_TypeCount argument");
239 1 : return nullptr;
240 : }
241 :
242 : /* -------------------------------------------------------------------- */
243 : /* Make sure we cleanup if there is an existing dataset of this */
244 : /* name. But even if that seems to fail we will continue since */
245 : /* it might just be a corrupt file or something. */
246 : /* -------------------------------------------------------------------- */
247 23847 : if (!CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false))
248 : {
249 : // Someone issuing Create("foo.tif") on a
250 : // memory driver doesn't expect files with those names to be deleted
251 : // on a file system...
252 : // This is somewhat messy. Ideally there should be a way for the
253 : // driver to overload the default behavior
254 23828 : if (!EQUAL(GetDescription(), "MEM") &&
255 36895 : !EQUAL(GetDescription(), "Memory") &&
256 : // ogr2ogr -f PostgreSQL might reach the Delete method of the
257 : // PostgisRaster driver which is undesirable
258 13067 : !EQUAL(GetDescription(), "PostgreSQL"))
259 : {
260 13065 : QuietDelete(pszFilename);
261 : }
262 : }
263 :
264 : /* -------------------------------------------------------------------- */
265 : /* Validate creation options. */
266 : /* -------------------------------------------------------------------- */
267 23847 : if (CPLTestBool(
268 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
269 23847 : GDALValidateCreationOptions(this, papszOptions);
270 :
271 : /* -------------------------------------------------------------------- */
272 : /* Proceed with creation. */
273 : /* -------------------------------------------------------------------- */
274 47694 : CPLDebug("GDAL", "GDALDriver::Create(%s,%s,%d,%d,%d,%s,%p)",
275 23847 : GetDescription(), pszFilename, nXSize, nYSize, nBands,
276 : GDALGetDataTypeName(eType), papszOptions);
277 :
278 23847 : GDALDataset *poDS = nullptr;
279 23847 : if (pfnCreateEx != nullptr)
280 : {
281 0 : poDS = pfnCreateEx(this, pszFilename, nXSize, nYSize, nBands, eType,
282 : const_cast<char **>(papszOptions));
283 : }
284 23847 : else if (pfnCreate != nullptr)
285 : {
286 23847 : poDS = pfnCreate(pszFilename, nXSize, nYSize, nBands, eType,
287 : const_cast<char **>(papszOptions));
288 : }
289 0 : else if (nBands < 1)
290 : {
291 0 : poDS = pfnCreateVectorOnly(this, pszFilename,
292 : const_cast<char **>(papszOptions));
293 : }
294 :
295 23847 : if (poDS != nullptr)
296 : {
297 45100 : if (poDS->GetDescription() == nullptr ||
298 22550 : strlen(poDS->GetDescription()) == 0)
299 19892 : poDS->SetDescription(pszFilename);
300 :
301 22550 : if (poDS->poDriver == nullptr)
302 21886 : poDS->poDriver = this;
303 :
304 22550 : poDS->AddToDatasetOpenList();
305 : }
306 :
307 23847 : return poDS;
308 : }
309 :
310 : /************************************************************************/
311 : /* GDALCreate() */
312 : /************************************************************************/
313 :
314 : /**
315 : * \brief Create a new dataset with this driver.
316 : *
317 : * @see GDALDriver::Create()
318 : */
319 :
320 19725 : GDALDatasetH CPL_DLL CPL_STDCALL GDALCreate(GDALDriverH hDriver,
321 : const char *pszFilename, int nXSize,
322 : int nYSize, int nBands,
323 : GDALDataType eBandType,
324 : CSLConstList papszOptions)
325 :
326 : {
327 19725 : VALIDATE_POINTER1(hDriver, "GDALCreate", nullptr);
328 :
329 19725 : GDALDatasetH hDS = GDALDriver::FromHandle(hDriver)->Create(
330 : pszFilename, nXSize, nYSize, nBands, eBandType, papszOptions);
331 :
332 : #ifdef OGRAPISPY_ENABLED
333 19725 : if (nBands < 1)
334 : {
335 3593 : OGRAPISpyCreateDataSource(hDriver, pszFilename,
336 : const_cast<char **>(papszOptions), hDS);
337 : }
338 : #endif
339 :
340 19725 : return hDS;
341 : }
342 :
343 : /************************************************************************/
344 : /* CreateMultiDimensional() */
345 : /************************************************************************/
346 :
347 : /**
348 : * \brief Create a new multidimensional dataset with this driver.
349 : *
350 : * Only drivers that advertise the GDAL_DCAP_MULTIDIM_RASTER capability and
351 : * implement the pfnCreateMultiDimensional method might return a non nullptr
352 : * GDALDataset.
353 : *
354 : * This is the same as the C function GDALCreateMultiDimensional().
355 : *
356 : * @param pszFilename the name of the dataset to create. UTF-8 encoded.
357 : * @param papszRootGroupOptions driver specific options regarding the creation
358 : * of the root group. Might be nullptr.
359 : * @param papszOptions driver specific options regarding the creation
360 : * of the dataset. Might be nullptr.
361 : * @return a new dataset, or nullptr in case of failure.
362 : *
363 : * @since GDAL 3.1
364 : */
365 :
366 : GDALDataset *
367 523 : GDALDriver::CreateMultiDimensional(const char *pszFilename,
368 : CSLConstList papszRootGroupOptions,
369 : CSLConstList papszOptions)
370 :
371 : {
372 : /* -------------------------------------------------------------------- */
373 : /* Does this format support creation. */
374 : /* -------------------------------------------------------------------- */
375 523 : pfnCreateMultiDimensional = GetCreateMultiDimensionalCallback();
376 523 : if (pfnCreateMultiDimensional == nullptr)
377 : {
378 0 : CPLError(CE_Failure, CPLE_NotSupported,
379 : "GDALDriver::CreateMultiDimensional() ... "
380 : "no CreateMultiDimensional method implemented "
381 : "for this format.");
382 :
383 0 : return nullptr;
384 : }
385 :
386 : /* -------------------------------------------------------------------- */
387 : /* Validate creation options. */
388 : /* -------------------------------------------------------------------- */
389 523 : if (CPLTestBool(
390 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
391 : {
392 : const char *pszOptionList =
393 523 : GetMetadataItem(GDAL_DMD_MULTIDIM_DATASET_CREATIONOPTIONLIST);
394 1046 : CPLString osDriver;
395 523 : osDriver.Printf("driver %s", GetDescription());
396 523 : GDALValidateOptions(pszOptionList, papszOptions, "creation option",
397 : osDriver);
398 : }
399 :
400 523 : auto poDstDS = pfnCreateMultiDimensional(pszFilename, papszRootGroupOptions,
401 : papszOptions);
402 :
403 523 : if (poDstDS != nullptr)
404 : {
405 1042 : if (poDstDS->GetDescription() == nullptr ||
406 521 : strlen(poDstDS->GetDescription()) == 0)
407 144 : poDstDS->SetDescription(pszFilename);
408 :
409 521 : if (poDstDS->poDriver == nullptr)
410 519 : poDstDS->poDriver = this;
411 : }
412 :
413 523 : return poDstDS;
414 : }
415 :
416 : /************************************************************************/
417 : /* GDALCreateMultiDimensional() */
418 : /************************************************************************/
419 :
420 : /** \brief Create a new multidimensional dataset with this driver.
421 : *
422 : * This is the same as the C++ method GDALDriver::CreateMultiDimensional().
423 : */
424 474 : GDALDatasetH GDALCreateMultiDimensional(GDALDriverH hDriver,
425 : const char *pszName,
426 : CSLConstList papszRootGroupOptions,
427 : CSLConstList papszOptions)
428 : {
429 474 : VALIDATE_POINTER1(hDriver, __func__, nullptr);
430 474 : VALIDATE_POINTER1(pszName, __func__, nullptr);
431 474 : return GDALDataset::ToHandle(
432 : GDALDriver::FromHandle(hDriver)->CreateMultiDimensional(
433 474 : pszName, papszRootGroupOptions, papszOptions));
434 : }
435 :
436 : /************************************************************************/
437 : /* DefaultCreateCopyMultiDimensional() */
438 : /************************************************************************/
439 :
440 : //! @cond Doxygen_Suppress
441 :
442 26 : CPLErr GDALDriver::DefaultCreateCopyMultiDimensional(
443 : GDALDataset *poSrcDS, GDALDataset *poDstDS, bool bStrict,
444 : CSLConstList papszOptions, GDALProgressFunc pfnProgress,
445 : void *pProgressData)
446 : {
447 26 : if (pfnProgress == nullptr)
448 2 : pfnProgress = GDALDummyProgress;
449 :
450 52 : auto poSrcRG = poSrcDS->GetRootGroup();
451 26 : if (!poSrcRG)
452 0 : return CE_Failure;
453 52 : auto poDstRG = poDstDS->GetRootGroup();
454 26 : if (!poDstRG)
455 0 : return CE_Failure;
456 26 : GUInt64 nCurCost = 0;
457 52 : return poDstRG->CopyFrom(poDstRG, poSrcDS, poSrcRG, bStrict, nCurCost,
458 : poSrcRG->GetTotalCopyCost(), pfnProgress,
459 26 : pProgressData, papszOptions)
460 26 : ? CE_None
461 26 : : CE_Failure;
462 : }
463 :
464 : //! @endcond
465 :
466 : /************************************************************************/
467 : /* DefaultCopyMasks() */
468 : /************************************************************************/
469 :
470 : //! @cond Doxygen_Suppress
471 6166 : CPLErr GDALDriver::DefaultCopyMasks(GDALDataset *poSrcDS, GDALDataset *poDstDS,
472 : int bStrict)
473 :
474 : {
475 6166 : return DefaultCopyMasks(poSrcDS, poDstDS, bStrict, nullptr, nullptr,
476 6166 : nullptr);
477 : }
478 :
479 8151 : CPLErr GDALDriver::DefaultCopyMasks(GDALDataset *poSrcDS, GDALDataset *poDstDS,
480 : int bStrict, CSLConstList /*papszOptions*/,
481 : GDALProgressFunc pfnProgress,
482 : void *pProgressData)
483 :
484 : {
485 8151 : if (pfnProgress == nullptr)
486 6166 : pfnProgress = GDALDummyProgress;
487 :
488 8151 : int nBands = poSrcDS->GetRasterCount();
489 8151 : if (nBands == 0)
490 0 : return CE_None;
491 :
492 : /* -------------------------------------------------------------------- */
493 : /* Try to copy mask if it seems appropriate. */
494 : /* -------------------------------------------------------------------- */
495 8151 : const char *papszOptions[2] = {"COMPRESSED=YES", nullptr};
496 8151 : CPLErr eErr = CE_None;
497 :
498 8151 : int nTotalBandsWithMask = 0;
499 28302 : for (int iBand = 0; iBand < nBands; ++iBand)
500 : {
501 20151 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
502 :
503 20151 : int nMaskFlags = poSrcBand->GetMaskFlags();
504 20151 : if (!(nMaskFlags &
505 : (GMF_ALL_VALID | GMF_PER_DATASET | GMF_ALPHA | GMF_NODATA)))
506 : {
507 8 : nTotalBandsWithMask++;
508 : }
509 : }
510 :
511 8151 : int iBandWithMask = 0;
512 28302 : for (int iBand = 0; eErr == CE_None && iBand < nBands; ++iBand)
513 : {
514 20151 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
515 :
516 20151 : int nMaskFlags = poSrcBand->GetMaskFlags();
517 20151 : if (eErr == CE_None && !(nMaskFlags & (GMF_ALL_VALID | GMF_PER_DATASET |
518 : GMF_ALPHA | GMF_NODATA)))
519 : {
520 8 : GDALRasterBand *poDstBand = poDstDS->GetRasterBand(iBand + 1);
521 8 : if (poDstBand != nullptr)
522 : {
523 8 : eErr = poDstBand->CreateMaskBand(nMaskFlags);
524 8 : if (eErr == CE_None)
525 : {
526 24 : void *pScaledData = GDALCreateScaledProgress(
527 8 : double(iBandWithMask) /
528 8 : std::max(1, nTotalBandsWithMask),
529 8 : double(iBandWithMask + 1) /
530 8 : std::max(1, nTotalBandsWithMask),
531 : pfnProgress, pProgressData);
532 16 : eErr = GDALRasterBandCopyWholeRaster(
533 8 : poSrcBand->GetMaskBand(), poDstBand->GetMaskBand(),
534 : papszOptions, GDALScaledProgress, pScaledData);
535 8 : GDALDestroyScaledProgress(pScaledData);
536 : }
537 0 : else if (!bStrict)
538 : {
539 0 : eErr = CE_None;
540 : }
541 : }
542 : }
543 : }
544 :
545 : /* -------------------------------------------------------------------- */
546 : /* Try to copy a per-dataset mask if we have one. */
547 : /* -------------------------------------------------------------------- */
548 8151 : const int nMaskFlags = poSrcDS->GetRasterBand(1)->GetMaskFlags();
549 8151 : if (eErr == CE_None &&
550 8151 : !(nMaskFlags & (GMF_ALL_VALID | GMF_ALPHA | GMF_NODATA)) &&
551 13 : (nMaskFlags & GMF_PER_DATASET))
552 : {
553 8 : eErr = poDstDS->CreateMaskBand(nMaskFlags);
554 8 : if (eErr == CE_None)
555 : {
556 8 : eErr = GDALRasterBandCopyWholeRaster(
557 8 : poSrcDS->GetRasterBand(1)->GetMaskBand(),
558 8 : poDstDS->GetRasterBand(1)->GetMaskBand(), papszOptions,
559 : pfnProgress, pProgressData);
560 : }
561 0 : else if (!bStrict)
562 : {
563 0 : eErr = CE_None;
564 : }
565 : }
566 :
567 8151 : return eErr;
568 : }
569 :
570 : /************************************************************************/
571 : /* DefaultCreateCopy() */
572 : /************************************************************************/
573 :
574 1423 : GDALDataset *GDALDriver::DefaultCreateCopy(const char *pszFilename,
575 : GDALDataset *poSrcDS, int bStrict,
576 : CSLConstList papszOptions,
577 : GDALProgressFunc pfnProgress,
578 : void *pProgressData)
579 :
580 : {
581 1423 : if (pfnProgress == nullptr)
582 0 : pfnProgress = GDALDummyProgress;
583 :
584 1423 : CPLErrorReset();
585 :
586 : /* -------------------------------------------------------------------- */
587 : /* Use multidimensional raster API if available. */
588 : /* -------------------------------------------------------------------- */
589 2846 : auto poSrcGroup = poSrcDS->GetRootGroup();
590 1423 : if (poSrcGroup != nullptr && GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER))
591 : {
592 48 : CPLStringList aosDatasetCO;
593 31 : for (const char *pszOption : cpl::Iterate(papszOptions))
594 : {
595 7 : if (!STARTS_WITH_CI(pszOption, "ARRAY:"))
596 0 : aosDatasetCO.AddString(pszOption);
597 : }
598 : auto poDstDS = std::unique_ptr<GDALDataset>(
599 48 : CreateMultiDimensional(pszFilename, nullptr, aosDatasetCO.List()));
600 24 : if (!poDstDS)
601 0 : return nullptr;
602 48 : auto poDstGroup = poDstDS->GetRootGroup();
603 24 : if (!poDstGroup)
604 0 : return nullptr;
605 24 : if (DefaultCreateCopyMultiDimensional(
606 24 : poSrcDS, poDstDS.get(), CPL_TO_BOOL(bStrict), papszOptions,
607 24 : pfnProgress, pProgressData) != CE_None)
608 0 : return nullptr;
609 24 : return poDstDS.release();
610 : }
611 :
612 : /* -------------------------------------------------------------------- */
613 : /* Validate that we can create the output as requested. */
614 : /* -------------------------------------------------------------------- */
615 1399 : const int nXSize = poSrcDS->GetRasterXSize();
616 1399 : const int nYSize = poSrcDS->GetRasterYSize();
617 1399 : const int nBands = poSrcDS->GetRasterCount();
618 :
619 1399 : CPLDebug("GDAL", "Using default GDALDriver::CreateCopy implementation.");
620 :
621 1399 : const int nLayerCount = poSrcDS->GetLayerCount();
622 1423 : if (nBands == 0 && nLayerCount == 0 &&
623 24 : GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
624 : {
625 17 : CPLError(CE_Failure, CPLE_NotSupported,
626 : "GDALDriver::DefaultCreateCopy does not support zero band");
627 17 : return nullptr;
628 : }
629 1382 : if (poSrcDS->GetDriver() != nullptr &&
630 1352 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
631 1345 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr &&
632 2737 : GetMetadataItem(GDAL_DCAP_RASTER) == nullptr &&
633 3 : GetMetadataItem(GDAL_DCAP_VECTOR) != nullptr)
634 : {
635 3 : CPLError(CE_Failure, CPLE_NotSupported,
636 : "Source driver is raster-only whereas output driver is "
637 : "vector-only");
638 3 : return nullptr;
639 : }
640 1379 : else if (poSrcDS->GetDriver() != nullptr &&
641 1349 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_RASTER) ==
642 7 : nullptr &&
643 7 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VECTOR) !=
644 7 : nullptr &&
645 2728 : GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
646 0 : GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
647 : {
648 0 : CPLError(CE_Failure, CPLE_NotSupported,
649 : "Source driver is vector-only whereas output driver is "
650 : "raster-only");
651 0 : return nullptr;
652 : }
653 :
654 1379 : if (!pfnProgress(0.0, nullptr, pProgressData))
655 : {
656 2 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
657 2 : return nullptr;
658 : }
659 :
660 : /* -------------------------------------------------------------------- */
661 : /* Propagate some specific structural metadata as options if it */
662 : /* appears to be supported by the target driver and the caller */
663 : /* didn't provide values. */
664 : /* -------------------------------------------------------------------- */
665 1377 : char **papszCreateOptions = CSLDuplicate(papszOptions);
666 1377 : const char *const apszOptItems[] = {"NBITS", "IMAGE_STRUCTURE", "PIXELTYPE",
667 : "IMAGE_STRUCTURE", nullptr};
668 :
669 4099 : for (int iOptItem = 0; nBands > 0 && apszOptItems[iOptItem] != nullptr;
670 2722 : iOptItem += 2)
671 : {
672 : // does the source have this metadata item on the first band?
673 2722 : auto poBand = poSrcDS->GetRasterBand(1);
674 2722 : poBand->EnablePixelTypeSignedByteWarning(false);
675 5444 : const char *pszValue = poBand->GetMetadataItem(
676 2722 : apszOptItems[iOptItem], apszOptItems[iOptItem + 1]);
677 2722 : poBand->EnablePixelTypeSignedByteWarning(true);
678 :
679 2722 : if (pszValue == nullptr)
680 2721 : continue;
681 :
682 : // Do not override provided value.
683 1 : if (CSLFetchNameValue(papszCreateOptions, pszValue) != nullptr)
684 0 : continue;
685 :
686 : // Does this appear to be a supported creation option on this driver?
687 : const char *pszOptionList =
688 1 : GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
689 :
690 1 : if (pszOptionList == nullptr ||
691 1 : strstr(pszOptionList, apszOptItems[iOptItem]) == nullptr)
692 0 : continue;
693 :
694 1 : papszCreateOptions = CSLSetNameValue(papszCreateOptions,
695 1 : apszOptItems[iOptItem], pszValue);
696 : }
697 :
698 : /* -------------------------------------------------------------------- */
699 : /* Create destination dataset. */
700 : /* -------------------------------------------------------------------- */
701 1377 : GDALDataType eType = GDT_Unknown;
702 :
703 1377 : if (nBands > 0)
704 1361 : eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
705 : GDALDataset *poDstDS =
706 1377 : Create(pszFilename, nXSize, nYSize, nBands, eType, papszCreateOptions);
707 :
708 1377 : CSLDestroy(papszCreateOptions);
709 :
710 1377 : if (poDstDS == nullptr)
711 326 : return nullptr;
712 :
713 1051 : int nDstBands = poDstDS->GetRasterCount();
714 1051 : CPLErr eErr = CE_None;
715 1051 : if (nDstBands != nBands)
716 : {
717 0 : if (GetMetadataItem(GDAL_DCAP_RASTER) != nullptr)
718 : {
719 : // Should not happen for a well-behaved driver.
720 0 : CPLError(
721 : CE_Failure, CPLE_AppDefined,
722 : "Output driver created only %d bands whereas %d were expected",
723 : nDstBands, nBands);
724 0 : eErr = CE_Failure;
725 : }
726 0 : nDstBands = 0;
727 : }
728 :
729 : /* -------------------------------------------------------------------- */
730 : /* Try setting the projection and geotransform if it seems */
731 : /* suitable. */
732 : /* -------------------------------------------------------------------- */
733 1051 : if (nDstBands == 0 && !bStrict)
734 4 : CPLTurnFailureIntoWarning(true);
735 :
736 1051 : GDALGeoTransform gt;
737 1974 : if (eErr == CE_None && poSrcDS->GetGeoTransform(gt) == CE_None &&
738 1974 : gt != GDALGeoTransform())
739 : {
740 919 : eErr = poDstDS->SetGeoTransform(gt);
741 919 : if (!bStrict)
742 569 : eErr = CE_None;
743 : }
744 :
745 1051 : if (eErr == CE_None)
746 : {
747 1042 : const auto poSrcSRS = poSrcDS->GetSpatialRefRasterOnly();
748 1042 : if (poSrcSRS && !poSrcSRS->IsEmpty())
749 : {
750 858 : eErr = poDstDS->SetSpatialRef(poSrcSRS);
751 858 : if (!bStrict)
752 540 : eErr = CE_None;
753 : }
754 : }
755 :
756 : /* -------------------------------------------------------------------- */
757 : /* Copy GCPs. */
758 : /* -------------------------------------------------------------------- */
759 1051 : if (poSrcDS->GetGCPCount() > 0 && eErr == CE_None)
760 : {
761 2 : eErr = poDstDS->SetGCPs(poSrcDS->GetGCPCount(), poSrcDS->GetGCPs(),
762 : poSrcDS->GetGCPProjection());
763 2 : if (!bStrict)
764 1 : eErr = CE_None;
765 : }
766 :
767 1051 : if (nDstBands == 0 && !bStrict)
768 4 : CPLTurnFailureIntoWarning(false);
769 :
770 : /* -------------------------------------------------------------------- */
771 : /* Copy metadata. */
772 : /* -------------------------------------------------------------------- */
773 1051 : DefaultCopyMetadata(poSrcDS, poDstDS, papszOptions, nullptr);
774 :
775 : /* -------------------------------------------------------------------- */
776 : /* Loop copying bands. */
777 : /* -------------------------------------------------------------------- */
778 2671 : for (int iBand = 0; eErr == CE_None && iBand < nDstBands; ++iBand)
779 : {
780 1620 : GDALRasterBand *const poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
781 1620 : GDALRasterBand *const poDstBand = poDstDS->GetRasterBand(iBand + 1);
782 :
783 : /* --------------------------------------------------------------------
784 : */
785 : /* Do we need to copy a colortable. */
786 : /* --------------------------------------------------------------------
787 : */
788 1620 : GDALColorTable *const poCT = poSrcBand->GetColorTable();
789 1620 : if (poCT != nullptr)
790 29 : poDstBand->SetColorTable(poCT);
791 :
792 : /* --------------------------------------------------------------------
793 : */
794 : /* Do we need to copy other metadata? Most of this is */
795 : /* non-critical, so lets not bother folks if it fails are we */
796 : /* are not in strict mode. */
797 : /* --------------------------------------------------------------------
798 : */
799 1620 : if (!bStrict)
800 1003 : CPLTurnFailureIntoWarning(true);
801 :
802 1620 : if (strlen(poSrcBand->GetDescription()) > 0)
803 52 : poDstBand->SetDescription(poSrcBand->GetDescription());
804 :
805 1620 : if (CSLCount(poSrcBand->GetMetadata()) > 0)
806 114 : poDstBand->SetMetadata(poSrcBand->GetMetadata());
807 :
808 1620 : int bSuccess = FALSE;
809 1620 : double dfValue = poSrcBand->GetOffset(&bSuccess);
810 1620 : if (bSuccess && dfValue != 0.0)
811 5 : poDstBand->SetOffset(dfValue);
812 :
813 1620 : dfValue = poSrcBand->GetScale(&bSuccess);
814 1620 : if (bSuccess && dfValue != 1.0)
815 4 : poDstBand->SetScale(dfValue);
816 :
817 1620 : GDALCopyNoDataValue(poDstBand, poSrcBand);
818 :
819 2652 : if (poSrcBand->GetColorInterpretation() != GCI_Undefined &&
820 1032 : poSrcBand->GetColorInterpretation() !=
821 1032 : poDstBand->GetColorInterpretation())
822 815 : poDstBand->SetColorInterpretation(
823 815 : poSrcBand->GetColorInterpretation());
824 :
825 1620 : char **papszCatNames = poSrcBand->GetCategoryNames();
826 1620 : if (nullptr != papszCatNames)
827 1 : poDstBand->SetCategoryNames(papszCatNames);
828 :
829 : // Only copy RAT if it is of reasonable size to fit in memory
830 1620 : GDALRasterAttributeTable *poRAT = poSrcBand->GetDefaultRAT();
831 1622 : if (poRAT != nullptr && static_cast<GIntBig>(poRAT->GetColumnCount()) *
832 2 : poRAT->GetRowCount() <
833 : 1024 * 1024)
834 : {
835 2 : poDstBand->SetDefaultRAT(poRAT);
836 : }
837 :
838 1620 : if (!bStrict)
839 : {
840 1003 : CPLTurnFailureIntoWarning(false);
841 : }
842 : else
843 : {
844 617 : eErr = CPLGetLastErrorType();
845 : }
846 : }
847 :
848 : /* -------------------------------------------------------------------- */
849 : /* Copy image data. */
850 : /* -------------------------------------------------------------------- */
851 1051 : if (eErr == CE_None && nDstBands > 0)
852 : {
853 1006 : const char *const apszCopyRasterOptionsSkipHoles[] = {"SKIP_HOLES=YES",
854 : nullptr};
855 1006 : const bool bSkipHoles = CPLTestBool(
856 : CSLFetchNameValueDef(papszOptions, "SKIP_HOLES", "FALSE"));
857 1006 : eErr = GDALDatasetCopyWholeRaster(
858 : poSrcDS, poDstDS,
859 : bSkipHoles ? apszCopyRasterOptionsSkipHoles : nullptr, pfnProgress,
860 : pProgressData);
861 : }
862 :
863 : /* -------------------------------------------------------------------- */
864 : /* Should we copy some masks over? */
865 : /* -------------------------------------------------------------------- */
866 1051 : if (eErr == CE_None && nDstBands > 0)
867 989 : eErr = DefaultCopyMasks(poSrcDS, poDstDS, eErr);
868 :
869 : /* -------------------------------------------------------------------- */
870 : /* Copy vector layers */
871 : /* -------------------------------------------------------------------- */
872 1051 : if (eErr == CE_None)
873 : {
874 1002 : if (nLayerCount > 0 && poDstDS->TestCapability(ODsCCreateLayer))
875 : {
876 20 : for (int iLayer = 0; iLayer < nLayerCount; ++iLayer)
877 : {
878 10 : OGRLayer *poLayer = poSrcDS->GetLayer(iLayer);
879 :
880 10 : if (poLayer == nullptr)
881 0 : continue;
882 :
883 10 : poDstDS->CopyLayer(poLayer, poLayer->GetName(), nullptr);
884 : }
885 : }
886 : }
887 :
888 : /* -------------------------------------------------------------------- */
889 : /* Try to cleanup the output dataset if the translation failed. */
890 : /* -------------------------------------------------------------------- */
891 1051 : if (eErr != CE_None)
892 : {
893 49 : delete poDstDS;
894 49 : if (!CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false))
895 : {
896 : // Only delete if creating a new file
897 49 : Delete(pszFilename);
898 : }
899 49 : return nullptr;
900 : }
901 : else
902 : {
903 1002 : CPLErrorReset();
904 : }
905 :
906 1002 : return poDstDS;
907 : }
908 :
909 : /************************************************************************/
910 : /* DefaultCopyMetadata() */
911 : /************************************************************************/
912 :
913 5413 : void GDALDriver::DefaultCopyMetadata(GDALDataset *poSrcDS, GDALDataset *poDstDS,
914 : CSLConstList papszOptions,
915 : CSLConstList papszExcludedDomains)
916 : {
917 : const char *pszCopySrcMDD =
918 5413 : CSLFetchNameValueDef(papszOptions, "COPY_SRC_MDD", "AUTO");
919 5413 : char **papszSrcMDD = CSLFetchNameValueMultiple(papszOptions, "SRC_MDD");
920 5413 : if (EQUAL(pszCopySrcMDD, "AUTO") || CPLTestBool(pszCopySrcMDD) ||
921 : papszSrcMDD)
922 : {
923 4 : if ((!papszSrcMDD || CSLFindString(papszSrcMDD, "") >= 0 ||
924 2 : CSLFindString(papszSrcMDD, "_DEFAULT_") >= 0) &&
925 10668 : CSLFindString(papszExcludedDomains, "") < 0 &&
926 5253 : CSLFindString(papszExcludedDomains, "_DEFAULT_") < 0)
927 : {
928 5253 : if (poSrcDS->GetMetadata() != nullptr)
929 826 : poDstDS->SetMetadata(poSrcDS->GetMetadata());
930 : }
931 :
932 : /* -------------------------------------------------------------------- */
933 : /* Copy transportable special domain metadata. */
934 : /* It would be nice to copy geolocation, but it is pretty fragile. */
935 : /* -------------------------------------------------------------------- */
936 5411 : constexpr const char *apszDefaultDomains[] = {
937 : "RPC", "xml:XMP", "json:ISIS3", "json:VICAR"};
938 27055 : for (const char *pszDomain : apszDefaultDomains)
939 : {
940 43272 : if ((!papszSrcMDD || CSLFindString(papszSrcMDD, pszDomain) >= 0) &&
941 21628 : CSLFindString(papszExcludedDomains, pszDomain) < 0)
942 : {
943 21628 : char **papszMD = poSrcDS->GetMetadata(pszDomain);
944 21628 : if (papszMD)
945 5 : poDstDS->SetMetadata(papszMD, pszDomain);
946 : }
947 : }
948 :
949 5411 : if ((!EQUAL(pszCopySrcMDD, "AUTO") && CPLTestBool(pszCopySrcMDD)) ||
950 : papszSrcMDD)
951 : {
952 24 : for (const char *pszDomain :
953 30 : CPLStringList(poSrcDS->GetMetadataDomainList()))
954 : {
955 36 : if (pszDomain[0] != 0 &&
956 12 : (!papszSrcMDD ||
957 12 : CSLFindString(papszSrcMDD, pszDomain) >= 0))
958 : {
959 10 : bool bCanCopy = true;
960 10 : if (CSLFindString(papszExcludedDomains, pszDomain) >= 0)
961 : {
962 0 : bCanCopy = false;
963 : }
964 : else
965 : {
966 50 : for (const char *pszOtherDomain : apszDefaultDomains)
967 : {
968 40 : if (EQUAL(pszDomain, pszOtherDomain))
969 : {
970 0 : bCanCopy = false;
971 0 : break;
972 : }
973 : }
974 10 : if (!papszSrcMDD)
975 : {
976 6 : constexpr const char *const apszReservedDomains[] =
977 : {"IMAGE_STRUCTURE", "DERIVED_SUBDATASETS"};
978 6 : for (const char *pszOtherDomain :
979 12 : apszReservedDomains)
980 : {
981 10 : if (EQUAL(pszDomain, pszOtherDomain))
982 : {
983 4 : bCanCopy = false;
984 4 : break;
985 : }
986 : }
987 : }
988 : }
989 10 : if (bCanCopy)
990 : {
991 6 : poDstDS->SetMetadata(poSrcDS->GetMetadata(pszDomain),
992 6 : pszDomain);
993 : }
994 : }
995 : }
996 : }
997 : }
998 5413 : CSLDestroy(papszSrcMDD);
999 5413 : }
1000 :
1001 : /************************************************************************/
1002 : /* QuietDeleteForCreateCopy() */
1003 : /************************************************************************/
1004 :
1005 11656 : CPLErr GDALDriver::QuietDeleteForCreateCopy(const char *pszFilename,
1006 : GDALDataset *poSrcDS)
1007 : {
1008 : // Someone issuing CreateCopy("foo.tif") on a
1009 : // memory driver doesn't expect files with those names to be deleted
1010 : // on a file system...
1011 : // This is somewhat messy. Ideally there should be a way for the
1012 : // driver to overload the default behavior
1013 22727 : if (!EQUAL(GetDescription(), "MEM") && !EQUAL(GetDescription(), "Memory") &&
1014 : // Also exclude database formats for which there's no file list
1015 : // and whose opening might be slow (GeoRaster in particular)
1016 33798 : !EQUAL(GetDescription(), "GeoRaster") &&
1017 11071 : !EQUAL(GetDescription(), "PostGISRaster"))
1018 : {
1019 : /* --------------------------------------------------------------------
1020 : */
1021 : /* Establish list of files of output dataset if it already
1022 : * exists. */
1023 : /* --------------------------------------------------------------------
1024 : */
1025 22106 : std::set<std::string> oSetExistingDestFiles;
1026 : {
1027 22106 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1028 11053 : const char *const apszAllowedDrivers[] = {GetDescription(),
1029 11053 : nullptr};
1030 : auto poExistingOutputDS =
1031 : std::unique_ptr<GDALDataset>(GDALDataset::Open(
1032 22106 : pszFilename, GDAL_OF_RASTER, apszAllowedDrivers));
1033 11053 : if (poExistingOutputDS)
1034 : {
1035 674 : for (const char *pszFileInList :
1036 640 : CPLStringList(poExistingOutputDS->GetFileList()))
1037 : {
1038 : oSetExistingDestFiles.insert(
1039 337 : CPLString(pszFileInList).replaceAll('\\', '/'));
1040 : }
1041 : }
1042 : }
1043 :
1044 : /* --------------------------------------------------------------------
1045 : */
1046 : /* Check if the source dataset shares some files with the dest
1047 : * one.*/
1048 : /* --------------------------------------------------------------------
1049 : */
1050 22106 : std::set<std::string> oSetExistingDestFilesFoundInSource;
1051 11053 : if (!oSetExistingDestFiles.empty())
1052 : {
1053 606 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1054 : // We need to reopen in a temporary dataset for the particular
1055 : // case of overwritten a .tif.ovr file from a .tif
1056 : // If we probe the file list of the .tif, it will then open the
1057 : // .tif.ovr !
1058 303 : const char *const apszAllowedDrivers[] = {
1059 303 : poSrcDS->GetDriver() ? poSrcDS->GetDriver()->GetDescription()
1060 : : nullptr,
1061 303 : nullptr};
1062 : auto poSrcDSTmp = std::unique_ptr<GDALDataset>(GDALDataset::Open(
1063 303 : poSrcDS->GetDescription(), GDAL_OF_RASTER, apszAllowedDrivers,
1064 606 : poSrcDS->papszOpenOptions));
1065 303 : if (poSrcDSTmp)
1066 : {
1067 206 : for (const char *pszFileInList :
1068 400 : CPLStringList(poSrcDSTmp->GetFileList()))
1069 : {
1070 412 : CPLString osFilename(pszFileInList);
1071 206 : osFilename.replaceAll('\\', '/');
1072 206 : if (cpl::contains(oSetExistingDestFiles, osFilename))
1073 : {
1074 : oSetExistingDestFilesFoundInSource.insert(
1075 16 : std::move(osFilename));
1076 : }
1077 : }
1078 : }
1079 : }
1080 :
1081 : // If the source file(s) and the dest one share some files in
1082 : // common, only remove the files that are *not* in common
1083 11053 : if (!oSetExistingDestFilesFoundInSource.empty())
1084 : {
1085 36 : for (const std::string &osFilename : oSetExistingDestFiles)
1086 : {
1087 21 : if (!cpl::contains(oSetExistingDestFilesFoundInSource,
1088 : osFilename))
1089 : {
1090 5 : VSIUnlink(osFilename.c_str());
1091 : }
1092 : }
1093 : }
1094 :
1095 11053 : QuietDelete(pszFilename);
1096 : }
1097 :
1098 11656 : return CE_None;
1099 : }
1100 :
1101 : //! @endcond
1102 :
1103 : /************************************************************************/
1104 : /* CreateCopy() */
1105 : /************************************************************************/
1106 :
1107 : /**
1108 : * \brief Create a copy of a dataset.
1109 : *
1110 : * This method will attempt to create a copy of a raster dataset with the
1111 : * indicated filename, and in this drivers format. Band number, size,
1112 : * type, projection, geotransform and so forth are all to be copied from
1113 : * the provided template dataset.
1114 : *
1115 : * Note that many sequential write once formats (such as JPEG and PNG) don't
1116 : * implement the Create() method but do implement this CreateCopy() method.
1117 : * If the driver doesn't implement CreateCopy(), but does implement Create()
1118 : * then the default CreateCopy() mechanism built on calling Create() will
1119 : * be used.
1120 : * So to test if CreateCopy() is available, you can test if GDAL_DCAP_CREATECOPY
1121 : * or GDAL_DCAP_CREATE is set in the GDAL metadata.
1122 : *
1123 : * It is intended that CreateCopy() will often be used with a source dataset
1124 : * which is a virtual dataset allowing configuration of band types, and other
1125 : * information without actually duplicating raster data (see the VRT driver).
1126 : * This is what is done by the gdal_translate utility for example.
1127 : *
1128 : * That function will try to validate the creation option list passed to the
1129 : * driver with the GDALValidateCreationOptions() method. This check can be
1130 : * disabled by defining the configuration option
1131 : * GDAL_VALIDATE_CREATION_OPTIONS=NO.
1132 : *
1133 : * This function copy all metadata from the default domain ("")
1134 : *
1135 : * Even is bStrict is TRUE, only the <b>value</b> of the data is equivalent,
1136 : * but the data layout (INTERLEAVE as PIXEL/LINE/BAND) of the dst dataset is
1137 : * controlled by the papszOptions creation options, and may differ from the
1138 : * poSrcDS src dataset.
1139 : * Starting from GDAL 3.5, if no INTERLEAVE and COMPRESS creation option has
1140 : * been specified in papszOptions, and if the driver supports equivalent
1141 : * interleaving as the src dataset, the CreateCopy() will internally add the
1142 : * proper creation option to get the same data interleaving.
1143 : *
1144 : * After you have finished working with the returned dataset, it is
1145 : * <b>required</b> to close it with GDALClose(). This does not only close the
1146 : * file handle, but also ensures that all the data and metadata has been written
1147 : * to the dataset (GDALFlushCache() is not sufficient for that purpose).
1148 : *
1149 : * For multidimensional datasets, papszOptions can contain array creation
1150 : * options, if they are prefixed with "ARRAY:". \see GDALGroup::CopyFrom()
1151 : * documentation for further details regarding such options.
1152 : *
1153 : * @param pszFilename the name for the new dataset. UTF-8 encoded.
1154 : * @param poSrcDS the dataset being duplicated.
1155 : * @param bStrict TRUE if the copy must be strictly equivalent, or more
1156 : * normally FALSE indicating that the copy may adapt as needed for the
1157 : * output format.
1158 : * @param papszOptions additional format dependent options controlling
1159 : * creation of the output file.
1160 : * The APPEND_SUBDATASET=YES option can be specified to avoid prior destruction
1161 : * of existing dataset.
1162 : * Starting with GDAL 3.8.0, the following options are recognized by the
1163 : * GTiff, COG, VRT, PNG au JPEG drivers:
1164 : * <ul>
1165 : * <li>COPY_SRC_MDD=AUTO/YES/NO: whether metadata domains of the source dataset
1166 : * should be copied to the destination dataset. In the default AUTO mode, only
1167 : * "safe" domains will be copied, which include the default metadata domain
1168 : * (some drivers may include other domains such as IMD, RPC, GEOLOCATION). When
1169 : * setting YES, all domains will be copied (but a few reserved ones like
1170 : * IMAGE_STRUCTURE or DERIVED_SUBDATASETS). When setting NO, no source metadata
1171 : * will be copied.
1172 : * </li>
1173 : *<li>SRC_MDD=domain_name: which source metadata domain should be copied.
1174 : * This option restricts the list of source metadata domains to be copied
1175 : * (it implies COPY_SRC_MDD=YES if it is not set). This option may be specified
1176 : * as many times as they are source domains. The default metadata domain is the
1177 : * empty string "" ("_DEFAULT_") may also be used when empty string is not practical)
1178 : * </li>
1179 : * </ul>
1180 : * @param pfnProgress a function to be used to report progress of the copy.
1181 : * @param pProgressData application data passed into progress function.
1182 : *
1183 : * @return a pointer to the newly created dataset (may be read-only access).
1184 : */
1185 :
1186 11135 : GDALDataset *GDALDriver::CreateCopy(const char *pszFilename,
1187 : GDALDataset *poSrcDS, int bStrict,
1188 : CSLConstList papszOptions,
1189 : GDALProgressFunc pfnProgress,
1190 : void *pProgressData)
1191 :
1192 : {
1193 11135 : if (pfnProgress == nullptr)
1194 8575 : pfnProgress = GDALDummyProgress;
1195 :
1196 11135 : const int nBandCount = poSrcDS->GetRasterCount();
1197 :
1198 : /* -------------------------------------------------------------------- */
1199 : /* If no INTERLEAVE creation option is given, we will try to add */
1200 : /* one that matches the current srcDS interleaving */
1201 : /* -------------------------------------------------------------------- */
1202 11135 : char **papszOptionsToDelete = nullptr;
1203 : const char *srcInterleave =
1204 11135 : poSrcDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
1205 6692 : if (nBandCount > 1 && srcInterleave != nullptr &&
1206 24144 : CSLFetchNameValue(papszOptions, "INTERLEAVE") == nullptr &&
1207 6317 : EQUAL(CSLFetchNameValueDef(papszOptions, "COMPRESS", "NONE"), "NONE"))
1208 : {
1209 :
1210 : // look for INTERLEAVE values of the driver
1211 6163 : char **interleavesCSL = nullptr;
1212 : const char *pszOptionList =
1213 6163 : this->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
1214 : CPLXMLNode *xmlNode =
1215 6163 : !pszOptionList ? nullptr : CPLParseXMLString(pszOptionList);
1216 6163 : for (CPLXMLNode *child = !xmlNode ? nullptr : xmlNode->psChild;
1217 125679 : child != nullptr; child = child->psNext)
1218 : {
1219 119516 : if ((child->eType == CXT_Element) &&
1220 119516 : EQUAL(child->pszValue, "Option"))
1221 : {
1222 : const char *nameAttribute =
1223 119516 : CPLGetXMLValue(child, "name", nullptr);
1224 119516 : const bool isInterleaveAttribute =
1225 119516 : nameAttribute && EQUAL(nameAttribute, "INTERLEAVE");
1226 119516 : if (isInterleaveAttribute)
1227 : {
1228 1153 : for (CPLXMLNode *optionChild = child->psChild;
1229 6986 : optionChild != nullptr;
1230 5833 : optionChild = optionChild->psNext)
1231 : {
1232 5833 : if ((optionChild->eType == CXT_Element) &&
1233 2359 : EQUAL(optionChild->pszValue, "Value"))
1234 : {
1235 2359 : CPLXMLNode *optionChildValue = optionChild->psChild;
1236 2359 : if (optionChildValue &&
1237 2359 : (optionChildValue->eType == CXT_Text))
1238 : {
1239 2359 : interleavesCSL = CSLAddString(
1240 2359 : interleavesCSL, optionChildValue->pszValue);
1241 : }
1242 : }
1243 : }
1244 : }
1245 : }
1246 : }
1247 6163 : CPLDestroyXMLNode(xmlNode);
1248 :
1249 : const char *dstInterleaveBand =
1250 11197 : (CSLFindString(interleavesCSL, "BAND") >= 0) ? "BAND"
1251 5034 : : (CSLFindString(interleavesCSL, "BSQ") >= 0) ? "BSQ"
1252 6163 : : nullptr;
1253 : const char *dstInterleaveLine =
1254 12326 : (CSLFindString(interleavesCSL, "LINE") >= 0) ? "LINE"
1255 6163 : : (CSLFindString(interleavesCSL, "BIL") >= 0) ? "BIL"
1256 6163 : : nullptr;
1257 : const char *dstInterleavePixel =
1258 11197 : (CSLFindString(interleavesCSL, "PIXEL") >= 0) ? "PIXEL"
1259 5034 : : (CSLFindString(interleavesCSL, "BIP") >= 0) ? "BIP"
1260 6163 : : nullptr;
1261 6163 : const char *dstInterleave =
1262 6446 : EQUAL(srcInterleave, "BAND") ? dstInterleaveBand
1263 564 : : EQUAL(srcInterleave, "LINE") ? dstInterleaveLine
1264 281 : : EQUAL(srcInterleave, "PIXEL") ? dstInterleavePixel
1265 : : nullptr;
1266 6163 : CSLDestroy(interleavesCSL);
1267 :
1268 6163 : if (dstInterleave != nullptr)
1269 : {
1270 1153 : papszOptionsToDelete = CSLDuplicate(papszOptions);
1271 1153 : papszOptionsToDelete = CSLSetNameValue(papszOptionsToDelete,
1272 : "INTERLEAVE", dstInterleave);
1273 1153 : papszOptionsToDelete = CSLSetNameValue(
1274 : papszOptionsToDelete, "@INTERLEAVE_ADDED_AUTOMATICALLY", "YES");
1275 1153 : papszOptions = papszOptionsToDelete;
1276 : }
1277 : }
1278 :
1279 : /* -------------------------------------------------------------------- */
1280 : /* Make sure we cleanup if there is an existing dataset of this */
1281 : /* name. But even if that seems to fail we will continue since */
1282 : /* it might just be a corrupt file or something. */
1283 : /* -------------------------------------------------------------------- */
1284 : const bool bAppendSubdataset =
1285 11135 : CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false);
1286 : // Note: @QUIET_DELETE_ON_CREATE_COPY is set to NO by the KMLSuperOverlay
1287 : // driver when writing a .kmz file. Also by GDALTranslate() if it has
1288 : // already done a similar job.
1289 22250 : if (!bAppendSubdataset &&
1290 11115 : CPLFetchBool(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY", true))
1291 : {
1292 8718 : QuietDeleteForCreateCopy(pszFilename, poSrcDS);
1293 : }
1294 :
1295 : int iIdxQuietDeleteOnCreateCopy =
1296 11135 : CSLPartialFindString(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY=");
1297 11135 : if (iIdxQuietDeleteOnCreateCopy >= 0)
1298 : {
1299 2397 : if (papszOptionsToDelete == nullptr)
1300 1381 : papszOptionsToDelete = CSLDuplicate(papszOptions);
1301 2397 : papszOptionsToDelete = CSLRemoveStrings(
1302 : papszOptionsToDelete, iIdxQuietDeleteOnCreateCopy, 1, nullptr);
1303 2397 : papszOptions = papszOptionsToDelete;
1304 : }
1305 :
1306 : /* -------------------------------------------------------------------- */
1307 : /* If _INTERNAL_DATASET=YES, the returned dataset will not be */
1308 : /* registered in the global list of open datasets. */
1309 : /* -------------------------------------------------------------------- */
1310 : const int iIdxInternalDataset =
1311 11135 : CSLPartialFindString(papszOptions, "_INTERNAL_DATASET=");
1312 11135 : bool bInternalDataset = false;
1313 11135 : if (iIdxInternalDataset >= 0)
1314 : {
1315 : bInternalDataset =
1316 4165 : CPLFetchBool(papszOptions, "_INTERNAL_DATASET", false);
1317 4165 : if (papszOptionsToDelete == nullptr)
1318 4165 : papszOptionsToDelete = CSLDuplicate(papszOptions);
1319 4165 : papszOptionsToDelete = CSLRemoveStrings(
1320 : papszOptionsToDelete, iIdxInternalDataset, 1, nullptr);
1321 4165 : papszOptions = papszOptionsToDelete;
1322 : }
1323 :
1324 : /* -------------------------------------------------------------------- */
1325 : /* Validate creation options. */
1326 : /* -------------------------------------------------------------------- */
1327 11135 : if (CPLTestBool(
1328 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
1329 : {
1330 22270 : auto poSrcGroup = poSrcDS->GetRootGroup();
1331 11135 : if (poSrcGroup != nullptr && GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER))
1332 : {
1333 218 : CPLStringList aosDatasetCO;
1334 116 : for (const char *pszOption : cpl::Iterate(papszOptions))
1335 : {
1336 7 : if (!STARTS_WITH_CI(pszOption, "ARRAY:"))
1337 0 : aosDatasetCO.AddString(pszOption);
1338 : }
1339 109 : GDALValidateCreationOptions(this, aosDatasetCO.List());
1340 : }
1341 : else
1342 : {
1343 11026 : GDALValidateCreationOptions(this, papszOptions);
1344 : }
1345 : }
1346 :
1347 : /* -------------------------------------------------------------------- */
1348 : /* Advise the source raster that we are going to read it completely */
1349 : /* -------------------------------------------------------------------- */
1350 :
1351 11135 : const int nXSize = poSrcDS->GetRasterXSize();
1352 11135 : const int nYSize = poSrcDS->GetRasterYSize();
1353 11135 : GDALDataType eDT = GDT_Unknown;
1354 11135 : if (nBandCount > 0)
1355 : {
1356 10911 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
1357 10911 : if (poSrcBand)
1358 10911 : eDT = poSrcBand->GetRasterDataType();
1359 : }
1360 11135 : poSrcDS->AdviseRead(0, 0, nXSize, nYSize, nXSize, nYSize, eDT, nBandCount,
1361 11135 : nullptr, nullptr);
1362 :
1363 : /* -------------------------------------------------------------------- */
1364 : /* If the format provides a CreateCopy() method use that, */
1365 : /* otherwise fallback to the internal implementation using the */
1366 : /* Create() method. */
1367 : /* -------------------------------------------------------------------- */
1368 11135 : GDALDataset *poDstDS = nullptr;
1369 11135 : auto l_pfnCreateCopy = GetCreateCopyCallback();
1370 21149 : if (l_pfnCreateCopy != nullptr &&
1371 10014 : !CPLTestBool(CPLGetConfigOption("GDAL_DEFAULT_CREATE_COPY", "NO")))
1372 : {
1373 10014 : poDstDS = l_pfnCreateCopy(pszFilename, poSrcDS, bStrict,
1374 : const_cast<char **>(papszOptions),
1375 : pfnProgress, pProgressData);
1376 10014 : if (poDstDS != nullptr)
1377 : {
1378 17808 : if (poDstDS->GetDescription() == nullptr ||
1379 8904 : strlen(poDstDS->GetDescription()) == 0)
1380 385 : poDstDS->SetDescription(pszFilename);
1381 :
1382 8904 : if (poDstDS->poDriver == nullptr)
1383 7852 : poDstDS->poDriver = this;
1384 :
1385 8904 : if (!bInternalDataset)
1386 4739 : poDstDS->AddToDatasetOpenList();
1387 : }
1388 : }
1389 : else
1390 : {
1391 1121 : poDstDS = DefaultCreateCopy(pszFilename, poSrcDS, bStrict, papszOptions,
1392 : pfnProgress, pProgressData);
1393 : }
1394 :
1395 11135 : CSLDestroy(papszOptionsToDelete);
1396 11135 : return poDstDS;
1397 : }
1398 :
1399 : /************************************************************************/
1400 : /* GDALCreateCopy() */
1401 : /************************************************************************/
1402 :
1403 : /**
1404 : * \brief Create a copy of a dataset.
1405 : *
1406 : * @see GDALDriver::CreateCopy()
1407 : */
1408 :
1409 6369 : GDALDatasetH CPL_STDCALL GDALCreateCopy(GDALDriverH hDriver,
1410 : const char *pszFilename,
1411 : GDALDatasetH hSrcDS, int bStrict,
1412 : CSLConstList papszOptions,
1413 : GDALProgressFunc pfnProgress,
1414 : void *pProgressData)
1415 :
1416 : {
1417 6369 : VALIDATE_POINTER1(hDriver, "GDALCreateCopy", nullptr);
1418 6369 : VALIDATE_POINTER1(hSrcDS, "GDALCreateCopy", nullptr);
1419 :
1420 6369 : return GDALDriver::FromHandle(hDriver)->CreateCopy(
1421 : pszFilename, GDALDataset::FromHandle(hSrcDS), bStrict, papszOptions,
1422 6369 : pfnProgress, pProgressData);
1423 : }
1424 :
1425 : /************************************************************************/
1426 : /* CanVectorTranslateFrom() */
1427 : /************************************************************************/
1428 :
1429 : /** Returns whether the driver can translate from a vector dataset,
1430 : * using the arguments passed to GDALVectorTranslate() stored in
1431 : * papszVectorTranslateArguments.
1432 : *
1433 : * This is used to determine if the driver supports the VectorTranslateFrom()
1434 : * operation.
1435 : *
1436 : * @param pszDestName Target dataset name
1437 : * @param poSourceDS Source dataset
1438 : * @param papszVectorTranslateArguments Non-positional arguments passed to
1439 : * GDALVectorTranslate() (may be nullptr)
1440 : * @param[out] ppapszFailureReasons nullptr, or a pointer to an null-terminated
1441 : * array of strings to record the reason(s) for the impossibility.
1442 : * @return true if VectorTranslateFrom() can be called with the same arguments.
1443 : * @since GDAL 3.8
1444 : */
1445 881 : bool GDALDriver::CanVectorTranslateFrom(
1446 : const char *pszDestName, GDALDataset *poSourceDS,
1447 : CSLConstList papszVectorTranslateArguments, char ***ppapszFailureReasons)
1448 :
1449 : {
1450 881 : if (ppapszFailureReasons)
1451 : {
1452 0 : *ppapszFailureReasons = nullptr;
1453 : }
1454 :
1455 881 : if (!pfnCanVectorTranslateFrom)
1456 : {
1457 875 : if (ppapszFailureReasons)
1458 : {
1459 0 : *ppapszFailureReasons = CSLAddString(
1460 : nullptr,
1461 : "CanVectorTranslateFrom() not implemented for this driver");
1462 : }
1463 875 : return false;
1464 : }
1465 :
1466 6 : char **papszFailureReasons = nullptr;
1467 6 : bool bRet = pfnCanVectorTranslateFrom(
1468 : pszDestName, poSourceDS, papszVectorTranslateArguments,
1469 : ppapszFailureReasons ? ppapszFailureReasons : &papszFailureReasons);
1470 6 : if (!ppapszFailureReasons)
1471 : {
1472 2 : for (const char *pszReason :
1473 10 : cpl::Iterate(static_cast<CSLConstList>(papszFailureReasons)))
1474 : {
1475 2 : CPLDebug("GDAL", "%s", pszReason);
1476 : }
1477 6 : CSLDestroy(papszFailureReasons);
1478 : }
1479 6 : return bRet;
1480 : }
1481 :
1482 193 : bool GDALDriver::HasOpenOption(const char *pszOpenOptionName) const
1483 : {
1484 193 : if (pszOpenOptionName == nullptr)
1485 0 : return false;
1486 :
1487 : // Const cast is safe here since we are only reading the metadata
1488 386 : auto pszOOMd{const_cast<GDALDriver *>(this)->GetMetadataItem(
1489 193 : GDAL_DMD_OPENOPTIONLIST)};
1490 193 : if (pszOOMd == nullptr)
1491 74 : return false;
1492 :
1493 238 : const CPLXMLTreeCloser oXml{CPLParseXMLString(pszOOMd)};
1494 1148 : for (CPLXMLNode *option = oXml->psChild; option != nullptr;
1495 1029 : option = option->psNext)
1496 : {
1497 1030 : if (EQUAL(CPLGetXMLValue(CPLGetXMLNode(option, "name"), nullptr, ""),
1498 : pszOpenOptionName))
1499 1 : return true;
1500 : }
1501 118 : return false;
1502 : }
1503 :
1504 : /************************************************************************/
1505 : /* VectorTranslateFrom() */
1506 : /************************************************************************/
1507 :
1508 : /** Create a copy of a vector dataset, using the arguments passed to
1509 : * GDALVectorTranslate() stored in papszVectorTranslateArguments.
1510 : *
1511 : * This may be implemented by some drivers that can convert from an existing
1512 : * dataset in an optimized way.
1513 : *
1514 : * This is for example used by the PMTiles to convert from MBTiles.
1515 : *
1516 : * @param pszDestName Target dataset name
1517 : * @param poSourceDS Source dataset
1518 : * @param papszVectorTranslateArguments Non-positional arguments passed to
1519 : * GDALVectorTranslate() (may be nullptr)
1520 : * @param pfnProgress a function to be used to report progress of the copy.
1521 : * @param pProgressData application data passed into progress function.
1522 : * @return a new dataset in case of success, or nullptr in case of error.
1523 : * @since GDAL 3.8
1524 : */
1525 4 : GDALDataset *GDALDriver::VectorTranslateFrom(
1526 : const char *pszDestName, GDALDataset *poSourceDS,
1527 : CSLConstList papszVectorTranslateArguments, GDALProgressFunc pfnProgress,
1528 : void *pProgressData)
1529 :
1530 : {
1531 4 : if (!pfnVectorTranslateFrom)
1532 : {
1533 0 : CPLError(CE_Failure, CPLE_AppDefined,
1534 : "VectorTranslateFrom() not implemented for this driver");
1535 0 : return nullptr;
1536 : }
1537 :
1538 4 : return pfnVectorTranslateFrom(pszDestName, poSourceDS,
1539 : papszVectorTranslateArguments, pfnProgress,
1540 4 : pProgressData);
1541 : }
1542 :
1543 : /************************************************************************/
1544 : /* QuietDelete() */
1545 : /************************************************************************/
1546 :
1547 : /**
1548 : * \brief Delete dataset if found.
1549 : *
1550 : * This is a helper method primarily used by Create() and
1551 : * CreateCopy() to predelete any dataset of the name soon to be
1552 : * created. It will attempt to delete the named dataset if
1553 : * one is found, otherwise it does nothing. An error is only
1554 : * returned if the dataset is found but the delete fails.
1555 : *
1556 : * This is a static method and it doesn't matter what driver instance
1557 : * it is invoked on. It will attempt to discover the correct driver
1558 : * using Identify().
1559 : *
1560 : * @param pszName the dataset name to try and delete.
1561 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
1562 : * terminated list of strings with the driver short names that must be
1563 : * considered. (Note: implemented only starting with GDAL 3.4.1)
1564 : * @return CE_None if the dataset does not exist, or is deleted without issues.
1565 : */
1566 :
1567 24153 : CPLErr GDALDriver::QuietDelete(const char *pszName,
1568 : CSLConstList papszAllowedDrivers)
1569 :
1570 : {
1571 : VSIStatBufL sStat;
1572 : const bool bExists =
1573 24153 : VSIStatExL(pszName, &sStat,
1574 24153 : VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0;
1575 :
1576 : #ifdef S_ISFIFO
1577 24153 : if (bExists && S_ISFIFO(sStat.st_mode))
1578 0 : return CE_None;
1579 : #endif
1580 :
1581 24153 : GDALDriver *poDriver = nullptr;
1582 24153 : if (papszAllowedDrivers)
1583 : {
1584 70 : GDALOpenInfo oOpenInfo(pszName, GDAL_OF_ALL);
1585 35 : for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
1586 : {
1587 : GDALDriver *poTmpDriver =
1588 35 : GDALDriver::FromHandle(GDALGetDriverByName(pszDriverName));
1589 35 : if (poTmpDriver)
1590 : {
1591 : const bool bIdentifyRes =
1592 35 : poTmpDriver->pfnIdentifyEx
1593 70 : ? poTmpDriver->pfnIdentifyEx(poTmpDriver, &oOpenInfo) >
1594 : 0
1595 70 : : poTmpDriver->pfnIdentify &&
1596 35 : poTmpDriver->pfnIdentify(&oOpenInfo) > 0;
1597 35 : if (bIdentifyRes)
1598 : {
1599 35 : poDriver = poTmpDriver;
1600 35 : break;
1601 : }
1602 : }
1603 : }
1604 : }
1605 : else
1606 : {
1607 48236 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1608 24118 : poDriver = GDALDriver::FromHandle(GDALIdentifyDriver(pszName, nullptr));
1609 : }
1610 :
1611 24153 : if (poDriver == nullptr)
1612 23260 : return CE_None;
1613 :
1614 937 : if (bExists && VSI_ISDIR(sStat.st_mode) &&
1615 44 : (EQUAL(poDriver->GetDescription(), "MapInfo File") ||
1616 44 : EQUAL(poDriver->GetDescription(), "ESRI Shapefile")))
1617 : {
1618 : // Those drivers are a bit special and handle directories as container
1619 : // of layers, but it is quite common to found other files too, and
1620 : // removing the directory might be non-desirable.
1621 42 : return CE_None;
1622 : }
1623 :
1624 851 : CPLDebug("GDAL", "QuietDelete(%s) invoking Delete()", pszName);
1625 :
1626 851 : poDriver->pfnDelete = poDriver->GetDeleteCallback();
1627 889 : const bool bQuiet = !bExists && poDriver->pfnDelete == nullptr &&
1628 38 : poDriver->pfnDeleteDataSource == nullptr;
1629 851 : if (bQuiet)
1630 : {
1631 76 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1632 38 : return poDriver->Delete(pszName);
1633 : }
1634 : else
1635 : {
1636 813 : return poDriver->Delete(pszName);
1637 : }
1638 : }
1639 :
1640 : /************************************************************************/
1641 : /* Delete() */
1642 : /************************************************************************/
1643 :
1644 : /**
1645 : * \brief Delete named dataset.
1646 : *
1647 : * The driver will attempt to delete the named dataset in a driver specific
1648 : * fashion. Full featured drivers will delete all associated files,
1649 : * database objects, or whatever is appropriate. The default behavior when
1650 : * no driver specific behavior is provided is to attempt to delete all the
1651 : * files that are returned by GDALGetFileList() on the dataset handle.
1652 : *
1653 : * It is unwise to have open dataset handles on this dataset when it is
1654 : * deleted.
1655 : *
1656 : * Equivalent of the C function GDALDeleteDataset().
1657 : *
1658 : * @param pszFilename name of dataset to delete.
1659 : *
1660 : * @return CE_None on success, or CE_Failure if the operation fails.
1661 : */
1662 :
1663 4365 : CPLErr GDALDriver::Delete(const char *pszFilename)
1664 :
1665 : {
1666 4365 : pfnDelete = GetDeleteCallback();
1667 4365 : if (pfnDelete != nullptr)
1668 1075 : return pfnDelete(pszFilename);
1669 3290 : else if (pfnDeleteDataSource != nullptr)
1670 0 : return pfnDeleteDataSource(this, pszFilename);
1671 :
1672 : /* -------------------------------------------------------------------- */
1673 : /* Collect file list. */
1674 : /* -------------------------------------------------------------------- */
1675 3290 : GDALDatasetH hDS = GDALOpenEx(pszFilename, 0, nullptr, nullptr, nullptr);
1676 :
1677 3290 : if (hDS == nullptr)
1678 : {
1679 238 : if (CPLGetLastErrorNo() == 0)
1680 211 : CPLError(CE_Failure, CPLE_OpenFailed,
1681 : "Unable to open %s to obtain file list.", pszFilename);
1682 :
1683 238 : return CE_Failure;
1684 : }
1685 :
1686 6104 : const CPLStringList aosFileList(GDALGetFileList(hDS));
1687 :
1688 3052 : GDALClose(hDS);
1689 3052 : hDS = nullptr;
1690 :
1691 3052 : if (aosFileList.empty())
1692 : {
1693 0 : CPLError(CE_Failure, CPLE_NotSupported,
1694 : "Unable to determine files associated with %s, "
1695 : "delete fails.",
1696 : pszFilename);
1697 0 : return CE_Failure;
1698 : }
1699 :
1700 3052 : return Delete(nullptr, aosFileList.List());
1701 : }
1702 :
1703 : /************************************************************************/
1704 : /* Delete() */
1705 : /************************************************************************/
1706 :
1707 : /**
1708 : * \brief Delete a currently opened dataset
1709 : *
1710 : * The driver will attempt to delete the passed dataset in a driver specific
1711 : * fashion. Full featured drivers will delete all associated files,
1712 : * database objects, or whatever is appropriate. The default behavior when
1713 : * no driver specific behavior is provided is to attempt to delete all the
1714 : * files that are returned by GDALGetFileList() on the dataset handle.
1715 : *
1716 : * Note that this will generally not work on Windows systems that don't accept
1717 : * deleting opened files.
1718 : *
1719 : * At least one of poDS or papszFileList must not be NULL
1720 : *
1721 : * @param poDS dataset to delete, or NULL
1722 : * @param papszFileList File list to delete, typically obtained with
1723 : * poDS->GetFileList(), or NULL
1724 : *
1725 : * @return CE_None on success, or CE_Failure if the operation fails.
1726 : *
1727 : * @since 3.12
1728 : */
1729 :
1730 3063 : CPLErr GDALDriver::Delete(GDALDataset *poDS, CSLConstList papszFileList)
1731 :
1732 : {
1733 3063 : if (poDS)
1734 : {
1735 10 : pfnDelete = GetDeleteCallback();
1736 10 : if (pfnDelete != nullptr)
1737 6 : return pfnDelete(poDS->GetDescription());
1738 4 : else if (pfnDeleteDataSource != nullptr)
1739 0 : return pfnDeleteDataSource(this, poDS->GetDescription());
1740 : }
1741 :
1742 : /* -------------------------------------------------------------------- */
1743 : /* Delete all files. */
1744 : /* -------------------------------------------------------------------- */
1745 3057 : CPLErr eErr = CE_None;
1746 6765 : for (int i = 0; papszFileList && papszFileList[i]; ++i)
1747 : {
1748 3708 : if (VSIUnlink(papszFileList[i]) != 0)
1749 : {
1750 4 : CPLError(CE_Failure, CPLE_AppDefined, "Deleting %s failed:\n%s",
1751 2 : papszFileList[i], VSIStrerror(errno));
1752 2 : eErr = CE_Failure;
1753 : }
1754 : }
1755 :
1756 3057 : return eErr;
1757 : }
1758 :
1759 : /************************************************************************/
1760 : /* GDALDeleteDataset() */
1761 : /************************************************************************/
1762 :
1763 : /**
1764 : * \brief Delete named dataset.
1765 : *
1766 : * @see GDALDriver::Delete()
1767 : */
1768 :
1769 2391 : CPLErr CPL_STDCALL GDALDeleteDataset(GDALDriverH hDriver,
1770 : const char *pszFilename)
1771 :
1772 : {
1773 2391 : if (hDriver == nullptr)
1774 10 : hDriver = GDALIdentifyDriver(pszFilename, nullptr);
1775 :
1776 2391 : if (hDriver == nullptr)
1777 : {
1778 1 : CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
1779 : pszFilename);
1780 1 : return CE_Failure;
1781 : }
1782 :
1783 : #ifdef OGRAPISPY_ENABLED
1784 2390 : if (GDALGetMetadataItem(hDriver, GDAL_DCAP_VECTOR, nullptr))
1785 : {
1786 453 : OGRAPISpyDeleteDataSource(hDriver, pszFilename);
1787 : }
1788 : #endif
1789 :
1790 2390 : return GDALDriver::FromHandle(hDriver)->Delete(pszFilename);
1791 : }
1792 :
1793 : /************************************************************************/
1794 : /* DefaultRename() */
1795 : /* */
1796 : /* The generic implementation based on the file list used when */
1797 : /* there is no format specific implementation. */
1798 : /************************************************************************/
1799 :
1800 : //! @cond Doxygen_Suppress
1801 173 : CPLErr GDALDriver::DefaultRename(const char *pszNewName, const char *pszOldName)
1802 :
1803 : {
1804 : /* -------------------------------------------------------------------- */
1805 : /* Collect file list. */
1806 : /* -------------------------------------------------------------------- */
1807 173 : GDALDatasetH hDS = GDALOpen(pszOldName, GA_ReadOnly);
1808 :
1809 173 : if (hDS == nullptr)
1810 : {
1811 0 : if (CPLGetLastErrorNo() == 0)
1812 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1813 : "Unable to open %s to obtain file list.", pszOldName);
1814 :
1815 0 : return CE_Failure;
1816 : }
1817 :
1818 173 : char **papszFileList = GDALGetFileList(hDS);
1819 :
1820 173 : GDALClose(hDS);
1821 :
1822 173 : if (CSLCount(papszFileList) == 0)
1823 : {
1824 0 : CPLError(CE_Failure, CPLE_NotSupported,
1825 : "Unable to determine files associated with %s,\n"
1826 : "rename fails.",
1827 : pszOldName);
1828 :
1829 0 : return CE_Failure;
1830 : }
1831 :
1832 : /* -------------------------------------------------------------------- */
1833 : /* Produce a list of new filenames that correspond to the old */
1834 : /* names. */
1835 : /* -------------------------------------------------------------------- */
1836 173 : CPLErr eErr = CE_None;
1837 : char **papszNewFileList =
1838 173 : CPLCorrespondingPaths(pszOldName, pszNewName, papszFileList);
1839 :
1840 173 : if (papszNewFileList == nullptr)
1841 0 : return CE_Failure;
1842 :
1843 353 : for (int i = 0; papszFileList[i] != nullptr; ++i)
1844 : {
1845 180 : if (CPLMoveFile(papszNewFileList[i], papszFileList[i]) != 0)
1846 : {
1847 0 : eErr = CE_Failure;
1848 : // Try to put the ones we moved back.
1849 0 : for (--i; i >= 0; i--)
1850 : {
1851 : // Nothing we can do if the moving back doesn't work...
1852 0 : CPL_IGNORE_RET_VAL(
1853 0 : CPLMoveFile(papszFileList[i], papszNewFileList[i]));
1854 : }
1855 0 : break;
1856 : }
1857 : }
1858 :
1859 173 : CSLDestroy(papszNewFileList);
1860 173 : CSLDestroy(papszFileList);
1861 :
1862 173 : return eErr;
1863 : }
1864 :
1865 : //! @endcond
1866 :
1867 : /************************************************************************/
1868 : /* Rename() */
1869 : /************************************************************************/
1870 :
1871 : /**
1872 : * \brief Rename a dataset.
1873 : *
1874 : * Rename a dataset. This may including moving the dataset to a new directory
1875 : * or even a new filesystem.
1876 : *
1877 : * It is unwise to have open dataset handles on this dataset when it is
1878 : * being renamed.
1879 : *
1880 : * Equivalent of the C function GDALRenameDataset().
1881 : *
1882 : * @param pszNewName new name for the dataset.
1883 : * @param pszOldName old name for the dataset.
1884 : *
1885 : * @return CE_None on success, or CE_Failure if the operation fails.
1886 : */
1887 :
1888 175 : CPLErr GDALDriver::Rename(const char *pszNewName, const char *pszOldName)
1889 :
1890 : {
1891 175 : pfnRename = GetRenameCallback();
1892 175 : if (pfnRename != nullptr)
1893 3 : return pfnRename(pszNewName, pszOldName);
1894 :
1895 172 : return DefaultRename(pszNewName, pszOldName);
1896 : }
1897 :
1898 : /************************************************************************/
1899 : /* GDALRenameDataset() */
1900 : /************************************************************************/
1901 :
1902 : /**
1903 : * \brief Rename a dataset.
1904 : *
1905 : * @see GDALDriver::Rename()
1906 : */
1907 :
1908 176 : CPLErr CPL_STDCALL GDALRenameDataset(GDALDriverH hDriver,
1909 : const char *pszNewName,
1910 : const char *pszOldName)
1911 :
1912 : {
1913 176 : if (hDriver == nullptr)
1914 3 : hDriver = GDALIdentifyDriver(pszOldName, nullptr);
1915 :
1916 176 : if (hDriver == nullptr)
1917 : {
1918 1 : CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
1919 : pszOldName);
1920 1 : return CE_Failure;
1921 : }
1922 :
1923 175 : return GDALDriver::FromHandle(hDriver)->Rename(pszNewName, pszOldName);
1924 : }
1925 :
1926 : /************************************************************************/
1927 : /* DefaultCopyFiles() */
1928 : /* */
1929 : /* The default implementation based on file lists used when */
1930 : /* there is no format specific implementation. */
1931 : /************************************************************************/
1932 :
1933 : //! @cond Doxygen_Suppress
1934 10 : CPLErr GDALDriver::DefaultCopyFiles(const char *pszNewName,
1935 : const char *pszOldName)
1936 :
1937 : {
1938 : /* -------------------------------------------------------------------- */
1939 : /* Collect file list. */
1940 : /* -------------------------------------------------------------------- */
1941 10 : GDALDatasetH hDS = GDALOpen(pszOldName, GA_ReadOnly);
1942 :
1943 10 : if (hDS == nullptr)
1944 : {
1945 0 : if (CPLGetLastErrorNo() == 0)
1946 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1947 : "Unable to open %s to obtain file list.", pszOldName);
1948 :
1949 0 : return CE_Failure;
1950 : }
1951 :
1952 10 : char **papszFileList = GDALGetFileList(hDS);
1953 :
1954 10 : GDALClose(hDS);
1955 10 : hDS = nullptr;
1956 :
1957 10 : if (CSLCount(papszFileList) == 0)
1958 : {
1959 0 : CPLError(CE_Failure, CPLE_NotSupported,
1960 : "Unable to determine files associated with %s,\n"
1961 : "rename fails.",
1962 : pszOldName);
1963 :
1964 0 : return CE_Failure;
1965 : }
1966 :
1967 : /* -------------------------------------------------------------------- */
1968 : /* Produce a list of new filenames that correspond to the old */
1969 : /* names. */
1970 : /* -------------------------------------------------------------------- */
1971 10 : CPLErr eErr = CE_None;
1972 : char **papszNewFileList =
1973 10 : CPLCorrespondingPaths(pszOldName, pszNewName, papszFileList);
1974 :
1975 10 : if (papszNewFileList == nullptr)
1976 0 : return CE_Failure;
1977 :
1978 28 : for (int i = 0; papszFileList[i] != nullptr; ++i)
1979 : {
1980 18 : if (CPLCopyFile(papszNewFileList[i], papszFileList[i]) != 0)
1981 : {
1982 0 : eErr = CE_Failure;
1983 : // Try to put the ones we moved back.
1984 0 : for (--i; i >= 0; --i)
1985 0 : VSIUnlink(papszNewFileList[i]);
1986 0 : break;
1987 : }
1988 : }
1989 :
1990 10 : CSLDestroy(papszNewFileList);
1991 10 : CSLDestroy(papszFileList);
1992 :
1993 10 : return eErr;
1994 : }
1995 :
1996 : //! @endcond
1997 :
1998 : /************************************************************************/
1999 : /* CopyFiles() */
2000 : /************************************************************************/
2001 :
2002 : /**
2003 : * \brief Copy the files of a dataset.
2004 : *
2005 : * Copy all the files associated with a dataset.
2006 : *
2007 : * Equivalent of the C function GDALCopyDatasetFiles().
2008 : *
2009 : * @param pszNewName new name for the dataset.
2010 : * @param pszOldName old name for the dataset.
2011 : *
2012 : * @return CE_None on success, or CE_Failure if the operation fails.
2013 : */
2014 :
2015 12 : CPLErr GDALDriver::CopyFiles(const char *pszNewName, const char *pszOldName)
2016 :
2017 : {
2018 12 : pfnCopyFiles = GetCopyFilesCallback();
2019 12 : if (pfnCopyFiles != nullptr)
2020 3 : return pfnCopyFiles(pszNewName, pszOldName);
2021 :
2022 9 : return DefaultCopyFiles(pszNewName, pszOldName);
2023 : }
2024 :
2025 : /************************************************************************/
2026 : /* GDALCopyDatasetFiles() */
2027 : /************************************************************************/
2028 :
2029 : /**
2030 : * \brief Copy the files of a dataset.
2031 : *
2032 : * @see GDALDriver::CopyFiles()
2033 : */
2034 :
2035 13 : CPLErr CPL_STDCALL GDALCopyDatasetFiles(GDALDriverH hDriver,
2036 : const char *pszNewName,
2037 : const char *pszOldName)
2038 :
2039 : {
2040 13 : if (hDriver == nullptr)
2041 8 : hDriver = GDALIdentifyDriver(pszOldName, nullptr);
2042 :
2043 13 : if (hDriver == nullptr)
2044 : {
2045 1 : CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
2046 : pszOldName);
2047 1 : return CE_Failure;
2048 : }
2049 :
2050 12 : return GDALDriver::FromHandle(hDriver)->CopyFiles(pszNewName, pszOldName);
2051 : }
2052 :
2053 : /************************************************************************/
2054 : /* GDALDriverHasOpenOption() */
2055 : /************************************************************************/
2056 :
2057 : /**
2058 : * \brief Returns TRUE if the given open option is supported by the driver.
2059 : * @param hDriver the handle of the driver
2060 : * @param pszOpenOptionName name of the open option to be checked
2061 : * @return TRUE if the driver supports the open option
2062 : * @since GDAL 3.11
2063 : */
2064 2 : bool GDALDriverHasOpenOption(GDALDriverH hDriver, const char *pszOpenOptionName)
2065 : {
2066 2 : VALIDATE_POINTER1(hDriver, "GDALDriverHasOpenOption", false);
2067 2 : return GDALDriver::FromHandle(hDriver)->HasOpenOption(pszOpenOptionName);
2068 : }
2069 :
2070 : /************************************************************************/
2071 : /* GDALGetDriverShortName() */
2072 : /************************************************************************/
2073 :
2074 : /**
2075 : * \brief Return the short name of a driver
2076 : *
2077 : * This is the string that can be
2078 : * passed to the GDALGetDriverByName() function.
2079 : *
2080 : * For the GeoTIFF driver, this is "GTiff"
2081 : *
2082 : * @param hDriver the handle of the driver
2083 : * @return the short name of the driver. The
2084 : * returned string should not be freed and is owned by the driver.
2085 : */
2086 :
2087 3722540 : const char *CPL_STDCALL GDALGetDriverShortName(GDALDriverH hDriver)
2088 :
2089 : {
2090 3722540 : VALIDATE_POINTER1(hDriver, "GDALGetDriverShortName", nullptr);
2091 :
2092 3722540 : return GDALDriver::FromHandle(hDriver)->GetDescription();
2093 : }
2094 :
2095 : /************************************************************************/
2096 : /* GDALGetDriverLongName() */
2097 : /************************************************************************/
2098 :
2099 : /**
2100 : * \brief Return the long name of a driver
2101 : *
2102 : * For the GeoTIFF driver, this is "GeoTIFF"
2103 : *
2104 : * @param hDriver the handle of the driver
2105 : * @return the long name of the driver or empty string. The
2106 : * returned string should not be freed and is owned by the driver.
2107 : */
2108 :
2109 496 : const char *CPL_STDCALL GDALGetDriverLongName(GDALDriverH hDriver)
2110 :
2111 : {
2112 496 : VALIDATE_POINTER1(hDriver, "GDALGetDriverLongName", nullptr);
2113 :
2114 : const char *pszLongName =
2115 496 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_LONGNAME);
2116 :
2117 496 : if (pszLongName == nullptr)
2118 0 : return "";
2119 :
2120 496 : return pszLongName;
2121 : }
2122 :
2123 : /************************************************************************/
2124 : /* GDALGetDriverHelpTopic() */
2125 : /************************************************************************/
2126 :
2127 : /**
2128 : * \brief Return the URL to the help that describes the driver
2129 : *
2130 : * That URL is relative to the GDAL documentation directory.
2131 : *
2132 : * For the GeoTIFF driver, this is "frmt_gtiff.html"
2133 : *
2134 : * @param hDriver the handle of the driver
2135 : * @return the URL to the help that describes the driver or NULL. The
2136 : * returned string should not be freed and is owned by the driver.
2137 : */
2138 :
2139 0 : const char *CPL_STDCALL GDALGetDriverHelpTopic(GDALDriverH hDriver)
2140 :
2141 : {
2142 0 : VALIDATE_POINTER1(hDriver, "GDALGetDriverHelpTopic", nullptr);
2143 :
2144 0 : return GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_HELPTOPIC);
2145 : }
2146 :
2147 : /************************************************************************/
2148 : /* GDALGetDriverCreationOptionList() */
2149 : /************************************************************************/
2150 :
2151 : /**
2152 : * \brief Return the list of creation options of the driver
2153 : *
2154 : * Return the list of creation options of the driver used by Create() and
2155 : * CreateCopy() as an XML string
2156 : *
2157 : * @param hDriver the handle of the driver
2158 : * @return an XML string that describes the list of creation options or
2159 : * empty string. The returned string should not be freed and is
2160 : * owned by the driver.
2161 : */
2162 :
2163 0 : const char *CPL_STDCALL GDALGetDriverCreationOptionList(GDALDriverH hDriver)
2164 :
2165 : {
2166 0 : VALIDATE_POINTER1(hDriver, "GDALGetDriverCreationOptionList", nullptr);
2167 :
2168 : const char *pszOptionList =
2169 0 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2170 0 : GDAL_DMD_CREATIONOPTIONLIST);
2171 :
2172 0 : if (pszOptionList == nullptr)
2173 0 : return "";
2174 :
2175 0 : return pszOptionList;
2176 : }
2177 :
2178 : /************************************************************************/
2179 : /* GDALValidateCreationOptions() */
2180 : /************************************************************************/
2181 :
2182 : /**
2183 : * \brief Validate the list of creation options that are handled by a driver
2184 : *
2185 : * This is a helper method primarily used by Create() and
2186 : * CreateCopy() to validate that the passed in list of creation options
2187 : * is compatible with the GDAL_DMD_CREATIONOPTIONLIST metadata item defined
2188 : * by some drivers. @see GDALGetDriverCreationOptionList()
2189 : *
2190 : * If the GDAL_DMD_CREATIONOPTIONLIST metadata item is not defined, this
2191 : * function will return TRUE. Otherwise it will check that the keys and values
2192 : * in the list of creation options are compatible with the capabilities declared
2193 : * by the GDAL_DMD_CREATIONOPTIONLIST metadata item. In case of incompatibility
2194 : * a (non fatal) warning will be emitted and FALSE will be returned.
2195 : *
2196 : * @param hDriver the handle of the driver with whom the lists of creation
2197 : * option must be validated
2198 : * @param papszCreationOptions the list of creation options. An array of
2199 : * strings, whose last element is a NULL pointer
2200 : * @return TRUE if the list of creation options is compatible with the Create()
2201 : * and CreateCopy() method of the driver, FALSE otherwise.
2202 : */
2203 :
2204 35145 : int CPL_STDCALL GDALValidateCreationOptions(GDALDriverH hDriver,
2205 : CSLConstList papszCreationOptions)
2206 : {
2207 35145 : VALIDATE_POINTER1(hDriver, "GDALValidateCreationOptions", FALSE);
2208 : const char *pszOptionList =
2209 35145 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2210 35145 : GDAL_DMD_CREATIONOPTIONLIST);
2211 35145 : CPLString osDriver;
2212 : osDriver.Printf("driver %s",
2213 35145 : GDALDriver::FromHandle(hDriver)->GetDescription());
2214 35145 : bool bFoundOptionToRemove = false;
2215 35145 : constexpr const char *const apszExcludedOptions[] = {
2216 : "APPEND_SUBDATASET", "COPY_SRC_MDD", "SRC_MDD", "SKIP_HOLES"};
2217 51112 : for (const char *pszCO : cpl::Iterate(papszCreationOptions))
2218 : {
2219 80460 : for (const char *pszExcludedOptions : apszExcludedOptions)
2220 : {
2221 64493 : if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
2222 196 : pszCO[strlen(pszExcludedOptions)] == '=')
2223 : {
2224 196 : bFoundOptionToRemove = true;
2225 196 : break;
2226 : }
2227 : }
2228 16163 : if (bFoundOptionToRemove)
2229 196 : break;
2230 : }
2231 35145 : CSLConstList papszOptionsToValidate = papszCreationOptions;
2232 35145 : char **papszOptionsToFree = nullptr;
2233 35145 : if (bFoundOptionToRemove)
2234 : {
2235 596 : for (const char *pszCO : cpl::Iterate(papszCreationOptions))
2236 : {
2237 400 : bool bMatch = false;
2238 1625 : for (const char *pszExcludedOptions : apszExcludedOptions)
2239 : {
2240 1434 : if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
2241 209 : pszCO[strlen(pszExcludedOptions)] == '=')
2242 : {
2243 209 : bMatch = true;
2244 209 : break;
2245 : }
2246 : }
2247 400 : if (!bMatch)
2248 191 : papszOptionsToFree = CSLAddString(papszOptionsToFree, pszCO);
2249 : }
2250 196 : papszOptionsToValidate = papszOptionsToFree;
2251 : }
2252 :
2253 35145 : const bool bRet = CPL_TO_BOOL(GDALValidateOptions(
2254 : pszOptionList, papszOptionsToValidate, "creation option", osDriver));
2255 35145 : CSLDestroy(papszOptionsToFree);
2256 35145 : return bRet;
2257 : }
2258 :
2259 : /************************************************************************/
2260 : /* GDALValidateOpenOptions() */
2261 : /************************************************************************/
2262 :
2263 57562 : int GDALValidateOpenOptions(GDALDriverH hDriver,
2264 : const char *const *papszOpenOptions)
2265 : {
2266 57562 : VALIDATE_POINTER1(hDriver, "GDALValidateOpenOptions", FALSE);
2267 : const char *pszOptionList =
2268 57562 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2269 57553 : GDAL_DMD_OPENOPTIONLIST);
2270 115043 : CPLString osDriver;
2271 : osDriver.Printf("driver %s",
2272 57520 : GDALDriver::FromHandle(hDriver)->GetDescription());
2273 57537 : return GDALValidateOptions(pszOptionList, papszOpenOptions, "open option",
2274 57494 : osDriver);
2275 : }
2276 :
2277 : /************************************************************************/
2278 : /* GDALValidateOptions() */
2279 : /************************************************************************/
2280 :
2281 106190 : int GDALValidateOptions(const char *pszOptionList,
2282 : const char *const *papszOptionsToValidate,
2283 : const char *pszErrorMessageOptionType,
2284 : const char *pszErrorMessageContainerName)
2285 : {
2286 106190 : if (papszOptionsToValidate == nullptr || *papszOptionsToValidate == nullptr)
2287 89555 : return TRUE;
2288 16635 : if (pszOptionList == nullptr)
2289 178 : return TRUE;
2290 :
2291 16457 : CPLXMLNode *psNode = CPLParseXMLString(pszOptionList);
2292 16457 : if (psNode == nullptr)
2293 : {
2294 0 : CPLError(CE_Warning, CPLE_AppDefined,
2295 : "Could not parse %s list of %s. Assuming options are valid.",
2296 : pszErrorMessageOptionType, pszErrorMessageContainerName);
2297 0 : return TRUE;
2298 : }
2299 :
2300 16457 : bool bRet = true;
2301 44556 : while (*papszOptionsToValidate)
2302 : {
2303 28099 : char *pszKey = nullptr;
2304 : const char *pszValue =
2305 28099 : CPLParseNameValue(*papszOptionsToValidate, &pszKey);
2306 28099 : if (pszKey == nullptr)
2307 : {
2308 1 : CPLError(CE_Warning, CPLE_NotSupported,
2309 : "%s '%s' is not formatted with the key=value format",
2310 : pszErrorMessageOptionType, *papszOptionsToValidate);
2311 1 : bRet = false;
2312 :
2313 1 : ++papszOptionsToValidate;
2314 2132 : continue;
2315 : }
2316 :
2317 28098 : if (EQUAL(pszKey, "VALIDATE_OPEN_OPTIONS"))
2318 : {
2319 0 : ++papszOptionsToValidate;
2320 0 : CPLFree(pszKey);
2321 0 : continue;
2322 : }
2323 :
2324 : // Must we be forgiving in case of missing option ?
2325 28098 : bool bWarnIfMissingKey = true;
2326 28098 : if (pszKey[0] == '@')
2327 : {
2328 2116 : bWarnIfMissingKey = false;
2329 2116 : memmove(pszKey, pszKey + 1, strlen(pszKey + 1) + 1);
2330 : }
2331 :
2332 28098 : CPLXMLNode *psChildNode = psNode->psChild;
2333 275574 : while (psChildNode)
2334 : {
2335 273443 : if (EQUAL(psChildNode->pszValue, "OPTION"))
2336 : {
2337 : const char *pszOptionName =
2338 273443 : CPLGetXMLValue(psChildNode, "name", "");
2339 : /* For option names terminated by wildcard (NITF BLOCKA option
2340 : * names for example) */
2341 273443 : if (strlen(pszOptionName) > 0 &&
2342 273443 : pszOptionName[strlen(pszOptionName) - 1] == '*' &&
2343 378 : EQUALN(pszOptionName, pszKey, strlen(pszOptionName) - 1))
2344 : {
2345 216 : break;
2346 : }
2347 :
2348 : /* For option names beginning by a wildcard */
2349 273227 : if (pszOptionName[0] == '*' &&
2350 57 : strlen(pszKey) > strlen(pszOptionName) &&
2351 9 : EQUAL(pszKey + strlen(pszKey) - strlen(pszOptionName + 1),
2352 : pszOptionName + 1))
2353 : {
2354 2 : break;
2355 : }
2356 :
2357 : // For options names with * in the middle
2358 273225 : const char *pszStarInOptionName = strchr(pszOptionName, '*');
2359 273225 : if (pszStarInOptionName &&
2360 183 : pszStarInOptionName != pszOptionName &&
2361 : pszStarInOptionName !=
2362 183 : pszOptionName + strlen(pszOptionName) - 1 &&
2363 21 : strlen(pszKey) > static_cast<size_t>(pszStarInOptionName -
2364 12 : pszOptionName) &&
2365 12 : EQUALN(pszKey, pszOptionName,
2366 : static_cast<size_t>(pszStarInOptionName -
2367 12 : pszOptionName)) &&
2368 12 : EQUAL(pszKey +
2369 : static_cast<size_t>(pszStarInOptionName -
2370 : pszOptionName) +
2371 : 1,
2372 : pszStarInOptionName + 1))
2373 : {
2374 6 : break;
2375 : }
2376 :
2377 273219 : if (EQUAL(pszOptionName, pszKey))
2378 : {
2379 25695 : break;
2380 : }
2381 247524 : const char *pszAlias = CPLGetXMLValue(
2382 : psChildNode, "alias",
2383 : CPLGetXMLValue(psChildNode, "deprecated_alias", ""));
2384 247524 : if (EQUAL(pszAlias, pszKey))
2385 : {
2386 48 : CPLDebug("GDAL",
2387 : "Using deprecated alias '%s'. New name is '%s'",
2388 : pszAlias, pszOptionName);
2389 48 : break;
2390 : }
2391 : }
2392 247476 : psChildNode = psChildNode->psNext;
2393 : }
2394 28098 : if (psChildNode == nullptr)
2395 : {
2396 2153 : if (bWarnIfMissingKey &&
2397 22 : (!EQUAL(pszErrorMessageOptionType, "open option") ||
2398 0 : CPLFetchBool(papszOptionsToValidate, "VALIDATE_OPEN_OPTIONS",
2399 : true)))
2400 : {
2401 22 : CPLError(CE_Warning, CPLE_NotSupported,
2402 : "%s does not support %s %s",
2403 : pszErrorMessageContainerName,
2404 : pszErrorMessageOptionType, pszKey);
2405 22 : bRet = false;
2406 : }
2407 :
2408 2131 : CPLFree(pszKey);
2409 2131 : ++papszOptionsToValidate;
2410 2131 : continue;
2411 : }
2412 :
2413 : #ifdef DEBUG
2414 25967 : CPLXMLNode *psChildSubNode = psChildNode->psChild;
2415 154324 : while (psChildSubNode)
2416 : {
2417 128357 : if (psChildSubNode->eType == CXT_Attribute)
2418 : {
2419 90094 : if (!(EQUAL(psChildSubNode->pszValue, "name") ||
2420 64127 : EQUAL(psChildSubNode->pszValue, "alias") ||
2421 64004 : EQUAL(psChildSubNode->pszValue, "deprecated_alias") ||
2422 63921 : EQUAL(psChildSubNode->pszValue, "alt_config_option") ||
2423 63904 : EQUAL(psChildSubNode->pszValue, "description") ||
2424 42127 : EQUAL(psChildSubNode->pszValue, "type") ||
2425 16160 : EQUAL(psChildSubNode->pszValue, "min") ||
2426 15871 : EQUAL(psChildSubNode->pszValue, "max") ||
2427 15514 : EQUAL(psChildSubNode->pszValue, "default") ||
2428 1020 : EQUAL(psChildSubNode->pszValue, "maxsize") ||
2429 995 : EQUAL(psChildSubNode->pszValue, "required") ||
2430 940 : EQUAL(psChildSubNode->pszValue, "scope")))
2431 : {
2432 : /* Driver error */
2433 0 : CPLError(CE_Warning, CPLE_NotSupported,
2434 : "%s : unhandled attribute '%s' for %s %s.",
2435 : pszErrorMessageContainerName,
2436 : psChildSubNode->pszValue, pszKey,
2437 : pszErrorMessageOptionType);
2438 : }
2439 : }
2440 128357 : psChildSubNode = psChildSubNode->psNext;
2441 : }
2442 : #endif
2443 :
2444 25967 : const char *pszType = CPLGetXMLValue(psChildNode, "type", nullptr);
2445 25967 : const char *pszMin = CPLGetXMLValue(psChildNode, "min", nullptr);
2446 25967 : const char *pszMax = CPLGetXMLValue(psChildNode, "max", nullptr);
2447 25967 : if (pszType != nullptr)
2448 : {
2449 25967 : if (EQUAL(pszType, "INT") || EQUAL(pszType, "INTEGER"))
2450 : {
2451 8632 : const char *pszValueIter = pszValue;
2452 22076 : while (*pszValueIter)
2453 : {
2454 13446 : if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
2455 20 : *pszValueIter == '+' || *pszValueIter == '-'))
2456 : {
2457 2 : CPLError(CE_Warning, CPLE_NotSupported,
2458 : "'%s' is an unexpected value for %s %s of "
2459 : "type int.",
2460 : pszValue, pszKey, pszErrorMessageOptionType);
2461 2 : bRet = false;
2462 2 : break;
2463 : }
2464 13444 : ++pszValueIter;
2465 : }
2466 8632 : if (*pszValueIter == '\0')
2467 : {
2468 8630 : if (pszMin && atoi(pszValue) < atoi(pszMin))
2469 : {
2470 10 : CPLError(CE_Warning, CPLE_NotSupported,
2471 : "'%s' is an unexpected value for %s %s that "
2472 : "should be >= %s.",
2473 : pszValue, pszKey, pszErrorMessageOptionType,
2474 : pszMin);
2475 10 : bRet = false;
2476 : }
2477 8630 : if (pszMax && atoi(pszValue) > atoi(pszMax))
2478 : {
2479 12 : CPLError(CE_Warning, CPLE_NotSupported,
2480 : "'%s' is an unexpected value for %s %s that "
2481 : "should be <= %s.",
2482 : pszValue, pszKey, pszErrorMessageOptionType,
2483 : pszMax);
2484 12 : bRet = false;
2485 : }
2486 8632 : }
2487 : }
2488 17335 : else if (EQUAL(pszType, "UNSIGNED INT"))
2489 : {
2490 3 : const char *pszValueIter = pszValue;
2491 10 : while (*pszValueIter)
2492 : {
2493 7 : if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
2494 0 : *pszValueIter == '+'))
2495 : {
2496 0 : CPLError(CE_Warning, CPLE_NotSupported,
2497 : "'%s' is an unexpected value for %s %s of "
2498 : "type unsigned int.",
2499 : pszValue, pszKey, pszErrorMessageOptionType);
2500 0 : bRet = false;
2501 0 : break;
2502 : }
2503 7 : ++pszValueIter;
2504 : }
2505 3 : if (*pszValueIter == '\0')
2506 : {
2507 3 : if (pszMin && atoi(pszValue) < atoi(pszMin))
2508 : {
2509 0 : CPLError(CE_Warning, CPLE_NotSupported,
2510 : "'%s' is an unexpected value for %s %s that "
2511 : "should be >= %s.",
2512 : pszValue, pszKey, pszErrorMessageOptionType,
2513 : pszMin);
2514 0 : bRet = false;
2515 : }
2516 3 : if (pszMax && atoi(pszValue) > atoi(pszMax))
2517 : {
2518 0 : CPLError(CE_Warning, CPLE_NotSupported,
2519 : "'%s' is an unexpected value for %s %s that "
2520 : "should be <= %s.",
2521 : pszValue, pszKey, pszErrorMessageOptionType,
2522 : pszMax);
2523 0 : bRet = false;
2524 : }
2525 : }
2526 : }
2527 17332 : else if (EQUAL(pszType, "FLOAT"))
2528 : {
2529 691 : char *endPtr = nullptr;
2530 691 : double dfVal = CPLStrtod(pszValue, &endPtr);
2531 691 : if (!(endPtr == nullptr || *endPtr == '\0'))
2532 : {
2533 0 : CPLError(
2534 : CE_Warning, CPLE_NotSupported,
2535 : "'%s' is an unexpected value for %s %s of type float.",
2536 : pszValue, pszKey, pszErrorMessageOptionType);
2537 0 : bRet = false;
2538 : }
2539 : else
2540 : {
2541 691 : if (pszMin && dfVal < CPLAtof(pszMin))
2542 : {
2543 2 : CPLError(CE_Warning, CPLE_NotSupported,
2544 : "'%s' is an unexpected value for %s %s that "
2545 : "should be >= %s.",
2546 : pszValue, pszKey, pszErrorMessageOptionType,
2547 : pszMin);
2548 2 : bRet = false;
2549 : }
2550 691 : if (pszMax && dfVal > CPLAtof(pszMax))
2551 : {
2552 0 : CPLError(CE_Warning, CPLE_NotSupported,
2553 : "'%s' is an unexpected value for %s %s that "
2554 : "should be <= %s.",
2555 : pszValue, pszKey, pszErrorMessageOptionType,
2556 : pszMax);
2557 0 : bRet = false;
2558 : }
2559 : }
2560 : }
2561 16641 : else if (EQUAL(pszType, "BOOLEAN"))
2562 : {
2563 3753 : if (!(EQUAL(pszValue, "ON") || EQUAL(pszValue, "TRUE") ||
2564 3696 : EQUAL(pszValue, "YES") || EQUAL(pszValue, "OFF") ||
2565 428 : EQUAL(pszValue, "FALSE") || EQUAL(pszValue, "NO")))
2566 : {
2567 0 : CPLError(CE_Warning, CPLE_NotSupported,
2568 : "'%s' is an unexpected value for %s %s of type "
2569 : "boolean.",
2570 : pszValue, pszKey, pszErrorMessageOptionType);
2571 0 : bRet = false;
2572 : }
2573 : }
2574 12888 : else if (EQUAL(pszType, "STRING-SELECT"))
2575 : {
2576 6646 : bool bMatchFound = false;
2577 6646 : CPLXMLNode *psStringSelect = psChildNode->psChild;
2578 41200 : while (psStringSelect)
2579 : {
2580 41163 : if (psStringSelect->eType == CXT_Element &&
2581 20084 : EQUAL(psStringSelect->pszValue, "Value"))
2582 : {
2583 20084 : CPLXMLNode *psOptionNode = psStringSelect->psChild;
2584 33861 : while (psOptionNode)
2585 : {
2586 20386 : if (psOptionNode->eType == CXT_Text &&
2587 20074 : EQUAL(psOptionNode->pszValue, pszValue))
2588 : {
2589 6599 : bMatchFound = true;
2590 6599 : break;
2591 : }
2592 13787 : if (psOptionNode->eType == CXT_Attribute &&
2593 312 : (EQUAL(psOptionNode->pszValue, "alias") ||
2594 15 : EQUAL(psOptionNode->pszValue,
2595 297 : "deprecated_alias")) &&
2596 297 : EQUAL(psOptionNode->psChild->pszValue,
2597 : pszValue))
2598 : {
2599 10 : bMatchFound = true;
2600 10 : break;
2601 : }
2602 13777 : psOptionNode = psOptionNode->psNext;
2603 : }
2604 20084 : if (bMatchFound)
2605 6609 : break;
2606 : }
2607 34554 : psStringSelect = psStringSelect->psNext;
2608 : }
2609 6646 : if (!bMatchFound)
2610 : {
2611 37 : CPLError(CE_Warning, CPLE_NotSupported,
2612 : "'%s' is an unexpected value for %s %s of type "
2613 : "string-select.",
2614 : pszValue, pszKey, pszErrorMessageOptionType);
2615 37 : bRet = false;
2616 : }
2617 : }
2618 6242 : else if (EQUAL(pszType, "STRING"))
2619 : {
2620 : const char *pszMaxSize =
2621 6242 : CPLGetXMLValue(psChildNode, "maxsize", nullptr);
2622 6242 : if (pszMaxSize != nullptr)
2623 : {
2624 25 : if (static_cast<int>(strlen(pszValue)) > atoi(pszMaxSize))
2625 : {
2626 1 : CPLError(CE_Warning, CPLE_NotSupported,
2627 : "'%s' is of size %d, whereas maximum size for "
2628 : "%s %s is %d.",
2629 1 : pszValue, static_cast<int>(strlen(pszValue)),
2630 : pszKey, pszErrorMessageOptionType,
2631 : atoi(pszMaxSize));
2632 1 : bRet = false;
2633 : }
2634 : }
2635 : }
2636 : else
2637 : {
2638 : /* Driver error */
2639 0 : CPLError(CE_Warning, CPLE_NotSupported,
2640 : "%s : type '%s' for %s %s is not recognized.",
2641 : pszErrorMessageContainerName, pszType, pszKey,
2642 : pszErrorMessageOptionType);
2643 : }
2644 : }
2645 : else
2646 : {
2647 : /* Driver error */
2648 0 : CPLError(CE_Warning, CPLE_NotSupported, "%s : no type for %s %s.",
2649 : pszErrorMessageContainerName, pszKey,
2650 : pszErrorMessageOptionType);
2651 : }
2652 25967 : CPLFree(pszKey);
2653 25967 : ++papszOptionsToValidate;
2654 : }
2655 :
2656 16457 : CPLDestroyXMLNode(psNode);
2657 16457 : return bRet ? TRUE : FALSE;
2658 : }
2659 :
2660 : /************************************************************************/
2661 : /* GDALIdentifyDriver() */
2662 : /************************************************************************/
2663 :
2664 : /**
2665 : * \brief Identify the driver that can open a dataset.
2666 : *
2667 : * This function will try to identify the driver that can open the passed file
2668 : * name by invoking the Identify method of each registered GDALDriver in turn.
2669 : * The first driver that successfully identifies the file name will be returned.
2670 : * If all drivers fail then NULL is returned.
2671 : *
2672 : * In order to reduce the need for such searches to touch the operating system
2673 : * file system machinery, it is possible to give an optional list of files.
2674 : * This is the list of all files at the same level in the file system as the
2675 : * target file, including the target file. The filenames will not include any
2676 : * path components, and are essentially just the output of VSIReadDir() on the
2677 : * parent directory. If the target object does not have filesystem semantics
2678 : * then the file list should be NULL.
2679 : *
2680 : * @param pszFilename the name of the file to access. In the case of
2681 : * exotic drivers this may not refer to a physical file, but instead contain
2682 : * information for the driver on how to access a dataset.
2683 : *
2684 : * @param papszFileList an array of strings, whose last element is the NULL
2685 : * pointer. These strings are filenames that are auxiliary to the main
2686 : * filename. The passed value may be NULL.
2687 : *
2688 : * @return A GDALDriverH handle or NULL on failure. For C++ applications
2689 : * this handle can be cast to a GDALDriver *.
2690 : */
2691 :
2692 25511 : GDALDriverH CPL_STDCALL GDALIdentifyDriver(const char *pszFilename,
2693 : CSLConstList papszFileList)
2694 :
2695 : {
2696 25511 : return GDALIdentifyDriverEx(pszFilename, 0, nullptr, papszFileList);
2697 : }
2698 :
2699 : /************************************************************************/
2700 : /* GDALIdentifyDriverEx() */
2701 : /************************************************************************/
2702 :
2703 : /**
2704 : * \brief Identify the driver that can open a dataset.
2705 : *
2706 : * This function will try to identify the driver that can open the passed file
2707 : * name by invoking the Identify method of each registered GDALDriver in turn.
2708 : * The first driver that successfully identifies the file name will be returned.
2709 : * If all drivers fail then NULL is returned.
2710 : *
2711 : * In order to reduce the need for such searches to touch the operating system
2712 : * file system machinery, it is possible to give an optional list of files.
2713 : * This is the list of all files at the same level in the file system as the
2714 : * target file, including the target file. The filenames will not include any
2715 : * path components, and are essentially just the output of VSIReadDir() on the
2716 : * parent directory. If the target object does not have filesystem semantics
2717 : * then the file list should be NULL.
2718 : *
2719 : * @param pszFilename the name of the file to access. In the case of
2720 : * exotic drivers this may not refer to a physical file, but instead contain
2721 : * information for the driver on how to access a dataset.
2722 : *
2723 : * @param nIdentifyFlags a combination of GDAL_OF_RASTER for raster drivers
2724 : * or GDAL_OF_VECTOR for vector drivers. If none of the value is specified,
2725 : * both kinds are implied.
2726 : *
2727 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
2728 : * terminated list of strings with the driver short names that must be
2729 : * considered.
2730 : *
2731 : * @param papszFileList an array of strings, whose last element is the NULL
2732 : * pointer. These strings are filenames that are auxiliary to the main
2733 : * filename. The passed value may be NULL.
2734 : *
2735 : * @return A GDALDriverH handle or NULL on failure. For C++ applications
2736 : * this handle can be cast to a GDALDriver *.
2737 : */
2738 :
2739 25601 : GDALDriverH CPL_STDCALL GDALIdentifyDriverEx(
2740 : const char *pszFilename, unsigned int nIdentifyFlags,
2741 : const char *const *papszAllowedDrivers, const char *const *papszFileList)
2742 : {
2743 25601 : GDALDriverManager *poDM = GetGDALDriverManager();
2744 25601 : CPLAssert(nullptr != poDM);
2745 :
2746 : // If no driver kind is specified, assume all are to be probed.
2747 25601 : if ((nIdentifyFlags & GDAL_OF_KIND_MASK) == 0)
2748 25558 : nIdentifyFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
2749 :
2750 51202 : GDALOpenInfo oOpenInfo(pszFilename, nIdentifyFlags, papszFileList);
2751 25601 : oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
2752 :
2753 51202 : CPLErrorStateBackuper oBackuper;
2754 25601 : CPLErrorSetState(CE_None, CPLE_AppDefined, "");
2755 :
2756 25601 : const int nDriverCount = poDM->GetDriverCount();
2757 :
2758 : // First pass: only use drivers that have a pfnIdentify implementation.
2759 51202 : std::vector<GDALDriver *> apoSecondPassDrivers;
2760 5566680 : for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
2761 : {
2762 5542320 : GDALDriver *poDriver = poDM->GetDriver(iDriver);
2763 5549620 : if (papszAllowedDrivers != nullptr &&
2764 7303 : CSLFindString(papszAllowedDrivers,
2765 : GDALGetDriverShortName(poDriver)) == -1)
2766 : {
2767 1046740 : continue;
2768 : }
2769 :
2770 5536300 : VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
2771 :
2772 5535060 : if (poDriver->pfnIdentify == nullptr &&
2773 1035680 : poDriver->pfnIdentifyEx == nullptr)
2774 : {
2775 1035680 : continue;
2776 : }
2777 :
2778 4499420 : if (papszAllowedDrivers != nullptr &&
2779 44 : CSLFindString(papszAllowedDrivers,
2780 : GDALGetDriverShortName(poDriver)) == -1)
2781 0 : continue;
2782 13493400 : if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
2783 4499880 : (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
2784 505 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
2785 141 : continue;
2786 13501000 : if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
2787 4504110 : (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
2788 4876 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
2789 3657 : continue;
2790 :
2791 4495580 : if (poDriver->pfnIdentifyEx)
2792 : {
2793 0 : if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) > 0)
2794 0 : return poDriver;
2795 : }
2796 : else
2797 : {
2798 4495580 : const int nIdentifyRes = poDriver->pfnIdentify(&oOpenInfo);
2799 4495580 : if (nIdentifyRes > 0)
2800 1244 : return poDriver;
2801 4519710 : if (nIdentifyRes < 0 &&
2802 25374 : poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
2803 : {
2804 : // Not loaded plugin
2805 36 : apoSecondPassDrivers.push_back(poDriver);
2806 : }
2807 : }
2808 : }
2809 :
2810 : // second pass: try loading plugin drivers
2811 24390 : for (auto poDriver : apoSecondPassDrivers)
2812 : {
2813 : // Force plugin driver loading
2814 34 : poDriver->GetMetadata();
2815 34 : if (poDriver->pfnIdentify(&oOpenInfo) > 0)
2816 1 : return poDriver;
2817 : }
2818 :
2819 : // third pass: slow method.
2820 5465930 : for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
2821 : {
2822 5441660 : GDALDriver *poDriver = poDM->GetDriver(iDriver);
2823 5445470 : if (papszAllowedDrivers != nullptr &&
2824 3807 : CSLFindString(papszAllowedDrivers,
2825 : GDALGetDriverShortName(poDriver)) == -1)
2826 : {
2827 3790 : continue;
2828 : }
2829 :
2830 5437870 : VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
2831 :
2832 16312200 : if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
2833 5438320 : (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
2834 446 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
2835 137 : continue;
2836 16313800 : if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
2837 5439300 : (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
2838 1563 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
2839 946 : continue;
2840 :
2841 5436790 : if (poDriver->pfnIdentifyEx != nullptr)
2842 : {
2843 0 : if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) == 0)
2844 0 : continue;
2845 : }
2846 5436790 : else if (poDriver->pfnIdentify != nullptr)
2847 : {
2848 4418910 : if (poDriver->pfnIdentify(&oOpenInfo) == 0)
2849 4394010 : continue;
2850 : }
2851 :
2852 : GDALDataset *poDS;
2853 1042780 : if (poDriver->pfnOpen != nullptr)
2854 : {
2855 994189 : poDS = poDriver->pfnOpen(&oOpenInfo);
2856 994189 : if (poDS != nullptr)
2857 : {
2858 91 : delete poDS;
2859 91 : return GDALDriver::ToHandle(poDriver);
2860 : }
2861 :
2862 994098 : if (CPLGetLastErrorType() != CE_None)
2863 0 : return nullptr;
2864 : }
2865 48595 : else if (poDriver->pfnOpenWithDriverArg != nullptr)
2866 : {
2867 0 : poDS = poDriver->pfnOpenWithDriverArg(poDriver, &oOpenInfo);
2868 0 : if (poDS != nullptr)
2869 : {
2870 0 : delete poDS;
2871 0 : return GDALDriver::ToHandle(poDriver);
2872 : }
2873 :
2874 0 : if (CPLGetLastErrorType() != CE_None)
2875 0 : return nullptr;
2876 : }
2877 : }
2878 :
2879 24265 : return nullptr;
2880 : }
2881 :
2882 : /************************************************************************/
2883 : /* GetMetadataItem() */
2884 : /************************************************************************/
2885 :
2886 12027900 : const char *GDALDriver::GetMetadataItem(const char *pszName,
2887 : const char *pszDomain)
2888 : {
2889 12027900 : if (pszDomain == nullptr || pszDomain[0] == '\0')
2890 : {
2891 12021500 : if (EQUAL(pszName, GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST))
2892 : {
2893 2168 : const char *pszVal = GDALMajorObject::GetMetadataItem(pszName, "");
2894 2168 : if (pszVal)
2895 1947 : return pszVal;
2896 221 : if (GetMetadataItem(GDAL_DCAP_RASTER))
2897 : {
2898 152 : auto poDM = GetGDALDriverManager();
2899 152 : auto poGTiffDrv = poDM->GetDriverByName("GTiff");
2900 152 : if (poGTiffDrv)
2901 : {
2902 : const char *pszXML =
2903 152 : poGTiffDrv->GetMetadataItem(pszName, "");
2904 152 : if (pszXML)
2905 : {
2906 304 : CPLString osXML(pszXML);
2907 152 : osXML.replaceAll("<Value>INTERNAL</Value>", "");
2908 152 : return CPLSPrintf("%s", osXML.c_str());
2909 : }
2910 : }
2911 : }
2912 : }
2913 : }
2914 12025800 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
2915 : }
2916 :
2917 : /************************************************************************/
2918 : /* SetMetadataItem() */
2919 : /************************************************************************/
2920 :
2921 4431320 : CPLErr GDALDriver::SetMetadataItem(const char *pszName, const char *pszValue,
2922 : const char *pszDomain)
2923 :
2924 : {
2925 4431320 : if (pszDomain == nullptr || pszDomain[0] == '\0')
2926 : {
2927 : /* Automatically sets GDAL_DMD_EXTENSIONS from GDAL_DMD_EXTENSION */
2928 4623300 : if (EQUAL(pszName, GDAL_DMD_EXTENSION) &&
2929 197263 : GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSIONS) == nullptr)
2930 : {
2931 197263 : GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSIONS, pszValue);
2932 : }
2933 : /* and vice-versa if there is a single extension in GDAL_DMD_EXTENSIONS */
2934 8535540 : else if (EQUAL(pszName, GDAL_DMD_EXTENSIONS) &&
2935 4235800 : strchr(pszValue, ' ') == nullptr &&
2936 7032 : GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSION) ==
2937 : nullptr)
2938 : {
2939 7032 : GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSION, pszValue);
2940 : }
2941 : }
2942 4431320 : return GDALMajorObject::SetMetadataItem(pszName, pszValue, pszDomain);
2943 : }
2944 :
2945 : /************************************************************************/
2946 : /* InstantiateAlgorithm() */
2947 : /************************************************************************/
2948 :
2949 : //! @cond Doxygen_Suppress
2950 :
2951 : GDALAlgorithm *
2952 56 : GDALDriver::InstantiateAlgorithm(const std::vector<std::string> &aosPath)
2953 : {
2954 56 : pfnInstantiateAlgorithm = GetInstantiateAlgorithmCallback();
2955 56 : if (pfnInstantiateAlgorithm)
2956 56 : return pfnInstantiateAlgorithm(aosPath);
2957 0 : return nullptr;
2958 : }
2959 :
2960 : /************************************************************************/
2961 : /* DeclareAlgorithm() */
2962 : /************************************************************************/
2963 :
2964 7036 : void GDALDriver::DeclareAlgorithm(const std::vector<std::string> &aosPath)
2965 : {
2966 14072 : const std::string osDriverName = GetDescription();
2967 7036 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
2968 :
2969 14072 : if (!singleton.HasDeclaredSubAlgorithm({"driver"}))
2970 : {
2971 3110 : singleton.DeclareAlgorithm(
2972 : {"driver"},
2973 41 : []() -> std::unique_ptr<GDALAlgorithm>
2974 : {
2975 82 : return std::make_unique<GDALContainerAlgorithm>(
2976 41 : "driver", "Command for driver specific operations.");
2977 1555 : });
2978 : }
2979 :
2980 : std::vector<std::string> path = {"driver",
2981 42216 : CPLString(osDriverName).tolower()};
2982 7036 : if (!singleton.HasDeclaredSubAlgorithm(path))
2983 : {
2984 137 : auto lambda = [osDriverName]() -> std::unique_ptr<GDALAlgorithm>
2985 : {
2986 : auto poDriver =
2987 137 : GetGDALDriverManager()->GetDriverByName(osDriverName.c_str());
2988 137 : if (poDriver)
2989 : {
2990 : const char *pszHelpTopic =
2991 137 : poDriver->GetMetadataItem(GDAL_DMD_HELPTOPIC);
2992 274 : return std::make_unique<GDALContainerAlgorithm>(
2993 274 : CPLString(osDriverName).tolower(),
2994 274 : std::string("Command for ")
2995 137 : .append(osDriverName)
2996 : .append(" driver specific operations."),
2997 274 : pszHelpTopic ? std::string("/").append(pszHelpTopic)
2998 137 : : std::string());
2999 : }
3000 0 : return nullptr;
3001 6220 : };
3002 6220 : singleton.DeclareAlgorithm(path, std::move(lambda));
3003 : }
3004 :
3005 7036 : path.insert(path.end(), aosPath.begin(), aosPath.end());
3006 :
3007 56 : auto lambda = [osDriverName, aosPath]() -> std::unique_ptr<GDALAlgorithm>
3008 : {
3009 : auto poDriver =
3010 56 : GetGDALDriverManager()->GetDriverByName(osDriverName.c_str());
3011 56 : if (poDriver)
3012 : return std::unique_ptr<GDALAlgorithm>(
3013 56 : poDriver->InstantiateAlgorithm(aosPath));
3014 0 : return nullptr;
3015 14072 : };
3016 :
3017 7036 : singleton.DeclareAlgorithm(path, std::move(lambda));
3018 :
3019 7036 : CPL_IGNORE_RET_VAL(osDriverName);
3020 7036 : }
3021 :
3022 : //! @endcond
3023 :
3024 : /************************************************************************/
3025 : /* DoesDriverHandleExtension() */
3026 : /************************************************************************/
3027 :
3028 175762 : static bool DoesDriverHandleExtension(GDALDriverH hDriver, const char *pszExt)
3029 : {
3030 175762 : bool bRet = false;
3031 : const char *pszDriverExtensions =
3032 175762 : GDALGetMetadataItem(hDriver, GDAL_DMD_EXTENSIONS, nullptr);
3033 175762 : if (pszDriverExtensions)
3034 : {
3035 291948 : const CPLStringList aosTokens(CSLTokenizeString(pszDriverExtensions));
3036 145974 : const int nTokens = aosTokens.size();
3037 326965 : for (int j = 0; j < nTokens; ++j)
3038 : {
3039 185424 : if (EQUAL(pszExt, aosTokens[j]))
3040 : {
3041 4433 : bRet = true;
3042 4433 : break;
3043 : }
3044 : }
3045 : }
3046 175762 : return bRet;
3047 : }
3048 :
3049 : /************************************************************************/
3050 : /* IsOnlyExpectedGDBDrivers() */
3051 : /************************************************************************/
3052 :
3053 1 : static bool IsOnlyExpectedGDBDrivers(const CPLStringList &aosDriverNames)
3054 : {
3055 3 : for (const char *pszDrvName : aosDriverNames)
3056 : {
3057 2 : if (!EQUAL(pszDrvName, "OpenFileGDB") &&
3058 1 : !EQUAL(pszDrvName, "FileGDB") && !EQUAL(pszDrvName, "GPSBabel"))
3059 : {
3060 0 : return false;
3061 : }
3062 : }
3063 1 : return true;
3064 : }
3065 :
3066 : /************************************************************************/
3067 : /* GDALGetOutputDriversForDatasetName() */
3068 : /************************************************************************/
3069 :
3070 : /** Return a list of driver short names that are likely candidates for the
3071 : * provided output file name.
3072 : *
3073 : * @param pszDestDataset Output dataset name (might not exist).
3074 : * @param nDatasetTypeFlag GDAL_OF_RASTER, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER
3075 : * or a binary-or'ed combination of them
3076 : * @param bSingleMatch Whether a single match is desired, that is to say the
3077 : * returned list will contain at most one item, which will
3078 : * be the first driver in the order they are registered to
3079 : * match the output dataset name. Note that in this mode, if
3080 : * nDatasetTypeFlag==GDAL_OF_RASTER and pszDestDataset has
3081 : * no extension, GTiff will be selected.
3082 : * @param bEmitWarning Whether a warning should be emitted when bSingleMatch is
3083 : * true and there are more than 2 candidates.
3084 : * @return NULL terminated list of driver short names.
3085 : * To be freed with CSLDestroy()
3086 : * @since 3.9
3087 : */
3088 2584 : char **GDALGetOutputDriversForDatasetName(const char *pszDestDataset,
3089 : int nDatasetTypeFlag,
3090 : bool bSingleMatch, bool bEmitWarning)
3091 : {
3092 5168 : CPLStringList aosDriverNames;
3093 5168 : CPLStringList aosMissingDriverNames;
3094 :
3095 5168 : std::string osExt = CPLGetExtensionSafe(pszDestDataset);
3096 2584 : if (EQUAL(osExt.c_str(), "zip"))
3097 : {
3098 2 : const CPLString osLower(CPLString(pszDestDataset).tolower());
3099 1 : if (osLower.endsWith(".shp.zip"))
3100 : {
3101 1 : osExt = "shp.zip";
3102 : }
3103 0 : else if (osLower.endsWith(".gpkg.zip"))
3104 : {
3105 0 : osExt = "gpkg.zip";
3106 : }
3107 : }
3108 2583 : else if (EQUAL(osExt.c_str(), "json"))
3109 : {
3110 1 : const CPLString osLower(CPLString(pszDestDataset).tolower());
3111 1 : if (osLower.endsWith(".gdalg.json"))
3112 0 : return nullptr;
3113 : }
3114 :
3115 2584 : auto poDM = GetGDALDriverManager();
3116 2584 : const int nDriverCount = poDM->GetDriverCount(true);
3117 2584 : GDALDriver *poMissingPluginDriver = nullptr;
3118 5168 : std::string osMatchingPrefix;
3119 581007 : for (int i = 0; i < nDriverCount; i++)
3120 : {
3121 578423 : GDALDriver *poDriver = poDM->GetDriver(i, true);
3122 578423 : bool bOk = false;
3123 578423 : if ((poDriver->GetMetadataItem(GDAL_DCAP_CREATE) != nullptr ||
3124 353618 : poDriver->GetMetadataItem(GDAL_DCAP_CREATECOPY) != nullptr ||
3125 1156850 : poDriver->GetMetadataItem(GDAL_DCAP_UPDATE) != nullptr) &&
3126 294573 : (((nDatasetTypeFlag & GDAL_OF_RASTER) &&
3127 238829 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) != nullptr) ||
3128 143734 : ((nDatasetTypeFlag & GDAL_OF_VECTOR) &&
3129 55402 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) != nullptr) ||
3130 116520 : ((nDatasetTypeFlag & GDAL_OF_MULTIDIM_RASTER) &&
3131 342 : poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) != nullptr)))
3132 : {
3133 178074 : bOk = true;
3134 : }
3135 404545 : else if (poDriver->GetMetadataItem(GDAL_DCAP_VECTOR_TRANSLATE_FROM) &&
3136 4196 : (nDatasetTypeFlag & GDAL_OF_VECTOR) != 0)
3137 : {
3138 0 : bOk = true;
3139 : }
3140 578423 : if (bOk)
3141 : {
3142 353836 : if (!osExt.empty() &&
3143 175762 : DoesDriverHandleExtension(GDALDriver::ToHandle(poDriver),
3144 : osExt.c_str()))
3145 : {
3146 4433 : if (poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
3147 : {
3148 0 : poMissingPluginDriver = poDriver;
3149 0 : aosMissingDriverNames.AddString(poDriver->GetDescription());
3150 : }
3151 : else
3152 4433 : aosDriverNames.AddString(poDriver->GetDescription());
3153 : }
3154 : else
3155 : {
3156 : const char *pszPrefix =
3157 173641 : poDriver->GetMetadataItem(GDAL_DMD_CONNECTION_PREFIX);
3158 173641 : if (pszPrefix && STARTS_WITH_CI(pszDestDataset, pszPrefix))
3159 : {
3160 9 : if (poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
3161 : {
3162 0 : osMatchingPrefix = pszPrefix;
3163 0 : poMissingPluginDriver = poDriver;
3164 : aosMissingDriverNames.AddString(
3165 0 : poDriver->GetDescription());
3166 : }
3167 : else
3168 9 : aosDriverNames.AddString(poDriver->GetDescription());
3169 : }
3170 : }
3171 : }
3172 : }
3173 :
3174 : // GMT is registered before netCDF for opening reasons, but we want
3175 : // netCDF to be used by default for output.
3176 2589 : if (EQUAL(osExt.c_str(), "nc") && aosDriverNames.size() == 2 &&
3177 2589 : EQUAL(aosDriverNames[0], "GMT") && EQUAL(aosDriverNames[1], "netCDF"))
3178 : {
3179 0 : aosDriverNames.Clear();
3180 0 : aosDriverNames.AddString("netCDF");
3181 0 : aosDriverNames.AddString("GMT");
3182 : }
3183 :
3184 2584 : if (bSingleMatch)
3185 : {
3186 2516 : if (nDatasetTypeFlag == GDAL_OF_RASTER)
3187 : {
3188 2095 : if (aosDriverNames.empty())
3189 : {
3190 12 : if (osExt.empty())
3191 : {
3192 8 : aosDriverNames.AddString("GTiff");
3193 : }
3194 : }
3195 2083 : else if (aosDriverNames.size() >= 2)
3196 : {
3197 3786 : if (bEmitWarning && !(EQUAL(aosDriverNames[0], "GTiff") &&
3198 1893 : EQUAL(aosDriverNames[1], "COG")))
3199 : {
3200 0 : CPLError(CE_Warning, CPLE_AppDefined,
3201 : "Several drivers matching %s extension. Using %s",
3202 : osExt.c_str(), aosDriverNames[0]);
3203 : }
3204 3786 : const std::string osDrvName = aosDriverNames[0];
3205 1893 : aosDriverNames.Clear();
3206 1893 : aosDriverNames.AddString(osDrvName.c_str());
3207 : }
3208 : }
3209 422 : else if (EQUAL(osExt.c_str(), "gdb") &&
3210 1 : IsOnlyExpectedGDBDrivers(aosDriverNames))
3211 : {
3212 : // Do not warn about that case given that FileGDB write support
3213 : // forwards to OpenFileGDB one. And also consider GPSBabel as too
3214 : // marginal to deserve the warning.
3215 1 : aosDriverNames.Clear();
3216 1 : aosDriverNames.AddString("OpenFileGDB");
3217 : }
3218 420 : else if (aosDriverNames.size() >= 2)
3219 : {
3220 0 : if (bEmitWarning)
3221 : {
3222 0 : CPLError(CE_Warning, CPLE_AppDefined,
3223 : "Several drivers matching %s %s. Using %s",
3224 0 : osMatchingPrefix.empty() ? osExt.c_str()
3225 0 : : osMatchingPrefix.c_str(),
3226 0 : osMatchingPrefix.empty() ? "extension" : "prefix",
3227 : aosDriverNames[0]);
3228 : }
3229 0 : const std::string osDrvName = aosDriverNames[0];
3230 0 : aosDriverNames.Clear();
3231 0 : aosDriverNames.AddString(osDrvName.c_str());
3232 : }
3233 : }
3234 :
3235 2613 : if (aosDriverNames.empty() && bEmitWarning &&
3236 2613 : aosMissingDriverNames.size() == 1 && poMissingPluginDriver)
3237 : {
3238 0 : CPLError(CE_Failure, CPLE_AppDefined,
3239 : "No installed driver matching %s %s, but %s driver is "
3240 : "known. However plugin %s",
3241 0 : osMatchingPrefix.empty() ? osExt.c_str()
3242 0 : : osMatchingPrefix.c_str(),
3243 0 : osMatchingPrefix.empty() ? "extension" : "prefix",
3244 0 : poMissingPluginDriver->GetDescription(),
3245 0 : GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver)
3246 : .c_str());
3247 : }
3248 2612 : else if (aosDriverNames.empty() && bEmitWarning &&
3249 28 : aosMissingDriverNames.empty())
3250 : {
3251 771 : for (const auto &sConnectionPrefix : asKnownConnectionPrefixes)
3252 : {
3253 744 : if (STARTS_WITH_CI(pszDestDataset, sConnectionPrefix.pszPrefix))
3254 : {
3255 1 : CPLError(CE_Failure, CPLE_AppDefined,
3256 : "Filename %s starts with the connection prefix of "
3257 : "driver %s, which is not enabled in this GDAL build. "
3258 : "If that filename is really intended, explicitly "
3259 : "specify its output format.",
3260 1 : pszDestDataset, sConnectionPrefix.pszDriverName);
3261 1 : break;
3262 : }
3263 : }
3264 : }
3265 :
3266 2584 : return aosDriverNames.StealList();
3267 : }
3268 :
3269 : /************************************************************************/
3270 : /* GDALGetMessageAboutMissingPluginDriver() */
3271 : /************************************************************************/
3272 :
3273 : std::string
3274 0 : GDALGetMessageAboutMissingPluginDriver(GDALDriver *poMissingPluginDriver)
3275 : {
3276 : std::string osMsg =
3277 0 : poMissingPluginDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME");
3278 : osMsg += " is not available in your "
3279 0 : "installation.";
3280 0 : if (const char *pszInstallationMsg = poMissingPluginDriver->GetMetadataItem(
3281 0 : GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE))
3282 : {
3283 0 : osMsg += " ";
3284 0 : osMsg += pszInstallationMsg;
3285 : }
3286 :
3287 : VSIStatBuf sStat;
3288 0 : if (const char *pszGDALDriverPath =
3289 0 : CPLGetConfigOption("GDAL_DRIVER_PATH", nullptr))
3290 : {
3291 0 : if (VSIStat(pszGDALDriverPath, &sStat) != 0)
3292 : {
3293 0 : if (osMsg.back() != '.')
3294 0 : osMsg += ".";
3295 0 : osMsg += " Directory '";
3296 0 : osMsg += pszGDALDriverPath;
3297 0 : osMsg += "' pointed by GDAL_DRIVER_PATH does not exist.";
3298 : }
3299 : }
3300 : else
3301 : {
3302 0 : if (osMsg.back() != '.')
3303 0 : osMsg += ".";
3304 : #ifdef INSTALL_PLUGIN_FULL_DIR
3305 : if (VSIStat(INSTALL_PLUGIN_FULL_DIR, &sStat) != 0)
3306 : {
3307 : osMsg += " Directory '";
3308 : osMsg += INSTALL_PLUGIN_FULL_DIR;
3309 : osMsg += "' hardcoded in the GDAL library does not "
3310 : "exist and the GDAL_DRIVER_PATH "
3311 : "configuration option is not set.";
3312 : }
3313 : else
3314 : #endif
3315 : {
3316 : osMsg += " The GDAL_DRIVER_PATH configuration "
3317 0 : "option is not set.";
3318 : }
3319 : }
3320 0 : return osMsg;
3321 : }
|