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 455752 : GDALDriver::~GDALDriver()
50 :
51 : {
52 257308 : if (pfnUnloadDriver != nullptr)
53 6927 : pfnUnloadDriver(this);
54 455752 : }
55 :
56 : /************************************************************************/
57 : /* GDALCreateDriver() */
58 : /************************************************************************/
59 :
60 : /**
61 : * \brief Create a GDALDriver.
62 : *
63 : * Creates a driver in the GDAL heap.
64 : */
65 :
66 233 : GDALDriverH CPL_STDCALL GDALCreateDriver()
67 : {
68 233 : 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 510559 : GDALDataset *GDALDriver::Open(GDALOpenInfo *poOpenInfo, bool bSetOpenOptions)
99 : {
100 :
101 510559 : GDALDataset *poDS = nullptr;
102 510559 : pfnOpen = GetOpenCallback();
103 510559 : if (pfnOpen != nullptr)
104 : {
105 510556 : poDS = pfnOpen(poOpenInfo);
106 : }
107 3 : else if (pfnOpenWithDriverArg != nullptr)
108 : {
109 3 : poDS = pfnOpenWithDriverArg(this, poOpenInfo);
110 : }
111 :
112 510559 : if (poDS)
113 : {
114 : // Only set GDAL_OF_THREAD_SAFE if the driver itself has set it in
115 : // poDS->nOpenFlags
116 62208 : int nOpenFlags = poOpenInfo->nOpenFlags &
117 : ~(GDAL_OF_FROM_GDALOPEN | GDAL_OF_THREAD_SAFE);
118 62208 : if (poDS->nOpenFlags & GDAL_OF_THREAD_SAFE)
119 914 : nOpenFlags |= GDAL_OF_THREAD_SAFE;
120 62208 : poDS->nOpenFlags = nOpenFlags;
121 :
122 62208 : if (strlen(poDS->GetDescription()) == 0)
123 14068 : poDS->SetDescription(poOpenInfo->pszFilename);
124 :
125 62208 : if (poDS->poDriver == nullptr)
126 58243 : poDS->poDriver = this;
127 :
128 62208 : if (poDS->papszOpenOptions == nullptr && bSetOpenOptions)
129 : {
130 29 : poDS->papszOpenOptions = CSLDuplicate(poOpenInfo->papszOpenOptions);
131 : }
132 :
133 62208 : if (!(poOpenInfo->nOpenFlags & GDAL_OF_INTERNAL))
134 : {
135 49727 : 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 49721 : CPLDebug("GDAL", "GDALOpen(%s, this=%p) succeeds as %s.",
145 49721 : poOpenInfo->pszFilename, poDS, GetDescription());
146 :
147 49727 : poDS->AddToDatasetOpenList();
148 : }
149 : }
150 :
151 510559 : 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 25219 : 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 25219 : pfnCreate = GetCreateCallback();
202 25219 : 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 25218 : 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 25217 : if (CPL_UNLIKELY(GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
224 : GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr &&
225 25217 : (nXSize < 1 || nYSize < 1)))
226 : {
227 2 : 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 2 : return nullptr;
232 : }
233 :
234 25215 : 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 25214 : 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 25195 : if (!EQUAL(GetDescription(), "MEM") &&
255 38735 : !EQUAL(GetDescription(), "Memory") &&
256 : // ogr2ogr -f PostgreSQL might reach the Delete method of the
257 : // PostgisRaster driver which is undesirable
258 13540 : !EQUAL(GetDescription(), "PostgreSQL"))
259 : {
260 13538 : QuietDelete(pszFilename);
261 : }
262 : }
263 :
264 : /* -------------------------------------------------------------------- */
265 : /* Validate creation options. */
266 : /* -------------------------------------------------------------------- */
267 25214 : if (CPLTestBool(
268 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
269 25214 : GDALValidateCreationOptions(this, papszOptions);
270 :
271 : /* -------------------------------------------------------------------- */
272 : /* Proceed with creation. */
273 : /* -------------------------------------------------------------------- */
274 50428 : CPLDebug("GDAL", "GDALDriver::Create(%s,%s,%d,%d,%d,%s,%p)",
275 25214 : GetDescription(), pszFilename, nXSize, nYSize, nBands,
276 : GDALGetDataTypeName(eType), papszOptions);
277 :
278 25214 : GDALDataset *poDS = nullptr;
279 25214 : if (pfnCreateEx != nullptr)
280 : {
281 0 : poDS = pfnCreateEx(this, pszFilename, nXSize, nYSize, nBands, eType,
282 : const_cast<char **>(papszOptions));
283 : }
284 25214 : else if (pfnCreate != nullptr)
285 : {
286 25214 : 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 25214 : if (poDS != nullptr)
296 : {
297 47828 : if (poDS->GetDescription() == nullptr ||
298 23914 : strlen(poDS->GetDescription()) == 0)
299 21235 : poDS->SetDescription(pszFilename);
300 :
301 23914 : if (poDS->poDriver == nullptr)
302 23191 : poDS->poDriver = this;
303 :
304 23914 : poDS->AddToDatasetOpenList();
305 : }
306 :
307 25214 : 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 20815 : 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 20815 : VALIDATE_POINTER1(hDriver, "GDALCreate", nullptr);
328 :
329 20815 : GDALDatasetH hDS = GDALDriver::FromHandle(hDriver)->Create(
330 : pszFilename, nXSize, nYSize, nBands, eBandType, papszOptions);
331 :
332 : #ifdef OGRAPISPY_ENABLED
333 20815 : if (nBands < 1)
334 : {
335 3872 : OGRAPISpyCreateDataSource(hDriver, pszFilename,
336 : const_cast<char **>(papszOptions), hDS);
337 : }
338 : #endif
339 :
340 20815 : 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 566 : GDALDriver::CreateMultiDimensional(const char *pszFilename,
368 : CSLConstList papszRootGroupOptions,
369 : CSLConstList papszOptions)
370 :
371 : {
372 : /* -------------------------------------------------------------------- */
373 : /* Does this format support creation. */
374 : /* -------------------------------------------------------------------- */
375 566 : pfnCreateMultiDimensional = GetCreateMultiDimensionalCallback();
376 566 : 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 566 : if (CPLTestBool(
390 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
391 : {
392 : const char *pszOptionList =
393 566 : GetMetadataItem(GDAL_DMD_MULTIDIM_DATASET_CREATIONOPTIONLIST);
394 1132 : CPLString osDriver;
395 566 : osDriver.Printf("driver %s", GetDescription());
396 566 : GDALValidateOptions(pszOptionList, papszOptions, "creation option",
397 : osDriver);
398 : }
399 :
400 566 : auto poDstDS = pfnCreateMultiDimensional(pszFilename, papszRootGroupOptions,
401 : papszOptions);
402 :
403 566 : if (poDstDS != nullptr)
404 : {
405 1128 : if (poDstDS->GetDescription() == nullptr ||
406 564 : strlen(poDstDS->GetDescription()) == 0)
407 147 : poDstDS->SetDescription(pszFilename);
408 :
409 564 : if (poDstDS->poDriver == nullptr)
410 562 : poDstDS->poDriver = this;
411 : }
412 :
413 566 : 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 514 : GDALDatasetH GDALCreateMultiDimensional(GDALDriverH hDriver,
425 : const char *pszName,
426 : CSLConstList papszRootGroupOptions,
427 : CSLConstList papszOptions)
428 : {
429 514 : VALIDATE_POINTER1(hDriver, __func__, nullptr);
430 514 : VALIDATE_POINTER1(pszName, __func__, nullptr);
431 514 : return GDALDataset::ToHandle(
432 : GDALDriver::FromHandle(hDriver)->CreateMultiDimensional(
433 514 : pszName, papszRootGroupOptions, papszOptions));
434 : }
435 :
436 : /************************************************************************/
437 : /* DefaultCreateCopyMultiDimensional() */
438 : /************************************************************************/
439 :
440 : //! @cond Doxygen_Suppress
441 :
442 27 : CPLErr GDALDriver::DefaultCreateCopyMultiDimensional(
443 : GDALDataset *poSrcDS, GDALDataset *poDstDS, bool bStrict,
444 : CSLConstList papszOptions, GDALProgressFunc pfnProgress,
445 : void *pProgressData)
446 : {
447 27 : if (pfnProgress == nullptr)
448 3 : pfnProgress = GDALDummyProgress;
449 :
450 54 : auto poSrcRG = poSrcDS->GetRootGroup();
451 27 : if (!poSrcRG)
452 0 : return CE_Failure;
453 54 : auto poDstRG = poDstDS->GetRootGroup();
454 27 : if (!poDstRG)
455 0 : return CE_Failure;
456 27 : GUInt64 nCurCost = 0;
457 54 : return poDstRG->CopyFrom(poDstRG, poSrcDS, poSrcRG, bStrict, nCurCost,
458 : poSrcRG->GetTotalCopyCost(), pfnProgress,
459 27 : pProgressData, papszOptions)
460 27 : ? CE_None
461 27 : : CE_Failure;
462 : }
463 :
464 : //! @endcond
465 :
466 : /************************************************************************/
467 : /* DefaultCopyMasks() */
468 : /************************************************************************/
469 :
470 : //! @cond Doxygen_Suppress
471 6228 : CPLErr GDALDriver::DefaultCopyMasks(GDALDataset *poSrcDS, GDALDataset *poDstDS,
472 : int bStrict)
473 :
474 : {
475 6228 : return DefaultCopyMasks(poSrcDS, poDstDS, bStrict, nullptr, nullptr,
476 6228 : nullptr);
477 : }
478 :
479 8283 : CPLErr GDALDriver::DefaultCopyMasks(GDALDataset *poSrcDS, GDALDataset *poDstDS,
480 : int bStrict, CSLConstList /*papszOptions*/,
481 : GDALProgressFunc pfnProgress,
482 : void *pProgressData)
483 :
484 : {
485 8283 : if (pfnProgress == nullptr)
486 6228 : pfnProgress = GDALDummyProgress;
487 :
488 8283 : int nBands = poSrcDS->GetRasterCount();
489 8283 : if (nBands == 0)
490 0 : return CE_None;
491 :
492 : /* -------------------------------------------------------------------- */
493 : /* Try to copy mask if it seems appropriate. */
494 : /* -------------------------------------------------------------------- */
495 8283 : const char *papszOptions[2] = {"COMPRESSED=YES", nullptr};
496 8283 : CPLErr eErr = CE_None;
497 :
498 8283 : int nTotalBandsWithMask = 0;
499 28620 : for (int iBand = 0; iBand < nBands; ++iBand)
500 : {
501 20337 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
502 :
503 20337 : int nMaskFlags = poSrcBand->GetMaskFlags();
504 20337 : if (!(nMaskFlags &
505 : (GMF_ALL_VALID | GMF_PER_DATASET | GMF_ALPHA | GMF_NODATA)))
506 : {
507 8 : nTotalBandsWithMask++;
508 : }
509 : }
510 :
511 8283 : int iBandWithMask = 0;
512 28620 : for (int iBand = 0; eErr == CE_None && iBand < nBands; ++iBand)
513 : {
514 20337 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
515 :
516 20337 : int nMaskFlags = poSrcBand->GetMaskFlags();
517 20337 : 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 8283 : const int nMaskFlags = poSrcDS->GetRasterBand(1)->GetMaskFlags();
549 8283 : if (eErr == CE_None &&
550 8283 : !(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 8283 : return eErr;
568 : }
569 :
570 : /************************************************************************/
571 : /* DefaultCreateCopy() */
572 : /************************************************************************/
573 :
574 1479 : GDALDataset *GDALDriver::DefaultCreateCopy(const char *pszFilename,
575 : GDALDataset *poSrcDS, int bStrict,
576 : CSLConstList papszOptions,
577 : GDALProgressFunc pfnProgress,
578 : void *pProgressData)
579 :
580 : {
581 1479 : if (pfnProgress == nullptr)
582 0 : pfnProgress = GDALDummyProgress;
583 :
584 1479 : CPLErrorReset();
585 :
586 : /* -------------------------------------------------------------------- */
587 : /* Use multidimensional raster API if available. */
588 : /* -------------------------------------------------------------------- */
589 2958 : auto poSrcGroup = poSrcDS->GetRootGroup();
590 1479 : 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 1455 : const int nXSize = poSrcDS->GetRasterXSize();
616 1455 : const int nYSize = poSrcDS->GetRasterYSize();
617 1455 : const int nBands = poSrcDS->GetRasterCount();
618 :
619 1455 : CPLDebug("GDAL", "Using default GDALDriver::CreateCopy implementation.");
620 :
621 1455 : const int nLayerCount = poSrcDS->GetLayerCount();
622 1479 : 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 1438 : if (poSrcDS->GetDriver() != nullptr &&
630 1408 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
631 1401 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr &&
632 2849 : 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 1435 : else if (poSrcDS->GetDriver() != nullptr &&
641 1405 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_RASTER) ==
642 7 : nullptr &&
643 7 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VECTOR) !=
644 7 : nullptr &&
645 2840 : 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 1435 : 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 1433 : char **papszCreateOptions = CSLDuplicate(papszOptions);
666 1433 : const char *const apszOptItems[] = {"NBITS", "IMAGE_STRUCTURE", "PIXELTYPE",
667 : "IMAGE_STRUCTURE", nullptr};
668 :
669 4267 : for (int iOptItem = 0; nBands > 0 && apszOptItems[iOptItem] != nullptr;
670 2834 : iOptItem += 2)
671 : {
672 : // does the source have this metadata item on the first band?
673 2834 : auto poBand = poSrcDS->GetRasterBand(1);
674 2834 : poBand->EnablePixelTypeSignedByteWarning(false);
675 5668 : const char *pszValue = poBand->GetMetadataItem(
676 2834 : apszOptItems[iOptItem], apszOptItems[iOptItem + 1]);
677 2834 : poBand->EnablePixelTypeSignedByteWarning(true);
678 :
679 2834 : if (pszValue == nullptr)
680 2832 : continue;
681 :
682 : // Do not override provided value.
683 2 : 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 2 : GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
689 :
690 2 : if (pszOptionList == nullptr ||
691 2 : strstr(pszOptionList, apszOptItems[iOptItem]) == nullptr)
692 0 : continue;
693 :
694 2 : papszCreateOptions = CSLSetNameValue(papszCreateOptions,
695 2 : apszOptItems[iOptItem], pszValue);
696 : }
697 :
698 : /* -------------------------------------------------------------------- */
699 : /* Create destination dataset. */
700 : /* -------------------------------------------------------------------- */
701 1433 : GDALDataType eType = GDT_Unknown;
702 :
703 1433 : if (nBands > 0)
704 1417 : eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
705 : GDALDataset *poDstDS =
706 1433 : Create(pszFilename, nXSize, nYSize, nBands, eType, papszCreateOptions);
707 :
708 1433 : CSLDestroy(papszCreateOptions);
709 :
710 1433 : if (poDstDS == nullptr)
711 326 : return nullptr;
712 :
713 1107 : int nDstBands = poDstDS->GetRasterCount();
714 1107 : CPLErr eErr = CE_None;
715 1107 : 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 1107 : if (nDstBands == 0 && !bStrict)
734 4 : CPLTurnFailureIntoWarning(true);
735 :
736 1107 : GDALGeoTransform gt;
737 2089 : if (eErr == CE_None && poSrcDS->GetGeoTransform(gt) == CE_None &&
738 2089 : gt != GDALGeoTransform())
739 : {
740 980 : eErr = poDstDS->SetGeoTransform(gt);
741 980 : if (!bStrict)
742 623 : eErr = CE_None;
743 : }
744 :
745 1107 : if (eErr == CE_None)
746 : {
747 1098 : const auto poSrcSRS = poSrcDS->GetSpatialRefRasterOnly();
748 1098 : if (poSrcSRS && !poSrcSRS->IsEmpty())
749 : {
750 918 : eErr = poDstDS->SetSpatialRef(poSrcSRS);
751 918 : if (!bStrict)
752 593 : eErr = CE_None;
753 : }
754 : }
755 :
756 : /* -------------------------------------------------------------------- */
757 : /* Copy GCPs. */
758 : /* -------------------------------------------------------------------- */
759 1107 : 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 1107 : if (nDstBands == 0 && !bStrict)
768 4 : CPLTurnFailureIntoWarning(false);
769 :
770 : /* -------------------------------------------------------------------- */
771 : /* Copy metadata. */
772 : /* -------------------------------------------------------------------- */
773 1107 : DefaultCopyMetadata(poSrcDS, poDstDS, papszOptions, nullptr);
774 :
775 : /* -------------------------------------------------------------------- */
776 : /* Loop copying bands. */
777 : /* -------------------------------------------------------------------- */
778 2870 : for (int iBand = 0; eErr == CE_None && iBand < nDstBands; ++iBand)
779 : {
780 1763 : GDALRasterBand *const poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
781 1763 : GDALRasterBand *const poDstBand = poDstDS->GetRasterBand(iBand + 1);
782 :
783 : /* --------------------------------------------------------------------
784 : */
785 : /* Do we need to copy a colortable. */
786 : /* --------------------------------------------------------------------
787 : */
788 1763 : GDALColorTable *const poCT = poSrcBand->GetColorTable();
789 1763 : if (poCT != nullptr)
790 39 : 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 1763 : if (!bStrict)
800 1129 : CPLTurnFailureIntoWarning(true);
801 :
802 1763 : if (strlen(poSrcBand->GetDescription()) > 0)
803 52 : poDstBand->SetDescription(poSrcBand->GetDescription());
804 :
805 1763 : if (CSLCount(poSrcBand->GetMetadata()) > 0)
806 115 : poDstBand->SetMetadata(poSrcBand->GetMetadata());
807 :
808 1763 : int bSuccess = FALSE;
809 1763 : double dfValue = poSrcBand->GetOffset(&bSuccess);
810 1763 : if (bSuccess && dfValue != 0.0)
811 5 : poDstBand->SetOffset(dfValue);
812 :
813 1763 : dfValue = poSrcBand->GetScale(&bSuccess);
814 1763 : if (bSuccess && dfValue != 1.0)
815 4 : poDstBand->SetScale(dfValue);
816 :
817 1763 : GDALCopyNoDataValue(poDstBand, poSrcBand);
818 :
819 2932 : if (poSrcBand->GetColorInterpretation() != GCI_Undefined &&
820 1169 : poSrcBand->GetColorInterpretation() !=
821 1169 : poDstBand->GetColorInterpretation())
822 941 : poDstBand->SetColorInterpretation(
823 941 : poSrcBand->GetColorInterpretation());
824 :
825 1763 : char **papszCatNames = poSrcBand->GetCategoryNames();
826 1763 : if (nullptr != papszCatNames)
827 1 : poDstBand->SetCategoryNames(papszCatNames);
828 :
829 : // Only copy RAT if it is of reasonable size to fit in memory
830 1763 : GDALRasterAttributeTable *poRAT = poSrcBand->GetDefaultRAT();
831 1765 : if (poRAT != nullptr && static_cast<GIntBig>(poRAT->GetColumnCount()) *
832 2 : poRAT->GetRowCount() <
833 : 1024 * 1024)
834 : {
835 2 : poDstBand->SetDefaultRAT(poRAT);
836 : }
837 :
838 1763 : if (!bStrict)
839 : {
840 1129 : CPLTurnFailureIntoWarning(false);
841 : }
842 : else
843 : {
844 634 : eErr = CPLGetLastErrorType();
845 : }
846 : }
847 :
848 : /* -------------------------------------------------------------------- */
849 : /* Copy image data. */
850 : /* -------------------------------------------------------------------- */
851 1107 : if (eErr == CE_None && nDstBands > 0)
852 : {
853 1063 : const char *const apszCopyRasterOptionsSkipHoles[] = {"SKIP_HOLES=YES",
854 : nullptr};
855 1063 : const bool bSkipHoles = CPLTestBool(
856 : CSLFetchNameValueDef(papszOptions, "SKIP_HOLES", "FALSE"));
857 1063 : eErr = GDALDatasetCopyWholeRaster(
858 : poSrcDS, poDstDS,
859 : bSkipHoles ? apszCopyRasterOptionsSkipHoles : nullptr, pfnProgress,
860 : pProgressData);
861 : }
862 :
863 : /* -------------------------------------------------------------------- */
864 : /* Should we copy some masks over? */
865 : /* -------------------------------------------------------------------- */
866 1107 : if (eErr == CE_None && nDstBands > 0)
867 1045 : eErr = DefaultCopyMasks(poSrcDS, poDstDS, eErr);
868 :
869 : /* -------------------------------------------------------------------- */
870 : /* Copy vector layers */
871 : /* -------------------------------------------------------------------- */
872 1107 : if (eErr == CE_None)
873 : {
874 1058 : 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 1107 : 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 1058 : CPLErrorReset();
904 : }
905 :
906 1058 : return poDstDS;
907 : }
908 :
909 : /************************************************************************/
910 : /* DefaultCopyMetadata() */
911 : /************************************************************************/
912 :
913 5436 : void GDALDriver::DefaultCopyMetadata(GDALDataset *poSrcDS, GDALDataset *poDstDS,
914 : CSLConstList papszOptions,
915 : CSLConstList papszExcludedDomains)
916 : {
917 : const char *pszCopySrcMDD =
918 5436 : CSLFetchNameValueDef(papszOptions, "COPY_SRC_MDD", "AUTO");
919 5436 : char **papszSrcMDD = CSLFetchNameValueMultiple(papszOptions, "SRC_MDD");
920 5436 : if (EQUAL(pszCopySrcMDD, "AUTO") || CPLTestBool(pszCopySrcMDD) ||
921 : papszSrcMDD)
922 : {
923 4 : if ((!papszSrcMDD || CSLFindString(papszSrcMDD, "") >= 0 ||
924 2 : CSLFindString(papszSrcMDD, "_DEFAULT_") >= 0) &&
925 10721 : CSLFindString(papszExcludedDomains, "") < 0 &&
926 5283 : CSLFindString(papszExcludedDomains, "_DEFAULT_") < 0)
927 : {
928 5283 : if (poSrcDS->GetMetadata() != nullptr)
929 871 : 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 5434 : constexpr const char *apszDefaultDomains[] = {
937 : "RPC", "xml:XMP", "json:ISIS3", "json:VICAR"};
938 27170 : for (const char *pszDomain : apszDefaultDomains)
939 : {
940 43456 : if ((!papszSrcMDD || CSLFindString(papszSrcMDD, pszDomain) >= 0) &&
941 21720 : CSLFindString(papszExcludedDomains, pszDomain) < 0)
942 : {
943 21720 : CSLConstList papszMD = poSrcDS->GetMetadata(pszDomain);
944 21720 : if (papszMD)
945 5 : poDstDS->SetMetadata(papszMD, pszDomain);
946 : }
947 : }
948 :
949 5434 : 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 5436 : CSLDestroy(papszSrcMDD);
999 5436 : }
1000 :
1001 : /************************************************************************/
1002 : /* QuietDeleteForCreateCopy() */
1003 : /************************************************************************/
1004 :
1005 12207 : 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 23781 : if (!EQUAL(GetDescription(), "MEM") && !EQUAL(GetDescription(), "Memory") &&
1014 : // VRT with empty name is a un-materialized dataset
1015 11574 : !(EQUAL(GetDescription(), "VRT") && pszFilename[0] == 0) &&
1016 : // Also exclude database formats for which there's no file list
1017 : // and whose opening might be slow (GeoRaster in particular)
1018 34654 : !EQUAL(GetDescription(), "GeoRaster") &&
1019 10873 : !EQUAL(GetDescription(), "PostGISRaster"))
1020 : {
1021 : /* --------------------------------------------------------------------
1022 : */
1023 : /* Establish list of files of output dataset if it already
1024 : * exists. */
1025 : /* --------------------------------------------------------------------
1026 : */
1027 21710 : std::set<std::string> oSetExistingDestFiles;
1028 : {
1029 21710 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1030 10855 : const char *const apszAllowedDrivers[] = {GetDescription(),
1031 10855 : nullptr};
1032 : auto poExistingOutputDS =
1033 : std::unique_ptr<GDALDataset>(GDALDataset::Open(
1034 21710 : pszFilename, GDAL_OF_RASTER, apszAllowedDrivers));
1035 10855 : if (poExistingOutputDS)
1036 : {
1037 682 : for (const char *pszFileInList :
1038 648 : CPLStringList(poExistingOutputDS->GetFileList()))
1039 : {
1040 : oSetExistingDestFiles.insert(
1041 341 : CPLString(pszFileInList).replaceAll('\\', '/'));
1042 : }
1043 : }
1044 : }
1045 :
1046 : /* --------------------------------------------------------------------
1047 : */
1048 : /* Check if the source dataset shares some files with the dest
1049 : * one.*/
1050 : /* --------------------------------------------------------------------
1051 : */
1052 21710 : std::set<std::string> oSetExistingDestFilesFoundInSource;
1053 10855 : if (!oSetExistingDestFiles.empty())
1054 : {
1055 614 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1056 : // We need to reopen in a temporary dataset for the particular
1057 : // case of overwritten a .tif.ovr file from a .tif
1058 : // If we probe the file list of the .tif, it will then open the
1059 : // .tif.ovr !
1060 307 : const char *const apszAllowedDrivers[] = {
1061 307 : poSrcDS->GetDriver() ? poSrcDS->GetDriver()->GetDescription()
1062 : : nullptr,
1063 307 : nullptr};
1064 : auto poSrcDSTmp = std::unique_ptr<GDALDataset>(GDALDataset::Open(
1065 307 : poSrcDS->GetDescription(), GDAL_OF_RASTER, apszAllowedDrivers,
1066 614 : poSrcDS->papszOpenOptions));
1067 307 : if (poSrcDSTmp)
1068 : {
1069 212 : for (const char *pszFileInList :
1070 412 : CPLStringList(poSrcDSTmp->GetFileList()))
1071 : {
1072 424 : CPLString osFilename(pszFileInList);
1073 212 : osFilename.replaceAll('\\', '/');
1074 212 : if (cpl::contains(oSetExistingDestFiles, osFilename))
1075 : {
1076 : oSetExistingDestFilesFoundInSource.insert(
1077 16 : std::move(osFilename));
1078 : }
1079 : }
1080 : }
1081 : }
1082 :
1083 : // If the source file(s) and the dest one share some files in
1084 : // common, only remove the files that are *not* in common
1085 10855 : if (!oSetExistingDestFilesFoundInSource.empty())
1086 : {
1087 36 : for (const std::string &osFilename : oSetExistingDestFiles)
1088 : {
1089 21 : if (!cpl::contains(oSetExistingDestFilesFoundInSource,
1090 : osFilename))
1091 : {
1092 5 : VSIUnlink(osFilename.c_str());
1093 : }
1094 : }
1095 : }
1096 :
1097 10855 : QuietDelete(pszFilename);
1098 : }
1099 :
1100 12207 : return CE_None;
1101 : }
1102 :
1103 : //! @endcond
1104 :
1105 : /************************************************************************/
1106 : /* CreateCopy() */
1107 : /************************************************************************/
1108 :
1109 : /**
1110 : * \brief Create a copy of a dataset.
1111 : *
1112 : * This method will attempt to create a copy of a raster dataset with the
1113 : * indicated filename, and in this drivers format. Band number, size,
1114 : * type, projection, geotransform and so forth are all to be copied from
1115 : * the provided template dataset.
1116 : *
1117 : * Note that many sequential write once formats (such as JPEG and PNG) don't
1118 : * implement the Create() method but do implement this CreateCopy() method.
1119 : * If the driver doesn't implement CreateCopy(), but does implement Create()
1120 : * then the default CreateCopy() mechanism built on calling Create() will
1121 : * be used.
1122 : * So to test if CreateCopy() is available, you can test if GDAL_DCAP_CREATECOPY
1123 : * or GDAL_DCAP_CREATE is set in the GDAL metadata.
1124 : *
1125 : * It is intended that CreateCopy() will often be used with a source dataset
1126 : * which is a virtual dataset allowing configuration of band types, and other
1127 : * information without actually duplicating raster data (see the VRT driver).
1128 : * This is what is done by the gdal_translate utility for example.
1129 : *
1130 : * That function will try to validate the creation option list passed to the
1131 : * driver with the GDALValidateCreationOptions() method. This check can be
1132 : * disabled by defining the configuration option
1133 : * GDAL_VALIDATE_CREATION_OPTIONS=NO.
1134 : *
1135 : * This function copy all metadata from the default domain ("")
1136 : *
1137 : * Even is bStrict is TRUE, only the <b>value</b> of the data is equivalent,
1138 : * but the data layout (INTERLEAVE as PIXEL/LINE/BAND) of the dst dataset is
1139 : * controlled by the papszOptions creation options, and may differ from the
1140 : * poSrcDS src dataset.
1141 : * Starting from GDAL 3.5, if no INTERLEAVE and COMPRESS creation option has
1142 : * been specified in papszOptions, and if the driver supports equivalent
1143 : * interleaving as the src dataset, the CreateCopy() will internally add the
1144 : * proper creation option to get the same data interleaving.
1145 : *
1146 : * After you have finished working with the returned dataset, it is
1147 : * <b>required</b> to close it with GDALClose(). This does not only close the
1148 : * file handle, but also ensures that all the data and metadata has been written
1149 : * to the dataset (GDALFlushCache() is not sufficient for that purpose).
1150 : *
1151 : * For multidimensional datasets, papszOptions can contain array creation
1152 : * options, if they are prefixed with "ARRAY:". \see GDALGroup::CopyFrom()
1153 : * documentation for further details regarding such options.
1154 : *
1155 : * @param pszFilename the name for the new dataset. UTF-8 encoded.
1156 : * @param poSrcDS the dataset being duplicated.
1157 : * @param bStrict TRUE if the copy must be strictly equivalent, or more
1158 : * normally FALSE indicating that the copy may adapt as needed for the
1159 : * output format.
1160 : * @param papszOptions additional format dependent options controlling
1161 : * creation of the output file.
1162 : * The APPEND_SUBDATASET=YES option can be specified to avoid prior destruction
1163 : * of existing dataset.
1164 : * Starting with GDAL 3.8.0, the following options are recognized by the
1165 : * GTiff, COG, VRT, PNG au JPEG drivers:
1166 : * <ul>
1167 : * <li>COPY_SRC_MDD=AUTO/YES/NO: whether metadata domains of the source dataset
1168 : * should be copied to the destination dataset. In the default AUTO mode, only
1169 : * "safe" domains will be copied, which include the default metadata domain
1170 : * (some drivers may include other domains such as IMD, RPC, GEOLOCATION). When
1171 : * setting YES, all domains will be copied (but a few reserved ones like
1172 : * IMAGE_STRUCTURE or DERIVED_SUBDATASETS). When setting NO, no source metadata
1173 : * will be copied.
1174 : * </li>
1175 : *<li>SRC_MDD=domain_name: which source metadata domain should be copied.
1176 : * This option restricts the list of source metadata domains to be copied
1177 : * (it implies COPY_SRC_MDD=YES if it is not set). This option may be specified
1178 : * as many times as they are source domains. The default metadata domain is the
1179 : * empty string "" ("_DEFAULT_") may also be used when empty string is not practical)
1180 : * </li>
1181 : * </ul>
1182 : * @param pfnProgress a function to be used to report progress of the copy.
1183 : * @param pProgressData application data passed into progress function.
1184 : *
1185 : * @return a pointer to the newly created dataset (may be read-only access).
1186 : */
1187 :
1188 11630 : GDALDataset *GDALDriver::CreateCopy(const char *pszFilename,
1189 : GDALDataset *poSrcDS, int bStrict,
1190 : CSLConstList papszOptions,
1191 : GDALProgressFunc pfnProgress,
1192 : void *pProgressData)
1193 :
1194 : {
1195 11630 : if (pfnProgress == nullptr)
1196 8766 : pfnProgress = GDALDummyProgress;
1197 :
1198 11630 : const int nBandCount = poSrcDS->GetRasterCount();
1199 :
1200 : /* -------------------------------------------------------------------- */
1201 : /* If no INTERLEAVE creation option is given, we will try to add */
1202 : /* one that matches the current srcDS interleaving */
1203 : /* -------------------------------------------------------------------- */
1204 11630 : char **papszOptionsToDelete = nullptr;
1205 : const char *srcInterleave =
1206 11630 : poSrcDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
1207 6900 : if (nBandCount > 1 && srcInterleave != nullptr &&
1208 25035 : CSLFetchNameValue(papszOptions, "INTERLEAVE") == nullptr &&
1209 6505 : EQUAL(CSLFetchNameValueDef(papszOptions, "COMPRESS", "NONE"), "NONE"))
1210 : {
1211 :
1212 : // look for INTERLEAVE values of the driver
1213 6322 : char **interleavesCSL = nullptr;
1214 : const char *pszOptionList =
1215 6322 : this->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
1216 : CPLXMLNode *xmlNode =
1217 6322 : !pszOptionList ? nullptr : CPLParseXMLString(pszOptionList);
1218 6322 : for (CPLXMLNode *child = !xmlNode ? nullptr : xmlNode->psChild;
1219 132381 : child != nullptr; child = child->psNext)
1220 : {
1221 126059 : if ((child->eType == CXT_Element) &&
1222 126059 : EQUAL(child->pszValue, "Option"))
1223 : {
1224 : const char *nameAttribute =
1225 126059 : CPLGetXMLValue(child, "name", nullptr);
1226 126059 : const bool isInterleaveAttribute =
1227 126059 : nameAttribute && EQUAL(nameAttribute, "INTERLEAVE");
1228 126059 : if (isInterleaveAttribute)
1229 : {
1230 1185 : for (CPLXMLNode *optionChild = child->psChild;
1231 7178 : optionChild != nullptr;
1232 5993 : optionChild = optionChild->psNext)
1233 : {
1234 5993 : if ((optionChild->eType == CXT_Element) &&
1235 2423 : EQUAL(optionChild->pszValue, "Value"))
1236 : {
1237 2423 : CPLXMLNode *optionChildValue = optionChild->psChild;
1238 2423 : if (optionChildValue &&
1239 2423 : (optionChildValue->eType == CXT_Text))
1240 : {
1241 2423 : interleavesCSL = CSLAddString(
1242 2423 : interleavesCSL, optionChildValue->pszValue);
1243 : }
1244 : }
1245 : }
1246 : }
1247 : }
1248 : }
1249 6322 : CPLDestroyXMLNode(xmlNode);
1250 :
1251 : const char *dstInterleaveBand =
1252 11483 : (CSLFindString(interleavesCSL, "BAND") >= 0) ? "BAND"
1253 5161 : : (CSLFindString(interleavesCSL, "BSQ") >= 0) ? "BSQ"
1254 6322 : : nullptr;
1255 : const char *dstInterleaveLine =
1256 12644 : (CSLFindString(interleavesCSL, "LINE") >= 0) ? "LINE"
1257 6322 : : (CSLFindString(interleavesCSL, "BIL") >= 0) ? "BIL"
1258 6322 : : nullptr;
1259 : const char *dstInterleavePixel =
1260 11483 : (CSLFindString(interleavesCSL, "PIXEL") >= 0) ? "PIXEL"
1261 5161 : : (CSLFindString(interleavesCSL, "BIP") >= 0) ? "BIP"
1262 6322 : : nullptr;
1263 6322 : const char *dstInterleave =
1264 6625 : EQUAL(srcInterleave, "BAND") ? dstInterleaveBand
1265 604 : : EQUAL(srcInterleave, "LINE") ? dstInterleaveLine
1266 301 : : EQUAL(srcInterleave, "PIXEL") ? dstInterleavePixel
1267 : : nullptr;
1268 6322 : CSLDestroy(interleavesCSL);
1269 :
1270 6322 : if (dstInterleave != nullptr)
1271 : {
1272 1185 : papszOptionsToDelete = CSLDuplicate(papszOptions);
1273 1185 : papszOptionsToDelete = CSLSetNameValue(papszOptionsToDelete,
1274 : "INTERLEAVE", dstInterleave);
1275 1185 : papszOptionsToDelete = CSLSetNameValue(
1276 : papszOptionsToDelete, "@INTERLEAVE_ADDED_AUTOMATICALLY", "YES");
1277 1185 : papszOptions = papszOptionsToDelete;
1278 : }
1279 : }
1280 :
1281 : /* -------------------------------------------------------------------- */
1282 : /* Make sure we cleanup if there is an existing dataset of this */
1283 : /* name. But even if that seems to fail we will continue since */
1284 : /* it might just be a corrupt file or something. */
1285 : /* -------------------------------------------------------------------- */
1286 : const bool bAppendSubdataset =
1287 11630 : CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false);
1288 : // Note: @QUIET_DELETE_ON_CREATE_COPY is set to NO by the KMLSuperOverlay
1289 : // driver when writing a .kmz file. Also by GDALTranslate() if it has
1290 : // already done a similar job.
1291 23235 : if (!bAppendSubdataset &&
1292 11605 : CPLFetchBool(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY", true))
1293 : {
1294 8931 : QuietDeleteForCreateCopy(pszFilename, poSrcDS);
1295 : }
1296 :
1297 : int iIdxQuietDeleteOnCreateCopy =
1298 11630 : CSLPartialFindString(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY=");
1299 11630 : if (iIdxQuietDeleteOnCreateCopy >= 0)
1300 : {
1301 2674 : if (papszOptionsToDelete == nullptr)
1302 1623 : papszOptionsToDelete = CSLDuplicate(papszOptions);
1303 2674 : papszOptionsToDelete = CSLRemoveStrings(
1304 : papszOptionsToDelete, iIdxQuietDeleteOnCreateCopy, 1, nullptr);
1305 2674 : papszOptions = papszOptionsToDelete;
1306 : }
1307 :
1308 : /* -------------------------------------------------------------------- */
1309 : /* If _INTERNAL_DATASET=YES, the returned dataset will not be */
1310 : /* registered in the global list of open datasets. */
1311 : /* -------------------------------------------------------------------- */
1312 : const int iIdxInternalDataset =
1313 11630 : CSLPartialFindString(papszOptions, "_INTERNAL_DATASET=");
1314 11630 : bool bInternalDataset = false;
1315 11630 : if (iIdxInternalDataset >= 0)
1316 : {
1317 : bInternalDataset =
1318 4166 : CPLFetchBool(papszOptions, "_INTERNAL_DATASET", false);
1319 4166 : if (papszOptionsToDelete == nullptr)
1320 4166 : papszOptionsToDelete = CSLDuplicate(papszOptions);
1321 4166 : papszOptionsToDelete = CSLRemoveStrings(
1322 : papszOptionsToDelete, iIdxInternalDataset, 1, nullptr);
1323 4166 : papszOptions = papszOptionsToDelete;
1324 : }
1325 :
1326 : /* -------------------------------------------------------------------- */
1327 : /* Validate creation options. */
1328 : /* -------------------------------------------------------------------- */
1329 11630 : if (CPLTestBool(
1330 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
1331 : {
1332 23260 : auto poSrcGroup = poSrcDS->GetRootGroup();
1333 11630 : if (poSrcGroup != nullptr && GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER))
1334 : {
1335 226 : CPLStringList aosDatasetCO;
1336 120 : for (const char *pszOption : cpl::Iterate(papszOptions))
1337 : {
1338 7 : if (!STARTS_WITH_CI(pszOption, "ARRAY:"))
1339 0 : aosDatasetCO.AddString(pszOption);
1340 : }
1341 113 : GDALValidateCreationOptions(this, aosDatasetCO.List());
1342 : }
1343 : else
1344 : {
1345 11517 : GDALValidateCreationOptions(this, papszOptions);
1346 : }
1347 : }
1348 :
1349 : /* -------------------------------------------------------------------- */
1350 : /* Advise the source raster that we are going to read it completely */
1351 : /* -------------------------------------------------------------------- */
1352 :
1353 11630 : const int nXSize = poSrcDS->GetRasterXSize();
1354 11630 : const int nYSize = poSrcDS->GetRasterYSize();
1355 11630 : GDALDataType eDT = GDT_Unknown;
1356 11630 : if (nBandCount > 0)
1357 : {
1358 11394 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
1359 11394 : if (poSrcBand)
1360 11394 : eDT = poSrcBand->GetRasterDataType();
1361 : }
1362 11630 : poSrcDS->AdviseRead(0, 0, nXSize, nYSize, nXSize, nYSize, eDT, nBandCount,
1363 11630 : nullptr, nullptr);
1364 :
1365 : /* -------------------------------------------------------------------- */
1366 : /* If the format provides a CreateCopy() method use that, */
1367 : /* otherwise fallback to the internal implementation using the */
1368 : /* Create() method. */
1369 : /* -------------------------------------------------------------------- */
1370 11630 : GDALDataset *poDstDS = nullptr;
1371 11630 : auto l_pfnCreateCopy = GetCreateCopyCallback();
1372 22091 : if (l_pfnCreateCopy != nullptr &&
1373 10461 : !CPLTestBool(CPLGetConfigOption("GDAL_DEFAULT_CREATE_COPY", "NO")))
1374 : {
1375 10461 : poDstDS = l_pfnCreateCopy(pszFilename, poSrcDS, bStrict,
1376 : const_cast<char **>(papszOptions),
1377 : pfnProgress, pProgressData);
1378 10461 : if (poDstDS != nullptr)
1379 : {
1380 18404 : if (poDstDS->GetDescription() == nullptr ||
1381 9202 : strlen(poDstDS->GetDescription()) == 0)
1382 445 : poDstDS->SetDescription(pszFilename);
1383 :
1384 9202 : if (poDstDS->poDriver == nullptr)
1385 8160 : poDstDS->poDriver = this;
1386 :
1387 9202 : if (!bInternalDataset)
1388 5036 : poDstDS->AddToDatasetOpenList();
1389 : }
1390 : }
1391 : else
1392 : {
1393 1169 : poDstDS = DefaultCreateCopy(pszFilename, poSrcDS, bStrict, papszOptions,
1394 : pfnProgress, pProgressData);
1395 : }
1396 :
1397 11630 : CSLDestroy(papszOptionsToDelete);
1398 11630 : return poDstDS;
1399 : }
1400 :
1401 : /************************************************************************/
1402 : /* GDALCreateCopy() */
1403 : /************************************************************************/
1404 :
1405 : /**
1406 : * \brief Create a copy of a dataset.
1407 : *
1408 : * @see GDALDriver::CreateCopy()
1409 : */
1410 :
1411 6781 : GDALDatasetH CPL_STDCALL GDALCreateCopy(GDALDriverH hDriver,
1412 : const char *pszFilename,
1413 : GDALDatasetH hSrcDS, int bStrict,
1414 : CSLConstList papszOptions,
1415 : GDALProgressFunc pfnProgress,
1416 : void *pProgressData)
1417 :
1418 : {
1419 6781 : VALIDATE_POINTER1(hDriver, "GDALCreateCopy", nullptr);
1420 6781 : VALIDATE_POINTER1(hSrcDS, "GDALCreateCopy", nullptr);
1421 :
1422 6781 : return GDALDriver::FromHandle(hDriver)->CreateCopy(
1423 : pszFilename, GDALDataset::FromHandle(hSrcDS), bStrict, papszOptions,
1424 6781 : pfnProgress, pProgressData);
1425 : }
1426 :
1427 : /************************************************************************/
1428 : /* CanVectorTranslateFrom() */
1429 : /************************************************************************/
1430 :
1431 : /** Returns whether the driver can translate from a vector dataset,
1432 : * using the arguments passed to GDALVectorTranslate() stored in
1433 : * papszVectorTranslateArguments.
1434 : *
1435 : * This is used to determine if the driver supports the VectorTranslateFrom()
1436 : * operation.
1437 : *
1438 : * @param pszDestName Target dataset name
1439 : * @param poSourceDS Source dataset
1440 : * @param papszVectorTranslateArguments Non-positional arguments passed to
1441 : * GDALVectorTranslate() (may be nullptr)
1442 : * @param[out] ppapszFailureReasons nullptr, or a pointer to an null-terminated
1443 : * array of strings to record the reason(s) for the impossibility.
1444 : * @return true if VectorTranslateFrom() can be called with the same arguments.
1445 : * @since GDAL 3.8
1446 : */
1447 941 : bool GDALDriver::CanVectorTranslateFrom(
1448 : const char *pszDestName, GDALDataset *poSourceDS,
1449 : CSLConstList papszVectorTranslateArguments, char ***ppapszFailureReasons)
1450 :
1451 : {
1452 941 : if (ppapszFailureReasons)
1453 : {
1454 0 : *ppapszFailureReasons = nullptr;
1455 : }
1456 :
1457 941 : if (!pfnCanVectorTranslateFrom)
1458 : {
1459 935 : if (ppapszFailureReasons)
1460 : {
1461 0 : *ppapszFailureReasons = CSLAddString(
1462 : nullptr,
1463 : "CanVectorTranslateFrom() not implemented for this driver");
1464 : }
1465 935 : return false;
1466 : }
1467 :
1468 6 : char **papszFailureReasons = nullptr;
1469 6 : bool bRet = pfnCanVectorTranslateFrom(
1470 : pszDestName, poSourceDS, papszVectorTranslateArguments,
1471 : ppapszFailureReasons ? ppapszFailureReasons : &papszFailureReasons);
1472 6 : if (!ppapszFailureReasons)
1473 : {
1474 2 : for (const char *pszReason :
1475 10 : cpl::Iterate(static_cast<CSLConstList>(papszFailureReasons)))
1476 : {
1477 2 : CPLDebug("GDAL", "%s", pszReason);
1478 : }
1479 6 : CSLDestroy(papszFailureReasons);
1480 : }
1481 6 : return bRet;
1482 : }
1483 :
1484 193 : bool GDALDriver::HasOpenOption(const char *pszOpenOptionName) const
1485 : {
1486 193 : if (pszOpenOptionName == nullptr)
1487 0 : return false;
1488 :
1489 : // Const cast is safe here since we are only reading the metadata
1490 386 : auto pszOOMd{const_cast<GDALDriver *>(this)->GetMetadataItem(
1491 193 : GDAL_DMD_OPENOPTIONLIST)};
1492 193 : if (pszOOMd == nullptr)
1493 74 : return false;
1494 :
1495 238 : const CPLXMLTreeCloser oXml{CPLParseXMLString(pszOOMd)};
1496 1185 : for (CPLXMLNode *option = oXml->psChild; option != nullptr;
1497 1066 : option = option->psNext)
1498 : {
1499 1067 : if (EQUAL(CPLGetXMLValue(CPLGetXMLNode(option, "name"), nullptr, ""),
1500 : pszOpenOptionName))
1501 1 : return true;
1502 : }
1503 118 : return false;
1504 : }
1505 :
1506 : /************************************************************************/
1507 : /* VectorTranslateFrom() */
1508 : /************************************************************************/
1509 :
1510 : /** Create a copy of a vector dataset, using the arguments passed to
1511 : * GDALVectorTranslate() stored in papszVectorTranslateArguments.
1512 : *
1513 : * This may be implemented by some drivers that can convert from an existing
1514 : * dataset in an optimized way.
1515 : *
1516 : * This is for example used by the PMTiles to convert from MBTiles.
1517 : *
1518 : * @param pszDestName Target dataset name
1519 : * @param poSourceDS Source dataset
1520 : * @param papszVectorTranslateArguments Non-positional arguments passed to
1521 : * GDALVectorTranslate() (may be nullptr)
1522 : * @param pfnProgress a function to be used to report progress of the copy.
1523 : * @param pProgressData application data passed into progress function.
1524 : * @return a new dataset in case of success, or nullptr in case of error.
1525 : * @since GDAL 3.8
1526 : */
1527 4 : GDALDataset *GDALDriver::VectorTranslateFrom(
1528 : const char *pszDestName, GDALDataset *poSourceDS,
1529 : CSLConstList papszVectorTranslateArguments, GDALProgressFunc pfnProgress,
1530 : void *pProgressData)
1531 :
1532 : {
1533 4 : if (!pfnVectorTranslateFrom)
1534 : {
1535 0 : CPLError(CE_Failure, CPLE_AppDefined,
1536 : "VectorTranslateFrom() not implemented for this driver");
1537 0 : return nullptr;
1538 : }
1539 :
1540 4 : return pfnVectorTranslateFrom(pszDestName, poSourceDS,
1541 : papszVectorTranslateArguments, pfnProgress,
1542 4 : pProgressData);
1543 : }
1544 :
1545 : /************************************************************************/
1546 : /* QuietDelete() */
1547 : /************************************************************************/
1548 :
1549 : /**
1550 : * \brief Delete dataset if found.
1551 : *
1552 : * This is a helper method primarily used by Create() and
1553 : * CreateCopy() to predelete any dataset of the name soon to be
1554 : * created. It will attempt to delete the named dataset if
1555 : * one is found, otherwise it does nothing. An error is only
1556 : * returned if the dataset is found but the delete fails.
1557 : *
1558 : * This is a static method and it doesn't matter what driver instance
1559 : * it is invoked on. It will attempt to discover the correct driver
1560 : * using Identify().
1561 : *
1562 : * @param pszName the dataset name to try and delete.
1563 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
1564 : * terminated list of strings with the driver short names that must be
1565 : * considered. (Note: implemented only starting with GDAL 3.4.1)
1566 : * @return CE_None if the dataset does not exist, or is deleted without issues.
1567 : */
1568 :
1569 24393 : CPLErr GDALDriver::QuietDelete(const char *pszName,
1570 : CSLConstList papszAllowedDrivers)
1571 :
1572 : {
1573 : VSIStatBufL sStat;
1574 : const bool bExists =
1575 24393 : VSIStatExL(pszName, &sStat,
1576 24393 : VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0;
1577 :
1578 : #ifdef S_ISFIFO
1579 24393 : if (bExists && S_ISFIFO(sStat.st_mode))
1580 0 : return CE_None;
1581 : #endif
1582 :
1583 24393 : GDALDriver *poDriver = nullptr;
1584 24393 : if (papszAllowedDrivers)
1585 : {
1586 0 : GDALOpenInfo oOpenInfo(pszName, GDAL_OF_ALL);
1587 0 : for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
1588 : {
1589 : GDALDriver *poTmpDriver =
1590 0 : GDALDriver::FromHandle(GDALGetDriverByName(pszDriverName));
1591 0 : if (poTmpDriver)
1592 : {
1593 : const bool bIdentifyRes =
1594 0 : poTmpDriver->pfnIdentifyEx
1595 0 : ? poTmpDriver->pfnIdentifyEx(poTmpDriver, &oOpenInfo) >
1596 : 0
1597 0 : : poTmpDriver->pfnIdentify &&
1598 0 : poTmpDriver->pfnIdentify(&oOpenInfo) > 0;
1599 0 : if (bIdentifyRes)
1600 : {
1601 0 : poDriver = poTmpDriver;
1602 0 : break;
1603 : }
1604 : }
1605 : }
1606 : }
1607 : else
1608 : {
1609 48786 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1610 24393 : poDriver = GDALDriver::FromHandle(GDALIdentifyDriver(pszName, nullptr));
1611 : }
1612 :
1613 24393 : if (poDriver == nullptr)
1614 23510 : return CE_None;
1615 :
1616 925 : if (bExists && VSI_ISDIR(sStat.st_mode) &&
1617 42 : (EQUAL(poDriver->GetDescription(), "MapInfo File") ||
1618 42 : EQUAL(poDriver->GetDescription(), "ESRI Shapefile")))
1619 : {
1620 : // Those drivers are a bit special and handle directories as container
1621 : // of layers, but it is quite common to found other files too, and
1622 : // removing the directory might be non-desirable.
1623 42 : return CE_None;
1624 : }
1625 :
1626 841 : CPLDebug("GDAL", "QuietDelete(%s) invoking Delete()", pszName);
1627 :
1628 841 : poDriver->pfnDelete = poDriver->GetDeleteCallback();
1629 879 : const bool bQuiet = !bExists && poDriver->pfnDelete == nullptr &&
1630 38 : poDriver->pfnDeleteDataSource == nullptr;
1631 841 : if (bQuiet)
1632 : {
1633 76 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1634 38 : return poDriver->Delete(pszName);
1635 : }
1636 : else
1637 : {
1638 803 : return poDriver->Delete(pszName);
1639 : }
1640 : }
1641 :
1642 : /************************************************************************/
1643 : /* Delete() */
1644 : /************************************************************************/
1645 :
1646 : /**
1647 : * \brief Delete named dataset.
1648 : *
1649 : * The driver will attempt to delete the named dataset in a driver specific
1650 : * fashion. Full featured drivers will delete all associated files,
1651 : * database objects, or whatever is appropriate. The default behavior when
1652 : * no driver specific behavior is provided is to attempt to delete all the
1653 : * files that are returned by GDALGetFileList() on the dataset handle.
1654 : *
1655 : * It is unwise to have open dataset handles on this dataset when it is
1656 : * deleted.
1657 : *
1658 : * Equivalent of the C function GDALDeleteDataset().
1659 : *
1660 : * @param pszFilename name of dataset to delete.
1661 : *
1662 : * @return CE_None on success, or CE_Failure if the operation fails.
1663 : */
1664 :
1665 4394 : CPLErr GDALDriver::Delete(const char *pszFilename)
1666 :
1667 : {
1668 4394 : pfnDelete = GetDeleteCallback();
1669 4394 : if (pfnDelete != nullptr)
1670 1041 : return pfnDelete(pszFilename);
1671 3353 : else if (pfnDeleteDataSource != nullptr)
1672 0 : return pfnDeleteDataSource(this, pszFilename);
1673 :
1674 : /* -------------------------------------------------------------------- */
1675 : /* Collect file list. */
1676 : /* -------------------------------------------------------------------- */
1677 3353 : GDALDatasetH hDS = GDALOpenEx(pszFilename, GDAL_OF_VERBOSE_ERROR, nullptr,
1678 : nullptr, nullptr);
1679 :
1680 3353 : if (hDS == nullptr)
1681 : {
1682 237 : if (CPLGetLastErrorNo() == 0)
1683 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1684 : "Unable to open %s to obtain file list.", pszFilename);
1685 :
1686 237 : return CE_Failure;
1687 : }
1688 :
1689 6232 : const CPLStringList aosFileList(GDALGetFileList(hDS));
1690 :
1691 3116 : GDALClose(hDS);
1692 3116 : hDS = nullptr;
1693 :
1694 3116 : if (aosFileList.empty())
1695 : {
1696 0 : CPLError(CE_Failure, CPLE_NotSupported,
1697 : "Unable to determine files associated with %s, "
1698 : "delete fails.",
1699 : pszFilename);
1700 0 : return CE_Failure;
1701 : }
1702 :
1703 3116 : return Delete(nullptr, aosFileList.List());
1704 : }
1705 :
1706 : /************************************************************************/
1707 : /* Delete() */
1708 : /************************************************************************/
1709 :
1710 : /**
1711 : * \brief Delete a currently opened dataset
1712 : *
1713 : * The driver will attempt to delete the passed dataset in a driver specific
1714 : * fashion. Full featured drivers will delete all associated files,
1715 : * database objects, or whatever is appropriate. The default behavior when
1716 : * no driver specific behavior is provided is to attempt to delete all the
1717 : * files that are returned by GDALGetFileList() on the dataset handle.
1718 : *
1719 : * Note that this will generally not work on Windows systems that don't accept
1720 : * deleting opened files.
1721 : *
1722 : * At least one of poDS or papszFileList must not be NULL
1723 : *
1724 : * @param poDS dataset to delete, or NULL
1725 : * @param papszFileList File list to delete, typically obtained with
1726 : * poDS->GetFileList(), or NULL
1727 : *
1728 : * @return CE_None on success, or CE_Failure if the operation fails.
1729 : *
1730 : * @since 3.12
1731 : */
1732 :
1733 3127 : CPLErr GDALDriver::Delete(GDALDataset *poDS, CSLConstList papszFileList)
1734 :
1735 : {
1736 3127 : if (poDS)
1737 : {
1738 10 : pfnDelete = GetDeleteCallback();
1739 10 : if (pfnDelete != nullptr)
1740 6 : return pfnDelete(poDS->GetDescription());
1741 4 : else if (pfnDeleteDataSource != nullptr)
1742 0 : return pfnDeleteDataSource(this, poDS->GetDescription());
1743 : }
1744 :
1745 : /* -------------------------------------------------------------------- */
1746 : /* Delete all files. */
1747 : /* -------------------------------------------------------------------- */
1748 3121 : CPLErr eErr = CE_None;
1749 6897 : for (int i = 0; papszFileList && papszFileList[i]; ++i)
1750 : {
1751 3776 : if (VSIUnlink(papszFileList[i]) != 0)
1752 : {
1753 4 : CPLError(CE_Failure, CPLE_AppDefined, "Deleting %s failed:\n%s",
1754 2 : papszFileList[i], VSIStrerror(errno));
1755 2 : eErr = CE_Failure;
1756 : }
1757 : }
1758 :
1759 3121 : return eErr;
1760 : }
1761 :
1762 : /************************************************************************/
1763 : /* GDALDeleteDataset() */
1764 : /************************************************************************/
1765 :
1766 : /**
1767 : * \brief Delete named dataset.
1768 : *
1769 : * @see GDALDriver::Delete()
1770 : */
1771 :
1772 2391 : CPLErr CPL_STDCALL GDALDeleteDataset(GDALDriverH hDriver,
1773 : const char *pszFilename)
1774 :
1775 : {
1776 2391 : if (hDriver == nullptr)
1777 10 : hDriver = GDALIdentifyDriver(pszFilename, nullptr);
1778 :
1779 2391 : if (hDriver == nullptr)
1780 : {
1781 1 : CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
1782 : pszFilename);
1783 1 : return CE_Failure;
1784 : }
1785 :
1786 : #ifdef OGRAPISPY_ENABLED
1787 2390 : if (GDALGetMetadataItem(hDriver, GDAL_DCAP_VECTOR, nullptr))
1788 : {
1789 453 : OGRAPISpyDeleteDataSource(hDriver, pszFilename);
1790 : }
1791 : #endif
1792 :
1793 2390 : return GDALDriver::FromHandle(hDriver)->Delete(pszFilename);
1794 : }
1795 :
1796 : /************************************************************************/
1797 : /* DefaultRename() */
1798 : /* */
1799 : /* The generic implementation based on the file list used when */
1800 : /* there is no format specific implementation. */
1801 : /************************************************************************/
1802 :
1803 : //! @cond Doxygen_Suppress
1804 175 : CPLErr GDALDriver::DefaultRename(const char *pszNewName, const char *pszOldName)
1805 :
1806 : {
1807 : /* -------------------------------------------------------------------- */
1808 : /* Collect file list. */
1809 : /* -------------------------------------------------------------------- */
1810 : auto poDS = std::unique_ptr<GDALDataset>(
1811 : GDALDataset::Open(pszOldName, GDAL_OF_ALL | GDAL_OF_VERBOSE_ERROR,
1812 350 : nullptr, nullptr, nullptr));
1813 :
1814 175 : if (!poDS)
1815 : {
1816 0 : if (CPLGetLastErrorNo() == 0)
1817 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1818 : "Unable to open %s to obtain file list.", pszOldName);
1819 :
1820 0 : return CE_Failure;
1821 : }
1822 :
1823 350 : const CPLStringList aosFileList(poDS->GetFileList());
1824 :
1825 175 : poDS.reset();
1826 :
1827 175 : if (aosFileList.empty())
1828 : {
1829 0 : CPLError(CE_Failure, CPLE_NotSupported,
1830 : "Unable to determine files associated with %s,\n"
1831 : "rename fails.",
1832 : pszOldName);
1833 :
1834 0 : return CE_Failure;
1835 : }
1836 :
1837 : /* -------------------------------------------------------------------- */
1838 : /* Produce a list of new filenames that correspond to the old */
1839 : /* names. */
1840 : /* -------------------------------------------------------------------- */
1841 175 : CPLErr eErr = CE_None;
1842 : const CPLStringList aosNewFileList(
1843 350 : CPLCorrespondingPaths(pszOldName, pszNewName, aosFileList.List()));
1844 :
1845 175 : if (aosNewFileList.empty())
1846 0 : return CE_Failure;
1847 :
1848 : // Guaranteed by CPLCorrespondingPaths()
1849 175 : CPLAssert(aosNewFileList.size() == aosFileList.size());
1850 :
1851 : VSIStatBufL sStatBuf;
1852 177 : if (VSIStatL(pszOldName, &sStatBuf) == 0 && VSI_ISDIR(sStatBuf.st_mode) &&
1853 2 : VSIStatL(pszNewName, &sStatBuf) != 0)
1854 : {
1855 2 : if (VSIMkdirRecursive(pszNewName, 0755) != 0)
1856 : {
1857 1 : CPLError(CE_Failure, CPLE_AppDefined,
1858 : "Cannot create directory '%s'", pszNewName);
1859 1 : return CE_Failure;
1860 : }
1861 : }
1862 :
1863 358 : for (int i = 0; i < aosFileList.size(); ++i)
1864 : {
1865 184 : if (CPLMoveFile(aosNewFileList[i], aosFileList[i]) != 0)
1866 : {
1867 : // Above method will have emitted an error in case of failure.
1868 0 : eErr = CE_Failure;
1869 : // Try to put the ones we moved back.
1870 0 : for (--i; i >= 0; i--)
1871 : {
1872 : // Nothing we can do if the moving back doesn't work...
1873 0 : CPL_IGNORE_RET_VAL(
1874 0 : CPLMoveFile(aosFileList[i], aosNewFileList[i]));
1875 : }
1876 0 : break;
1877 : }
1878 : }
1879 :
1880 174 : return eErr;
1881 : }
1882 :
1883 : //! @endcond
1884 :
1885 : /************************************************************************/
1886 : /* Rename() */
1887 : /************************************************************************/
1888 :
1889 : /**
1890 : * \brief Rename a dataset.
1891 : *
1892 : * Rename a dataset. This may including moving the dataset to a new directory
1893 : * or even a new filesystem.
1894 : *
1895 : * It is unwise to have open dataset handles on this dataset when it is
1896 : * being renamed.
1897 : *
1898 : * Equivalent of the C function GDALRenameDataset().
1899 : *
1900 : * @param pszNewName new name for the dataset.
1901 : * @param pszOldName old name for the dataset.
1902 : *
1903 : * @return CE_None on success, or CE_Failure if the operation fails.
1904 : */
1905 :
1906 177 : CPLErr GDALDriver::Rename(const char *pszNewName, const char *pszOldName)
1907 :
1908 : {
1909 177 : pfnRename = GetRenameCallback();
1910 177 : if (pfnRename != nullptr)
1911 3 : return pfnRename(pszNewName, pszOldName);
1912 :
1913 174 : return DefaultRename(pszNewName, pszOldName);
1914 : }
1915 :
1916 : /************************************************************************/
1917 : /* GDALRenameDataset() */
1918 : /************************************************************************/
1919 :
1920 : /**
1921 : * \brief Rename a dataset.
1922 : *
1923 : * @see GDALDriver::Rename()
1924 : */
1925 :
1926 178 : CPLErr CPL_STDCALL GDALRenameDataset(GDALDriverH hDriver,
1927 : const char *pszNewName,
1928 : const char *pszOldName)
1929 :
1930 : {
1931 178 : if (hDriver == nullptr)
1932 5 : hDriver = GDALIdentifyDriver(pszOldName, nullptr);
1933 :
1934 178 : if (hDriver == nullptr)
1935 : {
1936 1 : CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
1937 : pszOldName);
1938 1 : return CE_Failure;
1939 : }
1940 :
1941 177 : return GDALDriver::FromHandle(hDriver)->Rename(pszNewName, pszOldName);
1942 : }
1943 :
1944 : /************************************************************************/
1945 : /* DefaultCopyFiles() */
1946 : /* */
1947 : /* The default implementation based on file lists used when */
1948 : /* there is no format specific implementation. */
1949 : /************************************************************************/
1950 :
1951 : //! @cond Doxygen_Suppress
1952 12 : CPLErr GDALDriver::DefaultCopyFiles(const char *pszNewName,
1953 : const char *pszOldName)
1954 :
1955 : {
1956 : /* -------------------------------------------------------------------- */
1957 : /* Collect file list. */
1958 : /* -------------------------------------------------------------------- */
1959 : auto poDS = std::unique_ptr<GDALDataset>(
1960 : GDALDataset::Open(pszOldName, GDAL_OF_ALL | GDAL_OF_VERBOSE_ERROR,
1961 24 : nullptr, nullptr, nullptr));
1962 :
1963 12 : if (!poDS)
1964 : {
1965 0 : if (CPLGetLastErrorNo() == 0)
1966 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1967 : "Unable to open %s to obtain file list.", pszOldName);
1968 :
1969 0 : return CE_Failure;
1970 : }
1971 :
1972 24 : const CPLStringList aosFileList(poDS->GetFileList());
1973 :
1974 12 : poDS.reset();
1975 :
1976 12 : if (aosFileList.empty())
1977 : {
1978 0 : CPLError(CE_Failure, CPLE_NotSupported,
1979 : "Unable to determine files associated with %s,\n"
1980 : "copy fails.",
1981 : pszOldName);
1982 :
1983 0 : return CE_Failure;
1984 : }
1985 :
1986 : /* -------------------------------------------------------------------- */
1987 : /* Produce a list of new filenames that correspond to the old */
1988 : /* names. */
1989 : /* -------------------------------------------------------------------- */
1990 12 : CPLErr eErr = CE_None;
1991 : const CPLStringList aosNewFileList(
1992 24 : CPLCorrespondingPaths(pszOldName, pszNewName, aosFileList.List()));
1993 :
1994 12 : if (aosNewFileList.empty())
1995 0 : return CE_Failure;
1996 :
1997 : // Guaranteed by CPLCorrespondingPaths()
1998 12 : CPLAssert(aosNewFileList.size() == aosFileList.size());
1999 :
2000 : VSIStatBufL sStatBuf;
2001 14 : if (VSIStatL(pszOldName, &sStatBuf) == 0 && VSI_ISDIR(sStatBuf.st_mode) &&
2002 2 : VSIStatL(pszNewName, &sStatBuf) != 0)
2003 : {
2004 2 : if (VSIMkdirRecursive(pszNewName, 0755) != 0)
2005 : {
2006 1 : CPLError(CE_Failure, CPLE_AppDefined,
2007 : "Cannot create directory '%s'", pszNewName);
2008 1 : return CE_Failure;
2009 : }
2010 : }
2011 :
2012 33 : for (int i = 0; i < aosFileList.size(); ++i)
2013 : {
2014 22 : if (CPLCopyFile(aosNewFileList[i], aosFileList[i]) != 0)
2015 : {
2016 : // Above method will have emitted an error in case of failure.
2017 0 : eErr = CE_Failure;
2018 : // Try to put the ones we moved back.
2019 0 : for (--i; i >= 0; --i)
2020 : {
2021 0 : if (VSIUnlink(aosNewFileList[i]) != 0)
2022 : {
2023 0 : CPLError(CE_Warning, CPLE_AppDefined, "Cannot delete '%s'",
2024 : aosNewFileList[i]);
2025 : }
2026 : }
2027 0 : break;
2028 : }
2029 : }
2030 :
2031 11 : return eErr;
2032 : }
2033 :
2034 : //! @endcond
2035 :
2036 : /************************************************************************/
2037 : /* CopyFiles() */
2038 : /************************************************************************/
2039 :
2040 : /**
2041 : * \brief Copy the files of a dataset.
2042 : *
2043 : * Copy all the files associated with a dataset.
2044 : *
2045 : * Equivalent of the C function GDALCopyDatasetFiles().
2046 : *
2047 : * @param pszNewName new name for the dataset.
2048 : * @param pszOldName old name for the dataset.
2049 : *
2050 : * @return CE_None on success, or CE_Failure if the operation fails.
2051 : */
2052 :
2053 14 : CPLErr GDALDriver::CopyFiles(const char *pszNewName, const char *pszOldName)
2054 :
2055 : {
2056 14 : pfnCopyFiles = GetCopyFilesCallback();
2057 14 : if (pfnCopyFiles != nullptr)
2058 3 : return pfnCopyFiles(pszNewName, pszOldName);
2059 :
2060 11 : return DefaultCopyFiles(pszNewName, pszOldName);
2061 : }
2062 :
2063 : /************************************************************************/
2064 : /* GDALCopyDatasetFiles() */
2065 : /************************************************************************/
2066 :
2067 : /**
2068 : * \brief Copy the files of a dataset.
2069 : *
2070 : * @see GDALDriver::CopyFiles()
2071 : */
2072 :
2073 15 : CPLErr CPL_STDCALL GDALCopyDatasetFiles(GDALDriverH hDriver,
2074 : const char *pszNewName,
2075 : const char *pszOldName)
2076 :
2077 : {
2078 15 : if (hDriver == nullptr)
2079 10 : hDriver = GDALIdentifyDriver(pszOldName, nullptr);
2080 :
2081 15 : if (hDriver == nullptr)
2082 : {
2083 1 : CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
2084 : pszOldName);
2085 1 : return CE_Failure;
2086 : }
2087 :
2088 14 : return GDALDriver::FromHandle(hDriver)->CopyFiles(pszNewName, pszOldName);
2089 : }
2090 :
2091 : /************************************************************************/
2092 : /* GDALDriverHasOpenOption() */
2093 : /************************************************************************/
2094 :
2095 : /**
2096 : * \brief Returns TRUE if the given open option is supported by the driver.
2097 : * @param hDriver the handle of the driver
2098 : * @param pszOpenOptionName name of the open option to be checked
2099 : * @return TRUE if the driver supports the open option
2100 : * @since GDAL 3.11
2101 : */
2102 2 : bool GDALDriverHasOpenOption(GDALDriverH hDriver, const char *pszOpenOptionName)
2103 : {
2104 2 : VALIDATE_POINTER1(hDriver, "GDALDriverHasOpenOption", false);
2105 2 : return GDALDriver::FromHandle(hDriver)->HasOpenOption(pszOpenOptionName);
2106 : }
2107 :
2108 : /************************************************************************/
2109 : /* GDALGetDriverShortName() */
2110 : /************************************************************************/
2111 :
2112 : /**
2113 : * \brief Return the short name of a driver
2114 : *
2115 : * This is the string that can be
2116 : * passed to the GDALGetDriverByName() function.
2117 : *
2118 : * For the GeoTIFF driver, this is "GTiff"
2119 : *
2120 : * @param hDriver the handle of the driver
2121 : * @return the short name of the driver. The
2122 : * returned string should not be freed and is owned by the driver.
2123 : */
2124 :
2125 8608820 : const char *CPL_STDCALL GDALGetDriverShortName(GDALDriverH hDriver)
2126 :
2127 : {
2128 8608820 : VALIDATE_POINTER1(hDriver, "GDALGetDriverShortName", nullptr);
2129 :
2130 8608820 : return GDALDriver::FromHandle(hDriver)->GetDescription();
2131 : }
2132 :
2133 : /************************************************************************/
2134 : /* GDALGetDriverLongName() */
2135 : /************************************************************************/
2136 :
2137 : /**
2138 : * \brief Return the long name of a driver
2139 : *
2140 : * For the GeoTIFF driver, this is "GeoTIFF"
2141 : *
2142 : * @param hDriver the handle of the driver
2143 : * @return the long name of the driver or empty string. The
2144 : * returned string should not be freed and is owned by the driver.
2145 : */
2146 :
2147 511 : const char *CPL_STDCALL GDALGetDriverLongName(GDALDriverH hDriver)
2148 :
2149 : {
2150 511 : VALIDATE_POINTER1(hDriver, "GDALGetDriverLongName", nullptr);
2151 :
2152 : const char *pszLongName =
2153 511 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_LONGNAME);
2154 :
2155 511 : if (pszLongName == nullptr)
2156 0 : return "";
2157 :
2158 511 : return pszLongName;
2159 : }
2160 :
2161 : /************************************************************************/
2162 : /* GDALGetDriverHelpTopic() */
2163 : /************************************************************************/
2164 :
2165 : /**
2166 : * \brief Return the URL to the help that describes the driver
2167 : *
2168 : * That URL is relative to the GDAL documentation directory.
2169 : *
2170 : * For the GeoTIFF driver, this is "frmt_gtiff.html"
2171 : *
2172 : * @param hDriver the handle of the driver
2173 : * @return the URL to the help that describes the driver or NULL. The
2174 : * returned string should not be freed and is owned by the driver.
2175 : */
2176 :
2177 0 : const char *CPL_STDCALL GDALGetDriverHelpTopic(GDALDriverH hDriver)
2178 :
2179 : {
2180 0 : VALIDATE_POINTER1(hDriver, "GDALGetDriverHelpTopic", nullptr);
2181 :
2182 0 : return GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_HELPTOPIC);
2183 : }
2184 :
2185 : /************************************************************************/
2186 : /* GDALGetDriverCreationOptionList() */
2187 : /************************************************************************/
2188 :
2189 : /**
2190 : * \brief Return the list of creation options of the driver
2191 : *
2192 : * Return the list of creation options of the driver used by Create() and
2193 : * CreateCopy() as an XML string
2194 : *
2195 : * @param hDriver the handle of the driver
2196 : * @return an XML string that describes the list of creation options or
2197 : * empty string. The returned string should not be freed and is
2198 : * owned by the driver.
2199 : */
2200 :
2201 0 : const char *CPL_STDCALL GDALGetDriverCreationOptionList(GDALDriverH hDriver)
2202 :
2203 : {
2204 0 : VALIDATE_POINTER1(hDriver, "GDALGetDriverCreationOptionList", nullptr);
2205 :
2206 : const char *pszOptionList =
2207 0 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2208 0 : GDAL_DMD_CREATIONOPTIONLIST);
2209 :
2210 0 : if (pszOptionList == nullptr)
2211 0 : return "";
2212 :
2213 0 : return pszOptionList;
2214 : }
2215 :
2216 : /************************************************************************/
2217 : /* GDALValidateCreationOptions() */
2218 : /************************************************************************/
2219 :
2220 : /**
2221 : * \brief Validate the list of creation options that are handled by a driver
2222 : *
2223 : * This is a helper method primarily used by Create() and
2224 : * CreateCopy() to validate that the passed in list of creation options
2225 : * is compatible with the GDAL_DMD_CREATIONOPTIONLIST metadata item defined
2226 : * by some drivers. @see GDALGetDriverCreationOptionList()
2227 : *
2228 : * If the GDAL_DMD_CREATIONOPTIONLIST metadata item is not defined, this
2229 : * function will return TRUE. Otherwise it will check that the keys and values
2230 : * in the list of creation options are compatible with the capabilities declared
2231 : * by the GDAL_DMD_CREATIONOPTIONLIST metadata item. In case of incompatibility
2232 : * a (non fatal) warning will be emitted and FALSE will be returned.
2233 : *
2234 : * @param hDriver the handle of the driver with whom the lists of creation
2235 : * option must be validated
2236 : * @param papszCreationOptions the list of creation options. An array of
2237 : * strings, whose last element is a NULL pointer
2238 : * @return TRUE if the list of creation options is compatible with the Create()
2239 : * and CreateCopy() method of the driver, FALSE otherwise.
2240 : */
2241 :
2242 37007 : int CPL_STDCALL GDALValidateCreationOptions(GDALDriverH hDriver,
2243 : CSLConstList papszCreationOptions)
2244 : {
2245 37007 : VALIDATE_POINTER1(hDriver, "GDALValidateCreationOptions", FALSE);
2246 : const char *pszOptionList =
2247 37007 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2248 37007 : GDAL_DMD_CREATIONOPTIONLIST);
2249 37007 : CPLString osDriver;
2250 : osDriver.Printf("driver %s",
2251 37007 : GDALDriver::FromHandle(hDriver)->GetDescription());
2252 37007 : bool bFoundOptionToRemove = false;
2253 37007 : constexpr const char *const apszExcludedOptions[] = {
2254 : "APPEND_SUBDATASET", "COPY_SRC_MDD", "SRC_MDD", "SKIP_HOLES"};
2255 54399 : for (const char *pszCO : cpl::Iterate(papszCreationOptions))
2256 : {
2257 87603 : for (const char *pszExcludedOptions : apszExcludedOptions)
2258 : {
2259 70211 : if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
2260 205 : pszCO[strlen(pszExcludedOptions)] == '=')
2261 : {
2262 205 : bFoundOptionToRemove = true;
2263 205 : break;
2264 : }
2265 : }
2266 17597 : if (bFoundOptionToRemove)
2267 205 : break;
2268 : }
2269 37007 : CSLConstList papszOptionsToValidate = papszCreationOptions;
2270 37007 : char **papszOptionsToFree = nullptr;
2271 37007 : if (bFoundOptionToRemove)
2272 : {
2273 628 : for (const char *pszCO : cpl::Iterate(papszCreationOptions))
2274 : {
2275 423 : bool bMatch = false;
2276 1713 : for (const char *pszExcludedOptions : apszExcludedOptions)
2277 : {
2278 1508 : if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
2279 218 : pszCO[strlen(pszExcludedOptions)] == '=')
2280 : {
2281 218 : bMatch = true;
2282 218 : break;
2283 : }
2284 : }
2285 423 : if (!bMatch)
2286 205 : papszOptionsToFree = CSLAddString(papszOptionsToFree, pszCO);
2287 : }
2288 205 : papszOptionsToValidate = papszOptionsToFree;
2289 : }
2290 :
2291 37007 : const bool bRet = CPL_TO_BOOL(GDALValidateOptions(
2292 : pszOptionList, papszOptionsToValidate, "creation option", osDriver));
2293 37007 : CSLDestroy(papszOptionsToFree);
2294 37007 : return bRet;
2295 : }
2296 :
2297 : /************************************************************************/
2298 : /* GDALValidateOpenOptions() */
2299 : /************************************************************************/
2300 :
2301 63154 : int GDALValidateOpenOptions(GDALDriverH hDriver,
2302 : const char *const *papszOpenOptions)
2303 : {
2304 63154 : VALIDATE_POINTER1(hDriver, "GDALValidateOpenOptions", FALSE);
2305 : const char *pszOptionList =
2306 63154 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2307 63154 : GDAL_DMD_OPENOPTIONLIST);
2308 126308 : CPLString osDriver;
2309 : osDriver.Printf("driver %s",
2310 63154 : GDALDriver::FromHandle(hDriver)->GetDescription());
2311 63154 : return GDALValidateOptions(pszOptionList, papszOpenOptions, "open option",
2312 63154 : osDriver);
2313 : }
2314 :
2315 : /************************************************************************/
2316 : /* GDALValidateOptions() */
2317 : /************************************************************************/
2318 :
2319 114536 : int GDALValidateOptions(const char *pszOptionList,
2320 : const char *const *papszOptionsToValidate,
2321 : const char *pszErrorMessageOptionType,
2322 : const char *pszErrorMessageContainerName)
2323 : {
2324 114536 : if (papszOptionsToValidate == nullptr || *papszOptionsToValidate == nullptr)
2325 96862 : return TRUE;
2326 17674 : if (pszOptionList == nullptr)
2327 181 : return TRUE;
2328 :
2329 17493 : CPLXMLNode *psNode = CPLParseXMLString(pszOptionList);
2330 17493 : if (psNode == nullptr)
2331 : {
2332 0 : CPLError(CE_Warning, CPLE_AppDefined,
2333 : "Could not parse %s list of %s. Assuming options are valid.",
2334 : pszErrorMessageOptionType, pszErrorMessageContainerName);
2335 0 : return TRUE;
2336 : }
2337 :
2338 17493 : bool bRet = true;
2339 47864 : while (*papszOptionsToValidate)
2340 : {
2341 30371 : char *pszKey = nullptr;
2342 : const char *pszValue =
2343 30371 : CPLParseNameValue(*papszOptionsToValidate, &pszKey);
2344 30371 : if (pszKey == nullptr)
2345 : {
2346 1 : CPLError(CE_Warning, CPLE_NotSupported,
2347 : "%s '%s' is not formatted with the key=value format",
2348 : pszErrorMessageOptionType, *papszOptionsToValidate);
2349 1 : bRet = false;
2350 :
2351 1 : ++papszOptionsToValidate;
2352 2356 : continue;
2353 : }
2354 :
2355 30370 : if (EQUAL(pszKey, "VALIDATE_OPEN_OPTIONS"))
2356 : {
2357 0 : ++papszOptionsToValidate;
2358 0 : CPLFree(pszKey);
2359 0 : continue;
2360 : }
2361 :
2362 : // Must we be forgiving in case of missing option ?
2363 30370 : bool bWarnIfMissingKey = true;
2364 30370 : if (pszKey[0] == '@')
2365 : {
2366 2338 : bWarnIfMissingKey = false;
2367 2338 : memmove(pszKey, pszKey + 1, strlen(pszKey + 1) + 1);
2368 : }
2369 :
2370 30370 : CPLXMLNode *psChildNode = psNode->psChild;
2371 306771 : while (psChildNode)
2372 : {
2373 304416 : if (EQUAL(psChildNode->pszValue, "OPTION"))
2374 : {
2375 : const char *pszOptionName =
2376 304416 : CPLGetXMLValue(psChildNode, "name", "");
2377 : /* For option names terminated by wildcard (NITF BLOCKA option
2378 : * names for example) */
2379 304416 : if (strlen(pszOptionName) > 0 &&
2380 304416 : pszOptionName[strlen(pszOptionName) - 1] == '*' &&
2381 1288 : EQUALN(pszOptionName, pszKey, strlen(pszOptionName) - 1))
2382 : {
2383 216 : break;
2384 : }
2385 :
2386 : /* For option names beginning by a wildcard */
2387 304200 : if (pszOptionName[0] == '*' &&
2388 57 : strlen(pszKey) > strlen(pszOptionName) &&
2389 9 : EQUAL(pszKey + strlen(pszKey) - strlen(pszOptionName + 1),
2390 : pszOptionName + 1))
2391 : {
2392 2 : break;
2393 : }
2394 :
2395 : // For options names with * in the middle
2396 304198 : const char *pszStarInOptionName = strchr(pszOptionName, '*');
2397 304198 : if (pszStarInOptionName &&
2398 1093 : pszStarInOptionName != pszOptionName &&
2399 : pszStarInOptionName !=
2400 1093 : pszOptionName + strlen(pszOptionName) - 1 &&
2401 21 : strlen(pszKey) > static_cast<size_t>(pszStarInOptionName -
2402 12 : pszOptionName) &&
2403 12 : EQUALN(pszKey, pszOptionName,
2404 : static_cast<size_t>(pszStarInOptionName -
2405 12 : pszOptionName)) &&
2406 12 : EQUAL(pszKey +
2407 : static_cast<size_t>(pszStarInOptionName -
2408 : pszOptionName) +
2409 : 1,
2410 : pszStarInOptionName + 1))
2411 : {
2412 6 : break;
2413 : }
2414 :
2415 304192 : if (EQUAL(pszOptionName, pszKey))
2416 : {
2417 27679 : break;
2418 : }
2419 : const char *pszAlias =
2420 276513 : CPLGetXMLValue(psChildNode, "alias", nullptr);
2421 : const char *pszDeprecatedAlias =
2422 276513 : pszAlias ? nullptr
2423 275610 : : CPLGetXMLValue(psChildNode, "deprecated_alias",
2424 276513 : nullptr);
2425 276513 : if (!pszAlias && pszDeprecatedAlias)
2426 151 : pszAlias = pszDeprecatedAlias;
2427 276513 : if (pszAlias && EQUAL(pszAlias, pszKey))
2428 : {
2429 112 : if (pszDeprecatedAlias)
2430 : {
2431 0 : CPLDebug(
2432 : "GDAL",
2433 : "Using deprecated alias '%s'. New name is '%s'",
2434 : pszAlias, pszOptionName);
2435 : }
2436 112 : break;
2437 : }
2438 : }
2439 276401 : psChildNode = psChildNode->psNext;
2440 : }
2441 30370 : if (psChildNode == nullptr)
2442 : {
2443 2379 : if (bWarnIfMissingKey &&
2444 24 : (!EQUAL(pszErrorMessageOptionType, "open option") ||
2445 2 : CPLFetchBool(papszOptionsToValidate, "VALIDATE_OPEN_OPTIONS",
2446 : true)))
2447 : {
2448 24 : CPLError(CE_Warning, CPLE_NotSupported,
2449 : "%s does not support %s %s",
2450 : pszErrorMessageContainerName,
2451 : pszErrorMessageOptionType, pszKey);
2452 24 : bRet = false;
2453 : }
2454 :
2455 2355 : CPLFree(pszKey);
2456 2355 : ++papszOptionsToValidate;
2457 2355 : continue;
2458 : }
2459 :
2460 : #ifdef DEBUG
2461 28015 : CPLXMLNode *psChildSubNode = psChildNode->psChild;
2462 166399 : while (psChildSubNode)
2463 : {
2464 138384 : if (psChildSubNode->eType == CXT_Attribute)
2465 : {
2466 96940 : if (!(EQUAL(psChildSubNode->pszValue, "name") ||
2467 68925 : EQUAL(psChildSubNode->pszValue, "alias") ||
2468 68730 : EQUAL(psChildSubNode->pszValue, "deprecated_alias") ||
2469 68643 : EQUAL(psChildSubNode->pszValue, "alt_config_option") ||
2470 68623 : EQUAL(psChildSubNode->pszValue, "description") ||
2471 45078 : EQUAL(psChildSubNode->pszValue, "type") ||
2472 17063 : EQUAL(psChildSubNode->pszValue, "min") ||
2473 16746 : EQUAL(psChildSubNode->pszValue, "max") ||
2474 16361 : EQUAL(psChildSubNode->pszValue, "default") ||
2475 1029 : EQUAL(psChildSubNode->pszValue, "maxsize") ||
2476 999 : EQUAL(psChildSubNode->pszValue, "required") ||
2477 944 : EQUAL(psChildSubNode->pszValue, "scope")))
2478 : {
2479 : /* Driver error */
2480 0 : CPLError(CE_Warning, CPLE_NotSupported,
2481 : "%s : unhandled attribute '%s' for %s %s.",
2482 : pszErrorMessageContainerName,
2483 : psChildSubNode->pszValue, pszKey,
2484 : pszErrorMessageOptionType);
2485 : }
2486 : }
2487 138384 : psChildSubNode = psChildSubNode->psNext;
2488 : }
2489 : #endif
2490 :
2491 28015 : const char *pszType = CPLGetXMLValue(psChildNode, "type", nullptr);
2492 28015 : const char *pszMin = CPLGetXMLValue(psChildNode, "min", nullptr);
2493 28015 : const char *pszMax = CPLGetXMLValue(psChildNode, "max", nullptr);
2494 28015 : if (pszType != nullptr)
2495 : {
2496 28015 : if (EQUAL(pszType, "INT") || EQUAL(pszType, "INTEGER"))
2497 : {
2498 8772 : const char *pszValueIter = pszValue;
2499 22479 : while (*pszValueIter)
2500 : {
2501 13757 : if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
2502 69 : *pszValueIter == '+' || *pszValueIter == '-'))
2503 : {
2504 50 : CPLError(CE_Warning, CPLE_NotSupported,
2505 : "'%s' is an unexpected value for %s %s of "
2506 : "type int.",
2507 : pszValue, pszKey, pszErrorMessageOptionType);
2508 50 : bRet = false;
2509 50 : break;
2510 : }
2511 13707 : ++pszValueIter;
2512 : }
2513 8772 : if (*pszValueIter == '\0')
2514 : {
2515 8722 : if (pszMin && atoi(pszValue) < atoi(pszMin))
2516 : {
2517 10 : CPLError(CE_Warning, CPLE_NotSupported,
2518 : "'%s' is an unexpected value for %s %s that "
2519 : "should be >= %s.",
2520 : pszValue, pszKey, pszErrorMessageOptionType,
2521 : pszMin);
2522 10 : bRet = false;
2523 : }
2524 8722 : if (pszMax && atoi(pszValue) > atoi(pszMax))
2525 : {
2526 12 : CPLError(CE_Warning, CPLE_NotSupported,
2527 : "'%s' is an unexpected value for %s %s that "
2528 : "should be <= %s.",
2529 : pszValue, pszKey, pszErrorMessageOptionType,
2530 : pszMax);
2531 12 : bRet = false;
2532 : }
2533 8772 : }
2534 : }
2535 19243 : else if (EQUAL(pszType, "UNSIGNED INT"))
2536 : {
2537 3 : const char *pszValueIter = pszValue;
2538 10 : while (*pszValueIter)
2539 : {
2540 7 : if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
2541 0 : *pszValueIter == '+'))
2542 : {
2543 0 : CPLError(CE_Warning, CPLE_NotSupported,
2544 : "'%s' is an unexpected value for %s %s of "
2545 : "type unsigned int.",
2546 : pszValue, pszKey, pszErrorMessageOptionType);
2547 0 : bRet = false;
2548 0 : break;
2549 : }
2550 7 : ++pszValueIter;
2551 : }
2552 3 : if (*pszValueIter == '\0')
2553 : {
2554 3 : if (pszMin && atoi(pszValue) < atoi(pszMin))
2555 : {
2556 0 : CPLError(CE_Warning, CPLE_NotSupported,
2557 : "'%s' is an unexpected value for %s %s that "
2558 : "should be >= %s.",
2559 : pszValue, pszKey, pszErrorMessageOptionType,
2560 : pszMin);
2561 0 : bRet = false;
2562 : }
2563 3 : if (pszMax && atoi(pszValue) > atoi(pszMax))
2564 : {
2565 0 : CPLError(CE_Warning, CPLE_NotSupported,
2566 : "'%s' is an unexpected value for %s %s that "
2567 : "should be <= %s.",
2568 : pszValue, pszKey, pszErrorMessageOptionType,
2569 : pszMax);
2570 0 : bRet = false;
2571 : }
2572 : }
2573 : }
2574 19240 : else if (EQUAL(pszType, "FLOAT"))
2575 : {
2576 772 : char *endPtr = nullptr;
2577 772 : double dfVal = CPLStrtod(pszValue, &endPtr);
2578 772 : if (!(endPtr == nullptr || *endPtr == '\0'))
2579 : {
2580 2 : CPLError(
2581 : CE_Warning, CPLE_NotSupported,
2582 : "'%s' is an unexpected value for %s %s of type float.",
2583 : pszValue, pszKey, pszErrorMessageOptionType);
2584 2 : bRet = false;
2585 : }
2586 : else
2587 : {
2588 770 : if (pszMin && dfVal < CPLAtof(pszMin))
2589 : {
2590 3 : CPLError(CE_Warning, CPLE_NotSupported,
2591 : "'%s' is an unexpected value for %s %s that "
2592 : "should be >= %s.",
2593 : pszValue, pszKey, pszErrorMessageOptionType,
2594 : pszMin);
2595 3 : bRet = false;
2596 : }
2597 770 : if (pszMax && dfVal > CPLAtof(pszMax))
2598 : {
2599 0 : CPLError(CE_Warning, CPLE_NotSupported,
2600 : "'%s' is an unexpected value for %s %s that "
2601 : "should be <= %s.",
2602 : pszValue, pszKey, pszErrorMessageOptionType,
2603 : pszMax);
2604 0 : bRet = false;
2605 : }
2606 : }
2607 : }
2608 18468 : else if (EQUAL(pszType, "BOOLEAN"))
2609 : {
2610 4170 : if (!(EQUAL(pszValue, "ON") || EQUAL(pszValue, "TRUE") ||
2611 4101 : EQUAL(pszValue, "YES") || EQUAL(pszValue, "OFF") ||
2612 488 : EQUAL(pszValue, "FALSE") || EQUAL(pszValue, "NO")))
2613 : {
2614 0 : CPLError(CE_Warning, CPLE_NotSupported,
2615 : "'%s' is an unexpected value for %s %s of type "
2616 : "boolean.",
2617 : pszValue, pszKey, pszErrorMessageOptionType);
2618 0 : bRet = false;
2619 : }
2620 : }
2621 14298 : else if (EQUAL(pszType, "STRING-SELECT"))
2622 : {
2623 7384 : bool bMatchFound = false;
2624 7384 : bool bOtherValuesElementFound = false;
2625 7384 : CPLXMLNode *psStringSelect = psChildNode->psChild;
2626 45453 : while (psStringSelect)
2627 : {
2628 45411 : if (psStringSelect->eType == CXT_Element &&
2629 21934 : EQUAL(psStringSelect->pszValue, "Value"))
2630 : {
2631 21934 : CPLXMLNode *psOptionNode = psStringSelect->psChild;
2632 37153 : while (psOptionNode)
2633 : {
2634 22561 : if (psOptionNode->eType == CXT_Text &&
2635 21815 : EQUAL(psOptionNode->pszValue, pszValue))
2636 : {
2637 7223 : bMatchFound = true;
2638 7223 : break;
2639 : }
2640 15338 : if (psOptionNode->eType == CXT_Attribute &&
2641 746 : (EQUAL(psOptionNode->pszValue, "alias") ||
2642 15 : EQUAL(psOptionNode->pszValue,
2643 731 : "deprecated_alias")) &&
2644 731 : EQUAL(psOptionNode->psChild->pszValue,
2645 : pszValue))
2646 : {
2647 119 : bMatchFound = true;
2648 119 : break;
2649 : }
2650 15219 : psOptionNode = psOptionNode->psNext;
2651 : }
2652 21934 : if (bMatchFound)
2653 21934 : break;
2654 : }
2655 23477 : else if (psStringSelect->eType == CXT_Element &&
2656 0 : EQUAL(psStringSelect->pszValue, "OtherValues"))
2657 : {
2658 0 : bOtherValuesElementFound = true;
2659 : }
2660 38069 : psStringSelect = psStringSelect->psNext;
2661 : }
2662 7384 : if (!bMatchFound && !bOtherValuesElementFound)
2663 : {
2664 42 : CPLError(CE_Warning, CPLE_NotSupported,
2665 : "'%s' is an unexpected value for %s %s of type "
2666 : "string-select.",
2667 : pszValue, pszKey, pszErrorMessageOptionType);
2668 42 : bRet = false;
2669 : }
2670 : }
2671 6914 : else if (EQUAL(pszType, "STRING"))
2672 : {
2673 : const char *pszMaxSize =
2674 6914 : CPLGetXMLValue(psChildNode, "maxsize", nullptr);
2675 6914 : if (pszMaxSize != nullptr)
2676 : {
2677 30 : if (static_cast<int>(strlen(pszValue)) > atoi(pszMaxSize))
2678 : {
2679 1 : CPLError(CE_Warning, CPLE_NotSupported,
2680 : "'%s' is of size %d, whereas maximum size for "
2681 : "%s %s is %d.",
2682 1 : pszValue, static_cast<int>(strlen(pszValue)),
2683 : pszKey, pszErrorMessageOptionType,
2684 : atoi(pszMaxSize));
2685 1 : bRet = false;
2686 : }
2687 : }
2688 : }
2689 : else
2690 : {
2691 : /* Driver error */
2692 0 : CPLError(CE_Warning, CPLE_NotSupported,
2693 : "%s : type '%s' for %s %s is not recognized.",
2694 : pszErrorMessageContainerName, pszType, pszKey,
2695 : pszErrorMessageOptionType);
2696 : }
2697 : }
2698 : else
2699 : {
2700 : /* Driver error */
2701 0 : CPLError(CE_Warning, CPLE_NotSupported, "%s : no type for %s %s.",
2702 : pszErrorMessageContainerName, pszKey,
2703 : pszErrorMessageOptionType);
2704 : }
2705 28015 : CPLFree(pszKey);
2706 28015 : ++papszOptionsToValidate;
2707 : }
2708 :
2709 17493 : CPLDestroyXMLNode(psNode);
2710 17493 : return bRet ? TRUE : FALSE;
2711 : }
2712 :
2713 : /************************************************************************/
2714 : /* GDALIdentifyDriver() */
2715 : /************************************************************************/
2716 :
2717 : /**
2718 : * \brief Identify the driver that can open a dataset.
2719 : *
2720 : * This function will try to identify the driver that can open the passed file
2721 : * name by invoking the Identify method of each registered GDALDriver in turn.
2722 : * The first driver that successfully identifies the file name will be returned.
2723 : * If all drivers fail then NULL is returned.
2724 : *
2725 : * In order to reduce the need for such searches to touch the operating system
2726 : * file system machinery, it is possible to give an optional list of files.
2727 : * This is the list of all files at the same level in the file system as the
2728 : * target file, including the target file. The filenames will not include any
2729 : * path components, and are essentially just the output of VSIReadDir() on the
2730 : * parent directory. If the target object does not have filesystem semantics
2731 : * then the file list should be NULL.
2732 : *
2733 : * @param pszFilename the name of the file to access. In the case of
2734 : * exotic drivers this may not refer to a physical file, but instead contain
2735 : * information for the driver on how to access a dataset.
2736 : *
2737 : * @param papszFileList an array of strings, whose last element is the NULL
2738 : * pointer. These strings are filenames that are auxiliary to the main
2739 : * filename. The passed value may be NULL.
2740 : *
2741 : * @return A GDALDriverH handle or NULL on failure. For C++ applications
2742 : * this handle can be cast to a GDALDriver *.
2743 : */
2744 :
2745 25977 : GDALDriverH CPL_STDCALL GDALIdentifyDriver(const char *pszFilename,
2746 : CSLConstList papszFileList)
2747 :
2748 : {
2749 25977 : return GDALIdentifyDriverEx(pszFilename, 0, nullptr, papszFileList);
2750 : }
2751 :
2752 : /************************************************************************/
2753 : /* GDALIdentifyDriverEx() */
2754 : /************************************************************************/
2755 :
2756 : /**
2757 : * \brief Identify the driver that can open a dataset.
2758 : *
2759 : * This function will try to identify the driver that can open the passed file
2760 : * name by invoking the Identify method of each registered GDALDriver in turn.
2761 : * The first driver that successfully identifies the file name will be returned.
2762 : * If all drivers fail then NULL is returned.
2763 : *
2764 : * In order to reduce the need for such searches to touch the operating system
2765 : * file system machinery, it is possible to give an optional list of files.
2766 : * This is the list of all files at the same level in the file system as the
2767 : * target file, including the target file. The filenames will not include any
2768 : * path components, and are essentially just the output of VSIReadDir() on the
2769 : * parent directory. If the target object does not have filesystem semantics
2770 : * then the file list should be NULL.
2771 : *
2772 : * @param pszFilename the name of the file to access. In the case of
2773 : * exotic drivers this may not refer to a physical file, but instead contain
2774 : * information for the driver on how to access a dataset.
2775 : *
2776 : * @param nIdentifyFlags a combination of GDAL_OF_RASTER for raster drivers
2777 : * or GDAL_OF_VECTOR for vector drivers. If none of the value is specified,
2778 : * both kinds are implied.
2779 : *
2780 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
2781 : * terminated list of strings with the driver short names that must be
2782 : * considered.
2783 : *
2784 : * @param papszFileList an array of strings, whose last element is the NULL
2785 : * pointer. These strings are filenames that are auxiliary to the main
2786 : * filename. The passed value may be NULL.
2787 : *
2788 : * @return A GDALDriverH handle or NULL on failure. For C++ applications
2789 : * this handle can be cast to a GDALDriver *.
2790 : */
2791 :
2792 26067 : GDALDriverH CPL_STDCALL GDALIdentifyDriverEx(
2793 : const char *pszFilename, unsigned int nIdentifyFlags,
2794 : const char *const *papszAllowedDrivers, const char *const *papszFileList)
2795 : {
2796 26067 : GDALDriverManager *poDM = GetGDALDriverManager();
2797 26067 : CPLAssert(nullptr != poDM);
2798 :
2799 : // If no driver kind is specified, assume all are to be probed.
2800 26067 : if ((nIdentifyFlags & GDAL_OF_KIND_MASK) == 0)
2801 26024 : nIdentifyFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
2802 :
2803 52134 : GDALOpenInfo oOpenInfo(pszFilename, nIdentifyFlags, papszFileList);
2804 26067 : oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
2805 :
2806 52134 : CPLErrorStateBackuper oBackuper;
2807 26067 : CPLErrorSetState(CE_None, CPLE_AppDefined, "");
2808 :
2809 26067 : const int nDriverCount = poDM->GetDriverCount();
2810 :
2811 : // First pass: only use drivers that have a pfnIdentify implementation.
2812 52134 : std::vector<GDALDriver *> apoSecondPassDrivers;
2813 5740770 : for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
2814 : {
2815 5715990 : GDALDriver *poDriver = poDM->GetDriver(iDriver);
2816 5723360 : if (papszAllowedDrivers != nullptr &&
2817 7370 : CSLFindString(papszAllowedDrivers,
2818 : GDALGetDriverShortName(poDriver)) == -1)
2819 : {
2820 1115280 : continue;
2821 : }
2822 :
2823 5709940 : VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
2824 :
2825 5708660 : if (poDriver->pfnIdentify == nullptr &&
2826 1104120 : poDriver->pfnIdentifyEx == nullptr)
2827 : {
2828 1104120 : continue;
2829 : }
2830 :
2831 4604580 : if (papszAllowedDrivers != nullptr &&
2832 44 : CSLFindString(papszAllowedDrivers,
2833 : GDALGetDriverShortName(poDriver)) == -1)
2834 0 : continue;
2835 13808900 : if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
2836 4605050 : (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
2837 508 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
2838 141 : continue;
2839 13816500 : if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
2840 4609310 : (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
2841 4912 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
2842 3693 : continue;
2843 :
2844 4600710 : if (poDriver->pfnIdentifyEx)
2845 : {
2846 0 : if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) > 0)
2847 0 : return poDriver;
2848 : }
2849 : else
2850 : {
2851 4600710 : const int nIdentifyRes = poDriver->pfnIdentify(&oOpenInfo);
2852 4600710 : if (nIdentifyRes > 0)
2853 1280 : return poDriver;
2854 4625420 : if (nIdentifyRes < 0 &&
2855 25993 : poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
2856 : {
2857 : // Not loaded plugin
2858 37 : apoSecondPassDrivers.push_back(poDriver);
2859 : }
2860 : }
2861 : }
2862 :
2863 : // second pass: try loading plugin drivers
2864 24821 : for (auto poDriver : apoSecondPassDrivers)
2865 : {
2866 : // Force plugin driver loading
2867 35 : poDriver->GetMetadata();
2868 35 : if (poDriver->pfnIdentify(&oOpenInfo) > 0)
2869 1 : return poDriver;
2870 : }
2871 :
2872 : // third pass: slow method.
2873 5610740 : for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
2874 : {
2875 5586180 : GDALDriver *poDriver = poDM->GetDriver(iDriver);
2876 5590040 : if (papszAllowedDrivers != nullptr &&
2877 3858 : CSLFindString(papszAllowedDrivers,
2878 : GDALGetDriverShortName(poDriver)) == -1)
2879 : {
2880 3841 : continue;
2881 : }
2882 :
2883 5582340 : VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
2884 :
2885 16745600 : if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
2886 5582790 : (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
2887 452 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
2888 141 : continue;
2889 16747200 : if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
2890 5583780 : (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
2891 1584 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
2892 953 : continue;
2893 :
2894 5581250 : if (poDriver->pfnIdentifyEx != nullptr)
2895 : {
2896 0 : if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) == 0)
2897 0 : continue;
2898 : }
2899 5581250 : else if (poDriver->pfnIdentify != nullptr)
2900 : {
2901 4501030 : if (poDriver->pfnIdentify(&oOpenInfo) == 0)
2902 4475670 : continue;
2903 : }
2904 :
2905 : GDALDataset *poDS;
2906 1105580 : if (poDriver->pfnOpen != nullptr)
2907 : {
2908 1056270 : poDS = poDriver->pfnOpen(&oOpenInfo);
2909 1056270 : if (poDS != nullptr)
2910 : {
2911 95 : delete poDS;
2912 95 : return GDALDriver::ToHandle(poDriver);
2913 : }
2914 :
2915 1056180 : if (CPLGetLastErrorType() != CE_None)
2916 136 : return nullptr;
2917 : }
2918 49311 : else if (poDriver->pfnOpenWithDriverArg != nullptr)
2919 : {
2920 0 : poDS = poDriver->pfnOpenWithDriverArg(poDriver, &oOpenInfo);
2921 0 : if (poDS != nullptr)
2922 : {
2923 0 : delete poDS;
2924 0 : return GDALDriver::ToHandle(poDriver);
2925 : }
2926 :
2927 0 : if (CPLGetLastErrorType() != CE_None)
2928 0 : return nullptr;
2929 : }
2930 : }
2931 :
2932 24555 : return nullptr;
2933 : }
2934 :
2935 : /************************************************************************/
2936 : /* GetMetadataItem() */
2937 : /************************************************************************/
2938 :
2939 13056300 : const char *GDALDriver::GetMetadataItem(const char *pszName,
2940 : const char *pszDomain)
2941 : {
2942 13056300 : if (pszDomain == nullptr || pszDomain[0] == '\0')
2943 : {
2944 13056200 : if (EQUAL(pszName, GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST))
2945 : {
2946 2212 : const char *pszVal = GDALMajorObject::GetMetadataItem(pszName, "");
2947 2212 : if (pszVal)
2948 1988 : return pszVal;
2949 224 : if (GetMetadataItem(GDAL_DCAP_RASTER))
2950 : {
2951 153 : auto poDM = GetGDALDriverManager();
2952 153 : auto poGTiffDrv = poDM->GetDriverByName("GTiff");
2953 153 : if (poGTiffDrv)
2954 : {
2955 : const char *pszXML =
2956 153 : poGTiffDrv->GetMetadataItem(pszName, "");
2957 153 : if (pszXML)
2958 : {
2959 306 : CPLString osXML(pszXML);
2960 153 : osXML.replaceAll("<Value>INTERNAL</Value>", "");
2961 153 : return CPLSPrintf("%s", osXML.c_str());
2962 : }
2963 : }
2964 : }
2965 : }
2966 : }
2967 13054200 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
2968 : }
2969 :
2970 : /************************************************************************/
2971 : /* SetMetadataItem() */
2972 : /************************************************************************/
2973 :
2974 4565380 : CPLErr GDALDriver::SetMetadataItem(const char *pszName, const char *pszValue,
2975 : const char *pszDomain)
2976 :
2977 : {
2978 4565380 : if (pszDomain == nullptr || pszDomain[0] == '\0')
2979 : {
2980 : /* Automatically sets GDAL_DMD_EXTENSIONS from GDAL_DMD_EXTENSION */
2981 4757940 : if (EQUAL(pszName, GDAL_DMD_EXTENSION) &&
2982 197967 : GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSIONS) == nullptr)
2983 : {
2984 197967 : GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSIONS, pszValue);
2985 : }
2986 : /* and vice-versa if there is a single extension in GDAL_DMD_EXTENSIONS */
2987 8804880 : else if (EQUAL(pszName, GDAL_DMD_EXTENSIONS) &&
2988 4370990 : strchr(pszValue, ' ') == nullptr &&
2989 8987 : GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSION) ==
2990 : nullptr)
2991 : {
2992 8987 : GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSION, pszValue);
2993 : }
2994 : }
2995 4565380 : return GDALMajorObject::SetMetadataItem(pszName, pszValue, pszDomain);
2996 : }
2997 :
2998 : /************************************************************************/
2999 : /* InstantiateAlgorithm() */
3000 : /************************************************************************/
3001 :
3002 : //! @cond Doxygen_Suppress
3003 :
3004 : GDALAlgorithm *
3005 843 : GDALDriver::InstantiateAlgorithm(const std::vector<std::string> &aosPath)
3006 : {
3007 843 : pfnInstantiateAlgorithm = GetInstantiateAlgorithmCallback();
3008 843 : if (pfnInstantiateAlgorithm)
3009 843 : return pfnInstantiateAlgorithm(aosPath);
3010 0 : return nullptr;
3011 : }
3012 :
3013 : /************************************************************************/
3014 : /* DeclareAlgorithm() */
3015 : /************************************************************************/
3016 :
3017 10895 : void GDALDriver::DeclareAlgorithm(const std::vector<std::string> &aosPath)
3018 : {
3019 21790 : const std::string osDriverName = GetDescription();
3020 10895 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
3021 :
3022 21790 : if (!singleton.HasDeclaredSubAlgorithm({"driver"}))
3023 : {
3024 3190 : singleton.DeclareAlgorithm(
3025 : {"driver"},
3026 144 : []() -> std::unique_ptr<GDALAlgorithm>
3027 : {
3028 288 : return std::make_unique<GDALContainerAlgorithm>(
3029 144 : "driver", "Command for driver specific operations.");
3030 1595 : });
3031 : }
3032 :
3033 : std::vector<std::string> path = {"driver",
3034 65370 : CPLString(osDriverName).tolower()};
3035 10895 : if (!singleton.HasDeclaredSubAlgorithm(path))
3036 : {
3037 1064 : auto lambda = [osDriverName]() -> std::unique_ptr<GDALAlgorithm>
3038 : {
3039 : auto poDriver =
3040 1064 : GetGDALDriverManager()->GetDriverByName(osDriverName.c_str());
3041 1064 : if (poDriver)
3042 : {
3043 : const char *pszHelpTopic =
3044 1064 : poDriver->GetMetadataItem(GDAL_DMD_HELPTOPIC);
3045 2128 : return std::make_unique<GDALContainerAlgorithm>(
3046 2128 : CPLString(osDriverName).tolower(),
3047 2128 : std::string("Command for ")
3048 1064 : .append(osDriverName)
3049 : .append(" driver specific operations."),
3050 2128 : pszHelpTopic ? std::string("/").append(pszHelpTopic)
3051 1064 : : std::string());
3052 : }
3053 0 : return nullptr;
3054 9570 : };
3055 9570 : singleton.DeclareAlgorithm(path, std::move(lambda));
3056 : }
3057 :
3058 10895 : path.insert(path.end(), aosPath.begin(), aosPath.end());
3059 :
3060 843 : auto lambda = [osDriverName, aosPath]() -> std::unique_ptr<GDALAlgorithm>
3061 : {
3062 : auto poDriver =
3063 843 : GetGDALDriverManager()->GetDriverByName(osDriverName.c_str());
3064 843 : if (poDriver)
3065 : return std::unique_ptr<GDALAlgorithm>(
3066 843 : poDriver->InstantiateAlgorithm(aosPath));
3067 0 : return nullptr;
3068 21790 : };
3069 :
3070 10895 : singleton.DeclareAlgorithm(path, std::move(lambda));
3071 :
3072 10895 : CPL_IGNORE_RET_VAL(osDriverName);
3073 10895 : }
3074 :
3075 : //! @endcond
3076 :
3077 : /************************************************************************/
3078 : /* DoesDriverHandleExtension() */
3079 : /************************************************************************/
3080 :
3081 191671 : static bool DoesDriverHandleExtension(GDALDriverH hDriver, const char *pszExt)
3082 : {
3083 191671 : bool bRet = false;
3084 : const char *pszDriverExtensions =
3085 191671 : GDALGetMetadataItem(hDriver, GDAL_DMD_EXTENSIONS, nullptr);
3086 191671 : if (pszDriverExtensions)
3087 : {
3088 320902 : const CPLStringList aosTokens(CSLTokenizeString(pszDriverExtensions));
3089 160451 : const int nTokens = aosTokens.size();
3090 360063 : for (int j = 0; j < nTokens; ++j)
3091 : {
3092 204212 : if (EQUAL(pszExt, aosTokens[j]))
3093 : {
3094 4600 : bRet = true;
3095 4600 : break;
3096 : }
3097 : }
3098 : }
3099 191671 : return bRet;
3100 : }
3101 :
3102 : /************************************************************************/
3103 : /* IsOnlyExpectedGDBDrivers() */
3104 : /************************************************************************/
3105 :
3106 1 : static bool IsOnlyExpectedGDBDrivers(const CPLStringList &aosDriverNames)
3107 : {
3108 3 : for (const char *pszDrvName : aosDriverNames)
3109 : {
3110 2 : if (!EQUAL(pszDrvName, "OpenFileGDB") &&
3111 1 : !EQUAL(pszDrvName, "FileGDB") && !EQUAL(pszDrvName, "GPSBabel"))
3112 : {
3113 0 : return false;
3114 : }
3115 : }
3116 1 : return true;
3117 : }
3118 :
3119 : /************************************************************************/
3120 : /* GDALGetOutputDriversForDatasetName() */
3121 : /************************************************************************/
3122 :
3123 : /** Return a list of driver short names that are likely candidates for the
3124 : * provided output file name.
3125 : *
3126 : * @param pszDestDataset Output dataset name (might not exist).
3127 : * @param nDatasetTypeFlag GDAL_OF_RASTER, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER
3128 : * or a binary-or'ed combination of them
3129 : * @param bSingleMatch Whether a single match is desired, that is to say the
3130 : * returned list will contain at most one item, which will
3131 : * be the first driver in the order they are registered to
3132 : * match the output dataset name. Note that in this mode, if
3133 : * nDatasetTypeFlag==GDAL_OF_RASTER and pszDestDataset has
3134 : * no extension, GTiff will be selected.
3135 : * @param bEmitWarning Whether a warning should be emitted when bSingleMatch is
3136 : * true and there are more than 2 candidates.
3137 : * @return NULL terminated list of driver short names.
3138 : * To be freed with CSLDestroy()
3139 : * @since 3.9
3140 : */
3141 2699 : char **GDALGetOutputDriversForDatasetName(const char *pszDestDataset,
3142 : int nDatasetTypeFlag,
3143 : bool bSingleMatch, bool bEmitWarning)
3144 : {
3145 5398 : CPLStringList aosDriverNames;
3146 5398 : CPLStringList aosMissingDriverNames;
3147 :
3148 5398 : std::string osExt = CPLGetExtensionSafe(pszDestDataset);
3149 2699 : if (EQUAL(osExt.c_str(), "zip"))
3150 : {
3151 2 : const CPLString osLower(CPLString(pszDestDataset).tolower());
3152 1 : if (osLower.endsWith(".shp.zip"))
3153 : {
3154 1 : osExt = "shp.zip";
3155 : }
3156 0 : else if (osLower.endsWith(".gpkg.zip"))
3157 : {
3158 0 : osExt = "gpkg.zip";
3159 : }
3160 : }
3161 2698 : else if (EQUAL(osExt.c_str(), "json"))
3162 : {
3163 1 : const CPLString osLower(CPLString(pszDestDataset).tolower());
3164 1 : if (osLower.endsWith(".gdalg.json"))
3165 0 : return nullptr;
3166 : }
3167 :
3168 2699 : auto poDM = GetGDALDriverManager();
3169 2699 : const int nDriverCount = poDM->GetDriverCount(true);
3170 2699 : GDALDriver *poMissingPluginDriver = nullptr;
3171 5398 : std::string osMatchingPrefix;
3172 614977 : for (int i = 0; i < nDriverCount; i++)
3173 : {
3174 612278 : GDALDriver *poDriver = poDM->GetDriver(i, true);
3175 612278 : bool bOk = false;
3176 612278 : if ((poDriver->GetMetadataItem(GDAL_DCAP_CREATE) != nullptr ||
3177 374769 : poDriver->GetMetadataItem(GDAL_DCAP_CREATECOPY) != nullptr ||
3178 1224560 : poDriver->GetMetadataItem(GDAL_DCAP_UPDATE) != nullptr) &&
3179 318479 : (((nDatasetTypeFlag & GDAL_OF_RASTER) &&
3180 254643 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) != nullptr) ||
3181 154472 : ((nDatasetTypeFlag & GDAL_OF_VECTOR) &&
3182 63246 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) != nullptr) ||
3183 124458 : ((nDatasetTypeFlag & GDAL_OF_MULTIDIM_RASTER) &&
3184 590 : poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) != nullptr)))
3185 : {
3186 194071 : bOk = true;
3187 : }
3188 422533 : else if (poDriver->GetMetadataItem(GDAL_DCAP_VECTOR_TRANSLATE_FROM) &&
3189 4326 : (nDatasetTypeFlag & GDAL_OF_VECTOR) != 0)
3190 : {
3191 0 : bOk = true;
3192 : }
3193 612278 : if (bOk)
3194 : {
3195 385742 : if (!osExt.empty() &&
3196 191671 : DoesDriverHandleExtension(GDALDriver::ToHandle(poDriver),
3197 : osExt.c_str()))
3198 : {
3199 4600 : if (poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
3200 : {
3201 0 : poMissingPluginDriver = poDriver;
3202 0 : aosMissingDriverNames.AddString(poDriver->GetDescription());
3203 : }
3204 : else
3205 4600 : aosDriverNames.AddString(poDriver->GetDescription());
3206 : }
3207 : else
3208 : {
3209 : const char *pszPrefix =
3210 189471 : poDriver->GetMetadataItem(GDAL_DMD_CONNECTION_PREFIX);
3211 189471 : if (pszPrefix && STARTS_WITH_CI(pszDestDataset, pszPrefix))
3212 : {
3213 9 : if (poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
3214 : {
3215 0 : osMatchingPrefix = pszPrefix;
3216 0 : poMissingPluginDriver = poDriver;
3217 : aosMissingDriverNames.AddString(
3218 0 : poDriver->GetDescription());
3219 : }
3220 : else
3221 9 : aosDriverNames.AddString(poDriver->GetDescription());
3222 : }
3223 : }
3224 : }
3225 : }
3226 :
3227 : // GMT is registered before netCDF for opening reasons, but we want
3228 : // netCDF to be used by default for output.
3229 2706 : if (EQUAL(osExt.c_str(), "nc") && aosDriverNames.size() == 2 &&
3230 2706 : EQUAL(aosDriverNames[0], "GMT") && EQUAL(aosDriverNames[1], "netCDF"))
3231 : {
3232 0 : aosDriverNames.Clear();
3233 0 : aosDriverNames.AddString("netCDF");
3234 0 : aosDriverNames.AddString("GMT");
3235 : }
3236 :
3237 2699 : if (bSingleMatch)
3238 : {
3239 2627 : if (nDatasetTypeFlag == GDAL_OF_RASTER)
3240 : {
3241 2158 : if (aosDriverNames.empty())
3242 : {
3243 12 : if (osExt.empty())
3244 : {
3245 8 : aosDriverNames.AddString("GTiff");
3246 : }
3247 : }
3248 2146 : else if (aosDriverNames.size() >= 2)
3249 : {
3250 3892 : if (bEmitWarning && !(EQUAL(aosDriverNames[0], "GTiff") &&
3251 1945 : EQUAL(aosDriverNames[1], "COG")))
3252 : {
3253 2 : CPLError(CE_Warning, CPLE_AppDefined,
3254 : "Several drivers matching %s extension. Using %s",
3255 : osExt.c_str(), aosDriverNames[0]);
3256 : }
3257 3894 : const std::string osDrvName = aosDriverNames[0];
3258 1947 : aosDriverNames.Clear();
3259 1947 : aosDriverNames.AddString(osDrvName.c_str());
3260 : }
3261 : }
3262 470 : else if (EQUAL(osExt.c_str(), "gdb") &&
3263 1 : IsOnlyExpectedGDBDrivers(aosDriverNames))
3264 : {
3265 : // Do not warn about that case given that FileGDB write support
3266 : // forwards to OpenFileGDB one. And also consider GPSBabel as too
3267 : // marginal to deserve the warning.
3268 1 : aosDriverNames.Clear();
3269 1 : aosDriverNames.AddString("OpenFileGDB");
3270 : }
3271 468 : else if (aosDriverNames.size() >= 2)
3272 : {
3273 0 : if (bEmitWarning)
3274 : {
3275 0 : CPLError(CE_Warning, CPLE_AppDefined,
3276 : "Several drivers matching %s %s. Using %s",
3277 0 : osMatchingPrefix.empty() ? osExt.c_str()
3278 0 : : osMatchingPrefix.c_str(),
3279 0 : osMatchingPrefix.empty() ? "extension" : "prefix",
3280 : aosDriverNames[0]);
3281 : }
3282 0 : const std::string osDrvName = aosDriverNames[0];
3283 0 : aosDriverNames.Clear();
3284 0 : aosDriverNames.AddString(osDrvName.c_str());
3285 : }
3286 : }
3287 :
3288 2730 : if (aosDriverNames.empty() && bEmitWarning &&
3289 2730 : aosMissingDriverNames.size() == 1 && poMissingPluginDriver)
3290 : {
3291 0 : CPLError(CE_Failure, CPLE_AppDefined,
3292 : "No installed driver matching %s %s, but %s driver is "
3293 : "known. However plugin %s",
3294 0 : osMatchingPrefix.empty() ? osExt.c_str()
3295 0 : : osMatchingPrefix.c_str(),
3296 0 : osMatchingPrefix.empty() ? "extension" : "prefix",
3297 0 : poMissingPluginDriver->GetDescription(),
3298 0 : GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver)
3299 : .c_str());
3300 : }
3301 2729 : else if (aosDriverNames.empty() && bEmitWarning &&
3302 30 : aosMissingDriverNames.empty())
3303 : {
3304 827 : for (const auto &sConnectionPrefix : asKnownConnectionPrefixes)
3305 : {
3306 798 : if (STARTS_WITH_CI(pszDestDataset, sConnectionPrefix.pszPrefix))
3307 : {
3308 1 : CPLError(CE_Failure, CPLE_AppDefined,
3309 : "Filename %s starts with the connection prefix of "
3310 : "driver %s, which is not enabled in this GDAL build. "
3311 : "If that filename is really intended, explicitly "
3312 : "specify its output format.",
3313 1 : pszDestDataset, sConnectionPrefix.pszDriverName);
3314 1 : break;
3315 : }
3316 : }
3317 : }
3318 :
3319 2699 : return aosDriverNames.StealList();
3320 : }
3321 :
3322 : /************************************************************************/
3323 : /* GDALGetMessageAboutMissingPluginDriver() */
3324 : /************************************************************************/
3325 :
3326 : std::string
3327 0 : GDALGetMessageAboutMissingPluginDriver(GDALDriver *poMissingPluginDriver)
3328 : {
3329 : std::string osMsg =
3330 0 : poMissingPluginDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME");
3331 : osMsg += " is not available in your "
3332 0 : "installation.";
3333 0 : if (const char *pszInstallationMsg = poMissingPluginDriver->GetMetadataItem(
3334 0 : GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE))
3335 : {
3336 0 : osMsg += " ";
3337 0 : osMsg += pszInstallationMsg;
3338 : }
3339 :
3340 : VSIStatBuf sStat;
3341 0 : if (const char *pszGDALDriverPath =
3342 0 : CPLGetConfigOption("GDAL_DRIVER_PATH", nullptr))
3343 : {
3344 0 : if (VSIStat(pszGDALDriverPath, &sStat) != 0)
3345 : {
3346 0 : if (osMsg.back() != '.')
3347 0 : osMsg += ".";
3348 0 : osMsg += " Directory '";
3349 0 : osMsg += pszGDALDriverPath;
3350 0 : osMsg += "' pointed by GDAL_DRIVER_PATH does not exist.";
3351 : }
3352 : }
3353 : else
3354 : {
3355 0 : if (osMsg.back() != '.')
3356 0 : osMsg += ".";
3357 : #ifdef INSTALL_PLUGIN_FULL_DIR
3358 : if (VSIStat(INSTALL_PLUGIN_FULL_DIR, &sStat) != 0)
3359 : {
3360 : osMsg += " Directory '";
3361 : osMsg += INSTALL_PLUGIN_FULL_DIR;
3362 : osMsg += "' hardcoded in the GDAL library does not "
3363 : "exist and the GDAL_DRIVER_PATH "
3364 : "configuration option is not set.";
3365 : }
3366 : else
3367 : #endif
3368 : {
3369 : osMsg += " The GDAL_DRIVER_PATH configuration "
3370 0 : "option is not set.";
3371 : }
3372 : }
3373 0 : return osMsg;
3374 : }
3375 :
3376 : /************************************************************************/
3377 : /* GDALClearMemoryCaches() */
3378 : /************************************************************************/
3379 :
3380 : /**
3381 : * \brief Clear all GDAL-controlled in-memory caches.
3382 : *
3383 : * Iterates registered drivers and calls their pfnClearCaches callback if set,
3384 : * then calls VSICurlClearCache() to clear /vsicurl/ and related caches.
3385 : *
3386 : * Note that neither the global raster block cache or caches specific to open
3387 : * dataset objects are not cleared by this function (in its current implementation).
3388 : *
3389 : * Useful when remote datasets may have changed during the lifetime of a
3390 : * process.
3391 : *
3392 : * @since GDAL 3.13
3393 : */
3394 4 : void GDALClearMemoryCaches()
3395 : {
3396 4 : auto *poDM = GetGDALDriverManager();
3397 4 : if (poDM)
3398 : {
3399 912 : for (int i = 0; i < poDM->GetDriverCount(); i++)
3400 : {
3401 908 : auto *poDriver = poDM->GetDriver(i);
3402 908 : if (poDriver && poDriver->pfnClearCaches)
3403 4 : poDriver->pfnClearCaches(poDriver);
3404 : }
3405 : }
3406 4 : VSICurlClearCache();
3407 4 : }
|