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 513944 : GDALDriver::~GDALDriver()
50 :
51 : {
52 289837 : if (pfnUnloadDriver != nullptr)
53 8984 : pfnUnloadDriver(this);
54 513944 : }
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 519721 : GDALDataset *GDALDriver::Open(GDALOpenInfo *poOpenInfo, bool bSetOpenOptions)
99 : {
100 :
101 519721 : GDALDataset *poDS = nullptr;
102 519721 : pfnOpen = GetOpenCallback();
103 519721 : if (pfnOpen != nullptr)
104 : {
105 519718 : poDS = pfnOpen(poOpenInfo);
106 : }
107 3 : else if (pfnOpenWithDriverArg != nullptr)
108 : {
109 3 : poDS = pfnOpenWithDriverArg(this, poOpenInfo);
110 : }
111 :
112 519721 : if (poDS)
113 : {
114 : // Only set GDAL_OF_THREAD_SAFE if the driver itself has set it in
115 : // poDS->nOpenFlags
116 62740 : int nOpenFlags = poOpenInfo->nOpenFlags &
117 : ~(GDAL_OF_FROM_GDALOPEN | GDAL_OF_THREAD_SAFE);
118 62740 : if (poDS->nOpenFlags & GDAL_OF_THREAD_SAFE)
119 915 : nOpenFlags |= GDAL_OF_THREAD_SAFE;
120 62740 : poDS->nOpenFlags = nOpenFlags;
121 :
122 62740 : if (strlen(poDS->GetDescription()) == 0)
123 14373 : poDS->SetDescription(poOpenInfo->pszFilename);
124 :
125 62740 : if (poDS->poDriver == nullptr)
126 58773 : poDS->poDriver = this;
127 :
128 62740 : if (poDS->papszOpenOptions == nullptr && bSetOpenOptions)
129 : {
130 29 : poDS->papszOpenOptions = CSLDuplicate(poOpenInfo->papszOpenOptions);
131 : }
132 :
133 62740 : if (!(poOpenInfo->nOpenFlags & GDAL_OF_INTERNAL))
134 : {
135 50254 : 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 50248 : CPLDebug("GDAL", "GDALOpen(%s, this=%p) succeeds as %s.",
145 50248 : poOpenInfo->pszFilename, poDS, GetDescription());
146 :
147 50254 : poDS->AddToDatasetOpenList();
148 : }
149 : }
150 :
151 519721 : 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 25450 : 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 25450 : pfnCreate = GetCreateCallback();
202 25450 : 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 25449 : 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 25448 : if (CPL_UNLIKELY(GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
224 : GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr &&
225 25448 : (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 25446 : 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 25445 : 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 25426 : if (!EQUAL(GetDescription(), "MEM") &&
255 39067 : !EQUAL(GetDescription(), "Memory") &&
256 : // ogr2ogr -f PostgreSQL might reach the Delete method of the
257 : // PostgisRaster driver which is undesirable
258 13641 : !EQUAL(GetDescription(), "PostgreSQL"))
259 : {
260 13639 : QuietDelete(pszFilename);
261 : }
262 : }
263 :
264 : /* -------------------------------------------------------------------- */
265 : /* Validate creation options. */
266 : /* -------------------------------------------------------------------- */
267 25445 : if (CPLTestBool(
268 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
269 25445 : GDALValidateCreationOptions(this, papszOptions);
270 :
271 : /* -------------------------------------------------------------------- */
272 : /* Proceed with creation. */
273 : /* -------------------------------------------------------------------- */
274 50890 : CPLDebug("GDAL", "GDALDriver::Create(%s,%s,%d,%d,%d,%s,%p)",
275 25445 : GetDescription(), pszFilename, nXSize, nYSize, nBands,
276 : GDALGetDataTypeName(eType), papszOptions);
277 :
278 25445 : GDALDataset *poDS = nullptr;
279 25445 : if (pfnCreateEx != nullptr)
280 : {
281 0 : poDS = pfnCreateEx(this, pszFilename, nXSize, nYSize, nBands, eType,
282 : const_cast<char **>(papszOptions));
283 : }
284 25445 : else if (pfnCreate != nullptr)
285 : {
286 25445 : 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 25445 : if (poDS != nullptr)
296 : {
297 48290 : if (poDS->GetDescription() == nullptr ||
298 24145 : strlen(poDS->GetDescription()) == 0)
299 21464 : poDS->SetDescription(pszFilename);
300 :
301 24145 : if (poDS->poDriver == nullptr)
302 23412 : poDS->poDriver = this;
303 :
304 24145 : poDS->AddToDatasetOpenList();
305 : }
306 :
307 25445 : 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 20975 : 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 20975 : VALIDATE_POINTER1(hDriver, "GDALCreate", nullptr);
328 :
329 20975 : GDALDatasetH hDS = GDALDriver::FromHandle(hDriver)->Create(
330 : pszFilename, nXSize, nYSize, nBands, eBandType, papszOptions);
331 :
332 : #ifdef OGRAPISPY_ENABLED
333 20975 : if (nBands < 1)
334 : {
335 3937 : OGRAPISpyCreateDataSource(hDriver, pszFilename,
336 : const_cast<char **>(papszOptions), hDS);
337 : }
338 : #endif
339 :
340 20975 : 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(GDALDriver::ToHandle(this), pszOptionList,
397 : papszOptions, "creation option", 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 6231 : CPLErr GDALDriver::DefaultCopyMasks(GDALDataset *poSrcDS, GDALDataset *poDstDS,
472 : int bStrict)
473 :
474 : {
475 6231 : return DefaultCopyMasks(poSrcDS, poDstDS, bStrict, nullptr, nullptr,
476 6231 : nullptr);
477 : }
478 :
479 8301 : CPLErr GDALDriver::DefaultCopyMasks(GDALDataset *poSrcDS, GDALDataset *poDstDS,
480 : int bStrict, CSLConstList /*papszOptions*/,
481 : GDALProgressFunc pfnProgress,
482 : void *pProgressData)
483 :
484 : {
485 8301 : if (pfnProgress == nullptr)
486 6231 : pfnProgress = GDALDummyProgress;
487 :
488 8301 : int nBands = poSrcDS->GetRasterCount();
489 8301 : if (nBands == 0)
490 0 : return CE_None;
491 :
492 : /* -------------------------------------------------------------------- */
493 : /* Try to copy mask if it seems appropriate. */
494 : /* -------------------------------------------------------------------- */
495 8301 : const char *papszOptions[2] = {"COMPRESSED=YES", nullptr};
496 8301 : CPLErr eErr = CE_None;
497 :
498 8301 : int nTotalBandsWithMask = 0;
499 28659 : for (int iBand = 0; iBand < nBands; ++iBand)
500 : {
501 20358 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
502 :
503 20358 : int nMaskFlags = poSrcBand->GetMaskFlags();
504 20358 : if (!(nMaskFlags &
505 : (GMF_ALL_VALID | GMF_PER_DATASET | GMF_ALPHA | GMF_NODATA)))
506 : {
507 8 : nTotalBandsWithMask++;
508 : }
509 : }
510 :
511 8301 : int iBandWithMask = 0;
512 28659 : for (int iBand = 0; eErr == CE_None && iBand < nBands; ++iBand)
513 : {
514 20358 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
515 :
516 20358 : int nMaskFlags = poSrcBand->GetMaskFlags();
517 20358 : 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 8301 : const int nMaskFlags = poSrcDS->GetRasterBand(1)->GetMaskFlags();
549 8301 : if (eErr == CE_None &&
550 8301 : !(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 8301 : return eErr;
568 : }
569 :
570 : /************************************************************************/
571 : /* DefaultCreateCopy() */
572 : /************************************************************************/
573 :
574 1482 : GDALDataset *GDALDriver::DefaultCreateCopy(const char *pszFilename,
575 : GDALDataset *poSrcDS, int bStrict,
576 : CSLConstList papszOptions,
577 : GDALProgressFunc pfnProgress,
578 : void *pProgressData)
579 :
580 : {
581 1482 : if (pfnProgress == nullptr)
582 0 : pfnProgress = GDALDummyProgress;
583 :
584 1482 : CPLErrorReset();
585 :
586 : /* -------------------------------------------------------------------- */
587 : /* Use multidimensional raster API if available. */
588 : /* -------------------------------------------------------------------- */
589 2964 : auto poSrcGroup = poSrcDS->GetRootGroup();
590 1482 : 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 1458 : const int nXSize = poSrcDS->GetRasterXSize();
616 1458 : const int nYSize = poSrcDS->GetRasterYSize();
617 1458 : const int nBands = poSrcDS->GetRasterCount();
618 :
619 1458 : CPLDebug("GDAL", "Using default GDALDriver::CreateCopy implementation.");
620 :
621 1458 : const int nLayerCount = poSrcDS->GetLayerCount();
622 1482 : 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 1441 : if (poSrcDS->GetDriver() != nullptr &&
630 1411 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
631 1404 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr &&
632 2855 : 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 1438 : else if (poSrcDS->GetDriver() != nullptr &&
641 1408 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_RASTER) ==
642 7 : nullptr &&
643 7 : poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VECTOR) !=
644 7 : nullptr &&
645 2846 : 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 1438 : 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 1436 : char **papszCreateOptions = CSLDuplicate(papszOptions);
666 1436 : const char *const apszOptItems[] = {"NBITS", "IMAGE_STRUCTURE", "PIXELTYPE",
667 : "IMAGE_STRUCTURE", nullptr};
668 :
669 4276 : for (int iOptItem = 0; nBands > 0 && apszOptItems[iOptItem] != nullptr;
670 2840 : iOptItem += 2)
671 : {
672 : // does the source have this metadata item on the first band?
673 2840 : auto poBand = poSrcDS->GetRasterBand(1);
674 2840 : poBand->EnablePixelTypeSignedByteWarning(false);
675 5680 : const char *pszValue = poBand->GetMetadataItem(
676 2840 : apszOptItems[iOptItem], apszOptItems[iOptItem + 1]);
677 2840 : poBand->EnablePixelTypeSignedByteWarning(true);
678 :
679 2840 : if (pszValue == nullptr)
680 2838 : 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 1436 : GDALDataType eType = GDT_Unknown;
702 :
703 1436 : if (nBands > 0)
704 1420 : eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
705 : GDALDataset *poDstDS =
706 1436 : Create(pszFilename, nXSize, nYSize, nBands, eType, papszCreateOptions);
707 :
708 1436 : CSLDestroy(papszCreateOptions);
709 :
710 1436 : if (poDstDS == nullptr)
711 326 : return nullptr;
712 :
713 1110 : int nDstBands = poDstDS->GetRasterCount();
714 1110 : CPLErr eErr = CE_None;
715 1110 : 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 1110 : if (nDstBands == 0 && !bStrict)
734 4 : CPLTurnFailureIntoWarning(true);
735 :
736 1110 : GDALGeoTransform gt;
737 2095 : if (eErr == CE_None && poSrcDS->GetGeoTransform(gt) == CE_None &&
738 2095 : gt != GDALGeoTransform())
739 : {
740 983 : eErr = poDstDS->SetGeoTransform(gt);
741 983 : if (!bStrict)
742 626 : eErr = CE_None;
743 : }
744 :
745 1110 : if (eErr == CE_None)
746 : {
747 1101 : const auto poSrcSRS = poSrcDS->GetSpatialRefRasterOnly();
748 1101 : if (poSrcSRS && !poSrcSRS->IsEmpty())
749 : {
750 921 : eErr = poDstDS->SetSpatialRef(poSrcSRS);
751 921 : if (!bStrict)
752 596 : eErr = CE_None;
753 : }
754 : }
755 :
756 : /* -------------------------------------------------------------------- */
757 : /* Copy GCPs. */
758 : /* -------------------------------------------------------------------- */
759 1110 : 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 1110 : if (nDstBands == 0 && !bStrict)
768 4 : CPLTurnFailureIntoWarning(false);
769 :
770 : /* -------------------------------------------------------------------- */
771 : /* Copy metadata. */
772 : /* -------------------------------------------------------------------- */
773 1110 : DefaultCopyMetadata(poSrcDS, poDstDS, papszOptions, nullptr);
774 :
775 : /* -------------------------------------------------------------------- */
776 : /* Loop copying bands. */
777 : /* -------------------------------------------------------------------- */
778 2879 : for (int iBand = 0; eErr == CE_None && iBand < nDstBands; ++iBand)
779 : {
780 1769 : GDALRasterBand *const poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
781 1769 : GDALRasterBand *const poDstBand = poDstDS->GetRasterBand(iBand + 1);
782 :
783 : /* --------------------------------------------------------------------
784 : */
785 : /* Do we need to copy a colortable. */
786 : /* --------------------------------------------------------------------
787 : */
788 1769 : GDALColorTable *const poCT = poSrcBand->GetColorTable();
789 1769 : 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 1769 : if (!bStrict)
800 1135 : CPLTurnFailureIntoWarning(true);
801 :
802 1769 : if (strlen(poSrcBand->GetDescription()) > 0)
803 52 : poDstBand->SetDescription(poSrcBand->GetDescription());
804 :
805 1769 : if (CSLCount(poSrcBand->GetMetadata()) > 0)
806 115 : poDstBand->SetMetadata(poSrcBand->GetMetadata());
807 :
808 1769 : int bSuccess = FALSE;
809 1769 : double dfValue = poSrcBand->GetOffset(&bSuccess);
810 1769 : if (bSuccess && dfValue != 0.0)
811 5 : poDstBand->SetOffset(dfValue);
812 :
813 1769 : dfValue = poSrcBand->GetScale(&bSuccess);
814 1769 : if (bSuccess && dfValue != 1.0)
815 4 : poDstBand->SetScale(dfValue);
816 :
817 1769 : GDALCopyNoDataValue(poDstBand, poSrcBand);
818 :
819 2944 : if (poSrcBand->GetColorInterpretation() != GCI_Undefined &&
820 1175 : poSrcBand->GetColorInterpretation() !=
821 1175 : poDstBand->GetColorInterpretation())
822 947 : poDstBand->SetColorInterpretation(
823 947 : poSrcBand->GetColorInterpretation());
824 :
825 1769 : char **papszCatNames = poSrcBand->GetCategoryNames();
826 1769 : if (nullptr != papszCatNames)
827 1 : poDstBand->SetCategoryNames(papszCatNames);
828 :
829 : // Only copy RAT if it is of reasonable size to fit in memory
830 1769 : GDALRasterAttributeTable *poRAT = poSrcBand->GetDefaultRAT();
831 1771 : if (poRAT != nullptr && static_cast<GIntBig>(poRAT->GetColumnCount()) *
832 2 : poRAT->GetRowCount() <
833 : 1024 * 1024)
834 : {
835 2 : poDstBand->SetDefaultRAT(poRAT);
836 : }
837 :
838 1769 : if (!bStrict)
839 : {
840 1135 : CPLTurnFailureIntoWarning(false);
841 : }
842 : else
843 : {
844 634 : eErr = CPLGetLastErrorType();
845 : }
846 : }
847 :
848 : /* -------------------------------------------------------------------- */
849 : /* Copy image data. */
850 : /* -------------------------------------------------------------------- */
851 1110 : if (eErr == CE_None && nDstBands > 0)
852 : {
853 1066 : const char *const apszCopyRasterOptionsSkipHoles[] = {"SKIP_HOLES=YES",
854 : nullptr};
855 1066 : const bool bSkipHoles = CPLTestBool(
856 : CSLFetchNameValueDef(papszOptions, "SKIP_HOLES", "FALSE"));
857 1066 : eErr = GDALDatasetCopyWholeRaster(
858 : poSrcDS, poDstDS,
859 : bSkipHoles ? apszCopyRasterOptionsSkipHoles : nullptr, pfnProgress,
860 : pProgressData);
861 : }
862 :
863 : /* -------------------------------------------------------------------- */
864 : /* Should we copy some masks over? */
865 : /* -------------------------------------------------------------------- */
866 1110 : if (eErr == CE_None && nDstBands > 0)
867 1048 : eErr = DefaultCopyMasks(poSrcDS, poDstDS, eErr);
868 :
869 : /* -------------------------------------------------------------------- */
870 : /* Copy vector layers */
871 : /* -------------------------------------------------------------------- */
872 1110 : if (eErr == CE_None)
873 : {
874 1061 : 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 1110 : 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 1061 : CPLErrorReset();
904 : }
905 :
906 1061 : return poDstDS;
907 : }
908 :
909 : /************************************************************************/
910 : /* DefaultCopyMetadata() */
911 : /************************************************************************/
912 :
913 5439 : void GDALDriver::DefaultCopyMetadata(GDALDataset *poSrcDS, GDALDataset *poDstDS,
914 : CSLConstList papszOptions,
915 : CSLConstList papszExcludedDomains)
916 : {
917 : const char *pszCopySrcMDD =
918 5439 : CSLFetchNameValueDef(papszOptions, "COPY_SRC_MDD", "AUTO");
919 5439 : char **papszSrcMDD = CSLFetchNameValueMultiple(papszOptions, "SRC_MDD");
920 5439 : if (EQUAL(pszCopySrcMDD, "AUTO") || CPLTestBool(pszCopySrcMDD) ||
921 : papszSrcMDD)
922 : {
923 4 : if ((!papszSrcMDD || CSLFindString(papszSrcMDD, "") >= 0 ||
924 2 : CSLFindString(papszSrcMDD, "_DEFAULT_") >= 0) &&
925 10727 : CSLFindString(papszExcludedDomains, "") < 0 &&
926 5286 : CSLFindString(papszExcludedDomains, "_DEFAULT_") < 0)
927 : {
928 5286 : if (poSrcDS->GetMetadata() != nullptr)
929 874 : 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 5437 : constexpr const char *apszDefaultDomains[] = {
937 : "RPC", "xml:XMP", "json:ISIS3", "json:VICAR"};
938 27185 : for (const char *pszDomain : apszDefaultDomains)
939 : {
940 43480 : if ((!papszSrcMDD || CSLFindString(papszSrcMDD, pszDomain) >= 0) &&
941 21732 : CSLFindString(papszExcludedDomains, pszDomain) < 0)
942 : {
943 21732 : CSLConstList papszMD = poSrcDS->GetMetadata(pszDomain);
944 21732 : if (papszMD)
945 5 : poDstDS->SetMetadata(papszMD, pszDomain);
946 : }
947 : }
948 :
949 5437 : 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 5439 : CSLDestroy(papszSrcMDD);
999 5439 : }
1000 :
1001 : /************************************************************************/
1002 : /* QuietDeleteForCreateCopy() */
1003 : /************************************************************************/
1004 :
1005 12222 : 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 23808 : if (!EQUAL(GetDescription(), "MEM") && !EQUAL(GetDescription(), "Memory") &&
1014 : // VRT with empty name is a un-materialized dataset
1015 11586 : !(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 34696 : !EQUAL(GetDescription(), "GeoRaster") &&
1019 10888 : !EQUAL(GetDescription(), "PostGISRaster"))
1020 : {
1021 : /* --------------------------------------------------------------------
1022 : */
1023 : /* Establish list of files of output dataset if it already
1024 : * exists. */
1025 : /* --------------------------------------------------------------------
1026 : */
1027 21740 : std::set<std::string> oSetExistingDestFiles;
1028 : {
1029 21740 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1030 10870 : const char *const apszAllowedDrivers[] = {GetDescription(),
1031 10870 : nullptr};
1032 : auto poExistingOutputDS =
1033 : std::unique_ptr<GDALDataset>(GDALDataset::Open(
1034 21740 : pszFilename, GDAL_OF_RASTER, apszAllowedDrivers));
1035 10870 : 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 21740 : std::set<std::string> oSetExistingDestFilesFoundInSource;
1053 10870 : 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 10870 : 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 10870 : QuietDelete(pszFilename);
1098 : }
1099 :
1100 12222 : 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 11645 : GDALDataset *GDALDriver::CreateCopy(const char *pszFilename,
1189 : GDALDataset *poSrcDS, int bStrict,
1190 : CSLConstList papszOptions,
1191 : GDALProgressFunc pfnProgress,
1192 : void *pProgressData)
1193 :
1194 : {
1195 11645 : if (pfnProgress == nullptr)
1196 8769 : pfnProgress = GDALDummyProgress;
1197 :
1198 11645 : 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 11645 : char **papszOptionsToDelete = nullptr;
1205 : const char *srcInterleave =
1206 11645 : poSrcDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
1207 6903 : if (nBandCount > 1 && srcInterleave != nullptr &&
1208 25057 : CSLFetchNameValue(papszOptions, "INTERLEAVE") == nullptr &&
1209 6509 : EQUAL(CSLFetchNameValueDef(papszOptions, "COMPRESS", "NONE"), "NONE"))
1210 : {
1211 :
1212 : // look for INTERLEAVE values of the driver
1213 6326 : char **interleavesCSL = nullptr;
1214 : const char *pszOptionList =
1215 6326 : this->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
1216 : CPLXMLNode *xmlNode =
1217 6326 : !pszOptionList ? nullptr : CPLParseXMLString(pszOptionList);
1218 6326 : for (CPLXMLNode *child = !xmlNode ? nullptr : xmlNode->psChild;
1219 132394 : child != nullptr; child = child->psNext)
1220 : {
1221 126068 : if ((child->eType == CXT_Element) &&
1222 126068 : EQUAL(child->pszValue, "Option"))
1223 : {
1224 : const char *nameAttribute =
1225 126068 : CPLGetXMLValue(child, "name", nullptr);
1226 126068 : const bool isInterleaveAttribute =
1227 126068 : nameAttribute && EQUAL(nameAttribute, "INTERLEAVE");
1228 126068 : if (isInterleaveAttribute)
1229 : {
1230 1188 : for (CPLXMLNode *optionChild = child->psChild;
1231 7196 : optionChild != nullptr;
1232 6008 : optionChild = optionChild->psNext)
1233 : {
1234 6008 : if ((optionChild->eType == CXT_Element) &&
1235 2429 : EQUAL(optionChild->pszValue, "Value"))
1236 : {
1237 2429 : CPLXMLNode *optionChildValue = optionChild->psChild;
1238 2429 : if (optionChildValue &&
1239 2429 : (optionChildValue->eType == CXT_Text))
1240 : {
1241 2429 : interleavesCSL = CSLAddString(
1242 2429 : interleavesCSL, optionChildValue->pszValue);
1243 : }
1244 : }
1245 : }
1246 : }
1247 : }
1248 : }
1249 6326 : CPLDestroyXMLNode(xmlNode);
1250 :
1251 : const char *dstInterleaveBand =
1252 11488 : (CSLFindString(interleavesCSL, "BAND") >= 0) ? "BAND"
1253 5162 : : (CSLFindString(interleavesCSL, "BSQ") >= 0) ? "BSQ"
1254 6326 : : nullptr;
1255 : const char *dstInterleaveLine =
1256 12652 : (CSLFindString(interleavesCSL, "LINE") >= 0) ? "LINE"
1257 6326 : : (CSLFindString(interleavesCSL, "BIL") >= 0) ? "BIL"
1258 6326 : : nullptr;
1259 : const char *dstInterleavePixel =
1260 11488 : (CSLFindString(interleavesCSL, "PIXEL") >= 0) ? "PIXEL"
1261 5162 : : (CSLFindString(interleavesCSL, "BIP") >= 0) ? "BIP"
1262 6326 : : nullptr;
1263 6326 : const char *dstInterleave =
1264 6630 : EQUAL(srcInterleave, "BAND") ? dstInterleaveBand
1265 606 : : EQUAL(srcInterleave, "LINE") ? dstInterleaveLine
1266 302 : : EQUAL(srcInterleave, "PIXEL") ? dstInterleavePixel
1267 : : nullptr;
1268 6326 : CSLDestroy(interleavesCSL);
1269 :
1270 6326 : if (dstInterleave != nullptr)
1271 : {
1272 1188 : papszOptionsToDelete = CSLDuplicate(papszOptions);
1273 1188 : papszOptionsToDelete = CSLSetNameValue(papszOptionsToDelete,
1274 : "INTERLEAVE", dstInterleave);
1275 1188 : papszOptionsToDelete = CSLSetNameValue(
1276 : papszOptionsToDelete, "@INTERLEAVE_ADDED_AUTOMATICALLY", "YES");
1277 1188 : 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 11645 : 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 23265 : if (!bAppendSubdataset &&
1292 11620 : CPLFetchBool(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY", true))
1293 : {
1294 8929 : QuietDeleteForCreateCopy(pszFilename, poSrcDS);
1295 : }
1296 :
1297 : int iIdxQuietDeleteOnCreateCopy =
1298 11645 : CSLPartialFindString(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY=");
1299 11645 : if (iIdxQuietDeleteOnCreateCopy >= 0)
1300 : {
1301 2691 : if (papszOptionsToDelete == nullptr)
1302 1637 : papszOptionsToDelete = CSLDuplicate(papszOptions);
1303 2691 : papszOptionsToDelete = CSLRemoveStrings(
1304 : papszOptionsToDelete, iIdxQuietDeleteOnCreateCopy, 1, nullptr);
1305 2691 : 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 11645 : CSLPartialFindString(papszOptions, "_INTERNAL_DATASET=");
1314 11645 : bool bInternalDataset = false;
1315 11645 : 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 11645 : if (CPLTestBool(
1330 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
1331 : {
1332 23290 : auto poSrcGroup = poSrcDS->GetRootGroup();
1333 11645 : 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 11532 : GDALValidateCreationOptions(this, papszOptions);
1346 : }
1347 : }
1348 :
1349 : /* -------------------------------------------------------------------- */
1350 : /* Advise the source raster that we are going to read it completely */
1351 : /* -------------------------------------------------------------------- */
1352 :
1353 11645 : const int nXSize = poSrcDS->GetRasterXSize();
1354 11645 : const int nYSize = poSrcDS->GetRasterYSize();
1355 11645 : GDALDataType eDT = GDT_Unknown;
1356 11645 : if (nBandCount > 0)
1357 : {
1358 11409 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
1359 11409 : if (poSrcBand)
1360 11409 : eDT = poSrcBand->GetRasterDataType();
1361 : }
1362 11645 : poSrcDS->AdviseRead(0, 0, nXSize, nYSize, nXSize, nYSize, eDT, nBandCount,
1363 11645 : 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 11645 : GDALDataset *poDstDS = nullptr;
1371 11645 : auto l_pfnCreateCopy = GetCreateCopyCallback();
1372 22118 : if (l_pfnCreateCopy != nullptr &&
1373 10473 : !CPLTestBool(CPLGetConfigOption("GDAL_DEFAULT_CREATE_COPY", "NO")))
1374 : {
1375 10473 : poDstDS = l_pfnCreateCopy(pszFilename, poSrcDS, bStrict,
1376 : const_cast<char **>(papszOptions),
1377 : pfnProgress, pProgressData);
1378 10473 : if (poDstDS != nullptr)
1379 : {
1380 18428 : if (poDstDS->GetDescription() == nullptr ||
1381 9214 : strlen(poDstDS->GetDescription()) == 0)
1382 445 : poDstDS->SetDescription(pszFilename);
1383 :
1384 9214 : if (poDstDS->poDriver == nullptr)
1385 8175 : poDstDS->poDriver = this;
1386 :
1387 9214 : if (!bInternalDataset)
1388 5048 : poDstDS->AddToDatasetOpenList();
1389 : }
1390 : }
1391 : else
1392 : {
1393 1172 : poDstDS = DefaultCreateCopy(pszFilename, poSrcDS, bStrict, papszOptions,
1394 : pfnProgress, pProgressData);
1395 : }
1396 :
1397 11645 : CSLDestroy(papszOptionsToDelete);
1398 11645 : 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 6794 : 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 6794 : VALIDATE_POINTER1(hDriver, "GDALCreateCopy", nullptr);
1420 6794 : VALIDATE_POINTER1(hSrcDS, "GDALCreateCopy", nullptr);
1421 :
1422 6794 : return GDALDriver::FromHandle(hDriver)->CreateCopy(
1423 : pszFilename, GDALDataset::FromHandle(hSrcDS), bStrict, papszOptions,
1424 6794 : 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 960 : bool GDALDriver::CanVectorTranslateFrom(
1448 : const char *pszDestName, GDALDataset *poSourceDS,
1449 : CSLConstList papszVectorTranslateArguments, char ***ppapszFailureReasons)
1450 :
1451 : {
1452 960 : if (ppapszFailureReasons)
1453 : {
1454 0 : *ppapszFailureReasons = nullptr;
1455 : }
1456 :
1457 960 : if (!pfnCanVectorTranslateFrom)
1458 : {
1459 954 : if (ppapszFailureReasons)
1460 : {
1461 0 : *ppapszFailureReasons = CSLAddString(
1462 : nullptr,
1463 : "CanVectorTranslateFrom() not implemented for this driver");
1464 : }
1465 954 : 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 : /************************************************************************/
1485 : /* HasOpenOption() */
1486 : /************************************************************************/
1487 :
1488 193 : bool GDALDriver::HasOpenOption(const char *pszOpenOptionName) const
1489 : {
1490 193 : if (pszOpenOptionName == nullptr)
1491 0 : return false;
1492 :
1493 : // Const cast is safe here since we are only reading the metadata
1494 386 : auto pszOOMd{const_cast<GDALDriver *>(this)->GetMetadataItem(
1495 193 : GDAL_DMD_OPENOPTIONLIST)};
1496 193 : if (pszOOMd == nullptr)
1497 74 : return false;
1498 :
1499 238 : const CPLXMLTreeCloser oXml{CPLParseXMLString(pszOOMd)};
1500 1222 : for (CPLXMLNode *option = oXml->psChild; option != nullptr;
1501 1103 : option = option->psNext)
1502 : {
1503 1104 : if (EQUAL(CPLGetXMLValue(CPLGetXMLNode(option, "name"), nullptr, ""),
1504 : pszOpenOptionName))
1505 1 : return true;
1506 : }
1507 118 : return false;
1508 : }
1509 :
1510 : /************************************************************************/
1511 : /* HasLayerCreationOption() */
1512 : /************************************************************************/
1513 :
1514 7 : bool GDALDriver::HasLayerCreationOption(const char *pszOptionName) const
1515 : {
1516 7 : if (pszOptionName == nullptr)
1517 0 : return false;
1518 :
1519 : // Const cast is safe here since we are only reading the metadata
1520 14 : auto pszXML{const_cast<GDALDriver *>(this)->GetMetadataItem(
1521 7 : GDAL_DS_LAYER_CREATIONOPTIONLIST)};
1522 7 : if (pszXML == nullptr)
1523 0 : return false;
1524 :
1525 14 : const CPLXMLTreeCloser oXml{CPLParseXMLString(pszXML)};
1526 49 : for (CPLXMLNode *option = oXml->psChild; option != nullptr;
1527 42 : option = option->psNext)
1528 : {
1529 49 : if (EQUAL(CPLGetXMLValue(CPLGetXMLNode(option, "name"), nullptr, ""),
1530 : pszOptionName))
1531 7 : return true;
1532 : }
1533 0 : return false;
1534 : }
1535 :
1536 : /************************************************************************/
1537 : /* VectorTranslateFrom() */
1538 : /************************************************************************/
1539 :
1540 : /** Create a copy of a vector dataset, using the arguments passed to
1541 : * GDALVectorTranslate() stored in papszVectorTranslateArguments.
1542 : *
1543 : * This may be implemented by some drivers that can convert from an existing
1544 : * dataset in an optimized way.
1545 : *
1546 : * This is for example used by the PMTiles to convert from MBTiles.
1547 : *
1548 : * @param pszDestName Target dataset name
1549 : * @param poSourceDS Source dataset
1550 : * @param papszVectorTranslateArguments Non-positional arguments passed to
1551 : * GDALVectorTranslate() (may be nullptr)
1552 : * @param pfnProgress a function to be used to report progress of the copy.
1553 : * @param pProgressData application data passed into progress function.
1554 : * @return a new dataset in case of success, or nullptr in case of error.
1555 : * @since GDAL 3.8
1556 : */
1557 4 : GDALDataset *GDALDriver::VectorTranslateFrom(
1558 : const char *pszDestName, GDALDataset *poSourceDS,
1559 : CSLConstList papszVectorTranslateArguments, GDALProgressFunc pfnProgress,
1560 : void *pProgressData)
1561 :
1562 : {
1563 4 : if (!pfnVectorTranslateFrom)
1564 : {
1565 0 : CPLError(CE_Failure, CPLE_AppDefined,
1566 : "VectorTranslateFrom() not implemented for this driver");
1567 0 : return nullptr;
1568 : }
1569 :
1570 4 : return pfnVectorTranslateFrom(pszDestName, poSourceDS,
1571 : papszVectorTranslateArguments, pfnProgress,
1572 4 : pProgressData);
1573 : }
1574 :
1575 : /************************************************************************/
1576 : /* QuietDelete() */
1577 : /************************************************************************/
1578 :
1579 : /**
1580 : * \brief Delete dataset if found.
1581 : *
1582 : * This is a helper method primarily used by Create() and
1583 : * CreateCopy() to predelete any dataset of the name soon to be
1584 : * created. It will attempt to delete the named dataset if
1585 : * one is found, otherwise it does nothing. An error is only
1586 : * returned if the dataset is found but the delete fails.
1587 : *
1588 : * This is a static method and it doesn't matter what driver instance
1589 : * it is invoked on. It will attempt to discover the correct driver
1590 : * using Identify().
1591 : *
1592 : * @param pszName the dataset name to try and delete.
1593 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
1594 : * terminated list of strings with the driver short names that must be
1595 : * considered. (Note: implemented only starting with GDAL 3.4.1)
1596 : * @return CE_None if the dataset does not exist, or is deleted without issues.
1597 : */
1598 :
1599 24509 : CPLErr GDALDriver::QuietDelete(const char *pszName,
1600 : CSLConstList papszAllowedDrivers)
1601 :
1602 : {
1603 : VSIStatBufL sStat;
1604 : const bool bExists =
1605 24509 : VSIStatExL(pszName, &sStat,
1606 24509 : VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0;
1607 :
1608 : #ifdef S_ISFIFO
1609 24509 : if (bExists && S_ISFIFO(sStat.st_mode))
1610 0 : return CE_None;
1611 : #endif
1612 :
1613 24509 : GDALDriver *poDriver = nullptr;
1614 24509 : if (papszAllowedDrivers)
1615 : {
1616 0 : GDALOpenInfo oOpenInfo(pszName, GDAL_OF_ALL);
1617 0 : for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
1618 : {
1619 : GDALDriver *poTmpDriver =
1620 0 : GDALDriver::FromHandle(GDALGetDriverByName(pszDriverName));
1621 0 : if (poTmpDriver)
1622 : {
1623 : const bool bIdentifyRes =
1624 0 : poTmpDriver->pfnIdentifyEx
1625 0 : ? poTmpDriver->pfnIdentifyEx(poTmpDriver, &oOpenInfo) >
1626 : 0
1627 0 : : poTmpDriver->pfnIdentify &&
1628 0 : poTmpDriver->pfnIdentify(&oOpenInfo) > 0;
1629 0 : if (bIdentifyRes)
1630 : {
1631 0 : poDriver = poTmpDriver;
1632 0 : break;
1633 : }
1634 : }
1635 : }
1636 : }
1637 : else
1638 : {
1639 49018 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1640 24509 : poDriver = GDALDriver::FromHandle(GDALIdentifyDriver(pszName, nullptr));
1641 : }
1642 :
1643 24509 : if (poDriver == nullptr)
1644 23626 : return CE_None;
1645 :
1646 924 : if (bExists && VSI_ISDIR(sStat.st_mode) &&
1647 41 : (EQUAL(poDriver->GetDescription(), "MapInfo File") ||
1648 41 : EQUAL(poDriver->GetDescription(), "ESRI Shapefile")))
1649 : {
1650 : // Those drivers are a bit special and handle directories as container
1651 : // of layers, but it is quite common to found other files too, and
1652 : // removing the directory might be non-desirable.
1653 41 : return CE_None;
1654 : }
1655 :
1656 842 : CPLDebug("GDAL", "QuietDelete(%s) invoking Delete()", pszName);
1657 :
1658 842 : poDriver->pfnDelete = poDriver->GetDeleteCallback();
1659 880 : const bool bQuiet = !bExists && poDriver->pfnDelete == nullptr &&
1660 38 : poDriver->pfnDeleteDataSource == nullptr;
1661 842 : if (bQuiet)
1662 : {
1663 76 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1664 38 : return poDriver->Delete(pszName);
1665 : }
1666 : else
1667 : {
1668 804 : return poDriver->Delete(pszName);
1669 : }
1670 : }
1671 :
1672 : /************************************************************************/
1673 : /* Delete() */
1674 : /************************************************************************/
1675 :
1676 : /**
1677 : * \brief Delete named dataset.
1678 : *
1679 : * The driver will attempt to delete the named dataset in a driver specific
1680 : * fashion. Full featured drivers will delete all associated files,
1681 : * database objects, or whatever is appropriate. The default behavior when
1682 : * no driver specific behavior is provided is to attempt to delete all the
1683 : * files that are returned by GDALGetFileList() on the dataset handle.
1684 : *
1685 : * It is unwise to have open dataset handles on this dataset when it is
1686 : * deleted.
1687 : *
1688 : * Equivalent of the C function GDALDeleteDataset().
1689 : *
1690 : * @param pszFilename name of dataset to delete.
1691 : *
1692 : * @return CE_None on success, or CE_Failure if the operation fails.
1693 : */
1694 :
1695 4399 : CPLErr GDALDriver::Delete(const char *pszFilename)
1696 :
1697 : {
1698 4399 : pfnDelete = GetDeleteCallback();
1699 4399 : if (pfnDelete != nullptr)
1700 1046 : return pfnDelete(pszFilename);
1701 3353 : else if (pfnDeleteDataSource != nullptr)
1702 0 : return pfnDeleteDataSource(this, pszFilename);
1703 :
1704 : /* -------------------------------------------------------------------- */
1705 : /* Collect file list. */
1706 : /* -------------------------------------------------------------------- */
1707 3353 : GDALDatasetH hDS = GDALOpenEx(pszFilename, GDAL_OF_VERBOSE_ERROR, nullptr,
1708 : nullptr, nullptr);
1709 :
1710 3353 : if (hDS == nullptr)
1711 : {
1712 237 : if (CPLGetLastErrorNo() == 0)
1713 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1714 : "Unable to open %s to obtain file list.", pszFilename);
1715 :
1716 237 : return CE_Failure;
1717 : }
1718 :
1719 6232 : const CPLStringList aosFileList(GDALGetFileList(hDS));
1720 :
1721 3116 : GDALClose(hDS);
1722 3116 : hDS = nullptr;
1723 :
1724 3116 : if (aosFileList.empty())
1725 : {
1726 0 : CPLError(CE_Failure, CPLE_NotSupported,
1727 : "Unable to determine files associated with %s, "
1728 : "delete fails.",
1729 : pszFilename);
1730 0 : return CE_Failure;
1731 : }
1732 :
1733 3116 : return Delete(nullptr, aosFileList.List());
1734 : }
1735 :
1736 : /************************************************************************/
1737 : /* Delete() */
1738 : /************************************************************************/
1739 :
1740 : /**
1741 : * \brief Delete a currently opened dataset
1742 : *
1743 : * The driver will attempt to delete the passed dataset in a driver specific
1744 : * fashion. Full featured drivers will delete all associated files,
1745 : * database objects, or whatever is appropriate. The default behavior when
1746 : * no driver specific behavior is provided is to attempt to delete all the
1747 : * files that are returned by GDALGetFileList() on the dataset handle.
1748 : *
1749 : * Note that this will generally not work on Windows systems that don't accept
1750 : * deleting opened files.
1751 : *
1752 : * At least one of poDS or papszFileList must not be NULL
1753 : *
1754 : * @param poDS dataset to delete, or NULL
1755 : * @param papszFileList File list to delete, typically obtained with
1756 : * poDS->GetFileList(), or NULL
1757 : *
1758 : * @return CE_None on success, or CE_Failure if the operation fails.
1759 : *
1760 : * @since 3.12
1761 : */
1762 :
1763 3128 : CPLErr GDALDriver::Delete(GDALDataset *poDS, CSLConstList papszFileList)
1764 :
1765 : {
1766 3128 : if (poDS)
1767 : {
1768 11 : pfnDelete = GetDeleteCallback();
1769 11 : if (pfnDelete != nullptr)
1770 7 : return pfnDelete(poDS->GetDescription());
1771 4 : else if (pfnDeleteDataSource != nullptr)
1772 0 : return pfnDeleteDataSource(this, poDS->GetDescription());
1773 : }
1774 :
1775 : /* -------------------------------------------------------------------- */
1776 : /* Delete all files. */
1777 : /* -------------------------------------------------------------------- */
1778 3121 : CPLErr eErr = CE_None;
1779 6897 : for (int i = 0; papszFileList && papszFileList[i]; ++i)
1780 : {
1781 3776 : if (VSIUnlink(papszFileList[i]) != 0)
1782 : {
1783 4 : CPLError(CE_Failure, CPLE_AppDefined, "Deleting %s failed:\n%s",
1784 2 : papszFileList[i], VSIStrerror(errno));
1785 2 : eErr = CE_Failure;
1786 : }
1787 : }
1788 :
1789 3121 : return eErr;
1790 : }
1791 :
1792 : /************************************************************************/
1793 : /* GDALDeleteDataset() */
1794 : /************************************************************************/
1795 :
1796 : /**
1797 : * \brief Delete named dataset.
1798 : *
1799 : * @see GDALDriver::Delete()
1800 : */
1801 :
1802 2391 : CPLErr CPL_STDCALL GDALDeleteDataset(GDALDriverH hDriver,
1803 : const char *pszFilename)
1804 :
1805 : {
1806 2391 : if (hDriver == nullptr)
1807 10 : hDriver = GDALIdentifyDriver(pszFilename, nullptr);
1808 :
1809 2391 : if (hDriver == nullptr)
1810 : {
1811 1 : CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
1812 : pszFilename);
1813 1 : return CE_Failure;
1814 : }
1815 :
1816 : #ifdef OGRAPISPY_ENABLED
1817 2390 : if (GDALGetMetadataItem(hDriver, GDAL_DCAP_VECTOR, nullptr))
1818 : {
1819 453 : OGRAPISpyDeleteDataSource(hDriver, pszFilename);
1820 : }
1821 : #endif
1822 :
1823 2390 : return GDALDriver::FromHandle(hDriver)->Delete(pszFilename);
1824 : }
1825 :
1826 : /************************************************************************/
1827 : /* DefaultRename() */
1828 : /* */
1829 : /* The generic implementation based on the file list used when */
1830 : /* there is no format specific implementation. */
1831 : /************************************************************************/
1832 :
1833 : //! @cond Doxygen_Suppress
1834 175 : CPLErr GDALDriver::DefaultRename(const char *pszNewName, const char *pszOldName)
1835 :
1836 : {
1837 : /* -------------------------------------------------------------------- */
1838 : /* Collect file list. */
1839 : /* -------------------------------------------------------------------- */
1840 : auto poDS = std::unique_ptr<GDALDataset>(
1841 : GDALDataset::Open(pszOldName, GDAL_OF_ALL | GDAL_OF_VERBOSE_ERROR,
1842 350 : nullptr, nullptr, nullptr));
1843 :
1844 175 : if (!poDS)
1845 : {
1846 0 : if (CPLGetLastErrorNo() == 0)
1847 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1848 : "Unable to open %s to obtain file list.", pszOldName);
1849 :
1850 0 : return CE_Failure;
1851 : }
1852 :
1853 350 : const CPLStringList aosFileList(poDS->GetFileList());
1854 :
1855 175 : poDS.reset();
1856 :
1857 175 : if (aosFileList.empty())
1858 : {
1859 0 : CPLError(CE_Failure, CPLE_NotSupported,
1860 : "Unable to determine files associated with %s,\n"
1861 : "rename fails.",
1862 : pszOldName);
1863 :
1864 0 : return CE_Failure;
1865 : }
1866 :
1867 : /* -------------------------------------------------------------------- */
1868 : /* Produce a list of new filenames that correspond to the old */
1869 : /* names. */
1870 : /* -------------------------------------------------------------------- */
1871 175 : CPLErr eErr = CE_None;
1872 : const CPLStringList aosNewFileList(
1873 350 : CPLCorrespondingPaths(pszOldName, pszNewName, aosFileList.List()));
1874 :
1875 175 : if (aosNewFileList.empty())
1876 0 : return CE_Failure;
1877 :
1878 : // Guaranteed by CPLCorrespondingPaths()
1879 175 : CPLAssert(aosNewFileList.size() == aosFileList.size());
1880 :
1881 : VSIStatBufL sStatBuf;
1882 177 : if (VSIStatL(pszOldName, &sStatBuf) == 0 && VSI_ISDIR(sStatBuf.st_mode) &&
1883 2 : VSIStatL(pszNewName, &sStatBuf) != 0)
1884 : {
1885 2 : if (VSIMkdirRecursive(pszNewName, 0755) != 0)
1886 : {
1887 1 : CPLError(CE_Failure, CPLE_AppDefined,
1888 : "Cannot create directory '%s'", pszNewName);
1889 1 : return CE_Failure;
1890 : }
1891 : }
1892 :
1893 358 : for (int i = 0; i < aosFileList.size(); ++i)
1894 : {
1895 184 : if (CPLMoveFile(aosNewFileList[i], aosFileList[i]) != 0)
1896 : {
1897 : // Above method will have emitted an error in case of failure.
1898 0 : eErr = CE_Failure;
1899 : // Try to put the ones we moved back.
1900 0 : for (--i; i >= 0; i--)
1901 : {
1902 : // Nothing we can do if the moving back doesn't work...
1903 0 : CPL_IGNORE_RET_VAL(
1904 0 : CPLMoveFile(aosFileList[i], aosNewFileList[i]));
1905 : }
1906 0 : break;
1907 : }
1908 : }
1909 :
1910 174 : return eErr;
1911 : }
1912 :
1913 : //! @endcond
1914 :
1915 : /************************************************************************/
1916 : /* Rename() */
1917 : /************************************************************************/
1918 :
1919 : /**
1920 : * \brief Rename a dataset.
1921 : *
1922 : * Rename a dataset. This may including moving the dataset to a new directory
1923 : * or even a new filesystem.
1924 : *
1925 : * It is unwise to have open dataset handles on this dataset when it is
1926 : * being renamed.
1927 : *
1928 : * Equivalent of the C function GDALRenameDataset().
1929 : *
1930 : * @param pszNewName new name for the dataset.
1931 : * @param pszOldName old name for the dataset.
1932 : *
1933 : * @return CE_None on success, or CE_Failure if the operation fails.
1934 : */
1935 :
1936 177 : CPLErr GDALDriver::Rename(const char *pszNewName, const char *pszOldName)
1937 :
1938 : {
1939 177 : pfnRename = GetRenameCallback();
1940 177 : if (pfnRename != nullptr)
1941 3 : return pfnRename(pszNewName, pszOldName);
1942 :
1943 174 : return DefaultRename(pszNewName, pszOldName);
1944 : }
1945 :
1946 : /************************************************************************/
1947 : /* GDALRenameDataset() */
1948 : /************************************************************************/
1949 :
1950 : /**
1951 : * \brief Rename a dataset.
1952 : *
1953 : * @see GDALDriver::Rename()
1954 : */
1955 :
1956 178 : CPLErr CPL_STDCALL GDALRenameDataset(GDALDriverH hDriver,
1957 : const char *pszNewName,
1958 : const char *pszOldName)
1959 :
1960 : {
1961 178 : if (hDriver == nullptr)
1962 5 : hDriver = GDALIdentifyDriver(pszOldName, nullptr);
1963 :
1964 178 : if (hDriver == nullptr)
1965 : {
1966 1 : CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
1967 : pszOldName);
1968 1 : return CE_Failure;
1969 : }
1970 :
1971 177 : return GDALDriver::FromHandle(hDriver)->Rename(pszNewName, pszOldName);
1972 : }
1973 :
1974 : /************************************************************************/
1975 : /* DefaultCopyFiles() */
1976 : /* */
1977 : /* The default implementation based on file lists used when */
1978 : /* there is no format specific implementation. */
1979 : /************************************************************************/
1980 :
1981 : //! @cond Doxygen_Suppress
1982 12 : CPLErr GDALDriver::DefaultCopyFiles(const char *pszNewName,
1983 : const char *pszOldName)
1984 :
1985 : {
1986 : /* -------------------------------------------------------------------- */
1987 : /* Collect file list. */
1988 : /* -------------------------------------------------------------------- */
1989 : auto poDS = std::unique_ptr<GDALDataset>(
1990 : GDALDataset::Open(pszOldName, GDAL_OF_ALL | GDAL_OF_VERBOSE_ERROR,
1991 24 : nullptr, nullptr, nullptr));
1992 :
1993 12 : if (!poDS)
1994 : {
1995 0 : if (CPLGetLastErrorNo() == 0)
1996 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1997 : "Unable to open %s to obtain file list.", pszOldName);
1998 :
1999 0 : return CE_Failure;
2000 : }
2001 :
2002 24 : const CPLStringList aosFileList(poDS->GetFileList());
2003 :
2004 12 : poDS.reset();
2005 :
2006 12 : if (aosFileList.empty())
2007 : {
2008 0 : CPLError(CE_Failure, CPLE_NotSupported,
2009 : "Unable to determine files associated with %s,\n"
2010 : "copy fails.",
2011 : pszOldName);
2012 :
2013 0 : return CE_Failure;
2014 : }
2015 :
2016 : /* -------------------------------------------------------------------- */
2017 : /* Produce a list of new filenames that correspond to the old */
2018 : /* names. */
2019 : /* -------------------------------------------------------------------- */
2020 12 : CPLErr eErr = CE_None;
2021 : const CPLStringList aosNewFileList(
2022 24 : CPLCorrespondingPaths(pszOldName, pszNewName, aosFileList.List()));
2023 :
2024 12 : if (aosNewFileList.empty())
2025 0 : return CE_Failure;
2026 :
2027 : // Guaranteed by CPLCorrespondingPaths()
2028 12 : CPLAssert(aosNewFileList.size() == aosFileList.size());
2029 :
2030 : VSIStatBufL sStatBuf;
2031 14 : if (VSIStatL(pszOldName, &sStatBuf) == 0 && VSI_ISDIR(sStatBuf.st_mode) &&
2032 2 : VSIStatL(pszNewName, &sStatBuf) != 0)
2033 : {
2034 2 : if (VSIMkdirRecursive(pszNewName, 0755) != 0)
2035 : {
2036 1 : CPLError(CE_Failure, CPLE_AppDefined,
2037 : "Cannot create directory '%s'", pszNewName);
2038 1 : return CE_Failure;
2039 : }
2040 : }
2041 :
2042 33 : for (int i = 0; i < aosFileList.size(); ++i)
2043 : {
2044 22 : if (CPLCopyFile(aosNewFileList[i], aosFileList[i]) != 0)
2045 : {
2046 : // Above method will have emitted an error in case of failure.
2047 0 : eErr = CE_Failure;
2048 : // Try to put the ones we moved back.
2049 0 : for (--i; i >= 0; --i)
2050 : {
2051 0 : if (VSIUnlink(aosNewFileList[i]) != 0)
2052 : {
2053 0 : CPLError(CE_Warning, CPLE_AppDefined, "Cannot delete '%s'",
2054 : aosNewFileList[i]);
2055 : }
2056 : }
2057 0 : break;
2058 : }
2059 : }
2060 :
2061 11 : return eErr;
2062 : }
2063 :
2064 : //! @endcond
2065 :
2066 : /************************************************************************/
2067 : /* CopyFiles() */
2068 : /************************************************************************/
2069 :
2070 : /**
2071 : * \brief Copy the files of a dataset.
2072 : *
2073 : * Copy all the files associated with a dataset.
2074 : *
2075 : * Equivalent of the C function GDALCopyDatasetFiles().
2076 : *
2077 : * @param pszNewName new name for the dataset.
2078 : * @param pszOldName old name for the dataset.
2079 : *
2080 : * @return CE_None on success, or CE_Failure if the operation fails.
2081 : */
2082 :
2083 14 : CPLErr GDALDriver::CopyFiles(const char *pszNewName, const char *pszOldName)
2084 :
2085 : {
2086 14 : pfnCopyFiles = GetCopyFilesCallback();
2087 14 : if (pfnCopyFiles != nullptr)
2088 3 : return pfnCopyFiles(pszNewName, pszOldName);
2089 :
2090 11 : return DefaultCopyFiles(pszNewName, pszOldName);
2091 : }
2092 :
2093 : /************************************************************************/
2094 : /* GDALCopyDatasetFiles() */
2095 : /************************************************************************/
2096 :
2097 : /**
2098 : * \brief Copy the files of a dataset.
2099 : *
2100 : * @see GDALDriver::CopyFiles()
2101 : */
2102 :
2103 15 : CPLErr CPL_STDCALL GDALCopyDatasetFiles(GDALDriverH hDriver,
2104 : const char *pszNewName,
2105 : const char *pszOldName)
2106 :
2107 : {
2108 15 : if (hDriver == nullptr)
2109 10 : hDriver = GDALIdentifyDriver(pszOldName, nullptr);
2110 :
2111 15 : if (hDriver == nullptr)
2112 : {
2113 1 : CPLError(CE_Failure, CPLE_AppDefined, "No identifiable driver for %s.",
2114 : pszOldName);
2115 1 : return CE_Failure;
2116 : }
2117 :
2118 14 : return GDALDriver::FromHandle(hDriver)->CopyFiles(pszNewName, pszOldName);
2119 : }
2120 :
2121 : /************************************************************************/
2122 : /* GDALDriverHasOpenOption() */
2123 : /************************************************************************/
2124 :
2125 : /**
2126 : * \brief Returns TRUE if the given open option is supported by the driver.
2127 : * @param hDriver the handle of the driver
2128 : * @param pszOpenOptionName name of the open option to be checked
2129 : * @return TRUE if the driver supports the open option
2130 : * @since GDAL 3.11
2131 : */
2132 2 : bool GDALDriverHasOpenOption(GDALDriverH hDriver, const char *pszOpenOptionName)
2133 : {
2134 2 : VALIDATE_POINTER1(hDriver, "GDALDriverHasOpenOption", false);
2135 2 : return GDALDriver::FromHandle(hDriver)->HasOpenOption(pszOpenOptionName);
2136 : }
2137 :
2138 : /************************************************************************/
2139 : /* GDALGetDriverShortName() */
2140 : /************************************************************************/
2141 :
2142 : /**
2143 : * \brief Return the short name of a driver
2144 : *
2145 : * This is the string that can be
2146 : * passed to the GDALGetDriverByName() function.
2147 : *
2148 : * For the GeoTIFF driver, this is "GTiff"
2149 : *
2150 : * @param hDriver the handle of the driver
2151 : * @return the short name of the driver. The
2152 : * returned string should not be freed and is owned by the driver.
2153 : */
2154 :
2155 8782830 : const char *CPL_STDCALL GDALGetDriverShortName(GDALDriverH hDriver)
2156 :
2157 : {
2158 8782830 : VALIDATE_POINTER1(hDriver, "GDALGetDriverShortName", nullptr);
2159 :
2160 8782830 : return GDALDriver::FromHandle(hDriver)->GetDescription();
2161 : }
2162 :
2163 : /************************************************************************/
2164 : /* GDALGetDriverLongName() */
2165 : /************************************************************************/
2166 :
2167 : /**
2168 : * \brief Return the long name of a driver
2169 : *
2170 : * For the GeoTIFF driver, this is "GeoTIFF"
2171 : *
2172 : * @param hDriver the handle of the driver
2173 : * @return the long name of the driver or empty string. The
2174 : * returned string should not be freed and is owned by the driver.
2175 : */
2176 :
2177 509 : const char *CPL_STDCALL GDALGetDriverLongName(GDALDriverH hDriver)
2178 :
2179 : {
2180 509 : VALIDATE_POINTER1(hDriver, "GDALGetDriverLongName", nullptr);
2181 :
2182 : const char *pszLongName =
2183 509 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_LONGNAME);
2184 :
2185 509 : if (pszLongName == nullptr)
2186 0 : return "";
2187 :
2188 509 : return pszLongName;
2189 : }
2190 :
2191 : /************************************************************************/
2192 : /* GDALGetDriverHelpTopic() */
2193 : /************************************************************************/
2194 :
2195 : /**
2196 : * \brief Return the URL to the help that describes the driver
2197 : *
2198 : * That URL is relative to the GDAL documentation directory.
2199 : *
2200 : * For the GeoTIFF driver, this is "frmt_gtiff.html"
2201 : *
2202 : * @param hDriver the handle of the driver
2203 : * @return the URL to the help that describes the driver or NULL. The
2204 : * returned string should not be freed and is owned by the driver.
2205 : */
2206 :
2207 0 : const char *CPL_STDCALL GDALGetDriverHelpTopic(GDALDriverH hDriver)
2208 :
2209 : {
2210 0 : VALIDATE_POINTER1(hDriver, "GDALGetDriverHelpTopic", nullptr);
2211 :
2212 0 : return GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_HELPTOPIC);
2213 : }
2214 :
2215 : /************************************************************************/
2216 : /* GDALGetDriverCreationOptionList() */
2217 : /************************************************************************/
2218 :
2219 : /**
2220 : * \brief Return the list of creation options of the driver
2221 : *
2222 : * Return the list of creation options of the driver used by Create() and
2223 : * CreateCopy() as an XML string
2224 : *
2225 : * @param hDriver the handle of the driver
2226 : * @return an XML string that describes the list of creation options or
2227 : * empty string. The returned string should not be freed and is
2228 : * owned by the driver.
2229 : */
2230 :
2231 0 : const char *CPL_STDCALL GDALGetDriverCreationOptionList(GDALDriverH hDriver)
2232 :
2233 : {
2234 0 : VALIDATE_POINTER1(hDriver, "GDALGetDriverCreationOptionList", nullptr);
2235 :
2236 : const char *pszOptionList =
2237 0 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2238 0 : GDAL_DMD_CREATIONOPTIONLIST);
2239 :
2240 0 : if (pszOptionList == nullptr)
2241 0 : return "";
2242 :
2243 0 : return pszOptionList;
2244 : }
2245 :
2246 : /************************************************************************/
2247 : /* GDALValidateCreationOptions() */
2248 : /************************************************************************/
2249 :
2250 : /**
2251 : * \brief Validate the list of creation options that are handled by a driver
2252 : *
2253 : * This is a helper method primarily used by Create() and
2254 : * CreateCopy() to validate that the passed in list of creation options
2255 : * is compatible with the GDAL_DMD_CREATIONOPTIONLIST metadata item defined
2256 : * by some drivers. @see GDALGetDriverCreationOptionList()
2257 : *
2258 : * If the GDAL_DMD_CREATIONOPTIONLIST metadata item is not defined, this
2259 : * function will return TRUE. Otherwise it will check that the keys and values
2260 : * in the list of creation options are compatible with the capabilities declared
2261 : * by the GDAL_DMD_CREATIONOPTIONLIST metadata item. In case of incompatibility
2262 : * a (non fatal) warning will be emitted and FALSE will be returned.
2263 : *
2264 : * @param hDriver the handle of the driver with whom the lists of creation
2265 : * option must be validated
2266 : * @param papszCreationOptions the list of creation options. An array of
2267 : * strings, whose last element is a NULL pointer
2268 : * @return TRUE if the list of creation options is compatible with the Create()
2269 : * and CreateCopy() method of the driver, FALSE otherwise.
2270 : */
2271 :
2272 37253 : int CPL_STDCALL GDALValidateCreationOptions(GDALDriverH hDriver,
2273 : CSLConstList papszCreationOptions)
2274 : {
2275 37253 : VALIDATE_POINTER1(hDriver, "GDALValidateCreationOptions", FALSE);
2276 : const char *pszOptionList =
2277 37253 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2278 37253 : GDAL_DMD_CREATIONOPTIONLIST);
2279 37253 : CPLString osDriver;
2280 : osDriver.Printf("driver %s",
2281 37253 : GDALDriver::FromHandle(hDriver)->GetDescription());
2282 37253 : bool bFoundOptionToRemove = false;
2283 37253 : constexpr const char *const apszExcludedOptions[] = {
2284 : "APPEND_SUBDATASET", "COPY_SRC_MDD", "SRC_MDD", "SKIP_HOLES"};
2285 54732 : for (const char *pszCO : cpl::Iterate(papszCreationOptions))
2286 : {
2287 88038 : for (const char *pszExcludedOptions : apszExcludedOptions)
2288 : {
2289 70559 : if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
2290 205 : pszCO[strlen(pszExcludedOptions)] == '=')
2291 : {
2292 205 : bFoundOptionToRemove = true;
2293 205 : break;
2294 : }
2295 : }
2296 17684 : if (bFoundOptionToRemove)
2297 205 : break;
2298 : }
2299 37253 : CSLConstList papszOptionsToValidate = papszCreationOptions;
2300 37253 : char **papszOptionsToFree = nullptr;
2301 37253 : if (bFoundOptionToRemove)
2302 : {
2303 628 : for (const char *pszCO : cpl::Iterate(papszCreationOptions))
2304 : {
2305 423 : bool bMatch = false;
2306 1713 : for (const char *pszExcludedOptions : apszExcludedOptions)
2307 : {
2308 1508 : if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
2309 218 : pszCO[strlen(pszExcludedOptions)] == '=')
2310 : {
2311 218 : bMatch = true;
2312 218 : break;
2313 : }
2314 : }
2315 423 : if (!bMatch)
2316 205 : papszOptionsToFree = CSLAddString(papszOptionsToFree, pszCO);
2317 : }
2318 205 : papszOptionsToValidate = papszOptionsToFree;
2319 : }
2320 :
2321 37253 : const bool bRet = CPL_TO_BOOL(
2322 : GDALValidateOptions(hDriver, pszOptionList, papszOptionsToValidate,
2323 : "creation option", osDriver));
2324 37253 : CSLDestroy(papszOptionsToFree);
2325 37253 : return bRet;
2326 : }
2327 :
2328 : /************************************************************************/
2329 : /* GDALValidateOpenOptions() */
2330 : /************************************************************************/
2331 :
2332 63808 : int GDALValidateOpenOptions(GDALDriverH hDriver,
2333 : const char *const *papszOpenOptions)
2334 : {
2335 63808 : VALIDATE_POINTER1(hDriver, "GDALValidateOpenOptions", FALSE);
2336 : const char *pszOptionList =
2337 63808 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2338 63808 : GDAL_DMD_OPENOPTIONLIST);
2339 127616 : CPLString osDriver;
2340 : osDriver.Printf("driver %s",
2341 63808 : GDALDriver::FromHandle(hDriver)->GetDescription());
2342 63808 : return GDALValidateOptions(hDriver, pszOptionList, papszOpenOptions,
2343 63808 : "open option", osDriver);
2344 : }
2345 :
2346 : /************************************************************************/
2347 : /* GDALValidateOptions() */
2348 : /************************************************************************/
2349 :
2350 115665 : int GDALValidateOptions(GDALDriverH hDriver, const char *pszOptionList,
2351 : const char *const *papszOptionsToValidate,
2352 : const char *pszErrorMessageOptionType,
2353 : const char *pszErrorMessageContainerName)
2354 : {
2355 115665 : if (papszOptionsToValidate == nullptr || *papszOptionsToValidate == nullptr)
2356 97740 : return TRUE;
2357 17925 : if (pszOptionList == nullptr)
2358 180 : return TRUE;
2359 :
2360 17745 : CPLXMLNode *psNode = CPLParseXMLString(pszOptionList);
2361 17745 : if (psNode == nullptr)
2362 : {
2363 0 : CPLError(CE_Warning, CPLE_AppDefined,
2364 : "Could not parse %s list of %s. Assuming options are valid.",
2365 : pszErrorMessageOptionType, pszErrorMessageContainerName);
2366 0 : return TRUE;
2367 : }
2368 :
2369 17745 : bool bRet = true;
2370 48425 : while (*papszOptionsToValidate)
2371 : {
2372 30680 : char *pszKey = nullptr;
2373 : const char *pszValue =
2374 30680 : CPLParseNameValue(*papszOptionsToValidate, &pszKey);
2375 30680 : if (pszKey == nullptr)
2376 : {
2377 1 : CPLError(CE_Warning, CPLE_NotSupported,
2378 : "%s '%s' is not formatted with the key=value format",
2379 : pszErrorMessageOptionType, *papszOptionsToValidate);
2380 1 : bRet = false;
2381 :
2382 1 : ++papszOptionsToValidate;
2383 2374 : continue;
2384 : }
2385 :
2386 30679 : if (EQUAL(pszKey, "VALIDATE_OPEN_OPTIONS"))
2387 : {
2388 0 : ++papszOptionsToValidate;
2389 0 : CPLFree(pszKey);
2390 0 : continue;
2391 : }
2392 :
2393 : // Must we be forgiving in case of missing option ?
2394 30679 : bool bWarnIfMissingKey = true;
2395 30679 : if (pszKey[0] == '@')
2396 : {
2397 2354 : bWarnIfMissingKey = false;
2398 2354 : memmove(pszKey, pszKey + 1, strlen(pszKey + 1) + 1);
2399 : }
2400 :
2401 30679 : CPLXMLNode *psChildNode = psNode->psChild;
2402 308617 : while (psChildNode)
2403 : {
2404 306244 : if (EQUAL(psChildNode->pszValue, "OPTION"))
2405 : {
2406 : const char *pszOptionName =
2407 306244 : CPLGetXMLValue(psChildNode, "name", "");
2408 : /* For option names terminated by wildcard (NITF BLOCKA option
2409 : * names for example) */
2410 306244 : if (strlen(pszOptionName) > 0 &&
2411 306244 : pszOptionName[strlen(pszOptionName) - 1] == '*' &&
2412 1288 : EQUALN(pszOptionName, pszKey, strlen(pszOptionName) - 1))
2413 : {
2414 216 : break;
2415 : }
2416 :
2417 : /* For option names beginning by a wildcard */
2418 306028 : if (pszOptionName[0] == '*' &&
2419 57 : strlen(pszKey) > strlen(pszOptionName) &&
2420 9 : EQUAL(pszKey + strlen(pszKey) - strlen(pszOptionName + 1),
2421 : pszOptionName + 1))
2422 : {
2423 2 : break;
2424 : }
2425 :
2426 : // For options names with * in the middle
2427 306026 : const char *pszStarInOptionName = strchr(pszOptionName, '*');
2428 306026 : if (pszStarInOptionName &&
2429 1093 : pszStarInOptionName != pszOptionName &&
2430 : pszStarInOptionName !=
2431 1093 : pszOptionName + strlen(pszOptionName) - 1 &&
2432 21 : strlen(pszKey) > static_cast<size_t>(pszStarInOptionName -
2433 12 : pszOptionName) &&
2434 12 : EQUALN(pszKey, pszOptionName,
2435 : static_cast<size_t>(pszStarInOptionName -
2436 12 : pszOptionName)) &&
2437 12 : EQUAL(pszKey +
2438 : static_cast<size_t>(pszStarInOptionName -
2439 : pszOptionName) +
2440 : 1,
2441 : pszStarInOptionName + 1))
2442 : {
2443 6 : break;
2444 : }
2445 :
2446 306020 : if (EQUAL(pszOptionName, pszKey))
2447 : {
2448 27970 : break;
2449 : }
2450 : const char *pszAlias =
2451 278050 : CPLGetXMLValue(psChildNode, "alias", nullptr);
2452 : const char *pszDeprecatedAlias =
2453 278050 : pszAlias ? nullptr
2454 277139 : : CPLGetXMLValue(psChildNode, "deprecated_alias",
2455 278050 : nullptr);
2456 278050 : if (!pszAlias && pszDeprecatedAlias)
2457 159 : pszAlias = pszDeprecatedAlias;
2458 278050 : if (pszAlias && EQUAL(pszAlias, pszKey))
2459 : {
2460 112 : if (pszDeprecatedAlias)
2461 : {
2462 0 : CPLDebug(
2463 : "GDAL",
2464 : "Using deprecated alias '%s'. New name is '%s'",
2465 : pszAlias, pszOptionName);
2466 : }
2467 112 : break;
2468 : }
2469 : }
2470 277938 : psChildNode = psChildNode->psNext;
2471 : }
2472 30679 : if (psChildNode == nullptr)
2473 : {
2474 2399 : if (bWarnIfMissingKey &&
2475 26 : (!EQUAL(pszErrorMessageOptionType, "open option") ||
2476 2 : CPLFetchBool(papszOptionsToValidate, "VALIDATE_OPEN_OPTIONS",
2477 : true)))
2478 : {
2479 26 : const char *pszAdditionalMsg = "";
2480 26 : if (hDriver &&
2481 21 : EQUAL(pszErrorMessageOptionType, "creation option"))
2482 : {
2483 : const char *pszLCOList =
2484 16 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2485 16 : GDAL_DS_LAYER_CREATIONOPTIONLIST);
2486 22 : if (pszLCOList &&
2487 22 : (CPLString(pszLCOList)
2488 6 : .ifind(CPLSPrintf("\"%s\"", pszKey)) !=
2489 12 : std::string::npos ||
2490 22 : CPLString(pszLCOList)
2491 6 : .ifind(CPLSPrintf("'%s'", pszKey)) !=
2492 : std::string::npos))
2493 : {
2494 1 : pszAdditionalMsg = ", but a layer creation option of "
2495 : "that name exists.";
2496 16 : }
2497 : }
2498 10 : else if (hDriver && EQUAL(pszErrorMessageOptionType,
2499 : "layer creation option"))
2500 : {
2501 : const char *pszLCOList =
2502 3 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2503 3 : GDAL_DMD_CREATIONOPTIONLIST);
2504 6 : if (pszLCOList &&
2505 6 : (CPLString(pszLCOList)
2506 3 : .ifind(CPLSPrintf("\"%s\"", pszKey)) !=
2507 6 : std::string::npos ||
2508 6 : CPLString(pszLCOList)
2509 3 : .ifind(CPLSPrintf("'%s'", pszKey)) !=
2510 : std::string::npos))
2511 : {
2512 1 : pszAdditionalMsg = ", but a creation option of "
2513 : "that name exists.";
2514 : }
2515 : }
2516 :
2517 26 : CPLError(CE_Warning, CPLE_NotSupported,
2518 : "%s does not support %s %s%s",
2519 : pszErrorMessageContainerName,
2520 : pszErrorMessageOptionType, pszKey, pszAdditionalMsg);
2521 26 : bRet = false;
2522 : }
2523 :
2524 2373 : CPLFree(pszKey);
2525 2373 : ++papszOptionsToValidate;
2526 2373 : continue;
2527 : }
2528 :
2529 : #ifdef DEBUG
2530 28306 : CPLXMLNode *psChildSubNode = psChildNode->psChild;
2531 167931 : while (psChildSubNode)
2532 : {
2533 139625 : if (psChildSubNode->eType == CXT_Attribute)
2534 : {
2535 98018 : if (!(EQUAL(psChildSubNode->pszValue, "name") ||
2536 69712 : EQUAL(psChildSubNode->pszValue, "alias") ||
2537 69517 : EQUAL(psChildSubNode->pszValue, "deprecated_alias") ||
2538 69430 : EQUAL(psChildSubNode->pszValue, "alt_config_option") ||
2539 69410 : EQUAL(psChildSubNode->pszValue, "description") ||
2540 45598 : EQUAL(psChildSubNode->pszValue, "type") ||
2541 17292 : EQUAL(psChildSubNode->pszValue, "min") ||
2542 16973 : EQUAL(psChildSubNode->pszValue, "max") ||
2543 16585 : EQUAL(psChildSubNode->pszValue, "default") ||
2544 1032 : EQUAL(psChildSubNode->pszValue, "maxsize") ||
2545 1002 : EQUAL(psChildSubNode->pszValue, "required") ||
2546 947 : EQUAL(psChildSubNode->pszValue, "scope")))
2547 : {
2548 : /* Driver error */
2549 0 : CPLError(CE_Warning, CPLE_NotSupported,
2550 : "%s : unhandled attribute '%s' for %s %s.",
2551 : pszErrorMessageContainerName,
2552 : psChildSubNode->pszValue, pszKey,
2553 : pszErrorMessageOptionType);
2554 : }
2555 : }
2556 139625 : psChildSubNode = psChildSubNode->psNext;
2557 : }
2558 : #endif
2559 :
2560 28306 : const char *pszType = CPLGetXMLValue(psChildNode, "type", nullptr);
2561 28306 : const char *pszMin = CPLGetXMLValue(psChildNode, "min", nullptr);
2562 28306 : const char *pszMax = CPLGetXMLValue(psChildNode, "max", nullptr);
2563 28306 : if (pszType != nullptr)
2564 : {
2565 28306 : if (EQUAL(pszType, "INT") || EQUAL(pszType, "INTEGER"))
2566 : {
2567 8797 : const char *pszValueIter = pszValue;
2568 22571 : while (*pszValueIter)
2569 : {
2570 13824 : if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
2571 69 : *pszValueIter == '+' || *pszValueIter == '-'))
2572 : {
2573 50 : CPLError(CE_Warning, CPLE_NotSupported,
2574 : "'%s' is an unexpected value for %s %s of "
2575 : "type int.",
2576 : pszValue, pszKey, pszErrorMessageOptionType);
2577 50 : bRet = false;
2578 50 : break;
2579 : }
2580 13774 : ++pszValueIter;
2581 : }
2582 8797 : if (*pszValueIter == '\0')
2583 : {
2584 8747 : if (pszMin && atoi(pszValue) < atoi(pszMin))
2585 : {
2586 10 : CPLError(CE_Warning, CPLE_NotSupported,
2587 : "'%s' is an unexpected value for %s %s that "
2588 : "should be >= %s.",
2589 : pszValue, pszKey, pszErrorMessageOptionType,
2590 : pszMin);
2591 10 : bRet = false;
2592 : }
2593 8747 : if (pszMax && atoi(pszValue) > atoi(pszMax))
2594 : {
2595 12 : CPLError(CE_Warning, CPLE_NotSupported,
2596 : "'%s' is an unexpected value for %s %s that "
2597 : "should be <= %s.",
2598 : pszValue, pszKey, pszErrorMessageOptionType,
2599 : pszMax);
2600 12 : bRet = false;
2601 : }
2602 8797 : }
2603 : }
2604 19509 : else if (EQUAL(pszType, "UNSIGNED INT"))
2605 : {
2606 3 : const char *pszValueIter = pszValue;
2607 10 : while (*pszValueIter)
2608 : {
2609 7 : if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
2610 0 : *pszValueIter == '+'))
2611 : {
2612 0 : CPLError(CE_Warning, CPLE_NotSupported,
2613 : "'%s' is an unexpected value for %s %s of "
2614 : "type unsigned int.",
2615 : pszValue, pszKey, pszErrorMessageOptionType);
2616 0 : bRet = false;
2617 0 : break;
2618 : }
2619 7 : ++pszValueIter;
2620 : }
2621 3 : if (*pszValueIter == '\0')
2622 : {
2623 3 : if (pszMin && atoi(pszValue) < atoi(pszMin))
2624 : {
2625 0 : CPLError(CE_Warning, CPLE_NotSupported,
2626 : "'%s' is an unexpected value for %s %s that "
2627 : "should be >= %s.",
2628 : pszValue, pszKey, pszErrorMessageOptionType,
2629 : pszMin);
2630 0 : bRet = false;
2631 : }
2632 3 : if (pszMax && atoi(pszValue) > atoi(pszMax))
2633 : {
2634 0 : CPLError(CE_Warning, CPLE_NotSupported,
2635 : "'%s' is an unexpected value for %s %s that "
2636 : "should be <= %s.",
2637 : pszValue, pszKey, pszErrorMessageOptionType,
2638 : pszMax);
2639 0 : bRet = false;
2640 : }
2641 : }
2642 : }
2643 19506 : else if (EQUAL(pszType, "FLOAT"))
2644 : {
2645 773 : char *endPtr = nullptr;
2646 773 : double dfVal = CPLStrtod(pszValue, &endPtr);
2647 773 : if (!(endPtr == nullptr || *endPtr == '\0'))
2648 : {
2649 2 : CPLError(
2650 : CE_Warning, CPLE_NotSupported,
2651 : "'%s' is an unexpected value for %s %s of type float.",
2652 : pszValue, pszKey, pszErrorMessageOptionType);
2653 2 : bRet = false;
2654 : }
2655 : else
2656 : {
2657 771 : if (pszMin && dfVal < CPLAtof(pszMin))
2658 : {
2659 3 : CPLError(CE_Warning, CPLE_NotSupported,
2660 : "'%s' is an unexpected value for %s %s that "
2661 : "should be >= %s.",
2662 : pszValue, pszKey, pszErrorMessageOptionType,
2663 : pszMin);
2664 3 : bRet = false;
2665 : }
2666 771 : if (pszMax && dfVal > CPLAtof(pszMax))
2667 : {
2668 0 : CPLError(CE_Warning, CPLE_NotSupported,
2669 : "'%s' is an unexpected value for %s %s that "
2670 : "should be <= %s.",
2671 : pszValue, pszKey, pszErrorMessageOptionType,
2672 : pszMax);
2673 0 : bRet = false;
2674 : }
2675 : }
2676 : }
2677 18733 : else if (EQUAL(pszType, "BOOLEAN"))
2678 : {
2679 4350 : if (!(EQUAL(pszValue, "ON") || EQUAL(pszValue, "TRUE") ||
2680 4280 : EQUAL(pszValue, "YES") || EQUAL(pszValue, "OFF") ||
2681 649 : EQUAL(pszValue, "FALSE") || EQUAL(pszValue, "NO")))
2682 : {
2683 0 : CPLError(CE_Warning, CPLE_NotSupported,
2684 : "'%s' is an unexpected value for %s %s of type "
2685 : "boolean.",
2686 : pszValue, pszKey, pszErrorMessageOptionType);
2687 0 : bRet = false;
2688 : }
2689 : }
2690 14383 : else if (EQUAL(pszType, "STRING-SELECT"))
2691 : {
2692 7428 : bool bMatchFound = false;
2693 7428 : bool bOtherValuesElementFound = false;
2694 7428 : CPLXMLNode *psStringSelect = psChildNode->psChild;
2695 45667 : while (psStringSelect)
2696 : {
2697 45625 : if (psStringSelect->eType == CXT_Element &&
2698 22018 : EQUAL(psStringSelect->pszValue, "Value"))
2699 : {
2700 22018 : CPLXMLNode *psOptionNode = psStringSelect->psChild;
2701 37277 : while (psOptionNode)
2702 : {
2703 22645 : if (psOptionNode->eType == CXT_Text &&
2704 21899 : EQUAL(psOptionNode->pszValue, pszValue))
2705 : {
2706 7267 : bMatchFound = true;
2707 7267 : break;
2708 : }
2709 15378 : if (psOptionNode->eType == CXT_Attribute &&
2710 746 : (EQUAL(psOptionNode->pszValue, "alias") ||
2711 15 : EQUAL(psOptionNode->pszValue,
2712 731 : "deprecated_alias")) &&
2713 731 : EQUAL(psOptionNode->psChild->pszValue,
2714 : pszValue))
2715 : {
2716 119 : bMatchFound = true;
2717 119 : break;
2718 : }
2719 15259 : psOptionNode = psOptionNode->psNext;
2720 : }
2721 22018 : if (bMatchFound)
2722 22018 : break;
2723 : }
2724 23607 : else if (psStringSelect->eType == CXT_Element &&
2725 0 : EQUAL(psStringSelect->pszValue, "OtherValues"))
2726 : {
2727 0 : bOtherValuesElementFound = true;
2728 : }
2729 38239 : psStringSelect = psStringSelect->psNext;
2730 : }
2731 7428 : if (!bMatchFound && !bOtherValuesElementFound)
2732 : {
2733 42 : CPLError(CE_Warning, CPLE_NotSupported,
2734 : "'%s' is an unexpected value for %s %s of type "
2735 : "string-select.",
2736 : pszValue, pszKey, pszErrorMessageOptionType);
2737 42 : bRet = false;
2738 : }
2739 : }
2740 6955 : else if (EQUAL(pszType, "STRING"))
2741 : {
2742 : const char *pszMaxSize =
2743 6955 : CPLGetXMLValue(psChildNode, "maxsize", nullptr);
2744 6955 : if (pszMaxSize != nullptr)
2745 : {
2746 30 : if (static_cast<int>(strlen(pszValue)) > atoi(pszMaxSize))
2747 : {
2748 1 : CPLError(CE_Warning, CPLE_NotSupported,
2749 : "'%s' is of size %d, whereas maximum size for "
2750 : "%s %s is %d.",
2751 1 : pszValue, static_cast<int>(strlen(pszValue)),
2752 : pszKey, pszErrorMessageOptionType,
2753 : atoi(pszMaxSize));
2754 1 : bRet = false;
2755 : }
2756 : }
2757 : }
2758 : else
2759 : {
2760 : /* Driver error */
2761 0 : CPLError(CE_Warning, CPLE_NotSupported,
2762 : "%s : type '%s' for %s %s is not recognized.",
2763 : pszErrorMessageContainerName, pszType, pszKey,
2764 : pszErrorMessageOptionType);
2765 : }
2766 : }
2767 : else
2768 : {
2769 : /* Driver error */
2770 0 : CPLError(CE_Warning, CPLE_NotSupported, "%s : no type for %s %s.",
2771 : pszErrorMessageContainerName, pszKey,
2772 : pszErrorMessageOptionType);
2773 : }
2774 28306 : CPLFree(pszKey);
2775 28306 : ++papszOptionsToValidate;
2776 : }
2777 :
2778 17745 : CPLDestroyXMLNode(psNode);
2779 17745 : return bRet ? TRUE : FALSE;
2780 : }
2781 :
2782 : /************************************************************************/
2783 : /* GDALIdentifyDriver() */
2784 : /************************************************************************/
2785 :
2786 : /**
2787 : * \brief Identify the driver that can open a dataset.
2788 : *
2789 : * This function will try to identify the driver that can open the passed file
2790 : * name by invoking the Identify method of each registered GDALDriver in turn.
2791 : * The first driver that successfully identifies the file name will be returned.
2792 : * If all drivers fail then NULL is returned.
2793 : *
2794 : * In order to reduce the need for such searches to touch the operating system
2795 : * file system machinery, it is possible to give an optional list of files.
2796 : * This is the list of all files at the same level in the file system as the
2797 : * target file, including the target file. The filenames will not include any
2798 : * path components, and are essentially just the output of VSIReadDir() on the
2799 : * parent directory. If the target object does not have filesystem semantics
2800 : * then the file list should be NULL.
2801 : *
2802 : * @param pszFilename the name of the file to access. In the case of
2803 : * exotic drivers this may not refer to a physical file, but instead contain
2804 : * information for the driver on how to access a dataset.
2805 : *
2806 : * @param papszFileList an array of strings, whose last element is the NULL
2807 : * pointer. These strings are filenames that are auxiliary to the main
2808 : * filename. The passed value may be NULL.
2809 : *
2810 : * @return A GDALDriverH handle or NULL on failure. For C++ applications
2811 : * this handle can be cast to a GDALDriver *.
2812 : */
2813 :
2814 26172 : GDALDriverH CPL_STDCALL GDALIdentifyDriver(const char *pszFilename,
2815 : CSLConstList papszFileList)
2816 :
2817 : {
2818 26172 : return GDALIdentifyDriverEx(pszFilename, 0, nullptr, papszFileList);
2819 : }
2820 :
2821 : /************************************************************************/
2822 : /* GDALIdentifyDriverEx() */
2823 : /************************************************************************/
2824 :
2825 : /**
2826 : * \brief Identify the driver that can open a dataset.
2827 : *
2828 : * This function will try to identify the driver that can open the passed file
2829 : * name by invoking the Identify method of each registered GDALDriver in turn.
2830 : * The first driver that successfully identifies the file name will be returned.
2831 : * If all drivers fail then NULL is returned.
2832 : *
2833 : * In order to reduce the need for such searches to touch the operating system
2834 : * file system machinery, it is possible to give an optional list of files.
2835 : * This is the list of all files at the same level in the file system as the
2836 : * target file, including the target file. The filenames will not include any
2837 : * path components, and are essentially just the output of VSIReadDir() on the
2838 : * parent directory. If the target object does not have filesystem semantics
2839 : * then the file list should be NULL.
2840 : *
2841 : * @param pszFilename the name of the file to access. In the case of
2842 : * exotic drivers this may not refer to a physical file, but instead contain
2843 : * information for the driver on how to access a dataset.
2844 : *
2845 : * @param nIdentifyFlags a combination of GDAL_OF_RASTER for raster drivers
2846 : * or GDAL_OF_VECTOR for vector drivers. If none of the value is specified,
2847 : * both kinds are implied.
2848 : *
2849 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
2850 : * terminated list of strings with the driver short names that must be
2851 : * considered.
2852 : *
2853 : * @param papszFileList an array of strings, whose last element is the NULL
2854 : * pointer. These strings are filenames that are auxiliary to the main
2855 : * filename. The passed value may be NULL.
2856 : *
2857 : * @return A GDALDriverH handle or NULL on failure. For C++ applications
2858 : * this handle can be cast to a GDALDriver *.
2859 : */
2860 :
2861 26262 : GDALDriverH CPL_STDCALL GDALIdentifyDriverEx(
2862 : const char *pszFilename, unsigned int nIdentifyFlags,
2863 : const char *const *papszAllowedDrivers, const char *const *papszFileList)
2864 : {
2865 26262 : GDALDriverManager *poDM = GetGDALDriverManager();
2866 26262 : CPLAssert(nullptr != poDM);
2867 :
2868 : // If no driver kind is specified, assume all are to be probed.
2869 26262 : if ((nIdentifyFlags & GDAL_OF_KIND_MASK) == 0)
2870 26219 : nIdentifyFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
2871 :
2872 52524 : GDALOpenInfo oOpenInfo(pszFilename, nIdentifyFlags, papszFileList);
2873 26262 : oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
2874 :
2875 52524 : CPLErrorStateBackuper oBackuper;
2876 26262 : CPLErrorSetState(CE_None, CPLE_AppDefined, "");
2877 :
2878 26262 : const int nDriverCount = poDM->GetDriverCount();
2879 :
2880 : // First pass: only use drivers that have a pfnIdentify implementation.
2881 52524 : std::vector<GDALDriver *> apoSecondPassDrivers;
2882 5834520 : for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
2883 : {
2884 5809550 : GDALDriver *poDriver = poDM->GetDriver(iDriver);
2885 5817020 : if (papszAllowedDrivers != nullptr &&
2886 7468 : CSLFindString(papszAllowedDrivers,
2887 : GDALGetDriverShortName(poDriver)) == -1)
2888 : {
2889 1123720 : continue;
2890 : }
2891 :
2892 5803420 : VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
2893 :
2894 5802130 : if (poDriver->pfnIdentify == nullptr &&
2895 1112420 : poDriver->pfnIdentifyEx == nullptr)
2896 : {
2897 1112420 : continue;
2898 : }
2899 :
2900 4689750 : if (papszAllowedDrivers != nullptr &&
2901 44 : CSLFindString(papszAllowedDrivers,
2902 : GDALGetDriverShortName(poDriver)) == -1)
2903 0 : continue;
2904 14064300 : if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
2905 4690220 : (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
2906 514 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
2907 147 : continue;
2908 14072000 : if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
2909 4694530 : (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
2910 4969 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
2911 3729 : continue;
2912 :
2913 4685830 : if (poDriver->pfnIdentifyEx)
2914 : {
2915 0 : if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) > 0)
2916 0 : return poDriver;
2917 : }
2918 : else
2919 : {
2920 4685830 : const int nIdentifyRes = poDriver->pfnIdentify(&oOpenInfo);
2921 4685830 : if (nIdentifyRes > 0)
2922 1291 : return poDriver;
2923 4710720 : if (nIdentifyRes < 0 &&
2924 26178 : poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
2925 : {
2926 : // Not loaded plugin
2927 34 : apoSecondPassDrivers.push_back(poDriver);
2928 : }
2929 : }
2930 : }
2931 :
2932 : // second pass: try loading plugin drivers
2933 25002 : for (auto poDriver : apoSecondPassDrivers)
2934 : {
2935 : // Force plugin driver loading
2936 32 : poDriver->GetMetadata();
2937 32 : if (poDriver->pfnIdentify(&oOpenInfo) > 0)
2938 1 : return poDriver;
2939 : }
2940 :
2941 : // third pass: slow method.
2942 5702280 : for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
2943 : {
2944 5677540 : GDALDriver *poDriver = poDM->GetDriver(iDriver);
2945 5681430 : if (papszAllowedDrivers != nullptr &&
2946 3892 : CSLFindString(papszAllowedDrivers,
2947 : GDALGetDriverShortName(poDriver)) == -1)
2948 : {
2949 3875 : continue;
2950 : }
2951 :
2952 5673670 : VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
2953 :
2954 17019500 : if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
2955 5674120 : (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
2956 456 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
2957 145 : continue;
2958 17021200 : if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
2959 5675120 : (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
2960 1598 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
2961 960 : continue;
2962 :
2963 5672560 : if (poDriver->pfnIdentifyEx != nullptr)
2964 : {
2965 0 : if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) == 0)
2966 0 : continue;
2967 : }
2968 5672560 : else if (poDriver->pfnIdentify != nullptr)
2969 : {
2970 4584240 : if (poDriver->pfnIdentify(&oOpenInfo) == 0)
2971 4558700 : continue;
2972 : }
2973 :
2974 : GDALDataset *poDS;
2975 1113860 : if (poDriver->pfnOpen != nullptr)
2976 : {
2977 1064190 : poDS = poDriver->pfnOpen(&oOpenInfo);
2978 1064190 : if (poDS != nullptr)
2979 : {
2980 95 : delete poDS;
2981 95 : return GDALDriver::ToHandle(poDriver);
2982 : }
2983 :
2984 1064090 : if (CPLGetLastErrorType() != CE_None)
2985 136 : return nullptr;
2986 : }
2987 49679 : else if (poDriver->pfnOpenWithDriverArg != nullptr)
2988 : {
2989 0 : poDS = poDriver->pfnOpenWithDriverArg(poDriver, &oOpenInfo);
2990 0 : if (poDS != nullptr)
2991 : {
2992 0 : delete poDS;
2993 0 : return GDALDriver::ToHandle(poDriver);
2994 : }
2995 :
2996 0 : if (CPLGetLastErrorType() != CE_None)
2997 0 : return nullptr;
2998 : }
2999 : }
3000 :
3001 24739 : return nullptr;
3002 : }
3003 :
3004 : /************************************************************************/
3005 : /* GetMetadataItem() */
3006 : /************************************************************************/
3007 :
3008 13374300 : const char *GDALDriver::GetMetadataItem(const char *pszName,
3009 : const char *pszDomain)
3010 : {
3011 13374300 : if (pszDomain == nullptr || pszDomain[0] == '\0')
3012 : {
3013 13374100 : if (EQUAL(pszName, GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST))
3014 : {
3015 2224 : const char *pszVal = GDALMajorObject::GetMetadataItem(pszName, "");
3016 2224 : if (pszVal)
3017 1998 : return pszVal;
3018 226 : if (GetMetadataItem(GDAL_DCAP_RASTER))
3019 : {
3020 153 : auto poDM = GetGDALDriverManager();
3021 153 : auto poGTiffDrv = poDM->GetDriverByName("GTiff");
3022 153 : if (poGTiffDrv)
3023 : {
3024 : const char *pszXML =
3025 153 : poGTiffDrv->GetMetadataItem(pszName, "");
3026 153 : if (pszXML)
3027 : {
3028 306 : CPLString osXML(pszXML);
3029 153 : osXML.replaceAll("<Value>INTERNAL</Value>", "");
3030 153 : return CPLSPrintf("%s", osXML.c_str());
3031 : }
3032 : }
3033 : }
3034 : }
3035 : }
3036 13372100 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
3037 : }
3038 :
3039 : /************************************************************************/
3040 : /* SetMetadataItem() */
3041 : /************************************************************************/
3042 :
3043 4621390 : CPLErr GDALDriver::SetMetadataItem(const char *pszName, const char *pszValue,
3044 : const char *pszDomain)
3045 :
3046 : {
3047 4621390 : if (pszDomain == nullptr || pszDomain[0] == '\0')
3048 : {
3049 : /* Automatically sets GDAL_DMD_EXTENSIONS from GDAL_DMD_EXTENSION */
3050 4816820 : if (EQUAL(pszName, GDAL_DMD_EXTENSION) &&
3051 200871 : GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSIONS) == nullptr)
3052 : {
3053 200871 : GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSIONS, pszValue);
3054 : }
3055 : /* and vice-versa if there is a single extension in GDAL_DMD_EXTENSIONS */
3056 8911480 : else if (EQUAL(pszName, GDAL_DMD_EXTENSIONS) &&
3057 4424120 : strchr(pszValue, ' ') == nullptr &&
3058 9037 : GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSION) ==
3059 : nullptr)
3060 : {
3061 9037 : GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSION, pszValue);
3062 : }
3063 : }
3064 4621390 : return GDALMajorObject::SetMetadataItem(pszName, pszValue, pszDomain);
3065 : }
3066 :
3067 : /************************************************************************/
3068 : /* InstantiateAlgorithm() */
3069 : /************************************************************************/
3070 :
3071 : //! @cond Doxygen_Suppress
3072 :
3073 : GDALAlgorithm *
3074 1127 : GDALDriver::InstantiateAlgorithm(const std::vector<std::string> &aosPath)
3075 : {
3076 1127 : pfnInstantiateAlgorithm = GetInstantiateAlgorithmCallback();
3077 1127 : if (pfnInstantiateAlgorithm)
3078 1127 : return pfnInstantiateAlgorithm(aosPath);
3079 0 : return nullptr;
3080 : }
3081 :
3082 : /************************************************************************/
3083 : /* DeclareAlgorithm() */
3084 : /************************************************************************/
3085 :
3086 14564 : void GDALDriver::DeclareAlgorithm(const std::vector<std::string> &aosPath)
3087 : {
3088 29128 : const std::string osDriverName = GetDescription();
3089 14564 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
3090 :
3091 29128 : if (!singleton.HasDeclaredSubAlgorithm({"driver"}))
3092 : {
3093 3210 : singleton.DeclareAlgorithm(
3094 : {"driver"},
3095 151 : []() -> std::unique_ptr<GDALAlgorithm>
3096 : {
3097 302 : return std::make_unique<GDALContainerAlgorithm>(
3098 151 : "driver", "Command for driver specific operations.");
3099 1605 : });
3100 : }
3101 :
3102 : std::vector<std::string> path = {"driver",
3103 87384 : CPLString(osDriverName).tolower()};
3104 14564 : if (!singleton.HasDeclaredSubAlgorithm(path))
3105 : {
3106 1305 : auto lambda = [osDriverName]() -> std::unique_ptr<GDALAlgorithm>
3107 : {
3108 : auto poDriver =
3109 1305 : GetGDALDriverManager()->GetDriverByName(osDriverName.c_str());
3110 1305 : if (poDriver)
3111 : {
3112 : const char *pszHelpTopic =
3113 1305 : poDriver->GetMetadataItem(GDAL_DMD_HELPTOPIC);
3114 2610 : return std::make_unique<GDALContainerAlgorithm>(
3115 2610 : CPLString(osDriverName).tolower(),
3116 2610 : std::string("Command for ")
3117 1305 : .append(osDriverName)
3118 : .append(" driver specific operations."),
3119 2610 : pszHelpTopic ? std::string("/").append(pszHelpTopic)
3120 1305 : : std::string());
3121 : }
3122 0 : return nullptr;
3123 11235 : };
3124 11235 : singleton.DeclareAlgorithm(path, std::move(lambda));
3125 : }
3126 :
3127 14564 : path.insert(path.end(), aosPath.begin(), aosPath.end());
3128 :
3129 1127 : auto lambda = [osDriverName, aosPath]() -> std::unique_ptr<GDALAlgorithm>
3130 : {
3131 : auto poDriver =
3132 1127 : GetGDALDriverManager()->GetDriverByName(osDriverName.c_str());
3133 1127 : if (poDriver)
3134 : return std::unique_ptr<GDALAlgorithm>(
3135 1127 : poDriver->InstantiateAlgorithm(aosPath));
3136 0 : return nullptr;
3137 29128 : };
3138 :
3139 14564 : singleton.DeclareAlgorithm(path, std::move(lambda));
3140 :
3141 14564 : CPL_IGNORE_RET_VAL(osDriverName);
3142 14564 : }
3143 :
3144 : //! @endcond
3145 :
3146 : /************************************************************************/
3147 : /* DoesDriverHandleExtension() */
3148 : /************************************************************************/
3149 :
3150 195367 : static bool DoesDriverHandleExtension(GDALDriverH hDriver, const char *pszExt)
3151 : {
3152 195367 : bool bRet = false;
3153 : const char *pszDriverExtensions =
3154 195367 : GDALGetMetadataItem(hDriver, GDAL_DMD_EXTENSIONS, nullptr);
3155 195367 : if (pszDriverExtensions)
3156 : {
3157 326576 : const CPLStringList aosTokens(CSLTokenizeString(pszDriverExtensions));
3158 163288 : const int nTokens = aosTokens.size();
3159 367108 : for (int j = 0; j < nTokens; ++j)
3160 : {
3161 208495 : if (EQUAL(pszExt, aosTokens[j]))
3162 : {
3163 4675 : bRet = true;
3164 4675 : break;
3165 : }
3166 : }
3167 : }
3168 195367 : return bRet;
3169 : }
3170 :
3171 : /************************************************************************/
3172 : /* IsOnlyExpectedGDBDrivers() */
3173 : /************************************************************************/
3174 :
3175 1 : static bool IsOnlyExpectedGDBDrivers(const CPLStringList &aosDriverNames)
3176 : {
3177 3 : for (const char *pszDrvName : aosDriverNames)
3178 : {
3179 2 : if (!EQUAL(pszDrvName, "OpenFileGDB") &&
3180 1 : !EQUAL(pszDrvName, "FileGDB") && !EQUAL(pszDrvName, "GPSBabel"))
3181 : {
3182 0 : return false;
3183 : }
3184 : }
3185 1 : return true;
3186 : }
3187 :
3188 : /************************************************************************/
3189 : /* GDALGetOutputDriversForDatasetName() */
3190 : /************************************************************************/
3191 :
3192 : /** Return a list of driver short names that are likely candidates for the
3193 : * provided output file name.
3194 : *
3195 : * @param pszDestDataset Output dataset name (might not exist).
3196 : * @param nDatasetTypeFlag GDAL_OF_RASTER, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER
3197 : * or a binary-or'ed combination of them
3198 : * @param bSingleMatch Whether a single match is desired, that is to say the
3199 : * returned list will contain at most one item, which will
3200 : * be the first driver in the order they are registered to
3201 : * match the output dataset name. Note that in this mode, if
3202 : * nDatasetTypeFlag==GDAL_OF_RASTER and pszDestDataset has
3203 : * no extension, GTiff will be selected.
3204 : * @param bEmitWarning Whether a warning should be emitted when bSingleMatch is
3205 : * true and there are more than 2 candidates.
3206 : * @return NULL terminated list of driver short names.
3207 : * To be freed with CSLDestroy()
3208 : * @since 3.9
3209 : */
3210 2760 : char **GDALGetOutputDriversForDatasetName(const char *pszDestDataset,
3211 : int nDatasetTypeFlag,
3212 : bool bSingleMatch, bool bEmitWarning)
3213 : {
3214 5520 : CPLStringList aosDriverNames;
3215 5520 : CPLStringList aosMissingDriverNames;
3216 :
3217 5520 : std::string osExt = CPLGetExtensionSafe(pszDestDataset);
3218 2760 : if (EQUAL(osExt.c_str(), "zip"))
3219 : {
3220 2 : const CPLString osLower(CPLString(pszDestDataset).tolower());
3221 1 : if (osLower.endsWith(".shp.zip"))
3222 : {
3223 1 : osExt = "shp.zip";
3224 : }
3225 0 : else if (osLower.endsWith(".gpkg.zip"))
3226 : {
3227 0 : osExt = "gpkg.zip";
3228 : }
3229 : }
3230 2759 : else if (EQUAL(osExt.c_str(), "json"))
3231 : {
3232 1 : const CPLString osLower(CPLString(pszDestDataset).tolower());
3233 1 : if (osLower.endsWith(".gdalg.json"))
3234 0 : return nullptr;
3235 : }
3236 :
3237 2760 : auto poDM = GetGDALDriverManager();
3238 2760 : const int nDriverCount = poDM->GetDriverCount(true);
3239 2760 : GDALDriver *poMissingPluginDriver = nullptr;
3240 5520 : std::string osMatchingPrefix;
3241 634405 : for (int i = 0; i < nDriverCount; i++)
3242 : {
3243 631645 : GDALDriver *poDriver = poDM->GetDriver(i, true);
3244 631645 : bool bOk = false;
3245 631645 : if ((poDriver->GetMetadataItem(GDAL_DCAP_CREATE) != nullptr ||
3246 388768 : poDriver->GetMetadataItem(GDAL_DCAP_CREATECOPY) != nullptr ||
3247 1263290 : poDriver->GetMetadataItem(GDAL_DCAP_UPDATE) != nullptr) &&
3248 325677 : (((nDatasetTypeFlag & GDAL_OF_RASTER) &&
3249 256295 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) != nullptr) ||
3250 160606 : ((nDatasetTypeFlag & GDAL_OF_VECTOR) &&
3251 68792 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) != nullptr) ||
3252 127960 : ((nDatasetTypeFlag & GDAL_OF_MULTIDIM_RASTER) &&
3253 590 : poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) != nullptr)))
3254 : {
3255 197767 : bOk = true;
3256 : }
3257 438232 : else if (poDriver->GetMetadataItem(GDAL_DCAP_VECTOR_TRANSLATE_FROM) &&
3258 4354 : (nDatasetTypeFlag & GDAL_OF_VECTOR) != 0)
3259 : {
3260 0 : bOk = true;
3261 : }
3262 631645 : if (bOk)
3263 : {
3264 393134 : if (!osExt.empty() &&
3265 195367 : DoesDriverHandleExtension(GDALDriver::ToHandle(poDriver),
3266 : osExt.c_str()))
3267 : {
3268 4675 : if (poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
3269 : {
3270 0 : poMissingPluginDriver = poDriver;
3271 0 : aosMissingDriverNames.AddString(poDriver->GetDescription());
3272 : }
3273 : else
3274 4675 : aosDriverNames.AddString(poDriver->GetDescription());
3275 : }
3276 : else
3277 : {
3278 : const char *pszPrefix =
3279 193092 : poDriver->GetMetadataItem(GDAL_DMD_CONNECTION_PREFIX);
3280 193092 : if (pszPrefix && STARTS_WITH_CI(pszDestDataset, pszPrefix))
3281 : {
3282 9 : if (poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
3283 : {
3284 0 : osMatchingPrefix = pszPrefix;
3285 0 : poMissingPluginDriver = poDriver;
3286 : aosMissingDriverNames.AddString(
3287 0 : poDriver->GetDescription());
3288 : }
3289 : else
3290 9 : aosDriverNames.AddString(poDriver->GetDescription());
3291 : }
3292 : }
3293 : }
3294 : }
3295 :
3296 : // GMT is registered before netCDF for opening reasons, but we want
3297 : // netCDF to be used by default for output.
3298 2767 : if (EQUAL(osExt.c_str(), "nc") && aosDriverNames.size() == 2 &&
3299 2767 : EQUAL(aosDriverNames[0], "GMT") && EQUAL(aosDriverNames[1], "netCDF"))
3300 : {
3301 0 : aosDriverNames.Clear();
3302 0 : aosDriverNames.AddString("netCDF");
3303 0 : aosDriverNames.AddString("GMT");
3304 : }
3305 :
3306 2760 : if (bSingleMatch)
3307 : {
3308 2688 : if (nDatasetTypeFlag == GDAL_OF_RASTER)
3309 : {
3310 2172 : if (aosDriverNames.empty())
3311 : {
3312 12 : if (osExt.empty())
3313 : {
3314 8 : aosDriverNames.AddString("GTiff");
3315 : }
3316 : }
3317 2160 : else if (aosDriverNames.size() >= 2)
3318 : {
3319 3920 : if (bEmitWarning && !(EQUAL(aosDriverNames[0], "GTiff") &&
3320 1959 : EQUAL(aosDriverNames[1], "COG")))
3321 : {
3322 2 : CPLError(CE_Warning, CPLE_AppDefined,
3323 : "Several drivers matching %s extension. Using %s",
3324 : osExt.c_str(), aosDriverNames[0]);
3325 : }
3326 3922 : const std::string osDrvName = aosDriverNames[0];
3327 1961 : aosDriverNames.Clear();
3328 1961 : aosDriverNames.AddString(osDrvName.c_str());
3329 : }
3330 : }
3331 517 : else if (EQUAL(osExt.c_str(), "gdb") &&
3332 1 : IsOnlyExpectedGDBDrivers(aosDriverNames))
3333 : {
3334 : // Do not warn about that case given that FileGDB write support
3335 : // forwards to OpenFileGDB one. And also consider GPSBabel as too
3336 : // marginal to deserve the warning.
3337 1 : aosDriverNames.Clear();
3338 1 : aosDriverNames.AddString("OpenFileGDB");
3339 : }
3340 515 : else if (aosDriverNames.size() >= 2)
3341 : {
3342 0 : if (bEmitWarning)
3343 : {
3344 0 : CPLError(CE_Warning, CPLE_AppDefined,
3345 : "Several drivers matching %s %s. Using %s",
3346 0 : osMatchingPrefix.empty() ? osExt.c_str()
3347 0 : : osMatchingPrefix.c_str(),
3348 0 : osMatchingPrefix.empty() ? "extension" : "prefix",
3349 : aosDriverNames[0]);
3350 : }
3351 0 : const std::string osDrvName = aosDriverNames[0];
3352 0 : aosDriverNames.Clear();
3353 0 : aosDriverNames.AddString(osDrvName.c_str());
3354 : }
3355 : }
3356 :
3357 2791 : if (aosDriverNames.empty() && bEmitWarning &&
3358 2791 : aosMissingDriverNames.size() == 1 && poMissingPluginDriver)
3359 : {
3360 0 : CPLError(CE_Failure, CPLE_AppDefined,
3361 : "No installed driver matching %s %s, but %s driver is "
3362 : "known. However plugin %s",
3363 0 : osMatchingPrefix.empty() ? osExt.c_str()
3364 0 : : osMatchingPrefix.c_str(),
3365 0 : osMatchingPrefix.empty() ? "extension" : "prefix",
3366 0 : poMissingPluginDriver->GetDescription(),
3367 0 : GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver)
3368 : .c_str());
3369 : }
3370 2790 : else if (aosDriverNames.empty() && bEmitWarning &&
3371 30 : aosMissingDriverNames.empty())
3372 : {
3373 827 : for (const auto &sConnectionPrefix : asKnownConnectionPrefixes)
3374 : {
3375 798 : if (STARTS_WITH_CI(pszDestDataset, sConnectionPrefix.pszPrefix))
3376 : {
3377 1 : CPLError(CE_Failure, CPLE_AppDefined,
3378 : "Filename %s starts with the connection prefix of "
3379 : "driver %s, which is not enabled in this GDAL build. "
3380 : "If that filename is really intended, explicitly "
3381 : "specify its output format.",
3382 1 : pszDestDataset, sConnectionPrefix.pszDriverName);
3383 1 : break;
3384 : }
3385 : }
3386 : }
3387 :
3388 2760 : return aosDriverNames.StealList();
3389 : }
3390 :
3391 : /************************************************************************/
3392 : /* GDALGetMessageAboutMissingPluginDriver() */
3393 : /************************************************************************/
3394 :
3395 : std::string
3396 0 : GDALGetMessageAboutMissingPluginDriver(GDALDriver *poMissingPluginDriver)
3397 : {
3398 : std::string osMsg =
3399 0 : poMissingPluginDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME");
3400 : osMsg += " is not available in your "
3401 0 : "installation.";
3402 0 : if (const char *pszInstallationMsg = poMissingPluginDriver->GetMetadataItem(
3403 0 : GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE))
3404 : {
3405 0 : osMsg += " ";
3406 0 : osMsg += pszInstallationMsg;
3407 : }
3408 :
3409 : VSIStatBuf sStat;
3410 0 : if (const char *pszGDALDriverPath =
3411 0 : CPLGetConfigOption("GDAL_DRIVER_PATH", nullptr))
3412 : {
3413 0 : if (VSIStat(pszGDALDriverPath, &sStat) != 0)
3414 : {
3415 0 : if (osMsg.back() != '.')
3416 0 : osMsg += ".";
3417 0 : osMsg += " Directory '";
3418 0 : osMsg += pszGDALDriverPath;
3419 0 : osMsg += "' pointed by GDAL_DRIVER_PATH does not exist.";
3420 : }
3421 : }
3422 : else
3423 : {
3424 0 : if (osMsg.back() != '.')
3425 0 : osMsg += ".";
3426 : #ifdef INSTALL_PLUGIN_FULL_DIR
3427 : if (VSIStat(INSTALL_PLUGIN_FULL_DIR, &sStat) != 0)
3428 : {
3429 : osMsg += " Directory '";
3430 : osMsg += INSTALL_PLUGIN_FULL_DIR;
3431 : osMsg += "' hardcoded in the GDAL library does not "
3432 : "exist and the GDAL_DRIVER_PATH "
3433 : "configuration option is not set.";
3434 : }
3435 : else
3436 : #endif
3437 : {
3438 : osMsg += " The GDAL_DRIVER_PATH configuration "
3439 0 : "option is not set.";
3440 : }
3441 : }
3442 0 : return osMsg;
3443 : }
3444 :
3445 : /************************************************************************/
3446 : /* GDALClearMemoryCaches() */
3447 : /************************************************************************/
3448 :
3449 : /**
3450 : * \brief Clear all GDAL-controlled in-memory caches.
3451 : *
3452 : * Iterates registered drivers and calls their pfnClearCaches callback if set,
3453 : * then calls VSICurlClearCache() to clear /vsicurl/ and related caches.
3454 : *
3455 : * Note that neither the global raster block cache or caches specific to open
3456 : * dataset objects are not cleared by this function (in its current implementation).
3457 : *
3458 : * Useful when remote datasets may have changed during the lifetime of a
3459 : * process.
3460 : *
3461 : * @since GDAL 3.13
3462 : */
3463 4 : void GDALClearMemoryCaches()
3464 : {
3465 4 : auto *poDM = GetGDALDriverManager();
3466 4 : if (poDM)
3467 : {
3468 920 : for (int i = 0; i < poDM->GetDriverCount(); i++)
3469 : {
3470 916 : auto *poDriver = poDM->GetDriver(i);
3471 916 : if (poDriver && poDriver->pfnClearCaches)
3472 4 : poDriver->pfnClearCaches(poDriver);
3473 : }
3474 : }
3475 4 : VSICurlClearCache();
3476 4 : }
|