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 460042 : GDALDriver::~GDALDriver()
50 :
51 : {
52 259583 : if (pfnUnloadDriver != nullptr)
53 6957 : pfnUnloadDriver(this);
54 460042 : }
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 514111 : GDALDataset *GDALDriver::Open(GDALOpenInfo *poOpenInfo, bool bSetOpenOptions)
99 : {
100 :
101 514111 : GDALDataset *poDS = nullptr;
102 514111 : pfnOpen = GetOpenCallback();
103 514111 : if (pfnOpen != nullptr)
104 : {
105 514108 : poDS = pfnOpen(poOpenInfo);
106 : }
107 3 : else if (pfnOpenWithDriverArg != nullptr)
108 : {
109 3 : poDS = pfnOpenWithDriverArg(this, poOpenInfo);
110 : }
111 :
112 514111 : if (poDS)
113 : {
114 : // Only set GDAL_OF_THREAD_SAFE if the driver itself has set it in
115 : // poDS->nOpenFlags
116 62486 : int nOpenFlags = poOpenInfo->nOpenFlags &
117 : ~(GDAL_OF_FROM_GDALOPEN | GDAL_OF_THREAD_SAFE);
118 62486 : if (poDS->nOpenFlags & GDAL_OF_THREAD_SAFE)
119 914 : nOpenFlags |= GDAL_OF_THREAD_SAFE;
120 62486 : poDS->nOpenFlags = nOpenFlags;
121 :
122 62486 : if (strlen(poDS->GetDescription()) == 0)
123 14125 : poDS->SetDescription(poOpenInfo->pszFilename);
124 :
125 62486 : if (poDS->poDriver == nullptr)
126 58520 : poDS->poDriver = this;
127 :
128 62486 : if (poDS->papszOpenOptions == nullptr && bSetOpenOptions)
129 : {
130 29 : poDS->papszOpenOptions = CSLDuplicate(poOpenInfo->papszOpenOptions);
131 : }
132 :
133 62486 : if (!(poOpenInfo->nOpenFlags & GDAL_OF_INTERNAL))
134 : {
135 49998 : 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 49992 : CPLDebug("GDAL", "GDALOpen(%s, this=%p) succeeds as %s.",
145 49992 : poOpenInfo->pszFilename, poDS, GetDescription());
146 :
147 49998 : poDS->AddToDatasetOpenList();
148 : }
149 : }
150 :
151 514111 : 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 25401 : 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 25401 : pfnCreate = GetCreateCallback();
202 25401 : 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 25400 : 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 25399 : if (CPL_UNLIKELY(GetMetadataItem(GDAL_DCAP_RASTER) != nullptr &&
224 : GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr &&
225 25399 : (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 25397 : 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 25396 : 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 25377 : if (!EQUAL(GetDescription(), "MEM") &&
255 39003 : !EQUAL(GetDescription(), "Memory") &&
256 : // ogr2ogr -f PostgreSQL might reach the Delete method of the
257 : // PostgisRaster driver which is undesirable
258 13626 : !EQUAL(GetDescription(), "PostgreSQL"))
259 : {
260 13624 : QuietDelete(pszFilename);
261 : }
262 : }
263 :
264 : /* -------------------------------------------------------------------- */
265 : /* Validate creation options. */
266 : /* -------------------------------------------------------------------- */
267 25396 : if (CPLTestBool(
268 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
269 25396 : GDALValidateCreationOptions(this, papszOptions);
270 :
271 : /* -------------------------------------------------------------------- */
272 : /* Proceed with creation. */
273 : /* -------------------------------------------------------------------- */
274 50792 : CPLDebug("GDAL", "GDALDriver::Create(%s,%s,%d,%d,%d,%s,%p)",
275 25396 : GetDescription(), pszFilename, nXSize, nYSize, nBands,
276 : GDALGetDataTypeName(eType), papszOptions);
277 :
278 25396 : GDALDataset *poDS = nullptr;
279 25396 : if (pfnCreateEx != nullptr)
280 : {
281 0 : poDS = pfnCreateEx(this, pszFilename, nXSize, nYSize, nBands, eType,
282 : const_cast<char **>(papszOptions));
283 : }
284 25396 : else if (pfnCreate != nullptr)
285 : {
286 25396 : 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 25396 : if (poDS != nullptr)
296 : {
297 48192 : if (poDS->GetDescription() == nullptr ||
298 24096 : strlen(poDS->GetDescription()) == 0)
299 21417 : poDS->SetDescription(pszFilename);
300 :
301 24096 : if (poDS->poDriver == nullptr)
302 23363 : poDS->poDriver = this;
303 :
304 24096 : poDS->AddToDatasetOpenList();
305 : }
306 :
307 25396 : 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 20935 : 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 20935 : VALIDATE_POINTER1(hDriver, "GDALCreate", nullptr);
328 :
329 20935 : GDALDatasetH hDS = GDALDriver::FromHandle(hDriver)->Create(
330 : pszFilename, nXSize, nYSize, nBands, eBandType, papszOptions);
331 :
332 : #ifdef OGRAPISPY_ENABLED
333 20935 : if (nBands < 1)
334 : {
335 3915 : OGRAPISpyCreateDataSource(hDriver, pszFilename,
336 : const_cast<char **>(papszOptions), hDS);
337 : }
338 : #endif
339 :
340 20935 : return hDS;
341 : }
342 :
343 : /************************************************************************/
344 : /* CreateMultiDimensional() */
345 : /************************************************************************/
346 :
347 : /**
348 : * \brief Create a new multidimensional dataset with this driver.
349 : *
350 : * Only drivers that advertise the GDAL_DCAP_MULTIDIM_RASTER capability and
351 : * implement the pfnCreateMultiDimensional method might return a non nullptr
352 : * GDALDataset.
353 : *
354 : * This is the same as the C function GDALCreateMultiDimensional().
355 : *
356 : * @param pszFilename the name of the dataset to create. UTF-8 encoded.
357 : * @param papszRootGroupOptions driver specific options regarding the creation
358 : * of the root group. Might be nullptr.
359 : * @param papszOptions driver specific options regarding the creation
360 : * of the dataset. Might be nullptr.
361 : * @return a new dataset, or nullptr in case of failure.
362 : *
363 : * @since GDAL 3.1
364 : */
365 :
366 : GDALDataset *
367 566 : GDALDriver::CreateMultiDimensional(const char *pszFilename,
368 : CSLConstList papszRootGroupOptions,
369 : CSLConstList papszOptions)
370 :
371 : {
372 : /* -------------------------------------------------------------------- */
373 : /* Does this format support creation. */
374 : /* -------------------------------------------------------------------- */
375 566 : pfnCreateMultiDimensional = GetCreateMultiDimensionalCallback();
376 566 : if (pfnCreateMultiDimensional == nullptr)
377 : {
378 0 : CPLError(CE_Failure, CPLE_NotSupported,
379 : "GDALDriver::CreateMultiDimensional() ... "
380 : "no CreateMultiDimensional method implemented "
381 : "for this format.");
382 :
383 0 : return nullptr;
384 : }
385 :
386 : /* -------------------------------------------------------------------- */
387 : /* Validate creation options. */
388 : /* -------------------------------------------------------------------- */
389 566 : if (CPLTestBool(
390 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
391 : {
392 : const char *pszOptionList =
393 566 : GetMetadataItem(GDAL_DMD_MULTIDIM_DATASET_CREATIONOPTIONLIST);
394 1132 : CPLString osDriver;
395 566 : osDriver.Printf("driver %s", GetDescription());
396 566 : GDALValidateOptions(pszOptionList, papszOptions, "creation option",
397 : osDriver);
398 : }
399 :
400 566 : auto poDstDS = pfnCreateMultiDimensional(pszFilename, papszRootGroupOptions,
401 : papszOptions);
402 :
403 566 : if (poDstDS != nullptr)
404 : {
405 1128 : if (poDstDS->GetDescription() == nullptr ||
406 564 : strlen(poDstDS->GetDescription()) == 0)
407 147 : poDstDS->SetDescription(pszFilename);
408 :
409 564 : if (poDstDS->poDriver == nullptr)
410 562 : poDstDS->poDriver = this;
411 : }
412 :
413 566 : return poDstDS;
414 : }
415 :
416 : /************************************************************************/
417 : /* GDALCreateMultiDimensional() */
418 : /************************************************************************/
419 :
420 : /** \brief Create a new multidimensional dataset with this driver.
421 : *
422 : * This is the same as the C++ method GDALDriver::CreateMultiDimensional().
423 : */
424 514 : GDALDatasetH GDALCreateMultiDimensional(GDALDriverH hDriver,
425 : const char *pszName,
426 : CSLConstList papszRootGroupOptions,
427 : CSLConstList papszOptions)
428 : {
429 514 : VALIDATE_POINTER1(hDriver, __func__, nullptr);
430 514 : VALIDATE_POINTER1(pszName, __func__, nullptr);
431 514 : return GDALDataset::ToHandle(
432 : GDALDriver::FromHandle(hDriver)->CreateMultiDimensional(
433 514 : pszName, papszRootGroupOptions, papszOptions));
434 : }
435 :
436 : /************************************************************************/
437 : /* DefaultCreateCopyMultiDimensional() */
438 : /************************************************************************/
439 :
440 : //! @cond Doxygen_Suppress
441 :
442 27 : CPLErr GDALDriver::DefaultCreateCopyMultiDimensional(
443 : GDALDataset *poSrcDS, GDALDataset *poDstDS, bool bStrict,
444 : CSLConstList papszOptions, GDALProgressFunc pfnProgress,
445 : void *pProgressData)
446 : {
447 27 : if (pfnProgress == nullptr)
448 3 : pfnProgress = GDALDummyProgress;
449 :
450 54 : auto poSrcRG = poSrcDS->GetRootGroup();
451 27 : if (!poSrcRG)
452 0 : return CE_Failure;
453 54 : auto poDstRG = poDstDS->GetRootGroup();
454 27 : if (!poDstRG)
455 0 : return CE_Failure;
456 27 : GUInt64 nCurCost = 0;
457 54 : return poDstRG->CopyFrom(poDstRG, poSrcDS, poSrcRG, bStrict, nCurCost,
458 : poSrcRG->GetTotalCopyCost(), pfnProgress,
459 27 : pProgressData, papszOptions)
460 27 : ? CE_None
461 27 : : CE_Failure;
462 : }
463 :
464 : //! @endcond
465 :
466 : /************************************************************************/
467 : /* DefaultCopyMasks() */
468 : /************************************************************************/
469 :
470 : //! @cond Doxygen_Suppress
471 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 8302 : CPLErr GDALDriver::DefaultCopyMasks(GDALDataset *poSrcDS, GDALDataset *poDstDS,
480 : int bStrict, CSLConstList /*papszOptions*/,
481 : GDALProgressFunc pfnProgress,
482 : void *pProgressData)
483 :
484 : {
485 8302 : if (pfnProgress == nullptr)
486 6231 : pfnProgress = GDALDummyProgress;
487 :
488 8302 : int nBands = poSrcDS->GetRasterCount();
489 8302 : if (nBands == 0)
490 0 : return CE_None;
491 :
492 : /* -------------------------------------------------------------------- */
493 : /* Try to copy mask if it seems appropriate. */
494 : /* -------------------------------------------------------------------- */
495 8302 : const char *papszOptions[2] = {"COMPRESSED=YES", nullptr};
496 8302 : CPLErr eErr = CE_None;
497 :
498 8302 : int nTotalBandsWithMask = 0;
499 28661 : for (int iBand = 0; iBand < nBands; ++iBand)
500 : {
501 20359 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
502 :
503 20359 : int nMaskFlags = poSrcBand->GetMaskFlags();
504 20359 : if (!(nMaskFlags &
505 : (GMF_ALL_VALID | GMF_PER_DATASET | GMF_ALPHA | GMF_NODATA)))
506 : {
507 8 : nTotalBandsWithMask++;
508 : }
509 : }
510 :
511 8302 : int iBandWithMask = 0;
512 28661 : for (int iBand = 0; eErr == CE_None && iBand < nBands; ++iBand)
513 : {
514 20359 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
515 :
516 20359 : int nMaskFlags = poSrcBand->GetMaskFlags();
517 20359 : 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 8302 : const int nMaskFlags = poSrcDS->GetRasterBand(1)->GetMaskFlags();
549 8302 : if (eErr == CE_None &&
550 8302 : !(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 8302 : 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 12223 : 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 23810 : if (!EQUAL(GetDescription(), "MEM") && !EQUAL(GetDescription(), "Memory") &&
1014 : // VRT with empty name is a un-materialized dataset
1015 11587 : !(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 34699 : !EQUAL(GetDescription(), "GeoRaster") &&
1019 10889 : !EQUAL(GetDescription(), "PostGISRaster"))
1020 : {
1021 : /* --------------------------------------------------------------------
1022 : */
1023 : /* Establish list of files of output dataset if it already
1024 : * exists. */
1025 : /* --------------------------------------------------------------------
1026 : */
1027 21742 : std::set<std::string> oSetExistingDestFiles;
1028 : {
1029 21742 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1030 10871 : const char *const apszAllowedDrivers[] = {GetDescription(),
1031 10871 : nullptr};
1032 : auto poExistingOutputDS =
1033 : std::unique_ptr<GDALDataset>(GDALDataset::Open(
1034 21742 : pszFilename, GDAL_OF_RASTER, apszAllowedDrivers));
1035 10871 : 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 21742 : std::set<std::string> oSetExistingDestFilesFoundInSource;
1053 10871 : 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 10871 : 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 10871 : QuietDelete(pszFilename);
1098 : }
1099 :
1100 12223 : 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 11646 : GDALDataset *GDALDriver::CreateCopy(const char *pszFilename,
1189 : GDALDataset *poSrcDS, int bStrict,
1190 : CSLConstList papszOptions,
1191 : GDALProgressFunc pfnProgress,
1192 : void *pProgressData)
1193 :
1194 : {
1195 11646 : if (pfnProgress == nullptr)
1196 8769 : pfnProgress = GDALDummyProgress;
1197 :
1198 11646 : 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 11646 : char **papszOptionsToDelete = nullptr;
1205 : const char *srcInterleave =
1206 11646 : poSrcDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
1207 6903 : if (nBandCount > 1 && srcInterleave != nullptr &&
1208 25058 : 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 11646 : 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 23267 : if (!bAppendSubdataset &&
1292 11621 : CPLFetchBool(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY", true))
1293 : {
1294 8930 : QuietDeleteForCreateCopy(pszFilename, poSrcDS);
1295 : }
1296 :
1297 : int iIdxQuietDeleteOnCreateCopy =
1298 11646 : CSLPartialFindString(papszOptions, "@QUIET_DELETE_ON_CREATE_COPY=");
1299 11646 : 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 11646 : CSLPartialFindString(papszOptions, "_INTERNAL_DATASET=");
1314 11646 : bool bInternalDataset = false;
1315 11646 : 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 11646 : if (CPLTestBool(
1330 : CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
1331 : {
1332 23292 : auto poSrcGroup = poSrcDS->GetRootGroup();
1333 11646 : 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 11533 : GDALValidateCreationOptions(this, papszOptions);
1346 : }
1347 : }
1348 :
1349 : /* -------------------------------------------------------------------- */
1350 : /* Advise the source raster that we are going to read it completely */
1351 : /* -------------------------------------------------------------------- */
1352 :
1353 11646 : const int nXSize = poSrcDS->GetRasterXSize();
1354 11646 : const int nYSize = poSrcDS->GetRasterYSize();
1355 11646 : GDALDataType eDT = GDT_Unknown;
1356 11646 : if (nBandCount > 0)
1357 : {
1358 11410 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
1359 11410 : if (poSrcBand)
1360 11410 : eDT = poSrcBand->GetRasterDataType();
1361 : }
1362 11646 : poSrcDS->AdviseRead(0, 0, nXSize, nYSize, nXSize, nYSize, eDT, nBandCount,
1363 11646 : 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 11646 : GDALDataset *poDstDS = nullptr;
1371 11646 : auto l_pfnCreateCopy = GetCreateCopyCallback();
1372 22120 : if (l_pfnCreateCopy != nullptr &&
1373 10474 : !CPLTestBool(CPLGetConfigOption("GDAL_DEFAULT_CREATE_COPY", "NO")))
1374 : {
1375 10474 : poDstDS = l_pfnCreateCopy(pszFilename, poSrcDS, bStrict,
1376 : const_cast<char **>(papszOptions),
1377 : pfnProgress, pProgressData);
1378 10474 : if (poDstDS != nullptr)
1379 : {
1380 18430 : if (poDstDS->GetDescription() == nullptr ||
1381 9215 : strlen(poDstDS->GetDescription()) == 0)
1382 445 : poDstDS->SetDescription(pszFilename);
1383 :
1384 9215 : if (poDstDS->poDriver == nullptr)
1385 8176 : poDstDS->poDriver = this;
1386 :
1387 9215 : if (!bInternalDataset)
1388 5049 : poDstDS->AddToDatasetOpenList();
1389 : }
1390 : }
1391 : else
1392 : {
1393 1172 : poDstDS = DefaultCreateCopy(pszFilename, poSrcDS, bStrict, papszOptions,
1394 : pfnProgress, pProgressData);
1395 : }
1396 :
1397 11646 : CSLDestroy(papszOptionsToDelete);
1398 11646 : 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 6795 : 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 6795 : VALIDATE_POINTER1(hDriver, "GDALCreateCopy", nullptr);
1420 6795 : VALIDATE_POINTER1(hSrcDS, "GDALCreateCopy", nullptr);
1421 :
1422 6795 : return GDALDriver::FromHandle(hDriver)->CreateCopy(
1423 : pszFilename, GDALDataset::FromHandle(hSrcDS), bStrict, papszOptions,
1424 6795 : 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 949 : bool GDALDriver::CanVectorTranslateFrom(
1448 : const char *pszDestName, GDALDataset *poSourceDS,
1449 : CSLConstList papszVectorTranslateArguments, char ***ppapszFailureReasons)
1450 :
1451 : {
1452 949 : if (ppapszFailureReasons)
1453 : {
1454 0 : *ppapszFailureReasons = nullptr;
1455 : }
1456 :
1457 949 : if (!pfnCanVectorTranslateFrom)
1458 : {
1459 943 : if (ppapszFailureReasons)
1460 : {
1461 0 : *ppapszFailureReasons = CSLAddString(
1462 : nullptr,
1463 : "CanVectorTranslateFrom() not implemented for this driver");
1464 : }
1465 943 : 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 24495 : CPLErr GDALDriver::QuietDelete(const char *pszName,
1600 : CSLConstList papszAllowedDrivers)
1601 :
1602 : {
1603 : VSIStatBufL sStat;
1604 : const bool bExists =
1605 24495 : VSIStatExL(pszName, &sStat,
1606 24495 : VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0;
1607 :
1608 : #ifdef S_ISFIFO
1609 24495 : if (bExists && S_ISFIFO(sStat.st_mode))
1610 0 : return CE_None;
1611 : #endif
1612 :
1613 24495 : GDALDriver *poDriver = nullptr;
1614 24495 : 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 48990 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
1640 24495 : poDriver = GDALDriver::FromHandle(GDALIdentifyDriver(pszName, nullptr));
1641 : }
1642 :
1643 24495 : if (poDriver == nullptr)
1644 23611 : return CE_None;
1645 :
1646 926 : if (bExists && VSI_ISDIR(sStat.st_mode) &&
1647 42 : (EQUAL(poDriver->GetDescription(), "MapInfo File") ||
1648 42 : 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 42 : 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 4398 : CPLErr GDALDriver::Delete(const char *pszFilename)
1696 :
1697 : {
1698 4398 : pfnDelete = GetDeleteCallback();
1699 4398 : if (pfnDelete != nullptr)
1700 1045 : 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 3127 : CPLErr GDALDriver::Delete(GDALDataset *poDS, CSLConstList papszFileList)
1764 :
1765 : {
1766 3127 : if (poDS)
1767 : {
1768 10 : pfnDelete = GetDeleteCallback();
1769 10 : if (pfnDelete != nullptr)
1770 6 : 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 8691460 : const char *CPL_STDCALL GDALGetDriverShortName(GDALDriverH hDriver)
2156 :
2157 : {
2158 8691460 : VALIDATE_POINTER1(hDriver, "GDALGetDriverShortName", nullptr);
2159 :
2160 8691460 : 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 512 : const char *CPL_STDCALL GDALGetDriverLongName(GDALDriverH hDriver)
2178 :
2179 : {
2180 512 : VALIDATE_POINTER1(hDriver, "GDALGetDriverLongName", nullptr);
2181 :
2182 : const char *pszLongName =
2183 512 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(GDAL_DMD_LONGNAME);
2184 :
2185 512 : if (pszLongName == nullptr)
2186 0 : return "";
2187 :
2188 512 : 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 37205 : int CPL_STDCALL GDALValidateCreationOptions(GDALDriverH hDriver,
2273 : CSLConstList papszCreationOptions)
2274 : {
2275 37205 : VALIDATE_POINTER1(hDriver, "GDALValidateCreationOptions", FALSE);
2276 : const char *pszOptionList =
2277 37205 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2278 37205 : GDAL_DMD_CREATIONOPTIONLIST);
2279 37205 : CPLString osDriver;
2280 : osDriver.Printf("driver %s",
2281 37205 : GDALDriver::FromHandle(hDriver)->GetDescription());
2282 37205 : bool bFoundOptionToRemove = false;
2283 37205 : constexpr const char *const apszExcludedOptions[] = {
2284 : "APPEND_SUBDATASET", "COPY_SRC_MDD", "SRC_MDD", "SKIP_HOLES"};
2285 54670 : for (const char *pszCO : cpl::Iterate(papszCreationOptions))
2286 : {
2287 87968 : for (const char *pszExcludedOptions : apszExcludedOptions)
2288 : {
2289 70503 : if (STARTS_WITH_CI(pszCO, pszExcludedOptions) &&
2290 205 : pszCO[strlen(pszExcludedOptions)] == '=')
2291 : {
2292 205 : bFoundOptionToRemove = true;
2293 205 : break;
2294 : }
2295 : }
2296 17670 : if (bFoundOptionToRemove)
2297 205 : break;
2298 : }
2299 37205 : CSLConstList papszOptionsToValidate = papszCreationOptions;
2300 37205 : char **papszOptionsToFree = nullptr;
2301 37205 : 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 37205 : const bool bRet = CPL_TO_BOOL(GDALValidateOptions(
2322 : pszOptionList, papszOptionsToValidate, "creation option", osDriver));
2323 37205 : CSLDestroy(papszOptionsToFree);
2324 37205 : return bRet;
2325 : }
2326 :
2327 : /************************************************************************/
2328 : /* GDALValidateOpenOptions() */
2329 : /************************************************************************/
2330 :
2331 63436 : int GDALValidateOpenOptions(GDALDriverH hDriver,
2332 : const char *const *papszOpenOptions)
2333 : {
2334 63436 : VALIDATE_POINTER1(hDriver, "GDALValidateOpenOptions", FALSE);
2335 : const char *pszOptionList =
2336 63436 : GDALDriver::FromHandle(hDriver)->GetMetadataItem(
2337 63436 : GDAL_DMD_OPENOPTIONLIST);
2338 126872 : CPLString osDriver;
2339 : osDriver.Printf("driver %s",
2340 63436 : GDALDriver::FromHandle(hDriver)->GetDescription());
2341 63436 : return GDALValidateOptions(pszOptionList, papszOpenOptions, "open option",
2342 63436 : osDriver);
2343 : }
2344 :
2345 : /************************************************************************/
2346 : /* GDALValidateOptions() */
2347 : /************************************************************************/
2348 :
2349 115206 : int GDALValidateOptions(const char *pszOptionList,
2350 : const char *const *papszOptionsToValidate,
2351 : const char *pszErrorMessageOptionType,
2352 : const char *pszErrorMessageContainerName)
2353 : {
2354 115206 : if (papszOptionsToValidate == nullptr || *papszOptionsToValidate == nullptr)
2355 97463 : return TRUE;
2356 17743 : if (pszOptionList == nullptr)
2357 181 : return TRUE;
2358 :
2359 17562 : CPLXMLNode *psNode = CPLParseXMLString(pszOptionList);
2360 17562 : if (psNode == nullptr)
2361 : {
2362 0 : CPLError(CE_Warning, CPLE_AppDefined,
2363 : "Could not parse %s list of %s. Assuming options are valid.",
2364 : pszErrorMessageOptionType, pszErrorMessageContainerName);
2365 0 : return TRUE;
2366 : }
2367 :
2368 17562 : bool bRet = true;
2369 48048 : while (*papszOptionsToValidate)
2370 : {
2371 30486 : char *pszKey = nullptr;
2372 : const char *pszValue =
2373 30486 : CPLParseNameValue(*papszOptionsToValidate, &pszKey);
2374 30486 : if (pszKey == nullptr)
2375 : {
2376 1 : CPLError(CE_Warning, CPLE_NotSupported,
2377 : "%s '%s' is not formatted with the key=value format",
2378 : pszErrorMessageOptionType, *papszOptionsToValidate);
2379 1 : bRet = false;
2380 :
2381 1 : ++papszOptionsToValidate;
2382 2370 : continue;
2383 : }
2384 :
2385 30485 : if (EQUAL(pszKey, "VALIDATE_OPEN_OPTIONS"))
2386 : {
2387 0 : ++papszOptionsToValidate;
2388 0 : CPLFree(pszKey);
2389 0 : continue;
2390 : }
2391 :
2392 : // Must we be forgiving in case of missing option ?
2393 30485 : bool bWarnIfMissingKey = true;
2394 30485 : if (pszKey[0] == '@')
2395 : {
2396 2352 : bWarnIfMissingKey = false;
2397 2352 : memmove(pszKey, pszKey + 1, strlen(pszKey + 1) + 1);
2398 : }
2399 :
2400 30485 : CPLXMLNode *psChildNode = psNode->psChild;
2401 308321 : while (psChildNode)
2402 : {
2403 305952 : if (EQUAL(psChildNode->pszValue, "OPTION"))
2404 : {
2405 : const char *pszOptionName =
2406 305952 : CPLGetXMLValue(psChildNode, "name", "");
2407 : /* For option names terminated by wildcard (NITF BLOCKA option
2408 : * names for example) */
2409 305952 : if (strlen(pszOptionName) > 0 &&
2410 305952 : pszOptionName[strlen(pszOptionName) - 1] == '*' &&
2411 1288 : EQUALN(pszOptionName, pszKey, strlen(pszOptionName) - 1))
2412 : {
2413 216 : break;
2414 : }
2415 :
2416 : /* For option names beginning by a wildcard */
2417 305736 : if (pszOptionName[0] == '*' &&
2418 57 : strlen(pszKey) > strlen(pszOptionName) &&
2419 9 : EQUAL(pszKey + strlen(pszKey) - strlen(pszOptionName + 1),
2420 : pszOptionName + 1))
2421 : {
2422 2 : break;
2423 : }
2424 :
2425 : // For options names with * in the middle
2426 305734 : const char *pszStarInOptionName = strchr(pszOptionName, '*');
2427 305734 : if (pszStarInOptionName &&
2428 1093 : pszStarInOptionName != pszOptionName &&
2429 : pszStarInOptionName !=
2430 1093 : pszOptionName + strlen(pszOptionName) - 1 &&
2431 21 : strlen(pszKey) > static_cast<size_t>(pszStarInOptionName -
2432 12 : pszOptionName) &&
2433 12 : EQUALN(pszKey, pszOptionName,
2434 : static_cast<size_t>(pszStarInOptionName -
2435 12 : pszOptionName)) &&
2436 12 : EQUAL(pszKey +
2437 : static_cast<size_t>(pszStarInOptionName -
2438 : pszOptionName) +
2439 : 1,
2440 : pszStarInOptionName + 1))
2441 : {
2442 6 : break;
2443 : }
2444 :
2445 305728 : if (EQUAL(pszOptionName, pszKey))
2446 : {
2447 27780 : break;
2448 : }
2449 : const char *pszAlias =
2450 277948 : CPLGetXMLValue(psChildNode, "alias", nullptr);
2451 : const char *pszDeprecatedAlias =
2452 277948 : pszAlias ? nullptr
2453 277041 : : CPLGetXMLValue(psChildNode, "deprecated_alias",
2454 277948 : nullptr);
2455 277948 : if (!pszAlias && pszDeprecatedAlias)
2456 159 : pszAlias = pszDeprecatedAlias;
2457 277948 : if (pszAlias && EQUAL(pszAlias, pszKey))
2458 : {
2459 112 : if (pszDeprecatedAlias)
2460 : {
2461 0 : CPLDebug(
2462 : "GDAL",
2463 : "Using deprecated alias '%s'. New name is '%s'",
2464 : pszAlias, pszOptionName);
2465 : }
2466 112 : break;
2467 : }
2468 : }
2469 277836 : psChildNode = psChildNode->psNext;
2470 : }
2471 30485 : if (psChildNode == nullptr)
2472 : {
2473 2393 : if (bWarnIfMissingKey &&
2474 24 : (!EQUAL(pszErrorMessageOptionType, "open option") ||
2475 2 : CPLFetchBool(papszOptionsToValidate, "VALIDATE_OPEN_OPTIONS",
2476 : true)))
2477 : {
2478 24 : CPLError(CE_Warning, CPLE_NotSupported,
2479 : "%s does not support %s %s",
2480 : pszErrorMessageContainerName,
2481 : pszErrorMessageOptionType, pszKey);
2482 24 : bRet = false;
2483 : }
2484 :
2485 2369 : CPLFree(pszKey);
2486 2369 : ++papszOptionsToValidate;
2487 2369 : continue;
2488 : }
2489 :
2490 : #ifdef DEBUG
2491 28116 : CPLXMLNode *psChildSubNode = psChildNode->psChild;
2492 166917 : while (psChildSubNode)
2493 : {
2494 138801 : if (psChildSubNode->eType == CXT_Attribute)
2495 : {
2496 97287 : if (!(EQUAL(psChildSubNode->pszValue, "name") ||
2497 69171 : EQUAL(psChildSubNode->pszValue, "alias") ||
2498 68976 : EQUAL(psChildSubNode->pszValue, "deprecated_alias") ||
2499 68889 : EQUAL(psChildSubNode->pszValue, "alt_config_option") ||
2500 68869 : EQUAL(psChildSubNode->pszValue, "description") ||
2501 45247 : EQUAL(psChildSubNode->pszValue, "type") ||
2502 17131 : EQUAL(psChildSubNode->pszValue, "min") ||
2503 16812 : EQUAL(psChildSubNode->pszValue, "max") ||
2504 16424 : EQUAL(psChildSubNode->pszValue, "default") ||
2505 1032 : EQUAL(psChildSubNode->pszValue, "maxsize") ||
2506 1002 : EQUAL(psChildSubNode->pszValue, "required") ||
2507 947 : EQUAL(psChildSubNode->pszValue, "scope")))
2508 : {
2509 : /* Driver error */
2510 0 : CPLError(CE_Warning, CPLE_NotSupported,
2511 : "%s : unhandled attribute '%s' for %s %s.",
2512 : pszErrorMessageContainerName,
2513 : psChildSubNode->pszValue, pszKey,
2514 : pszErrorMessageOptionType);
2515 : }
2516 : }
2517 138801 : psChildSubNode = psChildSubNode->psNext;
2518 : }
2519 : #endif
2520 :
2521 28116 : const char *pszType = CPLGetXMLValue(psChildNode, "type", nullptr);
2522 28116 : const char *pszMin = CPLGetXMLValue(psChildNode, "min", nullptr);
2523 28116 : const char *pszMax = CPLGetXMLValue(psChildNode, "max", nullptr);
2524 28116 : if (pszType != nullptr)
2525 : {
2526 28116 : if (EQUAL(pszType, "INT") || EQUAL(pszType, "INTEGER"))
2527 : {
2528 8799 : const char *pszValueIter = pszValue;
2529 22577 : while (*pszValueIter)
2530 : {
2531 13828 : if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
2532 69 : *pszValueIter == '+' || *pszValueIter == '-'))
2533 : {
2534 50 : CPLError(CE_Warning, CPLE_NotSupported,
2535 : "'%s' is an unexpected value for %s %s of "
2536 : "type int.",
2537 : pszValue, pszKey, pszErrorMessageOptionType);
2538 50 : bRet = false;
2539 50 : break;
2540 : }
2541 13778 : ++pszValueIter;
2542 : }
2543 8799 : if (*pszValueIter == '\0')
2544 : {
2545 8749 : if (pszMin && atoi(pszValue) < atoi(pszMin))
2546 : {
2547 10 : CPLError(CE_Warning, CPLE_NotSupported,
2548 : "'%s' is an unexpected value for %s %s that "
2549 : "should be >= %s.",
2550 : pszValue, pszKey, pszErrorMessageOptionType,
2551 : pszMin);
2552 10 : bRet = false;
2553 : }
2554 8749 : if (pszMax && atoi(pszValue) > atoi(pszMax))
2555 : {
2556 12 : CPLError(CE_Warning, CPLE_NotSupported,
2557 : "'%s' is an unexpected value for %s %s that "
2558 : "should be <= %s.",
2559 : pszValue, pszKey, pszErrorMessageOptionType,
2560 : pszMax);
2561 12 : bRet = false;
2562 : }
2563 8799 : }
2564 : }
2565 19317 : else if (EQUAL(pszType, "UNSIGNED INT"))
2566 : {
2567 3 : const char *pszValueIter = pszValue;
2568 10 : while (*pszValueIter)
2569 : {
2570 7 : if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
2571 0 : *pszValueIter == '+'))
2572 : {
2573 0 : CPLError(CE_Warning, CPLE_NotSupported,
2574 : "'%s' is an unexpected value for %s %s of "
2575 : "type unsigned int.",
2576 : pszValue, pszKey, pszErrorMessageOptionType);
2577 0 : bRet = false;
2578 0 : break;
2579 : }
2580 7 : ++pszValueIter;
2581 : }
2582 3 : if (*pszValueIter == '\0')
2583 : {
2584 3 : if (pszMin && atoi(pszValue) < atoi(pszMin))
2585 : {
2586 0 : 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 0 : bRet = false;
2592 : }
2593 3 : if (pszMax && atoi(pszValue) > atoi(pszMax))
2594 : {
2595 0 : 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 0 : bRet = false;
2601 : }
2602 : }
2603 : }
2604 19314 : else if (EQUAL(pszType, "FLOAT"))
2605 : {
2606 772 : char *endPtr = nullptr;
2607 772 : double dfVal = CPLStrtod(pszValue, &endPtr);
2608 772 : if (!(endPtr == nullptr || *endPtr == '\0'))
2609 : {
2610 2 : CPLError(
2611 : CE_Warning, CPLE_NotSupported,
2612 : "'%s' is an unexpected value for %s %s of type float.",
2613 : pszValue, pszKey, pszErrorMessageOptionType);
2614 2 : bRet = false;
2615 : }
2616 : else
2617 : {
2618 770 : if (pszMin && dfVal < CPLAtof(pszMin))
2619 : {
2620 3 : CPLError(CE_Warning, CPLE_NotSupported,
2621 : "'%s' is an unexpected value for %s %s that "
2622 : "should be >= %s.",
2623 : pszValue, pszKey, pszErrorMessageOptionType,
2624 : pszMin);
2625 3 : bRet = false;
2626 : }
2627 770 : if (pszMax && dfVal > CPLAtof(pszMax))
2628 : {
2629 0 : CPLError(CE_Warning, CPLE_NotSupported,
2630 : "'%s' is an unexpected value for %s %s that "
2631 : "should be <= %s.",
2632 : pszValue, pszKey, pszErrorMessageOptionType,
2633 : pszMax);
2634 0 : bRet = false;
2635 : }
2636 : }
2637 : }
2638 18542 : else if (EQUAL(pszType, "BOOLEAN"))
2639 : {
2640 4187 : if (!(EQUAL(pszValue, "ON") || EQUAL(pszValue, "TRUE") ||
2641 4117 : EQUAL(pszValue, "YES") || EQUAL(pszValue, "OFF") ||
2642 489 : EQUAL(pszValue, "FALSE") || EQUAL(pszValue, "NO")))
2643 : {
2644 0 : CPLError(CE_Warning, CPLE_NotSupported,
2645 : "'%s' is an unexpected value for %s %s of type "
2646 : "boolean.",
2647 : pszValue, pszKey, pszErrorMessageOptionType);
2648 0 : bRet = false;
2649 : }
2650 : }
2651 14355 : else if (EQUAL(pszType, "STRING-SELECT"))
2652 : {
2653 7406 : bool bMatchFound = false;
2654 7406 : bool bOtherValuesElementFound = false;
2655 7406 : CPLXMLNode *psStringSelect = psChildNode->psChild;
2656 45554 : while (psStringSelect)
2657 : {
2658 45512 : if (psStringSelect->eType == CXT_Element &&
2659 21971 : EQUAL(psStringSelect->pszValue, "Value"))
2660 : {
2661 21971 : CPLXMLNode *psOptionNode = psStringSelect->psChild;
2662 37205 : while (psOptionNode)
2663 : {
2664 22598 : if (psOptionNode->eType == CXT_Text &&
2665 21852 : EQUAL(psOptionNode->pszValue, pszValue))
2666 : {
2667 7245 : bMatchFound = true;
2668 7245 : break;
2669 : }
2670 15353 : if (psOptionNode->eType == CXT_Attribute &&
2671 746 : (EQUAL(psOptionNode->pszValue, "alias") ||
2672 15 : EQUAL(psOptionNode->pszValue,
2673 731 : "deprecated_alias")) &&
2674 731 : EQUAL(psOptionNode->psChild->pszValue,
2675 : pszValue))
2676 : {
2677 119 : bMatchFound = true;
2678 119 : break;
2679 : }
2680 15234 : psOptionNode = psOptionNode->psNext;
2681 : }
2682 21971 : if (bMatchFound)
2683 21971 : break;
2684 : }
2685 23541 : else if (psStringSelect->eType == CXT_Element &&
2686 0 : EQUAL(psStringSelect->pszValue, "OtherValues"))
2687 : {
2688 0 : bOtherValuesElementFound = true;
2689 : }
2690 38148 : psStringSelect = psStringSelect->psNext;
2691 : }
2692 7406 : if (!bMatchFound && !bOtherValuesElementFound)
2693 : {
2694 42 : CPLError(CE_Warning, CPLE_NotSupported,
2695 : "'%s' is an unexpected value for %s %s of type "
2696 : "string-select.",
2697 : pszValue, pszKey, pszErrorMessageOptionType);
2698 42 : bRet = false;
2699 : }
2700 : }
2701 6949 : else if (EQUAL(pszType, "STRING"))
2702 : {
2703 : const char *pszMaxSize =
2704 6949 : CPLGetXMLValue(psChildNode, "maxsize", nullptr);
2705 6949 : if (pszMaxSize != nullptr)
2706 : {
2707 30 : if (static_cast<int>(strlen(pszValue)) > atoi(pszMaxSize))
2708 : {
2709 1 : CPLError(CE_Warning, CPLE_NotSupported,
2710 : "'%s' is of size %d, whereas maximum size for "
2711 : "%s %s is %d.",
2712 1 : pszValue, static_cast<int>(strlen(pszValue)),
2713 : pszKey, pszErrorMessageOptionType,
2714 : atoi(pszMaxSize));
2715 1 : bRet = false;
2716 : }
2717 : }
2718 : }
2719 : else
2720 : {
2721 : /* Driver error */
2722 0 : CPLError(CE_Warning, CPLE_NotSupported,
2723 : "%s : type '%s' for %s %s is not recognized.",
2724 : pszErrorMessageContainerName, pszType, pszKey,
2725 : pszErrorMessageOptionType);
2726 : }
2727 : }
2728 : else
2729 : {
2730 : /* Driver error */
2731 0 : CPLError(CE_Warning, CPLE_NotSupported, "%s : no type for %s %s.",
2732 : pszErrorMessageContainerName, pszKey,
2733 : pszErrorMessageOptionType);
2734 : }
2735 28116 : CPLFree(pszKey);
2736 28116 : ++papszOptionsToValidate;
2737 : }
2738 :
2739 17562 : CPLDestroyXMLNode(psNode);
2740 17562 : return bRet ? TRUE : FALSE;
2741 : }
2742 :
2743 : /************************************************************************/
2744 : /* GDALIdentifyDriver() */
2745 : /************************************************************************/
2746 :
2747 : /**
2748 : * \brief Identify the driver that can open a dataset.
2749 : *
2750 : * This function will try to identify the driver that can open the passed file
2751 : * name by invoking the Identify method of each registered GDALDriver in turn.
2752 : * The first driver that successfully identifies the file name will be returned.
2753 : * If all drivers fail then NULL is returned.
2754 : *
2755 : * In order to reduce the need for such searches to touch the operating system
2756 : * file system machinery, it is possible to give an optional list of files.
2757 : * This is the list of all files at the same level in the file system as the
2758 : * target file, including the target file. The filenames will not include any
2759 : * path components, and are essentially just the output of VSIReadDir() on the
2760 : * parent directory. If the target object does not have filesystem semantics
2761 : * then the file list should be NULL.
2762 : *
2763 : * @param pszFilename the name of the file to access. In the case of
2764 : * exotic drivers this may not refer to a physical file, but instead contain
2765 : * information for the driver on how to access a dataset.
2766 : *
2767 : * @param papszFileList an array of strings, whose last element is the NULL
2768 : * pointer. These strings are filenames that are auxiliary to the main
2769 : * filename. The passed value may be NULL.
2770 : *
2771 : * @return A GDALDriverH handle or NULL on failure. For C++ applications
2772 : * this handle can be cast to a GDALDriver *.
2773 : */
2774 :
2775 26145 : GDALDriverH CPL_STDCALL GDALIdentifyDriver(const char *pszFilename,
2776 : CSLConstList papszFileList)
2777 :
2778 : {
2779 26145 : return GDALIdentifyDriverEx(pszFilename, 0, nullptr, papszFileList);
2780 : }
2781 :
2782 : /************************************************************************/
2783 : /* GDALIdentifyDriverEx() */
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 nIdentifyFlags a combination of GDAL_OF_RASTER for raster drivers
2807 : * or GDAL_OF_VECTOR for vector drivers. If none of the value is specified,
2808 : * both kinds are implied.
2809 : *
2810 : * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
2811 : * terminated list of strings with the driver short names that must be
2812 : * considered.
2813 : *
2814 : * @param papszFileList an array of strings, whose last element is the NULL
2815 : * pointer. These strings are filenames that are auxiliary to the main
2816 : * filename. The passed value may be NULL.
2817 : *
2818 : * @return A GDALDriverH handle or NULL on failure. For C++ applications
2819 : * this handle can be cast to a GDALDriver *.
2820 : */
2821 :
2822 26235 : GDALDriverH CPL_STDCALL GDALIdentifyDriverEx(
2823 : const char *pszFilename, unsigned int nIdentifyFlags,
2824 : const char *const *papszAllowedDrivers, const char *const *papszFileList)
2825 : {
2826 26235 : GDALDriverManager *poDM = GetGDALDriverManager();
2827 26235 : CPLAssert(nullptr != poDM);
2828 :
2829 : // If no driver kind is specified, assume all are to be probed.
2830 26235 : if ((nIdentifyFlags & GDAL_OF_KIND_MASK) == 0)
2831 26192 : nIdentifyFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
2832 :
2833 52470 : GDALOpenInfo oOpenInfo(pszFilename, nIdentifyFlags, papszFileList);
2834 26235 : oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
2835 :
2836 52470 : CPLErrorStateBackuper oBackuper;
2837 26235 : CPLErrorSetState(CE_None, CPLE_AppDefined, "");
2838 :
2839 26235 : const int nDriverCount = poDM->GetDriverCount();
2840 :
2841 : // First pass: only use drivers that have a pfnIdentify implementation.
2842 52470 : std::vector<GDALDriver *> apoSecondPassDrivers;
2843 5803910 : for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
2844 : {
2845 5778960 : GDALDriver *poDriver = poDM->GetDriver(iDriver);
2846 5786400 : if (papszAllowedDrivers != nullptr &&
2847 7443 : CSLFindString(papszAllowedDrivers,
2848 : GDALGetDriverShortName(poDriver)) == -1)
2849 : {
2850 1122670 : continue;
2851 : }
2852 :
2853 5772850 : VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
2854 :
2855 5771560 : if (poDriver->pfnIdentify == nullptr &&
2856 1111400 : poDriver->pfnIdentifyEx == nullptr)
2857 : {
2858 1111400 : continue;
2859 : }
2860 :
2861 4660200 : if (papszAllowedDrivers != nullptr &&
2862 44 : CSLFindString(papszAllowedDrivers,
2863 : GDALGetDriverShortName(poDriver)) == -1)
2864 0 : continue;
2865 13975700 : if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
2866 4660670 : (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
2867 511 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
2868 144 : continue;
2869 13983400 : if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
2870 4664960 : (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
2871 4948 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
2872 3729 : continue;
2873 :
2874 4656290 : if (poDriver->pfnIdentifyEx)
2875 : {
2876 0 : if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) > 0)
2877 0 : return poDriver;
2878 : }
2879 : else
2880 : {
2881 4656290 : const int nIdentifyRes = poDriver->pfnIdentify(&oOpenInfo);
2882 4656290 : if (nIdentifyRes > 0)
2883 1287 : return poDriver;
2884 4681160 : if (nIdentifyRes < 0 &&
2885 26156 : poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
2886 : {
2887 : // Not loaded plugin
2888 37 : apoSecondPassDrivers.push_back(poDriver);
2889 : }
2890 : }
2891 : }
2892 :
2893 : // second pass: try loading plugin drivers
2894 24982 : for (auto poDriver : apoSecondPassDrivers)
2895 : {
2896 : // Force plugin driver loading
2897 35 : poDriver->GetMetadata();
2898 35 : if (poDriver->pfnIdentify(&oOpenInfo) > 0)
2899 1 : return poDriver;
2900 : }
2901 :
2902 : // third pass: slow method.
2903 5672230 : for (int iDriver = 0; iDriver < nDriverCount; ++iDriver)
2904 : {
2905 5647510 : GDALDriver *poDriver = poDM->GetDriver(iDriver);
2906 5651390 : if (papszAllowedDrivers != nullptr &&
2907 3875 : CSLFindString(papszAllowedDrivers,
2908 : GDALGetDriverShortName(poDriver)) == -1)
2909 : {
2910 3858 : continue;
2911 : }
2912 :
2913 5643660 : VALIDATE_POINTER1(poDriver, "GDALIdentifyDriver", nullptr);
2914 :
2915 16929500 : if ((nIdentifyFlags & GDAL_OF_RASTER) != 0 &&
2916 5644110 : (nIdentifyFlags & GDAL_OF_VECTOR) == 0 &&
2917 454 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
2918 143 : continue;
2919 16931200 : if ((nIdentifyFlags & GDAL_OF_VECTOR) != 0 &&
2920 5645100 : (nIdentifyFlags & GDAL_OF_RASTER) == 0 &&
2921 1591 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
2922 960 : continue;
2923 :
2924 5642550 : if (poDriver->pfnIdentifyEx != nullptr)
2925 : {
2926 0 : if (poDriver->pfnIdentifyEx(poDriver, &oOpenInfo) == 0)
2927 0 : continue;
2928 : }
2929 5642550 : else if (poDriver->pfnIdentify != nullptr)
2930 : {
2931 4555260 : if (poDriver->pfnIdentify(&oOpenInfo) == 0)
2932 4529740 : continue;
2933 : }
2934 :
2935 : GDALDataset *poDS;
2936 1112820 : if (poDriver->pfnOpen != nullptr)
2937 : {
2938 1063180 : poDS = poDriver->pfnOpen(&oOpenInfo);
2939 1063180 : if (poDS != nullptr)
2940 : {
2941 95 : delete poDS;
2942 95 : return GDALDriver::ToHandle(poDriver);
2943 : }
2944 :
2945 1063090 : if (CPLGetLastErrorType() != CE_None)
2946 136 : return nullptr;
2947 : }
2948 49633 : else if (poDriver->pfnOpenWithDriverArg != nullptr)
2949 : {
2950 0 : poDS = poDriver->pfnOpenWithDriverArg(poDriver, &oOpenInfo);
2951 0 : if (poDS != nullptr)
2952 : {
2953 0 : delete poDS;
2954 0 : return GDALDriver::ToHandle(poDriver);
2955 : }
2956 :
2957 0 : if (CPLGetLastErrorType() != CE_None)
2958 0 : return nullptr;
2959 : }
2960 : }
2961 :
2962 24716 : return nullptr;
2963 : }
2964 :
2965 : /************************************************************************/
2966 : /* GetMetadataItem() */
2967 : /************************************************************************/
2968 :
2969 13232300 : const char *GDALDriver::GetMetadataItem(const char *pszName,
2970 : const char *pszDomain)
2971 : {
2972 13232300 : if (pszDomain == nullptr || pszDomain[0] == '\0')
2973 : {
2974 13232100 : if (EQUAL(pszName, GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST))
2975 : {
2976 2221 : const char *pszVal = GDALMajorObject::GetMetadataItem(pszName, "");
2977 2221 : if (pszVal)
2978 1996 : return pszVal;
2979 225 : if (GetMetadataItem(GDAL_DCAP_RASTER))
2980 : {
2981 153 : auto poDM = GetGDALDriverManager();
2982 153 : auto poGTiffDrv = poDM->GetDriverByName("GTiff");
2983 153 : if (poGTiffDrv)
2984 : {
2985 : const char *pszXML =
2986 153 : poGTiffDrv->GetMetadataItem(pszName, "");
2987 153 : if (pszXML)
2988 : {
2989 306 : CPLString osXML(pszXML);
2990 153 : osXML.replaceAll("<Value>INTERNAL</Value>", "");
2991 153 : return CPLSPrintf("%s", osXML.c_str());
2992 : }
2993 : }
2994 : }
2995 : }
2996 : }
2997 13230100 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
2998 : }
2999 :
3000 : /************************************************************************/
3001 : /* SetMetadataItem() */
3002 : /************************************************************************/
3003 :
3004 4594660 : CPLErr GDALDriver::SetMetadataItem(const char *pszName, const char *pszValue,
3005 : const char *pszDomain)
3006 :
3007 : {
3008 4594660 : if (pszDomain == nullptr || pszDomain[0] == '\0')
3009 : {
3010 : /* Automatically sets GDAL_DMD_EXTENSIONS from GDAL_DMD_EXTENSION */
3011 4788080 : if (EQUAL(pszName, GDAL_DMD_EXTENSION) &&
3012 198847 : GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSIONS) == nullptr)
3013 : {
3014 198847 : GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSIONS, pszValue);
3015 : }
3016 : /* and vice-versa if there is a single extension in GDAL_DMD_EXTENSIONS */
3017 8862000 : else if (EQUAL(pszName, GDAL_DMD_EXTENSIONS) &&
3018 4399420 : strchr(pszValue, ' ') == nullptr &&
3019 9027 : GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSION) ==
3020 : nullptr)
3021 : {
3022 9027 : GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSION, pszValue);
3023 : }
3024 : }
3025 4594660 : return GDALMajorObject::SetMetadataItem(pszName, pszValue, pszDomain);
3026 : }
3027 :
3028 : /************************************************************************/
3029 : /* InstantiateAlgorithm() */
3030 : /************************************************************************/
3031 :
3032 : //! @cond Doxygen_Suppress
3033 :
3034 : GDALAlgorithm *
3035 1127 : GDALDriver::InstantiateAlgorithm(const std::vector<std::string> &aosPath)
3036 : {
3037 1127 : pfnInstantiateAlgorithm = GetInstantiateAlgorithmCallback();
3038 1127 : if (pfnInstantiateAlgorithm)
3039 1127 : return pfnInstantiateAlgorithm(aosPath);
3040 0 : return nullptr;
3041 : }
3042 :
3043 : /************************************************************************/
3044 : /* DeclareAlgorithm() */
3045 : /************************************************************************/
3046 :
3047 14549 : void GDALDriver::DeclareAlgorithm(const std::vector<std::string> &aosPath)
3048 : {
3049 29098 : const std::string osDriverName = GetDescription();
3050 14549 : auto &singleton = GDALGlobalAlgorithmRegistry::GetSingleton();
3051 :
3052 29098 : if (!singleton.HasDeclaredSubAlgorithm({"driver"}))
3053 : {
3054 3206 : singleton.DeclareAlgorithm(
3055 : {"driver"},
3056 151 : []() -> std::unique_ptr<GDALAlgorithm>
3057 : {
3058 302 : return std::make_unique<GDALContainerAlgorithm>(
3059 151 : "driver", "Command for driver specific operations.");
3060 1603 : });
3061 : }
3062 :
3063 : std::vector<std::string> path = {"driver",
3064 87294 : CPLString(osDriverName).tolower()};
3065 14549 : if (!singleton.HasDeclaredSubAlgorithm(path))
3066 : {
3067 1305 : auto lambda = [osDriverName]() -> std::unique_ptr<GDALAlgorithm>
3068 : {
3069 : auto poDriver =
3070 1305 : GetGDALDriverManager()->GetDriverByName(osDriverName.c_str());
3071 1305 : if (poDriver)
3072 : {
3073 : const char *pszHelpTopic =
3074 1305 : poDriver->GetMetadataItem(GDAL_DMD_HELPTOPIC);
3075 2610 : return std::make_unique<GDALContainerAlgorithm>(
3076 2610 : CPLString(osDriverName).tolower(),
3077 2610 : std::string("Command for ")
3078 1305 : .append(osDriverName)
3079 : .append(" driver specific operations."),
3080 2610 : pszHelpTopic ? std::string("/").append(pszHelpTopic)
3081 1305 : : std::string());
3082 : }
3083 0 : return nullptr;
3084 11221 : };
3085 11221 : singleton.DeclareAlgorithm(path, std::move(lambda));
3086 : }
3087 :
3088 14549 : path.insert(path.end(), aosPath.begin(), aosPath.end());
3089 :
3090 1127 : auto lambda = [osDriverName, aosPath]() -> std::unique_ptr<GDALAlgorithm>
3091 : {
3092 : auto poDriver =
3093 1127 : GetGDALDriverManager()->GetDriverByName(osDriverName.c_str());
3094 1127 : if (poDriver)
3095 : return std::unique_ptr<GDALAlgorithm>(
3096 1127 : poDriver->InstantiateAlgorithm(aosPath));
3097 0 : return nullptr;
3098 29098 : };
3099 :
3100 14549 : singleton.DeclareAlgorithm(path, std::move(lambda));
3101 :
3102 14549 : CPL_IGNORE_RET_VAL(osDriverName);
3103 14549 : }
3104 :
3105 : //! @endcond
3106 :
3107 : /************************************************************************/
3108 : /* DoesDriverHandleExtension() */
3109 : /************************************************************************/
3110 :
3111 194751 : static bool DoesDriverHandleExtension(GDALDriverH hDriver, const char *pszExt)
3112 : {
3113 194751 : bool bRet = false;
3114 : const char *pszDriverExtensions =
3115 194751 : GDALGetMetadataItem(hDriver, GDAL_DMD_EXTENSIONS, nullptr);
3116 194751 : if (pszDriverExtensions)
3117 : {
3118 325674 : const CPLStringList aosTokens(CSLTokenizeString(pszDriverExtensions));
3119 162837 : const int nTokens = aosTokens.size();
3120 365925 : for (int j = 0; j < nTokens; ++j)
3121 : {
3122 207752 : if (EQUAL(pszExt, aosTokens[j]))
3123 : {
3124 4664 : bRet = true;
3125 4664 : break;
3126 : }
3127 : }
3128 : }
3129 194751 : return bRet;
3130 : }
3131 :
3132 : /************************************************************************/
3133 : /* IsOnlyExpectedGDBDrivers() */
3134 : /************************************************************************/
3135 :
3136 1 : static bool IsOnlyExpectedGDBDrivers(const CPLStringList &aosDriverNames)
3137 : {
3138 3 : for (const char *pszDrvName : aosDriverNames)
3139 : {
3140 2 : if (!EQUAL(pszDrvName, "OpenFileGDB") &&
3141 1 : !EQUAL(pszDrvName, "FileGDB") && !EQUAL(pszDrvName, "GPSBabel"))
3142 : {
3143 0 : return false;
3144 : }
3145 : }
3146 1 : return true;
3147 : }
3148 :
3149 : /************************************************************************/
3150 : /* GDALGetOutputDriversForDatasetName() */
3151 : /************************************************************************/
3152 :
3153 : /** Return a list of driver short names that are likely candidates for the
3154 : * provided output file name.
3155 : *
3156 : * @param pszDestDataset Output dataset name (might not exist).
3157 : * @param nDatasetTypeFlag GDAL_OF_RASTER, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER
3158 : * or a binary-or'ed combination of them
3159 : * @param bSingleMatch Whether a single match is desired, that is to say the
3160 : * returned list will contain at most one item, which will
3161 : * be the first driver in the order they are registered to
3162 : * match the output dataset name. Note that in this mode, if
3163 : * nDatasetTypeFlag==GDAL_OF_RASTER and pszDestDataset has
3164 : * no extension, GTiff will be selected.
3165 : * @param bEmitWarning Whether a warning should be emitted when bSingleMatch is
3166 : * true and there are more than 2 candidates.
3167 : * @return NULL terminated list of driver short names.
3168 : * To be freed with CSLDestroy()
3169 : * @since 3.9
3170 : */
3171 2749 : char **GDALGetOutputDriversForDatasetName(const char *pszDestDataset,
3172 : int nDatasetTypeFlag,
3173 : bool bSingleMatch, bool bEmitWarning)
3174 : {
3175 5498 : CPLStringList aosDriverNames;
3176 5498 : CPLStringList aosMissingDriverNames;
3177 :
3178 5498 : std::string osExt = CPLGetExtensionSafe(pszDestDataset);
3179 2749 : if (EQUAL(osExt.c_str(), "zip"))
3180 : {
3181 2 : const CPLString osLower(CPLString(pszDestDataset).tolower());
3182 1 : if (osLower.endsWith(".shp.zip"))
3183 : {
3184 1 : osExt = "shp.zip";
3185 : }
3186 0 : else if (osLower.endsWith(".gpkg.zip"))
3187 : {
3188 0 : osExt = "gpkg.zip";
3189 : }
3190 : }
3191 2748 : else if (EQUAL(osExt.c_str(), "json"))
3192 : {
3193 1 : const CPLString osLower(CPLString(pszDestDataset).tolower());
3194 1 : if (osLower.endsWith(".gdalg.json"))
3195 0 : return nullptr;
3196 : }
3197 :
3198 2749 : auto poDM = GetGDALDriverManager();
3199 2749 : const int nDriverCount = poDM->GetDriverCount(true);
3200 2749 : GDALDriver *poMissingPluginDriver = nullptr;
3201 5498 : std::string osMatchingPrefix;
3202 629126 : for (int i = 0; i < nDriverCount; i++)
3203 : {
3204 626377 : GDALDriver *poDriver = poDM->GetDriver(i, true);
3205 626377 : bool bOk = false;
3206 626377 : if ((poDriver->GetMetadataItem(GDAL_DCAP_CREATE) != nullptr ||
3207 384468 : poDriver->GetMetadataItem(GDAL_DCAP_CREATECOPY) != nullptr ||
3208 1252750 : poDriver->GetMetadataItem(GDAL_DCAP_UPDATE) != nullptr) &&
3209 324379 : (((nDatasetTypeFlag & GDAL_OF_RASTER) &&
3210 256295 : poDriver->GetMetadataItem(GDAL_DCAP_RASTER) != nullptr) ||
3211 159308 : ((nDatasetTypeFlag & GDAL_OF_VECTOR) &&
3212 67494 : poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) != nullptr) ||
3213 127278 : ((nDatasetTypeFlag & GDAL_OF_MULTIDIM_RASTER) &&
3214 590 : poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) != nullptr)))
3215 : {
3216 197151 : bOk = true;
3217 : }
3218 433580 : else if (poDriver->GetMetadataItem(GDAL_DCAP_VECTOR_TRANSLATE_FROM) &&
3219 4354 : (nDatasetTypeFlag & GDAL_OF_VECTOR) != 0)
3220 : {
3221 0 : bOk = true;
3222 : }
3223 626377 : if (bOk)
3224 : {
3225 391902 : if (!osExt.empty() &&
3226 194751 : DoesDriverHandleExtension(GDALDriver::ToHandle(poDriver),
3227 : osExt.c_str()))
3228 : {
3229 4664 : if (poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
3230 : {
3231 0 : poMissingPluginDriver = poDriver;
3232 0 : aosMissingDriverNames.AddString(poDriver->GetDescription());
3233 : }
3234 : else
3235 4664 : aosDriverNames.AddString(poDriver->GetDescription());
3236 : }
3237 : else
3238 : {
3239 : const char *pszPrefix =
3240 192487 : poDriver->GetMetadataItem(GDAL_DMD_CONNECTION_PREFIX);
3241 192487 : if (pszPrefix && STARTS_WITH_CI(pszDestDataset, pszPrefix))
3242 : {
3243 9 : if (poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
3244 : {
3245 0 : osMatchingPrefix = pszPrefix;
3246 0 : poMissingPluginDriver = poDriver;
3247 : aosMissingDriverNames.AddString(
3248 0 : poDriver->GetDescription());
3249 : }
3250 : else
3251 9 : aosDriverNames.AddString(poDriver->GetDescription());
3252 : }
3253 : }
3254 : }
3255 : }
3256 :
3257 : // GMT is registered before netCDF for opening reasons, but we want
3258 : // netCDF to be used by default for output.
3259 2756 : if (EQUAL(osExt.c_str(), "nc") && aosDriverNames.size() == 2 &&
3260 2756 : EQUAL(aosDriverNames[0], "GMT") && EQUAL(aosDriverNames[1], "netCDF"))
3261 : {
3262 0 : aosDriverNames.Clear();
3263 0 : aosDriverNames.AddString("netCDF");
3264 0 : aosDriverNames.AddString("GMT");
3265 : }
3266 :
3267 2749 : if (bSingleMatch)
3268 : {
3269 2677 : if (nDatasetTypeFlag == GDAL_OF_RASTER)
3270 : {
3271 2172 : if (aosDriverNames.empty())
3272 : {
3273 12 : if (osExt.empty())
3274 : {
3275 8 : aosDriverNames.AddString("GTiff");
3276 : }
3277 : }
3278 2160 : else if (aosDriverNames.size() >= 2)
3279 : {
3280 3920 : if (bEmitWarning && !(EQUAL(aosDriverNames[0], "GTiff") &&
3281 1959 : EQUAL(aosDriverNames[1], "COG")))
3282 : {
3283 2 : CPLError(CE_Warning, CPLE_AppDefined,
3284 : "Several drivers matching %s extension. Using %s",
3285 : osExt.c_str(), aosDriverNames[0]);
3286 : }
3287 3922 : const std::string osDrvName = aosDriverNames[0];
3288 1961 : aosDriverNames.Clear();
3289 1961 : aosDriverNames.AddString(osDrvName.c_str());
3290 : }
3291 : }
3292 506 : else if (EQUAL(osExt.c_str(), "gdb") &&
3293 1 : IsOnlyExpectedGDBDrivers(aosDriverNames))
3294 : {
3295 : // Do not warn about that case given that FileGDB write support
3296 : // forwards to OpenFileGDB one. And also consider GPSBabel as too
3297 : // marginal to deserve the warning.
3298 1 : aosDriverNames.Clear();
3299 1 : aosDriverNames.AddString("OpenFileGDB");
3300 : }
3301 504 : else if (aosDriverNames.size() >= 2)
3302 : {
3303 0 : if (bEmitWarning)
3304 : {
3305 0 : CPLError(CE_Warning, CPLE_AppDefined,
3306 : "Several drivers matching %s %s. Using %s",
3307 0 : osMatchingPrefix.empty() ? osExt.c_str()
3308 0 : : osMatchingPrefix.c_str(),
3309 0 : osMatchingPrefix.empty() ? "extension" : "prefix",
3310 : aosDriverNames[0]);
3311 : }
3312 0 : const std::string osDrvName = aosDriverNames[0];
3313 0 : aosDriverNames.Clear();
3314 0 : aosDriverNames.AddString(osDrvName.c_str());
3315 : }
3316 : }
3317 :
3318 2780 : if (aosDriverNames.empty() && bEmitWarning &&
3319 2780 : aosMissingDriverNames.size() == 1 && poMissingPluginDriver)
3320 : {
3321 0 : CPLError(CE_Failure, CPLE_AppDefined,
3322 : "No installed driver matching %s %s, but %s driver is "
3323 : "known. However plugin %s",
3324 0 : osMatchingPrefix.empty() ? osExt.c_str()
3325 0 : : osMatchingPrefix.c_str(),
3326 0 : osMatchingPrefix.empty() ? "extension" : "prefix",
3327 0 : poMissingPluginDriver->GetDescription(),
3328 0 : GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver)
3329 : .c_str());
3330 : }
3331 2779 : else if (aosDriverNames.empty() && bEmitWarning &&
3332 30 : aosMissingDriverNames.empty())
3333 : {
3334 827 : for (const auto &sConnectionPrefix : asKnownConnectionPrefixes)
3335 : {
3336 798 : if (STARTS_WITH_CI(pszDestDataset, sConnectionPrefix.pszPrefix))
3337 : {
3338 1 : CPLError(CE_Failure, CPLE_AppDefined,
3339 : "Filename %s starts with the connection prefix of "
3340 : "driver %s, which is not enabled in this GDAL build. "
3341 : "If that filename is really intended, explicitly "
3342 : "specify its output format.",
3343 1 : pszDestDataset, sConnectionPrefix.pszDriverName);
3344 1 : break;
3345 : }
3346 : }
3347 : }
3348 :
3349 2749 : return aosDriverNames.StealList();
3350 : }
3351 :
3352 : /************************************************************************/
3353 : /* GDALGetMessageAboutMissingPluginDriver() */
3354 : /************************************************************************/
3355 :
3356 : std::string
3357 0 : GDALGetMessageAboutMissingPluginDriver(GDALDriver *poMissingPluginDriver)
3358 : {
3359 : std::string osMsg =
3360 0 : poMissingPluginDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME");
3361 : osMsg += " is not available in your "
3362 0 : "installation.";
3363 0 : if (const char *pszInstallationMsg = poMissingPluginDriver->GetMetadataItem(
3364 0 : GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE))
3365 : {
3366 0 : osMsg += " ";
3367 0 : osMsg += pszInstallationMsg;
3368 : }
3369 :
3370 : VSIStatBuf sStat;
3371 0 : if (const char *pszGDALDriverPath =
3372 0 : CPLGetConfigOption("GDAL_DRIVER_PATH", nullptr))
3373 : {
3374 0 : if (VSIStat(pszGDALDriverPath, &sStat) != 0)
3375 : {
3376 0 : if (osMsg.back() != '.')
3377 0 : osMsg += ".";
3378 0 : osMsg += " Directory '";
3379 0 : osMsg += pszGDALDriverPath;
3380 0 : osMsg += "' pointed by GDAL_DRIVER_PATH does not exist.";
3381 : }
3382 : }
3383 : else
3384 : {
3385 0 : if (osMsg.back() != '.')
3386 0 : osMsg += ".";
3387 : #ifdef INSTALL_PLUGIN_FULL_DIR
3388 : if (VSIStat(INSTALL_PLUGIN_FULL_DIR, &sStat) != 0)
3389 : {
3390 : osMsg += " Directory '";
3391 : osMsg += INSTALL_PLUGIN_FULL_DIR;
3392 : osMsg += "' hardcoded in the GDAL library does not "
3393 : "exist and the GDAL_DRIVER_PATH "
3394 : "configuration option is not set.";
3395 : }
3396 : else
3397 : #endif
3398 : {
3399 : osMsg += " The GDAL_DRIVER_PATH configuration "
3400 0 : "option is not set.";
3401 : }
3402 : }
3403 0 : return osMsg;
3404 : }
3405 :
3406 : /************************************************************************/
3407 : /* GDALClearMemoryCaches() */
3408 : /************************************************************************/
3409 :
3410 : /**
3411 : * \brief Clear all GDAL-controlled in-memory caches.
3412 : *
3413 : * Iterates registered drivers and calls their pfnClearCaches callback if set,
3414 : * then calls VSICurlClearCache() to clear /vsicurl/ and related caches.
3415 : *
3416 : * Note that neither the global raster block cache or caches specific to open
3417 : * dataset objects are not cleared by this function (in its current implementation).
3418 : *
3419 : * Useful when remote datasets may have changed during the lifetime of a
3420 : * process.
3421 : *
3422 : * @since GDAL 3.13
3423 : */
3424 4 : void GDALClearMemoryCaches()
3425 : {
3426 4 : auto *poDM = GetGDALDriverManager();
3427 4 : if (poDM)
3428 : {
3429 916 : for (int i = 0; i < poDM->GetDriverCount(); i++)
3430 : {
3431 912 : auto *poDriver = poDM->GetDriver(i);
3432 912 : if (poDriver && poDriver->pfnClearCaches)
3433 4 : poDriver->pfnClearCaches(poDriver);
3434 : }
3435 : }
3436 4 : VSICurlClearCache();
3437 4 : }
|